HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
♥️
2기 최종 프로젝트 팀별 공간
/
팀 02 : 머쓱한녀석들
팀 02 : 머쓱한녀석들
/
🎏
BackEnd
/
📓
백엔드 컨벤션 및 전략
📓

백엔드 컨벤션 및 전략

들어가기에 앞서 1. 폴더 구조2. 테스트 전략3. 예외 처리 전략4. DTO ↔ Entity 변환 전략5. EndPoint 규칙6. 로깅 전략 7. Git Branch 전략 8. Validation 전략

💡
OOP, CleanCode를 지향하자 테스트도 프로덕트 코드처럼 생각하자.

들어가기에 앞서

💰
객체 지향 생활 체조 원칙
🪝
Clean Code
플레이그라운드
NEXTSTEP에서 개발자들을 위해 디자인된 강의를 수강해보세요.
플레이그라운드
https://edu.nextstep.camp/c/9WPRB0ys/
플레이그라운드
JPA Entity에서 일급 컬렉션 사용하기
최근 프로젝트를 진행하던 중 두 Entity를 양방향으로 묶고, 로직을 추가하던 중에 @OneToMany 부분의 List를 가공해야 하는 일이 생겼습니다.컬렉션을 가공할 일이 생기면 가장 먼저 떠오르는 것은 일급 컬렉션인데요.지금까지 그럴 일이 없어서인지 한번도 엔티티 안에서 일급 컬렉션을 사용해 본 적이 없었다는 것을 깨달았습니다. 상황은 다음과 같았습니다.
JPA Entity에서 일급 컬렉션 사용하기
https://wbluke.tistory.com/23
JPA Entity에서 일급 컬렉션 사용하기
 

1. 폴더 구조

  • Presentation - Application - Domain - Infrastructure
- commmon - exception - domain - config - member - presentation - memberController - Application - dto - CreateMemberRequest - MemberResponse - memberService - entity - Member - MemberRepository - infrastructure - s3 , querydsl
 

