[SE100 #024] C4 모델로 아키텍처 그리기
소프트웨어 공학 100 주제 시리즈의 24번째 글이다. (카테고리: 설계와 아키텍처)
한 줄 요약
C4 모델은 Simon Brown 이 만든 아키텍처 다이어그램 방식으로, 시스템 컨텍스트 → 컨테이너 → 컴포넌트 → 코드 네 단계로 확대해 들어간다. 지도 앱처럼 줌 레벨을 나눠 “한 그림에 한 수준의 추상화만” 담게 하는 것이 핵심이며, 표기법은 정하지 않는다.
왜 필요한가
C4 공식 소개 페이지는 즉흥 다이어그램의 흔한 문제를 이렇게 나열한다.
- 표기(색, 모양, 선 스타일)가 설명되지 않거나 일관되지 않다.
- 요소의 목적과 의미가 모호하다.
- 관계가 빠져 있거나 라벨이 없다.
- “비즈니스 로직” 같은 뭉뚱그린 용어를 쓴다.
- 약어가 설명되지 않는다.
- 기술 선택이 빠져 있다.
- 추상화 수준이 섞여 있다.
여러 장이 모이면 문제가 커진다. 그림마다 표기와 이름이 다르고, 어떤 순서로 읽어야 하는지, 한 그림에서 다음 그림으로 어떻게 넘어가는지 알 수 없다. 같은 페이지는 UML·ArchiMate·SysML 이 있지만 많은 팀이 이미 그것들을 버리고 단순한 “박스와 선” 으로 돌아섰으며, 그 과정에서 시각적으로 소통하는 능력을 잃었다고 진단한다. C4 는 UML 만큼 무겁지 않으면서 즉흥 그림보다 규율 있는 중간 지점을 노린다.
핵심 개념
기원
C4 역사 페이지에 따르면 Simon Brown 은 2000년대 중반부터 아키텍처 워크숍을 진행했는데, 설계 실습에서 참가자들(본인 포함)이 서로의 다이어그램을 거의 이해하지 못했다. 그래서 자신이 실무에서 쓰던 방식 — 시스템 전체, 웹 앱·DB 같은 실행 단위, 애플리케이션 내부 개념 순으로 그리는 블록 다이어그램 — 을 가르치기 시작했다. 2011년 QCon London 워크숍 자료가 “C4” 이름이 처음 보이는 곳이고, 당시 마지막 C 는 “클래스(Classes)” 였다. 2018년에 “코드(Code)” 로 바뀌었다.
추상화 4개 + 사람
| 추상화 | 공식 정의 요약 |
|---|---|
| 사람(Person) | 소프트웨어 시스템을 사용하는 사람(행위자, 역할, 페르소나 등) |
| 소프트웨어 시스템 | 가장 높은 추상화. 사용자에게 가치를 전달하는 것. 대개 한 팀이 만들고 소유하고 내부를 볼 수 있는 단위 |
| 컨테이너 | 도커가 아니다! 애플리케이션 또는 데이터 저장소. 시스템이 동작하려면 실행 중이어야 하는 것 — 서버 웹 앱, SPA, 모바일 앱, 배치, 서버리스 함수, DB 스키마, S3 버킷 등 |
| 컴포넌트 | 잘 정의된 인터페이스 뒤에 캡슐화된 관련 기능 묶음. 별도로 배포되지 않는다 — 컨테이너 안의 컴포넌트는 같은 프로세스 공간에서 실행 |
| 코드 | 컴포넌트를 구현하는 클래스, 인터페이스, 함수, 테이블 등 |
헷갈리기 쉬운 경계 세 가지를 공식 FAQ 가 정리해 둔다.
- JAR, DLL, 모듈은 컨테이너인가? 대개 아니다. 컨테이너는 런타임 구성물이고, JAR 등은 코드를 조직하는 단위다.
- 서버 렌더링 웹 앱과 SPA 는? 주로 정적 HTML 을 생성하면 컨테이너 하나, 상당한 JavaScript 앱(SPA)을 내려보내면 컨테이너 둘이다. 서로 다른 프로세스 공간이 원격 통신(JSON/HTTPS 등)으로 대화하기 때문이다.
- S3, RDS 같은 관리형 서비스는? 직접 운영하지 않아도 버킷과 스키마는 우리가 소유하고 책임지므로 컨테이너로 그린다.
또 “소프트웨어 시스템” 페이지는 제품 도메인, 바운디드 컨텍스트, 비즈니스 역량, 피처 팀, 스쿼드는 대개 소프트웨어 시스템이 아니라고 명시한다.
다이어그램 4단계
| 다이어그램 | 범위 | 주 요소 | 대상 독자 | 공식 권고 |
|---|---|---|---|---|
| 1. 시스템 컨텍스트 | 시스템 하나 | 대상 시스템 + 직접 연결된 사람·외부 시스템 | 기술·비기술 모두 | 모든 팀에 권장 |
| 2. 컨테이너 | 시스템 하나 | 시스템 안의 컨테이너 | 아키텍트, 개발자, 운영 | 모든 팀에 권장 |
| 3. 컴포넌트 | 컨테이너 하나 | 컨테이너 안의 컴포넌트 | 아키텍트, 개발자 | 가치가 있을 때만. 오래 둘 문서면 자동 생성 고려 |
| 4. 코드 | 컴포넌트 하나 | 클래스·인터페이스·테이블 | 아키텍트, 개발자 | 권장하지 않음. IDE 가 필요할 때 만들어 줌 |
공식 권고가 1·2단계만 “권장” 이라는 점이 중요하다. 3·4단계는 코드와 함께 빠르게 낡기 때문이다.
보조 다이어그램도 셋 있다.
- 시스템 랜드스케이프: 조직 전체 시스템 지도. 특정 시스템에 초점이 없는 컨텍스트 다이어그램. 큰 조직에서 권장.
- 동적 다이어그램: 특정 기능에서 요소들이 런타임에 협력하는 순서. UML 커뮤니케이션 다이어그램 기반. 아껴 쓰라고 권한다.
- 배포 다이어그램: 컨테이너 인스턴스가 환경별(운영·스테이징 등) 인프라에 어떻게 배치되는지. UML 배포 다이어그램 기반. 권장.
컨테이너 다이어그램 페이지는 클러스터링, 로드밸런서, 복제, 장애조치 같은 내용은 환경마다 다르므로 컨테이너 다이어그램이 아니라 환경별 배포 다이어그램에 담으라고 권한다. 논리 구조와 배치를 섞지 않는 것이다.
표기 규칙
표기 페이지는 C4 가 표기 독립적이며 특정 표기를 강제하지 않는다고 밝힌 뒤, 다음을 권한다.
- 모든 다이어그램에 유형과 범위를 담은 제목 (“System Context diagram for 결제 시스템”)
- 모든 다이어그램에 범례(도형, 색, 선, 화살표)
- 모든 요소에 유형(Person, Software System, Container, Component)과 짧은 설명
- 모든 컨테이너·컴포넌트에 기술 명시
- 모든 선은 단방향, 모든 선에 라벨. “Uses” 같은 한 단어는 피함
- 컨테이너 사이 관계(대개 프로세스 간 통신)에는 프로토콜 명시
- 파랑·회색 상자는 관례일 뿐 C4 가 정한 색이 아님. 흑백 인쇄와 색각 이상을 고려
그리기 대신 모델링
도구 페이지는 “다이어그래밍” 과 “모델링” 을 구분한다. 그림 도구는 상자 이름을 바꾸면 모든 그림에서 직접 고쳐야 하고, 질의(“컴포넌트 X 의 모든 의존”)가 안 되고, diff 가 어렵다. 모델링 도구는 요소와 관계를 하나의 모델(데이터) 로 정의하고 그 위에 여러 뷰를 만든다. 아키텍처 모델은 결국 노드와 엣지로 된 방향 그래프이고, 다이어그램은 그 부분 그래프다.
예제: Structurizr DSL 로 쓰는 C4
C4 저자가 만든 Structurizr 의 DSL은 모델과 뷰를 텍스트로 정의한다. Git 에 두고 PR 로 리뷰할 수 있다. 공식 최소 예제를 확장하면 다음과 같다.
workspace "주문 시스템" {
model {
customer = person "고객" "온라인으로 상품을 주문한다"
pg = softwareSystem "PG사" "카드 결제 승인" "External"
shop = softwareSystem "주문 시스템" {
spa = container "웹 프론트엔드" "상품 조회와 주문 화면" "React SPA"
api = container "주문 API" "주문 생성, 재고 확인" "Spring Boot" {
orderCtl = component "OrderController" "주문 REST 엔드포인트" "Spring MVC"
orderSvc = component "OrderService" "주문 규칙과 재고 차감" "Kotlin"
payPort = component "PaymentGateway" "결제 요청 포트" "Kotlin interface"
}
db = container "주문 DB" "주문과 재고" "PostgreSQL" "Database"
}
customer -> spa "주문한다" "HTTPS"
spa -> orderCtl "주문 생성 요청" "JSON/HTTPS"
orderCtl -> orderSvc "주문 생성을 위임"
orderSvc -> db "주문 저장, 재고 차감" "JDBC"
orderSvc -> payPort "결제 승인 요청"
payPort -> pg "승인 API 호출" "HTTPS"
}
views {
systemContext shop "context" {
include *
autoLayout lr
}
container shop "containers" {
include *
autoLayout lr
}
component api "components" {
include *
autoLayout lr
}
}
}
공식 문서의 implied relationships 설명대로, DSL 은 기본적으로 하위 요소 사이 관계로부터 상위 요소 사이의 “암시된 관계” 를 자동으로 만든다. 그래서 컴포넌트 수준 관계만 정의해도 컨테이너·컨텍스트 뷰에 관계가 나타난다. 이름을 바꾸면 모든 뷰에 반영된다. 이것이 공식 문서가 말하는 모델링의 이점이다.
리뷰 체크리스트
- 제목에 다이어그램 유형과 범위가 있는가
- 범례가 있는가
- 모든 요소에 유형·설명이, 컨테이너·컴포넌트에 기술이 있는가
- 모든 선이 단방향이고 의미 있는 라벨(동사구)과 프로토콜을 가졌는가
- 한 다이어그램에 추상화 수준이 섞이지 않았는가 (예: 컨텍스트 그림에 DB 테이블)
- 배포 세부(레플리카 수, LB)가 컨테이너 그림이 아닌 배포 그림에 있는가
흔한 오해와 함정
- “컨테이너 = 도커 컨테이너.” 공식 문서가 첫 줄에서 부정한다. 하나의 도커 컨테이너에 C4 컨테이너가 여러 개 있을 수도, 그 반대일 수도 있다.
- “네 단계를 모두 그려야 C4 다.” 공식 권고는 1·2단계와 배포 다이어그램이다. 코드 다이어그램은 권장하지 않는다.
- “C4 는 표기법이다.” C4 는 추상화와 다이어그램 계층이고 표기는 자유다. 그래서 범례가 필수다.
- “마이크로서비스 하나 = 소프트웨어 시스템.” 공식 페이지는 소유 팀 경계로 판단하라고 한다. 한 팀이 소유한 여러 서비스는 하나의 시스템 안 여러 컨테이너로 그리는 경우가 많다.
- “C4 가 4+1 을 대체한다.” C4 의 네 단계는 대부분 정적 구조(4+1 의 개발·논리 뷰에 가까움)이고, 동시성·프로세스 관점은 약하다. 성능·동시성 관심사가 크면 동적·배포 다이어그램이나 별도 뷰로 보완해야 한다(SE100 #023).
확인 문제
- React SPA 와 그것을 내려주는 Spring 서버는 C4 에서 컨테이너 몇 개인가? 이유는?
- 컴포넌트와 컨테이너를 가르는 기준은 무엇인가?
- 공식 문서가 “모든 팀에 권장” 하는 다이어그램은 무엇인가?
- 레플리카 3개와 로드밸런서는 어느 다이어그램에 그려야 하는가?
- 그림 도구 대신 모델링 도구(DSL)를 쓸 때의 이점 두 가지는?
풀이
- 두 개. 브라우저에서 도는 SPA 와 서버 애플리케이션은 서로 다른 프로세스 공간이며 원격 통신으로 대화하기 때문이다.
- 배포 단위 여부. 컨테이너는 따로 실행·배포되는 런타임 단위이고, 컴포넌트는 컨테이너 안에서 같은 프로세스로 실행되며 따로 배포되지 않는다.
- 시스템 컨텍스트 다이어그램과 컨테이너 다이어그램. (보조 중에서는 배포 다이어그램, 큰 조직이면 시스템 랜드스케이프)
- 해당 환경의 배포 다이어그램. 환경마다 달라지는 정보이기 때문이다.
- 요소를 한 번 정의하면 이름 변경이 모든 뷰에 반영된다. 모델을 질의하거나 다른 도구로 내보낼 수 있고, 텍스트라서 diff·PR 리뷰가 쉽다.
더 읽을거리 (References)
- Simon Brown, The C4 model — Introduction, History, Notation, Tooling
- Structurizr, DSL 문서, DSL 예제
- Philippe Kruchten, “The 4+1 View Model of architecture”, IEEE Software 12(6), 1995
- CS300: UML 기초