본문으로 건너뛰기

Best Simple System for Now

Daniel Terhorst-Northdannorth.net ↗

목차44개 항목

핵심 요약

Best Simple System for Now는 소프트웨어 시스템을 만들 때 “미래에 필요할지도 모르는 완벽한 구조”가 아니라, 지금의 맥락에서 가장 적절하고 단순하며 실제로 작동하는 시스템을 선택하자는 사고방식이다.

이 접근은 빠르게 만드는 것과 오래 버틸 수 있게 만드는 것을 이분법으로 보지 않는다. 한쪽에는 “빨리 정상에 오르기 위해 뒤를 돌아보지 않고 밀어붙이는 방식”이 있고, 다른 한쪽에는 “처음부터 모두가 따라올 수 있는 완벽한 길을 닦으며 천천히 오르는 방식”이 있다. Best Simple System for Now는 이 둘 사이에서 균형점을 찾는다. 즉, 지금 필요한 만큼 충분히 잘 만들고, 실제 피드백을 통해 다음 구조를 결정하는 방식이다.

이 문서의 핵심 주장은 다음과 같다.

  • 미래 예측은 대체로 “거의 맞지만, 그 거의가 문제를 만든다.”
  • 단순함은 고정된 속성이 아니라 현재 맥락에 따라 변한다.
  • 좋은 시스템은 처음부터 복잡하게 설계되지 않고, 작동하는 단순한 시스템에서 진화한다.
  • 프로토타입이나 스파이크 코드도 생산에 들어갈 수 있으므로, 처음부터 최소한의 품질 기준은 지켜야 한다.
  • 빠른 출시와 지속 가능한 구조는 반대 개념이 아니다.
  • 중요한 것은 큰 설계 선언이 아니라 좋은 습관, 용기, 겸손이다.

1. 문제의식: 빠르게 가는 팀과 길을 만드는 팀

소프트웨어 조직에는 자주 두 가지 성향이 충돌한다.

첫 번째 성향은 빠르게 결과를 내는 데 집중한다. 이들은 문제를 만나면 바로 구현하고, 장애물을 우회하거나 뚫고 지나가며, 가능한 한 빨리 목표 지점에 도달한다. 장점은 명확하다. 시장 반응을 빨리 얻고, 비즈니스 가치를 조기에 실현한다. 그러나 뒤를 돌아보면 복잡한 코드, 임시방편, 관리되지 않는 의존성, 불명확한 책임 경계가 남을 수 있다.

두 번째 성향은 신중하게 구조를 만든다. 이들은 재사용성, 확장성, 품질, 팀의 지속 가능성을 중요하게 여긴다. 덕분에 이후 사람들이 따라올 수 있는 길이 생긴다. 그러나 과도하게 신중해지면 아직 검증되지 않은 요구사항을 위해 구조를 만들고, 실제 가치가 나오기 전에 많은 시간을 소비한다.

이 충돌은 단순히 “해커 대 장인”, “빠름 대 품질”, “애자일 대 아키텍처”의 문제가 아니다. 실제 문제는 현재 필요한 수준의 구조와 품질을 어떻게 판단할 것인가다.

Best Simple System for Now는 이 판단을 위한 기준이다.


2. Best Simple System for Now의 의미

이 표현의 각 단어는 독립적인 의미를 가진다.

2.1 For Now: 지금을 기준으로 선택하기

“For Now”는 미래를 완전히 무시하자는 뜻이 아니다. 오히려 미래를 예측하려는 충동을 경계하자는 뜻이다.

경험 많은 개발자는 과거의 패턴을 많이 알고 있기 때문에 다음에 어떤 문제가 생길지 어느 정도 예상할 수 있다. 문제는 그 예상이 대개 “거의 맞다”는 점이다. 거의 맞는 예측은 위험하다. 실제 요구사항과 조금만 어긋나도, 미리 만들어둔 인터페이스, 추상화, 확장 포인트, API, 설정 구조가 오히려 발목을 잡는다.

