Skip to Content

Step 02. 아키텍처가 풀려는 진짜 문제

만화로 보는 요약 — 먼저 읽어보세요

만화로 보는 요약 — 먼저 읽어보세요

문제는 기능 하나가 아니라 변경의 파급이며, 관심사 분리와 정보 은닉으로 그 파급을 경계 안에 가둔다.

면접 실전 질문: ① 변경의 파급이 왜 위험한가? ② 정보 은닉은 무엇을 숨기는가? ③ 결합도와 응집도는 어떻게 연결되는가?


이 장의 질문: 소프트웨어는 왜 본질적으로 어려운가? 그리고 1968년의 “위기”에 1970년대가 내놓은 무기들 — 관심사의 분리, 정보 은닉, 결합도와 응집도 — 은 정확히 무엇을 겨냥했는가?


1. 위기의 해부 — 소프트웨어는 왜 본질적으로 어려운가

앞 장에서 1968년 가르미슈의 진단을 봤다: “우리는 우리가 만드는 것의 복잡성을 다루는 방법을 모른다.” 그런데 그 복잡성의 정체는 무엇인가? 이 질문에 가장 유명한 답을 내놓은 사람이 또 Fred Brooks다. 1986년의 에세이 「No Silver Bullet: Essence and Accidents of Software Engineering」.

제목의 은유부터 풀자. 늑대인간을 한 방에 잡는 은탄환처럼, 향후 10년 안에 소프트웨어의 생산성·신뢰성·단순성을 한 자릿수(10배) 이상 올려줄 단 하나의 기술은 없다는 주장이다 — 시한과 조건이 붙은, 검증 가능한 내기였다. 근거는 아리스토텔레스에게서 빌려온 구분이다.

  • 본질적(essential) 어려움: 소프트웨어가 무엇인가 때문에 생기는 어려움. 제거 불가능.
  • 우연적(accidental) 어려움: 소프트웨어를 오늘의 도구로 만들기 때문에 생기는 어려움. 제거 가능.

어셈블리 → 고급 언어, 천공카드 → 대화형 터미널, 수동 빌드 → 자동화. 지난 발전은 대부분 우연적 어려움의 제거였다. 그런데 우연적 어려움을 다 걷어내도 남는 것이 있다. Brooks는 그 본질을 네 가지로 해부한다.

  1. 복잡성(complexity) — 소프트웨어의 어떤 두 부분도 같지 않다(같다면 함수로 합쳤을 것이다). 규모가 커지면 요소가 아니라 요소 간 상호작용이 비선형으로 늘어난다. 건물이나 자동차 같은 물리적 인공물과 근본적으로 다른 지점.
  2. 정합성(conformity) — 소프트웨어는 물리 법칙이 아니라 인간이 만든 제도·관행·타 시스템에 맞춰야 한다. 세법, 레거시 API, 조직의 업무 절차. 이 인터페이스들은 일관성도 없고 협상도 안 된다.
  3. 변경 가능성(changeability) — 성공한 소프트웨어일수록 더 많이 바뀐다. 다리는 완공되면 그대로지만, 소프트웨어는 “부드러워(soft)” 보이기 때문에 모두가 변경을 요구한다.
  4. 비가시성(invisibility) — 소프트웨어는 공간에 존재하지 않는다. 도면 한 장으로 전체를 볼 수 없고, 제어 흐름·데이터 흐름·의존성은 각각 다른 그래프를 그린다.

이 네 가지를 아키텍처의 언어로 다시 읽으면 이 책의 지도가 된다. 복잡성과 비가시성이 “구조와 경계”라는 도구를 부르고, 변경 가능성이 “무엇을 미룰 것인가”라는 질문을 부른다. 아키텍처는 은탄환이 아니라, 본질적 어려움과 공존하는 기술이다.

2. 진짜 적은 변경이다

네 가지 본질 중 아키텍처와 가장 깊게 얽히는 것은 변경 가능성이다.

소프트웨어 비용의 대부분은 첫 출시 전이 아니라 후에 발생한다. 유지보수라 불리는 이 기간의 실체는 “고장 수리”가 아니라 대부분 요구사항 변경의 반영이다. 그리고 변경의 비용은 균일하지 않다 — 같은 한 줄짜리 요구사항이라도, 어떤 시스템에서는 함수 하나를 고치면 되고 어떤 시스템에서는 서른 개 파일을 건드려야 한다.

