Kỹ thuật 09 thg 4, 2026

Thiết kế kiến trúc phần mềm để mở rộng

Thiết kế kiến trúc phần mềm để mở rộng

Tác giả

Nam Pham

Từ MVP lên Enterprise mà không phải viết lại từ đầu (hy vọng là vậy)

Mình không phải kiểu “architect xịn xò”. Mình là dev từng làm sập production vài lần rồi phải fix trong áp lực. Nên bài này không phải lý thuyết — mà là những thứ mình ước gì mình làm sớm hơn khi build MVP.

Teaser (dùng cho card)

Những quyết định nhỏ về kiến trúc từ sớm có thể giúp bạn tránh việc phải rewrite cả hệ thống sau này. Đây là câu chuyện về việc chọn đủ tốt, không phải hoàn hảo.

Cái bẫy MVP (ai làm rồi cũng dính)

Khi làm MVP, mục tiêu là ship nhanh:

  • Nhét logic vào controller
  • 1 database xử lý tất cả
  • Bỏ qua structure vì “để sau refactor”

Vấn đề là… “sau” đến rất nhanh.

Một ngày đẹp trời:

  • user tăng gấp 10
  • nhiều team cùng code
  • khách enterprise yêu cầu SLA, security, audit log…

Và lúc đó, architecture bắt đầu “phản lại” bạn.

Quyết định #1: Tách Domain Logic sớm (dù chỉ một chút)

Trước mình nghĩ Clean Architecture là overkill cho MVP.
Giờ mình thấy: làm full thì có thể overkill, nhưng không tách gì cả thì còn tệ hơn.

Một rule đơn giản:

Đừng để business logic nằm trong controller/UI

Chỉ cần:

  • có services/ hoặc use-cases/

Là đã giúp:

  • dễ reuse
  • dễ test
  • dễ scale về sau

Quyết định #2: Ưu tiên scale phần đọc (read)

Phần lớn hệ thống scale read trước write.

Thay vì over-engineer:

  • cứ bắt đầu với monolith
  • nhưng tối ưu cho read

Những thứ mình hay làm gần đây:

  • caching sớm (Redis hoặc đơn giản hơn)
  • tách read model (kiểu CQRS nhẹ)
  • pagination ở mọi nơi

Không cần CQRS đầy đủ — chỉ cần đừng assume query nào cũng rẻ.

Quyết định #3: Cẩn thận với “1 database cho tất cả”

Cái này đau thật.

MVP thì 1 DB là ok. Nhưng:

Khi mọi feature dùng chung schema mà không có boundary → rất khó maintain

Cách mình cải thiện:

  • group table theo domain
  • hạn chế join cross-domain
  • dùng API nội bộ thay vì query trực tiếp DB

Kiểu như giả lập microservices… nhưng chưa phải chịu đau thật 😅

Quyết định #4: Nghĩ async sớm (khi hợp lý)

Sai lầm trước đây:

Cái gì cũng synchronous cho đơn giản

Hậu quả:

  • API chậm
  • timeout
  • UX tệ

Giờ mình tách sớm:

  • gửi email → async
  • report → async
  • xử lý nặng → async

Tools mình đang thử:

  • Kafka, RabbitMQ
  • job queue như BullMQ

Không cần event-driven full, nhưng async boundary rất đáng giá.

Quyết định #5: Observability không còn optional

Trước mình ignore cái này. Cho đến khi production lỗi 😅

Giờ dù MVP vẫn cố có:

  • logging có structure
  • tracing cơ bản (OpenTelemetry)
  • metrics

Vì:

Không nhìn thấy thì không debug được.

Một vài thứ mới mình đang explore

Gần đây mình có thử:

  • Serverless + edge (scale global read khá hay)
  • BFF pattern cho frontend phức tạp
  • GraphQL (dùng chọn lọc, không spam nữa 😅)
  • AI hỗ trợ monitoring (còn mới nhưng thú vị)

Không phải cái nào cũng cần — nhưng nó đang thay đổi cách mình nghĩ về scale.

Kết

MVP không cần architecture hoàn hảo.

Nhưng cần:

  • boundary rõ ràng
  • awareness về scale
  • và kỷ luật tránh “hack tạm”

Vì cái đắt nhất không phải build nhanh —
mà là phải build lại từ đầu.