만들면서 배우는 클린 아키텍처 3, 4장

허석문·2024년 5월 28일
0
post-thumbnail

03 코드 구성


계층으로 구성하기

기능으로 구성하기

  • package-private 접근 수준 이용해 패키지 간의 경계를 강화할 수 있다.

아키텍처적으로 표현력 있는 패키지 구조

의존성 주입의 역할

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?

04 유스케이스 구현하기


도메인 모델 구현하기

package buckpal.domain;

public class Account {

	private Accountld id;
	private Money baselineBalance;
	private Activitywindow activitywindow;

	// 생성자와 getter는 생략

	public Money calculateBalance() {
		return Money.add(
			this.baselineBalance,
			this.activitywindow.calculateBalance(this.id));
	}

	public boolean withdraw(Money money, Accountld targetAccountld) {
		if (!mayWithdraw(money)) {
			return false;
		}

		Activity withdrawal = new Activity(
		this.id,
		this.id,
		targetAccountld,
		LocalDateTime.now(),
		money);
		return true;
	}

	private boolean mayWithdraw(Money money) {
		return Money.add(
			this.calculateBalanceQ,
			money.negate()
			.isPositive();	
	}

	public boolean deposit(Money money, Accountld sourceAccountld) {
		Activity deposit = new Activity(
		this.id,
		sourceAccountld,
		this.id,
		LocalDateTime.now(),
		money);
		this.activitywindow.addActivity(deposit);
		return true;
	}
}

유스케이스 둘러보기

  1. 입력을 받는다.
  2. 비즈니스 규칙을 검증한다.
  3. 모델 상태를 조작한다.
  4. 출력을 반환한다.

유스케이스 코드가 도메인 로직에만 신경 써야 하고 입력 유효성 검증으로 오염되면 안 된다. 입력 유효성 검증은 다른 곳에서 처리한다. 그러나 유스케이스는 비즈니스 규칙(business rule)을 검증할 책임이 있다.

package buckpal.application.service;

@RequiredArgsConstructor
@Transactional
public class SendMoneyService implements SendMoneyUseCase {

	private final LoadAccountPort loadAccountPort;
	private final AccountLock accountLock;
	private final UpdateAccountStatePort updateAccountStatePort;
	
	©Override
	public boolean sendMoney(SendMoneyCommand command) {
	// TODO: 비즈니스 규칙 검증
	// TODO: 모델 상태 조작
	// TODO: 출력 값 반환
	}
}

입력 유효성 검증

입력 유효성 검증은 유스케이스 클래스의 책임 X,
하지만 여전히 애플리케이션 계층의 책임 O -> 왜? -> 유스케이스 호출자(celler) 가 모두 검증 했다고 믿을 수 없다

그럼 어디? -> 입력 모델 -> 정확히 말하면 생성자 내에서 입력 유효성을 검증

구현은 어떻게? -> Bean Validation API를 활용하여

유스케이스 구현체 주위에 사실상의 오류 방지 계층을 만들었다

생성자의 힘

생성자에 필요한 파라미터가 많으면 어떻게 해야하지? -> 빌더 패턴? -> 빌더는 유효성을 검증을 컴파일 단계에서 해주지 못한다

흠.. 이러한 이유로 생성자를 사용하자는 거 같은데 자바가 문제가 많다.. 코틀린으로 넘어가자

유스케이스마다 다른 입력 모델

범용성이 높은 입력 모델을 사용하기 위해서는 null 를 허용하게 된다 -> 그 자체로 문제가 발생
-> 동의하는 부분

비즈니스 규칙 검증하기

비즈니스 규칙 검증은 현재 상태에 접근을 해야된다!!!

구현 방법은 어떻게? -> 도메인 엔티티 안에 넣자 (DDD?) -> 여의치 않다면 -> 유스케이스에 -> 당연한 듯?

풍부한 도메인 모델 vs 빈약한 도메인 모델

유스케이스마다 다른 출력 모델

출력도 구체적으로, 꼭 필요한 데이터만 들고 있어야 한다.
-> 흠... 근데 이러면 도메인이 출력에 의존적으로 바뀌는 거 아닌가? -> 엔티티를 입력 모델이나 출력 모델로 사용하는 것은 11장에서...

읽기 전용 유스케이스는 어떨까?

애플리케이션 코어의 관점에서는 단순한 데이터 쿼리 -> 쿼리 서비스

CQS, CQRS 개념과 맞게

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?

단점은 작업의 양이 많아진다... -> 매핑과정이 늘어서
하지만 유스케이스를 명확하게 이해하게 하고 장기적 유지보수를 쉽게 만든다

profile
항상 노력하는 백엔드 개발자

0개의 댓글