유사 .NET 개발자였던 내게 갑자기 Spring Boot API 서버 개발 업무가 주어졌다. 이미 완성된 시스템에서 유지보수나 하던 내게 새로운 프레임워크로 처음하는 백엔드 개발 업무는 생소했다. 그래서 당연히 AI에게 도움을 요청했다. 그리고 어느정도 개발이 완료되어 출시를 앞둔 지금 느끼기에 AI가 설명해준 순서는 정말 정석이었다.

 

1. 요구사항 분석 및 도메인 모델 설계

  • 요구사항을 명확히 정의한 후, 도메인 모델을 설계합니다. 도메인 모델이란 시스템에서 사용될 엔티티(entity)와 그 관계를 정의하는 것으로, 실제 비즈니스 로직을 반영합니다.
  • 예를 들어, "유저가 상품을 주문한다"는 요구사항이 있다면 User, Product, Order와 같은 엔티티가 필요합니다.

: 제일 힘들었다. 요구사항이 수시로 바뀌고 수시로 회의를 하지만 아무도 이해하지 못한 그림으로 서로 이야기만 한다.

2. 엔티티(Entity) 클래스 설계

  • 객체 지향의 캡슐화 원칙에 따라 필요한 속성과 메서드를 가지는 엔티티 클래스를 만듭니다.
  • JPA를 활용해 데이터베이스 매핑을 설정하며, 엔티티 간의 관계도 명확히 설정합니다. 예를 들어, User와 Order는 @OneToMany 관계가 될 수 있습니다.

: 관계형 DB와 함께 설계를 진행했다. 외래키의 경우 단순히 키가 아닌 외래키의 대상이 되는 Entity를 멤버로 가진다.

3. 레포지토리(Repository) 인터페이스 생성

  • 데이터베이스에 접근하는 인터페이스를 Repository 패턴을 사용해 정의합니다. Spring Data JPA를 활용해 각 엔티티의 CRUD 기능을 담당할 레포지토리를 생성하며, 엔티티별로 필요한 커스텀 메서드도 추가합니다.

: Repository에서 DB의 데이터를 가져온다. 동시성 제어를 위해 비관적 락을 사용하였다.

4. 서비스(Service) 레이어 설계

  • 비즈니스 로직을 수행하는 서비스 클래스를 생성합니다. 서비스는 레포지토리에서 데이터를 조회하고, 비즈니스 규칙을 적용하여 필요한 경우 데이터를 처리합니다.
  • 이때, 서비스 계층이 도메인 로직의 핵심이 되도록 설계하고, 가능하면 @Transactional 어노테이션을 통해 트랜잭션 처리를 설정합니다.

: Circular 참조 문제가 발생하였다. A와 B가 각각 서로 서비스를 멤버로 가지면 안된다. 인터페이스를 상속받아 느슨한 결합을 한다.

5. DTO(데이터 전송 객체) 설계

  • DTO를 사용하여 엔티티와 API 응답 간의 매핑을 수행합니다. 클라이언트로 보내거나 클라이언트로부터 받는 데이터만을 포함하는 DTO를 만들어, 필요한 데이터만 노출합니다.
  • 예를 들어, UserDTO와 같은 객체를 만들어 User 엔티티를 그대로 노출하지 않고 필요한 데이터만 담아 전달합니다.

: DTO를 설계 후 API Parameter로 Json 객체로 받는다. Json 객체로 parameter를 받기에 REST의 형식은 POST다.

6. 컨트롤러(Controller) 설계

  • RESTful API를 제공하는 Controller 클래스를 생성하여 요청을 받아 처리합니다.
  • 클라이언트로부터 HTTP 요청을 받고, 필요한 경우 서비스 레이어로 해당 요청을 전달합니다. 요청을 받은 후 DTO로 변환해 응답합니다.

: API 서버의 직접적으로 유저와 통신하는 부분이다. URL을 정의하고 Controller는 서비스를 가지고 서비스는 Repository를 가진다.

7. Exception Handling 설계

  • @ControllerAdvice와 같은 어노테이션을 통해 전역 예외 처리기를 구현합니다. 비즈니스 로직에서 발생할 수 있는 예외들을 정의하고, 적절한 HTTP 상태 코드와 함께 사용자에게 명확한 에러 메시지를 반환할 수 있도록 합니다.

: 예외 발생 시 서버에 로그를 작성해도 되고 각 예외별 에러 코드를 정의하여 클라이언트에게 전송해도 된다.

8. 테스트 작성

  • 단위 테스트통합 테스트를 작성하여 각각의 클래스와 계층이 제대로 동작하는지 확인합니다. 특히 서비스와 컨트롤러 레이어는 @WebMvcTest와 같은 Spring의 테스트 어노테이션을 활용해 테스트합니다.
  • Mocking을 통해 서비스 계층에서 레포지토리를 모의(mock)하여 테스트할 수 있습니다.

: 아쉽게도 테스트 작성은 제대로 진행하지 못했다. C++과 다르게 어노테이션으로 쉽게 테스트를 할 수 있는 것 같다.

9. 리팩토링 및 추가적 설계 패턴 적용

  • 코드가 안정화되면, 객체 지향 설계 원칙에 따라 코드의 결합도를 낮추기 위해 의존성 주입(DI), 팩토리 패턴, 전략 패턴과 같은 설계 패턴을 추가 적용합니다.
  • 예를 들어, 특정 비즈니스 로직이 자주 변경되는 경우 전략 패턴을 통해 코드의 유연성을 높일 수 있습니다.

: 무에서 시작하다보니 미흡했던 설계가 눈에 보인다. 일정에 급급해 일단 만들기는 했지만 조금 더 간결하고 명확한 설계를 위해 개선점들이 보인다. 더 개선하고 싶었지만 이제 해당 업무에서 손을 떼므로 더이상 진행할 수 없는게 아쉽다.

+ Recent posts