이 직관에는 고전적 실증이 있다. Barry Boehm은 『Software Engineering Economics』(1981)에서 변경 비용 곡선을 제시했다 — 같은 결함·같은 요구사항 변경이라도 요구분석 단계에서 잡으면 1의 비용이, 운영 단계에서 잡으면 수십~백 배가 된다는, 단계가 늦어질수록 기하급수적으로 치솟는 곡선이다. 이 곡선은 “초기에 다 결정하라”는 빅 디자인의 근거로 오래 쓰였다. 그런데 2000년대에 Kent Beck(XP)이 정반대 해석을 내놓는다: 좋은 설계, 테스트, 리팩터링이 있다면 곡선을 평평하게 눕힐 수 있고, 곡선이 평평하다면 결정을 미루는 쪽이 오히려 합리적이라는 것이다. 누구 말이 맞는지는 지금도 실증적으로 논쟁 중이지만, 이 논쟁 자체가 요점을 드러낸다 — 양쪽 모두 아키텍처의 존재 이유를 “변경 비용 곡선의 기울기”에서 찾고 있다. 곡선을 피할 수 없다면 비싼 결정을 앞당기고(Boehm), 곡선을 눕힐 수 있다면 결정을 미룬다(Beck). 어느 쪽이든 싸움의 대상은 같다.

이 차이를 만드는 것이 구조다. 앞 장에서 세운 작업 정의 — 아키텍처란 되돌리기 비싼 결정들과 그 근거 — 를 이 장의 언어로 다시 쓰면:

아키텍처의 목적은 성능도 우아함도 아니라, 변경 비용의 통제다. 자주 바뀔 것을 싸게 바꿀 수 있게 만들고, 바꾸기 비싼 결정의 수 자체를 줄이는 것.

그렇다면 어떻게? 1970년대가 내놓은 세 개의 무기를 순서대로 보자. 셋은 별개의 기법이 아니라 하나의 전략 — “변경의 파급을 가두기” — 의 세 가지 표현이다.

3. 무기 1: 관심사의 분리 — Dijkstra, 1974

Edsger Dijkstra는 1968년 가르미슈의 참석자이자, 같은 해 「Go To Statement Considered Harmful」로 구조적 프로그래밍 논쟁에 불을 붙인 인물이다. 그가 1974년 에세이 「On the role of scientific thought」에서 정식화한 개념이 **관심사의 분리(separation of concerns)**다.

원래 맥락은 코드가 아니라 사고방식이었다. 프로그램의 정확성, 효율, 사용성은 서로 다른 관심사이며, 지적으로 성실한 사람은 한 번에 하나의 관심사만 붙들고 씨름한다는 것 — “나머지를 무시해서가 아니라, 나머지가 당장은 무관함을 알기 때문에.”

이것이 왜 무기인가? 비가시성과 복잡성(1절) 때문에 인간은 시스템 전체를 한 번에 머리에 담을 수 없다. 관심사의 분리는 **“전부 이해하지 않고도 일부를 올바르게 다룰 수 있는 조건”**을 만드는 원리다. 레이어드 아키텍처의 수평 분할도, 헥사고날의 안/밖 구분도, 결국 “어떤 관심사를 서로에게서 떼어놓을 것인가”에 대한 서로 다른 답이다. 분리 원리 자체는 같고, 자르는 선의 위치가 다를 뿐이다 — 이 관점은 Part 2 전체를 관통한다.

4. 무기 2: 정보 은닉 — Parnas, 1972

관심사를 분리하기로 했다면, 다음 질문은 “어디서 자르는가”다. 이 질문에 대한 20세기의 가장 중요한 답이 David Parnas의 1972년 논문 **「On the Criteria To Be Used in Decomposing Systems into Modules」**이다. 제목 그대로 — 시스템을 모듈로 쪼갤 때 그 기준은 무엇이어야 하는가.

