Chọn Architecture Phù Hợp: Decision Framework & Trade-off

Bạn đã học 10 architecture pattern — từ monolith đến microservices, từ layered đến hexagonal, từ CQRS đến serverless. Mỗi bài viết trình bày một pattern với điểm mạnh, điểm yếu, và use case. Nhưng biết pattern không giống với biết khi nào nên dùng chúng.
Đây là phần khó nhất của software architecture: chọn lựa. Không phải vì thiếu option, mà vì mỗi option đều kèm theo trade-off. Monolith đơn giản hơn nhưng khó scale độc lập. Microservices scale tốt nhưng nhân đôi operational complexity. Clean architecture enforce boundary nhưng thêm indirection. Serverless loại bỏ ops work nhưng gặp cold start và vendor lock-in.
Không có "architecture tốt nhất." Chỉ có architecture tốt nhất cho constraint của bạn — team, domain, scale, timeline.
Trong bài capstone này, chúng ta sẽ build một systematic decision framework giúp bạn chọn, document, và evolve architecture decision một cách tự tin.
✅ Architecture là trade-off: CAP theorem, complexity vs flexibility, reversibility
✅ Decision framework: team size, domain complexity, scale, deployment constraint
✅ Architecture Decision Record (ADR) với template thực tế
✅ Evolutionary architecture: fitness function và incremental change
✅ Bắt đầu đơn giản rồi evolve: monolith → modular monolith → microservices
✅ Kết hợp pattern: CQRS trong một service, simple CRUD trong service khác
✅ Anti-pattern: resume-driven development, premature microservices, architecture astronaut
✅ Case study: startup nhỏ, SaaS đang growth, enterprise migration
✅ Architecture review checklist
Architecture Là Trade-off
Mindset shift quan trọng nhất trong architecture là: mọi decision đều là trade-off. Không có bữa trưa miễn phí. Khi bạn gain thứ gì đó, bạn lose thứ khác.
Trade-off Triangle
Mọi architecture decision cân bằng ba lực:
- Monolith tối đa simplicity, hy sinh independent scalability
- Microservices tối đa scalability và team independence, hy sinh simplicity
- Clean/Hexagonal architecture tối đa flexibility và testability, thêm structural complexity
- Serverless tối đa operational simplicity, hy sinh control và portability
Không architecture nào có cả ba miễn phí. Công việc của bạn là quyết định trade-off nào chấp nhận được dựa trên constraint.
CAP Theorem: Trade-off Của Distributed System
Khi hệ thống là distributed (microservices, event-driven, multi-region), CAP theorem ràng buộc lựa chọn của bạn:
| Property | Ý nghĩa |
|---|---|
| Consistency | Mọi read trả về write gần nhất |
| Availability | Mọi request nhận được response (dù có thể stale) |
| Partition Tolerance | Hệ thống tiếp tục hoạt động dù network failure |
Trong distributed system, bạn chỉ có thể guarantee hai trong ba khi network partition xảy ra:
- CP system (Consistency + Partition Tolerance): Trả error thay vì stale data. Ví dụ: ZooKeeper, HBase, banking transaction.
- AP system (Availability + Partition Tolerance): Trả potentially stale data thay vì error. Ví dụ: Cassandra, DynamoDB, social media feed.
Ý nghĩa thực tế: Hầu hết web application không cần strong consistency ở mọi nơi. Checkout flow cần consistency (CP), nhưng product recommendation có thể tolerate staleness (AP). Architecture tốt nhất dùng consistency model khác nhau cho các phần khác nhau của hệ thống.
Reversibility: Chiều Ẩn
Không phải mọi architecture decision đều rủi ro như nhau. Một số dễ reverse, số khác thì không:
| Decision | Reversibility | Cost để thay đổi |
|---|---|---|
| Chọn web framework | Trung bình | Vài tuần |
| Thêm caching layer | Cao | Vài ngày |
| Split thành microservices | Thấp | Vài tháng |
| Chọn database engine | Thấp | Vài tháng |
| Chuyển sang serverless | Trung bình | Vài tuần - tháng |
| Thêm event sourcing | Rất thấp | Vài tháng - năm |
Nguyên tắc chính: Quyết định irreversible thì cân nhắc kỹ. Quyết định reversible thì ra nhanh. Khi không chắc, chọn option giữ lại nhiều lựa chọn tương lai hơn.
Architecture Decision Framework
Thay vì tranh cãi về pattern trên lý thuyết, dùng framework có cấu trúc để map constraint vào pattern phù hợp.
Bước 1: Đánh Giá Constraint
Trả lời những câu hỏi này một cách trung thực:
Team Size và Experience
| Team Size | Mức độ phức tạp tối đa | Lý do |
|---|---|---|
| 1-3 developer | Monolith hoặc modular monolith | Không thể sustain overhead của distributed system |
| 4-8 developer | Modular monolith hoặc 2-3 service | Một số service boundary xuất hiện, nhưng giữ đơn giản |
| 8-20 developer | Microservices (có giới hạn) | Team cần independence; Conway's Law bắt đầu tác động |
| 20+ developer | Microservices với platform team | Cần standardization, shared tooling, service mesh |
Experience quan trọng không kém size. Team 5 senior engineer đã từng operate microservices có thể handle nhiều complexity hơn team 15 junior. Hãy thành thật về operational maturity của team.
Domain Complexity
| Domain Complexity | Architecture phù hợp | Ví dụ |
|---|---|---|
| Simple CRUD | Monolith, layered architecture | Blog, todo app, admin panel đơn giản |
| Moderate business logic | Modular monolith, clean/hexagonal architecture | E-commerce, SaaS dashboard |
| Complex domain | DDD + hexagonal/clean, bounded context | Insurance, healthcare, financial trading |
| Nhiều domain độc lập | Microservices với DDD | E-commerce + logistics + payments + analytics |
Domain càng phức tạp, bạn càng cần strong modeling pattern (DDD, aggregate, bounded context). Domain càng đơn giản, monolith với basic layering càng đủ dùng.
Scale Requirement
| Mức Scale | Architecture Approach |
|---|---|
| Hàng trăm user | Monolith trên single server |
| Hàng nghìn user | Monolith với caching, read replica |
| Hàng chục nghìn | Modular monolith hoặc selective service extraction |
| Hàng trăm nghìn | Microservices cho hot path, monolith cho phần còn lại |
| Triệu+ | Full microservices, event-driven, CQRS cho read-heavy path |
Quan trọng: Hầu hết application không bao giờ đạt đến scale cần thiết phải dùng microservices. Premature scaling là một trong những sai lầm phổ biến nhất. Monolith được optimize tốt với caching và read replica xử lý được load lớn hơn nhiều so với hầu hết team nghĩ.
Deployment và Operational Constraint
| Constraint | Ảnh hưởng đến Architecture |
|---|---|
| Single server / VPS | Monolith (docker-compose là tối đa) |
| Kubernetes cluster | Microservices trở nên khả thi |
| Serverless platform | Function-based, event-driven |
| Yêu cầu on-premise | Deploy đơn giản hơn, ít moving part |
| Multi-region | Cần distributed pattern, eventual consistency |
| Ngành regulated | Có thể cần strict boundary, audit trail (event sourcing) |
Time to Market
| Timeline | Lời khuyên Architecture |
|---|---|
| MVP / 2-4 tuần | Monolith, không cần bàn cãi. Ship nhanh, validate idea. |
| Sản phẩm đầu tiên / 2-3 tháng | Monolith có cấu trúc tốt, có thể modular |
| Sản phẩm mature / 6+ tháng | Cân nhắc service boundary dựa trên pain point thực tế |
| Enterprise / nhiều năm | Full architecture design với ADR và evolutionary plan |
Bước 2: Map Constraint Vào Pattern
Dùng decision matrix này. Tìm primary constraint và follow recommendation:
Bước 3: Validate Bằng Câu Hỏi
Trước khi commit vào một architecture, tự hỏi:
- "Team mình operate được không?" — Có skill để debug, deploy, và monitor architecture này không?
- "Khi fail thì sao?" — Architecture này xử lý partial failure thế nào?
- "Bắt đầu đơn giản hơn được không?" — Có version đơn giản hơn hoạt động được trong 6-12 tháng tới không?
- "Thay đổi đầu tiên sẽ là gì?" — Khi outgrow architecture này, thứ đầu tiên cần extract hoặc refactor là gì?
- "Có match cách team làm việc không?" — Conway's Law nói architecture sẽ mirror org structure. Bạn đang fight hay align với nó?
Architecture Decision Record (ADR)
Khi đã ra quyết định, viết nó xuống. Architecture Decision Record (ADR) là document ngắn capture context, decision, và consequence của architectural choice.
Tại Sao ADR Quan Trọng
- Bạn trong tương lai sẽ quên tại sao chọn approach này
- Team member mới cần context cho decision hiện tại
- Reverse decision dễ hơn khi biết reasoning ban đầu
- Post-mortem reveal liệu assumption có đúng không
ADR Template
# ADR-001: Dùng Modular Monolith Architecture
## Status
Accepted
## Date
2026-03-01
## Context
Chúng ta đang build e-commerce platform cho startup.
Team: 4 backend developer, 2 frontend developer.
Expected load: 1,000-10,000 daily active user năm đầu.
Domain: moderately complex (catalog, order, payment, shipping).
Chúng ta đã cân nhắc:
1. Monolith (single module)
2. Modular monolith (feature module với boundary rõ ràng)
3. Microservices (separate deployment per domain)
## Decision
Chúng ta sẽ dùng **modular monolith** với feature-based module
(catalog, order, payment, shipping) giao tiếp qua internal
interface, không direct database access.
## Consequence
### Positive
- Single deployment unit — simple CI/CD pipeline
- Module enforce boundary không có network overhead
- Có thể extract module thành service sau nếu cần
- Cả team work trong một codebase với clear ownership
### Negative
- Tất cả module share một database (cần schema boundary)
- Không thể scale module độc lập
- Module boundary discipline cần code review
### Risk
- Module có thể coupled theo thời gian nếu không discipline
- Single database có thể bottleneck ở 50K+ DAU
## Follow-up
- Review architecture ở milestone 10K DAU
- Cân nhắc extract payment module đầu tiên (security boundary)ADR Best Practice
- Giữ ngắn — Tối đa một trang. Nếu cần nhiều hơn, decision quá lớn; chia nhỏ ra.
- Đánh số tuần tự — ADR-001, ADR-002, v.v. Không bao giờ xóa; đánh dấu superseded.
- Ghi lại alternative đã cân nhắc — Đây là phần có giá trị nhất. Reader tương lai cần biết bạn không chọn gì và tại sao.
- Bao gồm consequence — Cả positive và negative. Mọi decision đều có downside.
- Lưu trong repo — Trong thư mục
docs/adr/, version-controlled cùng code. - Review định kỳ — Xem lại ADR mỗi 6 tháng. Assumption vẫn đúng không?
Evolutionary Architecture
Architecture tốt nhất không phải cái bạn chọn đúng từ ngày đầu — mà là cái evolve khi understanding của bạn tăng lên.
Evolution Path
Hầu hết hệ thống thành công đi theo evolution có thể dự đoán:
Insight quan trọng: Bạn không cần predict final architecture. Bạn cần design hệ thống có thể evolve hướng tới architecture đúng khi hiểu rõ hơn.
Fitness Function
Fitness function là automated check bảo vệ architectural quality khi hệ thống evolve. Hãy nghĩ chúng như test cho architecture.
| Fitness Function | Kiểm tra gì | Ví dụ Tool |
|---|---|---|
| Module dependency | Không circular dependency giữa module | ArchUnit, Dependency Cruiser |
| Layer enforcement | Controller không gọi repository trực tiếp | ArchUnit, eslint-plugin-boundaries |
| Response time | 95th percentile API response < 200ms | Load test trong CI |
| Deployment independence | Service A deploy mà không cần redeploy B | CI pipeline check |
| Database coupling | Service A không query table của Service B | Schema analysis |
// Ví dụ ArchUnit: enforce layered architecture
@AnalyzeClasses(packages = "com.example.shop")
class ArchitectureTest {
@ArchTest
static final ArchRule layerRule = layeredArchitecture()
.consideringAllDependencies()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
.layer("Repository").definedBy("..repository..")
.whereLayer("Controller").mayOnlyBeAccessedByLayers()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
.whereLayer("Repository").mayOnlyBeAccessedByLayers("Service");
}// Ví dụ eslint-plugin-boundaries (NestJS)
// .eslintrc.js
module.exports = {
plugins: ['boundaries'],
rules: {
'boundaries/element-types': [2, {
default: 'disallow',
rules: [
{ from: 'controllers', allow: ['services'] },
{ from: 'services', allow: ['repositories', 'domain'] },
{ from: 'repositories', allow: ['domain'] },
// domain không depend vào gì cả
]
}]
}
};Fitness function biến architectural intention thành enforceable rule. Không có chúng, architecture bị xói mòn với mỗi pull request vội vàng.
Strangler Fig Pattern
Khi migrate từ monolith sang service, dùng strangler fig pattern thay vì big-bang rewrite:
Phase 1: Route tất cả traffic qua facade
Phase 2: Extract service đầu tiên
Phase 3: Extract thêm service, monolith thu nhỏ dần
Quy tắc cho strangler fig migration:
- Không bao giờ dừng feature development — Migration diễn ra song song với công việc bình thường
- Extract theo bounded context — Không theo technical layer (đừng extract "tất cả database code")
- Bắt đầu với module ít coupled nhất — Module có ít dependency nhất với phần còn lại
- Giữ old code chạy — Route traffic dần dần; fallback nếu service mới có issue
- Xóa old code chỉ khi service mới đã proven — Chạy song song cả hai trước
Kết Hợp Pattern
Hệ thống thực tế không dùng một pattern duy nhất. Chúng kết hợp pattern ở nơi phù hợp nhất.
Pattern Combination Hiệu Quả
Tại sao pattern khác nhau cho service khác nhau?
- Catalog là simple CRUD — không cần DDD hay event sourcing. Layered architecture với basic validation là đủ.
- Order có complex business rule (promotion, inventory, fulfillment state) — DDD với aggregate model hóa tốt việc này.
- Payment cần complete audit trail và phải handle reconciliation — event sourcing capture mọi state change.
- Notification là stateless, event-triggered — hoàn hảo cho serverless function.
- Analytics là read-heavy với query pattern khác hoàn toàn so với write — CQRS read model optimize cho dashboard.
Guideline Khi Mix Pattern
- Match complexity với subdomain — Đừng apply DDD cho trang setting. Đừng dùng simple CRUD cho trading engine.
- Dùng event để connect service — Async communication (event) decouple service tốt hơn sync call (REST/gRPC).
- Standardize communication — Dù service dùng internal architecture khác nhau, dùng consistent API contract và event schema.
- Giữ pattern đơn giản nhất làm default — Bắt đầu mọi service mới bằng simple CRUD. Upgrade lên DDD/CQRS/event sourcing chỉ khi complexity đòi hỏi.
- Document pattern per service — ADR nên specify mỗi service dùng pattern nào và tại sao.
Architecture Anti-Pattern
Biết không nên làm gì quan trọng không kém biết nên làm gì. Những anti-pattern này phổ biến, hấp dẫn, và phá hoại.
Resume-Driven Development
"Mình dùng Kubernetes, Kafka, và microservices đi!"
"Tại sao? Mình có 500 user và 3 developer."
"...sẽ đẹp trên CV lắm."
Là gì: Chọn technology và pattern để build CV thay vì giải quyết problem.
Tại sao nguy hiểm: Hệ thống over-engineer tốn nhiều hơn để build, nhiều hơn để operate, và chậm feature delivery. Team dành hàng tháng build platform infrastructure thay vì ship feature.
Cách tránh: Hỏi "Mình có chọn cái này không nếu phải maintain với nửa team?" Nếu câu trả lời là không, nó quá complex.
Premature Microservices
Là gì: Bắt đầu với microservices từ ngày một của project mới, trước khi hiểu domain boundary.
Tại sao nguy hiểm:
- Bạn vẽ service boundary trước khi hiểu domain → vẽ sai
- Boundary sai tạo ra distributed monolith: service coupled chặt phải deploy cùng nhau
- Network overhead, distributed transaction, và operational complexity — tất cả với zero benefit
Cách tránh: Bắt đầu với modular monolith. Khi tìm thấy module thực sự cần independent deployment hoặc scaling, extract nó. Để boundary emerge từ experience, không phải từ whiteboard session ngày đầu.
"Nếu bạn không thể build monolith có cấu trúc tốt, điều gì khiến bạn nghĩ microservices sẽ tốt hơn?" — Simon Brown
Architecture Astronaut
Là gì: Over-abstract và over-design hệ thống để handle hypothetical future requirement có thể không bao giờ xảy ra.
Dấu hiệu bạn đang làm vậy:
- "Clean architecture" có 7 layer cho TODO app
- Bạn build "enterprise service bus" cho 2 service
- Codebase có nhiều interface hơn implementation
- Bạn design cho 10 triệu user khi có 100
Cách tránh: Follow YAGNI (You Aren't Gonna Need It). Build cho requirement hôm nay và growth quý tới. Không phải cho scale tưởng tượng 3 năm sau.
Distributed Monolith
Là gì: Microservices mà coupled chặt — share database, deploy cùng nhau, và không thể function độc lập.
Dấu hiệu:
- Thay đổi một service đòi hỏi thay đổi 3 service khác
- Service gọi sync call thành chain (A → B → C → D)
- Tất cả service share một database
- Không thể deploy một service mà không deploy tất cả
- Bug trong một service crash toàn bộ hệ thống
Cách tránh: Mỗi service phải own data riêng, deploy độc lập, và communicate async khi có thể. Nếu service không thể function khi service khác down, chúng không thực sự independent.
Golden Hammer
Là gì: Dùng cùng architecture hoặc technology cho mọi problem vì bạn thoải mái với nó.
"Mình dùng microservices cho mọi thứ — sản phẩm chính, internal tool, blog, và landing page."
Cách tránh: Evaluate mỗi project độc lập. Landing page không cần cùng architecture như financial trading system. Match solution với problem.
Case Study
Hãy apply decision framework vào ba scenario thực tế.
Case Study 1: Startup Giai Đoạn Đầu — TaskFlow
Context:
- Product: Project management SaaS (như Asana đơn giản hóa)
- Team: 3 developer (1 senior, 2 mid-level)
- Timeline: MVP trong 6 tuần, paying customer đầu tiên trong 3 tháng
- Expected scale: 100-1,000 user năm đầu
- Budget: Bootstrapped, chi phí infrastructure tối thiểu
Decision:
| Constraint | Assessment |
|---|---|
| Team size | Nhỏ (3 dev) — không thể afford operational overhead |
| Domain complexity | Trung bình — task, project, team, notification |
| Scale | Thấp — hàng trăm user |
| Time to market | Critical — phải ship nhanh |
| Deployment | Single VPS hoặc simple cloud deployment |
Architecture được chọn: Monolith với clean module boundary
taskflow/
├── src/
│ ├── modules/
│ │ ├── auth/ # Authentication module
│ │ ├── projects/ # Projects & tasks
│ │ ├── teams/ # Team management
│ │ └── notifications/ # Email & in-app notifications
│ ├── shared/ # Shared utilities, DB client
│ └── app.ts # Express/NestJS entry point
├── docker-compose.yml # Postgres + App
└── DockerfileADR excerpt:
Chúng ta chọn monolith vì team 3 người không thể sustain operational burden của distributed service. Module boundary enforce separation mà không có network overhead. Chúng ta sẽ extract notification module thành serverless function nếu email volume trở thành bottleneck.
Evolution plan:
- Hiện tại: Monolith deploy qua Docker trên single VPS
- Ở 5K user: Thêm Redis caching, database read replica
- Ở 20K user: Extract notification thành serverless function (event-driven)
- Nếu nhiều team hình thành: Cân nhắc modular monolith → selective extraction
Case Study 2: SaaS Đang Growth — DataPulse
Context:
- Product: Business analytics dashboard với real-time data ingestion
- Team: 12 developer chia 3 squad (Ingestion, Dashboard, Platform)
- Trạng thái hiện tại: Monolith đang trở nên đau đớn — deploy chậm, merge conflict, thay đổi của squad này break feature squad khác
- Scale: 50,000 daily active user, growth 20% mỗi quý
- Pain point: Deploy mất 45 phút, ingestion pipeline block dashboard development
Decision:
| Constraint | Assessment |
|---|---|
| Team size | Trung bình (12 dev, 3 squad) — cần independence |
| Domain complexity | Cao — ingestion, transformation, storage, visualization, alert |
| Scale | Trung bình-cao — 50K DAU và đang growth |
| Conway's Law | 3 squad đã align với 3 domain |
| Pain hiện tại | Deploy coupling, team blocking, shared database contention |
Architecture được chọn: Selective extraction từ monolith (strangler fig)
Phase 1 (Hiện tại): Extract Ingestion ra khỏi monolith
Phase 2 (6 tháng): Tất cả service tách biệt
Tại sao extract Ingestion trước?
- Đây là domain độc lập nhất — ingest data, transform, store
- Có scaling need khác biệt nhất — bursty data upload vs steady dashboard read
- Align với Ingestion squad hiện có
- Coupling tối thiểu — communicate qua event, không synchronous call
ADR excerpt:
Chúng ta extract Ingestion pipeline thành service riêng vì (1) nó có scaling characteristic khác dashboard, (2) Ingestion squad bị block bởi shared deployment, và (3) nó có domain boundary sạch nhất. Chúng ta dùng Kafka cho async event communication. Dashboard và Platform module ở lại monolith cho đến khi pain tương tự xuất hiện ở các squad đó.
Case Study 3: Enterprise Migration — FinanceCore
Context:
- Product: Enterprise financial management platform (invoicing, payment, compliance, reporting)
- Team: 40+ developer chia 6 team
- Trạng thái hiện tại: Monolith 15 năm tuổi, hàng triệu dòng code, test suite mong manh
- Scale: 500,000 daily active user, yêu cầu uptime 99.99%
- Compliance: Quy định tài chính đòi hỏi audit trail, data residency, và security boundary
- Pain: Build mất 2 giờ, deployment window chỉ cuối tuần, bất kỳ thay đổi nào đều risk break feature không liên quan
Decision:
| Constraint | Assessment |
|---|---|
| Team size | Lớn (40+ dev, 6 team) — cần independence mạnh |
| Domain complexity | Rất cao — quy định tài chính, business rule phức tạp |
| Scale | Cao — 500K DAU, yêu cầu uptime strict |
| Legacy | Codebase 15 năm, không thể rewrite từ đầu |
| Compliance | Audit trail, data residency, security boundary |
Architecture được chọn: Bounded-context microservices với DDD, event sourcing cho compliance
Migration strategy: Strangler fig trong 18-24 tháng
Phase 1 (Tháng 1-6): API gateway + extract Payment service
(compliance need cao nhất, boundary rõ nhất)
Phase 2 (Tháng 7-12): Extract Invoicing + Reporting service
(Reporting dùng CQRS read model)
Phase 3 (Tháng 13-18): Extract Compliance service với event sourcing
(yêu cầu complete audit trail)
Phase 4 (Tháng 19-24): Module còn lại được extract hoặc modernize in-placeKey decision:
- Event sourcing cho Payment và Compliance — audit trail theo quy định đòi hỏi capture mọi state change
- CQRS cho Reporting — read pattern hoàn toàn khác write pattern (complex aggregation vs transactional write)
- DDD cho tất cả service — financial domain phức tạp cần proper modeling (aggregate cho invoice, value object cho money, domain event cho state transition)
- Simple CRUD cho internal admin tool — không phải mọi service cần cùng complexity
ADR excerpt:
Chúng ta adopt DDD với bounded-context microservices vì (1) 6 team cần deployment independence, (2) quy định tài chính đòi hỏi strict security boundary giữa payment processing và feature khác, (3) audit requirement cho Payment và Compliance phù hợp nhất với event sourcing. Chúng ta chọn KHÔNG apply event sourcing cho tất cả service — Catalog và User Management dùng simple CRUD vì domain complexity không đòi hỏi.
Architecture Review Checklist
Dùng checklist này khi evaluate architecture — dù đang design hệ thống mới hay review hệ thống hiện có.
Structural Fitness
- Module/service boundary rõ ràng — Bạn có thể giải thích mỗi module sở hữu gì trong một câu?
- Dependency direction — Dependency hướng vào trong (toward domain), không hướng ra ngoài?
- Không circular dependency — Module A không depend Module B mà depend lại Module A?
- Single responsibility — Mỗi module/service có một lý do để thay đổi?
Operational Fitness
- Deploy độc lập — Bạn có thể deploy một phần mà không cần redeploy mọi thứ?
- Observable — Bạn có thể biết chuyện gì đang xảy ra trong production (log, metric, trace)?
- Recoverable — Chuyện gì xảy ra khi component fail? Có fallback không?
- Scale được ở bottleneck — Bạn có thể scale phần cần scale mà không scale mọi thứ?
Team Fitness
- Match team structure — Service boundary align với team ownership (Conway's Law)?
- Onboarding friendly — Developer mới có thể hiểu architecture trong tuần đầu?
- Decision được document — Có ADR giải thích tại sao chọn architecture này?
- Skill-appropriate — Team có skill để operate architecture này?
Evolution Fitness
- Fitness function tồn tại — Architectural rule được enforce trong CI/CD?
- Extraction possible — Bạn có thể extract module thành service mà không cần rewrite?
- Technology replaceable — Bạn có thể swap database hoặc framework mà không rewrite business logic?
- Assumption được document — ADR ghi rõ điều gì phải đúng để architecture này vẫn valid?
Quality Attribute
| Attribute | Câu hỏi |
|---|---|
| Performance | Architecture support được response time yêu cầu? |
| Reliability | Xử lý failure thế nào (network, database, external service)? |
| Security | Sensitive operation được isolate với proper boundary? |
| Testability | Có thể test business logic mà không cần stand up infrastructure? |
| Maintainability | Có thể modify một feature mà không cần hiểu toàn bộ hệ thống? |
Quick Reference: Pattern Selection Guide
Khi cần câu trả lời nhanh, dùng bảng này:
| Nếu bạn cần... | Cân nhắc... | Từ series này |
|---|---|---|
| Time to market nhanh nhất | Monolith | ARCH-2 |
| Tổ chức code rõ ràng | Layered architecture | ARCH-3 |
| UI separation testable | MVC / MVVM | ARCH-4 |
| Team independence ở scale | Microservices | ARCH-5 |
| Async processing & decoupling | Event-driven | ARCH-6 |
| Tách biệt read/write optimization | CQRS | ARCH-7 |
| Swappable infrastructure | Hexagonal (Ports & Adapters) | ARCH-8 |
| Domain-centric với testability | Clean architecture | ARCH-9 |
| Model hóa business domain phức tạp | DDD | ARCH-10 |
| Zero ops / pay-per-use | Serverless | ARCH-11 |
Nhớ: Đây là điểm khởi đầu, không phải câu trả lời cuối cùng. Architecture tốt nhất cho project của bạn phụ thuộc vào constraint cụ thể.
Tổng Kết
✅ Mọi architecture decision là trade-off — simplicity vs flexibility vs scalability
✅ Dùng decision framework: đánh giá team size, domain complexity, scale, và deployment constraint
✅ Viết ADR để document decision, alternative đã cân nhắc, và consequence
✅ Bắt đầu đơn giản rồi evolve — monolith → modular monolith → selective extraction → microservices
✅ Kết hợp pattern — dùng simple CRUD nơi phù hợp, DDD nơi cần thiết, CQRS cho read-heavy path
✅ Tránh anti-pattern: resume-driven development, premature microservices, architecture astronaut, distributed monolith
✅ Fitness function enforce architecture rule tự động trong CI/CD
✅ Dùng strangler fig pattern cho gradual migration — không bao giờ big-bang rewrite
✅ Không có architecture tốt nhất — chỉ có architecture tốt nhất cho constraint của bạn
✅ Review architecture định kỳ bằng architecture review checklist
Tiếp Theo Trong Software Architecture Series
Đây là bài 12 trong 12 của series Software Architecture Patterns — và là bài cuối cùng! 🎉
- ✅ ARCH-1: Software Architecture Patterns Roadmap
- ✅ ARCH-2: Monolithic Architecture
- ✅ ARCH-3: Layered (N-Tier) Architecture
- ✅ ARCH-4: MVC, MVP & MVVM
- ✅ ARCH-5: Microservices Architecture
- ✅ ARCH-6: Event-Driven Architecture
- ✅ ARCH-7: CQRS & Event Sourcing
- ✅ ARCH-8: Hexagonal Architecture (Ports & Adapters)
- ✅ ARCH-9: Clean Architecture
- ✅ ARCH-10: Domain-Driven Design (DDD)
- ✅ ARCH-11: Serverless & FaaS Architecture
- ✅ ARCH-12: Choosing the Right Architecture (bài này)
Chúc mừng bạn đã hoàn thành toàn bộ series! Bạn giờ có một bộ toolkit toàn diện về architecture pattern và một systematic framework để chọn giữa chúng.
Bài liên quan:
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.