Layered Architecture란 무엇일까요?
웹 개념을 접하다 보면 해당 키워드에 대해 자주 듣게 됩니다.
따라서 이번 아티클에서는 Layered Architecture에 대해 정리해보려고 합니다.
소프트웨어 아키텍처란?
우선 소프트웨어 아키텍처에 대해 이야기해보려고 합니다.
소프트웨어 아키텍처는 정말 간단하게 말하면 하나의 소프트웨어 구조입니다.
그렇지만 일반적으로 저희가 일상생활에서 이야기하는 구조와는 조금 다른 점이 존재합니다.
소프트웨어 아키텍쳐는 단순한 구조에서 그치지 않고 조금 더 고수준의 개념을 의미합니다.
즉, 소프트웨어 아키텍쳐는 구조 및 코드 배치를 초월해 구성 요소 간 협력, 의존성 등까지 설계하는 것을 포함합니다.
소프트웨어 아키텍처는 저울질의 결과물이다
이런 소프트웨어 아키텍처는 결국 저울질(trade-off)의 결과물입니다.
우리의 소프트웨어는 어떤 가치를 내세울 것인지, 어떤 문제를 해결할 것인지 등에 따라 아키텍처는 달라질 수 있습니다.
배달의민족과 요기요는 둘 다 동일한 배달 도메인을 대상으로 하는 서비스인데,
두 서비스가 사용하는 소프트웨어의 아키텍처는 완전히 동일할까요?
아닐 확률이 높습니다.
각기 상황이 다르기 때문입니다.
가령 배달의민족 서비스는 성능에 초점을, 요기요는 유지보수성에 초점을 맞출 수도 있죠.
즉, 모든 상황에 들어맞는 완벽한 아키텍처는 존재하지 않으며 trade-off를 따져 아키텍처가 구성됩니다.
그렇지만 이미 널리 사용되고 있으며, 범용적으로 적용해 볼 수 있는 아키텍처는 존재할 수 있습니다.
바로 Layered Architecture가 그 예시 중 하나입니다.
Layered Architecture란?
Layered Architecture란 말 그대로 여러 개의 레이어들로 구성된 아키텍쳐입니다.
Layered Architecture에서는 몇 개의 레이어가 필요한지는 명시하지 않습니다.
비즈니스나 소프트웨어 규모에 따라 레이어 개수 및 속성은 달라질 수 있으며,
따라서 n-tier Layered Architecture라고 불리기도 합니다.
그렇지만 일반적으로 산업에서 사용하는 것은 4-tier Layered Architecture이며, 아래와 같은 그림의 형태입니다.
위 그림에서는 총 4개의 계층이 존재하는데요,
각각의 계층이 무엇을 수행하는지는 명확하게 이해하지 않아도 됩니다.
중요한 것은 레이어 안에 무엇이 포함되는지가 아니라 레이어 간의 관계이니까요.
회원 관리 서비스를 예시로 이해해 보기
회원 관리 서비스를 예시로 간단하게 흐름을 이해해 보겠습니다.
사용자가 회원가입을 시도하는 상황입니다.
1. Presentation Layer
회원가입 요청은 먼저 Presentation Layer에 도달합니다.
해당 레이어에서는 말 그대로 Presentation(표현)의 역할을 하기 때문에 Request를 받고, 나중에 회원가입이 완료되었음을 표현하는 역할만 수행합니다. 그리고 Business Layer에게 실질적인 비즈니스 로직을 수행하라고 메시지를 보냅니다.
2. Business Layer
회원이 이미 존재하는지, 유효한 정보인지를 검사하는 등의 비즈니스 로직을 수행합니다.
그리고 이런 비즈니스 로직 수행이 완료되었다면 Persistence Layer에게 저장하라는 메세지를 보냅니다.
3. Persistence Layer
회원 정보를 어떻게 영속성으로 저장할지를 코드 레벨에서 다룹니다.
4. Database Layer
메모리나 디스크 등에 회원 정보를 어떻게 저장할지를 데이터베이스 기술(SQLServer 등)로 다룹니다.
관심사의 분리와 격리
이처럼 각 계층은 해당 계층과 관련된 작업만 처리하고, 처리할 수 없는 부분은 아래 계층에 위임합니다.
이것이 Layered Architecture의 중요한 특징 중 하나이며 이는 관심사의 분리를 적극 활용한 것이라 볼 수 있습니다.
그리고 또 한 가지 중요한 특징이 있습니다.
앞서 회원가입 예제에서 하나의 계층은 바로 아래 계층만 접근하는 것을 보셨나요?
Layered Architecture에서는 각 계층이 닫혀 있어야 합니다.
즉, 어느 계층이라도 하나의 계층을 뛰어 넘어서서 접근할 수 없습니다.
예를 들어, Presentation Layer에서 Persistence Layer에 접근하려면 무조건 Business Layer를 통해 접근해야 합니다.
그리고 이런 모든 기법은 레이어 간의 의존성을 줄이기 위함입니다.
항상 닫혀있어야 하는 건 아니다
그렇지만 앞서 말한 규칙이 항상 적용될 순 없습니다.
유틸리티 기능을 담당하는 어떤 계층(Services Layer)이 위 그림처럼 추가되었다고 해보겠습니다.
이러한 계층이 도입되면 앞서 말한 Layered Architecture의 기본 원리에 따라 Business Layer는 Persistence Layer로 직접 접근할 수 없습니다.
어떤 레이어가 도입되었냐에 따라 다르겠지만, 이런 구조는 불필요하게 엄격하다는 단점이 있습니다.
이것은 Layered Architecture의 전통적인 문제점이기도 합니다.
따라서 위 그림처럼 개방의 개념을 도입했습니다.
특정 레이어를 개방시킴으로써 request를 우회할 수 있게 합니다.
조금 더 구체적으로는, 다음과 같은 코드가 개방이라고 볼 수 있겠습니다.
@RestController
public class GameController {
private final GameService gameService;
private final GameRepository gameRepository;
// 생성자 생략
@GetMapping(path = "/plays")
public void play() {
doSomething();
gameRepository.save();
// Presentation Layer에서 Persistence Layer로 Direct Access
// 이런 경우 Business Layer는 Open 되어 있다고 할 수 있음
}
}
이처럼 Layered Architecture는 개방과 폐쇄의 개념을 적절히 혼합하는 것이 중요합니다.
싱크홀 안티패턴을 조심하라
Layered Architecture의 핵심은 데이터의 흐름이 레이어를 관통해야 한다는 것인데요,
만약 데이터가 레이어를 관통하기는 하지만, 별 다른 처리 로직이 없는 경우 문제가 생길 수 있습니다.
예를 들어 service가 요청을 받고, 단순히 Repository의 메소드를 호출하는 경우 등이 있을 것 같습니다.
이런 경우 마치 싱크홀을 마주한 것처럼 request가 푹 꺼진다고 표현하고,
이렇게 단순 통과처리 되는 로직이 많은 경우 이를 싱크홀 안티패턴이라고 합니다.
보통 정상적인 Layered Architecture의 경우 전체 request의 20% 정도만 단순 통과처리라고 합니다.
따라서 Layered Architecture를 사용하는 경우, 싱크홀 안티패턴을 마주하지 않도록 유의해야 할 것 같습니다.
참고 자료
https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html
'객체지향' 카테고리의 다른 글
우아한 객체지향 정리 (조영호님) (2) | 2023.04.07 |
---|---|
왜 상태와 행위를 한 곳에서 관리해야할까? (4) | 2023.03.19 |
[객체지향의 사실과 오해] 6장: 객체 지도 (0) | 2023.02.23 |
[객체지향의 사실과 오해] 5장: 책임과 메세지 (0) | 2023.01.14 |
[객체지향의 사실과 오해] 4장: 역할, 책임, 협력 (0) | 2023.01.13 |