28 điểm bởi GN⁺ 2025-05-10 | 10 bình luận | Chia sẻ qua WhatsApp
  • Việc vội vàng tách code thành microservices ở startup giai đoạn đầu sẽ gây suy giảm nghiêm trọng về năng suất của đội ngũ và làm tăng độ phức tạp
  • Kiến trúc nguyên khối (monolithic) mang lại khả năng tối ưu cho việc sinh tồn nhờ triển khai đơn giản, ra mắt tính năng mới nhanh và cộng tác hiệu quả
  • Microservices chỉ thực sự mang lại lợi ích của việc tách riêng khi có nhu cầu mở rộng quy mô lớn, nhiều loại workload khác nhau hoặc yêu cầu runtime riêng biệt
  • Việc tách service quá mức, repo mọc tràn lan, môi trường phát triển cục bộ thiếu ổn định và công nghệ không đồng nhất đều dẫn tới chậm lại và giảm tinh thần đội ngũ
  • Startup nên bắt đầu với monolith và chỉ tách ra khi xuất hiện điểm nghẽn rõ ràng; đó là cách tiếp cận thận trọng tối ưu

Mở đầu và bối cảnh

  • Sự sống còn của startup được quyết định bởi tốc độ lặp nhanh, cung cấp tính năng mới và tạo ra giá trị sử dụng
  • Kiến trúc nền tảng của dự án, tech stack và lựa chọn ngôn ngữ lập trình đều ảnh hưởng tới tốc độ của đội ngũ
  • Việc áp dụng microservices quá sớm trông có vẻ bài bản trên danh nghĩa, nhưng trên thực tế lại gây ra giảm năng suất, dịch vụ dở dang và độ phức tạp dư thừa
  • Dữ liệu: phát sinh nhiều loại chi phí phát triển như điều phối service, vấn đề với Docker/script, CI/CD trùng lặp, sự phụ thuộc giữa các service, chi phí observability và kiểm thử phân tán
  • Thay vì tùy tiện tiến tới một kiến trúc phức tạp, bài viết nhấn mạnh tầm quan trọng của kiến trúc thực dụng

Điểm mạnh của monolith

  • Dù là SaaS hay chỉ là một lớp bọc cơ sở dữ liệu đơn giản, ứng dụng theo thời gian sẽ trở nên phức tạp hơn, nhưng kiến trúc monolith vẫn dễ giữ được sự đơn giản và linh hoạt
  • Việc triển khai dễ dàng, có sự hỗ trợ từ các framework phổ biến như Django, ASP.Net, Nest.js và hưởng lợi lớn từ cộng đồng mã nguồn mở
  • Ví dụ thực tế: một startup bất động sản đã dùng monolith Laravel để dễ dàng thực hiện nhiều tích hợp bên thứ ba và mở rộng tính năng
  • Họ có thể tập trung đáp ứng yêu cầu kinh doanh và kỳ vọng thay vì đưa vào hạ tầng phức tạp hoặc tách sang microservices
  • Bài học: sự gọn gàng của kiến trúc giúp đội ngũ tập trung vào triển khai; chỉ cần cẩn trọng với việc mô-đun hóa nội bộ kém là vẫn có thể mở rộng đủ tốt

Liệu microservices có luôn là lựa chọn tốt nhất?

  • Nhiều kỹ sư cho rằng microservices là đáp án chuẩn mực, nhưng thực tế nó chỉ phát huy giá trị khi có lý do đặc biệt như mở rộng quy mô
  • Với đội ngũ ít người, quy mô nhỏ và giai đoạn thay đổi nhanh, nó lại phản tác dụng do hạ tầng trùng lặp, phát triển cục bộ chậm và chu kỳ lặp chậm
  • Ngay cả những công ty như Segment cũng từng chuyển đổi vì cấu trúc kém hiệu quả
  • Bài học: microservices chỉ là công cụ để giải quyết điểm nghẽn, không phải template cho giai đoạn đầu

