Chater 1. 프로젝트에 대한 튜터님의 피드백 내용은 "프로젝트에 Layered Architecture 를 적용해 보세요! "
🔥내가 만든 코드의 문제점을 찾아보고 Layered Architecture 를 적용하여 프로젝트를 수정하고 발전시켜 보자!!
- Chater 1. 과제 확인
😺 Blog: https://happy-coding.tistory.com/23
[ Layered Architecture ]
- 소프트웨어 시스템을 논리적인 계층으로 분리하여 개발, 유지보수, 확장성을 용이하게 하는 디자인 패턴입니다.
- 각 계층은 특정한 책임을 가지고 있으며, 다른 계층과 명확히 구분되어 있어야 합니다.
- 정리: 각 구성 요소들이 관심사 분리를 달성하기 위해 책임을 가진 계층으로 분리한 아키텍쳐입니다.
[ 관심사 분리 ]
- 관심사 분리를 해야하는 이유
- 하나의 계층에 관심사가 여러개가 존재한다면, 해당 계층의 응집도가 떨어지고 결합도가 높아지게 됩니다.
- 각 계층들을 관심사 기준으로 분리함으로써 계층의 응집도를 높이고 결합도를 낮출 수 있습니다.
- 관심사의 분리를 통해 재사용성과 유지보수성을 높일 수 있다.
[ Layered Architecture의 의존성 ]
특정 계층의 구성요소는 해당 계층에 관련된 기능만 수행한다.
- Persentation Layer (UI 계층)
- 사용자가 시스템과 상호작용하는 계층입니다.
- Presentation Layer 는 비즈니스 로직이 어떻게 수행되는지 알 필요가 없습니다.
- 대표적인 구성요소는 View와 Controller가 있습니다.
- Business Layer (Application 계층)
- 비즈니스 로직을 처리하는 것에 주로 관심을 둡니다.
- Persentation 계층과 Domian 계층을 연결합니다.
- 대표적인 구성요소는 Service와 Dto가 있습니다.
- Persistence Layer (Domain 계층)
- 비즈니스와 가장 크게 밀접한 연관을 갖습니다.
- 데이터를 가져오고 다루는 것을 주로 관심을 둡니다.
- 대표적인 구성요소는 Entity와 Repository가 있습니다.
- 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 분리 ]
Layered Architecture 를 공부하기 이전에는 코드가 문제없이 동작했기 때문에 크게 생각하지 못했던 부분인 것 같다. Layered Architecture 를 공부함으로써 계층 분리의 이점이 뭔지 알게 되었고, 개발은 혼자 하는 것이 아닌 함께하는 것이기 때문에 이러한 Pattern 을 알아두고 적용하는 습관을 만드는 것이 중요한 것 같다.
읽어주셔서 감사합니다 😊
😺 GitHub: https://github.com/mad-cost/Sparta-Chapter1-project
'해피 코딩 > Spring' 카테고리의 다른 글
[MSA] Spring Cloud Config (0) | 2024.09.28 |
---|---|
RabbitMQ 실습하기 (0) | 2024.08.16 |
[Redis] Spring Boot 프로젝트에 캐싱 적용하기 (0) | 2024.08.13 |
[MSA] API 게이트웨이 Spring Cloud Gateway (0) | 2024.08.05 |
[MSA] 로드 밸런싱 Ribbon (0) | 2024.08.04 |