OrganicGrowth
주니어 개발자들을 위한 패턴 언어 - 기계적 조립이 아닌 유기적 성장으로 소프트웨어를 만드는 법
Contents
The Story 1: The Frankenstein Monster vs. The Growing Tree (Programming)
두 명의 개발자, 민수와 하나가 '블로그 시스템'을 구축하고 있다.
민수의 접근 (The Machine Assembly): 민수는 계획적이다. "완벽한 설계가 우선이야." 그는 1주 차에 DB 스키마를, 2주 차에 모든 API 엔드포인트를, 3주 차에 프론트엔드 컴포넌트를 만들었다. 4주 차에 "이제 조립해볼까?" 하고 모든 레이어를 연결하려는 순간 재앙이 시작되었다. 데이터 형식이 맞지 않았고, 실제 사용해보니 DB 설계가 UX와 충돌했다. 조립된 괴물(Frankenstein)은 삐걱거렸고, 민수는 수정하는 데만 2주를 더 써야 했다.
하나의 접근 (The Organic Growth): 하나는 다르게 시작했다. "일단 텍스트 한 줄이라도 화면에 띄우자." 그녀는 1일 차에 DB-Server-Client를 관통하는 Walking Skeleton을 만들었다. 2일 차에 진짜 게시글 제목을 저장하게 바꿨고, 3일 차에 목록 기능을 추가했다. 하나는 4주 내내 "작동하는 블로그"를 가지고 있었다. 처음에는 엉성했지만 시스템은 매일 조금씩 분화하며 자라났고, 4주 후에는 이미 가장 튼튼하고 자연스러운 완성본이 되어 있었다.
The Story 2: The Old City (Ordinary Life)
민수와 하나는 유럽의 유서 깊은 '오래된 도시'를 여행 중이다.
민수의 관찰 (The Grid City): 민수는 자로 잰 듯 반듯한 격자무늬의 신도시를 좋아한다. "모든 것이 계획대로 배치되어야 효율적이지." 하지만 그런 도시는 때로 삭막하고, 사람들의 실제 보행 동선과 맞지 않아 불편함을 주기도 한다. 건물들은 화려하지만 서로 단절되어 조화를 이루지 못한다.
하나의 발견 (The Living City): 하나는 수백 년 동안 자연스럽게 형성된 구도심의 골목길에서 생명력을 느꼈다. "이 도시는 한 번에 지어진 게 아니야. 광장을 중심으로 집들이 하나씩 생겨나고, 사람들이 다니는 길을 따라 상점이 들어서면서 자라난 거야." 도시는 처음부터 완성된 형태가 아니라, 필요에 따라 조금씩 덧붙여지고 변형되며 전체적인 조화를 찾아갔다. 유기적으로 성장한 도시는 시간이 흐를수록 더 견고하고 아름다운 전체성을 갖게 됨을 하나는 깨달았다.
Context
새로운 프로젝트나 큰 기능을 시작한다. 만들어야 할 구성 요소(DB, API, UI, 로직)가 많고 전체적인 구조를 어떻게 잡아야 할지 고민되는 상황이다.
일상적인 상황:
- "DB 스키마부터 완벽하게 짜고 시작하자"라고 생각한다.
- 프론트엔드와 백엔드 개발자가 각자 자기 부분만 작업하다가 마지막 날에 합치려 한다.
- 개별 부품은 완벽하게 테스트되었는데, 통합하는 과정에서 예상치 못한 문제가 쏟아진다.
- 프로젝트 초반에는 진도가 빠른 것 같았는데, 후반부 통합 지옥(Integration Hell)에서 일정이 무한정 늘어난다.
당신은 소프트웨어를 공산품 조립하듯이 만들고 있다. 하지만 소프트웨어는 생물처럼 키워야 한다.
Problem
각 부분을 따로 완성해서 마지막에 통합하려는 시도는 "통합 지옥"을 부르고 시스템의 생명력을 앗아간다.
부분의 합은 결코 전체가 아닙니다.
피드백의 지연: 아키텍처의 치명적 결함은 모든 레이어가 실제로 연결될 때 비로소 드러납니다. 마지막에 연결하면 그 대가를 너무 늦게 치르게 됩니다.
잘못된 가설의 누적: 연결되지 않은 채 각자 상상으로 만든 부품들은 실제 환경에서 서로 어긋날 확률이 매우 높습니다.
전체성의 상실: 조립된 시스템은 각 부품의 나열일 뿐, 시스템이 지향하는 궁극적인 가치를 조화롭게 담아내지 못합니다.
Solution
작동하는 가장 작은 전체(Whole)를 먼저 만들고, 그 "배아"를 점진적으로 세분화하며 키워라.
Christopher Alexander는 "도시가 나무처럼 성장해야 하듯, 구조물도 씨앗에서 출발하여 점진적으로 분화(Differentiation)되어야 한다"고 말했습니다.
Principle 1: Walking Skeleton (걸어 다니는 스켈레톤)
가장 먼저 할 일은 시스템의 End-to-End를 관통하는 가장 얇은 실을 연결하는 것입니다.
- DB - Server - UI가 연결되어 "Hello World"가 찍히는 상태를 1순위로 만드십시오. 뼈대가 서고 신경망이 연결되면, 그 위에 살(Feature)을 붙이는 것은 매우 쉽고 안전합니다.
Principle 2: Vertical Slicing (수직 분화)
기능을 레이어별(가로)로 완성하지 말고, 기능별(세로)로 분화시키십시오.
Bad: 모든 테이블 만들기 -> 모든 API 만들기 -> 모든 UI 만들기.
Good: "로그인"이라는 얇은 전체 만들기 -> "글쓰기"라는 얇은 전체 추가하기. 각 기능을 완료할 때마다 시스템은 "살아있는 전체"로서 성장합니다.
Principle 3: Refactor as You Grow (자라면서 구조 변경하기)
나무가 자라면 줄기가 굵어져야 하듯, 시스템도 성장함에 따라 내부 구조가 바뀌어야 합니다.
처음부터 MSA나 복잡한 레이어 구조를 강제하지 마십시오. 처음엔 DirectPath로 시작하고, 복잡성이 고통을 줄 때 ComplexityTaming 도구를 꺼내어 분화시키십시오.
Principle 4: Protect the Wholeness (전체성 보호)
개발의 매 순간 시스템은 작동하는 상태여야 합니다. BabySteps와 SafetyNet은 유기적 성장이 파괴적이지 않게 돕는 안전장치입니다.
Real Examples
Example 1: E-commerce System
상품 1개를 하드코딩해서 화면에 보여주고 '구매' 버튼을 누르면 '주문 완료'가 뜨는 2시간짜리 작업이 쇼핑몰의 시작입니다. 그 배아를 DB 연동, 결제 연동으로 조금씩 분화시켜 나갑니다.
Example 2: Gall's Law (갤의 법칙)
"작동하는 복잡한 시스템은 예외 없이 작동하는 단순한 시스템에서 진화했다. 처음부터 복잡하게 설계된 시스템은 결코 작동하지 않으며, 고쳐서 작동하게 만들 수도 없다."
Common Pitfalls
"But the code is dirty!"
초기 배아 단계의 코드는 엉성할 수 있습니다. 하지만 WorkingFirst 원칙에 따라 작동하는 실체를 만드는 것이 우선입니다. 살아있어야 개선도 할 수 있습니다.
Fear of Rework
"나중에 갈아엎으면 손해잖아요." 아닙니다. 잘못된 설계를 굳히고 나중에 발견하는 손해가 훨씬 큽니다. 점진적 성장은 재작업 비용을 최소화하는 가장 경제적인 방식입니다.
Connection to Other Patterns
StrongCenter - 성장은 무질서한 확장이 아닙니다. 강한 중심이 내뿜는 중력 안에서 시스템이 분화되어야 합니다. 뿌리와 줄기
RoughWholeFirst - 완벽한 조각을 맞추기보다 엉성한 전체에서 시작하여 세분화하십시오. 성장 방식
DirectPath - 자라나는 과정에서 불필요한 우회로가 생기지 않도록 경로를 단순하게 유지하십시오. 가지치기
BabySteps - 유기적 성장은 수많은 작은 보폭들이 쌓여 만들어지는 연속적인 진화입니다. 세포 분열
LivingVocabulary - 시스템이 자라나며 새로운 형태를 띨 때 이름도 함께 진화해야 합니다. 어휘의 병행 성장
Signs of Success
- 프로젝트 시작 직후부터 데모 가능한 시스템을 항상 보유하고 있다.
- "통합 테스트 기간"이라는 별도의 일정이 필요 없다. 매일 통합되고 있기 때문이다.
- 기획자나 사용자가 시스템이 자라나는 모습을 보며 함께 설레어한다.
- 아키텍처가 필요에 의해 자연스럽게 진화한다.
The Ultimate Insight
복잡한 시스템은 설계되는 것이 아니라 진화하는 것이다.
거대한 건축물을 한 번에 조립하려 하지 마십시오. 작은 씨앗을 심고 매일 물을 주십시오. 엉성한 시작이 단단한 전체로 변해가는 과정 자체가 소프트웨어 개발의 진정한 아름다움입니다.
CategoryPatternLanguage CategoryProgramming CategoryAgile CategoryArchitecture