현재 명확하지 않은 요구사항에 대해 추측으로 구조를 만들면 다음과 같은 비용이 생긴다.

  • 실제로 쓰이지 않는 확장 포인트를 유지해야 한다.
  • 구현은 단순한데 구조만 복잡해진다.
  • 변경 시 “미래를 위해 만든 설계”를 먼저 이해해야 한다.
  • 잘못된 예측을 되돌리기 위해 리팩터링이 아니라 해체 작업이 필요해진다.
  • 팀이 문제 자체보다 설계의 의도를 해석하는 데 시간을 쓴다.

따라서 “지금”은 게으른 선택이 아니라, 불확실성 앞에서 추측을 보류하는 절제다.

좋은 질문은 “언젠가 필요할 수 있지 않을까?”가 아니다. 더 나은 질문은 다음과 같다.

  • 지금 실제로 필요한가?
  • 지금 이 요구사항은 검증되었는가?
  • 지금 이 복잡성을 감당할 이유가 있는가?
  • 지금 추가하지 않으면 되돌릴 수 없는 결정인가?
  • 나중에 필요해졌을 때 추가하는 비용이 정말 더 큰가?

“For Now”는 미래를 닫는 것이 아니라, 미래가 실제로 드러날 때까지 결정을 지연하는 기술이다.


2.2 Simple: 본질만 남기기

단순함은 코드 줄 수가 적다는 뜻이 아니다. 단순함은 문제의 본질에 맞는 형태만 남아 있는 상태다.

많은 개발자는 문제를 보자마자 익숙한 해결책을 떠올린다. 패턴, 프레임워크, 메시지 큐, 마이크로서비스, 캐시, 이벤트 소싱, 플러그인 구조 같은 것들이 빠르게 후보로 올라온다. 그러나 단순한 해결책은 종종 더 근본적인 질문에서 나온다.

“정말 이 문제가 그 문제인가?”

예를 들어, 많은 데이터를 메모리에 올려 처리하다가 한계에 부딪혔다고 하자. 경험 많은 개발자는 메모리 관리, 배치 처리, 샤딩, 임시 파일, 병렬 처리 등을 떠올릴 수 있다. 그러나 문제의 본질이 “전체 데이터를 한꺼번에 들고 있어야 한다”가 아니라 “누적값을 계산해야 한다”라면, 해결책은 스트리밍 집계일 수 있다. 이 경우 거대한 구조가 아니라 단순한 누산기가 더 적절하다.

단순함은 현재 맥락의 함수다. 지난주에는 가장 단순했던 구조가 이번 주에는 더 이상 단순하지 않을 수 있다. 요구사항, 트래픽, 팀 규모, 운영 환경, 장애 비용, 규제 요건, 시장 압력이 바뀌면 “단순한 것”의 정의도 바뀐다.

단순함을 판단할 때 유용한 질문은 다음과 같다.

  • 이 문제의 핵심 데이터 흐름은 무엇인가?
  • 이 기능이 반드시 가져야 하는 책임은 무엇인가?
  • 지금 제거해도 되는 것은 무엇인가?
  • 구현 난이도를 높이는 가정은 무엇인가?
  • 더 적은 개념으로 같은 결과를 얻을 수 있는가?
  • 알고리즘 자체를 바꾸면 문제가 사라지는가?

좋은 단순함은 얕은 단순함이 아니다. 얕은 단순함은 대충 만드는 것이다. 좋은 단순함은 문제를 깊게 이해한 뒤 불필요한 것을 제거하는 것이다.


2.3 System: 코드만이 아니라 일하는 방식까지 포함하기

“System”은 애플리케이션 코드만 뜻하지 않는다. 시스템은 코드, 빌드, 배포, 테스트, 운영, 팀의 의사결정 방식, 커뮤니케이션 구조, 업무 프로세스까지 포함한다.

코드가 단순해도 배포가 복잡하면 시스템은 단순하지 않다. 아키텍처가 훌륭해도 의사결정 과정이 불투명하면 시스템은 둔해진다. 칸반 보드, 티켓 템플릿, 승인 절차, 문서화 방식, 릴리스 프로세스도 모두 시스템의 일부다.

따라서 Best Simple System for Now를 적용할 때는 다음도 함께 봐야 한다.

  • 지금 이 팀에 필요한 업무 추적 방식은 무엇인가?
  • 포스트잇이나 간단한 보드로 충분한가?
  • 복잡한 워크플로 도구가 실제 병목을 줄이는가, 아니면 새로운 병목을 만드는가?
  • 승인 절차는 위험을 줄이는가, 책임 회피를 만드는가?
  • 문서는 의사결정을 돕는가, 감사 흔적만 남기는가?
  • 빌드와 배포는 구조적 결정을 투명하게 드러내는가, 아니면 문제를 감추는가?