2. 테스트 전략

  • 단위 테스트는 필수
  • 테스트 템플릿
    • given when then 주석붙이기
    • Fixture 관리
  • 비즈니스 로직 테스트는 통합 테스트를 이용해보자
    • @SpringBootTest
  • jacoco , sonarcloud 사용
    • 도입하고 커버리지를 조금씩 올리자
  • `@DisplayName("저장 성공")
    • save_success()
save_success save_duplicateName_fail (유저 저장 성공) (이름 중복으로 인한 실패)
 

3. 예외 처리 전략

  • Enum errocode
    • (A001 , HttpStatus.NotFound , “존재하지 않은 유저입니다” )
      • 보내는 메시지의 경우 예외 안에 있는 메시지를 보내도록
public class BusinessException extends RuntimeException { private ErrorCode errorCode; public BusinessException(String message, ErrorCode errorCode) { super(message); this.errorCode = errorCode; } public BusinessException(ErrorCode errorCode) { super(errorCode.getMessage()); this.errorCode = errorCode; } public ErrorCode getErrorCode() { return errorCode; } } @JsonFormat(shape = JsonFormat.Shape.OBJECT) public enum ErrorCode { // Common INVALID_INPUT_VALUE(HttpStatus., "C001", " Invalid Input Value"), METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"), INTERNAL_SERVER_ERROR(500, "C004", "Server Error"), INVALID_TYPE_VALUE(400, "C005", " Invalid Type Value"), HANDLE_ACCESS_DENIED(403, "C006", "Access is Denied"), // Member EMAIL_DUPLICATION(400, "M001", "Email is Duplication"), LOGIN_INPUT_INVALID(400, "M002", "Login input is invalid"), // Coupon COUPON_ALREADY_USE(400, "CO001", "Coupon was already used"), COUPON_EXPIRE(400, "CO002", "Coupon was already expired") private final String code; private final String message; private int status; ErrorCode(final int status, final String code, final String message) { this.status = status; this.message = message; this.code = code; } public String getMessage() { return this.message; } public String getCode() { return code; } public int getStatus() { return status; } }
  • 최상위 예외 : BusinessException
    • 도메인 예외 : UserException
      • 상세 예외 : UserDuplicateException , UserInvalidException
spring-guide/exception-guide.md at master · cheese10yun/spring-guide
스프링은 예외처리를 위해 다양하고 막강한 어노테이션을 제공하고 있습니다. 일관성 있는 코드 스타일을 유지하면서 Exception을 처리하는 방법에 대해서 소개하겠습니다. Error Response 객체는 항상 동일한 Error Response를 가져야 합니다. 그렇지 않으면 클라이언트에서 예외 처리를 항상 동일한 로직으로 처리하기 어렵습니다. Error Response 객체를 유연하게 처리하기 위해서 간혹 Map 형식으로 처리하는데 이는 좋지 않다고 생각합니다.
spring-guide/exception-guide.md at master · cheese10yun/spring-guide
https://github.com/cheese10yun/spring-guide/blob/master/docs/exception-guide.md
spring-guide/exception-guide.md at master · cheese10yun/spring-guide
Team_i6_comepet_BE/ExceptionMessage.java at c23d43e46b59ae99fa5cb271f66c2f90391ac44b · prgrms-web-devcourse/Team_i6_comepet_BE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters You can't perform that action at this time. You signed in with another tab or window.
Team_i6_comepet_BE/ExceptionMessage.java at c23d43e46b59ae99fa5cb271f66c2f90391ac44b · prgrms-web-devcourse/Team_i6_comepet_BE
https://github.com/prgrms-web-devcourse/Team_i6_comepet_BE/blob/c23d43e46b59ae99fa5cb271f66c2f90391ac44b/src/main/java/com/pet/common/exception/ExceptionMessage.java
Team_i6_comepet_BE/ExceptionMessage.java at c23d43e46b59ae99fa5cb271f66c2f90391ac44b · prgrms-web-devcourse/Team_i6_comepet_BE
 
  • custom Exception 사용
    • 유저를 예로
public class UserException extends BusinessException{ public UserException(String message, ErrorCode errorCode) { super(message, errorCode); } }
public class UserCustomException extends UserException { private static final ErrorCode errorCode = ErrorCode.USER_NOT_FOUND; public UserCustomException(String message) { super(message, errorCode); } }

4. DTO ↔ Entity 변환 전략

  • 라이브러리 사용하지 않고 DTO 자체 변환 메소드 구현해 사용
  • Controller에서 받은 request, response DTO를 그대로 사용
  • 변환 위치
    • DTO에서 반환하도록
      • from, toEntity
  • 후에 리팩토링 하는 식으로 진행
초식 - 의존방향 생각하기
초보 개발자가 놓치기 쉬운 의존 방향에 대해 이야기해 봤습니다.참고 자료: 왕파라미터 사용하지 않기 - https://youtu.be/MIYwej-VodE
초식 - 의존방향 생각하기
https://youtu.be/cPdB-UBAVn8
초식 - 의존방향 생각하기
notion image
변경에 유연한 설계, 우리는 2가지 종류의 DTO를 쓴다!
안녕하세요 깃-들다의 손너잘 입니다. 이번 글에서는 깃들다의 설계중에 DTO와 관련된 이야기를 해보고자 합니다. 여러분은 DTO를 어떤식으로 많이 사용하시나요? 아마 많은 프로젝트에서 View ↔ Controller ↔ Service, 혹은 DAO ↔ Service 와 데이터를 주고받을 때 사용하실겁니다. 저희도 역시 마찬가지로 View ↔ Controller ↔ Service 간의 데이터 이동시 DTO를 이용하는데요, 깃들다의 경우 View ↔ Controller, Controller ↔ Service 에서 각각 서로 다른 DTO를 사용합니다.
변경에 유연한 설계, 우리는 2가지 종류의 DTO를 쓴다!
http://tech.pick-git.com/%EB%B3%80%EA%B2%BD%EC%97%90-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%84%A4%EA%B3%84,-%EC%9A%B0%EB%A6%AC%EB%8A%94-2%EA%B0%80%EC%A7%80-%EC%A2%85%EB%A5%98%EC%9D%98-DTO%EB%A5%BC-%EC%93%B4%EB%8B%A4/
변경에 유연한 설계, 우리는 2가지 종류의 DTO를 쓴다!
 

5. EndPoint 규칙

  • Rest API Best Practice로 따라가자
    • 단수 지양
    • 복수 지향
    • 동사 지양
    • 명사 지향
(번역) RESTful API Designing guidelines - The best practices
RESTful API Designing guidelines - The best practices 번역글 입니다. Facebook, Google, Github, Netflix와 같은 거대한 테크기업은 API를 통해서 개발자들과 프로덕트들이 자신들의 데이터를 사용할 수 있도록 하고, 그들을 위한 플랫폼이 되었다. 비록 당신이 다른 개발자들과 프로덕트를 위한 API를 개발하고 있지 않더라도, 잘 만들어진 API를 갖고 있는 것은 당신의 어플리케이션을 위해서도 좋다.
(번역) RESTful API Designing guidelines - The best practices
https://wayhome25.github.io/etc/2017/11/26/restful-api-designing-guidelines/
(번역) RESTful API Designing guidelines - The best practices
  • /api/ 를 prefix로 붙여주자
 

6. 로깅 전략

  • 커스텀 예외는 어떤 레벨로 찍을까?
    • error → Exception (예상하지 못한 에러는 error)
    • warn → 커스텀 예외 (예상할 수 있는 에러는 warn)
      • 원래는 info인듯하나 편의성을 위해 warn으로 설정
  • SQL 로깅까지
  • 비동기 로깅 → logback , log4j
  • cloudwatch 로그 연동 및 슬랙에 error시 알람 올 수 있도록
AWS CloudWatch Logs Dashboard 구성
다음과 같은 기능들을 제공한다. 애플리케이션 모니터링 시스템 전반의 성능 변경 사항에 대응 리소스 사용률 최적화 운영 상태에 대한 통합된 보기를 확보하는데 필요한 데이터 제공 로그, 지표 및 이벤트 형태로 모니터링 및 운영 데이터를 수집 AWS 리소스, 어플리케이션 및 서비스에 대한 통합된 뷰 제공 좌측 대시보드에서 대시보드 생성하기를 선택한다.
AWS CloudWatch Logs Dashboard 구성
https://xlffm3.github.io/devops/cloudwatch/
AWS CloudWatch Logs Dashboard 구성
Log4j2 및 Logback의 Async Logging 성능 테스트 비교
이 글은 Pick-Git 기술 블로그 에 업로드한 글입니다. Java 및 Spring 진영에서 사용할 수 있는 Logging Framework는 Log4j와 Logback 및 Log4j2 등 다양합니다. Pick-Git을 개발하면서 팀원들과 어떤 Logging Framework를 선택해야할지 고믾이 많았습니다. Logging Framework 종류별 특징을 학습하는 것에서 그치지 않고, 직접 Logging Framework들의 비동기 로깅(Async Logging) 성능을 테스트해보고 결과를 비교했습니다.
Log4j2 및 Logback의 Async Logging 성능 테스트 비교
https://xlffm3.github.io/spring%20&%20spring%20boot/async-logger-performance/
Log4j2 및 Logback의 Async Logging 성능 테스트 비교
 

7. Git Branch 전략

Github 협업 전략
Github 협업 전략
 

8. Validation 전략

  • 도메인에서 하기에 복잡한 validation은 Validator 유틸성 클래스를 만들어서 진행
    • null 체크