🎯 1. Layered Architecture란?
Layered Architecture : 계층화 아키텍쳐
Layered Architecture는 어느 하나의 프레임워크에 종속적인 개념이 아니라
소프트웨어 개발에서 일반적으로 흔히 사용되는 아키텍쳐의 개념이다.
Layered Architecture는 각 구성 요소들이 '관심사의 분리(Separation of Concerns)'를 달성하기 위해
'책임'을 가진 계층으로 분리한 아키텍쳐이다.
관심사의 분리 : 책임(관심사)을 기준으로 다른 책임(관심사)를 분리하는 것
※ 그렇다면, 관심사의 분리를 왜 할까?
하나의 계층에 관심사가 여러개가 존재한다면 해당 계층의 응집도가 떨어지고 결합도가 높아진다.
각 계층들을 관심사 기준으로 분리함으로써 계층의 응집도를 높이고 결합도를 낮출 수 있다.
이를 통해 재사용성과 유지보수성을 높일 수 있다.
따라서, Layered Architecutre를 사용하면,
관심사의 분리를 통해 재사용성과 유지보수성을 높일 수 있다.
🎯 2. Layered Architecture의 의존성
한 계층에서 자신의 책임외의 행위는 하위 계층에 의존적인 구조이다.
그러나 하위 계층은 상위 계층에 대한 어떤 지식이나 정보가 없어야 한다.
예를 들면, 사용자의 요청 & 응답을 처리하는 `Presentation Layer`에서는
내부 비즈니스 로직 수행 책임을 가지는 `Application Layer`를 의존한다.
이때 하위 계층인 `Application Layer`는 상위 계층인 `Presentation Layer`의 정보를 모른다.
단지 간접적으로 넘어온 데이터로 비즈니스 로직을 처리할 뿐이다.
3. 🎯 Layered Architecture의 예시
Layered Architecture에서 Layer의 수와 역할은 지정된 게 아니지만
소프트웨어의 설계와 개발에 있어 대부분 3-tier(3 계층) 또는 4-tier(4 계층)으로 계층을 구성한다.
우아한테크코스에서 Spring을 사용하여 진행한 '웹 자동차 경주' 미션의 계층을 기반으로
4-tier Layered Architecture의 예시를 설명하고자 한다.
(Layer의 이름 및 책임은 사람마다 차이가 있어서 일반적인 Layer 이름으로 예시를 들었다!)
🎯 4-tier Layered Architecture의 예시
4계층을 가지는 아키텍쳐는 다음과 같은 Layer를 가진다.
1. Presentation Layer
2. Business Layer
3. Persistence Layer
4. Database Layer
전체적인 계층도는 다음과 같다.
하나씩 어떤 계층인지 살펴보자.
Layer 이름을 외운다기 보다는, 해당 계층이 어떤 관심사(책임)를 가지는지 보는 것이 좋다!
✅ 3-1. Presentation Layer : 사용자의 요청 & 응답을 처리하는 책임
주 책임 : 사용자가 데이터를 전달하기 위해 화면에 정보를 표시하는 책임
주로 다음과 같은 역할을 가진다.
- 1. Client의 요청을 변환
- 2. 기본적인 요청 내용 검증
- 3. 수행 결과를 Client에 반환
✅ Presentation Layer 미션 예시 : WebRacingCarController
Presentation Layer인 `WebRacingCarController`는 다음과 같은 역할을 하고 있다.
@RestController
public class WebRacingCarController {
private final WebRaceService webRaceService;
public WebRacingCarController(final WebRaceService webRaceService) {
this.webRaceService = webRaceService;
}
@PostMapping("/plays")
public RaceResultResponse registerRaceResult(@Valid @RequestBody final GameInfoRequest gameInfoRequest) {
int savedRaceResultId = webRaceService.saveRaceResult(gameInfoRequest);
return webRaceService.createRaceResult(savedRaceResultId);
}
...
}
- 1. 클라이언트의 요청을 자바 객체로 변환한다.
- 사용자의 HTTP 요청을 스프링을 통해 GameInfoRequest 객체로 역직렬화한다.
- 2. 클라이언트의 HTTP 요청 내용을 검증한다.
- 사용자의 HTTP 요청을 스프링의 @Valid를 통해 검증한다.
- 3. 수행 결과를 Client에 반환한다.
- Application Layer(RaceService)에서 비즈니스 로직을 수행한 결과를 RaceResultResponse를 통해 스프링이 직렬화하여 Client에 반환한다.
✅ 3-2. Business Layer : 비즈니스 로직을 수행하는 책임
주 책임 : 애플리케이션 요구 사항, 비즈니스 로직을 수행하는 책임
✅ Business Layer 미션 예시 : WebRaceService
@Service
public class WebRaceService {
private final CarRepository carRepository;
private final RaceResultRepository raceResultRepository;
private final NumberGenerator numberGenerator;
public WebRaceService(final NumberGenerator numberGenerator, final CarDao carDao,
final RaceResultDao raceResultDao) {
this.numberGenerator = numberGenerator;
this.carRepository = carRepository;
this.raceResultRepository = raceResultRepository;
}
public int saveRaceResult(final GameInfoRequest gameInfoRequest) {
RacingCars carsAfterMove = race(gameInfoRequest);
RaceResultRegisterRequest raceResultRegisterRequest =
RaceResultRegisterRequest.create(gameInfoRequest.getCount(), carsAfterMove);
int savedPlayResultId = raceResultRepository.save(raceResultRegisterRequest);
carRepository.saveCars(carsAfterMove, savedPlayResultId);
return savedPlayResultId;
}
private RacingCars race(final GameInfoRequest gameInfoRequest) {
final String names = gameInfoRequest.getNames();
final RacingCars racingCars = RacingCars.makeCars(names);
final int tryCount = gameInfoRequest.getCount();
racingCars.moveAllCars(tryCount, numberGenerator);
return racingCars;
}
...
}
- '자동차 경주'라는 비즈니스 로직을 수행하고 Persistence Layer에 저장을 명령한다.
- Presentation Layer에서 변환해서 들어온 데이터 (gameInfoRequest)로 비즈니스 로직 수행
- 비즈니스 로직을 수행하기 위해 DB에 필요한 데이터를 얻기 위해 Persistence Layer에 요청을 보낸다.
- Persistence Layer에 전달할 데이터를 생성할 뿐, DB 관련 로직은 알지 못한다.
✅ 3-3. Persistence Layer : DB와 상호작용(데이터 CRUD)하는 책임
주 책임 : DB나 파일에 접근하여 데이터를 CRUD하는 책임
✅ Persistence Layer 미션 예시 : CarDao / CarRepository
@Repository
public class CarDao {
private final JdbcTemplate jdbcTemplate;
public CarDao(final JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save(final CarRegisterRequest carRegisterRequest) {
final SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
jdbcInsert.withTableName("CAR").usingGeneratedKeyColumns("id");
final SqlParameterSource params = new MapSqlParameterSource()
.addValue("name", carRegisterRequest.getName())
.addValue("position", carRegisterRequest.getPosition())
.addValue("play_result_id", carRegisterRequest.getPlayResultId());
jdbcInsert.execute(params);
}
...
}
- 실제 DB에 접근하여 DB에 데이터를 저장 및 관리한다.
- Business Layer에서 전달받은 데이터(CarRegisterRequest)를 받아서 DB에 접근하여 Car를 저장한다.
- 실제 SQL문을 사용하여 DB에 저장한다.
✅ 3-4. Database Layer : 실제 DB가 존재하는 계층
⚙️ application.yml
spring:
h2:
console:
enabled: true
datasource:
url: jdbc:h2:mem:testdb;MODE=MySQL
driver-class-name: org.h2.Driver
- H2, MySql 등 실제 DB가 위치한 계층
🎯 4. 웹 자동차 경주 미션 Layered Architecture 시나리오
✅ HTTP 요청
1. Client -> Presentation Layer
- HTTP Request(사용자 입력)이 자동차 이름, 시도 횟수를 담아 들어온다.
2. Presentation Layer -> Business Layer
- Presentation Layer에서 요청에 대한 검증을 거친 후 자바 객체로 역직렬화 된다.
- 역직렬화된 객체가 Business Layer에 전달된다.
3. Business Layer -> Persistence Layer
- Presentation Layer에서 전달받은 객체를 통해 비즈니스 로직을 실행한다.
- DB 로직 실행을 위한 객체(Dto, Entity)를 생성하여 Persistence Layer에 전달한다.
4. Persistence Layer -> Database Layer(H2 Database)
- Business Layer에서 전달받은 객체(Dto, Entity)를 통해 DB에 접근하여 CRUD를 수행한다.
✅ HTTP 응답
* Database Layer -> Pesistence Layer -> Business Latyer -> Presentation Layer -> Client
- DB로 부터 반환된 결과가 계층을 타고 변환 및 전달되면서 최종적으로 Client에게 전달된다.
🎯 4. 요약
Layered Architecture에서 중요한 것은 뭘까?
Presentation Layer, Business Layer 등 Layer들의 이름보다는
'Layered Architecture' 구조를 사용하는 이유와 각 Layer를 나누는 기준이 중요해보였다.
Layered Architecutre를 사용하는 이유는 애플리케이션의 재사용성과 유지보수성을 높이기 위해서이다.
먼저 각 Layer를 나누는 기준은 '관심사(책임)'이다!
관심사(책임)으로 각 Layer를 분리함으로써 각 계층이 격리된다.
그 결과로 각 계층의 응집도를 높이고 결합도를 낮춰서 재사용성과 유지보수성이 높아진다.
이러한 장점을 얻기 위해 Layered Architecture를 사용한다는 것이 중요하다!
다음에는 Layered Architecture를 사용하면
재사용성과 유지보수성이 높아지는 이유를 더 자세하게
Controller, Service, Repository, Dao의 개념과 함께 알아보도록 하겠다!
Reference
Layered Architecture Pattern - 계층화된 아키텍처 패턴, (n-tier - 2-tier, 3-tier, 4-tier)
백엔드 서버 아키텍처 — Application Layer 1. 개요와 기본 Variation
https://hudi.blog/layered-architecture/
'아키텍쳐' 카테고리의 다른 글
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (2) 멀티 모듈 구성하기 (1) | 2024.02.02 |
---|---|
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (1) MSA란? (0) | 2024.02.01 |
Controller와 Service 레이어 간 요청 & 응답 Dto 사용에 관하여 (2) | 2023.06.19 |
[아키텍쳐] 패키지 구조 : 계층형 VS 도메인형 어떤 것을 선택할까? (4) | 2023.05.06 |
[아키텍쳐] Service, Repository가 왜 필요할까? (0) | 2023.04.24 |