클린 아키텍처 with 파이썬 - "돌아가는 코드"를 넘어 "오래 살아남는 코드"로

반응형

 

"한빛미디어 서평단 <나는리뷰어다> 활동을 위해서 책을 협찬 받아 작성된 서평입니다."

 

 

도서 정보
- 원서 : Clean Architecture with Python (Packt, 2025)
- 저자 : 샘 킨(Sam Keen)
- 번역 : 송영숙
- 출판사 : 한빛아카데미
- 출간 : 2026년 4월 27일
- 페이지 : 361쪽

 

 

 

이런 고민 해보신 적 있나요?

코드를 작성한 지 6개월이 지났는데...

어디서부터 손을 대야 할지 막막한 느낌이요.

 

기능 하나 추가했더니 엉뚱한 곳에서 버그가 터지고, 테스트 코드는 있는데 뭔가 믿음이 안 가고...

Flask나 FastAPI로 빠르게 프로토타입은 만들었는데 규모가 커지면서 점점 스파게티 코드가 되어가는 것 같고...

 

저도 프로그램을 개발하면서 이런 고민을 한두 번이 아니었어요.

그래서 이번에 출간된 『클린 아키텍처 with 파이썬』을 바로 집어들었습니다.

 

 

저자는 누구?

 

샘 킨(Sam Keen)은 25년 이상의 경력을 가진 소프트웨어 엔지니어링 리더입니다.

 

소규모 스타트업부터 시작해 AWS, 룰루레몬(Lululemon), 나이키(Nike) 같은 대기업에서 파이썬으로 클라우드 네이티브 시스템을 설계해온 실전 전문가죠.

특히 룰루레몬에서는 회사 최초의 클라우드 네이티브 개발팀을 이끌며 분산 아키텍처 기준을 정립한 것으로 유명합니다.

 

흥미로운 점은, 이 책이 자바나 C# 중심으로만 이야기되던 클린 아키텍처를 "파이썬답게" 풀어보고 싶다는 저자의 진짜 고민에서 출발했다는 거예요.

 

"파이썬 커뮤니티에서는 클린 아키텍처가 과부하처럼 느껴진다는 시각이 많았어요.

저는 그 선입견을 깨고, 파이썬의 철학을 유지하면서도 아키텍처의 장점을 살릴 수 있다는 걸 보여주고 싶었습니다."
- Sam Keen 인터뷰 중

 

 

이 책은 어떤 책인가요?

 

한마디로 정리하면 → "파이썬다운 유연성"과 "아키텍처의 엄격함"을 동시에 잡는 실전 설계 가이드입니다.

 

로버트 C. 마틴(Uncle Bob)의 고전 『Clean Architecture』의 원칙을 바탕으로 하되, Python 3.13의 최신 문법인 타입 힌팅(Type Hints), 프로토콜(Protocol), 데이터클래스(dataclass)를 적극 활용해서 파이썬 개발자들이 실제로 쓸 수 있는 코드로 구현해냅니다.

 

책 전체에 걸쳐 태스크 관리 애플리케이션(TodoApp) 하나를 예제로 삼아, 챕터가 진행될수록 시스템이 점점 진화하는 방식으로 구성되어 있어요.

GitHub에 챕터별로 실제 동작하는 코드도 함께 제공되니 실습하면서 따라가기에도 아주 좋습니다.

 

 

어떤 내용을 다루나요?

 

총 12개 챕터로 구성되어 있고, 크게 3부분으로 나눠볼 수 있어요.

 

1) 기초 다지기 (1~3장)

 

1장에서는 클린 아키텍처가 왜 필요한지부터 설명합니다. AI 코딩 에이전트와 LLM 덕분에 코드 생산성은 폭발했지만, 역설적으로 유지보수 비용이 함께 급증한 현실에서 아키텍처가 왜 더 중요해졌는지를 설득력 있게 짚어줘요.

 

2장은 이 책에서 개인적으로 가장 중요한 챕터라고 생각합니다. SOLID 원칙 다섯 가지를 파이썬 실전 코드로 완전히 풀어냅니다. 단순히 이론 설명이 아니라, "이렇게 짜면 왜 나중에 문제가 생기는지"를 눈으로 보여주는 방식이라 이해가 정말 잘 됩니다.

 

3장은 파이썬의 동적 타이핑 특성인 덕 타이핑(Duck Typing), 타입 힌팅, 그리고 최신 기능인 Protocol을 클린 아키텍처 관점에서 어떻게 활용하는지 다룹니다.

 

