기능 요구사항을 잘 구현하면 좋은 소프트웨어가 되는 걸까?
예를 들어 쇼핑몰을 만든다고 해보자.
- 사용자는 상품을 검색할 수 있다.
- 장바구니에 상품을 담을 수 있다.
- 결제할 수 있다.
전부 제대로 동작한다. 그런데 동시에 사용자 10만 명이 들어오면 서버가 죽는다거나, 결제 정보가 유출된다거나, 기능 하나 추가할 때마다 코드 절반을 수정해야 한다면?
기능은 맞지만 좋은 시스템이라고 하기는 어렵다.
소프트웨어 아키텍처에서는 이런 문제를 아키텍처 특성(Architecture Characteristics) 이라는 관점에서 바라본다.
기능 요구사항은 "무엇을", 아키텍처 특성은 "어떻게"
기능 요구사항은 애플리케이션이 무엇을 해야 하는지를 설명한다.
사용자는 상품을 검색할 수 있다.
사용자는 주문을 취소할 수 있다.
사용자는 카드로 결제할 수 있다.반면 아키텍처 특성은 그 기능을 제공하는 시스템이 어떤 성질을 가져야 성공할 수 있는지를 말한다.
검색 결과는 빠르게 나와야 한다. → Performance
사용자가 갑자기 늘어나도 버텨야 한다. → Scalability
일부 서버가 죽어도 서비스되어야 한다. → Availability
결제 정보가 안전하게 보호되어야 한다. → Security
새로운 결제 수단을 쉽게 추가해야 한다. → Extensibility즉,
기능 요구사항이 What이라면 아키텍처 특성은 How well / Under what constraints에 가깝다.
책에서는 흔히 쓰는 **비기능 요구사항(Non-functional Requirement)**이라는 표현보다 Architecture Characteristics라는 표현을 사용한다.
이것들은 "기능이 아닌 부가적인 것"이 아니라, 경우에 따라서는 시스템의 성공 여부를 결정하는 핵심 요구사항이기 때문이다.
그런데 모든 품질 요구사항이 아키텍처 특성은 아니다
여기가 Chapter 4에서 개인적으로 제일 중요한 부분.
책에서는 어떤 요구사항을 아키텍처 특성이라고 부르기 위해 크게 세 가지 조건을 제시한다.
1. 도메인 기능 자체가 아닌 설계 고려사항이어야 한다.
2. 시스템의 구조에 영향을 미쳐야 한다.
3. 애플리케이션의 성공에 중요해야 한다.단순히
"우리 서비스는 보안이 중요합니다."
라고 말했다고 해서 무조건 보안이 핵심 아키텍처 특성이 되는 것은 아니다.
그 요구사항 때문에 시스템 구조가 달라지는가?
를 봐야 한다.
핵심은 "구조를 바꾸는가?"
예를 들어 두 서비스가 모두 카드 결제를 제공한다고 해보자.
서비스 A
외부 PG 업체를 이용한다.
우리 서비스
↓
PG API
↓
카드사우리 시스템은 카드 번호를 직접 저장하거나 처리하지 않는다.
물론 HTTPS나 인증 같은 기본적인 보안은 필요하다.
하지만 이를 위해 시스템 전체 구조를 특별하게 바꿀 필요까지는 없을 수도 있다.
서비스 B
카드 정보를 직접 처리한다.
사용자
↓
Payment API
↓
Payment Service
↓
암호화된 저장소이번에는 이야기가 달라진다.
- 결제 시스템을 다른 서비스와 격리하고
- 접근 권한을 별도로 관리하고
- 데이터를 암호화하고
- 감사 로그를 남기고
- 네트워크 구간도 분리해야 할 수 있다.
즉 Security라는 요구사항 때문에 시스템의 구조 자체가 달라진다.
이런 경우 보안은 명확한 아키텍처 특성이다.
어떤 요구사항이 코드 몇 줄의 문제가 아니라 시스템을 어떻게 나눌 것인가에 영향을 주기 시작하는 순간, 아키텍처의 문제가 된다.
왜 아키텍처 특성을 미리 알아야 할까
아키텍처 특성은 자연스럽게 아키텍처 선택을 밀어붙이는 힘이 된다.
예를 들어 요구사항이 이런 서비스가 있다고 해보자.
동시에 수백만 명이 접속할 수 있어야 한다.그렇다면 Scalability가 중요한 아키텍처 특성이다.
그러면 설계할 때부터 자연스럽게 이런 질문이 생긴다.
서버를 수평 확장할 수 있는가?
상태를 서버 내부에 가지고 있어도 되는가?
캐시는 어디에 둘 것인가?
데이터베이스가 병목이 되지 않는가?
트래픽을 어떻게 분산할 것인가?반대로 내부 직원 20명이 사용하는 어드민 서비스라면?
같은 수준의 확장성을 위해 시스템을 복잡하게 만드는 건 오히려 낭비일 수 있다.
그래서
Architecture Characteristic
↓
Architecture Decision
↓
System Structure라는 흐름이 만들어진다.
아키텍처 특성을 잘못 잡으면 필요하지도 않은 구조적 복잡성을 만들게 된다.
"좋은 특성"을 최대한 많이 넣으면 좋은 거 아닌가?
처음 보면 이런 생각도 든다.
확장성도 높고
가용성도 높고
보안도 강하고
성능도 빠르고
변경도 쉽고
배포도 쉽고
모든 게 좋으면 최고 아닌가?문제는 아키텍처에서 대부분의 특성이 공짜가 아니라는 것이다.
예를 들어 높은 가용성을 위해 서버와 DB를 여러 개 두면
Availability ↑
하지만
Cost ↑
Operational Complexity ↑
Data Consistency Complexity ↑가 될 수 있다.
강한 보안을 위해 모든 요청에 복잡한 인증과 암호화를 추가하면
Security ↑
하지만
Performance ↓
Complexity ↑가 될 수도 있다.
시스템을 작은 서비스로 잘게 나누면 변경이나 독립 배포가 쉬워질 수도 있지만
Deployability ↑
Scalability ↑
대신
Network Complexity ↑
Observability Difficulty ↑
Operational Cost ↑같은 문제가 따라올 수 있다.
결국 아키텍처에서는
모든 특성을 최대화하는 설계가 아니라, 우리 시스템에서 중요한 특성을 골라내는 것
이 중요하다.
대표적인 아키텍처 특성들
책에서는 아키텍처 특성을 크게 몇 가지 범주로 나누어 설명한다.
1. Operational
실제로 시스템이 운영될 때 중요한 특성.
Availability 얼마나 계속 사용할 수 있는가
Performance 얼마나 빠르게 응답하는가
Scalability 사용량 증가를 얼마나 감당할 수 있는가
Elasticity 트래픽 변화에 따라 얼마나 빠르게 확장/축소되는가
Reliability 예상대로 안정적으로 동작하는가
Recoverability 장애 이후 얼마나 복구할 수 있는가예를 들어 티켓팅 서비스라면 평소보다 특정 시간에 엄청난 트래픽이 몰리므로 Scalability와 Elasticity가 중요할 수 있다.
2. Structural
코드와 시스템 내부 구조에 관련된 특성.
Maintainability 얼마나 쉽게 유지보수할 수 있는가
Extensibility 기능을 얼마나 쉽게 확장할 수 있는가
Modularity 기능과 책임이 얼마나 적절히 나뉘어 있는가
Reuse 구성 요소를 얼마나 재사용할 수 있는가
Configurability 동작을 얼마나 쉽게 설정으로 변경할 수 있는가이 영역은 사용자 눈에는 잘 보이지 않는다.
하지만 서비스가 몇 년 동안 계속 개발된다면 굉장히 중요해진다.
오늘 기능을 빠르게 만드는 것보다
6개월 뒤에도 기능을 쉽게 추가할 수 있는 구조인가?
가 더 중요한 시스템도 있기 때문이다.
3. Cross-Cutting
시스템 전체에 걸쳐 영향을 미치는 특성도 있다.
대표적으로
Security
Observability
Authentication
Authorization
Privacy
Accessibility같은 것들.
특정 모듈 하나만 잘 만든다고 해결되지 않고 여러 컴포넌트와 계층을 가로질러 적용되기 때문에 설계 초반부터 고려해야 하는 경우가 많다.
같은 시스템에서도 무엇이 중요한지는 다르다
예를 들어 똑같은 "웹 서비스"라도 상황에 따라 아키텍처 특성이 완전히 달라진다.
은행
Security
Reliability
Availability
Auditability실시간 게임
Performance
Low Latency
Scalability
Availability사내 관리자 페이지
Maintainability
Simplicity
Deployability초기 스타트업 MVP
Time to Market
Simplicity
Modifiability따라서
"좋은 아키텍처는 무엇인가?"
라는 질문에는 사실 정답이 없다.
정확한 질문은
"이 시스템에서 가장 중요한 아키텍처 특성은 무엇인가?"
에 더 가깝다.
아키텍처는 결국 우선순위를 정하는 일이다
Chapter 4를 읽으면서 가장 크게 남은 건 아키텍처 특성의 종류 자체보다는 이 부분이었다.
아키텍처를 공부하면 처음에는 자꾸
마이크로서비스가 좋은가?
모놀리스가 좋은가?
이벤트 기반이 좋은가?
서버리스가 좋은가?처럼 구조 자체에서 출발하게 된다.
그런데 사실 순서는 반대일 수 있다.
Business / Domain
+
Architecture Characteristics
↓
Trade-offs
↓
Architecture먼저 시스템이 무엇을 해야 하는지 보고,
그다음 그 시스템이 성공하기 위해 어떤 성질이 특히 중요한지를 찾고,
그 특성을 만족시키기 위한 구조를 선택한다.
그래서 마이크로서비스가 좋은 아키텍처인 것도 아니고 모놀리스가 나쁜 아키텍처인 것도 아니다.
우리 서비스에서 중요한 것이
Scalability인지
Deployability인지
Maintainability인지
Security인지
혹은 그냥 Simplicity인지에 따라 선택이 달라진다.
결국 아키텍처 특성이란
한 줄로 정리하면,
아키텍처 특성은 기능 자체가 아니라, 그 시스템이 성공하기 위해 반드시 가져야 하는 중요한 성질이며 시스템의 구조적 결정을 만들어내는 요구사항이다.
그리고 어떤 요구사항을 만났을 때
"이거 중요한 요구사항인데요?"에서 끝나는 게 아니라
이건 도메인 기능인가?
이 요구사항이 구조에 영향을 주는가?
이게 정말 이 서비스의 성공에 중요한가?
이걸 얻는 대신 무엇을 포기해야 하는가?를 물어보는 게 아키텍처 관점에서의 사고인 것 같다.
결국 아키텍처는 좋은 것들을 전부 챙기는 기술이라기보다, 무엇을 중요하게 볼지 결정하는 기술에 가까운 듯.
레퍼런스
- Mark Richards, Neal Ford, Fundamentals of Software Architecture — Chapter 4, Architecture Characteristics Defined