Vì sao microservices thường thất bại, đặc biệt ở giai đoạn đầu

1. Ranh giới service tùy tiện

  • Việc mượn lý thuyết domain-driven design hay clean architecture để chia service theo logic nghiệp vụ thường dẫn tới ranh giới giữa logic thực tế và service không khớp nhau
  • Ví dụ: tách người dùng, xác thực và phân quyền riêng ra làm tăng độ phức tạp triển khai và độ khó khi phát triển API
  • Việc tách ra ở giai đoạn chưa hề xuất hiện điểm nghẽn thực sự sẽ làm hệ thống kém ổn định và chậm hơn
  • Mô phỏng việc tách trong tương lai bằng flag hoặc toggle nội bộ, đồng thời khám phá ranh giới một cách hữu cơ thay vì lao vào công việc hạ tầng cấp bách, sẽ hiệu quả hơn
  • Bài học: hãy quyết định tách dựa trên điểm nghẽn thực tế thay vì lý thuyết

2. Repo/hạ tầng dư thừa

  • Mọi yếu tố như style code, test, cấu hình môi trường, tài liệu, CI/CD đều tăng lên theo số lượng service
  • Nếu dùng cấu trúc monorepo, có thể quản lý mọi cấu hình tại một nơi để tăng tính nhất quán của code và hiệu quả cộng tác
  • Với Node.js, các công cụ như nx hoặc turborepo giúp quản lý phụ thuộc và build giữa các service nội bộ dễ dàng hơn
  • Nhược điểm là quan hệ phụ thuộc phức tạp, cần tinh chỉnh hiệu năng CI và có thể cần công cụ build nhanh hơn
  • Hệ sinh thái Go cũng có thể được quản lý bằng một workspace duy nhất ở giai đoạn đầu, rồi mới cân nhắc tách module khi quy mô lớn hơn
  • Bài học: đội ngũ nhỏ có thể tiết kiệm thời gian bằng monorepo và hạ tầng dùng chung

3. Môi trường phát triển cục bộ thiếu ổn định

  • Quá nhiều thời gian để chạy local, script phức tạp và phụ thuộc theo từng hệ thống đều gây ra chậm onboarding và giảm năng suất
  • Thiếu tài liệu, vấn đề tương thích và các cách vá riêng cho từng OS (ví dụ script chỉ chạy trên macOS) đều là rào cản
  • Trong một dự án, người ta đã giảm độ phức tạp của Docker bằng proxy Node.js, từ đó rút ngắn thời gian onboarding cho developer
  • Bài học: nếu ứng dụng chỉ chạy được trên một OS, năng suất của đội ngũ cuối cùng sẽ phụ thuộc vào độ tin cậy của đúng một chiếc laptop

4. Tech stack không đồng nhất

  • Node.jsPython phù hợp cho tốc độ lặp nhanh, nhưng trong môi trường microservices lại thường phát sinh vấn đề không khớp giữa build/runtime
  • Go có ưu thế ở binary tĩnh, build nhanh và vận hành đơn giản
  • Cần chọn tech stack cẩn thận ngay từ đầu; nếu cần thì có thể trộn nhiều ngôn ngữ thông qua các giao thức như gRPC
  • Nếu không có nhu cầu đặc biệt như ML hay ETL, việc trộn stack thường chỉ làm tăng thêm độ phức tạp
  • Bài học: hãy chọn stack phù hợp với thực tế của đội ngũ, không phải với giấc mơ kỹ thuật

5. Độ phức tạp ẩn: giao tiếp và giám sát

  • Trong microservices, các yếu tố như service discovery, versioning API, distributed tracing, quản lý log tập trung là bắt buộc
  • Việc truy vết bug/sự cố trong monolith có thể chỉ cần một stack trace, nhưng trong môi trường phân tán thì phức tạp hơn nhiều
  • Muốn làm cho bài bản thì cần đưa vào các công cụ chuyên dụng như OpenTelemetry và xây dựng hẳn một stack observability
  • Cần nhận thức rằng hệ thống phân tán là một khoản đầu tư bắt buộc cho những thách thức kỹ thuật bổ sung

