시스템 사고

발행: (2026년 2월 6일 오후 02:24 GMT+9)
11 min read

Source: Hacker News

소프트웨어 개발에 대한 두 가지 사고 방식

  1. 진화적(점진적) 개발 – 작게 시작하고, 시간이 지남에 따라 기능을 추가하며, 시스템이 자연스럽게 성장하도록 한다.
  2. 사전 대규모(공학) 설계 – 코드를 작성하기 전에 모든 복잡성을 포괄하는 사양을 작성한다.

요약하면, 이는 기업가가 스타트업을 구축하는 방식과 우리가 현대 고층 건물을 건설하는 방식의 차이와 같다: 진화 vs. 공학.

실제 사례

저는 한 번 > 3,000개의 활성 시스템을 보유한 대기업에서 일한 적이 있습니다. 이 시스템들은 수십 개의 사업 부문과 모든 내부 부서를 아우르고 있었습니다.

  • 이 환경은 ~50 년에 걸쳐 진화해 왔습니다.
  • 다양한 기술 스택, 셀 수 없이 많은 공급업체, 그리고 레거시와 최신 애플리케이션이 뒤섞인 형태였습니다.
  • 하나의 “것”으로 바라보면 불안정한 카드 집과도 같았습니다.

시스템 수가 적고 규모가 큰 경우는 어떨까요?

  • 데이터, 보안, 운영, 품질, 접근성의 불일치가 크게 줄어들 것입니다.
  • 최신, 고대, 잘 작동하는, 거의 작동하지 않는 시스템이 뒤섞인 상황이 보다 일관된 플랫폼으로 대체될 것입니다.
  • 전체 복잡도는 현재 수준의 ≈ 10 % 수준으로 감소할 수 있으며, 절반 수준에 그치지 않습니다.

예상되는 이점

  • 성능 및 신뢰성 향상
  • 변화에 대한 회복력 강화
  • 비용 절감 및 인력 감소
  • 현재 존재하는 많은 “불편한” 문제들의 제거

The Core Issue: Dependencies

항목Evolutionary ApproachBig‑Up‑Front Design
Assumption의존성을 처음에는 무시하고 나중에 해결할 수 있다.모든 의존성을 사전에 식별하고 설계에 반영해야 한다.
Pros빠른 시작, 즉각적인 진행, 조정 필요성 감소.아키텍처가 1일 차부터 일관성을 유지하고, 나중에 숨겨진 문제가 적다.
Cons숨겨진 의존성이 나중에 수정 비용이 크게 늘고, “해킹”이 누적돼 복잡도가 급증한다.많은 조정, 회의, 그리고 팀 간 초기 마찰이 필요하다.

수천 개의 독립적인 블롭이 있다면 각각을 “빠르게 구현”할 수 있습니다. 실제로는 매우 적은 구성 요소만이 진정으로 독립적이기 때문에, 시스템이 확장될수록 진화적 접근 방식은 위험합니다.

왜 초기 대규모 설계가 정체되는가

  1. 지식 부족 – 기반(기술 스택, 프레임워크, 라이브러리)이 빠르게 진화하여 보편적으로 받아들여지는 모범 사례가 거의 없습니다.
  2. 짧은 경력 경로 – 대부분의 애플리케이션 프로그래머는 ≤ 5 년의 깊은 경험을 가지고 있으며, “20년 이상” 베테랑 엔지니어는 드뭅니다.
  3. 복잡성 위협 – 초보 개발자들은 대규모 상호 의존 설계를 다루기에 준비가 부족하다고 느끼는 경우가 많습니다.

개인 선호도 & 현실 점검

진화형 프로젝트

장점

  • 더 재미있고 회의가 적으며 즉시 실무에 착수할 수 있음.
  • 초기 조정이 덜 필요해 “그냥 일에 들어갈 수 있음”.

단점

  • 코드베이스가 커질수록 탈선 위험이 증가함.
  • 시스템이 의도대로 동작하지 않을 때 말기에 패닉이 발생함.
  • 문제를 해결하기보다 오히려 문제를 추가했다는 장기적인 불만족이 생김.

대규모 사전 설계