Parnas는 KWIC 색인이라는 작은 프로그램을 두 가지 방식으로 분해해 보인다.

  • 분해 1: 처리 단계 기준. 입력 → 순환 시프트 → 정렬 → 출력. 순서도(flowchart)를 따라 자르는, 당시(그리고 지금도) 가장 자연스러워 보이는 방법.
  • 분해 2: 설계 결정 기준. “줄을 메모리에 어떻게 저장하는가”, “입력 포맷은 무엇인가” 같은 바뀔 법한 결정 하나하나를 모듈 하나에 가둔다.

겉보기엔 둘 다 그럴듯하다. 차이는 변경이 닥쳤을 때 드러난다. 저장 방식을 바꿔야 한다면? 분해 1에서는 거의 모든 모듈이 저장 형식을 알고 있으므로 전부 수정된다. 분해 2에서는 모듈 하나만 바뀐다. Parnas의 결론:

“모듈화의 기준은 처리 흐름이 아니다. 각 모듈은 어려운 결정, 또는 바뀔 법한 결정을 다른 모듈들로부터 숨겨야 한다.

이것이 **정보 은닉(information hiding)**이다. 여기서 숨기는 “정보”란 데이터가 아니라 설계 결정이다. 캡슐화(private 필드)는 이 원리의 언어 차원 지원일 뿐, 원리 자체는 훨씬 크다 — “DB가 MySQL이라는 사실”을 리포지토리 뒤에 숨기는 것, “외부 결제사가 누구인지”를 어댑터 뒤에 숨기는 것. 모두 Parnas다.

앞 장과의 연결이 보일 것이다. Fowler의 정의(“아키텍처란 바꾸기 어려운 것”)와 Parnas의 기준(“바뀔 법한 것을 숨겨라”)은 같은 동전의 양면이다. 바뀔 법한 결정을 성공적으로 숨기면, 그 결정은 더 이상 아키텍처가 아니게 된다 — 되돌리기 싸졌기 때문이다. 아키텍처 설계란 결국 “무엇을 숨길 수 있고, 무엇은 숨길 수 없는가”의 분류 작업이다.

5. 무기 3: 결합도와 응집도 — Constantine, 1974/1979

분리했고(무기 1), 자르는 기준도 얻었다(무기 2). 남은 질문: 잘 잘랐는지 어떻게 아는가? 측정의 언어를 만든 것이 Larry Constantine의 구조적 설계(structured design)다. 1960년대 말부터 발전시킨 개념이 Stevens·Myers·Constantine의 1974년 논문으로, 이후 Yourdon과의 1979년 책 『Structured Design』으로 정리됐다.

  • 결합도(coupling): 모듈 사이의 의존 강도. 낮을수록 좋다.
  • 응집도(cohesion): 모듈 요소들이 서로 관련된 정도. 높을수록 좋다.

중요한 것은 이것이 이분법이 아니라 스펙트럼이라는 점이다. 결합도는 나쁜 쪽부터:

결합 유형
내용(content)남의 내부를 직접 수정다른 모듈의 private 상태 조작
공통(common)전역 데이터 공유전역 변수, 공유 DB 테이블
외부(external)외부에서 강제된 포맷·프로토콜에 대한 공동 의존여러 모듈이 같은 외부 파일 포맷을 각자 파싱
제어(control)남의 분기를 플래그로 조종doIt(flag) 로 동작 전환
스탬프(stamp)필요 이상의 구조체 전달필드 2개 쓰려고 엔티티 통째로
데이터(data)필요한 값만 전달스칼라 파라미터

응집도도 마찬가지로 우연적(coincidental, 아무 관련 없는 것들의 잡탕 — 모든 코드베이스의 utils) → 논리적 → 시간적(같은 시점에 실행된다는 이유로 묶임 — init(), setUp()) → … → 기능적(functional, 하나의 목적) 순으로 오른다.

이 표가 반세기 뒤에도 살아 있는 이유: 추상화 수준을 바꿔도 그대로 적용되기 때문이다. 함수 사이, 클래스 사이, 모듈 사이, 마이크로서비스 사이. 훗날 “공유 DB는 안티패턴”이라는 분산 시스템의 교훈은, 이 표의 둘째 줄(공통 결합)을 서비스 규모로 확대한 것에 지나지 않는다. 데이터 아키텍처 장에서 이 줄을 다시 만나게 된다.