Khi nào microservices có hiệu quả

  • Cô lập workload: tách riêng các tác vụ bất đồng bộ cụ thể như xử lý ảnh, OCR sẽ hiệu quả hơn
  • Nhu cầu mở rộng không cân xứng: khi web API và workload ML có yêu cầu phần cứng/vận hành khác nhau thì nên tách riêng từng phần
  • Cần runtime khác: các thành phần không tương thích runtime với ứng dụng chính, chẳng hạn mã C++ legacy, nên được duy trì như service riêng
  • Qua các trường hợp ở tổ chức kỹ thuật lớn như Uber, có thể thấy nó chỉ phù hợp khi tồn tại nhu cầu tổ chức rõ ràng và năng lực vận hành đã trưởng thành
  • Ngay cả ở đội ngũ nhỏ, đôi khi việc tách riêng vẫn thực dụng nếu đó là dịch vụ bên ngoài như analytics và dễ quản lý
  • Bài học: chỉ áp dụng khi lợi ích của việc tách là rõ ràng với workload cụ thể

Hướng dẫn thực chiến cho startup

  • Ban đầu hãy bắt đầu với monolith và tập trung làm việc trên một framework đã được chứng minh
  • Một repository duy nhất có lợi hơn cho đội ngũ ban đầu về hiệu quả vận hành/quản trị và cả góc độ bảo mật
  • Đơn giản hóa môi trường phát triển cục bộ là rất quan trọng; nếu khó thì bắt buộc phải cung cấp tài liệu hoặc video hướng dẫn chi tiết
  • Đầu tư sớm vào CI/CD để tự động hóa công việc lặp lại và giảm gánh nặng tâm lý cho đội ngũ
  • Chỉ tách chọn lọc khi xuất hiện điểm nghẽn rõ ràng; nếu không thì hãy tập trung vào mô-đun hóa bên trong monolith và tăng cường kiểm thử
  • Mục tiêu ưu tiên cao nhất là giữ được tốc độ phát triển
  • Bài học: hãy bắt đầu từ sự đơn giản, rồi mở rộng theo đúng nhu cầu tách biệt

Nếu buộc phải dùng microservices

  • Đánh giá tech stack và đầu tư vào công cụ trải nghiệm developer: cần chuẩn bị tự động hóa theo từng service, script rõ ràng và công cụ quản lý triển khai thống nhất
  • Chuẩn hóa và xây dựng giao thức giao tiếp service đáng tin cậy: cần nắm rõ các phần phải triển khai thêm như tính nhất quán của message schema, tài liệu hóa và xử lý lỗi
  • Ổn định hóa hạ tầng kiểm thử: test đơn vị, tích hợp và E2E phải mở rộng tương ứng với việc tách service
  • Cân nhắc thư viện dùng chung: phần code chung cho observability/giao tiếp nên giữ ở phạm vi tối thiểu để tránh phải rebuild toàn bộ service quá thường xuyên
  • Đưa observability vào sớm: hãy bắt đầu từ các công cụ logging cơ bản như log JSON có cấu trúc và correlation ID
  • Tóm lại, nếu chấp nhận độ phức tạp thì phải dốc sức thiết kế một hệ thống có thể quản lý được

Kết luận

  • Việc áp dụng microservices một cách vội vàng chỉ để lại gánh nặng, vì vậy hãy ưu tiên sự đơn giản lên hàng đầu
  • Đừng tách ra khi chưa có điểm đau rõ ràng; điều quan trọng là chỉ thêm vào mức độ phức tạp tối thiểu cần thiết để tồn tại và phát triển
  • Sống sót là ưu tiên trước, mở rộng là chuyện sau

