- 복잡한 Python 애플리케이션은 규모가 커질수록 단순한 구현 방식만으로 테스트와 변경을 감당하기 어려워지며, 이 책은 그 해법으로 아키텍처 패턴을 코드 예제로 다룸
- MADE.com의 온라인 가구 판매와 글로벌 공급망을 예제로 삼아, 현실의 운영 문제를 소프트웨어 모델로 옮기는 도메인 모델링을 중심에 둠
- 핵심 축은 TDD, DDD, 이벤트 기반 아키텍처이며, 빠른 단위 테스트와 적은 수의 E2E 테스트, 인프라와 분리된 모델, 메시지 기반 통합을 목표로 함
- Flask, SQLAlchemy, pytest, Docker, Redis를 사용하지만, 특정 기술 선택이 구현 세부사항으로 밀려나는 구조를 만드는 데 초점을 맞춤
- 복잡한 Python 애플리케이션을 다뤄본 경험이 있으면 읽을 수 있으며, DDD나 고전적 애플리케이션 아키텍처 패턴을 미리 알 필요는 없음
테스트하기 쉬운 구조에서 출발한 문제의식
- Harry의 이전 책 Test-Driven Development with Python 이후, 애플리케이션을 어떻게 구조화해야 테스트하기 쉬운지에 대한 질문이 남음
- 핵심은 비즈니스 로직을 단위 테스트로 충분히 다루면서, 통합 테스트와 E2E 테스트 수를 최소화하는 구조를 만드는 것임
- "Hexagonal Architecture", "Ports and Adapters", "Functional Core, Imperative Shell" 같은 개념을 언급했지만, 당시에는 실제로 충분히 이해하거나 실천하지 못한 상태였음
- Bob은 팀에서 소프트웨어 아키텍처를 맡을 사람이 없어 아키텍트가 되었고, Ian Cooper에게 코드 작성과 사고 방식에 대한 새로운 접근을 배움
MADE.com 사례: 공급망을 소프트웨어로 모델링하기
- 두 저자는 유럽 이커머스 회사 MADE.com에서 일하며, 책의 기법을 실제 비즈니스 문제를 모델링하는 분산 시스템 구축에 적용함
- 예제 도메인은 Bob이 MADE에서 처음 만든 시스템을 바탕으로 하며, 새 프로그래머가 팀에 합류할 때 가르쳐야 하는 내용을 정리하려는 목적을 가짐
- MADE.com은 화물 파트너와 제조사로 이루어진 글로벌 공급망을 운영함
- 비용을 낮추기 위해 재고를 창고에 오래 쌓아두지 않도록 배송을 최적화하려 함
- 이상적으로는 고객이 소파를 구매하는 바로 그날 항구에 도착해, 보관 없이 고객 집으로 배송되는 흐름을 원함
- 컨테이너선으로 상품이 도착하는 데 3개월이 걸릴 수 있어 타이밍 조정이 어려움
- 실제 운영에서는 파손, 침수, 폭풍으로 인한 지연, 물류 파트너의 처리 오류, 서류 누락, 고객의 주문 변경 같은 변수가 계속 발생함
- 이런 문제를 다루기 위해 현실 세계의 운영을 소프트웨어로 표현하고, 가능한 많은 업무를 자동화하려 함
Python 프로젝트가 커질 때 드러나는 한계
- Python은 빠르게 성장하고 성숙해졌지만, C#과 Java 진영이 오래 다뤄온 종류의 문제를 이제 본격적으로 맡기 시작한 상태로 봄
- 스타트업은 실제 비즈니스가 되고, 웹 앱과 스크립트 자동화는 엔터프라이즈 소프트웨어로 커져감
- Python의 철학에는 “There should be one—and preferably only one—obvious way to do it”가 있지만, 프로젝트 규모가 커지면 가장 obvious한 방식이 복잡성과 요구사항 변화를 관리하는 데 항상 적합하지는 않음
- 책에서 다루는 기법과 패턴은 새롭지 않지만, 대부분 Python 세계에는 비교적 새로운 것으로 봄
- Eric Evans의 Domain-Driven Design, Martin Fowler의 Patterns of Enterprise Application Architecture를 대체하려는 책은 아니며, 해당 고전들을 자주 참조하고 읽기를 권장함
- 기존 문헌의 코드 예제는 Java나 C++/#로 쓰인 경우가 많아, Python 개발자에게는 읽기 부담이 클 수 있음
복잡성 관리를 위한 세 가지 도구
- 테스트 주도 개발(TDD) 은 올바른 코드를 만들고, 회귀를 두려워하지 않고 리팩터링하거나 기능을 추가하게 해줌
- 가능한 빠르게 테스트를 실행하는 방법
- 빠르고 의존성 없는 단위 테스트에서 최대한 많은 커버리지와 피드백을 얻는 방법
- 느리고 불안정한 E2E 테스트를 최소화하는 방법을 다룸
- 도메인 주도 설계(DDD) 는 비즈니스 도메인의 좋은 모델을 만드는 데 집중하게 함
- 모델이 인프라 관심사에 얽매이지 않도록 하는 방법
- 변경하기 어려운 모델이 되지 않게 하는 방법을 다룸
- 메시지로 통합되는 느슨하게 결합된 마이크로서비스, 때로는 reactive microservices라고 불리는 방식은 여러 애플리케이션이나 비즈니스 도메인 사이의 복잡성을 관리하는 해법으로 다뤄짐
- Flask, Django, Celery 같은 Python 생태계의 기존 도구와 어떻게 맞출지는 항상 분명하지 않음
- 마이크로서비스를 사용하지 않거나 관심이 없어도, 책의 대부분 패턴과 이벤트 기반 아키텍처 내용 상당수는 모놀리식 아키텍처에도 적용 가능함
독자와 전제 지식
- 이 책은 어느 정도 복잡한 Python 애플리케이션을 가까이에서 다뤄본 독자를 가정함
- 복잡성 관리에서 오는 고통을 경험한 독자에게 맞춰져 있음
- DDD나 고전적 애플리케이션 아키텍처 패턴에 대한 사전 지식은 필요하지 않음
- 설명은 예제 애플리케이션을 중심으로 장별로 쌓아가는 방식임
- 저자들은 업무에서 TDD를 사용하므로, 테스트 코드를 먼저 보여주고 그다음 구현을 보여주는 흐름을 자주 사용함
- Flask, SQLAlchemy, pytest, Docker, Redis를 쓰지만, 이미 익숙하면 도움이 될 뿐 필수는 아님
- 주요 목표 중 하나는 특정 기술 선택이 사소한 구현 세부사항이 되는 아키텍처를 만드는 것임
책의 구성
- 책은 두 부분으로 나뉨
-
1부: 도메인 모델링을 지원하는 아키텍처
- 도메인 모델링과 DDD는 1장, 2장, 7장에서 다룸
- 복잡한 비즈니스 문제를 코드 안의 도메인 모델로 반영해야 한다는 전제를 둠
- 외부 의존성이 없고 빠른 단위 테스트가 가능한 모델로 시작하는 방법을 설명함
- 이후 적절한 aggregate 선택과 데이터 무결성 문제를 다시 다룸
- Repository, Service Layer, Unit of Work 패턴은 2장, 4장, 5장에서 다룸
- 이 패턴들은 모델을 불필요한 의존성에서 분리하기 위해 서로를 보완함
- 영속 저장소 주변에 추상화 계층을 만들고, 시스템 진입점과 주요 유스케이스를 포착하는 서비스 계층을 둠
- Flask API나 CLI처럼 얇은 진입점을 만들기 쉬운 구조를 보여줌
- 추상화와 테스트에 대한 논의는 3장과 5장에서 이어짐
- Repository 패턴을 소개한 뒤 추상화를 선택하는 방법과 결합 방식에서 추상화의 역할을 다룸
- Service Layer 패턴 이후에는 테스트 피라미드와 가능한 높은 추상화 수준에서 단위 테스트를 작성하는 방법을 다룸
-
2부: 이벤트 기반 아키텍처
- 이벤트 기반 아키텍처는 8장부터 11장에서 다룸
- Domain Events, Message Bus, Handler 패턴을 소개함
- Domain Events는 시스템의 어떤 상호작용이 다른 동작을 촉발한다는 개념을 담는 수단임
- Message Bus는 동작이 이벤트를 촉발하고 적절한 handler를 호출하게 함
- 이벤트를 마이크로서비스 아키텍처에서 서비스 간 통합 패턴으로 사용하는 방법을 다룸
- commands와 events를 구분하며, 애플리케이션은 본질적으로 메시지 처리 시스템이 됨
- 12장에서는 CQRS 예제를 이벤트를 사용하는 방식과 사용하지 않는 방식으로 다룸
- 13장에서는 명시적·암묵적 의존성을 정리하고 간단한 의존성 주입 프레임워크를 구현함
- 에필로그에서는 새로 시작하는 단순 예제가 아니라 기존 소프트웨어에 이런 원칙을 적용하는 방법과 추가 읽을거리를 제공함
예제 코드와 따라 하기
- 책은 하나의 예제 프로젝트를 중심으로 구성되며, 장이 진행될수록 프로젝트를 단계적으로 확장함
- 독자가 실제로 코드를 만져보고 패턴이 어떻게 작동하는지 감각을 얻는 것을 중요하게 봄
- 모든 코드는 GitHub에 있으며 각 장마다 별도 브랜치가 있음
- 브랜치 목록은 GitHub의 branches 페이지에서 확인 가능함
- 따라 하는 방식은 세 가지로 제안됨
- 직접 저장소를 만들고 책의 예제를 따라 앱을 구축하며, 필요할 때 저자들의 저장소를 참고함
- 각 패턴을 장별로 자신의 작은 프로젝트에 적용해 봄
- 각 장의 "Exercise for the Reader"와 일부가 비어 있는 GitHub 코드를 사용해 빠르게 실습함
- 특히 자신의 프로젝트에 패턴을 적용하려는 독자는 단순한 예제를 먼저 다루는 것이 안전한 연습이 됨
- 최소한 각 장을 읽을 때 저장소에서
git checkout으로 코드를 받아 실제 동작하는 앱 맥락에서 코드를 확인하기를 권장함
라이선스와 형식
- 코드와 온라인 버전은 Creative Commons CC BY-NC-ND 라이선스임
- 비상업적 목적
- 저작자 표시
- 복사와 공유 가능
- 인쇄판은 별도 라이선스를 따르며, 재사용 관련 우려가 있으면 O’Reilly에 문의하도록 안내함
- 책의 표기 관례는 이탤릭, 고정폭, 고정폭 굵게, 고정폭 이탤릭을 구분해 사용함
- 이탤릭은 새 용어, URL, 이메일 주소, 파일명, 확장자를 나타냄
- 고정폭은 프로그램 목록과 코드 요소를 나타냄
- 고정폭 굵게는 사용자가 그대로 입력해야 하는 명령이나 텍스트를 나타냄
- 고정폭 이탤릭은 사용자가 제공하거나 문맥에 따라 정해지는 값으로 대체될 텍스트를 나타냄