Category Architecture

소프트웨어 공학 중 아키텍처에 대한 글입니다

DIP로 컴포넌트 순환 의존을 끊으려면 시그니처의 타입까지 옮겨야 한다

강의를 만들면 빈 커리큘럼도 함께 생기게 하고 싶었다. 강의 생성 서비스에서 커리큘럼 생성 포트를 한 줄 부르자 테스트 두 개가 깨졌다. 하나는 DB의 유니크 제약이고, 하나는 아키텍처 테스트의 순환 금지 규칙이다. 순환은 의존성 역전 원칙(DIP)으로 풀었다. 인터페이스를 쓰는 쪽 패키지로…

도메인에 위임만 하는 애플리케이션 서비스도 테스트해야 버그가 드러난다

커리큘럼 편집 서비스의 메서드는 모두 세 줄이다. 커리큘럼을 찾고, 도메인 메서드를 부르고, 저장한다. 로직은 전부 도메인에 있고 도메인 테스트는 꼼꼼하다. 강의는 이 서비스가 너무 단순하다며 테스트를 과제로 남겼다. 나는 그 과제를 하기 전에 서비스를 먼저 커밋했는데, 강의 코드에 있던 버그…

JPA OrderColumn과 orphanRemoval은 수업 이동에서 충돌한다

도메인 코드에서 수업을 지우는 방법은 리스트에서 빼는 것이다. JPA의 orphanRemoval은 그렇게 빠진 엔티티를 DB에서도 지워 준다. 편한 설정이지만 커리큘럼에서는 켤 수 없었다. 수업 이동이 “한 리스트에서 빼서 다른 리스트에 넣는” 동작이고, JPA 스펙은 고아가 된 엔티티를 다른 관계에 다시 넣지…

리스트 인덱스로 애그리거트 구조를 편집하면 삭제가 인덱스를 먼저 바꾼다

커리큘럼 편집 요청은 전부 숫자로 온다. “섹션 0번의 수업 2번을 섹션 1번의 0번 자리로 옮겨라” 같은 식이다. 리스트 인덱스로 애그리거트 구조 편집을 구현하면 코드는 짧다. 대신 remove가 한 번 일어나면 그 뒤 원소의 인덱스가 하나씩 당겨진다는 사실을 계속 의식해야 한다.…

커리큘럼 애그리거트는 탐색이 아니라 편집을 기준으로 트리로 설계한다

강의 애그리거트에는 강사, 소개, 공개 상태가 들어 있다. 다음은 실제 학습 내용이다. 강의는 여러 수업으로 이뤄지고, 수업이 많으니 섹션으로 다시 묶는다. 수업과 섹션은 강의에 속한 것처럼 보이니 Course 아래에 매달고 싶어진다. 이 글의 커리큘럼 애그리거트 트리 설계는 그 선택지를 버리는…

강의 도메인의 상태 전이는 애그리거트 안에서 강제한다

상태를 가진 도메인을 개발할 때 가장 흔한 구조는 엔티티에 status 컬럼을 두고, 서비스 코드에서 if (course.getStatus() == DRAFT) 같은 조건문으로 전이를 검사하는 방식이다. 처음에는 잘 동작한다. 문제는 그 강의를 다루는 코드가 두 곳, 세 곳으로 늘어날 때다. 어느 상태에서 어느…

ArchUnit 슬라이스 순환 의존성 검증으로 아키텍처를 코드로 강제한다

아키텍처 규칙은 대부분 문서에만 있다. “슬라이스 사이에는 순환 의존을 두지 않는다”고 적어 놓고, 코드 리뷰에서 걸러 내기를 기대한다. 그런데 리뷰어가 놓치면 그대로 들어가고, 한 번 들어간 순환 의존은 시간이 지날수록 걷어 내기 어려워진다 결론부터 말하면 이런 규칙은 테스트 코드로 강제할…

Instancio 랜덤 데이터 테스트 픽스처로 고정값을 걷어낸다

테스트 픽스처를 열어 보면 이런 코드가 있다 닉네임은 KimWhat이고 비밀번호는 verysecret이다. 이 값이 무슨 의미인지는 아무도 설명하지 않는다. 그냥 형식 검증을 통과할 만한 길이로 아무렇게나 정한 값이다. 그런데 이 값은 검증 코드에도 그대로 박혀 있다 이 테스트가 통과한다고 해서 비밀번호…

스프링 커스텀 스테레오타입 애노테이션으로 반복 설정을 묶는다

애플리케이션 서비스 클래스를 하나 열어 보면 이런 상태가 되어 있다 네 줄 모두 이 클래스가 무슨 일을 하는지에 대한 설명이 아니다. 스프링 빈으로 등록하고, 트랜잭션을 걸고, 파라미터 검증을 켜고, 생성자를 만들어 달라는 지시다. 애플리케이션 서비스를 새로 만들 때마다 이 네…