10 bình luận

 
kuil09 2025-05-12

Tôi nhìn chung đồng ý với ý của bài gốc.
Tôi nghĩ đây là vấn đề về kinh nghiệm của tổ chức.
Hãy thử tưởng tượng việc bán đồ ăn từ một xe bán đồ ăn lưu động rồi phát triển thành một nhà hàng.
Ngay từ đầu, các bên liên quan hoàn toàn thiếu kinh nghiệm để có thể tính đến phân công lao động và chuyên môn hóa.

 
dhlee0305 2025-05-12

Tôi cho rằng startup nên chọn cách ít tốn kém hơn để kéo dài thời gian sống còn. Microservices hoàn toàn không rẻ. Khi áp dụng vào thực tế tại hiện trường, nó thực sự phát sinh chi phí đáng kể. Nếu có thể, tôi nghĩ việc thiết kế một kiến trúc phù hợp với chính dịch vụ của công ty sẽ là cách đạt được hiệu quả tương tự với chi phí thấp hơn.
Điều đó không có nghĩa là microservices là xấu. Đây là một mô hình đòi hỏi nhiều chi phí.

 
mhj5730 2025-05-12

Tôi nghĩ chỉ cần đúng 2 thứ là đủ: một monolith chỉ dùng đồng bộ và một monolith chỉ dùng bất đồng bộ... Việc áp dụng microservices, theo tôi, rốt cuộc phụ thuộc vào quy mô các bảng cần phải quản lý bằng DB. Nếu số lượng bảng nhiều đến mức vô lý và phức tạp thì nên cân nhắc MSA, còn nếu đơn giản thì monolith là phù hợp nhất.

 
roxie 2025-05-12

Khi tất cả những làn sóng này qua đi, hậu thế sẽ nhớ về thế hệ này như thế nào?

 
n1ghtc4t 2025-05-12

Khi đó lại là làn sóng của thời điểm đó...

 
bungker 2025-05-11

Tôi nghĩ ở startup, microservice cũng có nhiều ưu điểm. Trước hết, tôi thật sự khuyến nghị dùng monorepo.

  • Khi định hướng sản phẩm thay đổi, với microservice thì những phần cần chỉnh sửa rõ ràng hơn và ít hơn so với monolithic. Tôi nghĩ đây là một điểm rất lớn.
  • Trong thời đại phát triển cùng AI, các đơn vị nhỏ của microservice dễ phát triển thông qua AI hơn. (Không có nghĩa là monolithic thì không làm được)
  • Tôi thừa nhận gánh nặng của CI/CD, nhưng cũng có những dịch vụ bị thanh lý ngay ở giai đoạn đang định hình hướng đi. Đến giai đoạn cuối cùng khi đã chốt được hướng, triển khai cũng gần như mức copy-paste nên có thể xây dựng trong vòng một tuần.
  • Có những mã nguồn mở có thế mạnh rất rõ theo từng ngôn ngữ. Ví dụ security và business logic làm bằng Java, còn AI làm bằng Python; trong kiến trúc microservice có thể tận dụng tối đa nhiều mã nguồn mở nhất có thể.
 
andone 2025-05-11

Tôi đồng ý rằng trong thời đại phát triển AI, việc triển khai theo các đơn vị nhỏ với trách nhiệm duy nhất là điều thiết yếu.

 
bus710 2025-05-10

Dù ở phần bình luận cũng đã nhắc thoáng qua, nhưng hệ BEAM/OTP kiểu này quả là khá linh hoạt và tốt. Trường hợp của Gleam thì nhờ kết hợp cú pháp hay của cả Go lẫn Rust với độ ổn định của BEAM nên đã trở thành một ngôn ngữ khá ấn tượng. Tôi bắt đầu muốn thử dùng nó cho các dự án quy mô nhỏ.

 
ndrgrd 2025-05-10

