Architecture
우리가 폴더 구조를 나누는 이유는 뭘까요??
저는 각 폴더마다 고유의 역할이나 책임이 있고 이를 효율적으로 분리해놓기 위해서라고 생각합니다.
그래야 이후에 또 작업을 진행할 때 있어서 한눈에 전체 구조를 파악하기 쉽기 때문입니다!
이를 곧 아키텍처라고 일컫습니다.
Architecture 는 뭘까요?
: 사실 아키텍처의 정의에 대해서 정답이 존재하지 않습니다.
따라서, 이런 흐름이구나 정도로 이해해주시면 좋을 것 같습니다.
- 시스템 구성 및 동작 원리를 나타낸 것
- 구성 요소 간의 관계 및 시스템 외부 환경과의 관계를 묘사하는 것
- 시스템의 전체적인 최적화를 목표로 하는 것
위 내용을 정리하면 "하나의, 서비스가 어떻게 구성되며 어떻게 동작된다"로 이해하시면 편하실 거 같습니다:)
그럼 Software Architecture 는요??
소프트웨어의 구성요소들 사이에서 서로 긴밀히 연관된 관계를 표현하고,
소프트웨어의 설계와 업그레이드를 통제하는, 간단히 말하면 프레임워크라고 칭할 수 있습니다.
크게 Layered, Event-driven, Microkernel, Microservices, space-based, Hexagonal 등이 있습니다.
Layered Architecture 를 선택한 이유!!!!
그럼에도 저는 이번 프로젝트에 있어서 Layered Architecture 를 선택하였습니다.
그 이유를 설명하기 전, 왜 해당 아키텍처를 선택했는지에 대해서 다른 아키텍처와 비교해서 간단하게 1줄 내로 설명드리겠습니다.
자세한 설명은 다음 URL을 참고해주시면 감사하겠습니다.
https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html
1. Event-driven: 중재자와 브로커로 주로 구성시키고, 이벤트 큐나 이벤트 채널과 같은 역할이 따로 필요없는 간단한 서비스를 만들 것이기 때문에
2. Microkernel: 특수적으로 비즈니스 기능을 처리하는 독립적인 플러그인 모듈을 두지 않는 간단한 서비스를 만들 것이기 때문에
3. Microservices: API REST 기반 토폴로지, 애플리케이션 REST 기반 토폴로지, 중앙 집중식 메시징 토폴로지 등 많은 구현방법이 있겠지만, 현재는 아키텍처를 중점으로 구현한다기 보다는 간단한 서비스라도 내부에 있는 데이터에 대해 알아보고 검증해보기 위해서
4. space-based: 애플리케이션 확장을 제한하는 요소를 최소화하는 분산 공유 메모리인 인메모리 데이터 그리드까지는 현재 쓰지 않을 것 이기 때문에
5. Hexagonal: 포트와 어댑터를 구성하고 관리하는 데 약간의 복잡성이 있어 초기 구축하는 데에만 시간적 비용이 발생할 수도 있기 때문에
그럼 왜 Layered Architecture를 썼는지 설명드리겠습니다.
- 가장 큰 이유로 관심사의 분리라고 말할 수 있습니다.
-> 이는 책임을 가진 각 계층별로 분리한 아키텍처입니다.
-> 만약 하나의 계층 내에 관심사(service, repository, domain)이 모두 존재한다면, 해당 계층의 응집도는 떨어지겠죠
-> 그렇지만, 각 계층들을 관심사를 기준으로 분리함으로써, 각 계층의 응집도를 높이고 결합도를 낮출 수 있습니다.
-> 위 관심사 분리를 통해 간단한 서비스에는 해당 아키텍처가 적합하다고 판단했습니다.
단, 모든 상황에 완벽한 아키텍처는 없다고 생각합니다.
왜냐하면 아키텍처 또한 효율적으로 만들어놓은 패턴인거지, 모든 상황에 딱 맞는 패턴은 존재하지 않다고 생각하기 때문입니다.
그리고, 여기에서 중요한 것은 Layered Architecture 의 사용 이유와 특징을 잘 이해하는 것이지, 설계한 아키텍처가 타당성 있는 구조라면 어떻게든 설계해도 상관없다고 생각합니다.
관심사의 분리 : 책임(관심사)을 기준으로 다른 책임(관심사)를 분리하는 것
결합도 : 서로 다른 모듈 간에 상호 의존하는 정도 또는 연관된 관계를 의미
응집도 : 모듈이 독립적으로 자체 기능만을 수행할 수 있는 정도를 의미
Layered Architecture
소프트 웨어 개발에 있어서 가장 일반적으로 사용되는 아키텍처입니다. 구성되는 계층의 숫자에 따라 N 계층 아키텍처 (N-tier Architecture) 라고도 합니다.
각 계층은 특정 역할과 관심사(화면 표현, 비즈니스 로직 수행, DB 수행 등) 별도로 구분(관심사의 분리)됩니다.
즉, 특정 계층의 구성요소는 해당 계층에 관련된 기능만을 수행합니다. 이를 통해 높은 유지보수성과 테스트라는 장점이 존재하는 것이죠
4-Tier Layered Architecture
각 계층에는 고유한 역할과 책임을 둡니다. Layered Architecture 패턴에서 특정해서 유형을 설명하고 있지는 않지만, 아래처럼 4개의 계층으로 흔히 구분합니다.
단, 비교적으로 단순한 애플리케이션에는 3개의 계층으로 나눌 수도 있는 반면, 크고 복잡한 애플리케이션에는 5개 이상의 계층으로도 나눌 수 있습니다.
위에서 부터 차례대로 설명드리겠습니다.
Presentation Layer
- 사용자의 데이터를 얻기 위해 시스템 내에서 화면에 정보를 표시하는 것을 주 관심사로 둡니다.
- 대표적인 구성요소로는 View, Controller가 있습니다.
Business Layer
- 기능 요구 사항을 위한 비즈니스 로직을 수행하는 것을 주 관심사로 둡니다.
- 대표적인 구성요소로는 Service, Domain Model 등이 있습니다.
Persistence Layer
- 애플리케이션의 영속성을 구현하기 위해, 데이터를 가져와서 데이터에 대해 다루는(값을 계산하거나, 집계)를 주 관심사로 둡니다.
- 대표적인 구성요소로는 Repository, DAO 등이 있습니다.
Database Layer
- 데이터 베이스 자체를 주 관심사로 둡니다.
- 대표적인 구성요소로는 데이터 베이스 종류인 MySQL, MariaDB 등이 있습니다.
해당 아키텍처는 아래방향으로 닫혀있는 구조를 띄어야합니다.
예를 들어, 프레젠 테이션 계층으로부터 사용자의 데이터 요청이 넘어오면 하위 계층들은 상위 계층이 하는 일을 알 필요가 없습니다.
CLOSED Layer
Layered Architecture의 중요한 특징으로 계층 책임 격리 라는 것이 있습니다.
만약에 사용자에게 단순한 요청(최소한의 게시물 단건 조회)가 들어온다면, Presentation 계층에서 다른 계층을 건너띄고 바로 Database 계층으로 이동해서 서로 상호작용 하면 되지 않을까요??
단순하게 이걸 생각해보면 불필요한 여러 계층을 거치는 것보다 훨씬 빠르다고 느끼실 수 있습니다.
하지만 Layered Architecture는 한 계층에서 이루어진 변경사항은 다른 계층의 Presentation 계층이 바로 Database 계층으로 접근하면, SQL에 대한 변경사항이 Business 계층과 Persistence 계층에 모두 영향을 끼치게 됩니다.
따라서 이는 곧 원점으로, 어떤 계층이 어떤 관심사를 맡고 있고, 어떻게 상호작용을 이루는지에 대해 종속성이 많아지는 복잡한 구조가 될 것입니다. 이렇게 된다면 추후에 테스트와 유지보수하기에는 굉장히 까다롭게 되는 구조겠죠..
즉, CLOSED Layer는 데이터를 격리 시켜, 아키텍처 내에서 각 계층 간 변경사항을 최소로 하게끔 동작하도록 도와주는 역할을 하는 것입니다! 최소한의 액세스 권한을 제한한다로 이해해주시면 편할 것 같습니다!
Layered Architecture Flow
검은색 화살표 : 화면을 통해 사용자의 데이터 요청이 들어왔을 경우, 해당 데이터를 찾기 위한 데이터의 흐름을 나타내고,
빨간색 화살표 : 데이터를 다시 사용자의 화면에 표시해주기 위한 데이터의 흐름을 나타냅니다.
Customer Screen -> 이 때, CLOSED Layer의 특징을 띄므로, Presentation 계층은 사용자가 요청한 데이터가 어디에 있는지, 그 데이터가 몇 개인지, 어떻게 추가적인 연산은 이루어지는 지? 알 수 없습니다. (알 수 없게 해야 합니다가 더 맞는 표현인 거 같기도 합니다.)
Customer Delegate -> 사용자의 해당 데이터 요청을 비즈니스 계층의 어떤 모듈이 처리할 수 있는지, 해당 모듈에 접근하는 전체적인 데이터 계약을 파악하는 역할을 합니다. ex) Spring Bean
Customer Object -> 사용자의 데이터 요청에 필요한 모든 정보를 집계하는 역할을 수행합니다.
Customer Dao, Order dao -> 실질적으로 필요한 데이터(고객, 주문 정보)를 SQL을 실행해서, 데이터베이스로부터 가져오는 역할을 수수행합니다.
주의 사항
아키텍처 싱크홀 안티 패턴
요청이 각 계층 내에서 무의미하게 통과됨(아무 로직도 수행하지 않고)으로써 여러 계층을 통해 흐르는 상황입니다.
중요한 점은 해당 패턴의 비율이 80-20 규칙을 확인해보는 습관을 기를 필요가 있다는 점입니다.
이게 뭐냐면 곧 '20%는 단순 통과 처리, 80%는 요청과 관련된 일부 비즈니스 로직을 포함'을 한번씩은 확인해보자는 것입니다.
다같이 혹시 무의미하게 통과되는 로직이 20% 이상으로 잡혀있는지 확인해보도록 합시다
또한, Layered Architecture는 계층의 분리와, CLOSED Layer를 통해 구성 요소의 관심사의 분리를 얻을 수 있었지만
구성 요소 간의 긴밀한 결합은 피할 수 없는 구조를 띄게 됩니다.
제 생각에 이는 곧 모놀리식 애플리케이션에 적합할 것 같습니다.
모놀리식 애플리케이션은 곧 대규모 애플리케이션의 경우 긴밀하게 연결되있기 때문에 확장이 어렵거나,
서비스의 문제가 발생했을 경우 애플리케이션 자체가 죽어버리고, 배포를 진행함에도 시간적 비용의 문제가 발생할 가능성이 있다고 생각합니다.
그럼에도, 모든 레이어에 대해서 비즈니스 테스트를 Presentation 계층이나 Business 계층을 모의함으로써 비교적 쉽게 진행할 수 있기 때문에 테스트 관점에서는 이점에서는 좋은 선택인 것 같습니다.
정리
Layered Architecture를 선택한 이유와 사용할 때 염려해야할 사항들을 정리해드리겠습니다.
- 각 계층 간의 격리를 통해 관심사의 분리를 얻을 수 있다. 따라서, 각 폴더 구조만의 역할과 책임을 띄게함으로써 한 눈에 애플리케이션 구조를 파악시킬 수 있다.
- CLOSED Layer의 특징을 띌 수 있도록 각 계층간의 단계를 건너띈 직접적인 접근은 피하자. 왜냐하면, 오히려 종속성을 띄우게 돼서 유지보수와 테스트하기 힘들기 때문에
- 데이터가 아키텍처 내에서 무의미하게 계층을 오고 가는 로직이 발생하면, 20-80 규칙을 확인해보는 습관을 기르도록 하자!
참고
https://www.oreilly.com/content/software-architecture-patterns/
https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html
https://madplay.github.io/post/coupling-and-cohesion-in-software-engineering
'Project > 너도나도' 카테고리의 다른 글
[너도나도] EP 6. JWT를 도입한 이유 & 생성 (0) | 2023.08.28 |
---|---|
[너도나도] EP 3. 카테고리 데이터 (0) | 2023.08.13 |
[너도나도] EP 2. 도메인 & 엔티티 설계 (0) | 2023.08.13 |
[너도나도] EP 1. 개발 계획 (0) | 2023.08.11 |