단일 책임 원칙은 SOLID 원칙 중 하나로, 하나의 클래스 또는 모듈은 오직 하나의 책임만 가져야 한다는 원칙입니다. 즉, 특정 클래스나 함수가 하나의 명확한 역할을 수행하고, 변경의 이유가 하나여야 한다는 뜻입니다. 이를 통해 코드는 이해하기 쉽고, 유지보수와 확장이 용이해집니다.
백엔드 코드에 이 원칙을 적용하기 위해서는 다음과 같은 단계를 고려할 수 있습니다.
역할(Role) 구분
책임(Responsibility) 분리
의존성 주입(Dependency Injection)
이것을 FastAPI와 같은 프레임워크에서는 다음과 같은 방식으로 SRP를 적용할 수 있습니다.
라우팅과 비즈니스 로직 분리
데이터베이스 접근 로직 분리
유틸리티 함수와 공통 기능 분리
project/
├── app/
│ ├── main.py # FastAPI 애플리케이션 초기화
│ ├── routes/
│ │ └── user_routes.py # 사용자 관련 API 엔드포인트 정의
│ ├── services/
│ │ └── user_service.py # 사용자 비즈니스 로직
│ ├── repositories/
│ │ └── user_repository.py # 데이터베이스 접근 로직
│ ├── models/
│ │ └── user.py # 사용자 모델 정의
│ ├── utils/
│ │ └── validators.py # 공통 유틸리티(예: 데이터 검증)
models/user.py
- 데이터 모델from pydantic import BaseModel
class User(BaseModel):
id: int
username: str
email: str
is_active: bool
repositories/user_repository.py
- 데이터베이스 접근 로직from typing import List, Optional
from app.models.user import User
class UserRepository:
def __init__(self):
# 임시 데이터베이스로 리스트 사용
self.users = []
def get_user_by_id(self, user_id: int) -> Optional[User]:
return next((user for user in self.users if user.id == user_id), None)
def get_all_users(self) -> List[User]:
return self.users
def create_user(self, user: User) -> User:
self.users.append(user)
return user
services/user_service.py
- 비즈니스 로직from typing import List
from app.models.user import User
from app.repositories.user_repository import UserRepository
class UserService:
def __init__(self, repository: UserRepository):
self.repository = repository
def get_user_details(self, user_id: int) -> User:
user = self.repository.get_user_by_id(user_id)
if not user:
raise ValueError("User not found")
return user
def create_user(self, user_data: User) -> User:
# 추가 비즈니스 로직 (예: 유효성 검사)
if not user_data.email:
raise ValueError("Email is required")
return self.repository.create_user(user_data)
routes/user_routes.py
- 라우팅 정의from fastapi import APIRouter, HTTPException
from app.models.user import User
from app.services.user_service import UserService
from app.repositories.user_repository import UserRepository
router = APIRouter()
repository = UserRepository()
service = UserService(repository)
@router.get("/users/{user_id}")
def get_user(user_id: int):
try:
return service.get_user_details(user_id)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
@router.post("/users")
def create_user(user: User):
try:
return service.create_user(user)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
main.py
- 애플리케이션 초기화from fastapi import FastAPI
from app.routes.user_routes import router as user_router
app = FastAPI()
app.include_router(user_router, prefix="/api")