시스템은 코드보다 넓다. 그리고 많은 조직에서 복잡성은 코드가 아니라 일하는 방식에서 먼저 축적된다.


2.4 Best: 가장 훌륭한 것이 아니라 가장 적합한 것

“Best”는 절대적으로 가장 뛰어난 기술, 가장 최신의 프레임워크, 가장 엄격한 설계를 뜻하지 않는다. 여기서 Best는 현재 조건에서 가장 적합한 선택이다.

적합성은 여러 축을 함께 고려한다.

  • 비즈니스 가치
  • 출시 속도
  • 변경 가능성
  • 운영 안정성
  • 장애 비용
  • 팀의 숙련도
  • 도메인 불확실성
  • 규제와 보안 요구사항
  • 관측 가능성
  • 되돌릴 수 있는 정도

예를 들어, 안전 필수 시스템과 내부 관리자 도구는 같은 품질 기준을 가질 수 없다. 금융 결제 시스템과 실험용 추천 기능은 같은 릴리스 전략을 가질 수 없다. 10명의 스타트업과 1만 명 조직은 같은 아키텍처 원칙을 가져도 적용 방식은 달라야 한다.

Best는 “가장 많이 설계한 것”이 아니다. Best는 “현재의 리스크와 가치 흐름에 가장 잘 맞는 것”이다.


3. 작동하는 단순한 시스템은 진화한다

복잡한 시스템은 처음부터 완성형으로 설계될 때 실패하기 쉽다. 반대로 잘 작동하는 복잡한 시스템은 대개 작동하는 단순한 시스템에서 진화한다.

이 관점은 아키텍처를 “초기 설계의 완성도”가 아니라 “진화 가능한 구조”로 보게 만든다. 처음부터 모든 기능, 모든 확장성, 모든 팀 구조, 모든 장애 시나리오를 반영한 시스템을 만들려고 하면 시스템은 무거워진다. 아직 확인되지 않은 요구사항을 위해 복잡성을 먼저 지불하는 셈이다.

더 나은 방식은 다음 순서다.

  1. 지금 필요한 단순한 시스템을 만든다.
  2. 실제 사용자, 운영, 시장, 팀 피드백을 얻는다.
  3. 반복되는 변경 지점을 관찰한다.
  4. 안정적으로 남은 요구사항을 중심으로 구조를 강화한다.
  5. 더 이상 맞지 않는 구조는 과감히 교체한다.

여기에는 두 가지 변화 방식이 함께 필요하다.

첫 번째는 점진적 개선이다. 작게 개선하고, 조금씩 정리하고, 안정화하고, 배포 흐름을 개선한다. 두 번째는 급진적 전환이다. 기존 접근이 더 이상 적합하지 않을 때, 알고리즘·기술·팀 구조·제품 전략을 바꾸는 것이다.

중요한 것은 이 둘을 혼동하지 않는 것이다. 점진적으로 개선해야 할 때 매번 대전환을 시도하면 조직이 피로해진다. 반대로 근본적으로 다른 접근이 필요한데 기존 방식만 조금씩 손보면 시간을 낭비한다.


4. 스케치 코드와 해킹의 차이

빠르게 만드는 코드가 모두 나쁜 것은 아니다. 문제는 “빠르게 만들었다”가 아니라 “생산에 들어갈 수 없는 수준으로 만들었다”다.

여기서 중요한 개념은 스케치 코드다. 스케치 코드는 해킹과 다르다. 해킹은 일단 돌아가게만 만든 코드다. 스케치 코드는 필요한 만큼 덜 만들되, 실제 환경에서 버틸 수 있는 최소한의 구조와 안전장치를 갖춘 코드다.

