Back to blog

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

software-architecturesystem-designdecision-makingbackendbest-practices
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
ConsistencyMọi read trả về write gần nhất
AvailabilityMọi request nhận được response (dù có thể stale)
Partition ToleranceHệ 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:

DecisionReversibilityCost để thay đổi
Chọn web frameworkTrung bìnhVài tuần
Thêm caching layerCaoVài ngày
Split thành microservicesThấpVài tháng
Chọn database engineThấpVài tháng
Chuyển sang serverlessTrung bìnhVài tuần - tháng
Thêm event sourcingRất thấpVà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 SizeMức độ phức tạp tối đaLý do
1-3 developerMonolith hoặc modular monolithKhông thể sustain overhead của distributed system
4-8 developerModular monolith hoặc 2-3 serviceMột số service boundary xuất hiện, nhưng giữ đơn giản
8-20 developerMicroservices (có giới hạn)Team cần independence; Conway's Law bắt đầu tác động
20+ developerMicroservices với platform teamCầ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 ComplexityArchitecture phù hợpVí dụ
Simple CRUDMonolith, layered architectureBlog, todo app, admin panel đơn giản
Moderate business logicModular monolith, clean/hexagonal architectureE-commerce, SaaS dashboard
Complex domainDDD + hexagonal/clean, bounded contextInsurance, healthcare, financial trading
Nhiều domain độc lậpMicroservices với DDDE-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 ScaleArchitecture Approach
Hàng trăm userMonolith trên single server
Hàng nghìn userMonolith với caching, read replica
Hàng chục nghìnModular monolith hoặc selective service extraction
Hàng trăm nghìnMicroservices 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 / VPSMonolith (docker-compose là tối đa)
Kubernetes clusterMicroservices trở nên khả thi
Serverless platformFunction-based, event-driven
Yêu cầu on-premiseDeploy đơn giản hơn, ít moving part
Multi-regionCần distributed pattern, eventual consistency
Ngành regulatedCó thể cần strict boundary, audit trail (event sourcing)

Time to Market

TimelineLời khuyên Architecture
MVP / 2-4 tuầnMonolith, không cần bàn cãi. Ship nhanh, validate idea.
Sản phẩm đầu tiên / 2-3 thángMonolith có cấu trúc tốt, có thể modular
Sản phẩm mature / 6+ thángCân nhắc service boundary dựa trên pain point thực tế
Enterprise / nhiều nămFull 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:

  1. "Team mình operate được không?" — Có skill để debug, deploy, và monitor architecture này không?
  2. "Khi fail thì sao?" — Architecture này xử lý partial failure thế nào?
  3. "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?
  4. "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ì?
  5. "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

  1. Giữ ngắn — Tối đa một trang. Nếu cần nhiều hơn, decision quá lớn; chia nhỏ ra.
  2. Đánh số tuần tự — ADR-001, ADR-002, v.v. Không bao giờ xóa; đánh dấu superseded.
  3. 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.
  4. Bao gồm consequence — Cả positive và negative. Mọi decision đều có downside.
  5. Lưu trong repo — Trong thư mục docs/adr/, version-controlled cùng code.
  6. 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 FunctionKiểm tra gìVí dụ Tool
Module dependencyKhông circular dependency giữa moduleArchUnit, Dependency Cruiser
Layer enforcementController không gọi repository trực tiếpArchUnit, eslint-plugin-boundaries
Response time95th percentile API response < 200msLoad test trong CI
Deployment independenceService A deploy mà không cần redeploy BCI pipeline check
Database couplingService A không query table của Service BSchema 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:

  1. Không bao giờ dừng feature development — Migration diễn ra song song với công việc bình thường
  2. Extract theo bounded context — Không theo technical layer (đừng extract "tất cả database code")
  3. Bắt đầu với module ít coupled nhất — Module có ít dependency nhất với phần còn lại
  4. Giữ old code chạy — Route traffic dần dần; fallback nếu service mới có issue
  5. 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

  1. Match complexity với subdomain — Đừng apply DDD cho trang setting. Đừng dùng simple CRUD cho trading engine.
  2. Dùng event để connect service — Async communication (event) decouple service tốt hơn sync call (REST/gRPC).
  3. Standardize communication — Dù service dùng internal architecture khác nhau, dùng consistent API contract và event schema.
  4. 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.
  5. 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:

ConstraintAssessment
Team sizeNhỏ (3 dev) — không thể afford operational overhead
Domain complexityTrung bình — task, project, team, notification
ScaleThấp — hàng trăm user
Time to marketCritical — phải ship nhanh
DeploymentSingle 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
└── Dockerfile

ADR 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:

  1. Hiện tại: Monolith deploy qua Docker trên single VPS
  2. Ở 5K user: Thêm Redis caching, database read replica
  3. Ở 20K user: Extract notification thành serverless function (event-driven)
  4. 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:

ConstraintAssessment
Team sizeTrung bình (12 dev, 3 squad) — cần independence
Domain complexityCao — ingestion, transformation, storage, visualization, alert
ScaleTrung bình-cao — 50K DAU và đang growth
Conway's Law3 squad đã align với 3 domain
Pain hiện tạiDeploy 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?

  1. Đây là domain độc lập nhất — ingest data, transform, store
  2. Có scaling need khác biệt nhất — bursty data upload vs steady dashboard read
  3. Align với Ingestion squad hiện có
  4. 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:

ConstraintAssessment
Team sizeLớn (40+ dev, 6 team) — cần independence mạnh
Domain complexityRất cao — quy định tài chính, business rule phức tạp
ScaleCao — 500K DAU, yêu cầu uptime strict
LegacyCodebase 15 năm, không thể rewrite từ đầu
ComplianceAudit 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-place

Key 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

AttributeCâu hỏi
PerformanceArchitecture support được response time yêu cầu?
ReliabilityXử lý failure thế nào (network, database, external service)?
SecuritySensitive operation được isolate với proper boundary?
TestabilityCó thể test business logic mà không cần stand up infrastructure?
MaintainabilityCó 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ấtMonolithARCH-2
Tổ chức code rõ ràngLayered architectureARCH-3
UI separation testableMVC / MVVMARCH-4
Team independence ở scaleMicroservicesARCH-5
Async processing & decouplingEvent-drivenARCH-6
Tách biệt read/write optimizationCQRSARCH-7
Swappable infrastructureHexagonal (Ports & Adapters)ARCH-8
Domain-centric với testabilityClean architectureARCH-9
Model hóa business domain phức tạpDDDARCH-10
Zero ops / pay-per-useServerlessARCH-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! 🎉

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.