결정-0057: out port를 상대 컨텍스트가 구현할 수 있다
상태
Accepted
맥락
두 컨텍스트가 서로를 필요로 하는 상황이 있습니다. A 가 B 의 데이터를 읽어야 하고, 동시에 B 가 자기 불변식을 지키려면 A 가 가진 정보를 확인해야 하는 경우입니다.
각자 상대의 계약을 호출하면 코드 의존이 순환합니다. 계약을 경유하더라도 순환은 순환입니다. 순환에 속한 패키지는 하나의 변경이 나머지에 영향을 미치고 따로 떼어 테스트할 수 없습니다.
결정
out port 의 구현을 상대 컨텍스트가 담당할 수 있습니다. 이 경우에만 포트의 선언 위치를 application 에서 contract 로 올립니다.
선언 위치를 올리는 이유는 구현자가 상대 컨텍스트이기 때문입니다. 상대가 그 인터페이스를 참조해야 하는데, 경계 규칙상 참조 가능한 위치는 contract 뿐입니다.
인터페이스 구현도 참조에 해당하므로, 구현체를 소비자 쪽에 두면 의존 방향이 소비자에서 제공자로 흐릅니다. 결과적으로 제공자는 어떤 컨텍스트도 참조하지 않게 됩니다.
적용 조건 — 셋을 모두 충족할 때만 씁니다
| 조건 | 필요한 이유 |
|---|---|
| 제공자가 자기 불변식 검증을 위해 그 정보를 요구한다 | 편의를 위한 조회라면 소비자가 자체 처리하면 됩니다 |
| 그 정보의 소유자가 소비자 쪽이다 | 소유자가 제공자면 스스로 판단할 수 있으므로 포트가 필요 없습니다 |
| 호출 방향이 이미 소비자에서 제공자로 있다 | 없던 방향을 새로 만드는 것이라면 순환을 옮긴 것에 불과합니다 |
셋 중 하나라도 어긋나면 이 수단을 쓰지 않습니다. 남용하면 계약 패키지가 두 성격의 인터페이스로 뒤섞여 어느 쪽이 제공이고 어느 쪽이 요구인지 읽어야 알게 됩니다.
검토한 대안
양쪽이 서로의 계약을 호출한다
| 구분 | 내용 |
|---|---|
| 장점 | 각자 필요한 것을 직접 가져오므로 구조가 직관적입니다 |
| 단점 | 코드 의존이 순환합니다. 두 컨텍스트를 따로 테스트할 수 없고 함께 변경됩니다 |
| 기각 사유 | 경계를 나눈 이유가 사라집니다 |
컨텍스트를 합친다
| 구분 | 내용 |
|---|---|
| 장점 | 순환이 원천적으로 사라집니다 |
| 단점 | 용어 체계가 다른 둘이 한 컨텍스트가 됩니다 |
| 기각 사유 | 기각이 아니라 먼저 검토할 선택지입니다. 컨텍스트 협력 3절의 세 질문에서 경계가 실재하지 않는 것으로 판정되면 합치는 편이 맞습니다. 본 ADR 은 경계가 실재한다고 판정된 뒤의 수단입니다 |
결과
컴파일 의존이 단방향으로 수렴합니다. 제공자 컨텍스트를 다른 컨텍스트 없이 빌드하고 테스트할 수 있습니다.
감수하는 것은 계약 패키지에 성격이 다른 두 인터페이스가 공존한다는 점입니다. 제공하는 것과 요구하는 것을 이름이나 하위 패키지로 구분하지 않으면 읽는 사람이 매번 구현체를 찾아야 합니다. 그래서 적용 조건을 셋으로 좁혀 개수 자체가 늘지 않게 했습니다.