스케치 코드는 다음 특성을 가진다.

  • 핵심 경로가 명확하다.
  • 불필요한 일반화를 피한다.
  • 실패 시 피해 범위를 제한한다.
  • 관측 가능성을 최소한 갖춘다.
  • 배포와 롤백이 가능하다.
  • 읽는 사람이 의도를 이해할 수 있다.
  • 나중에 안정화할 수 있는 여지를 남긴다.
  • 의존성을 과하게 늘리지 않는다.
  • 테스트가 전혀 없는 상태로 방치하지 않는다.
  • “버릴 코드”라는 이유로 품질 기준을 포기하지 않는다.

많은 성공적인 프로토타입은 다시 작성되지 않고 그대로 제품이 된다. 이 사실이 중요하다. “나중에 다시 만들 것”이라는 말은 자주 지켜지지 않는다. 사용자가 좋아하고 비즈니스가 반응하면 조직은 그것을 출시하려 한다. 따라서 초기 구현은 완성품 수준일 필요는 없지만, 제품으로 승격될 가능성을 견딜 수 있어야 한다.

스케치 코드를 잘 쓰려면 고급 설계 능력이 필요하다. 적게 그리면서도 본질을 남겨야 하기 때문이다. 이는 미숙함의 결과가 아니라 숙련의 결과다.


5. Spike and Stabilize: 먼저 찔러보고, 살아남으면 안정화하기

Best Simple System for Now의 실천 방식 중 하나는 Spike and Stabilize다.

원리는 단순하다.

  1. 모든 코드는 처음에는 스파이크로 시작한다.
  2. 작게 만들어 실제 환경에서 검증한다.
  3. 그 코드가 가치를 만들면 안정화한다.
  4. 가치가 없으면 버린다.

여기서 핵심은 “스파이크”를 쓰레기 코드로 취급하지 않는 것이다. 스파이크는 학습을 위한 코드이지만, 실제 환경에서 관찰할 수 있어야 한다. 그래서 최소한의 품질은 필요하다.

안정화 시점을 판단하는 기준은 다음과 같다.

  • 해당 코드를 다시 변경하러 왔다.
  • 사용자나 내부 팀이 계속 사용하고 있다.
  • 일정 기간 운영에서 살아남았다.
  • 장애나 운영 비용이 의미 있는 수준으로 드러났다.
  • 해당 코드 주변에 새로운 기능 요구가 붙기 시작했다.
  • 팀이 그 코드를 기반으로 다음 결정을 내리기 시작했다.

이 시점이 오면 코드의 위치를 다시 봐야 한다. 테스트를 보강하고, 책임 경계를 정리하고, 이름을 개선하고, 모니터링을 추가하고, 배포·롤백 경로를 강화하고, 필요하다면 설계를 재구성한다.

즉, 처음부터 완성된 구조를 만들지 않되, 가치가 확인된 코드에는 제때 투자한다.


6. 품질은 절대값이 아니라 맥락값이다

모든 시스템에 같은 품질 기준을 적용하는 것은 비효율적이다. 그러나 “맥락에 따라 다르다”는 말이 품질을 포기해도 된다는 뜻은 아니다.

품질은 시스템이 처한 위험과 목적에 맞아야 한다.

예를 들어 다음 시스템들은 서로 다른 품질 기준을 가져야 한다.

  • 의료 장비 제어 소프트웨어
  • 금융 결제 및 정산 시스템
  • 내부 실험 도구
  • 초기 제품 가설 검증 기능
  • 대규모 사용자 대상 협업 도구
  • 단발성 데이터 마이그레이션 스크립트
  • 고객에게 직접 노출되는 핵심 기능

각각에서 필요한 테스트, 감사 가능성, 배포 속도, 롤백 전략, 코드 리뷰 수준, 문서화 수준은 다르다. 중요한 것은 “품질을 얼마나 높일 것인가”가 아니라 어떤 품질이 지금 필요한가다.

실용적인 품질 질문은 다음과 같다.

  • 실패하면 누가 영향을 받는가?
  • 실패 비용은 얼마인가?
  • 문제를 얼마나 빨리 감지할 수 있는가?
  • 되돌릴 수 있는가?
  • 데이터 손상이 발생할 수 있는가?
  • 보안·규제 리스크가 있는가?
  • 이 코드는 오래 살 가능성이 높은가?
  • 이 기능은 아직 가설인가, 이미 검증된 핵심인가?

이 질문들에 답하지 않고 “무조건 빠르게” 또는 “무조건 견고하게”를 선택하면 둘 다 실패할 수 있다.


