

출처 : 도메인 주도 개발 시작하기
우리가 주로 다루고 있는 이 도메인은, 도메인과 사용자를 연결해 줄 표현, 응용 영역이 필요하게 된다.
단순 도메인만 있다고, 끝나는 것이 아니란 말이다.

출처 : 도메인 주도 개발 시작하기
사실 나를 포함한 많은 사람들은 Controller->Service에 요청을 보낼 때, 받은 DTO를 그대로 넘기는 경우가 많다.
예제와 같이 HttpServletRequest가 그대로 넘어온 경우에는 이가 당연하지만, 그렇지 않은 경우에도 여러 요청에 대해 동일한 Service로 매핑해주기 위해서 가끔 이렇게 처리해야 하는 경우가 있다.
응용 서비스는 주로 도메인 객체 간의 흐름을 제어하기 때문에 굉장히 단순한 형태를 가지게 된다.
확실히 애그리거트들을 생성하고, 저장하거나 혹은 사용하는 종류의 연산만을 수행해준다.
응용 서비스가 만일 복잡해진다면, 그것은 도메인 로직을 포함시킬 확률이 굉장히 높다. 이는, 코드 중복, 로직 분산 등 코드품질에 안좋은 영향을 끼칠 수 있기 때문에, 수정하는 것이 좋다.
또한 트랜잭션을 사용할 수도 있고, 이 이외의 접근 제어, 이벤트 처리가 있다.
코드 중복을 막기 위해, 응용 서비스 계층에 도메인 로직을 넣지 않는 것은 굉장히 중요하다.
이를 최대한 경계하고, 소프트웨어의 품질을 높일 수 있도록 하자.
응용 서비스 자체는 복잡한 로직을 수행하지 않는다. 그렇기 때문에 응용 서비스의 구현은 어렵지 않다.
하나의 응용 서비스에 모든 기능을 작성하게 되면 굉장히 커질 수 있다. (하지만, 응용서비스의 여러 메서드를 구현하면서 중복되는 부분을 prviate 메서드로 빼, 획기적으로 중복 코드를 줄일 수 있다는 장점이 존재한다.)
그렇기 때문에, 구분되는 기능별로 응용 서비스 클래스를 따로 구현하는 방법을 진행할 수 있다. 이를 활용하게 되면 파사드 디자인 패턴을 활용하게 되는 것이다.
이렇게 되면, 타 개발자가 코드를 보고 이해할 때 굉장히 도움을 줄 수 있다. (중복된 코드는 다량 발생하겠지만, 그래도 이해하기가 훨씬 쉽다.)
중복 코드가 발생했을 때, 이제 또 사용할 수 있는 방식은, Helper 객체를 두는 것이다. Helper 객체에는 중복되는 메서드를 정리해놓고, 서비스에서 이를 사용하는 것이다.
이렇게 하게 되면, 중복 코드 문제도 해결하고, 타 개발자의 이해도 도울 수 있는 것이다.
이번 프로젝트에서도 적용해봐야겠다.
과연, 응용 서비스에 대한 인터페이스들을 하나하나 선언할 필요가 있을까? 보통 OOP의 특징인 다형성을 이용하기 위해 extends,implements를 많이 활용하지만, 그렇지 않다면 굳이 사용할 필요도 없고, Test시에도 Stub을 사용하는 것이 아니라, Mockito와 같은 라이브러리를 사용하여 이를 해결할 수 있게 된다.
그래서 필자의 전체적인 의견은 굳이 다형성을 활용하기 위함이 아니라면 분리하지 않는 것이 좋다는 것이다.
인터페이스를 선언하는 것이 조금 귀찮긴하다.
계층간의 데이터가 넘나들 때, 파라미터가 두 개 이상이라면 dto를 사용하는 것도 좋은 판단이다.
또한, 값을 처리하고 나서, ID혹은 애그리거트 그 자체를 반환해서, 결과를 바로 사용자에게 보여줄 수도 있다.
하지만, 애그리거트 자체를 반환하는 행위는, 여러 곳에서 도메인 로직이 실행될 수 있는 환경을 만들어 응집도를 될 뿐만 아니라, API에 대한 응답으로 필요한 정보만 보낸다고 가정했을 때, 변경 사항에 굉장히 취약한 모습을 보여줄 수 있다.
애그리거트를 그대로 반환하면, 응집도가 깨졌던 것처럼, 표현 영역의 일을 응용, 도메인 계층까지 내리게 되면 이또한 응집도가 깨지는 일을 발생시킨다.
또한, 표현계층에 의존하는 값들로 인해서 테스트도 굉장히 어려워지게된다.
책에서, 트랜잭션에 대한 특징 중 하나인 Atomic한 성질을 예시로 들며, 트랜잭션을 활용해야 한다고 말하고있고, 이를 쉽게 활용하기 위해 @Transactional 어노테이션을 사용하라 말하고 있다.
표현 영역의 책임은 다음과 같다.

