

Pageable, Page class를 도메인 영역을 제외한 모든 영역에서 사용persistent에서만 사용하는게 헥사고날 아키텍처에 맞지만, [웹 영역 + 어플리케이션 영역]에 사용하지 않으면, Pageable, Page를 컨버팅 하는데 개발 비용을 사용[RP 개발 때 경험..]하게 된다. 비용을 줄이기 위해 매핑하기 않기(No Mapping) 전략을 사용함. 당연히 Page의 Generic 클래스는 컨버팅을 함[Artchip → GetArtchipResponse]
Pageable : 프론트에서 보내주는 QueryString 값을 컨버팅 하는 용도로 사용웹 계층, 영속성 계층에 단순히 전달하는 용도로 사용인커밍 아답터가 여러개일 경우 고민을 해봐야 할듯. spring-web와 함께 spring-data-jpa 기술을 사용할 경우 DispatcherServlet에서 PageableHandlerMethodArgumentResolver를 통해 스프링이 Pageable 객체를 만들어주지만, grpc, sqs, kafka 등을 통해 들어올 경우 DispatcherServlet를 통해 들어오지 않아 스프링이 Pageable 객체를 만들어주지 않음. 그래서, 결국 수동으로 컨버팅하는 경우가 생기는데, 이럴때는 공통적으로 컨버팅을 하는게 더 좋을수도 있을 것 같음. Spring Security의 SecurityContextHolder도 비슷한 문제가 발생할 수 있음.인커밍 아답터 → 아웃고잉 아답터[X], 인커밍 아답터 → 어플리케이션 → 아웃고잉 아답터[O]
web 영역[인커밍]에서 사용자의 인증을 체크하기 위해 authentication 영역[아웃고잉]을 바로 호출하지 말고, 중간에 어플리케이션 영역을 거쳐 인증을 구현인커밍 포트 구현체 → 인커밍 포트 → 인커밍 포트 구현체[X], 인커밍 포트 구현체 → EventHandler → 인커밍 포트, 인커밍 포트 구현체[O]
Collection 도메인과 Artchip 도메인은 다른 어그리거트로 설계함. Collection을 삭제하면 모든 Artchip에 설정된 Collection을 해제하는 기능이 있었는데, EventListener를 활용한 간접 호출로 구현// 컬렉션 삭제 이벤트 클래스
public class CollectionDeletedEvent extends Event {
private String collectionId;
private AuthenticationInfo authenticationInfo;
}
// 컬렉션 삭제 메서드
public class DeleteCollectionService implements DeleteCollectionUseCase {
private final GetCollection getCollection;
private final SaveCollectionPort saveCollectionPort;
private final GetAuthenticationInfoPort getAuthenticationInfoPort;
private final ApplicationEventPublisher publisher;
@Transactional
@Override
public void delete(String collectionId) {
Collection collection = getCollection.get(collectionId);
AuthenticationInfo authenticationInfo =
getAuthenticationInfoPort.getAuthenticationInfo();
Collection newCollection = collection.delete();
saveCollectionPort.saveCollection(newCollection);
// 컬렉션 삭제 이벤트 발생[간접 호출]
publisher.publishEvent(new CollectionDeletedEvent(collectionId,
authenticationInfo));
}
}
// 아트칩 이벤트 핸들러
public class ArtchipEventHandler {
private final DeleteArtchipCollectionsUseCase deleteArtchipCollectionsUseCase;
@EventListener(CollectionDeletedEvent.class)
public void collectionDeletedEventHandler(CollectionDeletedEvent event) {
log.info("eventTime: {}, data: {}", event.getEventTime(), event);
// 핸들러로 통하여, 아트칩에 연결된 컬렉션을 해제
deleteArtchipCollectionsUseCase.delete(event.getCollectionId(),
event.getAuthenticationInfo());
}
}
아웃고잉 포트! 오버로딩 VS 고유한 메서드명아웃고잉 포트는 여러개지만 포트의 구현체는 1개이다.
2개의 다른 아웃고잉 포트에서 중복된 메서드명으로 만들 때는 Command DTO를 활용하자!
오버로딩을 할 수 없다. 각 아웃고잉 포트에 Command DTO를 만들어서 사용하자!/** 잘못된 방법 **/
interface GetArtchipById {
Artchip get(String id);
}
interface GetArtchipByName {
Artchip get(String name);
}
// 컴파일 에러 발생
public class ArtchipRepositoryAdapter implements GetArtchipById, GetArtchipByName {
@Orveride
public Artchip get(String id) {
return null;
}
@Orveride
public Artchip get(String id) {
return null;
}
}
/** 올바른 방법 **/
interface GetArtchipById {
Artchip get(Command command);
@Data
class Command {
private String id;
}
}
interface GetArtchipByName {
Artchip get(Command command);
@Data
class Command {
private String name;
}
}
public class ArtchipRepositoryAdapter implements GetArtchipById, GetArtchipByName {
@Orveride
public Artchip get(GetArtchipById.Command command) {
return null;
}
@Orveride
public Artchip get(GetArtchipByName.Command command) {
return null;
}
}
DTO를 사용하지 않는다면, 각 포트마다 고유한 메서드명을 만들면 된다.
interface GetArtchipById {
Artchip getArtchipById(String id);
}
interface GetArtchipByName {
Artchip getArtchipByName(String name);
}
public class ArtchipRepositoryAdapter implements GetArtchipById, GetArtchipByName {
@Orveride
public Artchip getArtchipById(String id) {
return null;
}
@Orveride
public Artchip getArtchipByName(String name) {
return null;
}
}
오버로딩과 고유한 메서드명 중 하나를 선택한다면, 오버로딩이 더 식별성이 좋다고 생각. 최대한 DTO를 활용하여, 데이터를 응집하는게 더 좋다고 생각
// DTO를 활용한 오버로딩
GetArtchipById.Command command = new GetArtchipById.Command("id");
getArtchipByName.get(command);
// 고유한 메서드명
getArtchipByName.getArtchipByName(”id”);
인커밍 포트는 DTO가 아닌 객체 및 기본 자료형을 사용해도 상관없다.
인커밍 포트의 구현체는 1개이기 때문!@AggregateRoot, @Aggregate 어너테이션 선언하자.AggregateRoot인지, Aggregate인지 편하게 식별하기 위해 최상단에 어너테이션을 선언