2) 아키텍처 구현 (4~9장)

 

이 부분이 책의 핵심입니다. 클린 아키텍처의 동심원 레이어, 즉 도메인 계층 → 애플리케이션 계층 → 인터페이스 어댑터 계층 → 프레임워크 계층을 하나씩 구현해나가죠.

 

- 도메인 계층 : 핵심 비즈니스 로직을 외부 관심사(DB, 프레임워크, UI)로부터 완전히 격리하는 방법

- Repository 패턴 : 데이터 저장소를 추상화해서 테스트 가능성을 극대화하는 설계

- 의존성 주입(DI) : 의존성 역전 원칙(DIP)을 파이썬스럽게 구현하는 실전 기법

- Flask 통합 : 웹 프레임워크를 "세부 구현 사항"으로 대우하며 연결하는 방법

 

3) 실전 확장 (10~12장)

 

마지막 부분에서는 현업에서 만나는 난감한 상황들을 다룹니다.

 

- 이벤트 기반 아키텍처 : 이벤트를 활용한 계층 간 느슨한 결합 유지

- 레거시 코드 리팩터링 : "Strangler Fig" 패턴으로 기존 시스템을 단계적으로 클린 아키텍처로 전환하는 방법

- 관측 가능성(Observability) : 로깅과 모니터링을 아키텍처에 올바르게 녹이는 방법

 

 

책 내용을 기반으로 한 예제

 

클린 아키텍처의 핵심 가치는 테스트 가능성, 교체 가능성, 독립성 입니다.

다음 예제들은 이러한 클린 아키텍처의 핵심 가치를 잘 보여주는 예제들을 만들어보았습니다.

 

1) 의존성 역전 (Dependency Inversion) - Repository 패턴 : 교체 가능성

# 도메인 계층 (추상화)
from abc import ABC, abstractmethod

class TaskRepository(ABC):
    @abstractmethod
    def save(self, task): pass

    @abstractmethod
    def find_by_id(self, task_id): pass

# 인프라 계층 (세부 구현 — DB는 교체 가능)
class SQLiteTaskRepository(TaskRepository):
    def save(self, task):
        # SQLite에 저장
        pass

class InMemoryTaskRepository(TaskRepository):
    def save(self, task):
        # 테스트용 메모리 저장
        pass
 

이 예제의 본질은 "비즈니스 로직이 저장소를 선택하지 않는다" 는 점입니다.

 

일반적으로 코드를 짜다 보면 비즈니스 로직 안에 sqlite3.connect(...) 같은 코드가 직접 박히게 됩니다.

그러면 DB가 바뀔 때마다 비즈니스 로직을 건드려야 하고, 테스트할 때도 실제 DB가 반드시 있어야 합니다.

Repository 패턴은 이 방향을 역전시킵니다.

비즈니스 로직은 TaskRepository라는 추상화(인터페이스)에만 의존하고,

실제 저장소가 SQLite인지 PostgreSQL인지 MongoDB인지는 전혀 모릅니다.

저장소가 비즈니스 로직에 맞춰서 인터페이스를 구현하는 거지,

비즈니스 로직이 저장소에 맞춰 변경되지 않습니다.

이게 바로 의존성 역전(Dependency Inversion) 의 핵심입니다.

의존 방향이 "비즈니스 → DB"가 아니라 "DB → 비즈니스 인터페이스" 로 뒤집힌 거예요.

 

현실적인 이득은 명확합니다.

초기 개발 시에는 InMemoryTaskRepository로 빠르게 개발하고,

나중에 SQLiteTaskRepository로 바꿔 끼워도 비즈니스 로직 코드는 단 한 줄도 바뀌지 않습니다.

2년 후 PostgreSQL로 마이그레이션해야 할 때도 마찬가지입니다.

 

2) 유스케이스(Use Case) 계층 분리 : 독립성

# 애플리케이션 계층 — 프레임워크와 완전히 독립
class CreateTaskUseCase:
    def __init__(self, repo: TaskRepository):
        self.repo = repo

    def execute(self, title: str) -> Task:
        task = Task(title=title)
        self.repo.save(task)
        return task
 

이 예제의 본질은 "비즈니스 로직이 어떤 프레임워크에도 오염되지 않는다" 는 점입니다.

Flask로 API를 만들다 보면 자연스럽게 이런 코드가 만들어집니다.

