저장소 패턴이 영속적 저장소 개념에 대한 추상화라면 작업 단위 패턴은 원자적 연산이라는 개념에 대한 추상화.
서비스 계층에서 직접 세션과, 저장소를 불러서 작업하지 않게 해 줌으로써, 서비스 계층과 각 계층을 분리시켜줌.
책에서는 컨텐스트 매니저를 통해 구현했다.
근데 이게 뒤에서도 나오는데 기존에 세션이 하는 걸 한번 wrapping 한 느낌이다. 왜 그런지 밑에서 설명하고 그 차이와 트레이드오프를 말해준다.
밑에 예제만 봐도 알겠지만 서비스 로직를 트랜잭션 처리했다. 그 과정에서 uow는 필요한 모든 걸 갖고 있고 외부에서 호출하는 caller는 그냥 얘만 인자로 넘기면서 서비스를 호출하면 된다.
책 예제
class SqlAlchemyUnitOfWork(AbstractUnitOfWork):
def __init__(self, session_factory=DEFAULT_SESSION_FACTORY):
self.session_factory = session_factory
def __enter__(self):
self.session = self.session_factory() # type: Session
self.batches = repository.SqlAlchemyRepository(self.session)
return super().__enter__()
def __exit__(self, *args):
super().__exit__(*args)
self.session.close()
def commit(self):
self.session.commit()
def rollback(self):
self.session.rollback()
...
def reallocate(line: Orderline, uow:AbstractUnitOfWork) -> str:
with uow:
batch = uow.batches.get(sku= line.sku)
if batch is None:
raise InvalidSku(f'Invalid sku {line.sku}')
batch.deallocate(line)
allocate(line)
uow.commit()
해당 패턴에서 느낀 개인 프로젝트에 대한 생각
이 파트 중반에 보면 명시적 커밋과 암시적 커밋에 대한 내용이 잠깐 나오는데, 보면서 갑자기 생각이 든 건 내가 혼자 했던 프로젝트가 생각났다.
Meet-up-Spot에서는 애초에 도매인 모델 형식으로 설계할 생각도 못해서 이미 너무 다른 구조의 프로젝트가 되었지만, 내 프로젝트의 CRUD계층과 저장소 패턴부터 지금까지의 작업 단위 패턴을 보니까 CRUD계층이 너무 애매한 거 같다. 무엇보다 crud에 커밋을 묶어서 처리하는 게 여러 crud연산을 하나의 트랜잭션으로 묶는 것이 힘들다. 고쳐야 하는 게 맞는데 딱히 복잡한 로직이 없어서 그냥 두고 있긴 하다.
이 작업단위 패턴을 한다면 암시적으로 커밋을 해도 내부에 Uow에 필요한 repo들을 사용해 여러 저장소를 사용하는 트랜잭션이 가능할 것이다.
이걸 보면서 내가 만약 바꾼다면 그냥 crud에서 커밋을 뺄지 아니면 이상태에서 한 번 더 작업단위계층은 아니더라도 계층을 쌓아서 처리할지 고민을 해봤다. 기본 코드를 고치는 게 맞는 거 같은데, 왜냐면 계속 계층만 추가하면 더 이상해질 거 같다. 아무튼 첨부터 구조를 잘 짜는 게 정말 중요한 거 같다.
자신이 만든 것이 아니면 모킹하지 말라
한마디로 자신이 만든게 아니라 세션 같은 복잡한 인터페이스랑 결합하게 되면 테스트할 때도 분명히 걸리는 부분이 생김 그니까 한 번 더 추상화해서 사용하자는 거임. 나도 그래서 테스트할 때 불편한 것도 있었음. 위 문장은 와닿았음
여기서도 UoW 계층이 생기면서 기존에 test_orm 같은 모듈은 제거해도 된다. 어차피 test_repository에서 테스트가 되기때문에 장기적으로 필요 없기 때문이다.
나도 이번 내용을 보면서 느꼈지만, 실제로 SQLAlchemy는 세션 객체를 UoW패턴을 사용해서 구현했다고 한다. 그렇다면 굳이 한번더 추상화를 할 필요가 있을까 하는 생각이 든다. 이것 역시 트레이드오프를 잘 따져야겠다.
장점 | 단점 |
원자적 연산을 표현하는 좋은 추상화를 만듬, 컨텍스트 관리자를 사용하면 원자적으로 한 그룹으로 묶어야하는 코드 블록을 시각적으로 쉽게 알아 볼수 있음. 안전하게 트랜잭션 처리를 할 수 있음 또한 원자성은 뒤에서 이벤트나 메시지 버스를 사용할 때도 도움이 된다함 |
사용 중인 ORM이 이미 원자성을 중심으로 추상화를 제공하고 있음. 프로젝트에 사용중인 SQLAlchemy도 컨텐스트 관리자도 제공함. 롤백, 멀티쓰레딩 내포된 트랜잭션 등을 처리하는 코드를 만들때는 매우 신중하게 해야 된다고함. |
정리하면
위에서도 잠깐 언급했지만 세션 API는 풍부한 기능과 도메인에서 불필요한 연산을 제공하기 때문에, UoW는 세션을 단순화 시켜서 필요한 부분만 사용하게 해 준다.
참고 및 출처: <파이썬으로 살펴보는 아키텍처 패턴: TDD, DDD, EDM 적용하기)> (해리 퍼시벌, 밥 그레고리 지음, 오현석 옮김, 한빛미디어 , 2021)
'Book' 카테고리의 다른 글
오브젝트. Chapter 01 객체,설계 (0) | 2023.10.18 |
---|---|
애그리게이트와 일관성 경계 (0) | 2023.10.08 |
MySQL 퍼포먼스 최적화 (1~3장) (0) | 2023.08.17 |
실용주의 프로그래머(7장 ~마지막) (0) | 2023.07.31 |
실용주의 프로그래머(5~6장) (0) | 2023.07.29 |