Skip to Content

Step 04. 품질 속성 — 고통을 재는 자

만화로 보는 요약 — 먼저 읽어보세요

만화로 보는 요약 — 먼저 읽어보세요

품질 속성은 구조를 움직이고, 측정 가능한 시나리오와 우선순위 선택을 통해 피할 수 없는 트레이드오프를 관리한다.

면접 실전 질문: ① 기능 요구사항만으로 구조를 정할 수 없는 이유는? ② 품질 속성 시나리오는 어떻게 쓰는가? ③ 모든 것을 좋게 만들 수 없는 이유는?


이 장의 질문: “좋은 아키텍처”라고 할 때 그 좋음은 무엇으로 재는가? 그리고 왜 모든 아키텍처 결정은 결국 무언가를 포기하는 결정인가?


1. 기능은 아키텍처를 결정하지 않는다

사고 실험 하나. 두 팀이 “주문을 받고, 결제하고, 정산한다”는 같은 요구사항 명세서를 받아 시스템을 만들었다. 한 팀은 단일 서버에 레이어드 모놀리스를, 다른 팀은 이벤트로 통신하는 여섯 개의 서비스를 만들었다. 둘 다 명세의 모든 기능을 통과한다. 적어도 명세된 정상 경로에서 두 시스템의 기능은 동일하다. 그런데 구조는 완전히 다르다. (장애가 났을 때의 동작은 다를 것이다. 그 차이가 바로 이 장의 주제다.)

이 사실이 말해주는 것은 하나다. 기능 요구사항은 아키텍처를 결정하지 않는다. 무엇을 하는가(what)가 같아도 구조는 천차만별일 수 있다. 그렇다면 구조를 실제로 결정하는 것은 무엇인가? 두 시스템의 차이는 이런 질문들에서 드러난다. 트래픽이 10배가 되면? 정산 규칙이 바뀌면 몇 개 모듈을 고쳐야 하나? 결제 서버가 죽으면 주문도 죽나? 신입이 코드를 이해하는 데 며칠 걸리나?

이 질문들의 답을 품질 속성(quality attributes)이라 부른다. 성능, 가용성, 변경용이성, 테스트가능성… 영어 접미사를 따서 흔히 “-ility들”이라 부르는 것들이다. Bass·Clements·Kazman의 고전 『Software Architecture in Practice』의 핵심 주장이 바로 이것이다.

아키텍처를 결정하는 것은 기능이 아니라 품질 속성이다. 기능은 어떤 구조 위에서도 구현될 수 있다. 그러나 품질 속성은 구조 그 자체가 허락하거나 금지한다.

이 책의 프레임과도 곧장 이어진다. 우리는 각 아키텍처를 “이전 방식의 고통”에서 태어난 것으로 설명하기로 했다. 그 “고통”의 정체가 바로 품질 속성의 결핍이다. 레이어드의 고통은 변경용이성과 테스트가능성의 결핍이었고, 모놀리스의 고통은 배포독립성의 결핍이었다. 고통에 이름을 붙일 수 있어야 처방을 평가할 수 있다. 이 장은 그 이름들의 사전이다.

2. 주요 품질 속성은 고통의 사전이다

전부 나열하면 수십 개다(ISO 25010 표준이 하나의 공식 목록을 제공한다). 여기서는 이 책의 여정에서 주인공이 될 일곱을 뽑아, 각각 “결핍되면 어떤 고통인가”로 정의한다.

변경용이성(modifiability) — 요구사항 하나를 반영하는 데 몇 곳을 고쳐야 하는가. 결핍의 증상: 한 줄짜리 정책 변경이 서른 개 파일 수정이 된다. 앞의 두 장(무기들, 의존성)이 처음부터 끝까지 이 속성을 위한 것이었다. Part 2에서: 레이어드의 고통이자, 모든 스타일의 기본 심사 항목.

테스트가능성(testability) — 시스템의 한 조각을 얼마나 싸고 빠르게 검증할 수 있는가. 결핍의 증상: “주문 한도 검증 로직”을 테스트하려면 DB를 띄우고 서버를 부팅해야 한다. 정책을 세부사항에서 분리했다면(DIP) 정책만 떼어 검증할 수 있다. Part 2에서: 헥사고날 아키텍처를 낳은 직접적 동기.

