대화로 정한 코딩 스탠다드

여기 실린 표준들은 서로 이어져 있다. 아래 표는 정한 순서대로 나열했다 — 뒤의 글은 앞의 글에서 정한 것을 전제로 삼는다.

Claude Code, GitHub Copilot, Codex에 이 표준을 적용하는 배포 파일과 Windows·Ubuntu 설치 스크립트는 공개 coding-standards 저장소에서 버전별로 제공한다.

아직 정하지 않았거나 정한 것끼리 부딪히는 지점은 아직 정하지 않은 것에 따로 모아둔다.

# 표준 한 줄 요약 태그
1 팩토리 메소드로 VO 생성하기
DTO에서 VO로의 변환을 팩토리 메소드에 맡겨 Service의 변환 코드를 걷어낸다
팩토리메소드디자인패턴VO변환Service레이어코드가독성검증로직
2 Null-free 객체 설계와 생성 철학
생성자가 객체의 완전성을 보장한다. 정적 팩토리, 불변성, 그리고 엔티티에서의 타협점
객체지향방어적프로그래밍불변성정적팩토리빌더패턴엔티티DTO
3 Assert로 프로그래머의 실수를 잡아내기
내부 검증과 외부 검증의 경계를 나누고, 그 안쪽을 assert가 맡는다
assert디버깅내부검증예외처리설계패턴코드품질
4 상속 vs 합성
DTO 공통 필드는 1레벨 상속으로 관리하고, 그 밖은 합성으로 간다
JavaOOP상속합성객체지향설계패턴
5 계층별 DTO 네이밍 표준
Controller, Service, JPA, MyBatis 사이의 의존성을 끊는 DTO 설계 원칙
DTO네이밍컨벤션계층분리DomainJPAMyBatis의존성역전
6 Swagger 문서화 표준
@Schema와 Bean Validation의 역할을 나누고, 공통 응답은 전역에서 관리한다
SwaggerspringdocOpenAPIAPI문서화BeanValidationDTO문서화표준
7 계층별 검증 표준
무엇을 어디서 검증할지 가르는 기준은 "도메인 지식이 필요한가"이다
검증BeanValidationDTODomain예외처리계층분리방어적프로그래밍
8 Service 계층의 assert
메서드의 전제와 결과를 코드로 선언하고, 깨지는 순간 멈추게 하는 방법
assert계약에의한설계ServiceCommandFailFast개발생산성사전조건
9 DTO는 생성자로만 만든다
setter와 기본 생성자를 없애면 객체가 불완전한 상태로 존재할 수 없다
DTO생성자불변객체정적팩토리빌더패턴JacksonLombok
10 예외 처리 표준
ErrorCode를 단일 출처로 삼아 상태 코드, 메시지, 로그를 한 곳에서 통제한다
예외처리ErrorCodeRestControllerAdvice로깅HTTP상태코드API설계
11 예외의 종류
인증 실패는 Advice에 오지 않고, DB 제약 위반은 500이 된다
예외처리ErrorCodeSpringSecurity트랜잭션외부연동로깅
12 패키지 구조
도메인별로 나누고 package-private으로 막으면 계층 위반이 컴파일 에러가 된다
패키지구조아키텍처계층분리접근제어의존성역전
13 애그리거트 경계
Domain은 지연 로딩이 없다. 애그리거트 크기가 곧 매 조회의 비용이다
애그리거트DDDDomainRepository트랜잭션불변성
14 Repository 설계 표준
저장과 단건 조회는 JPA로, 조건이 조합되는 검색은 MyBatis로, 대량 쓰기는 Repository 밖으로 뺀다
RepositoryJPAMyBatis동적쿼리SpringBatchFetchJoin
15 UseCase 인터페이스
Service를 package-private으로 감추면 Controller가 쓸 수 있는 것이 컴파일러로 정해진다
UseCase아키텍처계층분리접근제어도메인간통신Snapshot
16 벌크와 배치
판단이 없으면 벌크, 있으면 배치. Domain을 거치는지는 결과이지 기준이 아니다
배치SpringBatch벌크연산트랜잭션예외처리Domain
17 Domain 영속화
POJO를 그대로 save하면 Domain이 모르는 컬럼이 조용히 null로 덮인다
JPA영속성트랜잭션Domain낙관적락애그리거트
18 조회 전용 타입
들어가는 쪽에 SearchCondition이 있듯, 나가는 쪽에 View가 있다
조회애그리거트Repository패키지구조DTOCQRS
19 삭제
지울 수 있는 애그리거트에만 delete를 둔다. 나머지는 컴파일러가 막는다
삭제애그리거트RepositoryFKJPA도메인간참조
20 인증 주체
LoginUser는 api에서 죽고, application으로는 userId만 간다
인증SpringSecurity계층분리CommandDomain권한