장점

  • 시작은 느리지만 전체 개발 흐름이 매끄러움.
  • 세부 사항, 재사용성, 아키텍처 일관성에 신중히 신경 쓸 수 있음.
  • 장기적으로 스트레스를 감소시킴; 올바르게 할 시간이 있음.

단점

  • 마찰감이 있음: 회의가 많고, 조정이 무겁고, 초기 진행이 느림.

Note: 대규모 사전 프로젝트가 잘못된 제품을 만들 위험은 종종 과장됩니다. 요구사항이 잘 이해된 성숙한 비즈니스 영역에서는 견고한 사양이 실제로 위험을 줄일 수 있습니다.

핵심 요약

  • 진화적 개발은 문제 영역이 유동적인 소규모, 빠르게 움직이는 이니셔티브에 적합합니다.
  • 대규모 사전 엔지니어링은 도메인이 안정적이고 숨겨진 의존성 비용이 높으며 조직이 초기 조정을 감당할 수 있을 때 빛을 발합니다.

올바른 접근 방식을 선택하는 것은 문제의 성격, 팀의 성숙도, 그리고 장기 기술 부채에 대한 허용 범위에 달려 있습니다.

원본 작업 리팩토링 및 결함 해결

중간 어딘가에 균형 잡힌 경로가 있어야 하지만, 수십 년이 지나도 그에 대한 공식적인 버전을 찾지 못했습니다.

우선 의존성을 살펴보고, 왜 일시적으로 무시할 수 있는지 설명할 수 있습니다. 다음 릴리스를 진행하면서도 막연하고 장기적인 설계를 염두에 둘 수 있습니다. 새로운, 예상치 못한 의존성이 나타나면 설계를 그에 맞게 리팩토링하면 됩니다. 계속해서 생각을 바꾸면서, 진화하는 작업이 견고한 거대한 설계에 수렴하도록 노력합니다.

  • 빠르게 시작하고, 속도를 늦췄다가 다시 가속하고, 이를 반복합니다.
  • 목표는 결국 “모두를 지배하는” 단일하고 포괄적인 시스템을 만드는 것이며, 이를 달성하는 데 시간이 걸리더라도 괜찮습니다.

Iteration Size Matters

각 iteration의 규모는 매우 중요합니다:

  • 매우 작은 iteration은 눈을 가리고 앞을 헤매는 경우가 많습니다.
  • 더 긴 iteration(눈을 가리지 않을 때)은 더 효과적입니다.

iteration은 반드시 균일할 필요는 없지만, 각 iteration이 끝난 뒤에는 멈춰서 상황을 점검해야 합니다.

  • 코딩 속도가 빨라질수록 정리(cleanup) 작업이 더 많이 필요합니다.
  • 정리를 미루면 문제가 기하급수적으로 커집니다.
  • 검증 없이 앞만 달리면 작업 환경이 결국 정체된 늪으로 변해 멈추게 됩니다.

이 원칙은 소프트웨어 시스템 구축부터 레스토랑에서 요리까지 모든 것에 적용됩니다. 속도는 언제나 트레이드‑오프입니다.

Balancing Evolution and Engineering

  • Evolution은 엔지니어링에 빠져들지 않게 도와주지만, 엔지니어링은 제품이 제 역할을 하도록 보장합니다.
  • 엔지니어링은 느리지만, 통제 없이 급격히 진행되는 것은 훨씬 더 느립니다.
  • Evolution은 역동적이지만 혼란스럽습니다; 잘못된 경로를 택했을 때 이를 인식하고 되돌아가는 것이 필요하고, 이를 인정하기가 어려울 수 있습니다.

대부분의 시스템에 대해:

  1. Engineered parts – 신중하게 설계하고 검증해야 하는 구성 요소.
  2. Evolved parts – 자연스럽게 변화하도록 허용할 수 있는 부분.

진화 경로가 무작위일수록 버리고 다시 만드는 일이 많아집니다. 흔들림은 언제나 비용이 많이 듭니다. 자연은 수백만 종을 통해 이를 극복하지만, 우리는 보통 하나의 개발 프로젝트만 진행합니다—따라서 위험이 더 크고 과정이 덜 편리합니다.

Back to Blog

관련 글

더 보기 »