저장소 패턴 소개
-
저장소 패턴은 영속성 저장소를 추상화 한 것이다. 저장소 패턴은 모든 데이터가 메모리상에 존재하는 것 처럼 가정하여 데이터 접근과 관련된 지루한 세부 사항을 감춘다.
-
가장 간단한 저장소에는 메서드가 두 가지 밖에 없다.
add()
는 새 원소를 저장소에 추가하고,get()
은 이전에 추가한 원소를 저장소에서 가져온다. -
도메인 서비스 계층에서 데이터에 접근할 때는 엄격하게 이 두가지 메서드만 사용할 수 있다. 이렇게 단순성을 강제로 유지하면 도메인 모델과 데이터베이스 사이의 결합을 끊을 수 있다.
from collections import abc
import model
class AbstractRepository(abc.ABC):
@abc.abstractmethod
def add(self, batch: model.Batch):
raise NotImplementedError
@abc.abstractmethod
def get(self, reference) -> model.Batch:
raise NotImplementedError
class SqlAlchemyRepository(AbstractRepository):
def __init__(self, session):
self.session = session
def add(self, batch):
self.session.add(batch)
def get(self, reference):
return self.session.query(model.Batch).filter_by(reference=reference).one()
def list(self):
return self.session.query(model.Batch).all()
- 따라서 이런 형태의 코드가 나올 것이다. 스프링에서
JPA
를 사용할 때repository
코드와 매우 닮아 있다.
트레이드오프
-
DDD와 의존성 역전이라는 경로를 택한 이상 저장소 패턴은 이 책에서 나열한 패턴 중에서도 가장 채택하기 쉬운 패턴이다.
-
코드만 고려한다면 저장소 패턴은 단지
SQLAlchemy
추상화 (session.query(Batch)
)를 우리가 직접 설계한 다른 추상화 (batches_repo.get
)로 바꿔치기 한 것 밖에 되지 않는다.
테스트에 사용하는 가짜 저장소를 쉽게 만드는 방법
class FakeRepository(AbstractRepository):
def __init__(self, batches):
self._batches = set(batches)
def add(self, batch):
self._batches.add(batch)
def get(self, reference):
return next(b for b in self._batches if b.reference == reference)
def list(self):
return list(self._batches)
-
이 클래스가
set()
을 감싸는 간단한 래퍼이므로 모든 메서드는 한줄로 끝난다. -
fake_repo = FakeRepository([batch1, batch2, batch3])
-
추상화를 대신하는 가짜 객체를 만드는 것은 설계에 대한 피드백을 얻는 아주 좋은 방법이다.
-
가짜 객체를 만들기 어렵다면 추상화를 너무 복잡하게 설계했기 때문일 것이다.
저장소 패턴 정리
-
ORM에 의존성 역전을 적용하자, 도메인 모델은 인프라에 대해서 걱정할 필요가 없어야 한다. ORM은 모델을 임포트해야 하며 모델이 ORM을 임포트해서는 안된다.
-
저장소 패턴은 영속성 저장소에 대한 단순한 추상화다. 저장소는 컬렉션이 메모리 상에 있는 개체라는 환상을 제공한다. 저장소를 사용하면 핵심 애플리케이션에는 영향을 미치지 않으면서 인프라를 이루는 세부 구조를 변경하거나 목 저장소를 쉽게 작성할 수 있다.
참고 문헌
>> Home