10 KiB
10 KiB
코드 컨벤션
파일 생성 규칙
- 새 기능은 가능하면
modules/{도메인명}Controller단위로 패키지를 만들고 그 아래에service,mapper,dto,vo를 필요한 만큼만 추가한다. - 요청 검증이나 JSON 바인딩이 필요하면
form패키지를 함께 만든다. - 클래스명은 역할이 바로 드러나게
도메인명 + 역할형식을 유지한다. 예:ApiService,ApiMapper,ApiVo - Mapper 인터페이스를 추가하면 같은 이름의 XML을
src/main/resources/mapper/{도메인경로}아래 함께 만든다. - 단순 예시 코드와 운영 코드는 섞지 말고 패키지로 분리한다.
- 설정성 클래스는
config하위 역할별 패키지에 둔다. 예:config.jwt,config.exception,config.properties
DTO/VO/Form 규칙
Dto는 각 Controller 에서 Service, Mapper 로 전달하는 파라미터 성격의 값 객체로 정의한다.Dto는 요청 처리에 필요한 저장, 수정, 로그 적재 같은 작업 파라미터를 담는 용도로 우선 사용한다.Vo는 Mapper 에서 Service, Controller 로 반환하는 값 객체로 정의한다.Vo는 Mapper 조회 결과를 담을 수 있고, Service 에서 비즈니스 로직 처리 후 필요한 데이터를 가공해서 Controller 로 반환하는 용도로 사용한다.Form은 Controller 입력 검증과 요청 바인딩 전용으로 두고,@Valid와 Jakarta Validation 어노테이션을 우선 사용한다.- Form/Dto/Vo 클래스명은 가능한 한 Controller 메서드명을 기준으로 맞춘다. 예: Controller 메서드가
adminMemberList이면AdminMemberListForm,AdminMemberListDto,AdminMemberListVo를 사용한다. - 신규 API 에서는 path 동작명과 다른 표현을 지양한다. 예: 목록은
Search보다List, 상세는Detail보다View, 수정은Update보다Modify를 우선 사용한다. - 현재 코드처럼 DTO/VO는 Lombok
@Getter, 필요한 경우에만@Setter를 사용한다. - Form 안에는 DTO 변환 메서드를 둘 수 있으며, 짝이 되는 Dto 로 변환하는 메서드는
toDto()를 기본으로 사용한다. 예:AdminMemberListForm#toDto()는AdminMemberListDto를 반환한다. - 하나의 Form 이 여러 Dto 로 변환되어야 하는 예외 상황에서만
toAdminMemberListDto()처럼 대상 Dto 이름을 명시한다. - Form 에서 DTO 로 변환할 때는 검증과
trim(), 기본값 치환까지 같이 처리하는 현재 패턴을 우선 따른다. - DTO 안에 연관된 다른 DTO 변환이 꼭 필요할 때만 최소한의 보조 메서드를 둔다.
- 외부 응답에 노출되면 안 되는 내부 필드는 응답에 사용될 수 있는 객체에서
@JsonIgnore로 숨긴다. - 등록, 수정, 삭제, 상태 변경처럼 처리 여부만 반환하는 VO 의 boolean 필드는
processed로 통일한다. 예:private boolean processed; - Controller 요청/응답 타입은 가능한 한 Form/Dto/Vo 로 명시한다.
Map<String, Object>는 응답 구조가 고정되지 않는 임시 디버깅, 외부 라이브러리 passthrough 같은 예외 상황에서만 제한적으로 사용한다. - 응답 필드가 단순 boolean 몇 개뿐이어도 운영 API 에서는 VO 를 만든다. 예: 로그인 상태 확인 응답은
Map<String, Object>보다AdminAuthLoginCheckedVo를 사용한다. - 목록 조회 API 는 특별한 사유가 없으면 기본적으로 페이징을 적용하고, 목록 조회 Form/Dto 는
PageRequest, 목록 응답 Vo 는PageResponse를 상속한다.
Swagger/OpenAPI 문서화 규칙
- 신규 또는 수정되는 Controller, Form, VO에는 Swagger 테스트 편의성을 위한 설명을 반드시 남긴다.
- Controller 클래스에는
@Tag를 사용해 API 그룹명과 설명을 작성한다. - Controller 메서드에는
@Operation으로summary와description을 작성한다. @RequestBodyForm 클래스에는 클래스 레벨@Schema(description = "...")를 작성한다.@ModelAttribute검색 Form 필드에도@Schema를 작성해 Swagger query parameter 설명과 예시가 보이게 한다.- Form 필드에는
@Schema로description,example을 작성한다. - 필수 입력값은 Jakarta Validation 어노테이션과
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)를 함께 사용한다. - 코드값 필드는 허용 값을
description에 명시한다. 예:userType: A 관리자, T 교사, S 학생,withdrawStatus: N 정상, P 탈퇴대기, Y 탈퇴완료. - VO 클래스에는 클래스 레벨
@Schema(description = "...")를 작성한다. - VO 필드에는
@Schema로 응답 값의 의미를 작성한다. - 토큰, 임시 비밀번호처럼 Swagger 테스트에 필요한 응답 필드는 VO에 명시하되
description에 용도를 적는다. - 비밀번호, DB 조회용 내부 식별자,
resultCode처럼 외부 응답에 노출하지 않는 필드는@JsonIgnore를 사용하고 필요하면@Schema(hidden = true)도 함께 사용한다. - 클라이언트가 직접 전달하지 않는 내부 계산 필드나 서버 전용 getter는
@Schema(hidden = true)로 숨긴다. - 페이징 요청에서 클라이언트는
page,size만 전달하고,limit,offset은 Swagger에 노출하지 않는다. - 페이징 응답의
rowStartNum처럼 계산 방식이 필요한 값은 프론트 사용 방법까지description에 남긴다.
Mapper/MyBatis 규칙
- Service/Mapper 메서드명은 주된 DB 동작이 드러나도록
select,insert,update접두어를 먼저 붙이고 Controller 메서드명을 이어서 만든다. 예: Controller 메서드가adminSsoClientList이면 Service/Mapper 조회 메서드는selectAdminSsoClientList. - 삭제 API도 기본적으로 물리 삭제가 아니라 상태 변경으로 처리하므로 실제 SQL 동작에 맞춰
update...Delete형태를 우선 사용한다. 예: Controller 메서드가adminSsoClientDelete이면 Service/Mapper 메서드는updateAdminSsoClientDelete. - 물리 삭제가 정책상 명확히 필요한 예외 상황에서만
deleteSQL과delete...메서드명을 사용한다. - SQL 을 여러 줄로 작성할 때 콤마는 다음 줄 앞에 둔다. 예:
SELECT COL1, 다음 줄, COL2. - Mapper XML
namespace는 인터페이스의 전체 경로와 정확히 일치시킨다. - XML의
id는 Mapper 메서드명과 동일하게 맞춘다. - 조회 결과 타입은
resultType, 저장/수정 파라미터는 DTO 필드명과 매핑되는 프로퍼티명을 그대로 사용한다. - Mapper XML 안 SQL 블록 시작부 주석은 현재 코드처럼
/*Mapper.method*/형식을 유지한다. - Mapper XML 위치는
src/main/resources/mapper/**/*.xml이다. map-underscore-to-camel-case: true설정으로 DB 컬럼user_idx는 Java 필드userIdx로 자동 매핑된다.useGeneratedKeys,keyProperty를 사용하는 insert 가 있으므로 신규 PK 생성 테이블은 현재 패턴을 먼저 확인한다.- 상태 집계나 이력성 데이터는 단건 update 외에 이벤트 로그 insert 가 같이 필요한지 확인한다.
Java/Spring 코드 스타일
- Java 코드는 현재 프로젝트 스타일에 맞춰 탭/들여쓰기와 import 정렬을 유지한다.
- 코드는 초급 개발자가 읽어도 흐름을 따라갈 수 있도록 직관적으로 작성한다. 과한 축약, 기교적인 표현, 불필요하게 복잡한 체이닝보다 명확한 변수명과 단계적인 흐름을 우선한다.
- Java 코드에서 메서드 호출, 어노테이션 인자, 생성자 인자 등을 여러 줄로 작성할 때 콤마는 다음 줄 앞에 둔다. 예:
summary = "회원 목록 조회"다음 줄, description = "..." - 기능 수정/추가 시 가능하면 Red-Green-Refactor 흐름을 따른다. 먼저 실패하는 테스트나 재현 가능한 검증 조건을 만들고(Red), 최소 구현으로 통과시키며(Green), 이후 컨벤션과 가독성에 맞게 정리한다(Refactor). 테스트 작성이 어려운 경우에는 최소 실행 검증 절차를 먼저 정하고 결과를 보고한다.
- Lombok은 반복 보일러플레이트 제거에만 절제해서 사용한다.
- 로그는
Slf4j를 사용하고 반복문 내부 대량 출력은 지양한다. - 새로운 기능은 가능하면 역할이 드러나는 패키지로 분리한다.
- 생성자 주입을 기본으로 하고 필드 주입은 추가하지 않는다.
- Service 에서 DB 상태를 바꾸는 메서드는 필요한 범위에서
@Transactional을 사용하고, 조회 전용은readOnly = true를 우선 검토한다. - 문자열 입력값은 현재 코드처럼 필요한 지점에서
trim()처리하고, null 가능성 여부를 먼저 확인한다. - 지역 변수명은
result,list,vo,dto처럼 범용적인 이름보다 도메인과 객체 종류가 드러나게 작성한다. 예:List<AdminMemberVo> adminMemberList,AdminMemberListVo adminMemberListVo,AdminMemberListDto adminMemberListDto. - 같은 타입 또는 같은 의미의 변수가 여러 개 필요해도 객체 종류를 유지하고, 구분이 필요한 경우 숫자 suffix 를 제한적으로 사용한다. 예:
AdminMemberVo adminMemberVo1,AdminMemberVo adminMemberVo2.
Controller/Service 규칙
- Controller 는 요청/응답 조립과 인증 주체 확인에 집중하고, DB 처리나 복잡한 계산은 Service 로 넘긴다.
- Controller 응답은
ResponseEntity<ApiResponse<T>>를 기본으로 사용한다. 파일 다운로드처럼 바이너리 응답이 필요한 경우만 예외로 둔다. - Controller 에서는
@RequestBody,@PathVariable,@RequestHeader,@CookieValue를 명시적으로 선언해 요청 출처를 드러낸다. - 인증 사용자 확인은 모듈 구현에 따라
HttpSession또는SecurityContextHolder를 사용하므로 기존 방식을 먼저 맞춘다. - 목록 조회는 Controller 에서
@ModelAttribute검색 Form 을 받고, Service 에서totalCount와 목록을 조회한 뒤PageResponse#setPaging(...)으로 페이징 정보를 채운다. - 신규 API path 의 동작명은 CRUD 성격에 맞춰 통일한다. 목록은
list, 상세 조회는view, 등록은add, 수정은modify, 삭제는delete를 사용한다. - Controller 메서드명은 가능한 한 path 조합을 기준으로 만든다. 클래스 레벨 path 와 메서드 레벨 path 를 이어 붙인 의미가 드러나게 작성한다. 예: 클래스 path 가
/admin/member, 메서드 path 가/list이면adminMemberList, 클래스 path 가/admin/sso/client, 메서드 path 가/view이면adminSsoClientView.