31일 차 TIL
오늘은 이전 1차 프로젝트를 회고하고 이후 계획을 좀 세워보려고 한다.
새로 배웠던 큰 기술들
1. 컨벤션 개념과 Issue 발행 및 PR 문화
코드 컨벤션은 우테코의 코드 컨벤션을 사용했었다.
PR은 CodeRabbit의 코드 리뷰 AI를 사용했었다.
전용 yml설정을 통해 AI에게 지시 사항을 커스텀할 수 있었다.
무엇을 중심으로 피드백할지 설정할 수 있었고,
현재 프로젝트의 버전(환경) 정보도 같이 넣어서 다른 의존성 문제로 오해하지 않게 할 수 있었다.
2. 도메인 주도 설계
Layered Architecture를 사용하다가 DDD를 사용한 프로젝트를 진행했었다.
도메인 별로 패키지를 구분하고
Infrastructure(인프라) 계층이 추가된 것이 가장 큰 차이점이다.
도메인 엔티티 자체에서 자신만의 비즈니스 규칙을 가진다.
이로써 서비스 클래스의 코드가 줄어들고, 비즈니스 로직이 수정될 때마다 서비스를 수정할 필요가 없어진다.
단지 도메인의 해당 비즈니스 규칙을 담당하는 메서드를 수정하면 된다.
(필드의 값 계산, Enum 상태관리, boolean을 반환하는 메서드로 도메인의 상태를 의미적으로 나타냄)
그리고 이번에 내 코드에서는, 서비스 구현체에서 다른 도메인의 Repository를 참조해서 가져오는데,
이는 DDD 설계상 좋지않다고 한다.
그 이유는 해당 도메인의 비즈니스로직이 변경되면 그 Repository를 받아서 사용하던 코드를 전부 수정해야 한다.
하지만 서비스에서 다른 도메인의 Repository 대신 그 도메인의 서비스를 참조한다면
비즈니스로직이 변경되면 참조하는 서비스들은 내버려두고
원래 해당 도메인의 서비스코드만 수정하면 된다고 한다.
3. 프로젝트 설계 툴
테이블의 연관 관계를 표현하는 ERDCloud와
인프라의 설계도를 작성하는 draw.io를 사용해 봤다.
4. 데이터 버전 관리 기술
Flyway를 많이 사용한다고 하는데, Liquibase를 사용해 봤다.
Flyway는 직접 sql을 적는데, 사용하려는 DB의 문법에 맞게 적어줘야 한다.
하지만 Liquibase는 직접 sql을 적을 수도 있지만 yml로도 ddl을 작성할 수 있어, 이기종 DB로의 전환이 자유롭다.
5. API 자동 문서화 툴
처음엔 Swagger를 많이 사용하시는 것 같은데, RestDocs를 사용해 봤다.
코드레벨에서 완성되는 Swagger에 비해 RestDocs는 테스트 코드 작성으로 이루어진다.
이때, Swagger 별도의 어노테이션을 코드에 붙여야 했기에 가독성면에서 좋지 않았고,
문서화 말고 실제 코드로직에만 집중할 수 있었다.
또한 RestDocs는 Swagger와 달리 테스트 시 더미데이터가 누적되지 않았다.
하지만 설정이 번거롭고, 테스트 코드를 꼭 작성해야 했으며 정적인 HTML로 API 문서를 확인할 수 있는 한계가 있었다.
6. QueryDSL
쿼리 성능 개선을 위해 QueryDSL를 사용해 봤다.
fetchJoin, 카운트 쿼리 등 n+1 조회, 페이징 처리에 활용해 보았다.
7. CI / CD 개념
지속적인 통합 및 지속적인 배포 즉, CI/CD를 자동화하는 작업을 경험해 봤다.
Github Actions를 통해
develop에 push시, CI work flow가 실행되고
main에 push시, CD work flow가 실행된다.
8. Spring AI
파이썬으로만 하던 LLM을 활용한 프로젝트를 스프링 AI를 통해 스프링 부트에서 경험해 봤다.
코드 레벨에서 새로 배운 개념들
1. 테스트 코드 작성법
리포지토리, 컨트롤러, 서비스 레이어, 세부 복잡한 기능 순서의 총 4개의 테스트 코드를 작성해 봤다.
이후 RestDocs API 문서화용으로 컨트롤러 테스트 코드를 수정해 봤다.
2. global 패키지를 통한 공통 설정 관리
- 응답 코드 및 에러 처리 전역 설정
=> 에러 코드를 enum으로 관리 및 기능에 맞게 구현체를 작성 + 서비스레이어에서 RuntimeException을 구현한 클래스를 반환한다, 이를 보통 BusinessException으로 작명함.
=> BusinessException클래스를 @ExceptionHandler 파라미터로 주어 메서드에 붙인다.
이 메서드는 ResponseEntitiy의 제네릭 타입을 커스텀해서 공용 응답을 처리할 수 있다.
다른 것들도 기능에 맞게 커스텀해서 @ExceptionHandler를 붙이고 이 메서드들을 모아서 하나의 클래스로 관리한다.
이를 GlobalExceptionAdvice 클래스로 작명하여, @RestControllerAdvise를 붙인다.
이제 스프링 전역에서 예외가 발생 시, 해당 어노테이션이 붙은 클래스에서 처리한다.
=> 이때 에러코드를 global 패키지에는 시스템 전체가 반드시 지켜야 할 에러코드 계약인 Error Code 인터페이스만 남겨두고,
UserErrorCode, OrderErrorCode 등은 해당 도메인 내 패키지로 독립시키면 좋다.
=> 에러코드를 추가할 때 본인이 맡은 패키지 내에서 수정할 수 있기에 충돌이 원천 차단된다.
=> 이후 모놀리식에서 MSA로 전환 시 해당 도메인패키지만 따로 서비스로 떼어내도 문제가 없다.
- @Configuration으로 Bean 수동 주입 전역 관리
- resolver로 http 요청 Page 사이즈 검증(PageableHandlerMethodArgumentResolver 구현)
- 커서 기반의 페이징 처리 ( 현재 id를 기준으로 + 몇 개 가져오기 )
- 인증 및 인가, JWT용 config 처리
- @PreAuthorize(" hasRole("OWNER"))로 메서드에서 사용자의 OWNER 권한 체크
=> 커스텀어노테이션으로 관리할 수 있다. @Target과 @Retention, @PreAuthorize()를 붙이고 @interface를 파일의 타입으로 하면 된다.
3. record 타입으로 dto 관리
불변 객체인 record 타입으로 dto를 관리했다. http로 전달하거나 결과로써 사용되기에 변하지 않아야 하기 때문이다. class로 관리하면 여러 어노테이션을 붙여야 하지만 record는 별도의 어노테이션이 필요 없다. static 메서드 from()으로 record 객체를 생성할 수 있다.
이후 글로 정리할 기술들
- 코드 래빗
- Liquibase
- RestDocs
- 새로 배웠던 것들의 개념, 사용법 등 다른 사람들에게 알려줄 수 있을 정도로 알아보기
'내배캠' 카테고리의 다른 글
| DDD와 헥사고날 아키텍처 (0) | 2026.03.19 |
|---|---|
| [내일배움캠프] 35일 차 TIL - DDD와 헥사고날 비교 (0) | 2026.03.17 |
| 30일 차 TIL - 프로젝트하며 얻은 것 리스트 (0) | 2026.03.11 |
| 29일차 TIL - RestDocs 사용법 (0) | 2026.03.10 |
| 28일 차 TIL (0) | 2026.03.09 |
