https://enterprisecraftsmanship.com/posts/what-is-domain-logic/
해당 포스트는 위 아티클을 읽고 정리한 내용이다.
어떤 하나의 소프트웨어 어플리케이션이 있을 때 크게 Problem space와 Solution space로 나누어 볼 수 있다.
Problem Space / Solution Space
Problem Space
The problem space is usually represented with such terms as Domain, Problem Domain, and Core Domain. They all stand for the actual problem your software is going to solve, the purpose it is being built for
Problem space에 해당하는 것은 개발자가 해결해야 하는, 즉 프로젝트의 목적을 구성하는 내용들이다.
예를 들어 유튜브라면 동영상 업로드, 댓글 작성, 인기 있는 동영상 보여주기 등등의 기능들이다.
이 내용을 Domain, Problem Domain, Core Domain 등으로 표현한다.
Solution Space
The solution space includes the terms Business Logic, Business Rules, Domain Logic, and Domain Knowledge. They represent a solution for the problem domain you have at hand
그리고 Problem들을 해결하기 위한, Domain을 구현하기 위한 내용들이 Soluion Space에 해당한다. 기능을 구현하기 위해 작성된 실질적인 코드들이다.
이를 Business Logic, Domain Logic 등등으로 표현한다. 여기서 'Domain Logic'이 등장한다.
도메인 로직(=비즈니스 로직)은 즉, 프로젝트가 요구하는 기능을 구현하기 위한 모든 것들을 이야기 한다.
Domain Logic : 도메인 로직
하나의 소프트웨어 어플리케이션을 구성하는 코드들이 모두 도메인 로직으로만 구성되어 있을 수는 없다.
실질적으로 '사용자가 동영상을 업로드할 수 있게 한다'는 도메인 하나에도 다른 서버와 연결하는 코드, 데이터베이스와 연결하는 코드, 사용자에게 알림을 보내는 코드 등등이 부가적으로 필요하게 됨을 알 수 있다. 즉 이 도메인 하나에 국한된 코드가 아니라, 구현을 위해 전반적으로 필요한 로직이 추가되게 된다.
도메인 로직을 이러한 다른 로직(특히 애플리케이션, 인프라스트럭처, UI 로직)과 분리하여 작성하는 것은 여러 이유로 중요하다.
With such a separation, you can significantly reduce the amount of cognitive load needed to reason about the domain as you are able to focus on it without paying attention to other details, such as persistence or UI concerns.
- 도메인 로직을 분리하면 비즈니스 규칙과 애플리케이션의 핵심 기능이 명확하게 구분된다. 이를 통해 코드를 쉽게 이해하고 유지보수할 수 있으며, 코드 변경이 필요할 때도 특정 도메인 로직만 수정하면 되므로 코드의 변경 범위가 제한된다.
- 도메인 로직을 별도로 분리하면 다른 UI나 인프라 요소에 영향을 받지 않고 순수하게 비즈니스 규칙만을 테스트할 수 있다. 독립적으로 테스트할 수 있는 코드가 되므로 단위 테스트와 유지보수가 훨씬 용이해진다.
그렇다면 무엇이 도메인 로직이고, 무엇이 다른 서비스 로직인지 어떻게 구분할까?
To do that, you need to look at whether or not the code makes decisions that have a business meaning. That is what differentiates domain logic. Your domain model is responsible for generating business-critical decisions while all other parts of your code base just interpret those decisions or provide input needed to make them.
해당 코드가 비즈니스에 의미가 있는 결정을 내리는지 여부를 확인하면 된다.
도메인 로직은 해당 비즈니스, 도메인에 중요한 결정을 생성하는 역할을 한다. 이 결정을 내리는 데 필요한 input들을 제공하거나 해석하는 것들은 모두 어플리케이션 서비스 로직에 해당한다.
이렇게만 얘기하니 뭐가 뭔지 잘 이해가 안 간다. 다음 내용을 보자.
도메인 로직 / 어플리케이션 서비스 로직
다음은 '사용자가 은행 계좌에서 돈을 출금한다'는 도메인을 구현하기 위한 코드이다.
private void TakeMoney(decimal amount) { string error = _atm.CanTakeMoney(amount); // 해당 금액 만큼 돈이 있는 지 확인 if (error != string.Empty) { NotifyClient(error); // 돈이 부족하면 사용자에게 Notify return ; } decimal amountWithCommission = _atm.CaluculateAmountWithCommission(amount); // 수수료 계산 _paymentGateway.ChargePayment(amountWithCommission); // 수수료 청구 _atm.TakeMoney(amount); // 요청 금액 차감 _repository.Save(_atm); // 데이터베이스에 저장 NotifyClient("You have taken " + amount.ToString("C2")); // 출금 완료 Notify }
이 코드는 어플리케이션 서비스 레이어의 코드이다.
'Atm' domain class에 다음에 해당하는 로직들이 구현되어 있다.
1. 원하는 금액 만큼 있는가? 확인
2. 수수료 계산
3. 실제 금액 차감
위 로직들은 모두 '도메인 로직', 실제 비즈니스에 의미가 있는 결정들이다. 그리고 이에 해당하는 코드들은 전부 Atm class에 구현되어 있으며 현재 코드에서는 단순히 해당 로직을 가져와 사용하기만 한다.
application service는 이 결정들을 받아 오는 코드들을 구성하고 핵심 로직 이외의 다른 부수적인 로직들(사용자에게 알리기, 영속성을 위해 DB에 저장)을 수행하고 있다.
아래는 또 다른 어플리케이션 서비스 레이어 코드이다.
private void ChatMessageRecieved(string message) { AuctionEvent ev = AuctionEvent.From(message); AuctionCommand command = _auctionSniper.Process(ev); if (command != AuctionCommand.None()) { _chat.SendMessage(command.ToString()); } Notify(nameof(LastPrice)); Notify(nameof(LastBid)); Notify(nameof(State)); }
여기서 Decision Maker는 'ActionSniper' 이다.
application service는 여기서 바깥 세상으로부터 'message'를 받아오고, 이를 Decision Maker가 이해할 수 있도록 변환하여 input을 제공, Decision Maker의 결정을 받아와 사용자에게 특정 포맷으로 보여주는 역할을 수행하고 있다.
두 코드 모두 직접적으로 의사 결정을 하지 않으며, 도메인 모델에 '권한을 위임' 한다.
Application service 레이어는 많은 코드들을 포함할 수 있지만, 그 어떤 것도 직접적으로 비즈니스에 의미가 있는 결정이어서는 안 된다.
요약
- Domain logic (aka business logic, business rules, and domain knowledge) is the logic that makes business-critical decisions.
- All other types of logic orchestrate the decisions made by the domain model and transform them into side-effects: save them to the data store, show to the user, or pass to 3rd-party services.
- It’s important to separate domain logic from other types of logic as it helps keep the overall code base simpler.
이어서 읽어볼 아티클
https://enterprisecraftsmanship.com/posts/domain-vs-application-services/
'개발 공부' 카테고리의 다른 글
[JPA] 지연 로딩, 즉시 로딩, N+1 문제 (1) | 2024.11.20 |
---|