학습 목표
C4 Model 의 Context·Container·Component·Code 4레벨과 대상 독자 를 설명할 수 있다.
Container 다이어그램으로 서비스·데이터스토어·외부 시스템 경계를 그릴 수 있다.
API 계약 (OpenAPI 등)이 서비스 간 결합 을 관리하는 방법임을 설명할 수 있다.
Living documentation — 코드·계약과 동기화 — 원칙을 적용할 수 있다.
문제 상황
신입이 3주 만에 "주문이 결제를 직접 호출하나요?" — 다이어그램 없음 , 구두 전승만
MSA 전환 후 draw.io 에 박스 40개 — 레벨 이 섞여 Context 와 클래스 가 한 장에
inventory가 order 내부 DTO 에 직접 의존 — 계약 없이 공유 jar
OpenAPI 6개월 전 버전 — 모바일은 v2 , 백엔드는 v3 배포
장애 RCA에서 "누가 Kafka topic 소유?" — 문서 ·코드 불일치
C4 Component 까지 전 서비스 그리다 유지 포기 — 범위 과다
데이터·이벤트까지 설계했다. 이제 팀이 같은 그림 을 보도록 문서 를 의도적으로 만드는 편이다.
1. 왜 아키텍처 문서인가
아키텍처 문서 — 구조·경계·결정을 공유 해 변경 비용 ·오해 를 줄인다.
없을 때
있을 때
구두·슬랙만
온보딩 ·리뷰 기준
"내 머릿속" 설계
이해관계자 별 뷰
계약 암묵
명시 API·이벤트 스키마
레거시 공포
경계 ·의존 추적
코드 = 진실 이지만 의도 ·트레이드오프 는 코드만으로 안 보임 → ADR은 다음 편
문서는 완벽 스냅샷 이 아니라 living — 배포·계약과 같이 갱신
2. C4 Model 개요
C4 (Context, Container, Component, Code) — 줌 레벨 별로 다른 추상화 .
레벨
보여 주는 것
주 독자
1 Context
시스템·사용자 ·외부 연동
전사·PM·비개발
2 Container
앱·서비스·DB·메시지 브로커
개발·운영·아키텍트
3 Component
한 컨테이너 안 모듈
해당 팀 개발자
4 Code
클래스·패키지
IDE — 보통 생략
한 장에 전 레벨 금지 — 독자 가 달라 혼란
Simon Brown C4 — notation 단순 , UML 전체가 아님
Deployment ·Dynamic 뷰는 보조 (배포 노드·시퀀스)
3. Level 1 — System Context
Context — 우리 시스템 하나를 박스로, 사람 ·외부 시스템 과 관계만.
[Customer] ──uses──> [Shop Platform] ──card payment──> [Payment PG]
│
└──sends notification──> [Email provider]
규칙
이유
내부 서비스 이름 넣지 않음
Container에서
목적 한 줄 per 박스
Scope 명확
화살표 에 동사 라벨
uses / sends / queries
품질 속성·SLA 요약을 캡션 으로 붙일 수 있음
이해관계자 concern과 맞춤 — 누가 무엇을 걱정 하는지
4. Level 2 — Container
Container — 배포 가능 단위: Spring Boot 앱, SPA, DB, Kafka, Lambda 등.
요소
예
Person
Customer
Container
Web App, API Gateway, Order API, Catalog API
Datastore
PostgreSQL, Redis, Kafka
External
Payment PG
관계 라벨
예
프로토콜
HTTPS JSON, gRPC, JDBC
방향
단방향 기본, 순환 주의
동기/비동기
REST vs publishes events
앞서 MSA 서비스 맵 을 런타임 관점으로 구체화
DB per service — Container마다 자기 datastore 연결
앞서 Kafka ·Redis — Container로 명시
Container 작성 체크
질문
배포 artifact 단위인가
소유 팀 이 있는가
기술 스택이 다른가
SPA vs API vs DB
5. Level 3 — Component (선택적)
Component — 하나의 Container 내부: Controller, Domain Service, Repository, Outbox Relay.
Order API (container)
├── OrderController
├── PlaceOrderService
├── OrderRepository
└── OutboxPublisher
할 때
안 할 때
복잡 도메인·레이어 논의
CRUD 단순 서비스
신규 팀 온보딩
전사 일괄 Component — 유지 불가
헥사고날 포트·어댑터 설명
코드가 진실 이면 링크 만
Component는 해당 repo README·/docs에 로컬 로 두는 경우 많음
6. 다이어그램 작성 원칙
원칙
설명
Scope
제목에 레벨 ·시스템 ·날짜
Legend
사람·시스템·외부·DB 색 통일
적은 박스
한 장 7±2 container
스파게티 금지
겹치면 분할 ·Dynamic 뷰
버전
container-v3-2026-07.png 또는 repo 내 Mermaid
Mermaid ·Structurizr ·PlantUML — 텍스트 로 diff 가능
Confluence 만 — rot 빠름, repo 옆 docs/ 권장
7. API 계약
API 계약 — consumer가 의존 하는 표면 : 경로·스키마·에러·버전.
산출물
역할
OpenAPI (REST)
HTTP API 스키마 ·예제
Protobuf (gRPC)
강타입 ·버전 필드
AsyncAPI
이벤트 topic·payload
JSON Schema
이벤트 envelope
openapi: 3.1.0
info:
title: Order API
version: 2.1.0
description: Provider-owned contract for order read model
paths:
/orders/{orderId}:
get:
operationId: getOrder
parameters:
- name: orderId
in: path
required: true
schema:
type: string
responses:
"200":
description: Order found
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"404":
description: Order not found
components:
schemas:
Order:
type: object
required: [orderId, status, totalAmount]
properties:
orderId:
type: string
status:
type: string
enum: [PENDING, PAID, SHIPPED, CANCELLED]
totalAmount:
type: integer
description: minor units (KRW)
items:
type: array
items:
$ref: "#/components/schemas/OrderItem"
OrderItem:
type: object
required: [sku, quantity]
properties:
sku:
type: string
quantity:
type: integer
규칙
이유
Provider 가 계약 소유
consumer pull
Breaking vs compatible 정의
semver·deprecation
CI contract test
drift 조기 발견
Correlation ID 문서화
분산 추적
공유 DTO jar — 계약 변경 이 전체 재배포 → 안티패턴
앞서 REST/gRPC 선택이 계약 형식 을 결정
버전·호환
변경
호환
필드 추가 (optional)
compatible
필드 삭제 ·타입 변경
breaking
enum 값 추가
보통 compatible
URL path 변경
breaking
Deprecation 헤더·sunset 날짜·마이그레이션 가이드
8. 이벤트·배포 문서
뷰
내용
Dynamic (시퀀스)
Place order 한 흐름 — 앞서 동기·이벤트 시나리오
Deployment
K8s namespace·AZ ·replica
Event catalog
topic·schema·owner ·retention
OrderPlaced:
topic: order.events
schema: order-placed.v2.json
owner: order-team
consumers: inventory, notification, analytics
CDC topic도 catalog 에 등록 — 앞서 CDC 파이프라인 연계
9. 문서 구조 실무
docs/
c4/
01-context.md
02-containers.md
adr/
api/
openapi-order-snippet.yaml
events/
order-placed.schema.json
습관
효과
PR에 다이어그램 diff
구조 변경 리뷰
온보딩 30분: Context→Container
빠른 지도
분기마다 Container 점검
drift 방지
계약 CI publish
Portal·SDK 자동
10. 실무 체크리스트
질문
좋은 답
C4 어디까지 ?
전사 Context+Container , Component는 팀
누가 갱신?
구조 PR 작성자
API 진실 ?
OpenAPI in repo , 배포 동기
이벤트?
AsyncAPI ·schema registry
너무 상세?
Code 레벨 생략 , IDE로
안티패턴
대안
전사 UML 클래스
C4 Container + ADR
한 번 그리고 방치
living doc·PR 연동
계약 없는 REST
OpenAPI 필수
내부 DB 직접 조회
API ·이벤트 만
11. 정리
C4 — Context→Container→Component→Code 줌 , 독자별 분리
Container — MSA·데이터·메시징 경계 의 핵심 산출물
API 계약 — OpenAPI·AsyncAPI로 결합 명시 ·버전
Living doc — repo·CI·PR과 같이 움직임
Part 6 업무 시작 — 다음은 ADR
다음에 다룰 것
ADR과 의사결정 기록
Architecture Decision Record 작성법
해당 내용은 Fundamentals of Software Architecture (Mark Richards, Neal Ford) 및 Software Architecture in Practice, 4/E (Bass, Clements, Kazman) 의 내용을 기반으로 합니다.