계층 설계하기(Layered Architecture) - Controller, Servicee, Repository, Domain, Entity, DTO

JINNI·2024년 5월 18일
0

[TIL] Java+Spring

목록 보기
7/15

안드로이드 개발을 하면서 클린아키텍처, MVVM을 공부하고 적용했었다.
소프트웨어공학개론을 공부할 때는 디자인 패턴을 정말 중요하게 다뤘고..
기능을 구현하기 급급했던 과거와 다르게 코드의 가독성, 유지보수성 등을 고려하기 시작하니 어려웠지만 요상하게 더 흥미가 생겼다.
API 개발을 할 때도 마찬가지로 적절한 아키텍처 패턴과 디자인 패턴을 바탕으로 설계해야 한다는 건 마찬가지일 것이다.

아키텍처?

소프트웨어 아키텍처에서 일반적으로 발생하는 문제점들에 대한 일반화되고 재사용 가능한 솔루션. 큰 규모의 시스템 수준에서 발생하는 문제를 해결하기 위한 구조적인 지침 및 원칙
e.g. Layered Architecture, Client-server Architecture, Master-slave Architecture, Pipe-filter Architecture, MVC Architecture, Peer-to-peer Architecture 등

디자인 패턴?

소프트웨어 설계에서 자주 발생하는 문제를 해결하기 위한 재사용 가능한 해결책을 제공하는 것. 개별적인 클래스나 객체 수준에서 발생하는 문제를 해결


Layered Architecture

복잡한 시스템을 계층 구조로 구성하여 구현하는 방법으로, 시스템을 여러 개의 계층으로 분리하고 각 계층이 서로 독립적으로 동작하며 상위 계층에서 하위 계층으로의 의존만 존재하는 형태이다.

관심사를 분리해서 특정 레이어 내의 구성 요소는 해당 레이어와 관련된 로직만 처리

  • Presentation Layer : 모든 사용자 인터페이스와 브라우저 통신 논리 처리
  • Business Layer : 요청과 관련된 특정 비즈니스 규칙을 실행하는 역할
  • Persistence Layer : 어플리케이션의 영속성을 구현하기 위해 데이터 출처와 그 데이터를 가져오고 다루는 역할
  • Database Layer : 데이터베이스가 위치한 계층

작동 과정


Controller는 Service를 의존하고, Service는 Repository를 의존한다.
Spring에서는 Controller, Service, Repository 등 각각의 계층에 맞춰 서버 애플리케이션을 구축할 수 있게 지원하고 있다.

  1. HTTP 요청이 들어옴.
  2. DispatcherServlet을 통해 요청을 처리
  3. DispatcherServlet은 돌아온 응답에 대해 View Resolver 또는 HTTPMessageConverter를 통해 적절한 응답을 만들어 Client에게 응답
  • DispatcherServletPresentation layer 앞단에서 HTTP 프로토콜을 통해 들어오는 모든 요청을 중앙집중식으로 처리하는 Front Controller
    // Spring 구현부
    public class DispatcherServlet extends FrameworkServlet 
    public abstract class FrameworkServlet extends HttpServletBean
    public abstract class HttpServletBean extends HttpServlet
  • DispatcherServlet을 거친 사용자의 HTTP 요청은 다루기 편한 Java 코드의 형태로 Controller에 전달(처리에 적합한 Controller를 찾아냄)
  • Controller → Service → Repository를 거쳐 Database를 통해 데이터를 처리하고 다시 DispatcherServlet으로 응답을 전달

🤔 @Component 어노테이션

Spring에서는 계층 설계를 위해 계층별로 Annotation을 만들고, Spring Bean으로 관리될 수 있게 구현되어 있다.

@Component는 Spring이 사용자 정의 Bean을 자동으로 감지할 수 있도록 하는 주석으로, 명시적인 코드를 작성하지 않고도 Spring에서 @Component 로 주석이 달린 클래스가 있는지 애플리케이션을 스캔하고, 인스턴스화하고 지정된 종속성을 주입 및 필요한 곳에 주사한다.


Controller