7. 경제성: 비용보다 지연을 봐야 한다

소프트웨어 조직은 종종 팀의 인건비, 도구 비용, 라이선스 비용 같은 활동 비용에 집중한다. 그러나 더 큰 비용은 자주 지연 비용이다.

지연 비용은 지금 출시했다면 얻을 수 있었지만, 아직 출시하지 못해서 잃는 가치다. 예를 들어 어떤 기능이 시장에서 즉시 수익을 낼 수 있는데 8주 뒤에 출시된다면, 그 8주는 회복할 수 없는 손실이다. 그 기간에 얻었을 사용자 피드백, 매출, 학습, 시장 포지션도 함께 사라진다.

여기에 기회비용도 있다. 한 팀이 A를 만드는 동안 B를 만들지 못한다면, B의 지연 비용도 함께 고려해야 한다. 따라서 실제 경제적 손실은 단순히 “이 팀이 한 달에 얼마를 쓰는가”보다 훨씬 클 수 있다.

Best Simple System for Now는 이 경제성을 다르게 본다.

전통적인 방식은 큰 투자를 먼저 하고 나중에 한 번에 가치를 회수하려 한다. 이 방식은 가치가 실현되기 전까지 위험이 계속 누적된다. 반면 작은 단위로 출시하고 학습하면 다음과 같은 효과가 있다.

  • 일부 가치를 더 빨리 실현한다.
  • 실패 범위를 줄인다.
  • 투자 대비 학습 속도가 빨라진다.
  • 제품이 스스로 다음 투자를 정당화할 수 있다.
  • 잘못된 방향을 더 일찍 발견한다.
  • 대규모 재작업 가능성을 낮춘다.

핵심은 ROI만 보는 것이 아니라, 위험을 조정한 자본 수익가치가 지연되는 비용을 함께 보는 것이다.


8. 왜 조직은 이 방식을 잘 하지 못하는가

Best Simple System for Now는 특별한 비밀 지식이 아니다. 오히려 기본기에 가깝다. 그런데도 많은 조직이 잘 실행하지 못한다. 주요 이유는 세 가지다.

8.1 습관

좋은 소프트웨어 개발은 지식보다 습관에 가깝다. 아무도 보지 않을 때 어떤 선택을 하는지가 중요하다.

  • 작은 변경을 자주 배포하는 습관
  • 불필요한 추상화를 미루는 습관
  • 측정 없이 최적화하지 않는 습관
  • 코드가 살아남으면 안정화하는 습관
  • 의존성을 추가하기 전에 비용을 따지는 습관
  • 복잡한 설계 대신 핵심 문제를 다시 묻는 습관
  • 빌드와 배포가 숨기는 문제를 주기적으로 드러내는 습관

결정은 한 번에 할 수 있지만, 습관은 반복으로 만들어진다. 따라서 이 접근은 선언이 아니라 훈련이다.

8.2 용기

현재 필요한 만큼만 만드는 것은 생각보다 용기가 필요하다. 왜냐하면 “아직 만들지 않겠다”는 선택은 외부에서 무책임해 보일 수 있기 때문이다.

팀은 다음 두려움과 마주한다.

  • 나중에 필요해지면 비난받지 않을까?
  • 다른 조직은 더 복잡한 구조를 쓰는데 우리가 뒤처진 것은 아닐까?
  • 지금 단순하게 만들면 미숙해 보이지 않을까?
  • 프로토타입이 제품이 되었을 때 문제가 되지 않을까?
  • 실패하면 내 판단이 틀렸다는 증거가 되지 않을까?

용기는 두려움이 없는 상태가 아니다. 두려움을 인식하고, 위험을 작게 만들고, 실험 가능한 범위에서 움직이는 것이다.

실천 전략은 간단하다. 큰 설득 대신 작게 실험한다.

  • 2주 동안만 시도한다.
  • 성공 기준을 미리 정한다.
  • 실패해도 손실이 제한되도록 한다.
  • 결과를 측정한다.
  • 작동하면 반복하고, 작동하지 않으면 배운다.

이 방식은 조직 내 신뢰를 만든다. 처음에는 사람을 믿고 시작하지만, 반복되면 팀이 자기 판단을 믿게 된다.