배포독립성(deployability) — 시스템의 일부를 나머지와 무관하게 릴리스할 수 있는가. 결핍의 증상: 정산 모듈 한 줄 고치고 시스템 전체를 재배포하며, 배포 일정을 전 팀이 협의한다. 비교적 최근에야 일급 속성으로 승격된 항목이다. 지속적 배포 문화가 이 속성의 몸값을 올렸다. Part 2에서: 마이크로서비스를 낳은 동기.

성능(performance) — 응답은 얼마나 빠르고(지연, latency), 단위 시간에 얼마나 처리하는가(처리량, throughput). 결핍의 증상: 피크 시간에 주문 API가 3초씩 걸린다. 지연과 처리량은 다른 축이다. 하나를 챙기다 다른 하나를 잃는 일도 흔하다.

확장성(scalability) — 부하가 커질 때 자원을 더해 감당할 수 있는가. 결핍의 증상: 트래픽 2배에 서버를 2배로 늘렸는데 처리량은 그대로다(공유 자원 병목).

가용성(availability) — 시스템이 살아서 응답하는 시간의 비율. “나인(9)“으로 세는 그 숫자다(99.9% = 연간 약 8.8시간 중단). 결핍의 증상: 결제사 점검 시간에 우리 서비스 전체가 함께 멈춘다. Part 2에서: 분산 시스템 장의 주인공. 일관성과의 트레이드오프(CAP)로.

보안(security) — 허가되지 않은 접근과 변조를 막는가. 결핍의 증상: 어느 날 갑자기 뉴스에 나온다. 다른 속성과 달리 아무도 명시적으로 요구하지 않아도 항상 요구되어 있는 속성이라는 점이 특징이다.

일곱 개 밖에도 이 책에서 계속 만날 이름들이 있다. 금융 도메인이라면 무결성(정합성 깨진 돈은 장애가 아니라 사고다), 팀 관점에서는 단순성/이해가능성(신입의 온보딩 시간)이다. 목록의 전모보다 중요한 것은 다음 두 절이다. 이 이름들을 측정 가능하게 만드는 법, 그리고 이들이 서로 싸운다는 사실.

3. 형용사는 요구사항이 아니다

“시스템은 빨라야 한다.” 이 문장은 요구사항이 아니다. 얼마나? 어떤 조건에서? 무엇이? 검증할 방법이 없는 형용사는 회의실에서 고개를 끄덕이게 할 뿐 설계를 움직이지 못한다.

Bass와 동료들의 처방이 품질 속성 시나리오(quality attribute scenario)다. 막연한 형용사를 여섯 조각의 구체적 문장으로 강제하는 틀이다. 자극원, 자극, 환경, 대상, 응답, 응답 측정치.

“시스템은 빨라야 한다” → “피크 시간대에(환경) 사용자가(자극원) 주문 생성을 요청하면(자극) 주문 API는(대상) 주문을 접수하고(응답) 99번째 백분위 기준 500ms 안에 응답한다(측정치).”

“장애에 강해야 한다” → “평상 운영 중(환경) 결제 외부사가(자극원) 무응답이 되면(자극) 주문 서비스는(대상) 주문을 ‘결제 대기’로 접수해두고(응답) 결제사 복구 후 5분 내 자동 재처리한다. 주문 접수 자체의 성공률은 유지된다(측정치).”

두 번째 예에서 보이듯, 시나리오를 쓰는 행위 자체가 설계를 시작한다. “결제사가 죽어도 주문은 받는다”고 쓰는 순간, 결제와 주문 사이에 비동기 경계가 필요하다는 구조적 결론이 따라 나온다. 측정 문장이 화살표 배치를 끌어낸다. 이것이 품질 속성이 “측정 언어”인 이유다. Part 2에서 각 스타일을 평가할 때, 우리는 “좋다/나쁘다”가 아니라 “이 시나리오는 통과하고 저 시나리오는 실패한다”로 말할 것이다.

이름 하나를 더 얹어두자. 시나리오가 요구를 재는 언어라면, 그 응답을 실현하는 수단에도 Bass는 이름을 붙였다. 전술(tactics)이다. 하트비트·이중화(가용성), 중개자 삽입·캡슐화(변경용이성)처럼, 품질 속성 하나의 응답을 담당하는 재사용 가능한 설계 수단이다. 이 책은 전술을 따로 카탈로그화하지 않는다. Part 2에서 만날 아키텍처 스타일들이 사실상 특정 전술들의 검증된 조합이라, 스타일을 보다 보면 자연스럽게 만나게 되기 때문이다.

