Chapter 4

점진주의와 경험주의

  • 4.1 우주선 예시로 살펴보는 모듈성
  • 4.2 효율 높은 조직 구성을 위한 비법
  • 4.3 점진주의를 적용하기 위한 실천 도구
  • 4.4 변경의 부작용을 최소화하자
  • 4.5 점진적인 설계
  • 4.6 꿈은 높게 그러나 발은 땅에
  • 4.7 실험과 경험은 분리해야 한다
  • 4.8 "저 이 버그 알아요!"
  • 4.9 자기기만은 우리의 적
  • 4.10 우리의 주장에 맞는 현실을 발명하자
  • 4.11 추측보다는 실험: 현실에 입각한 경험주의

지금 필요한 것만 만들되 나중에 바꿀 수 있는 구조를 유지하는 것이 점진주의고, 그 판단을 감이 아니라 증거에 기반하게 만드는 것이 경험주의야.

"나중에 필요할 것 같으니까 미리 만들어두자" — 이 말이 나올 때마다 Farley는 경고해. 거의 항상 낭비야. 점진주의의 핵심은 지금 필요한 것만 만들되, 나중에 바꿀 수 있는 구조를 유지하는 것이야.

반복(Iteration)과 비슷해 보이지만 다른 개념이야. 반복은 "같은 것을 개선해나가는 것"이고, 점진주의는 **"전체를 작은 조각으로 나눠서 하나씩 전달하는 것"**이야. 그리고 점진주의가 가능하려면 기술적 기반이 필요한데, 그게 바로 **모듈성(Modularity)**이야.

우주선을 생각해봐. 인류가 만든 가장 복잡한 시스템 중 하나인데, 한 번에 전체를 조립하는 게 아니라 추진 시스템, 생명 유지 시스템, 통신 시스템을 각각 독립적으로 개발하고 검증한 다음 조합하잖아. 각 모듈이 명확한 인터페이스를 가지고 있으니까, 추진 시스템을 개선해도 통신 시스템을 바꿀 필요가 없어. 소프트웨어도 마찬가지야. 모놀리식 스파게티 코드에서는 "이 부분만 먼저 배포"가 불가능하거든.

조직 구조도 중요해. 콘웨이의 법칙 — 시스템의 구조는 그것을 만든 조직의 구조를 반영해. Farley는 이걸 뒤집어서 쓰자고 해. 원하는 시스템 구조에 맞게 조직을 구성하는 역콘웨이 전략이야. 하나의 기능을 추가하려고 프론트엔드 팀, 백엔드 팀, DB 팀, QA 팀이 모두 조율해야 한다면, 점진적 전달은 꿈일 뿐이야. 기능 단위의 크로스 펑셔널 팀이 있어야 한 팀이 하나의 기능을 처음부터 끝까지 독립적으로 만들고 배포할 수 있지.

실천 도구도 있어. 피처 플래그로 미완성 기능을 안전하게 메인 브랜치에 통합하고, 브랜치 바이 앱스트랙션으로 빅 뱅 리팩토링 대신 점진적으로 전환하고, 다크 론칭으로 프로덕션 부하에서 새 코드를 검증할 수 있어. 공통점은 변경의 위험을 줄이면서 지속적으로 전진할 수 있게 해준다는 거야.

결국 점진주의가 가능하려면 높은 응집도, 낮은 결합도, 정보 은닉 — 수십 년 전부터 있던 이 원칙들이 제대로 지켜져야 해. 그래야 A를 바꿨는데 B가 깨지는 일이 없지. 설계도 마찬가지야. 처음부터 완벽한 아키텍처를 만들겠다는 생각을 버리고, 현재 알고 있는 것에 기반한 가장 단순한 설계로 시작해서 필요할 때 진화시켜 — 이게 **진화적 설계(Evolutionary Design)**야. 유연한 설계란 "모든 것을 확장 가능하게 만드는 것"이 아니라, **"변경 비용을 낮게 유지하는 것"**이야.

그런데 점진적으로 나아가면서 어떤 방향이 맞는지는 어떻게 판단할까? 여기서 경험주의가 등장해. "아, 저 이거 뭔지 알아요" — 디버깅에서 이 말이 나오는 순간이 가장 위험해. 과거에 비슷한 증상을 봤으니까 원인도 같을 거라고 성급하게 결론내리는 건데, 같은 증상이라도 원인은 전혀 다를 수 있거든.

Farley는 소프트웨어 엔지니어들이 빠지기 쉬운 인지적 함정들을 하나씩 까발려. 확증 편향 — 내 가설을 지지하는 증거만 보고 반박하는 증거는 무시하는 것. 매몰 비용의 오류 — "이미 6개월 투자했으니 계속 가야 해." 방향이 잘못됐으면 지금 바꾸는 게 가장 비용이 적은데도. 던닝-크루거 효과 — 새 프레임워크를 튜토리얼 수준으로 써보고 "다 아는데?"라고 생각하지만, 프로덕션에서 만나는 문제는 차원이 다르잖아.

가장 교묘한 건 자기 주장에 맞는 현실을 만들어내는 경향이야. "우리 코드 품질은 좋아" — 그러면 버그 리포트를 "사용자 오류"로 분류해. "우리 팀 생산성은 높아" — 그러면 배포 빈도나 리드타임 같은 지표는 측정하지 않아. 측정하면 불편한 진실이 드러나니까.

그래서 Farley가 강조하는 미묘하지만 중요한 구분이 있어. **경험(Experience)**과 **실험(Experiment)**은 다르다는 거야. "전 회사에서 마이크로서비스로 전환했는데 좋았다" — 이건 경험이야. 유용하지만, 그 상황과 지금 상황이 같다는 보장이 없어. 실험은 현재 맥락에서 가설을 세우고 검증하는 행위야. 경험에만 의존하면 과거 패턴을 현재에 무비판적으로 적용하는 오류를 범하게 돼.

이 모든 함정에 대한 처방은 하나야 — 추측하지 말고 측정하라. "이 함수가 느린 것 같다"가 아니라 프로파일링으로 확인해. "항상 그래왔다"에 의문을 품어. 작은 실험을 자주 하고, 결과가 내 기대와 다르면 기대를 바꿔야지 결과를 무시하면 안 돼. 과학적 방법의 핵심은 가설을 증명하는 게 아니라, 반증 가능한 가설을 세우고 틀렸는지 확인하는 거거든. 말처럼 쉽지 않아. 인간의 본능이 "내가 맞다"고 말하니까. 하지만 이 본능을 극복하는 과학적 사고의 훈련이 소프트웨어 엔지니어의 핵심 역량이야.


정리

4장 읽고 기억할 거 세 가지:

  1. 점진주의는 "지금 필요한 것만 만들되, 나중에 바꿀 수 있는 구조를 유지하는 것"이야. 모듈성과 진화적 설계가 이걸 가능하게 해.
  2. 경험과 실험을 구분하라. 과거의 경험을 현재에 무비판적으로 적용하지 말고, 현재 맥락에서 가설을 세우고 검증해.
  3. 추측하지 말고 측정하라. 확증 편향, 매몰 비용의 오류, 던닝-크루거 효과 — 우리의 인지적 편향을 극복하는 과학적 사고가 핵심 역량이야.