8.3 겸손

Best Simple System for Now는 자신의 예측 능력을 과신하지 않는 태도에서 출발한다. 경험은 중요하지만, 경험이 많을수록 “나는 이미 안다”는 착각도 강해질 수 있다.

겸손은 자신을 낮게 평가하는 것이 아니다. 문제, 사용자, 팀, 맥락을 자신보다 앞에 두는 것이다. 좋은 아키텍트나 리더는 자신의 설계를 증명하려고 하지 않는다. 팀이 더 잘 판단하고, 더 빨리 배우고, 더 안전하게 바꿀 수 있도록 돕는다.

겸손한 시스템 설계자는 다음을 인정한다.

  • 지금 모르는 것이 있다.
  • 미래 요구사항은 바뀔 수 있다.
  • 현재 선택은 나중에 후회될 수 있다.
  • 후회 자체가 실패는 아니다.
  • 초기 기술 결정 중 일부를 후회하지 않는다면 오히려 과설계했을 가능성이 있다.
  • 팀의 학습 속도가 설계의 완성도보다 중요할 때가 많다.

9. 리워크와 학습을 구분하기

조직에서 자주 나오는 말이 있다. “리워크는 낭비다.”

이 말은 절반만 맞다. 같은 실수를 반복해서 다시 만드는 것은 낭비다. 그러나 피드백을 받아 더 나은 방향으로 바꾸는 것은 낭비가 아니라 학습이다.

리워크가 낭비인지 학습인지 구분하려면 다음을 봐야 한다.

낭비에 가까운 경우:

  • 처음부터 알고 있던 요구사항을 무시했다.
  • 품질 기준을 의도적으로 포기했다.
  • 같은 결함이 반복된다.
  • 책임 경계가 불명확해 계속 수정이 번진다.
  • 배포 전 검증할 수 있었던 문제를 매번 운영에서 발견한다.

학습에 가까운 경우:

  • 사용자 반응이 예상과 달랐다.
  • 시장 조건이 바뀌었다.
  • 실제 운영 데이터가 새로운 병목을 드러냈다.
  • 처음에는 몰랐던 도메인 규칙이 확인되었다.
  • 더 단순한 알고리즘이나 모델을 발견했다.
  • 작은 출시 덕분에 큰 실패를 피했다.

중요한 것은 변경이 발생했다는 사실이 아니라, 변경을 통해 무엇을 배웠는가다.


10. 실천 원칙

Best Simple System for Now를 적용하려면 다음 원칙이 필요하다.

10.1 추측하지 말고 지연 가능한 결정을 지연하라

불확실한 요구사항을 위해 구조를 만들지 않는다. 되돌릴 수 없는 결정과 되돌릴 수 있는 결정을 구분한다. 되돌릴 수 있는 결정은 작게 시작하고, 되돌릴 수 없는 결정은 더 많은 근거를 요구한다.

10.2 복잡성을 추가할 때 명시적인 이유를 남겨라

새로운 추상화, 프레임워크, 인프라, 프로세스는 모두 비용이다. 추가할 때는 이유가 있어야 한다.

  • 어떤 문제를 해결하는가?
  • 그 문제가 지금 존재하는가?
  • 대안보다 왜 나은가?
  • 실패 시 되돌릴 수 있는가?
  • 운영 비용은 얼마인가?

10.3 먼저 측정하고 최적화하라

성능 최적화는 필요하다. 그러나 측정 없는 최적화는 추측이다. 대부분의 비효율은 중요하지 않지만, 일부 병목은 매우 중요하다. 중요한 병목을 찾으려면 감이 아니라 데이터를 사용해야 한다.

10.4 코드를 스케치하되, 제품이 될 가능성을 무시하지 마라

초기 코드는 완성품이 아닐 수 있다. 그러나 성공하면 제품이 될 수 있다. 따라서 최소한의 안정성, 관측 가능성, 배포 가능성, 이해 가능성은 갖춰야 한다.

10.5 가치가 확인되면 안정화하라

처음부터 모든 것을 안정화하지 않는다. 하지만 살아남은 코드, 반복 변경되는 코드, 사용자가 의존하는 코드는 반드시 안정화한다. 방치된 성공은 미래의 장애가 된다.