Client에서 보내는 HTTP Request를 받아 Service 계층에 전달, Service 계층에서 처리한 응답을 받아 처리하는 Class

  • Controller임을 나타내기 위해 class 위에 @Controller 또는 @RestController 어노테이션을 붙이면 된다. API 개발 시에는 @RestController를 붙여야 함!

  • @RestController = @Controller + @ResponseBody

    • @ResponseBody는 Java 객체를 JSON 기반의 HTTP body로 변환

    • @RequestBody는 JSON 기반의 HTTP body를 Java 객체로 변환.
      e.g. POST 요청의 경우 본문의 내용을 매핑해서 Entity 객체를 생성한다.

      POST /api/post HTTP/1.1
      {
      "id": 1,
      "name": "user1"
      }
      
      entity.id == 1
      entity.name == "user1"
      entity.address == null
  • Controller의 method 위에 어떤 HTTP Method를 받을지에 따라 @메소드Mapping을 사용

    • name 지정 시 class 위에 선언된 @RequestMapping 뒤의 name으로 이어짐
      e.g. @RequestMapping("/health") @GetMapping("/v1") → /health/v1

      @RestController
      @RequestMapping("/health")
      public class HealthCheckController {
      
          @GetMapping("/v1")
          public Map<String, String> healthCheck() {
              // response를 만드는 방식
              Map<String, String> response = new HashMap<>();
              response.put("status", "v1 OK");
      
              return response;
          }

Service

비즈니스 로직을 다루는 부분으로 특히 데이터베이스 Transaction과 관련된 처리를 담당한다. 사용자의 요청에 따라 DB에 접근해 데이터를 추가, 삭제, 수정, 선택하는 등의 요청을 처리할 수 있어야 한다.

  • @Service 어노테이션을 붙여서 사용
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {

    private final MemberJpaRepository memberJpaRepository;

    public MemberGetResponse getById(Long id) {
        return MemberGetResponse.of(memberJpaRepository.findById(id));
    }
}

Repository

Database와 직접적으로 연결되는 계층. Repository 계층을 통해서만 DB와 통신하기 때문에 데이터를 안정적으로 관리할 수 있다.

  • @Repository 어노테이션을 붙여서 사용.
  • JPA를 사용하는 경우 JpaRepository를 사용해 쉽고 빠르게 개발할 수 있다. (JpaRepository를 사용하는 경우 @Repository 어노테이션 불필요)

Domain

프로덕트를 구성하고 있는 요소들. 비즈니스 로직에 관련된 모든 개념 모델.

🤔 Entity와 Domain의 차이

안드로이드 개발을 할 때 entity와 domain layer 내 model의 차이가 명확하지 않아 의문이었을 때가 있다. 이참에 제대로 짚고 넘어가보자면.

  • Entity는 DB 테이블과 매핑되어 DB에 저장될 수 있는 객체를 말한다. Domain 내에서 식별 가능한 개별적인 객체 또는 개념을 뜻한다. Domain의 핵심 데이터를 캡슐화하고 처리하기 위해 사용된다.
  • Domain은 비즈니스 영역을 추상적으로 나타내는 개념, Entity는 도메인 내에서 실제 개별 객체나 개념을 나타내는 것이다.
    e.g. 음식 배달을 할 때 도메인은 음식 주문, 메뉴 관리, 배달 관리 / 엔티티는 고객 엔티티 / 음식 엔티티

DTO(Data Transfer Object)

데이터를 전달하는 객체 역할. 데이터는 클라이언트로부터 들어온 요청 데이터와 서버에서 처리한 데이터를 응답해주는 응답 데이터가 될 수 있다.

✔️DTO를 사용하는 이유

  • DB에서 Entity를 직접 API의 response에 담으면, 요구사항에 맞는 정확한 data를 API Response로 내려주기 어렵다.
    e.g. 클라이언트가 특정 사용자의 이름과 나이 조회 요청 → DB에서 사용자를 조회(DB에서 조회한 내용이 Entity에 담김) → 해당 사용자가 갖고 있는 데이터 중 이름과 나이만 response에 담아야 함. → Entity를 그대로 response에 담기 어려움!
  • 데이터의 가공이 잦은 상황에서 Entity를 직접 데이터 교환에 사용하면 위험함.
    • Entity는 프로덕트를 구성하는 Domain의 일부이므로 함부로 변경되어서는 안됨
    • DB에 저장될 수 있는 사용자의 데이터 그 자체이므로 최대한 노출되지 않아야 함

✔️DTO 만드는 방법

  • @Data 어노테이션을 이용해 쉽게 만들 수 있음
  • 모든 파라미터를 받는 생성자가 필요한 경우 @AllArgsConstructor 사용
  • Java record 클래스를 이용하는 경우 위 두가지 어노테이션이 불필요함
// API 응답 객체 정의
@Data // lombok으로 사용할 수 있는 Data 어노테이션(getter/setter, 기본 생성자, toString())
// 여기서는 @Getter만 사용해도 작동함.
public class HealthCheckResponse {
    private static final String STATUS = "OK";
    private String status;

    public HealthCheckResponse() {
        this.status = STATUS;
    }
}


참고자료

33기 DO SOPT 서버 파트 2차 세미나 자료(배포 불가)
아키텍처 스타일과 디자인 패턴
소프트웨어 아키텍처 패턴
계층화 아키텍처 (Layered Architecture)
[Spring] @RequestBody / @ResponseBody 어노테이션 이란?
도메인과 엔티티의 차이점
인프런 질문.entity와 domain의 차이
자바의 Record로 DTO를 만들어보자

profile
천재 개발자 되기

0개의 댓글