코딩 컨벤션
제가 개발할 때 따르는 코딩 컨벤션입니다.
핵심 원칙
1. TDD (Test-Driven Development)
- 테스트 먼저 작성: 구현 전에 테스트 코드를 작성합니다.
- 시나리오 기반: 테스트만 보고 기능을 즉시 파악할 수 있어야 합니다.
- Given-When-Then: 모든 테스트에 주석으로 명시합니다.
2. SOLID 원칙
- 단일 책임 원칙 (SRP): 클래스는 하나의 책임만 가집니다.
- 개방-폐쇄 원칙 (OCP): 확장에는 열려있고 수정에는 닫혀있어야 합니다.
- 리스코프 치환 원칙 (LSP): 하위 타입은 상위 타입을 대체할 수 있어야 합니다.
- 인터페이스 분리 원칙 (ISP): 클라이언트는 사용하지 않는 인터페이스에 의존하지 않아야 합니다.
- 의존성 역전 원칙 (DIP): 구체적인 것이 아닌 추상적인 것에 의존해야 합니다.
3. 문서화
- KDoc: 모든 public 함수와 클래스에 KDoc을 작성합니다.
- API 문서: REST API는 자동 문서화 도구(Spring REST Docs 등)를 사용합니다.
- 주석: 코드가 “무엇"을 하는지가 아닌 “왜” 하는지를 설명합니다.
4. 데이터베이스 규칙
Audit Trail (필수 5가지 필드)
모든 엔티티는 다음 5가지 필드를 필수로 포함해야 합니다:
| |
Soft Delete (물리적 삭제 금지)
- 논리적 삭제만 허용:
deletedAt필드를 사용하여 삭제 표시 - 물리적 삭제 금지:
DELETE쿼리 사용 금지
| |
Kotlin 코딩 스타일
기본 원칙
- Kotlin 공식 코딩 컨벤션 준수
- IntelliJ IDEA 기본 포맷터 사용
- 가독성 우선: 성능보다 가독성을 우선시하고, 필요시 최적화
네이밍 규칙
| |
로깅 규칙
절대 금지:
- ❌ println 사용 금지 (당연하지만):
println()절대 사용하지 않습니다. - ❌ 이모티콘 금지: 코드, 주석, 로그에 이모티콘을 사용하지 않습니다.
필수 사용:
- ✅ SLF4J Logger: 모든 로깅은 SLF4J Logger를 사용합니다.
| |
Import 규칙
FQCN (Fully Qualified Class Name) 사용 금지
| |
클래스 구조 순서
| |
함수 작성 규칙
| |
Null Safety
| |
Data Class 사용
| |
Spring Boot 규칙
레이어 구조
controller/ # REST API 엔드포인트
├── request/ # Request DTO
└── response/ # Response DTO
service/ # 비즈니스 로직
domain/ # 도메인 모델 (Entity)
repository/ # 데이터 접근 계층의존성 주입
| |
트랜잭션
| |
코드 리뷰 체크리스트
기본 원칙
- TDD: 테스트 코드를 먼저 작성했는가?
- SOLID: 단일 책임 원칙을 따르는가?
- 네이밍: 명확하고 의미를 잘 전달하는가?
- 문서화: KDoc이 작성됐는가?
보안 (Security)
- 민감정보: 하드코딩된 비밀번호/API 키가 없는가?
- 입력 검증: 모든 외부 입력을 검증하는가?
- SQL Injection: Prepared Statement 또는 Type-safe DSL을 사용하는가?
- 비밀번호: BCrypt 등으로 해싱하여 저장하는가?
- 로깅: 민감정보(비밀번호, 토큰)를 로그에 남기지 않는가?
동시성 (Concurrency)
- Thread-Safety: 공유 상태가 적절히 동기화되어 있는가?
- 불변 객체: val을 사용하고 가변 상태를 최소화했는가?
- Synchronized: 필요한 최소 범위만 동기화했는가?
- Coroutine: GlobalScope 대신 구조화된 동시성을 사용하는가?
성능 (Performance)
- 문자열 연결: 반복문에서 StringBuilder를 사용하는가?
- 컬렉션 초기 용량: 크기를 알 수 있는 경우 초기 용량을 설정했는가?
- 객체 생성: 불필요한 객체 생성을 피했는가?
- Sequence: 대용량 데이터 처리 시 Sequence를 고려했는가?
코드 품질
- Null Safety: !! 대신 Elvis operator나 let을 사용하는가?
- 예외 처리: 빈 catch 블록이 없고, 구체적인 예외를 처리하는가?
- 매직 넘버: 모든 숫자 리터럴을 상수로 정의했는가?
- 로깅: SLF4J Logger를 사용했는가? println, 이모티콘이 없는가?
- Import: FQCN을 사용하지 않았는가?
데이터베이스
- Audit Trail: 모든 엔티티에 5가지 필드가 있는가?
- Soft Delete: 물리적 삭제를 사용하지 않았는가?
- SELECT: 필요한 컬럼만 명시적으로 선택하는가?
보안 (Security)
1. 민감정보 처리
절대 금지:
- ❌ 하드코딩된 비밀번호/API 키: 코드에 직접 작성 금지
- ❌ 민감정보를 상수로 정의: 환경변수 또는 Secret Manager 사용
- ❌ 로그에 민감정보 노출: 비밀번호, 토큰, 개인정보 로깅 금지
| |
2. 입력 검증 (Input Validation)
모든 외부 입력은 반드시 검증해야 합니다:
| |
3. SQL Injection 방지
| |
4. 비밀번호 처리
| |
동시성 (Concurrency)
1. Thread-Safe 코드 작성
| |
2. 불변 객체 (Immutable Objects) 권장
| |
3. Synchronized 사용 가이드
| |
4. Coroutine 사용 시 주의사항
| |
성능 (Performance)
1. 문자열 연결
| |
2. 컬렉션 초기 용량 설정
| |
3. Stream vs for-loop
| |
4. 불필요한 객체 생성 금지
| |
5. Lazy 초기화
| |
코드 품질 (Code Quality)
1. Null 체크 패턴
| |
2. Optional 사용 가이드
| |
3. 예외 처리 규칙
| |
4. 매직 넘버 금지
| |
절대 금지 사항
로깅 관련
- ❌ println 사용 금지 (당연하지만):
println()절대 사용 금지 - ❌ 이모티콘 금지: 코드, 주석, 로그에 이모티콘 사용 금지
- ❌ FQCN 사용 금지: import 문을 반드시 사용
- ❌ 민감정보 로깅 금지: 비밀번호, 토큰, 개인정보 로그에 기록 금지
보안
- ❌ 하드코딩된 비밀번호/API 키: 환경변수 또는 Secret Manager 사용
- ❌ SQL Injection 취약점: Prepared Statement 또는 Type-safe DSL 사용
- ❌ 평문 비밀번호 저장: 반드시 BCrypt 등으로 해싱
- ❌ 입력 검증 누락: 모든 외부 입력은 반드시 검증
코드 품질
- ❌
!!(non-null assertion) 남발: 최소한으로 사용 - ❌
Any타입 사용: 명확한 타입 지정 - ❌ Magic number: 상수로 정의할 것
- ❌ 긴 함수: 20줄 이상은 리팩토링 고려
- ❌ God class: 하나의 클래스가 너무 많은 책임을 가지지 않도록
- ❌ 빈 catch 블록: 예외는 반드시 적절히 처리
동시성
- ❌ Thread-unsafe 코드: 공유 상태는 적절히 동기화
- ❌ GlobalScope 사용: 구조화된 동시성 사용
성능
- ❌ 반복문에서 + 연산자로 문자열 연결: StringBuilder 사용
- ❌ 대용량 컬렉션에 Stream 남발: Sequence 사용 고려
- ❌ 불필요한 객체 생성: 재사용 가능한 객체는 외부에 선언
데이터베이스
- ❌ 물리적 삭제 금지:
DELETE쿼리 사용 금지 - ❌ SELECT asterisk (*) 금지: 필요한 컬럼만 명시적으로 선택
- ❌ Audit Trail 누락 금지: 모든 엔티티에 5가지 필드 필수