10.6 시스템의 일하는 방식도 단순화하라

복잡한 프로세스는 좋은 아키텍처를 무력화할 수 있다. 팀의 현재 규모와 리스크에 맞는 업무 시스템을 사용한다. 필요한 만큼만 형식화하고, 필요해질 때 근거를 가지고 확장한다.

10.7 작은 실험으로 신뢰를 만들어라

큰 변화를 한 번에 설득하려 하지 않는다. 제한된 기간, 제한된 범위, 명확한 성공 기준으로 실험한다. 결과가 좋으면 다음 범위로 확장한다.


11. 팀에서 바로 사용할 수 있는 질문 목록

다음 질문들은 설계 리뷰, 기술 선택, 리팩터링 논의, 제품 실험 전에 사용할 수 있다.

현재성 확인

  • 지금 이 요구사항은 실제인가, 예상인가?
  • 이 구조는 지금 필요한가, 미래 가능성을 위한 것인가?
  • 나중에 추가하면 정말 늦는가?
  • 지금 결정하지 않아도 되는 것은 무엇인가?

단순성 확인

  • 이 문제의 본질은 무엇인가?
  • 더 적은 개념으로 해결할 수 있는가?
  • 알고리즘을 바꾸면 구조가 단순해지는가?
  • 제거해도 동작하는 부분은 무엇인가?
  • 이 코드의 책임을 한 문장으로 설명할 수 있는가?

적합성 확인

  • 실패 비용은 어느 정도인가?
  • 이 기능은 실험인가, 핵심 기능인가?
  • 사용자 영향 범위는 어디까지인가?
  • 팀이 이 기술을 운영할 수 있는가?
  • 이 선택은 되돌릴 수 있는가?

경제성 확인

  • 출시가 한 주 늦어지면 무엇을 잃는가?
  • 이 팀이 지금 하지 못하는 더 가치 있는 일은 무엇인가?
  • 작게 출시해도 얻을 수 있는 가치는 무엇인가?
  • 이번 작업의 가장 큰 불확실성은 무엇인가?

안정화 확인

  • 이 코드는 다시 변경되고 있는가?
  • 이 코드는 일정 기간 운영에서 살아남았는가?
  • 관측 가능성은 충분한가?
  • 장애가 났을 때 원인을 추적할 수 있는가?
  • 테스트는 핵심 경로를 보호하는가?
  • 의존성은 통제 가능한가?

12. 안티패턴

Best Simple System for Now를 방해하는 대표적인 안티패턴은 다음과 같다.

미래 대비형 과설계

아직 검증되지 않은 요구사항을 위해 확장 포인트, 플러그인 구조, 복잡한 설정 시스템을 만든다. 결과적으로 현재 기능은 단순한데 시스템은 복잡해진다.

버릴 코드라는 착각

프로토타입은 나중에 버릴 것이라고 가정하고 품질을 포기한다. 그러나 성공적인 프로토타입은 자주 제품이 된다. 버릴 것이라는 말은 책임 회피가 되기 쉽다.

측정 없는 최적화

성능 문제가 실제로 어디 있는지 확인하지 않고 익숙한 최적화부터 적용한다. 중요한 3%를 찾지 못하고 중요하지 않은 97%에 시간을 쓴다.

빌드에 숨겨진 복잡성

빌드, 배포, 설정, 자동 생성 코드가 시스템의 실제 구조를 가린다. 직접 조립해보지 않으면 어떤 의존성과 결정이 쌓였는지 알기 어렵다.

프로세스 과잉

팀의 현재 문제보다 큰 프로세스와 도구를 도입한다. 업무 시스템이 팀을 돕는 것이 아니라 팀이 프로세스를 만족시키기 위해 일하게 된다.

리팩터링 지연

코드가 가치를 만들기 시작했는데도 안정화하지 않는다. “나중에 정리하자”가 반복되며 성공한 코드가 가장 위험한 코드가 된다.


13. 적용 예시

예시 1: 초기 제품 기능

상황: 사용자의 반응을 확인해야 하는 새로운 기능이 있다.