Nếu chia nhỏ đội ngũ một cách quá mức, thì ngay cả việc tụ họp lại để trao đổi ý kiến cũng trở thành một khối lượng công việc khổng lồ.

 
GN⁺ 2025-05-10
Ý kiến trên Hacker News
  • Nhiều người nhận ra rằng nếu không thật sự có vấn đề về mở rộng, đội ngũ lớn hoặc các domain cần phát triển độc lập thì microservices chỉ làm tăng chi phí mà không mang lại lợi ích; thực tế Segment cũng đã quay lại từ việc tách microservices vì lý do này. Đây là một mô hình tổ chức hơn là một kỹ thuật. Thông thường nên vận hành một monolith duy nhất, rồi chỉ tách riêng frontend, backend hoặc các tác vụ chạy lâu như tạo PDF thành dịch vụ riêng. Khi số lượng dịch vụ tăng lên thì mới bắt đầu chuẩn hóa và suy nghĩ nghiêm túc về kiến trúc. Với tổ chức có dưới 200 kỹ sư thì thường còn bị giảm năng suất. Không phải công ty sống sót nhờ microservices, mà là họ vẫn sống sót dù có microservices.
    • Có xu hướng một số lập trình viên muốn đưa microservices vào để làm đẹp hồ sơ cho tương lai ở các tập đoàn lớn, nhưng điều đó hầu như không giúp ích gì cho startup thực tế. Muốn ngăn chuyện này thì cần lãnh đạo kỹ thuật thật sự sáng suốt.
    • Có người từng chứng kiến một startup khoảng 50 kỹ sư chia hệ thống thành hàng chục service; người mới cần ít nhất 6 tháng để hiểu hệ thống, trong khi người dùng chỉ có vài trăm nhưng độ phức tạp thì khổng lồ. Họ đốt $50 triệu vốn VC rồi cuối cùng phá sản. Sản phẩm có tính đổi mới và được thiết kế tốt, nhưng tất cả đều vô nghĩa.
    • Khi tách service cũng có cách không chia code ra, mà triển khai một monolith thông thường theo các cờ vai trò. Worker chạy nền cũng vận hành cùng web server, dùng health check và metric, còn load balancer phân phối traffic theo từng vai trò.
    • Giống như trường hợp Khan Academy từng trải qua, chỉ sau khi đã mở rộng monolith đủ xa thì mới có thể dựa trên kinh nghiệm để xác định ranh giới dịch vụ. Lúc đó việc áp dụng microservices mới phù hợp.
    • Dù có thể nêu ra các lý do kỹ thuật để phải tách, nhưng service vốn dĩ là việc khó. Tuy vậy, nếu thực sự cần thì điều quan trọng là sẵn sàng nâng cao năng lực. Đừng chỉ vì thấy nó là xu hướng mà bác bỏ hoàn toàn, hãy cân nhắc các trade-off.
    • Chỉ vì có “nhiều team” không có nghĩa là phải chia tổ chức ra. Thực tế có những director thấy vừa xuất hiện hai squad nhỏ là đã muốn tách monolith ngay. Nếu team cứ 9 tháng lại tái cơ cấu thì việc chốt ranh giới kiến trúc quá sớm có thể thành thảm họa. Chỉ khi nào xác nhận được rằng một team có thể vận hành ổn định ít nhất khoảng 18 tháng thì mới đáng để xem đó là ranh giới kiến trúc.
    • Định nghĩa microservices vốn là nói về “các domain có thể phát triển độc lập”, nên nhiều người thấy điều này cũng không có gì mới.
    • Có trường hợp chỉ một URL rất đặc thù có yêu cầu về traffic và bộ nhớ khác biệt, không phù hợp với server PHP nên chỉ bổ sung thêm một server viết bằng ngôn ngữ khác. Kết quả là cải thiện hiệu năng và chi phí tới 1000 lần. Cũng có ý kiến cho rằng nên thử nghĩ lại khái niệm service kiểu Java/Spring/Guava thành cách triển khai “ngoài process” hoặc “trong process”. Nếu chuẩn hóa tốt tech stack, phiên bản và serialization thì năng suất thậm chí có thể tăng lên; nhưng nếu thiếu chuẩn hóa thì dễ gây lỗi giao tiếp và vấn đề tương thích, dẫn tới hỗn loạn.
    • Conway's law (cấu trúc code phản ánh cấu trúc tổ chức) thực sự là một nhận định đúng.
    • Có người nhấn mạnh rằng service là thứ do con người cung cấp, còn microservice là service trong nền kinh tế nội bộ của doanh nghiệp.
    • Một kinh nghiệm từ 15 năm trước: ban đầu một giải pháp thống nhất với team nhỏ rất dễ vận hành, nhưng sau khi áp dụng microservices thì còn phải khởi động và điều phối từng service nên rất vất vả. Từ đó thấm thía tầm quan trọng của YAGNI (đừng làm trước khi thật sự cần).
    • Có nhiều lý do kỹ thuật để tách riêng, chẳng hạn chỉ tách các luồng có traffic cao hoặc đường đi quan trọng. Trong tổ chức nhỏ điều này thường không phải lựa chọn lý tưởng, nhưng nếu cắt riêng đúng các path tải cao thì startup vẫn có thể hưởng lợi lớn.
    • Trên thực tế, lợi ích lớn nhất của microservices là cho phép các nhóm nhỏ làm việc độc lập mà không cản trở nhau. Nhưng khi nhiều team cùng sở hữu các microservice riêng thì các cuộc họp chuẩn hóa kéo dài bất tận, và vì bị các service bên ngoài làm phiền nên kỹ năng ngoại giao kiểu “việc của ai người nấy lo” lại trở nên quan trọng hơn cả hợp tác.
  • Có người đồng cảm với bài viết này vì từng thấy một team 2-3 lập trình viên vẫn cố áp dụng microservices dù đã được khuyên là chỉ trông cho ngầu. Hai năm sau họ mới bắt đầu xây lại code cũ, và đến giờ sau 3 năm vẫn chưa giải quyết xong vấn đề triển khai và nhiều thứ khác. Nếu ban đầu họ chọn modular monolith thay vì phớt lờ lời khuyên thì đã không gặp những rắc rối này.
    • Nếu chỉ để lại một hồ sơ công nghệ/dự án hào nhoáng rồi nhanh chóng nhảy việc, thì hậu quả sẽ do người khác gánh chịu.
    • Microservices chỉ thật sự đáng dùng khi mỗi service có hẳn một team phụ trách; chưa ai thấy ví dụ tốt nào về việc một team phải chăm nhiều service cùng lúc.
    • Phần lớn vấn đề xuất phát từ việc các thành viên vẫn tiếp tục nghĩ về microservices như một hệ thống duy nhất (monolith). Từ thiết kế đến triển khai đều nảy sinh ma sát. Chỉ khi toàn bộ tổ chức cùng thấu hiểu thì mới có thể thành công. Nếu microservice hóa một hệ thống cũ thì sẽ có rất nhiều kháng cự nội bộ.
    • Cuối cùng có cảm giác rằng startup nào rồi cũng đi qua con đường đau khổ tương tự.
    • Ngay cả trong một dự án UI nội bộ gồm 8-12 microservice với chỉ 5-10 người dùng thực tế thì độ phức tạp cũng tăng lên vô ích. Không hiểu nổi lý do.
    • Có người từng áp dụng microservices + Java nhờ tư vấn của Thoughtworks; công ty tư vấn thì kiếm tiền rồi rời đi, còn tổ chức thì loay hoay tái hiện một monolith giàu tính năng thành các microservice phân tán. Dự án cuối cùng thất bại và công ty cũng biến mất. Từ đó về sau họ mất niềm tin vào các hãng tư vấn lớn.
  • Theo kiểu tư duy grug brain, có người không hiểu vì sao lại cố tình chọn cách khó hơn là chia nhỏ hệ thống rồi còn thêm cả network call.
    • Họ cảm thấy điều đó giống như cố thêm tính năng “monkey patch” vào một ngôn ngữ vốn không có nó, như Python.
    • Có ý kiến cho rằng network call biến một quy tắc (rule) thành một luật bất biến (law).
    • Theo kiểu đùa grug, vì có quá nhiều grug mang grug brain nên người ta ảo tưởng rằng một nhóm 9 grug có thể làm ra một baby grug chỉ trong 1 tháng.
  • Microservices hiệu quả trong tổ chức lớn để giải quyết vấn đề con người, gỡ bỏ rào cản quan liêu và trao quyền tự chủ cho lập trình viên; ở startup nhỏ thì lợi ích thực tế không lớn. Tuy vậy, nếu trong một domain cụ thể cần trộn nhiều tech stack khác nhau, chẳng hạn Elixir với Python/Go, thì kiểu tách này có thể cần thiết.
    • Nếu ứng dụng có các mức tải hoặc yêu cầu tài nguyên khác nhau thì ngay cả startup nhỏ cũng có lợi khi tạo service riêng. Phần lớn business logic vẫn nên để trong monolith, chỉ tách các tác vụ đặc thù như GPU. Tuy nhiên cần tránh để mô hình này trượt thành việc duy trì 100 service; mặc định vẫn nên ưu tiên monolith và chỉ tách khi thật sự cần.
    • Microservices lại có thể sinh ra thêm phụ thuộc mang tính tổ chức và nhu cầu điều phối. Ví dụ chính sách “cứ lấy bất kỳ service nào dùng” sẽ làm tăng mạnh chi phí bảo trì, và để hệ thống vận hành thì ai cũng phải học mọi thứ. Cuối cùng thời gian lại bị đốt vào việc tìm đúng người phù hợp.
    • Nếu các team mâu thuẫn hoặc chồng chéo nhau thì mức độ kém hiệu quả còn lớn hơn.
  • Microservices trong kiến trúc phần mềm cũng giống Conway's Law (cấu trúc tổ chức ảnh hưởng đến cấu trúc code): mỗi ranh giới team là một ranh giới phải vượt qua, và việc cố ý tạo ra những ranh giới kiến trúc lớn bên trong tổ chức thường phản tác dụng. Thay vào đó có thể quản lý bằng modular monolith với dependency injection, thiết kế ranh giới module và actor model; khi sau này thật sự cần thì cũng dễ tách ra thành service. Cách này cho tỷ lệ chi phí/hiệu quả tốt, theo kinh nghiệm đã trực tiếp tách monolith ra 3-4 lần.
    • Conway's Law là quy luật về giao tiếp, tức là các ranh giới communication. Không nhất thiết phải động đến từng ranh giới team; ngược lại thường phải tái cấu trúc tổ chức để phù hợp với phần mềm. Nghĩa là mỗi lần đổi kiến trúc lại phải reorganize công ty. Cách làm này chỉ làm trầm trọng thêm sự tách rời giữa team và mục tiêu kinh doanh, nên không nên mù quáng tôn sùng kiểu Amazon.
  • Về mặt kỹ thuật, những trường hợp microservices phù hợp với startup là: (1) khi ứng dụng lõi bắt buộc phải dùng ngôn ngữ khác, ví dụ Rails + R; (2) khi chỉ một vài service có quy mô khác biệt cực lớn; (3) khi một số dữ liệu nhất định có yêu cầu bảo mật hoặc vòng đời rất khác, chẳng hạn thông tin y tế. Ngoài ra gần như không có lý do để chia nhỏ đến vậy, và với tổ chức nhỏ thì thường còn thiệt hơn.
    • Việc tách vài service mới không giống microservices thực thụ; microservices thật sự là tách cả những phần mà trong ứng dụng bình thường đáng lẽ chỉ là module.
    • Không chỉ quy mô, nếu yêu cầu về độ tin cậy hoặc tính sẵn sàng khác biệt cực đoan thì việc tách service riêng cũng hợp lý. Tách biệt các mối quan tâm để duy trì SLA có thể giúp giảm rủi ro và tăng tốc triển khai.
    • Nhưng ngay cả trong những trường hợp này, có người cho rằng điều đó cũng không khác mấy so với việc chỉ vận hành riêng DB server.
  • Thành quả thật sự của microservices nằm ở mặt tổ chức: chia vấn đề thành từng mảnh, để mỗi team sở hữu trọn vẹn một phần và chịu trách nhiệm từ đầu đến cuối nên có thể chuyên môn hóa. Thay đổi về bản chất diễn ra dần dần, và API là con đường tương tác duy nhất; không có chuyện dùng chung một DB, file system hay API. Bù lại, chuẩn hóa và tooling quản trị như monitoring, test, CI/CD là rất quan trọng, dù với monolith hay kiểu nào khác thì ở mức nào đó vẫn đều cần.
    • Hạ tầng, logging, auth... có thể được đóng gói hoặc quản lý qua gRPC, message queue... Việc tạo service mới nhanh hơn, merge request trong nội bộ team cũng nhỏ hơn nên ít xung đột hơn và năng suất tăng lên. Khi quy mô 5-10 người, lúc còn dùng monolith thường xuyên gặp xung đột, vấn đề triển khai và phát hành; sau khi chuyển sang microservices thì năng suất, khả năng cộng tác và tài liệu README đều được cải thiện. Tuy nhiên các quy tắc về test, tài liệu hóa và endpoint là rất quan trọng.
    • Cũng có những trường hợp phải tách về mặt kỹ thuật, chẳng hạn vì tách DB hay hiệu năng, nhưng với startup thông thường thì điều này có thể hiếm.
  • Điểm mạnh của hệ sinh thái BEAM/OTP (Erlang, Elixir) là có thể giữ monolith nhưng vẫn luyện tập kiểu thiết kế “giống microservices”, rồi khi thật sự cần tách thì chuyển đổi dễ dàng. Khi còn nhỏ thì hưởng lợi từ monolith, khi lớn lên thì đồng thời có thể đạt được khả năng mở rộng và tính độc lập. Tuy nhiên cũng cần học về immutable object, giao tiếp đồng thời và quản lý lỗi, đồng thời việc tuyển người cũng có thể khó.
  • Phần lớn mọi người đồng ý rằng trong môi trường startup thì gần như không thể xác định ranh giới service cho đúng. Tuy vậy, với team nhỏ, đôi khi microservices lại có ích vì API bên ngoài hoặc phụ thuộc phức tạp. Trong trường hợp đó, ranh giới mạng là bắt buộc nên biến nó thành service riêng cũng không làm độ phức tạp tăng quá nhiều. Hoặc khi build/deploy quá phức tạp thì việc tách ra cũng có thể giúp đơn giản hóa monolith.
  • Microservices chỉ phù hợp khi cần mở rộng rất lớn hoặc cần micro-manage các team. Không nên từ bỏ việc xác lập ranh giới module rõ ràng. Có thể tận dụng ưu điểm của microservices ngay bên trong monolith bằng phong cách hướng đối tượng theo message passing. Cần rèn thói quen không chạm trực tiếp vào DB; trong các ngôn ngữ như Java có thể làm module hóa, namespace schema DB và chỉ công khai các interface tối thiểu, đồng thời vẫn test và monitor độc lập được. Việc triển khai nhiều service cùng lúc cũng trở nên dễ hơn.
    • Nếu hiểu đủ rõ các ranh giới logic thì còn có thể dùng công cụ như ArchUnit để cưỡng chế chúng.