-
Notifications
You must be signed in to change notification settings - Fork 0
Description
CHAPTER 1 '베스트 프랙티스'가 없다면?
아키텍트는 조직이 처한 상황과 환경에 대해 큰 그림을 그리는 사람들이므로 거의 대부분 문제에 독특한 어려움이 도사리고 있습니다.
누군가 지금 바로 이 상황과 정확히 똑같은 경험을 한 사람이 자기 블로그나 스택 오버플로에 글을 쓸 확률이 얼마나 될까요?
모든 문제가 하나하나 새로운 도전을 요하기에 어떻게든 문제를 해결하려는 중대한 의사 결정의 양편에 치우친 수많은 트레이드오프를 냉정하게 판단하고 평가할 때 아키텍트의 진가가 드러납니다.
아키텍트가 만들어낼 수 있는 최고의 설계는 나쁜 것 중에서 제일 나은 트레이드오프의 조합인 경우가 많습니다.
어느 한 가지 아키텍처 특성만 우월한 게 아니라, 다른 경쟁 아키텍처 특성도 균형이 다 잘 맞아야 프로젝트를 성공으로 이끌 수 있습니다.
1.1 왜 '하드 파트' 인가?
첫째, 어려움입니다.
아키텍트는 이전에 그 누구도 경험해보지 못한 난제에 끊임없이 직면해 의사 결정을 내리는, 대인 관계 및 정치적 환경에 시달리면서도 장기적인 영향을 미칠 만한 갖가지 기술 결정을 내리는 사람들입니다.
둘째, 단단함입니다.
아키텍트는 아키텍처와 설계를 구분하는데, 아키텍처는 구조에 관한 것이라 쉽게 달라지지 않지만 설계는 비교적 쉽게 변경됩니다.
1.2 소프트웨어 아키텍처에 관한 영원불변의 조언
소프트웨어 개발 생태계는 전혀 예상치 못했던 방향으로 확장하고 진화합니다.
새로운 기능이 다른 기능으로 이어지고 없던 기능이 불쑥 튀어나오기도 합니다.
시간이 흐르면서 생태계는 한 번에 하나씩 스스로를 완전히 대체합니다.
그래서 기술이나 상세 구현에 집중하는 대신, 아키텍트가 어떻게 의사 결정을 내리는지, 새로운 상황에 처했을 때 트레이드오프를 어떻게 객관적으로 평가할 것인지에 집중합니다.
1.3 아키텍처에서 데이터의 중요성
데이터는 소중한 것입니다. 데이터는 시스템 자체보다 더 오래갈 테니까요. - 팀 버너스-리Tim Berners-Lee
아키텍트와 DBA는 모놀리스 시스템을 분해하는 것과 같은 아키텍처의 큰 변화가 일어나도 비즈니스 데이터가 온전히 살아남아 가치를 창출할 수 있도록 만들어야 합니다.
여기서는 운영 데이터와 분석 데이터를 명확하게 구분하고 각각에 미치는 영향을 자세히 다룹니다.
운영 데이터
운영 데이터는 판매, 거래성 데이터, 재고 등 비즈니스 활동에 쓰이는 데이터입니다.
운영 데이터는 일반적으로 데이터베이스에서 데이터를 삽입, 수정, 삭제하는 OLTP(Online Transactional Processing) 성격의 데이터입니다.
분석 데이터
분석 데이터는 예측, 트렌드 분석, 기타 BI 용도로 데이터 과학자와 비즈니스 분석가가 사용하는 데이터입니다.
이 데이터는 장기적인 전략 수립과 의사 결정에 중요하게 활용됩니다.
1.4 아키텍처 결정 레코드
아키텍처 결정을 가장 효과적으로 문서화하는 방법은 ADR(Architecture Decision Records)을 활용하는 것입니다.
ADR은 아키텍처 결정이 기록된 짧은 텍스트로 작성합니다.
ADR의 포맷은 다음과 같습니다.
- Context: ADR이 다루는 문제를 간략히 기술하고 문제를 해결할 수 있는 대안을 열거한다.
- Decision: 확정된 아키텍처 결정과 결정하게 된 사유를 자세히 밝힌다.
- Consequence: 이 아키텍처 결정이 적용되면 어떤 결과가 발생하는지, 어떤 트레이드오프를 고려해야 하는지 기술한다.
1.5 아키텍처 피트니스 함수
아키텍트가 컴포넌트 관계를 파악해서 설계를 구체화한 다음에 다른 사름이 그렇게 설계한 대로 구현하도록 만들려면 어떻게 해야 할까요?
아키텍트는 자신이 정의한 설계 원칙이 정말 실현되는지 어떻게 확신할 수 있을까요?
이런 질문은 소프트웨어 개발에서 하나 이상의 부분을 조직적으로 관리/감독하는 아키텍처 거버넌스에 해당합니다.
여기서는 아키텍처의 구조를 다루므로 피트니스 함수로 설계와 품질 원칙을 자동화하는 방법을 비중있게 다룹니다.
1.5.1 피트니스 함수 사용하기
2017년 < Building Evolution Architectures > 에서 아키텍처 피트니스 함수라는 개념을
'어떤 아키텍처 특성이나 그것들을 조합한 아키텍처 특성의 무결성을 객관적으로 평가하는 임의의 매커니즘'이라고 정의했습니다.
(any mechanism that performs an objective integrity assessment of some architecture characteristic or combination of architecture characteristics)
임의의 메커니즘(any mechanism)
성능이나 확장성 같은 운영 아키텍처 특성은 아키텍처 구조를 테스트하는 전용 테스트 라이브러리로 평가합니다.
신뢰성과 복원성은 카오스 엔지니어링 프레임워크를 활용합니다.
객관적인 무결성 평가(Objective integrity assessment)
테스트, 모니터, 다른 피트니스 함수로 측정 가능한 객체의 값을 제공하는 방식이어야 합니다.
그 자체로 객관적으로 측정하기 어렵지만 다른 가능한 값들을 조합해서 파악할 수 있는 복합적인 아키텍처 특성도 잘 관찰해야 합니다.
(예: 민첩성은 다른 측정 가능한 특성인 배포성, 시험성, 배포 주기를 통해 식별)
만약 아키텍처 특성을 측정할 방법이 없다면 정의 자체가 모호하다는 증거입니다.
어떤 아키텍처 특성이나 그것들을 조합한 아키텍처 특성(Some architecture characteristic or combination of architecture characteristics)
피트니스 함수의 범위는 다음 두 가지로 분류됩니다.
- 원자적atomic: 하나의 아키텍처 특성만 처리
- 전체적holistic: 여러 아키텍처 특성이 조합 => 전체적 피트니스 함수로 확인
아키텍트는 아키텍처 특성의 예기치 않은 변화에 대비하기 위해 피트니스 함수를 구현합니다.
예로 탄력성은 폭증하는 유저 수를 감당하는 애플리케이션의 능력입니다.
아키텍트는 도메인을 속속들이 다 알 필요는 없지만 탄력성은 구조의 문제이므로 피트니스 함수의 범주에 속합니다.
그림 1-1은 아키텍트라면 누구나 피하고 싶은 유해한 안티패턴입니다.
Figure 1-1. Cyclic dependencies between components
코드 리뷰는 개발 주기상 너무 늦게 시작되므로 효과가 없습니다.
이 문제는 예제 1-1과 같은 피트니스 함수를 작성해서 컴포넌트 순환 참조를 방지하면 해결할 수 있습니다.
Example 1-1. Fitness function to detect component cycles
public class CycleTest {
private JDepend jdepend;
@BeforeEach
void init() {
jdepend = new JDepend();
jdepend.addDirectory("/path/to/project/persistence/classes");
jdepend.addDirectory("/path/to/project/web/classes");
jdepend.addDirectory("/path/to/project/thirdpartyjars");
}
@Test
void testAllPackages() {
Collection packages = jdepend.analyze();
assertEquals("Cycles exist", false, jdepend.containsCycles());
}
}JDepend라는 메트릭 도구로 패키지 간 디펜던시를 확인하는 코드입니다.
JDepend는 자바 패키지의 구조를 파악해서 순환 참조가 하나라도 발견되면 테스트를 실패 처리합니다.
이런 미시적인 것 외에 거시적인 구조를 검증해야 할 경우도 있습니다.
그림 1-2와 같은 레이어드 아키텍처를 설계할 때, 아키텍트는 관심사를 분리하기 위해 레이어를 나눕니다.
Figure 1-2. Traditional layered architecture
아키텍트가 이런 아키텍처를 설계한 타당한 이유를 그것을 구현하는 사람들이 임의로 침해하도록 내버려두는 건 장기적으로 볼 때 아키텍처의 건강을 해칩니다.
ArcUnit을 이용해 예제 1-2와 같은 피트니스 함수를 작성해 문제를 해결할 수 있습니다.
Example 1-2. ArchUnit fitness function to govern layers
layeredArchitecture()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
.layer("Persistence").definedBy("..persistence..")
.whereLayer("Controller").mayNotBeAccessedByAnyLayer()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
.whereLayer("Persistence").mayOnlyBeAccessedByLayers("Service")아키텍트는 다이어그램과 그 밖의 정보 아티팩트 외부에서도 아키텍처 원칙을 정립하고 그것이 잘 지켜지는지 지속적으로 확인할 수 있습니다.
.NET에서도 NetArchTest라는 도구가 있습니다.
피트니스 함수는 객관적인 결과를 얻는 것이 중요하지만 꼭 정적인 것을 의미하지는 않습니다.
true/false나 임계치 같은 비콘텍스트 값을 반환하는 피트니스 함수도 있고, 콘텍스트에 따라 다른 값을 반환하는 함수도 있습니다.
확장성을 평가할 때 동시 유저 수를 세어보고 유저별 성능을 측정하는 방식입니다.
수동으로 실행하는 피트니스 함수의 경우 사람이 직접 검증합니다.
배포 파이프라인은 수동 단계도 지원하므로 수동 피트니스 함수를 만들 수 있습니다.
수동 피트니스 함수는 실행하지 않으면 확인할 수 없으므로 가급적 자주 실행하는 것이 좋습니다.
코드, DB 스키마, 배포 구성, 피트니스 함수 어디서건 변경 발생 시 즉시 알아차릴 수 있게 배포 파이프라인을 구성하면 중요한 사내 거버넌스 작업을 두루 자동화할 수 있습니다.
피트니스 함수는 아키텍트가 다시 코딩을 할 수 있는 기회가 된다는 점에서 중요합니다.
빌드된 프로젝트를 상대로 언제든지 검증할 수 있는, 아키텍처의 실행 가능한 명세를 구축함으로써 아키텍트는 시스템을 이해하고 그것이 잘 발전되고 있는지 지켜볼 수 있습니다.
피트니스 함수의 과용은 금물입니다.
중요하지만 긴급하지 않은 원칙들을 실천할 수 있는 체크리스트를 만드는 게 좋습니다.
나쁜 건 알지만 시간이 없으니 그냥 하고 나중에 고치면 된다는 식으로 중요한 원칙들이 간과되는 일이 많습니다.
아키텍트는 코드 품질, 구조, 계속 실행되는 피트니스 함수에 반해 안정망이 허술해지지 않도록 규칙을 체계화함으로써 개발자가 그냥 지나칠 수 없는 품질 체크리스트를 작성합니다.
아툴 가완디가 쓴 < 체크! 체크리스트 > 는 항공기 조종사와 외과 의사 같은 전문직 종사자들이 체크리스트를 활용하는 방법을 소개합니다.
숙련된 프로라도 같은 일을 반복하고 또 반복하다 보면 간혹 빠뜨리고 지나치는 것들이 있습니다.
피트니스 함수는 아키텍트가 정의한 중요 원칙들이 적힌 체크리스트를 나타내며, 개발자가 길수로 지나치지 않게 보장하는 빌드 프로세스의 한 과정입니다.
1.6 아키텍처 vs. 설계: 정의는 간단명료하게
첫째,
아키텍트는 효과적인 결정을 하기 위해 아키텍처의 기본 원칙을 이해해야 합니다.
< 소프트웨어 아키텍처 101 > 에서 어떻게 보다 왜가 더 중요하다는 소프트웨어 아키텍처 제2법칙을 언급했습니다.
둘째,
아키텍처 개념에 집중함으로써 그 개념의 다양한 구현부에 대한 이야기는 건너뛸 수 있습니다.
아키텍트는 왜 비동기 통신을 선택했는지에 집중하고 상세 구현은 넘어갑니다.
셋째,
아키텍처 원칙에 집중하면 모든 것을 가능한 한 일반화할 수 있습니다.
핵심 개념들을 가장 간단하게 정의하면 다음과 같습니다.
서비스service
독립 실행 파일 형태로 배포된, 기능이 응집된 집합체입니다. 주로 분산 아키텍처에서 적용되는 개념입니다.
커플링coupling
한쪽을 변경하면 다른 쪽도 함께 변경해야 제대로 작동될 경우, 이 둘은 서로 결합된 것입니다.
컴포넌트component
비즈니스 또는 인프라 기능을 수행하는 애플리케이션의 아키텍처 구성 요소입니다.
패키지(Java), 네임스페이스(C#), 물리적 디렉터리 구조에 맞게 소스 코드 파일을 묶어 놓은 형태입니다.
동기 통신synchronous communication
비동기 통신asynchronous communication
오케스트레이션orchestrated coordination
주 임무가 워크플로 조정인 서비스, 즉 오케스트레이터가 포함된 조정 기법을 말합니다.
코레오그래피choreographed coodination
오케스트레이터가 없는 경우에는 워크플로 내부의 서비스들이 서로 긴밀하게 조정하면서 동작합니다.
원자성atomicity
워크플로의 전체 구성 요소가 일관되게 작동하면 원자적atomic이라고 합니다.
계약contract
두 소프트웨어 파트 간의 인터페이스, 메서드나 함수 호출, 통합 아키텍처 원격 호출, 디펜던시 등을 포괄적으로 가리킵니다.
두 소프트웨어 조각이 맞물리면 계약이 수반됩니다.
1.7 한빛가이버 사가
여기서 설명하는 기법과 트레이드오프는 기존 아키텍처에서 다루는 개발 테크닉이 아닌 기존 시스템의 문제를 살펴보는 방법으로 진행합니다.
고객은 한빛전자가 제조한 컴퓨터, TV, 스테레오 등의 전자 제품을 구입할 때 지원 플랜을 선택적으로 구매할 수 있습니다.
지원 플랜을 구매한 고객은 문제 발생시 티케팅 애플리케이션을 통해 티켓을 접수하고 한빛가이버 전문 기사는 고객을 방문해 제품을 수리하는 출장 서비스를 제공합니다.
한빛가이버 티케팅 애플리케이션의 4대 주요 유저는 다음과 같습니다.
- 관리자
- 고객
- 전문 기사
- 매니저
1.7.1 비티케팅 워크플로
- 관리자: 한빛가이버 전문 기사 추가, 기사의 스킬 세트, 위치, 가용성 정보 입력
- 고객: 한빛가이버 애플리케이션에 등록, 제품에 따른 지원 플랜 선택, 과금 내역 및 명세서 열람
- 시스템: 매월 요금 자동 과금
- 매니저: 재무 보고, 전문 기사 실적 보고, 티케팅 보고
1.7.2 티케팅 워크플로
- 고객이 고장 티켓 등록
- 가장 적합한 전문 기사 배정
- 전문 기사의 모바일 앱으로 티켓 전달
- 전문 기사 수리 예정 확인, 고객에게 알람 전달
- 전문 기사는 티켓 정보와 고객 위치 확인, 지식 베이스에 접속해 과거 수리 내역 참고
- 전문 기사는 수리 완료 후 티켓을 완료로 변경. 지식 베이스에 문제점과 해결 방법을 추가
- 티켓이 완료되면 고객에게 설문 링크가 전송
- 고객이 응답한 설문 정보는 시스템에 기록
1.7.3 현재 문제점
대규모 모놀리식 애플리케이션
티켓이 소실돼 점누 기사가 방문하지 않음
수리 방법을 모르는 기사가 배정됨
시스템 문제로 고객이 티켓을 등록할 수 없음
1.7.4 한빛가이버 아키텍처 컴포넌트
그림 1-3과 표 1-1은 현재 모놀리식 애플리케이션의 컴포넌트를 정리한 것입니다.
Figure 1-3. Components within the existing Sysops Squad application
Table 1-1. Existing Sysops Squad components
| Component | Namespace | Responsibility |
|---|---|---|
| Login | ss.login | Internal user and customer login and security logic |
| Billing payment | ss.billing.payment | Customer monthly billing and customer credit card info |
| Billing history | ss.billing.history | Payment history and prior billing statements |
| Customer notification | ss.customer.notification | Notify customer of billing, general info |
| Customer profile | ss.customer.profile | Maintain customer profile, customer registration |
| Expert profile | ss.expert.profile | Maintain expert profile (name, location, skills, etc.) |
| KB maint | ss.kb.maintenance | Maintain and view items in the knowledge base |
| KB search | ss.kb.search | Query engine for searching the knowledge base |
| Reporting | ss.reporting | All reporting (experts, tickets, financial) |
| Ticket | ss.ticket | Ticket creation, maintenance, completion, common code |
| Ticket assign | ss.ticket.assign | Find an expert and assign the ticket |
| Ticket notify | ss.ticket.notify | Notify customer that the expert is on their way |
| Ticket route | ss.ticket.route | Send the ticket to the expert’s mobile device app |
| Support contract | ss.supportcontract | Support contracts for customers, products in the plan |
| Survey | ss.survey | Maintain surveys, capture and record survey results |
| Survey notify | ss.survey.notify | Send survey email to customer |
| Survey templates | ss.survey.templates | Maintain various surveys based on type of service |
| User maintenance | ss.users | Maintain internal users and roles |
1.7.5 한빛가이버 데이터 모델
표 1-1 처럼 여러 컴포넌트로 구성되어 있지만 데이터베이스는 하나의 스키마로 모든 테이블과 관련 데터베이스 코드를 관리합니다.
표 1-2는 테이블 리스트, 그림 1-4는 ER 모델을 나타냅니다.
Figure 1-4. Data model within the existing Sysops Squad application
Table 1-2. Existing Sysops Squad database tables
| Table | Responsibility |
|---|---|
| Customer | Entities needing Sysops support |
| Customer_Notification | Notification preferences for customers |
| Survey | A survey for after-support customer satisfaction |
| Question | Questions in a survey |
| Survey_Question | A question is assigned to the survey |
| Survey_Administered | Survey question is assigned to customer |
| Survey_Response | A customer’s response to the survey |
| Billing | Billing information for support contract |
| Contract | A contract between an entity and Payment_Method Payment methods supported for making payment |
| Payment | Payments processed for billings |
| SysOps_User | The various users in Sysops |
| Profile | Profile information for Sysops users |
| Expert_Profile | Profiles of experts |
| Expertise | Various expertise within Sysops |
| Location | Locations served by the expert |
| Article | Articles for the knowledge base |
| Tag | Tags on articles |
| Keyword | Keyword for an article |
| Article_Tag | Tags associated to articles |
| Article_Keyword | Join table for keywords and articles |
| Ticket | Support tickets raised by customers |
| Ticket_Type | Different types of tickets |
| Ticket_History | The history of support tickets |
Metadata
Metadata
Assignees
Labels
Projects
Status