4. 제1법칙, 모든 것은 트레이드오프다

품질 속성들이 사이좋게 공존한다면 아키텍처는 쉬운 일이다. 현실은 반대다. 속성들은 서로 싸운다. Ford와 Richards는 『Fundamentals of Software Architecture』에서 이것을 소프트웨어 아키텍처 제1법칙으로 선언했다.

“소프트웨어 아키텍처의 모든 것은 트레이드오프다.” 따름정리: 트레이드오프가 안 보인다면, 그것은 없는 게 아니라 아직 못 본 것이다.

고전적인 전선(戰線)들은 이렇다.

  • 성능 vs 변경용이성. 앞 장에서 배운 간접층(인터페이스, 경계)은 공짜가 아니다. 호출 한 단계, 매핑 한 번, 탐색 난이도 한 칸. 극단의 성능이 필요한 코드는 종종 경계를 무너뜨린 코드다.
  • 가용성 vs 일관성. 분산된 두 노드가 서로 연락이 끊겼을 때, 응답을 계속하면(가용) 데이터가 갈라지고, 멈추면(일관) 서비스가 죽는다. 분산 시스템 장에서 CAP 정리라는 이름으로 정면으로 다룬다.
  • 배포독립성 vs 정합성. 서비스를 쪼개면 각자 배포할 수 있지만, 하나의 트랜잭션이던 것이 여러 개의 “결과적으로 맞춰지는” 단계가 된다. 데이터 장의 주제다.
  • 보안 vs 사용성/성능. 인증 단계 하나, 암호화 한 겹이 모두 마찰이다.
  • 거의 모든 것 vs 단순성. 어떤 속성이든 그것을 구조적으로 보장하는 장치는 시스템을 복잡하게 만든다. 복잡성은 모든 트레이드오프의 공용 화폐다.

여기서 아키텍처 설계의 성격이 드러난다. Ford와 Richards의 표현을 빌리면, 목표는 최선(best)의 아키텍처를 찾는 것이 아니라 “가장 덜 나쁜(least worst)” 아키텍처에 도달하는 것이다. 모든 속성을 최대화하는 답은 존재하지 않으므로, 좋은 아키텍트의 질문은 “무엇을 얻을까”가 아니라 “무엇을 포기해도 되는가”다. Step 01의 정의(아키텍처 = 되돌리기 비싼 결정 + 근거)와 합치면, 그 근거(rationale)의 실제 내용물이 바로 이 교환 명세서다. “우리는 X를 얻기 위해 Y를 지불했다.”

5. 다 가질 수는 없으니 목록을 줄인다

트레이드오프의 실천적 결론은 하나다. 챙길 속성의 목록은 짧아야 한다. 모든 -ility를 지원하겠다는 아키텍처는 아무것도 약속하지 않은 것과 같다. 지원 장치들이 서로를 상쇄하고, 복잡성 청구서만 남는다. Ford와 Richards의 실무 조언은 목록을 가능한 한 적게, 한 자릿수로 추리라는 것이다.

무엇을 남기는가는 도메인이 정한다. 같은 “주문 시스템”이라도:

  • 은행/정산: 무결성 > 가용성. 돈이 맞지 않는 것보다는 잠시 멈추는 게 낫다.
  • SNS 피드: 가용성 > 일관성. 피드가 3초 늦는 건 아무도 모르지만, 앱이 안 열리면 모두가 안다.
  • 초기 스타트업: 변경용이성·배포속도 > 확장성. 아직 없는 트래픽보다 매주 바뀌는 요구사항이 진짜 부하다.

한 가지 함정을 조심하라. 요구사항 문서에 없다고 해서 요구되지 않은 것이 아니다. 암묵적 속성이다. 아무도 “보안이 필요하다”고 회의에서 말하지 않지만 유출되면 회사가 흔들리고, 아무도 “유지보수 가능해야 한다”고 티켓을 만들지 않지만 2년 뒤 그것이 개발 속도의 전부가 된다. 아키텍트 역할의 상당 부분은 명세서에 적히지 않은 이 속성들을 대변하는 일이다.


6. 흔한 오해 바로잡기

오해 1: “품질 속성 = 비기능 요구사항(NFR), 즉 부차적인 것.” “비기능(non-functional)“이라는 전통 용어 자체가 오해의 근원이다. “기능이 아닌 것”이라 불리는 순간 우선순위에서 밀린다. 실상은 정반대로, 1절에서 봤듯 구조를 결정하는 쪽은 이들이다. Ford와 Richards가 굳이 “아키텍처 특성(architecture characteristics)“이라는 새 이름을 만든 이유가 이 낙인을 피하기 위해서다.