한 가지 주의. 목표는 결합의 제거가 아니다 — 결합이 0인 시스템은 아무것도 안 하는 시스템이다. 목표는 결합의 배치다: 자주 함께 바뀌는 것들은 가깝게(높은 응집), 따로 바뀌는 것들은 느슨하게(낮은 결합). “함께 바뀌는 것끼리 묶는다”는 이 기준이 Parnas의 “바뀔 법한 것을 숨겨라”와 정확히 포개진다는 점을 확인하라.

6. 빚이라는 은유 — 기술 부채, Cunningham 1992

무기들이 있어도 현실에서는 늘 시간이 없다. “제대로 자를 시간이 없으니 일단 붙여서 내보내자” — 이 상황을 경제학의 언어로 번역한 사람이 Ward Cunningham이다(1992년 OOPSLA 경험 보고).

급하게 내보내는 코드는 **차입(빚)**과 같다. 빚은 도구다 — 잘 쓰면 시장에 먼저 도달한다. 문제는 원금이 아니라 이자다: 그 구조 위에서 일하는 모든 시간이 조금씩 느려진다. 이자만 갚다가 원금(재설계)을 영영 못 갚는 상태가 파산이다.

주의할 것은 원래 의미다. Cunningham의 부채는 **“몰라서 쓴 나쁜 코드”가 아니라 “알고서 한 의도적 차입”**이다 — 지금의 이해로 일단 출시하고, 배운 것을 반영해 갚는다는 전제가 붙어 있다. 무지에서 나온 엉망은 부채가 아니라 그냥 결함이다.

이 은유가 이 장에 있는 이유: 아키텍처 결정은 완전한 이해 위에서 내려지지 않는다. Cunningham의 축은 흔히 알려진 “품질 vs 속도”의 교환이 아니라 학습-상환의 순환이다 — 도메인을 다 이해하기 전에 현재의 이해로 먼저 출시하고, 출시 후에 배운 것을 리팩터링으로 반영해 빚을 갚는다. 부채가 위험해지는 것은 차입 자체가 아니라 상환(학습의 반영)을 멈출 때다. 갚을 계획이 있는 차입인가, 이자율조차 모르는 차입인가.

7. 좋은 아키텍처의 판단 기준 — 무엇을 미루고, 무엇을 먼저 결정했는가

이 장의 재료를 한 문장으로 조립하자.

  • Brooks: 본질적 어려움 중 핵심은 변경이다.
  • Dijkstra: 관심사를 분리하라 — 전부 이해하지 않고도 일부를 다룰 수 있게.
  • Parnas: 자르는 기준은 처리 흐름이 아니라 변경 가능성이다. 바뀔 것을 숨겨라.
  • Constantine: 잘 잘랐는지는 결합도(사이)와 응집도(안)로 측정한다.
  • Cunningham: 못 자른 채 출시하는 것은 차입이다. 이자를 계산하라.

그래서 좋은 아키텍처란 무엇인가. 결정을 잘 내리는 것이라고 답하고 싶겠지만, 반만 맞다. 더 정확한 기준은:

좋은 아키텍처는 중요한 결정(되돌리기 비싼 것)을 신중하게 먼저 내리고, 나머지 결정(바뀔 법한 것)을 최대한 늦게 내릴 수 있도록 구조를 배치한 것이다.

DB 선택을 첫 주에 확정해야 하는 구조와, 출시 후에도 바꿀 수 있는 구조가 있다면 — 후자가 더 좋은 아키텍처다. 결정 자체를 잘해서가 아니라, 잘못 결정해도 되돌릴 수 있게 만들었기 때문이다. 불확실성이 가장 높은 시점(프로젝트 초기)에 내려야 하는 비가역적 결정의 수를 줄이는 것. 뒤에서 볼 헥사고날·클린 아키텍처가 “DB와 프레임워크는 세부사항”이라 주장할 때, 그 주장의 논리적 뿌리가 바로 이 문장이다.


8. 흔한 오해 바로잡기

오해 1: “No Silver Bullet은 비관론이다.” 반대다. Brooks의 요지는 “포기하라”가 아니라 “은탄환을 기다리지 말고, 본질을 다루는 정공법 — 좋은 설계자를 기르고, 점진적으로 키우고, 살 수 있는 것은 만들지 말고 사라 — 에 투자하라”다. 게다가 원래 주장은 “향후 10년 내에, 단일 기술로는”이라는 시한과 조건이 붙은 내기이지 영원한 불가능 선언이 아니다. 우연적 어려움의 제거도 여전히 가치 있다. 다만 그것 하나로 10배는 안 된다는 것.

