5장 웹 어댑터 구현하기
웹 어댑터는 외부로부터 요청을 받아 애플리케이션 코어에게 무슨 일을 해야 할지 알려줍니다. 구체적으로 말하자면 포트를 통해서 서비스에게 전달합니다.
웹 어댑터는 일반적으로 다음과 같은 단계를 따릅니다.
- HTTP 요청을 자바 객체로 매핑
- 권한 검사
- 입력 유효성 검증
- 입력을 유스케이스의 입력 모델로 매핑
- 유스케이스 호출
- 유스케이스의 출력을 HTTP로 매핑
- HTTP 응답을 반환
먼저 웹 어댑터는 외부로부터 HTTP 요청을 받습니다. URL, 경로, HTTP 메서드, 콘텐츠 타입과 같은 특정 기준을 만족하는 HTTP 요청을 수신하고 요청의 파라미터나 콘텐츠를 웹 어댑터 입력 모델로 매핑합니다.
그리고 웹 어댑터는 인증과 권한 부여를 수행하고, 입력 유효성 검증을 통해 웹 어댑터 입력 모델을 유스케이스 입력 모델로 매핑할 수 있는지 확인합니다. 이 과정에서 문제가 생기면 예외를 던지고, 웹 어댑터는 에러를 호출자에게 보여줄 메시지로 변환해 돌려줍니다.
웹 어댑터 입력 모델이 성공적으로 유스케이스의 입력 모델로 매핑되면, 유스케이스를 호출합니다. 이때 유스케이스를 바로 호출하는 것이 아니라 포트를 통해서 호출합니다. 포트를 통하지 않고 직접 호출하면 계층간의 접점이 불분명해집니다. 포트를 통해서 호출하면 외부와 어떤 통신이 일어나고 있는지 정확하게 알 수 있어서 유지보수하는데 도움이 됩니다.
유스케이스 출력을 바로 호출자에게 줄 수도 있지만 HTTP 응답 출력 모델로 변환해야 합니다. 그 이유는 이 유스케이스를 호출하는 어댑터 간의 결합도가 증가해 유지보수하기 어렵게 만들고, 유스케이스에서 HTTP 응답을 위한 데이터를 추가하고 싶은 유혹이 생기기 때문입니다.
웹 어댑터의 책임이 많긴 하지만 이 책임들은 애플리케이션 계층이 신경 써야 할 것들이 아닙니다. HTTP와 관련된 것들은 애플리케이션 계층에 침투해서는 안 됩니다. 애플리케이션 계층이 바깥 계층에서 HTTP를 다루고 있다는 것을 알게 되면 HTTP를 사용하는 어댑터만을 위한 도메인 로직을 만들게 되어 다양한 선택지를 잃게 되고, 도메인 로직이 오염됩니다. 이런 경계를 자연스럽게 유지하기 위해서는 웹 계층부터 개발을 시작하는 대신 애플리케이션 계층부터 개발하기 시작해야 합니다.
유지보수 가능한 웹 어댑터를 만들려면 어떻게 해야할까?
유스케이스 입력 모델에서 살펴봤던 것처럼 웹 어댑터 입력 모델 또한 다른 어댑터끼리 공유할 경우 어댑터 간의 결합도가 증가하게 됩니다. 예를 들어서 게시글 생성을 위한 데이터와 게시글 수정을 위한 데이터는 데이터가 거의 유사합니다. 그래서 같이 사용하고 싶은 유혹을 느낄 수 있습니다. 하지만 제목을 수정할 수 없다는 제약이 생긴다거나 할 때 웹 어댑터 입력 모델을 공유하고 있으면 필요 없는 데이터를 가지고 있어서 혼란을 줄 수 있습니다.
한 도메인 모델에 관한 기능들을 위한 웹 어댑터에서 처리하는 경우가 일반적입니다. 하지만 이렇게 되면 거대한 클래스가 되어 기능이 어디에 있는지 찾기 힘들고 협업할 때 충돌 위험이 증가합니다. 따라서 웹 어댑터에도 단일 책임 원칙을 적용하여 작게 세분화하는 것이 좋습니다.
따라서 각각의 웹 어댑터가 가능한 좁고, 가능한 적게 공유하도록 해야 합니다.