측정해 보고 나서 개발 환경을 덜어냈다
5 views
# 덜어냄의 공학, 미니멀 개발 환경은 취향이 아니라 측정의 결과다
## 무거움은 어떻게 기본값이 되었는가
새 노트북을 받은 첫날은 대개 비슷하게 흘러간다. 통합 개발 환경을 깔고, 쓰던 확장 기능 수십 개를 복원하고, 언어 런타임과 패키지 관리자를 겹겹이 얹는다. 일주일쯤 지나면 에디터가 뜨는 데 십수 초가 걸리고, 터미널 프롬프트 하나 그려지는 데도 지연이 느껴지고, 코드를 한 줄도 안 쳤는데 팬이 돌기 시작한다. 하드웨어는 해마다 빨라지는데 개발자의 대기 시간은 좀처럼 줄지 않는다.

원인은 단순하다. 개발 도구의 세계에서 추가는 쉽고 제거는 어렵다. 확장 기능 하나, 프레임워크의 추상화 계층 하나, 셸 설정 파일의 플러그인 한 줄은 각각 사소해 보이지만, 쌓이면 시작 시간과 메모리와 디스크에서 복리로 비용을 청구한다. 문제는 대부분의 개발자가 이 비용을 재 본 적이 없다는 데 있다. 느려졌다는 감각은 있는데, 무엇이 얼마나 느리게 만들었는지는 모른 채 산다.
미니멀 개발 환경은 도구를 무조건 줄이는 금욕이 아니다. 측정을 근거로 불필요한 계층과 오버헤드를 제거한 의사결정의 결과다. 빈 화면의 미학이나 유행하는 검소함과는 무관하다. 물어야 할 질문은 "무엇을 넣을 것인가"가 아니라 "무엇을 덜어낼 것인가"고, 그 답은 취향이 아니라 수치가 내린다.
## 덜어냄의 철학적 토대와 정량적 증거
이런 관점 자체는 새롭지 않다. Mary Poppendieck이 정리한 린 소프트웨어 개발의 첫 번째 원칙이 낭비의 제거, 곧 가치를 만들지 않는 모든 것을 걷어내라는 요구다. 개발 환경에 대입하면 쓰지 않는 확장 기능, 통과만 하는 추상화 계층, 언젠가 필요할지 모른다며 미리 깔아 둔 런타임이 전부 낭비에 해당한다. 결정을 필요한 시점까지 미루라는 린의 가르침은 환경 구성에서 "지금 쓰지 않는 것은 지금 설치하지 않는다"는 규율로 번역된다.
유닉스 철학도 같은 방향을 가리킨다. 한 가지 일을 잘하는 작은 프로그램을 만들고 텍스트 스트림으로 연결하라는 Doug McIlroy의 원칙은 거대한 단일 도구 대신 합성 가능한 부품의 조합을 권한다. 단일 책임과 합성 가능성, 이 두 성질이 미니멀 환경의 구조적 뼈대다.
수치도 뒤따른다. 컨테이너용 경량 리눅스인 Alpine Linux는 약 13.1MB, 애플리케이션 실행에 필요한 최소 파일만 남긴 Distroless 이미지는 약 20MB로, 범용 이미지 대비 디스크 사용량과 공격 표면을 동시에 줄인다. 프레임워크 쪽에서는 .NET의 Minimal API나 Node.js의 Fastify처럼 리플렉션과 추상화 계층을 걷어낸 설계가 초당 요청 처리량에서 우위를 입증했다. 미니멀 구성은 대체로 디스크 사용량을 3배에서 5배 줄이고, 콜드 스타트를 2배에서 4배 당기며, 메모리 점유를 절반 수준으로 낮춘다. 다만 이 수치를 남의 벤치마크로 소비하고 끝내면 곤란하다. 명령 실행 시간을 재는 hyperfine, 프로세스별 실메모리를 보여 주는 ps_mem으로 자기 환경을 직접 재야 덜어냄이 신념이 아니라 공학이 된다.
## 코어에서 재현성까지, 무엇을 남길 것인가
가장 안쪽은 에디터다. 키 입력이 편집 명령으로 작동하는 모달 에디터, 곧 Neovim이나 Helix가 한 축이고, VS Code 같은 모델리스 에디터가 다른 축이다. Neovim은 lazy.nvim의 지연 로딩으로 플러그인을 필요한 순간에만 불러 시작 시간을 지키고, Helix는 언어 지원을 내장한 채 가벼움을 기본값으로 삼는다. VS Code를 쓰더라도 시각적 소음을 줄이는 설정만으로 오버헤드를 꽤 걷어낼 수 있다. 어느 에디터가 우월한가보다, 자기 시작 시간과 메모리 점유를 재고 골랐는가가 갈림길이다.
에디터를 감싸는 층은 터미널과 셸이다. GPU 가속 터미널인 Alacritty, Kitty, WezTerm은 저마다 풋프린트가 다르고, 셸 프롬프트조차 렌더링 비용을 청구한다. Powerlevel10k가 instant prompt로 체감 지연을 지우는 방식과 Starship의 비동기 처리 비용을 나란히 놓고 보면, 프롬프트 한 줄에도 측정할 만한 트레이드오프가 있다. 그 위에서 grep, find, cat, ls의 현대적 대체재인 ripgrep, fd, fzf, bat, eza가 텍스트 파이프라인으로 엮인다. 사십 년 전의 유닉스 철학이 지금도 그대로 통하는 지점이다.

