AI 코딩 시대, CI가 병목이 되어 개선한 Linear의 사례
AI 코딩 에이전트로 코드 생산 속도는 빨라졌지만 검증을 담당하는 CI가 병목이 되면서 Linear는 인프라 업그레이드, 타입 체커 없는 린트, 게이팅 작업 최적화 등을 통해 대기 시간을 6분에서 5분으로 줄이고 테스트당 러너 시간을 절반으로 감축했습니다. 테스트 규모가 4배 가까이 늘어난 상황에서도 달성한 결과로, TypeScript 기반 팀뿐 아니라 다양한 언어·툴체인에 적용 가능한 실전 CI 최적화 가이드입니다.
팀에서 보내온 글입니다. AI 코딩 시대, CI가 병목이 되어 우리는 이를 개선했다 — Mufeez Amjad, 2026년 9월 21일.
올해 초 Linear를 열어보니 Tuomas CTO가 나에게 "CI 비용이 너무 높다"는 이슈를 할당해두었다. 그깟 김에 CI도 더 빠르게 만들어달라는 요청이었다. AI 에이전트 덕분에 코드를 배포하는 속도는 비약적으로 빨라졌지만, 그 변경사항을 검증하는 속도는 같은 폭으로 따라가지 못했다. 모든 PR은 여전히 CI를 통과해야 하므로, 개발이 빨라질수록 CI가 병목이 되어 인프라 비용을 끌어올리고 개발자와 에이전트는 피드백을 더 오래 기다리게 된다.
Linear에서 CI 성능을 개선하면서 우리가 최적화한 지표는 PR이 CI에서 대기하는 시간과 소비하는 러너 시간이었다. 테스트 스위트가 연초 대비 거의 4배로 늘어났음에도, PR 대기 시간을 6분 이상에서 5분 조금 넘게 줄이고 테스트당 러너 시간을 대략 절반으로 줄였다.
크게 보면 네 가지 방향으로 CI를 개선했다:
- 인프라와 툴링 업그레이드
- 다른 작업을 게이팅하는 잡 최적화
- 반복되는 셋업 감소
- 테스트 실행 효율화
Linear의 코드베이스는 주로 TypeScript지만, 이런 최적화 대부분은 언어와 툴체인을 가리지 않고 적용할 수 있다.
인프라와 툴링 업그레이드 가장 초기의 성과 일부는 CI 자체를 거의 최적화하지 않고도 얻었다. 워크로드를 GitHub Actions에서 더 빠른 CPU, 고성능 스토리지, 더 나은 캐시 인프라를 갖춘 서드파티 러너로 옮긴 것만으로 같은 파이프라인을 더 빠른 머신에서 돌릴 수 있었다. 전환 전후 이틀씩을 동일 조건으로 비교한 결과, 잡이 평균 34% 빨라졌고 tsc 같은 일부 워크로드는 52% 줄었다.
별도로 툴체인 현대화도 효과가 컸다. 네이티브 TypeScript 컴파일러인 tsgo로 전환하자 tsc 체크의 주간 중앙값이 73% 감소해, 타입 체킹이 병목에서 완전히 벗어날 정도였다.
타입 체커 없는 린트 린팅도 초기 개선 대상이었다. 우리의 커스텀 린트 규칙 일부는 제약을 강제하거나 자동 수정을 적용하기 위해 TypeScript 타입 정보에 의존했다. 그 때문에 모든 린트 실행이 해당 규칙을 평가하기 전에 전체 타입 그래프를 빌드해야 했고, 린팅은 가장 메모리를 많이 쓰는 CI 잡 중 하나였다.
우리는 이 규칙들을 추상 구문 트리(AST) 기반 정적 분석을 사용하도록 다시 작성해, 타입 정보 없이도 함수형 구조와 가드 패턴을 식별하도록 했다. 덕분에 ESLint가 TypeScript를 완전히 떼어낼 수 있었고, API 린트 시간이 68%, 전체 저장소 린트 시간이 55% 줄었다. 메모리 사용량도 크게 감소했다. 타입 정보 의존을 제거한 것은 이후 Oxlint로 전환하는 작업도 훨씬 쉽게 만들어주었는데, 순수하게 구문만 다루는 규칙은 포팅이 간단했기 때문이다. Oxlint 자체도 린팅에 쓰이는 CI 러너 시간(분)을 줄여주었다.
다른 작업을 게이팅하는 잡 최적화 기반 인프라와 개별 체크가 빨라지자, 이번에는 CI를 하나의 시스템으로 바라보며 시야를 넓혔다. 그러자 다른 모든 작업 앞에 놓인 작은 잡들이 눈에 들어왔다. 모든 실행은 PR이 어떤 경로를 건드렸는지, 그리고 같은 입력에 대해 이 테스트들이 이미 통과했는지 확인하는 것으로 시작한다. 우리는 이 확인을 잡 수준에서 게이팅하여 스킵된 작업이 러너를 예약하지 않도록 하지만, 그만큼 이들이 중요 경로(크리티컬 패스)에 직접 놓이게 된다. 8개의 API 테스트 샤드는 이들이 끝나야 시작할 수 있으므로, 작은 지연도 불균형하게 큰 영향을 준다.
각 잡에 필요한 것만 가져오기 우리 워크플로 중 일부는 변경 감지 잡으로 시작해 다음에 무엇을 실행할지 결정한다. 예를 들어 diff에 데이터베이스 마이그레이션이 포함되어 있는지 확인하고, 그 신호를 사용해 관련 데이터베이스 CI 체크를 스케줄링한다. 이런 잡들은 아주 작은 일부만 필요로 하는데도 전체 워킹 트리를 체크아웃하고 있었다. fetch 깊이를 제한하자 이런 게이트 중 가장 느렸던 잡이 94초에서 20초로 줄었고, 워킹 트리가 아예 필요 없는 잡에서는 체크아웃을 완전히 제거해 27초에서 7초로 줄였다.