오해 2: “모듈은 기능(처리 단계) 단위로 나누는 것이다.” Parnas가 1972년에 정면으로 반박한 그 기준이다. 순서도를 따라 자른 모듈은 데이터 형식이 바뀌는 순간 전부 수정된다. 기준은 처리 흐름이 아니라 변경 가능성이다. (마이크로서비스를 “기능별로” 잘랐다가 모든 배포가 맞물리는 분산 모놀리스가 되는 현대의 실패도 같은 오답의 반복이다.)

오해 3: “캡슐화 = 정보 은닉.” 캡슐화는 언어 메커니즘(private), 정보 은닉은 설계 원리(결정을 숨겨라)다. 모든 필드를 private으로 하고 전부 getter/setter를 뚫어놓은 클래스는 캡슐화됐지만 아무것도 숨기지 않는다.

오해 4: “결합도는 무조건 낮을수록 좋다.” 결합 없는 시스템은 동작하지 않는다. 목표는 제거가 아니라 배치 — 함께 바뀌는 것은 가깝게, 따로 바뀌는 것은 느슨하게. 억지로 결합을 낮추려 만든 과도한 간접층은 그 자체가 새로운 복잡성(우연적 어려움)이다.

오해 5: “기술 부채 = 나쁜 코드.” 원래 의미는 의도적·전략적 차입이다. 부채라는 말을 “우리 코드가 엉망인 이유”의 면죄부로 쓰는 순간 은유는 죽는다. 차입 시점에 상환 계획이 있었는가가 부채와 결함을 가른다.


9. 요약, 그리고 다음 장으로

  • 소프트웨어의 어려움에는 도구로 제거되는 우연적 어려움과 제거 불가능한 본질적 어려움(복잡성·정합성·변경 가능성·비가시성)이 있다 (Brooks, 1986).
  • 아키텍처의 목적은 변경 비용의 통제다.
  • 1970년대의 세 무기는 하나의 전략이다 — 변경의 파급을 가두기: 관심사의 분리(Dijkstra)로 나누고, 변경 가능성(Parnas)을 기준으로 자르고, 결합도/응집도(Constantine)로 측정한다.
  • 기술 부채(Cunningham)는 “현재의 이해로 출시하고 학습을 반영해 갚는” 순환을 사고하는 경제 언어다. 위험은 차입이 아니라 상환의 중단이다.
  • 좋은 아키텍처의 판단 기준: 되돌리기 비싼 결정은 신중히 먼저, 바뀔 법한 결정은 최대한 늦게 내릴 수 있는 구조인가.

다음 장 예고: 세 무기에는 공통의 재료가 있다 — 모듈 A가 모듈 B를 “안다”는 것, 즉 의존성이다. 다음 장에서는 의존성의 방향이 왜 아키텍처 그 자체인지, 그리고 그 방향을 뒤집는 지렛대(의존성 역전 원칙)가 어떻게 작동하는지를 본다. Part 2의 모든 아키텍처 스타일을 여는 열쇠다.


원전

연도문헌이 장에서의 역할
1968Dijkstra, Go To Statement Considered Harmful (CACM)구조적 프로그래밍 논쟁의 시작
1972Parnas, On the Criteria To Be Used in Decomposing Systems into Modules (CACM)정보 은닉 — 모듈 분해 기준은 변경 가능성
1974Dijkstra, On the role of scientific thought (EWD 447)관심사의 분리 정식화
1974Stevens, Myers & Constantine, Structured Design (IBM Systems Journal)결합도·응집도의 정식 발표
1979Yourdon & Constantine, Structured Design (단행본)구조적 설계의 집대성
1981Boehm, Software Engineering Economics변경 비용 곡선의 실증
1986Brooks, No Silver Bullet (IFIP; 1987 IEEE Computer 재수록)본질적/우연적 어려움, 복잡성의 해부
1992Cunningham, The WyCash Portfolio Management System (OOPSLA 경험 보고)기술 부채 은유의 원전
Last updated on