포스팅에서의 클린아키텍처는 Ports and Adapters 아키텍처, 헥사고날 아키텍처(육각형 아키텍처) 모두 같은 것을 의미한다.
클린 아키텍처는 도메인 중심의 아키텍처에 적합하기 때문에 도메인 엔터티를 만드는 것으로 시작한 후, 해당 도메인 엔터티를 중심으로 유스케이스를 구현한다.
- 엔터티에는 비즈니스 업무 규칙이 존재한다.
유스케이스는 엔티티를 감싸고 있다. 유스케이스는 애플리케이션에 특화된 업무 규칙(비즈니스 규칙)을 표현하며, 엔티티 내부의 핵심 업무 규칙을 호출(도메인에 접근)하고 시스템을 사용하는 흐름을 담는다.
엔티티(고수준영역)은 유스케이스영역(저수준영역)을 알게 해서는 안됨에 주의한다. 엔터티는 간단한 객체여야 하며, 프레임 워크 데이터베이스 또는 기타 복잡한 것에 의존해서는 안되고 유스케이스 객체를 통해서만 조작해야 한다.
* 고수준의 영역: 내부영역으로 비즈니스 계층이 이에 해당한다. 비즈니스로직을 표현한다.
* 저수준의 영역: 외부 영역으로 프리젠테이션 계층, 영속성 계층 등이 이에 해당하며, 인퍼테이스 처리를 담당한다.
즉, 유스케이스는 비즈니스 규칙(business rule) 을 검증할 책임을 갖고 있다. 그리고 도메인 엔터티와 이 책임을 공유한다.
- 비즈니스 규칙을 충족하면, 입력을 기반으로 모델의 상태를 변경한다.
- 도메인 객체의 상태를 바꾸고 영속성 어댑터를 통해 구현된 포트로 이 상태를 전달하여 저장한다.
일반적인 유스케이스의 사용 흐름을 본다면 다음 단계를 따를 것이다.
- 입력을 받는다.
- 비즈니스 규칙을 검증한다.
- 모델 상태를 조작한다.
- 출력을 반환한다.
유스케이스는 도메인 모델의 진입점으로 동작하고, 사용자의 의도만을 표현하면서 이 의도를 실제 작업을 수행하는 체계화된 도메인 엔터티 메서드 호출로 변환한다. 그리고 최종적으로 알맞은 응답을 반환한다.
여기서 주의할 것이, 입력 유효성 검사와, 비즈니스 규칙 검증은 다름에 주의해야한다. 그리고 유스케이스에서는 도메인 로직에만 신경써야하며, 입력 유효성 검증으로 이를 오염시키면 안된다.
입력에 관한 책임: 입력 유효성 검사는 어디에?
입력 유효성 검증의 책임은 애플리케이션 계층에 있다. 일반적으로 요청의 첫 진입점인 웹 계층에서 Early Return 으로 유효성을 검사하는 것이 좋은 패턴이라는 것은 많이들 알고 있는 사실이다. 하지만, 유스케이스에서 필요로 하는 것을 호출자(Caller)가 모두 검증했다고 믿을 수 없다. 또한 유스케이스는 하나 이상의 어댑터에서 호출될 수 있다. 즉, 애플리케이션 계층에서 입력 유효성 검사를 하지 않는다면 각각의 어댑터에서 입력 유효성 검사를 모두 작성해야 한다.
따라서, 입력 유효성의 검증은 애플리케이션계층에서 이뤄지는 것이 적절하다. 그리고 나는 해당 입력 유효성 검사를 입력모델(Input Model;DTO) 에서 진행하였다.
나는 입력모델에서 검증을 진행했다. 각 필드는 final 을 지정하고 일단 생성에 성공하고나면 상태는 유효하며, 이후 잘못된 상태로 변경 될 수 없음을 보장한다.
Command DTO 는 유스케이스 API의 일부분에 해당하며, 애플리케이션의 코어(육각형 아키텍처의 육갹형 내부)에 남아있으면서도 유스케이스 코드를 오염시키지 않을 수 있다.
비즈니스 규칙 검증하기
입력 유효성 검증은 유스케이스 로직의 일부가 아닌 반면, 비즈니스 규칙 검증은 명백한 유스케이스 로직의 일부이다. 그리고 비즈니스 규칙은 애플리케이션의 핵심이기에 적절하게 잘 다뤄야한다.
입력 유효성 검사와, 비즈니스 규칙 검증은 어떤 차이점이 있을까? 비즈니스 규칙을 검증하는 것은 도메인 모델의 현재 상태에 접근해야 한다. 하지만 입력 유효성 검사는 이럴 필요가 없다. 입력 유효성 검사는 @NotNull 어노테이션을 사용하는것처럼 선언적으로 구현 할 수 있지만, 비즈니스 규칙을 검증하는 일은 맥락이 더 필요하다.
- 입력 유효성 검사: 구문상의(syntactial) 유효성을 검증하는 것 ex) 송금되는 금액은 0보다 커야한다.
- 비즈니스 규칙 검사: 유스케이스의 맥락 속에서 의미적인(semantical) 유효성을 검증하는 것 ex) 출금 계좌는 초과 출금되어서는 안 된다.
비즈니스 에 관한 책임: 비즈니스 규칙 검증은 어디에?
비즈니스 규칙은 도메인 엔터티에서 진행하거나, 유스케이스에서 도메인 엔터티를 사용하기 전에 검증하는 것이 바람직하다. 유효성을 검증하는 코드를 호출하고, 유효성이 검증이 실패할 경우에는 유효성 검증 전용 예외를 발생시켜야 한다.
매우 복잡한 비즈니스 규칙의 경우 먼저 데이터베이스에서 도메인 모델을 불러와 상태를 검증해야할 수도 있다. 만약 도메인 모델을 불러와야 한다면, 도메인 엔터티 내에 비즈니스 규칙을 구현하는것이 좋다.
유스케이스의 출력 모델
유스케이스가 할일을 모두 하고나면, 알맞은 응답을 반환해야한다. 그리고 응답은 각 유스케이스에 맞기 구체적이어야하며, 호출자에게 꼭 필요한 데이터만 들고 있어야 한다. 반환하는 데이터에 대한 의심이 든다면, 가능한 적게 반환하도록하자. 그리고 유스케이스를 가능한 구체적으로 유지하기 위해서 계속해서 질문하도록하자!
가장 중요한 것은 유스케이스들 간에 같은 출력 모델을 공유하지 않는 것이 중요하다. 이렇게 된다면, 유스케이스들 끼리 강하게 결합되기 때문이다.(유스케이스를 나눈의미가 사라진다.) 그리고 장기적으로 봤을 때, 공유 모델은 점점 커져 괴물이 될 수 있다. 따라서, 단일 책임 원칙(변경할 이유는 한가지)를 적용하여 모델을 분리하여 유스케이스간의 결합을 줄이도록 한다.
단, 유스케이스들이 기능적으로 묶여있을 때에는 입출력 모델을 공유하는 것이 유효하다. 즉 특정 세부사항을 변경할 경우 공유하는 유스케이스에 모두 영향을 주고싶은 경우 공유 모델을 사용해도 좋다.
정리
유스케이스는 애플리케이션에 특화된 업무 규칙(비즈니스 규칙)을 표현하며, 엔티티 내부의 핵심 업무 규칙을 호출(도메인에 접근)하고 시스템을 사용하는 흐름을 담는다. 따라서 각 유스케이스마다 별도의 모델을 만들어야하고, 이 모델과 엔티티를 매핑해야한다.
유스케이스 별 모델을 만드는 것은 유스케이스를 보다 명확하게 하고, 장기적으로 유지보수하기도 쉬워지며, 여러명의 개발자가 다른 유스케이스에 영향을 주지 않고 여러개의 유스케이스를 동시 작업할 수 있게 해준다.
지속가능한 코드를 위한 유스케이스는 꼼꼼한 입력 유효성을 거치고, 유스케이스별 입출력 모델을 갖는 것이 중요하다.
참고 자료
만들면서 배우는 클린 아키텍처 - YES24
우리 모두는 낮은 개발 비용으로 유연하고 적응이 쉬운 소프트웨어 아키텍처를 구축하고자 한다. 그러나 불합리한 기한과 쉬워보이는 지름길은 이러한 아키텍처를 구축하는 것을 매우 어렵게
www.yes24.com
GitHub - KEEMSY/shoes-ordering-system: shoes-ordering-system
shoes-ordering-system. Contribute to KEEMSY/shoes-ordering-system development by creating an account on GitHub.
github.com
'개인공부 > 아키텍처' 카테고리의 다른 글
[ 아키텍처 ] 로드밸런싱 패턴 (1) | 2023.10.29 |
---|---|
[ 개인 공부 ] 코드의 디커플링에 관하여 (1) | 2023.10.24 |
[ 아키텍처 ] 클린아키텍처의 구성과 패키지 구조 (0) | 2023.07.24 |
[아키텍처] 클린아키텍처(Ports and Adapters): 왜 클린 아키텍처를 공부하게 되었는가? (0) | 2023.07.20 |
[아키텍처] 클린아키텍처(Ports and Adapters) (0) | 2023.07.20 |