Ninja(2020)의 성공과 실패
(neugierig.org)- 2011년 공개된 Ninja는 Make와 비슷한 빌드 시스템에서 출발해 Chrome, Android 일부, Meson, CMake 기반 프로젝트까지 퍼진 대표적 오픈소스 성공 사례가 됨
- 성패를 가른 축은 코드 자체보다 아키텍처, 더 나아가 유지보수와 사용자 기대 같은 사회적 문제였음
- Ninja는
ninja.build에 적힌 명령·입력·출력을 읽고 파일 수정 시각을 확인한 뒤 필요한 작업을 병렬 실행하며, 대형 프로젝트의 증분 빌드를 빠르게 만드는 데 집중함 - 가장 큰 설계 선택은 고수준 빌드 기능을 직접 품지 않고 액션 그래프(action graph) 실행기에 머문 점이며, 복잡한 판단은 생성기(generator)가 맡도록 분리함
- CMake 통합, Windows 지원, 병렬 실행 기본값은 확산을 키웠지만, 설계 목표와 충돌하는 요구와 기여는 오픈소스 유지보수의 큰 부담으로 남음
Ninja가 널리 쓰이게 된 맥락
- Ninja는 약 9년 전 공개된 Make와 비슷한 빌드 시스템이며, 처음에는 부끄럽게 공유한 사이드 프로젝트였지만 이후 널리 사용됨
- 주요 사용 사례는 다음과 같음
- Chrome은 결국 비-Ninja 빌드를 모두 제거함
- Android는 시스템의 큰 구성요소 일부에 Ninja를 사용함
- Meson 프로젝트는 Ninja를 사용하며, 자유 소프트웨어 세계에서 점점 더 많이 쓰이는 빌드 시스템으로 보임
- CMake와 함께 Ninja를 쓰는 프로젝트도 많고, Swift 빌드 안내도 Ninja 설치를 요구함
- Ninja는 2011년 릴리스됐고, 2014년에 프로젝트 소유권이 넘어갔으며, 이후 세 번째 메인테이너에게 다시 이어짐
- 이 회고에서 드러나는 핵심 경험은 코드보다 아키텍처, 아키텍처보다 사회적 이슈가 더 큰 영향을 준다는 점임
빠른 빌드를 위한 기본 동작
- Ninja가 하는 일은 비교적 단순함
- 사용자는
ninja.build파일에 실행할 명령, 각 명령이 소비하는 파일, 생성하는 파일을 적음 - Ninja는 이 파일을 읽고 여러 파일의 수정 시각을 확인함
- 최신 상태를 만들기 위해 필요한 명령을 병렬로 실행함
- 사용자는
- Make와 비교하면 입력 빌드 언어의 기능은 더 적고, 적은 기능을 매우 빠르게 수행하는 구조에 집중함
- 실행 흐름은 세 단계로 나뉨
- 빌드 파일 파싱 및 해석
- 입력 파일의 수정 시각 확인
- 필요한 명령 실행
- 목표는 10만 개를 넘는 입력 파일이 있는 대형 프로젝트에서도 세 번째 단계까지 가능한 한 빠르게 도달하는 것임
- 예시 최적화로, Ninja는 입력 파일 경로를 가능한 한 이른 시점에 고유한 메모리 객체로 매핑하고 이후 경로 동일성 비교에 포인터 비교를 사용함
- 더 낮은 수준의 성능 세부 사항은 The Performance of Open Source Software의 Ninja 장에서 다룸
- 여러 해 동안 Ninja 재구현도 나왔음
- 재미있는 20% 구현은 쉽지만 나머지 80%는 세부 사항이 많으며, 더 빠른 구현은 알려져 있지 않음
설계에서 중요했던 선택들
-
그래프 표현
- Make는 빌드 규칙 하나가 여러 파일을 생성하는 경우를 잘 다루지 못함
- Ninja는 파일 간 그래프가 아니라 파일과 명령 사이의 이분 그래프를 사용함
- 파일 노드는 명령 노드로 들어가는 간선이 되고, 명령 노드는 다시 출력 파일로 나가는 간선을 가짐
- 이 구조는 빌드의 실제 형태를 더 잘 포착함
- 입력 중 하나가 바뀌면 명령은 오래된 상태가 되고, 명령이 실행되면 모든 출력을 갱신함
- 특정 파일은 최대 하나의 입력 간선만 가질 수 있음
- 명령줄 자체도 명령 노드의 입력처럼 볼 수 있어, 명령줄 플래그가 바뀌면 명령과 출력이 오래된 상태가 됨
-
deps log와 C 헤더 의존성
- C 헤더 의존성을 정확히 처리하려면 C 컴파일러가 만든 추가 의존성 데이터를 소비해야 함
- 데이터베이스 도입 여부와 단순성 사이에서 고민하다가 deps log 표현 형식을 만들었음
- 이 형식은 꽤 압축적이지만 중요한 방식으로 아직 틀린 부분이 있음
-
end-to-end / crash-only 설계
- Ninja는 지속 실행되는 데몬 프로세스가 아니며, 매 실행마다 처음부터 작업함
- 이 선택은 end-to-end principle과 crash-only software의 영향을 받은 구조임
- 처음부터 실행하는 경로를 빠르게 만들면 별도의 “온라인” 코드 경로를 만들 필요가 없음
- 메모리에 상주할 수 있는 프로젝트는 결국 시작 성능이 방치되는 경향이 있음
-
파일 상태 확인
- 빌드 도구가 메모리에 상주해야 한다고 기대하는 이유 중 하나는 디스크 파일 상태를 캐시하기 위해서임
- 실제로는 커널이 이미 이 정보를 메모리에 캐시하며, 사용자 공간에서 다시 캐시해도 절약이 크지 않음
- Linux에서 파일 상태를 가져오는 작업은 매우 빠르고, Ninja는 이를 단일 스레드에서 처리함
- 10년 전 기준 “빠른” 머신에서도 3만 개 파일의
stat을 수십 밀리초 안에 수행할 수 있음
-
규모와 명세의 절충
- 경험칙으로 2배 규모 확장은 최적화로 가능하지만, 10배 규모 확장에는 재아키텍처가 필요함
- Ninja는 당시 약 3만 개 빌드 단계가 있던 Chrome 빌드를 중심으로 설계됨
- 지금은 더 작은 환경에서도 쓰이지만, 그런 경우 속도 이점이 필요하지 않을 수 있음
- Android 빌드 같은 더 큰 환경에서는 스케일 한계에 부딪히고 있으며, 다른 접근이 필요할 가능성이 있음
- Ninja는 병렬 실행을 위해 사용자가 충분한 정보를 제공해야 하지만, 빌드 전체를 완전히 알아야 한다고 강제하지는 않음
- 정확성, 편의성, 성능 사이에는 절충이 있으며, 더 정확하지만 불편한 도구보다 편의성을 위해 정확성을 일부 포기한 도구가 전체 생태계에서는 더 올바른 결과를 낼 수도 있음
“어셈블러” 은유가 만든 분리
- 빌드 시스템은 다양한 고수준 기능을 제공하며, 도구마다 자신을 설명하는 방식도 서로 비교하기 어려울 정도로 넓음
- Ninja의 핵심 통찰은 어떤 고수준 기능을 제공하든 결국 빌드 시스템은 파일을 최신 상태로 유지하기 위한 액션 그래프를 구성해야 한다는 점임
- Ninja는 이 액션 그래프만 실행하고, 그 위에 어떤 생성기를 둘지는 사용자에게 맡김
- 이 두 프로그램의 분리는 원래 Chrome 프로젝트에 잘 맞아서 만든 구조였지만, 이후 Ninja의 가장 중요한 기여가 됨
- 장점은 두 가지임
- Ninja 자체는 단순하고 빠르게 유지됨
*.c를 glob하는 것 같은 비용 큰 작업은 생성기 쪽으로 밀려남
- 다른 빌드 시스템이 한 번에 모든 작업을 처리하는 것과 달리, Ninja 구조는 계산된 액션 그래프를 디스크에 스냅샷으로 저장하게 만듦
- 결과적으로 빌드 사이에 액션 그래프를 캐시하는 형태가 됨
- 생성기는 원하는 만큼 고수준일 수 있음
- 예를 들어 전체 소스 트리를 glob해서 이름에
test가 있는 파일을 테스트로 찾는 방식도 가능함
- 예를 들어 전체 소스 트리를 glob해서 이름에
- 개발자는 무엇에 비용을 지불할지 직접 결정해야 함
- 생성기가 디스크 전체를 glob하면 가능하지만, 그 빌드가 왜 느린지도 더 분명해짐
- 생성기와 액션 그래프 사이의 분리는 실제로 간단하지 않으며, Ninja에도 어느 계층이 어떤 일을 맡을지 둘러싼 세부 사항이 많음
- Xcode나 Visual Studio 빌드 시스템도 이론상 같은 방식으로 사전 계산 후 결과를 스냅샷할 수 있지만, 계층을 섞고 싶은 유혹 때문에 잘 되지 않는다고 봄
- Make는 globbing, 변수 확장, substring, 함수 같은 프로그래머 대상 기능을 모두 포함하려 했고, 필요한 기능을 모두 표현하기에는 약하지만 느린 Makefile을 쓰기에는 충분히 강한 언어가 됨
- Ninja는 이런 방향을 피하려고 했음
기본값이 체감 성능을 지배함
- Ninja는 기본적으로 원하는 명령을 병렬 실행함
- Make도
-j플래그로 병렬 실행이 가능하지만, 기본값은 직렬 실행임 - Makefile은 의존성을 충분히 명시하지 않아 병렬 실행이 안전하지 않은 상태로 작성되기 쉬움
- Ninja는 단일 코어 시스템에서도 항상 병렬 실행하므로 이런 오류를 더 일찍 드러냄
- Ninja에 잘 맞는 프로그램은 보통 병렬 빌드에도 안전해짐
- Ninja가 잘못된 의존성을 감지하는 고급 시스템을 가진 것은 아니며, 잘못된 빌드가 더 자주 발생하면서 문제가 드러나는 구조임
- 사용자가 Make의 병렬 실행 플래그를 잊거나 모르는 경우가 많기 때문에, 기본값 하나만으로도 Ninja가 실제 사용에서 Make보다 “두 배 이상 빠르게” 느껴질 수 있음
- 사용자가 실제로 경험하지 못하는 최적화는 의미가 작음
속도에서 중요했던 지표
- 빌드 시스템의 성능에는 여러 의미가 있음
- 처음부터 전체 빌드가 얼마나 걸리는지
- 이미 빌드한 뒤 파일 하나를 수정하고 다시 빌드하는 데 얼마나 걸리는지
- Ninja는 대형 코드베이스의 증분 빌드에서 편집-컴파일 루프를 빠르게 하는 데 집중함
- 처음 Ninja를 만들 때는 blaze, 즉 bazel이 매우 빠르다는 기억 때문에 그 속도를 따라잡으려 했음
- 나중에 보면 관심 있던 지표에서는 blaze가 특별히 빠르지 않았고, Java 프로그램이라 도움말 출력조차 느렸음
- 증분 빌드에 집착한 이유는 반복 시간이 프로그래머 만족도에 큰 영향을 준다고 봤기 때문임
- Ninja는 편집-컴파일 루프에서 쓰이며, 1초와 4초의 차이가 중요함
- “빠름”의 의미는 사용자에게 전달하기 어렵고, Ninja 매뉴얼은 작은 프로젝트에서 속도 효과가 거의 느껴지지 않을 수 있다고 경고함
- 하지만 “빠름”은 잘 팔리는 표현이라, 기능 부족에 좌절하는 소형 앱 사용자도 Ninja를 쓰려 함
- Ninja는 증분 재빌드에 집중했지만, 일부 사용자는 전체 빌드 성능도 좋아졌다고 보고함
- Ninja가 거의 아무것도 하지 않아 빌드 중 CPU를 적게 사용하고, 실제 빌드 작업에 CPU를 덜 빼앗기기 때문임
- 출력도 매우 간결함
- 성공한 빌드는 대부분 한 줄만 출력함
- 다른 빌드 시스템은 여러 단계와 타이밍 정보를 많이 출력해 무겁게 느껴질 수 있음
- 적게 말하는 구조가 Ninja를 더 “없는 것처럼” 느끼게 함
확산을 키운 CMake 통합과 Windows 지원
-
CMake
- Ninja는 원래 Chrome의 특수한 빌드 시스템과 함께 쓰려고 만들어짐
- Peter Collingbourne이 Ninja를 더 널리 쓰이는 CMake 빌드 시스템에 연결하는 작업을 수행함
- 이 통합은 LLVM 작업을 위해 시작됐고, CMake뿐 아니라 Ninja 쪽에도 새로운 의미론을 추가해야 했음
- 실제 세계에서 Ninja가 성공하는 데 가장 큰 공로가 있는 사람으로 Peter가 꼽힘
- 이후 CMake 작성자들이 통합을 넘겨받았지만, 요청과 우려에 충분히 대응하지 못했음
- 개발자는 지금까지 CMake를 직접 사용한 적이 없음
-
Windows
- Chrome이 Windows도 대상으로 했기 때문에 Ninja도 Windows에서 동작하게 됨
- Windows 지원의 상당 부분은 기여자가 작성함
- 기술적으로 Windows 지원은 큰 번거로움임
- 프로세스 실행과 출력 캡처는 플랫폼별 API를 새로 배워야 하는 종류의 차이임
- Ninja 설계는 커널이 캐시한 파일의 마지막 수정 시각을 빠르게 가져올 수 있다는 성질에 의존하는데, Windows에서는 이것이 성립하지 않음
- 그럼에도 Windows는 개발자 규모가 큰 플랫폼임
- Linux용 멋진 도구는 공유하려는 충동이 강하지만, Windows용 도구는 판매하려는 충동이 강해 자유롭게 제공되는 도구가 상대적으로 적음
- 초기 Ninja 사용자 중 Windows 사용자가 많았던 점은 당시에는 놀라웠지만, Windows 개발자 수가 많기 때문에 일부만 관심을 가져도 사용자로 나타남
관련 작업을 이해하는 일
- Ninja는 처음에는 주말 데모 해킹처럼 시작했기 때문에, 만들기 전에 관련 작업을 충분히 조사하지 못한 점을 아쉬워함
- 무언가를 만들 때는 설계 공간을 실제로 이해하는 일이 중요함
- “action graph”라는 용어는 Ninja를 만들 때 사용한 표현이 아니라 Google의 빌드 시스템인 blaze/bazel에서 가져온 것임
- bazel은 “library”, “binary” 같은 고수준 타깃 그래프가 명령의 그래프인 action graph를 생성한다고 설명함
- 명령줄 텍스트를 파일과 같은 입력으로 보는 발상은 증분 계산의 한 사례임
- 증분 계산은 빌드 시스템뿐 아니라 UI의 증분성에도 연결됨
- Jane Street 블로그에는 Incremental 소개 글이 있으며, React 같은 UI 구성 방식과도 연결됨
- "Build Systems à la Carte"는 빌드 시스템 맥락에서 증분 계산을 논의하는 논문이며, Ninja 작성 전에 존재했으면 좋았을 자료로 꼽힘
오픈소스 유지보수의 부담
- 오픈소스 메인테이너 경험은 특별히 즐겁지 않았음
- 프로젝트에 대한 감정은 누군가 좋은 말을 해줄 때의 자부심과 더 큰 실망감이 섞여 있음
- 무료로 공개한 결과, 가끔 친절하게 요청하는 사람도 있었지만 더 자주 화난 사용자가 요구했고, 감사 인사는 드물었음
- 요구를 받아들이지 않으면 포크하겠다고 위협하는 사람도 반복적으로 있었음
- 설계 목표와 충돌하는 합리적인 기여도 또 다른 어려움이었음
- 친절하고 똑똑한 사람이 낸 기여를 거절하려면 충분한 설명으로 보답하고 싶었고, 그 설명 자체가 지치는 일이었음
- 자유 소프트웨어를 통해 프로그래밍에 입문했고 받은 것을 돌려주고 싶어 코드를 썼지만, 지금의 자유 소프트웨어는 동등한 사람 사이의 공유라기보다 사용자가 자신을 고객처럼 여기고 작성자를 매니저에게 불평할 수 있는 대상으로 대하는 흐름이 있음
- 지금의 동기는 널리 성공하는 것보다 존경하는 소수 해커에게 인상을 남기거나 그 기대에 부응하는 것에 가까움
- Ninja의 성공은 많은 것을 배우게 했지만, 더 작은 성공만으로도 비슷한 배움을 얻을 수 있었을 것이라 봄
메인테이너와 기여자
- Nico Weber는 신중한 협업자였고, 수년 동안 Ninja 메인테이너를 맡음
- Jan Niklas Hasse는 Nico 이후 프로젝트를 넘겨받았고, 잘 해내고 있는 것으로 보임
- 그 밖에도 많은 Ninja 기여자가 프로젝트에 참여함
댓글과 토론
Hacker News 의견들
-
“프로그래밍은 코드 작성처럼 말하지만, 실제로는 코드보다 아키텍처가 더 중요하고, 아키텍처보다 사회적 이슈가 더 중요해진다”는 표현이 오래 마음속에 있던 생각을 정확히 말해줌
- 강하게 동의함. Peopleware 1987 [1]에서도 같은 얘기를 함
책 1장은 “우리 일의 주요 문제는 기술적이라기보다 사회학적 성격이 크다”고 주장하고, 팀 케미스트리와 결속, “몰입 시간”, 조용한 작업 환경, 이직 비용 같은 사회적·정치적 문제를 다룸
[1] https://en.wikipedia.org/wiki/Peopleware:_Productive_Project... - 프로그래밍과 그 도구는 컴퓨터가 아니라 사람을 위한 것이고, 아주 사소한 일을 제외하면 컴퓨터 위에서 동작하는 무언가를 만들려면 여러 사람이 필요함
그래서 소프트웨어 공학은 많은 이들이 인정하거나 편해하는 것보다 훨씬 사회과학에 가깝다고 봄. 사회과학은 자연과학보다 유동적이고 덜 예측 가능하니, 사회적 부분을 피하거나 아주 원시적으로만 다루려는 경향이 있는 듯함. 기술의 원자적 디테일에는 집착하면서도, 정작 팀이 만든 제품은 너무 자주 형편없어짐 - https://en.wikipedia.org/wiki/Conway's_law
“시스템을 설계하는 조직은 그 조직의 커뮤니케이션 구조를 복제한 설계를 만들 수밖에 없다.” — Melvin E. Conway, How Do Committees Invent? - 내 경험상 기술 문제의 대략 80% 는 두 사람이나 두 팀이 그냥 마주 앉아 이야기하기를 꺼려서 생김
- 그렇다고 이분법은 아님. 좋은 아키텍처는 사람들이 시스템에 요구하는 바를 충족하면서도, 인간이 이해할 수 있게 유지해줌
- 강하게 동의함. Peopleware 1987 [1]에서도 같은 얘기를 함
-
당시에도 논의됐음:
The Success and Failure of Ninja - https://news.ycombinator.com/item?id=23157783 - 2020년 5월, 댓글 38개
1년쯤 지나면 재게시도 괜찮고, 과거 스레드 링크는 더 궁금한 독자를 위한 것임 -
“Android가 시스템의 어떤 큰 컴포넌트에 Ninja를 쓰는데, 정확히는 이해한 적이 없다”는 부분이 웃김
Ninja는 실제로 AOSP에서 큰 비중을 차지함. 빌드 시스템은 처음엔 Makefile을 썼지만, 커스텀 선언형 빌드 시스템인 soong과 실패·중단된 Bazel 마이그레이션 때문에 빠르게 복잡해졌음. Google은 Makefile을 Ninja 빌드 파일로 바꾸는 kati(https://github.com/google/kati)를 만들었고, 그 결과물은 정말 거대함:
λ wc -l out/build-qssi.ninja
3035442 out/build-qssi.ninja
Makefile/soong에서 Ninja로 넘어가는 과정은 고통스럽고 최신 머신에서도 몇 분 걸리지만, Ninja가 받아 든 뒤에는 엄청 빠르게 돈다- Ninja를 써본 적이 없는데, Makefile과 비교해 어떤 장점이 있는지 궁금함
한 도구에서 다른 도구로 번역하기 위해 또 다른 도구를 도입할 가치가 있는지도 의문임. 특히 Ninja 파일이 저렇게 크고 사람이 읽기 어려울 수 있다면 더 그렇다
- Ninja를 써본 적이 없는데, Makefile과 비교해 어떤 장점이 있는지 궁금함
-
“프로그래머는 지연 시간을 체감하고, 본인이 알아차리지 못해도 기분에 영향을 받는다고 믿는다. Google이 최근 이 분야 연구를 했고 내 믿음을 어느 정도 확인해줬다”는 부분에서, 그 지연 시간 연구가 실제로 공개됐는지 궁금함
- 저자가 가리킨 정확한 연구인지는 모르겠지만, 이 논문일 수 있음: https://www.computer.org/csdl/magazine/so/2023/04/10176199/1...
- 400ms Doherty Threshold는 빌드에도 적용됨
-
Ninja는 게임 개발자 사이에서 꽤 인기 있음
“Windows는 여전히 개발자 측면에서 거대한 플랫폼이고, 그 개발자들은 도구에 굶주려 있다”는 문장이 재미있었음. 주로 Windows에서 개발하는 입장에서는 오히려 좋은 디버거인 Visual Studio나 프로파일러인 Superluminal 없이 사는 Linux 개발자들이 도구에 굶주린 것처럼 느껴짐. 최근에는 두 플랫폼 사이의 격차가 점점 작아지는 듯하고, 대체로 크로스플랫폼으로 동작하는 Rust 유틸리티들도 마음에 듦- 누가 Visual Studio와 “좋다”를 같은 문장에 넣을 때마다, 우주가 시뮬레이션이고 다른 사람들은 다른 우주에서 온 것 같다는 이상한 느낌이 듦
Visual Studio와의 상호작용 중 “좋다”고 부를 만한 게 떠오르지 않음. “간신히 괜찮다” 정도는 몇 개 생각나지만 디버깅은 거기에 들어가지 않음. 다만 2022에서는 디버거가 더 이상 버그투성이가 아니니, 아마 그 얘기일 수도 있음 - 어떤 세계에서 Visual Studio 디버거가 좋다고 여겨지는지 모르겠음. 드디어 고쳤다면 모를까, 마지막으로 써봤을 때는 한 줄 단계 실행에 몇 초씩 걸릴 정도로 견딜 수 없이 느렸음
- UNIX가 개발자 도구의 전부라고 보는 커뮤니티가 있고, 그러다 숲만 보고 나무를 놓치는 것 같음
1993년에 Xenix를 접한 뒤 여러 변종을 써왔을 만큼 UNIX를 잘 알지만, WSL은 Linux Docker 컨테이너를 돌리는 용도 외에는 거의 쓰지 않음
- 누가 Visual Studio와 “좋다”를 같은 문장에 넣을 때마다, 우주가 시뮬레이션이고 다른 사람들은 다른 우주에서 온 것 같다는 이상한 느낌이 듦
-
아직 Ninja를 쓰던 몇 가지는 samurai로 바꿨고, 가능한 모든 면에서 개선됐음
그래도 이런 종류의 빌드 시스템은 방향이 틀렸다고 봄. 빌드 시스템에 원하는 것은 모든 전이적 입력의 내용을 해시해서, 그 결과가 레지스트리에 있는지 조회하는 것임- 맞음. 분산 캐시를 지원하는 빌드 시스템은 기본적으로 변경 확인에 타임스탬프 대신 다이제스트를 씀: Bazel, Pants, Buck 등이 그렇다
다만 모두 엄청 복잡함. 로컬 빌드만 놓고 보면 SCons와 Waf도 변경 감지에 해시를 쓰는 것으로 알고 있음 - Ninja 작성자가 만든 n2에 관심이 있을 수 있음
- 그게 NetKernel의 아이디어였던 것 같음
비슷한 것으로 Deno 라이브러리 “TDAR”[1]를 만들었고 잘 동작하지만, 변경 가능한 파일시스템에서 동작한다고 가정하는 명령줄 도구들을 순수 함수처럼 호출하는 척 감싸려면 손이 좀 감
[1] 아직 상위 프로젝트[2]에서 따로 빼내지는 않았지만, 이 YouTube 영상에서 이야기했음: https://youtu.be/sty29o8sUKI
[2] 이런 것에 관심이 있다면 소스를 공개하라고 찔러도 됨. togos zero zero at gee mail dot comb - Samurai가 뭐가 더 나은지 궁금함. Ninja의 호환 하위집합이라고 생각했음
그리고 “내가 원한 것이 아니다”가 곧 “틀렸다”는 뜻은 아님. 세상에는 취향이 다른 사람들도 있기 때문임 - Samurai가 아직 살아 있는지 모르겠음. 시그널 처리를 개선하는 풀 리퀘스트를 보냈는데 반년 넘게 무시된 채로 있음
- 맞음. 분산 캐시를 지원하는 빌드 시스템은 기본적으로 변경 확인에 타임스탬프 대신 다이제스트를 씀: Bazel, Pants, Buck 등이 그렇다
-
CMake에서 C++20 모듈을 쓰려면 Ninja가 필요하므로, Ninja는 꽤 오래 남아 있을 것임
-
가장 흥미로웠던 부분은 “정확성과 편의성 또는 성능 사이에서 자주 타협해야 하며, 그 연속선상에서 어디를 택하는지 의식적이어야 한다”는 대목임
어떤 프로그래머들은 이 동역학을 너무 경직되게 보며, 한쪽 가치가 당연히 우선한다고 생각함. 하지만 실제로는 상호작용이 꽤 미묘함. 예를 들어 정확성을 일부 희생하고 편의성을 택한 도구가, 더 정확하지만 덜 편리한 대안보다 전체 생태계에서는 더 올바른 결과를 낼 수 있음. 프로그래머들이 후자를 피하게 되면 그렇다- 이건 정말 금광 같은 통찰임. 그래서 Python, Go, TypeScript/JavaScript가 Haskell/OCaml보다 훨씬 더 인기 있음
-
“부끄러운 이름은 용서해달라”니, 이름은 훌륭함
추신: 이걸 구현하면 더 빠르게 만들 수도 있음: https://github.com/ninja-build/ninja/issues/2157 다만 글에서 설명했듯 이 도구는 이전 실행에서 나온 아주 작은 힌트조차 포함해 상태를 의도적으로 갖지 않음