적절한 접근:

  • 핵심 사용자 흐름만 구현한다.
  • 고급 설정, 확장 옵션, 관리 기능은 미룬다.
  • 기능 플래그와 롤백 경로를 둔다.
  • 최소한의 이벤트 로깅을 넣는다.
  • 핵심 경로 테스트만 작성한다.
  • 사용량과 피드백이 확인되면 안정화한다.

피해야 할 접근:

  • 아직 고객이 원한다고 확인되지 않은 옵션을 모두 설계한다.
  • 플러그인 구조를 먼저 만든다.
  • 성능 요구가 없는데 캐시 계층을 추가한다.
  • “프로토타입이라 괜찮다”며 관측 가능성을 포기한다.

예시 2: 성능 병목

상황: 대량 데이터를 처리하는 기능이 느리다.

적절한 접근:

  • 먼저 측정한다.
  • 실제 병목 구간을 확인한다.
  • 데이터 구조와 알고리즘을 재검토한다.
  • 전체 데이터를 메모리에 올려야 하는지 질문한다.
  • 스트리밍, 누산, 배치, 인덱스 등 문제 본질에 맞는 해법을 비교한다.

피해야 할 접근:

  • 측정 없이 인프라를 늘린다.
  • 캐시부터 추가한다.
  • 현재 알고리즘을 유지한 채 주변만 복잡하게 만든다.
  • 근본 문제가 다른데 기존 방식에 계속 투자한다.

예시 3: 팀 프로세스

상황: 팀이 작업 추적과 우선순위 조율에 어려움을 겪는다.

적절한 접근:

  • 현재 병목을 명확히 한다.
  • 간단한 보드나 체크리스트로 시작한다.
  • 필요할 때만 상태, 승인, 템플릿을 추가한다.
  • 프로세스가 실제 결정을 빠르게 하는지 관찰한다.

피해야 할 접근:

  • 대규모 프레임워크를 그대로 도입한다.
  • 도구 설정이 업무보다 복잡해진다.
  • 팀 규모와 리스크에 맞지 않는 승인 단계를 만든다.
  • 프로세스를 지키는 것이 목적이 된다.

14. 실무 적용 체크리스트

새로운 기능이나 시스템을 시작할 때 다음 체크리스트를 사용한다.

[ ] 이 요구사항은 지금 검증된 것인가?
[ ] 가장 작은 가치 단위는 무엇인가?
[ ] 지금 만들지 않아도 되는 것은 무엇인가?
[ ] 이 결정은 되돌릴 수 있는가?
[ ] 실패 시 피해 범위는 어디까지인가?
[ ] 최소한의 테스트는 무엇인가?
[ ] 최소한의 관측 가능성은 무엇인가?
[ ] 배포와 롤백은 가능한가?
[ ] 이 코드가 제품이 되어도 견딜 수 있는가?
[ ] 가치가 확인되면 언제 안정화할 것인가?
[ ] 안정화 기준은 무엇인가?
[ ] 이 선택의 경제적 이유는 무엇인가?

15. 결론

Best Simple System for Now는 “대충 만들자”는 주장이 아니다. 또한 “처음부터 완벽한 아키텍처를 만들자”는 주장도 아니다.

핵심은 다음과 같다.

지금 필요한 만큼 충분히 단순하고, 충분히 안전하며, 실제 피드백을 받을 수 있는 시스템을 만든다. 그리고 가치가 확인되면 그때 구조를 강화한다.

이 접근은 빠른 출시와 좋은 설계를 대립시키지 않는다. 오히려 좋은 설계란 변화와 학습을 수용하는 설계라고 본다. 처음부터 복잡한 시스템을 만드는 대신, 작동하는 단순한 시스템을 만들고, 그 시스템이 실제 세계에서 배운 것을 바탕으로 진화하게 한다.

실천은 거창하지 않다. 작은 범위에서 시작하면 된다.

  • 추측을 줄인다.
  • 단순한 해법을 찾는다.
  • 스케치 코드를 제품 가능성을 가진 코드로 다룬다.
  • 작게 출시한다.
  • 측정한다.
  • 살아남은 코드를 안정화한다.
  • 팀의 습관을 개선한다.

좋은 시스템은 완벽한 예측에서 나오지 않는다. 좋은 시스템은 현재를 정확히 보고, 작게 움직이고, 학습하며, 필요한 순간에 더 나은 구조로 진화하는 과정에서 나온다.