
파이썬으로 새 프로젝트를 시작하면 구조는 단순하다. 하지만 기능이 늘고 코드가 쌓일수록 구조는 빠르게 복잡해진다.
“이 코드는 어디에 둬야 하지?”
“이 함수 하나 고쳤는데 왜 다른 곳이 깨질까?”
이런 문제의 원인은 대부분 설계 기준 없이 코드가 쌓였기 때문이다. 이 글에서는 파이썬 프로젝트를 더 읽기 쉽고, 고치기 쉽고, 테스트하기 쉽게 만드는 다섯 가지 설계 원칙을 정리한다.
원칙 1: 기술이 아니라 ‘업무’ 기준으로 코드를 묶는다
많은 프로젝트가 이렇게 시작한다.
utils/
services/
helpers/
models/
처음에는 편하다. 하지만 프로젝트가 커지면 “이 기능이 어디에 있는지” 찾는 데 시간이 더 든다.
해결책: 도메인(업무) 기준 구조
쇼핑몰이라면 구조는 이렇게 나뉜다.
users/
products/
orders/
payments/
이 구조의 핵심은 단순하다.
“같은 일을 하는 코드는 같은 폴더에 둔다.”
예를 들어 users/ 안에는 다음이 함께 있다.
- 사용자 모델
- 사용자 관련 규칙
- 사용자 저장/조회 코드
덕분에 기능 수정 시 한 폴더만 보면 된다.
원칙 2: 비즈니스 규칙은 인프라를 몰라야 한다
비즈니스 규칙은 “무엇이 올바른가”를 판단하는 코드다.
잘 설계된 함수의 책임
def create_user(data: dict) -> User:
# 유효성 검사
# 기본값 설정
# 사용자 객체 생성
return user
이 함수는 사용자를 어떻게 정의할지만 안다. 데이터베이스, 이메일, 메시지 큐는 모른다.
잘못된 예
def create_user(data: dict) -> User:
db.session.add(user)
db.session.commit()
send_email(user.email)
이 함수는 너무 많은 것을 안다.
- DB 기술
- 트랜잭션 방식
- 이메일 시스템
올바른 조립 방식 (유스케이스)
user = user_service.create_user(data)
user_repo.save(user)
email_service.send_welcome(user)
이렇게 하면 기술이 바뀌어도 비즈니스 규칙은 그대로 유지된다.
원칙 3: 코드의 역할을 명확히 구분한다
services.py 하나에 모든 로직을 넣으면 책임이 섞이고 테스트가 어려워진다.
핵심 역할 3가지
1️⃣ 도메인 서비스
역할
- 순수한 비즈니스 규칙
- 계산, 검증, 판단만 수행
특징
- DB, 네트워크, 파일 시스템을 모름
- 테스트가 가장 쉬움
def can_upgrade_plan(user, plan):
return user.level >= plan.required_level
2️⃣ 레포지토리 (Repository)
역할
- 데이터를 저장하고 불러옴
- DB 기술을 감춤
class UserRepository:
def save(self, user): ...
def get_by_email(self, email): ...
도메인 서비스는 “어디에 저장되는지”를 신경 쓰지 않는다.
3️⃣ 애플리케이션 서비스
역할
- 하나의 유스케이스를 완성
- 여러 컴포넌트를 조합
def register_user(data):
user = create_user(data)
user_repo.save(user)
email_service.send_welcome(user)
역할과 의존성 방향

의존성은 항상 위에서 아래로만 흐른다.
원칙 4: 순환 참조는 설계가 깨졌다는 신호다
다음 구조를 상상해보자.
users → payments
payments → users
이 상태에서는:
- 하나를 고치면 다른 쪽이 깨짐
- import 에러 발생
- 테스트가 어려워짐
해결 전략
- 공통 규칙을 상위 레이어로 이동
- 의존성 방향을 단방향으로 재설계
payments → users
users ✕ payments
순환 참조는 “임시 해결”의 대상이 아니라 “구조를 다시 보라”는 경고다.
원칙 5: 표준 구조는 목표가 아니라 시작점이다
많은 프로젝트가 이렇게 시작한다.
src/
project/
tests/
이 구조는 나쁘지 않다. 하지만 구조만 있고 원칙이 없으면 의미가 없다.
좋은 구조는 다음을 만족한다.
- 업무 기준으로 나뉘어 있고
- 비즈니스와 인프라가 분리되어 있으며
- 의존성이 단방향이고
- 테스트가 쉽다
예제: 회원가입 유스케이스 흐름

이 구조의 장점은 명확하다.
- 도메인 서비스는 단위 테스트 가능
- DB 없이도 비즈니스 규칙 검증 가능
- 인프라 교체 비용이 낮음
마무리: 설계는 복잡함을 줄이기 위한 도구다
다섯 가지 원칙은 서로 연결되어 있다.
- 업무 기준으로 구조를 잡고
- 비즈니스와 인프라를 분리하고
- 역할을 명확히 나누며
- 의존성을 단순하게 유지하고
- 구조를 출발점으로 삼는다
이 원칙을 적용하면 프로젝트는:
- 테스트하기 쉬워지고
- 리팩터링이 덜 무서워지며
- 시간이 지나도 유지보수가 가능해진다
완벽하게 시작할 필요는 없다. 하나의 원칙만 의식하는 것이 설계의 출발점이다.
'잡(job)기술 > 파이썬 공부' 카테고리의 다른 글
| 이제야 알게 된 Python else의 힘 (1) | 2026.01.12 |
|---|---|
| 내 코드가 외부 API와 통신한 척하게 만드는 방법 - 파이썬 Mocking 핵심 개념 2가지 (3) | 2026.01.02 |
| 당신의 테스트는 안녕한가요? Pytest로 데이터베이스를 제대로 검증하는 3가지 핵심 원리 (0) | 2026.01.02 |
| 파이썬 sqlite3, 혹시 이렇게 쓰고 있는가? - 나의 코드를 바꿔놓을 4가지 핵심 팁 (0) | 2025.12.31 |
| Poetry로 Python 프로젝트 환경 만들기 (2) | 2025.06.24 |