출처 : 도메인 주도 개발 시작하기
웹을 활용하여 게시글 쓰기를 진행한다고 하면 다음과 같이 진행될 것이다.
읔 근데, 예시로 보여주시는 코드들이 다 너무 더럽다.
try, catch, ServletRequest에서 그대로 값을 꺼내는 모습까지, 옛날에 처리하던 방식을 그대로 자료에 활용하신 것 같다.
사용자가 폼에 정보를 입력한다고 가정해보자.
이 때, 사용자가 잘못된 값을 입력하고 있다고 가정했을 때, 가장 좋은 사용자 경험을 제공할 수 있는 방법은 무엇일까?
바로, 그냥 바로 아래에 이거 값 잘못됐다~ 이런 식으로 표현해주는 것이다.
만일 그렇지 않고, submit했을 때, 예외를 감지하는 형식으로 진행한다고 하면, 어떠한 예외들이 발생했는지 알고 싶을 것이다. 하지만, 일반적인 방식으로 처리하게 되면, 가장 먼저 마주친 예외를 반환하고 끝나게 될 것이다.
이를 방지하기 위해서, ValidationError를 활용할 수 있다. 개인적으로 좋은 방법으로 보인다.
뭐 또, Validator 인터페이스를 구현해 처리하는 방법도 있다고 한다.
항상 고민하는 부분인, 그래서 검증의 책임을 어떻게 나눌 것인가라는 부분이 있다.
이는 다음과 같이 정의할 수 있다.
그러니, 값으로만 확인할 수 있는 부분은 표현 영역에서 처리해주면 좋고, 응용서비스는 정말 인프라 딴까지 접근해 확인할 수 있는 부분을 검증하는 것이 좋다는 것이다.
근데 필자는 이렇게 말한다.
요즘은 가능하면 응용 서비스에서 필수 값 검증과 논리적인 검증을 모두 하는 것이 좋다고, 나도 이렇게 생각한다. 이래야 응용 서비스가 단단해지고, 소프트웨어의 품질을 높일 수 있다고 생각한다.
스프링 시큐리티는
인프라를 제외한 모든 계층에서 권한 검사를 수행할 수 있다.
각각의 영역에서 할 수 있는 인증들은 어느정도 정해져 있다.

출처 : 도메인 주도 개발 시작하기
이런 접근을 하기에 좋은 위치는 Servlet Filter이다.
쨌든, 이렇게 URL등으로 접근 제어를 할 수 있는 부분들은 다음과 같이 처리할 수 있겠지만, 그렇지 않다면 AOP를 활용한 스프링 시큐리티의 기능을 활용하면 된다.

출처 : 도메인 주도 개발 시작하기
다음과 같이, 어노테이션으로 어떠한 Role을 가지고 있는지 확인할 수 있다.
하지만, 여기서 더 들어가서 게시글 삭제는 본인 혹은 어드민만 할 수 있다라는 등의 도메인 규칙이 존재한다면, 이는 꼭 애그리거트를 확인해야지 가능한 동작이라는 것을 알 수 있다.
이러한 부분들은 도메인에 간단하게 구현할 수 있지만, 시큐리티를 확장하여 처리할 수도 있다고 한다.
하지만, 이는 시큐리티에 대한 이해도가 높아야 한다고 한다.
그러니, 이 정도까지 시큐리티를 확장하여 사용하는 것은 자제해야겠다.

출처 : 도메인 주도 개발 시작하기
또한, 다음과 같이 굉장히 간단한 로직을 가진 조회 요청이라면 응용서비스 계층을 거치지 않을 수도 있다.
항상 그렇듯 선택의 차이인 것 같다라는 생각을 많이한다.
이번 장은 확실히 이전 장들보다 재미있고, 배울 점도 조금은 있었던 것 같다.