언어 툴체인도 마찬가지다. Python에서 pyenv와 uv 조합은 기존 pip 대비 8배에서 100배의 속도 향상과 통합 관리를 제공한다. Node.js에서는 pnpm의 효율적인 node_modules 배치와 Yarn Berry의 zero-installs가 서로 다른 방식으로 중복을 없애고, C/C++와 Rust에서는 sccache나 Ninja 같은 컴파일 캐시가 반복 빌드의 낭비를 걷어낸다. 런타임 버전 관리자의 세대교체가 특히 상징적이다. asdf의 shim 방식이 호출마다 약 120ms를 지불했다면 mise는 같은 일을 5에서 10ms에 해낸다. 기능은 같은데 계층 하나를 뺀 대가가 스무 배의 지연 차이로 나타났다.
마지막 층은 재현성이다. 아무리 잘 깎은 환경도 다시 만들 수 없으면 개인의 수공예품에 그친다. devcontainer.json 표준 명세는 컨테이너 기반 환경을 선언적으로 기술해 GitHub Codespaces까지 이어지고, Nix Flakes는 순수 샌드박스 빌드로 바이트 수준의 재현성을 보장한다. 설정 파일 관리에서는 심볼릭 링크의 GNU Stow, bare Git 방식의 yadm, 템플릿과 비밀 관리를 갖춘 chezmoi가 각자의 자리에서 "내 환경을 코드로 남긴다"는 같은 목적에 복무한다. 덜어냄의 종착점은 가벼움 자체가 아니라, 가볍고도 언제든 복원 가능한 상태다.
## 반론 앞에서, 그리고 방향으로서의 미니멀
반론도 만만치 않다. Jonathan Blow를 비롯한 이들은 작은 도구의 조합이 오히려 통합의 복잡성을 낳는다고 비판해 왔다. 정당한 지적이다. 열 개의 도구를 잇는 접착 스크립트가 하나의 통합 도구보다 무거워지는 순간은 실제로 온다. 미니멀리즘 자체의 과잉이라는 함정도 있다. 시작 시간 10ms를 줄이려고 주말을 바치거나 쓰지도 않을 Nix 표현식을 다듬는 일은 낭비 제거라는 명분을 쓴 새로운 낭비다. 플랫폼 고유의 비용도 있다. Windows의 WSL2에서는 파일시스템 경계를 넘는 접근이 성능을 무너뜨리기 때문에 작업 디렉토리를 ext4 안에 두어야 한다.
그래서 급진보다 단계가 낫다. 현재 환경의 병목을 수치로 확인하고, 가장 비싼 계층 하나를 교체하고, 효과를 다시 재는 점진적 로드맵이 과잉 엔지니어링을 막는 규율이다. 미니멀은 도달해야 할 상태가 아니라 유지해야 할 방향이다. 도구는 바뀐다. 오늘의 uv와 mise도 언젠가 다른 이름에 자리를 내줄 것이다. 그래도 낭비를 측정하고, 계층을 의심하고, 합성 가능한 작은 부품을 선호하는 원칙은 도구보다 오래 남는다.
개발 환경은 개발자가 매일 지나는 통로다. 거기서 무엇을 덜어낼지 직접 재고 결정하는 사람만이 도구에 부림을 당하지 않고 도구를 부린다.