@app.route('/tasks', methods=['POST'])
def create_task():
    title = request.json['title']         # Flask 의존
    task = Task(title=title)
    db.session.add(task)                  # SQLAlchemy 의존
    db.session.commit()
    return jsonify(task.to_dict()), 201
 

이 코드는 Flask와 SQLAlchemy 없이는 단 한 줄도 실행되지 않습니다.

나중에 FastAPI로 바꾸거나 CLI 도구로 재사용하려 하면 전부 다시 짜야 합니다.

 

반면 CreateTaskUseCase는 Flask도, FastAPI도, SQLAlchemy도 전혀 모릅니다.

title을 받아서 Task를 만들고 저장하는 순수한 비즈니스 규칙만 담고 있습니다.

그래서 이 유스케이스는 웹 API 핸들러에서도, CLI에서도, 배치 처리에서도, 테스트 코드에서도 완전히 동일하게 재사용됩니다.

 

독립성이란 결국 "변경의 이유가 오직 하나여야 한다" 는 단일 책임 원칙(SRP)을 계층 전체에 적용한 것입니다.

프레임워크가 바뀌는 것은 비즈니스 로직이 변경되는 이유가 아니므로, 유스케이스는 프레임워크 변경에 영향을 받지 않아야 합니다.

 

3) Protocol을 활용한 덕 타이핑 인터페이스 : 교체 가능성

from typing import Protocol

# ABC 상속 없이 인터페이스 정의
class Notifier(Protocol):
    def send(self, message: str) -> None: ...

# 세부 구현들 — Notifier를 상속하지 않아도 됨!
class EmailNotifier:
    def send(self, message: str) -> None:
        print(f"이메일 전송: {message}")

class SlackNotifier:
    def send(self, message: str) -> None:
        print(f"Slack 전송: {message}")

class SilentNotifier:  # 테스트용
    def send(self, message: str) -> None:
        pass

# 비즈니스 로직 — 구체 구현을 전혀 모름
class TaskCompleteUseCase:
    def __init__(self, notifier: Notifier):
        self.notifier = notifier

    def execute(self, task_title: str) -> None:
        # 비즈니스 로직 처리...
        self.notifier.send(f"태스크 완료: {task_title}")

# 런타임에 자유롭게 교체
use_case = TaskCompleteUseCase(EmailNotifier())
use_case = TaskCompleteUseCase(SlackNotifier())
use_case = TaskCompleteUseCase(SilentNotifier())  # 테스트 시
 

이 예제의 본질은 "구현체가 인터페이스를 몰라도 된다" 는 점입니다.

 

ABC(Abstract Base Class) 방식은 반드시 class EmailNotifier(Notifier)처럼 명시적으로 상속해야 합니다.

이 말은 서드파티 라이브러리의 클래스를 가져다 쓰려면 해당 클래스를 수정하거나 래퍼를 만들어야 한다는 뜻입니다.

 

Protocol은 이 제약을 완전히 없애버립니다.

send(message: str) 메서드만 있으면, 그게 어디서 온 클래스든 Notifier로 취급합니다.

실제로 외부 라이브러리의 알림 클래스가 우연히 같은 시그니처의 메서드를 갖고 있다면 수정 없이 바로 꽂아 쓸 수 있습니다.

 

더 깊은 의미는 "인터페이스의 소유권이 사용하는 쪽에 있다" 는 점입니다.

TaskCompleteUseCase가 필요한 기능(send)을 Protocol로 정의하고, 구현체들은 그 규약을 맞추기만 하면 됩니다.

비즈니스 로직이 외부 구현에 맞춰 변경되는 것이 아니라, 외부 구현이 비즈니스 로직의 기대에 맞춰집니다.

이것 역시 의존성 역전의 다른 표현입니다.

 

4) 테스트 친화적 구조 : 테스트 가능성

def test_create_task():
    repo = InMemoryTaskRepository()  # DB 없이 테스트
    use_case = CreateTaskUseCase(repo)

    task = use_case.execute("블로그 작성")

    assert task.title == "블로그 작성"
    assert len(repo.tasks) == 1
 

이 예제의 본질은 "테스트가 아키텍처의 품질을 측정하는 리트머스 시험지" 라는 점입니다.

 

테스트 코드를 짜기 어려운 이유는 대부분 아키텍처가 잘못되어 있기 때문입니다.

DB 연결, 외부 API, 파일 시스템 없이 테스트를 작성할 수 없다면,

