본문 바로가기
해피 코딩/Spring

Layered Architecture Pattern? 그게 뭔데!

by happy-coding 2024. 8. 15.
Chater 1. 프로젝트에 대한 튜터님의 피드백 내용은 "프로젝트에 Layered Architecture 를 적용해 보세요! "
🔥내가 만든 코드의 문제점을 찾아보고 Layered Architecture 를 적용하여 프로젝트를 수정하고 발전시켜 보자!!

 

 

  • Chater 1. 과제 확인

😺 Blog: https://happy-coding.tistory.com/23


[ Layered Architecture ]

  • 소프트웨어 시스템을 논리적인 계층으로 분리하여 개발, 유지보수, 확장성을 용이하게 하는 디자인 패턴입니다.
  • 각 계층은 특정한 책임을 가지고 있으며, 다른 계층과 명확히 구분되어 있어야 합니다.
  • 정리: 각 구성 요소들이 관심사 분리를 달성하기 위해 책임을 가진 계층으로 분리한 아키텍쳐입니다.

[ 관심사 분리 ]

  • 관심사 분리를 해야하는 이유
    • 하나의 계층에 관심사가 여러개가 존재한다면, 해당 계층의 응집도가 떨어지고 결합도가 높아지게 됩니다.
    • 각 계층들을 관심사 기준으로 분리함으로써 계층의 응집도를 높이고 결합도를 낮출 수 있습니다.
    • 관심사의 분리를 통해 재사용성과 유지보수성을 높일 수 있다.

[ Layered Architecture의 의존성 ]

특정 계층의 구성요소는 해당 계층에 관련된 기능만 수행한다.

Layered Architecture에서 각각의 나뉘어진 수평 계층은 수직적으로 배치된다.

  • Persentation Layer (UI 계층)
    • 사용자가 시스템과 상호작용하는 계층입니다.
    • Presentation Layer 는 비즈니스 로직이 어떻게 수행되는지 알 필요가 없습니다.
    • 대표적인 구성요소는 View와 Controller가 있습니다.
  • Business Layer (Application 계층)
    • 비즈니스 로직을 처리하는 것에 주로 관심을 둡니다.
    • Persentation 계층과 Domian 계층을 연결합니다.
    • 대표적인 구성요소는 ServiceDto가 있습니다.
  • Persistence Layer (Domain 계층)
    • 비즈니스와 가장 크게 밀접한 연관을 갖습니다.
    • 데이터를 가져오고 다루는 것을 주로 관심을 둡니다.
    • 대표적인 구성요소는 EntityRepository가 있습니다.
  • Database Layer (데이터 베이스가 위치한 계층)
    • MySQL, MariaDB, PostgreSQL 등 데이터베이스가 위치한 계층을 의미합니다.
  • Infrastructure Layer (데이터 접근 계층)
    • 상위 계층을 지원하는 일반화된 기술적 기능을 제공합니다.
    • 애플리케이션에 대한 메시지 전송, 이메일 서비스, 도메인 영속화 등이 있습니다.
    • 대표적인 구성요소는 Interface가 있습니다

[ 문제 ]

  • 도메인 계층인 Product(Entity)에서 Application 계층인 RequestDto를 사용
    • UI -> Application -> Domain 계층 방향으로 흐르는 단방향 의존성 설계 실패
@Getter
@Entity
@NoArgsConstructor
public class Product {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  Long product_id;

  private String name;
  private Integer supply_price;

  public Product(ProductRequestDto requestDto) {
    this.name = requestDto.getName();
    this.supply_price = requestDto.getSupply_price();
  }
}

[ 해결 1 ]

@Setter 를 사용하여 계층 분리하기

 

  • Domain 계층의 Product 객체에 @Setter 를 추가
@Getter
@Entity
@Setter
@NoArgsConstructor
public class Product {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  Long product_id;

  private String name;
  private Integer supply_price;
}

 

  • Application 계층의 createProducts 메서드에서, Setter를 이용하여 접근
@CacheEvict(cacheNames = "productList_cache", allEntries = true)
public void createProducts(ProductRequestDto requestDto) {
  // Layered Architecture Pattern 적용 Setter 접근
  Product product = new Product();
  product.setName(requestDto.getName());
  product.setSupply_price(requestDto.getSupply_price());
  productRepository.save(product);
}
Layered Architecture를 적용하여 계층분리에는 성공했지만, Setter를 사용한 접근은 권장하지 않는다.
음.. 그렇다면 어떻게 해야 할까..? 🤔
@Builder를 사용해 보도록 하자!! 

[ 해결 2 ]

@Builder 를 사용하여 계층 분리하기

 

  • Domain 계층의 Product 객체에 @Builer, create 메서드추가
@Getter
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Product {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  Long product_id;

  private String name;
  private Integer supply_price;

  public static Product create(String name, Integer supply_price) {
    return Product.builder()
            .name(name)
            .supply_price(supply_price)
            .build();
  }
}

 

  • Application 계층의 createProducts 메서드에서, create 메서드를 이용하여 접근
@CacheEvict(cacheNames = "productList_cache", allEntries = true)
public void createProducts(ProductRequestDto requestDto) {
  productRepository.save(Product.create(requestDto.getName(), requestDto.getSupply_price()));
}
이로써 우리는 Layered Architecture 계층분리에 성공하였다. 추가로 Package도 계층에 맞춰 분리해 주도록 하자

[ Package 분리 ]

Package 분리 전, 분리 후 비교


Layered Architecture 를 공부하기 이전에는 코드가 문제없이 동작했기 때문에 크게 생각하지 못했던 부분인 것 같다. Layered Architecture 를 공부함으로써 계층 분리의 이점이 뭔지 알게 되었고, 개발은 혼자 하는 것이 아닌 함께하는 것이기 때문에 이러한 Pattern 을 알아두고 적용하는 습관을 만드는 것이 중요한 것 같다.

 

읽어주셔서 감사합니다 😊

 

😺 GitHub: https://github.com/mad-cost/Sparta-Chapter1-project