오해 2: “일단 기능부터 만들고, 품질은 나중에 붙인다.” 속성마다 사후 이식의 난이도가 다르다는 게 정확한 답이다. 성능은 상당 부분 나중에 튜닝된다. 변경용이성과 테스트가능성은 구조 그 자체라서, 사후 이식의 실제 이름은 “재작성”이다. 가용성과 보안은 그 중간이다. 무상태 설계라면 다중 인스턴스와 로드밸런서로, 인증·암호화는 계층으로 어느 정도 덧댈 수 있지만, 그 덧대기가 싸게 먹히려면 무상태·신뢰 경계라는 구조적 선행 조건이 이미 갖춰져 있어야 한다. 결국 어느 속성이 구조적인지(늦출 수 없는지) 판별하는 것 자체가 첫 장의 “무엇을 먼저 결정해야 하는가” 질문이다.

오해 3: “좋은 아키텍처는 모든 속성이 우수하다.” 제1법칙 위반. 모든 속성이 우수하다는 주장은 트레이드오프를 아직 발견하지 못했다는 자백이다. 좋은 아키텍처는 모든 것이 우수한 것이 아니라 포기한 것이 명시된 것이다.

오해 4: “측정할 수 없는 속성도 목표로 삼을 수 있다.” 측정 불가능한 목표는 설계를 움직이지 못하고, 달성했는지 알 수도 없다. “확장 가능해야 한다”는 소망이고, “블랙프라이데이 10배 트래픽에서 p99 1초 유지”는 요구사항이다. 시나리오로 쓸 수 없다면 아직 요구사항이 아니다.


7. 요약, 그리고 Part 1을 닫으며

  • 기능은 아키텍처를 결정하지 않는다. 구조를 결정하는 것은 품질 속성이고, 각 아키텍처가 태어난 “고통”의 정체는 품질 속성의 결핍이다.
  • 핵심 속성은 변경용이성, 테스트가능성, 배포독립성, 성능, 확장성, 가용성, 보안이다. 그리고 도메인이 정하는 우선순위(금융이라면 무결성).
  • 형용사는 요구사항이 아니다. 품질 속성 시나리오(자극원·자극·환경·대상·응답·측정치)로 써야 설계를 움직인다.
  • 제1법칙은 이것이다. 모든 것은 트레이드오프다. 목표는 최선이 아니라 “가장 덜 나쁜” 아키텍처이고, 좋은 설계의 근거란 “X를 얻으려 Y를 지불했다”는 교환 명세서다.
  • 목록은 짧게(한 자릿수), 암묵적 속성(보안, 유지보수성)은 아키텍트가 대변한다.

이로써 Part 1의 도구 상자가 완성됐다. 정의(아키텍처 = 되돌리기 비싼 결정과 그 근거), 전략(변경의 파급을 가두라), 기하학(화살표의 방향을 통제하라, 곧 경계와 DIP), 그리고 이제 측정 언어(품질 속성 시나리오와 트레이드오프). 네 개의 렌즈를 전부 손에 쥐었다. 이 측정 언어의 종착지는 이 책 후반의 진화적 아키텍처 장이다. 품질 속성 시나리오를 자동 실행되는 검사로 만든 것이 거기서 만날 적합도 함수(fitness function)다. 측정 언어는 결국 자동화된 방어선이 된다.

다음 장 예고: 이제 역사가 시작된다. Part 2의 첫 장은 아키텍처가 없는 곳에서 출발한다. 구조가 부재할 때 소프트웨어가 자연히 도달하는 상태, Big Ball of Mud다. 미리 도발 하나. 그 논문의 요지는 “진흙공은 나쁘다”가 아니다. “진흙공은 계속 이긴다, 왜인가?”다.


원전

연도문헌이 장에서의 역할
1998/2021Bass, Clements & Kazman, Software Architecture in Practice (초판/4판)품질 속성 중심 설계론, 품질 속성 시나리오 6요소
2011ISO/IEC 25010품질 특성의 표준 분류 체계
2020Ford & Richards, Fundamentals of Software Architecture제1법칙(모든 것은 트레이드오프), “아키텍처 특성” 용어, least-worst, 목록 다이어트
Last updated on