그건 비즈니스 로직이 외부 의존성과 강하게 결합되어 있다는 신호입니다.

 

위 테스트 코드가 이렇게 단순할 수 있는 이유는 앞의 1~3번 예제가 올바르게 설계되어 있기 때문입니다.

InMemoryTaskRepository로 교체할 수 있는 건 Repository 패턴(1번) 덕분이고,

CreateTaskUseCase를 독립적으로 호출할 수 있는 건 계층 분리(2번) 덕분입니다.

 

또 하나 중요한 관점은 "테스트 코드는 아키텍처의 첫 번째 클라이언트" 라는 점입니다.

테스트가 복잡해진다는 건 실제 사용자 코드도 이 모듈을 사용하기 어렵다는 의미이고,

테스트가 간단하다는 건 실제 코드에서도 조합하고 확장하기 쉽다는 의미입니다.

즉, 좋은 테스트 구조는 좋은 설계의 결과이면서 동시에 증거입니다.

 

 

이 책의 가장 큰 장점은?

 

첫째, UML 다이어그램이 없어요!

 

아키텍처 책들이 흔히 UML로 가득 차 있는데, 이 책은 과감하게 코드로 설명합니다.

"개념을 이해하기에 충분한 코드"와 "실제로 동작하는 Github 코드"를 분리해서 제공하는 방식이 정말 탁월합니다.

 

둘째, AI 시대에 더 빛나는 책입니다.

 

저자가 직접 언급한 내용인데, 클린 아키텍처는 AI 코딩 도구와 궁합이 아주 좋습니다. 레이어별로 문제를 분리해두면 AI 에이전트에게 "도메인 객체 부분만 작업해줘"처럼 스코프를 좁혀서 지시할 수 있거든요. Context Rot(긴 컨텍스트에서 AI 성능이 떨어지는 현상) 문제도 자연스럽게 줄어듭니다.

 

셋째, 레거시 전환 전략이 현실적입니다.

 

빅뱅 방식으로 전체를 다시 짜는 건 거의 항상 실패한다고 단호하게 말하면서, 스트랭글러 패턴(Strangler Fig)으로 하위 레이어부터 조금씩 분리하는 현실적인 전략을 구체적으로 알려줘요.

 

 

어떤 분께 추천하나요?

 

- 파이썬 개발 경력이 1~3년 이상인 중급 이상의 개발자

- 혼자 짜면 잘 돌아가는데, 팀 프로젝트나 장기 유지보수가 힘든 분

- Flask/FastAPI로 개발 중인데 점점 코드가 복잡해지는 느낌이 드는 분

- 레거시 파이썬 코드를 정리하고 싶은데 어디서 시작해야 할지 모르는 분

- AI 코딩 도구(Claude Code, Cursor 등)를 더 효과적으로 활용하고 싶은 개발자

 

단, 파이썬을 처음 배우는 분이나 OOP가 아직 낯선 분께는 다소 어려울 수 있어요.

어느 정도 Python 객체 지향 프로그래밍에 익숙한 분에게 맞는 책입니다.

 

 

마무리하며...

 

솔직히 말씀드리면, "파이썬은 동적 언어니까 자바식 아키텍처는 어울리지 않아" 라는 편견을 저도 조금 갖고 있었어요.

 

그런데 이 책을 읽으면서 그 생각이 완전히 바뀌었습니다.

 

파이썬의 Protocol, 타입 힌팅, 데이터클래스를 활용하면 클린 아키텍처가 오히려 더 파이썬답게 구현될 수 있다는 걸 직접 코드로 보여주거든요.

 

단순히 "돌아가는 코드"가 아니라, 6개월 뒤, 2년 뒤에도 유지보수하기 쉬운 코드를 짜고 싶은 파이썬 개발자라면 꼭 한 번 읽어볼 만한 책입니다!

 

특히 요즘처럼 AI 코딩 도구가 급속도로 발전하는 시대일수록, 좋은 아키텍처를 갖춘 코드베이스가 더 큰 경쟁력이 된다는 점... 잊지 마세요.

 

 

 

 

#클린아키텍처 #파이썬 #CleanArchitecture #Python #소프트웨어설계 #SOLID원칙 #한빛아카데미 #샘킨 #도서리뷰 #개발자책추천 #백엔드개발 #리팩터링 #레거시코드 #의존성주입 #테스트가능한코드

 

 

 

반응형
TAGS.

Comments