
Một codebase được quản lý bằng version control, nhiều môi trường triển khai
- Theo tài liệu gốc, một ứng dụng Twelve-Factor phải có một codebase được theo dõi bằng hệ thống quản lý phiên bản như Git, và nhiều deploy khác nhau có thể chạy từ codebase đó.
- Twelve-Factor nhấn mạnh quan hệ 1–1 giữa app và codebase: một app thì có một codebase; nếu có nhiều codebase thì về bản chất đó là một distributed system gồm nhiều app/thành phần.
- Nhiều ứng dụng cùng dùng chung một đống code trong cùng một repo theo kiểu “copy dùng tạm” là dấu hiệu dễ gây rối. Tài liệu gốc khuyên nên tách phần dùng chung thành library/dependency thay vì để nhiều app “dính” vào cùng một codebase mơ hồ.
- Đây là nền móng để team làm việc rõ ràng hơn, deploy dễ hơn, và giảm cảnh “máy em chạy được mà”. Tinh thần đó cũng nằm trong mục tiêu chung của Twelve-Factor: giảm chênh lệch giữa development và production, tăng tính portable và khả năng scale.
1) Mở bài: vì sao junior rất dễ vấp ở factor này?
Hãy tưởng tượng team của bạn có một hệ thống “quản lý công việc nội bộ”. Ban đầu chỉ có một web app. Sau vài tháng, team thêm worker xử lý email, thêm một admin tool để sửa dữ liệu, rồi thêm một service đồng bộ sang hệ thống khác.
Lúc này bắt đầu có những câu rất quen:
- “Code phần gửi email nằm repo nào nhỉ?”
- “Sao staging khác production?”
- “Script này lấy từ service A hay service B?”
- “Copy tạm folder common từ project cũ sang đi.”
Khi những câu này xuất hiện thường xuyên, vấn đề thường không nằm ở Git khó dùng, mà nằm ở chỗ ranh giới của ứng dụng đang bị mờ.
Factor I của Twelve-Factor giải quyết đúng chỗ đó: một app phải có một codebase rõ ràng, được quản lý bằng version control, và từ codebase đó có thể có nhiều deploy như local, staging, production.
2) Định nghĩa gốc của Factor I
Tên chính thức của factor này là:
“One codebase tracked in revision control, many deploys.”
Diễn giải rất dễ hiểu cho người mới:
Một ứng dụng nên có một nơi duy nhất để định danh “đây là code của nó”. Nơi đó được quản lý bằng version control như Git. Từ cùng codebase này, bạn có thể triển khai ra nhiều môi trường khác nhau: máy dev, staging, production.
Tài liệu gốc còn nói rõ mấy ý rất quan trọng:
- App Twelve-Factor luôn được theo dõi bằng hệ thống revision control như Git, Mercurial hoặc Subversion.
- Một codebase có thể là một repo, hoặc một tập repo có chung root commit trong mô hình phân tán.
- Có mối tương quan 1–1 giữa codebase và app.
- Nếu có nhiều codebase thì đó không còn là một app đơn lẻ, mà là một distributed system; mỗi thành phần của hệ đó có thể được xem như một app riêng.
- Nhiều app cùng chia sẻ một codebase là vi phạm Twelve-Factor; cách xử lý là tách phần dùng chung thành library để quản lý qua dependency manager.
Đây là một trong 12 nguyên lý cốt lõi của Twelve-Factor, một methodology được thiết kế cho các ứng dụng chạy như service, nhấn mạnh tính portable, giảm khác biệt giữa dev và prod, và hỗ trợ scale mà không phải đổi hẳn cách làm phần mềm.
3) Factor này thật sự muốn giải quyết vấn đề gì?
Nói ngắn gọn: sự mập mờ.
Một khi team không trả lời rõ được câu hỏi “đâu là source of truth cho ứng dụng này?”, rất nhiều rắc rối kéo theo:
- Không biết phiên bản nào đang chạy ở staging hay production.
- Sửa bug ở một nơi nhưng quên sửa ở nơi khác.
- Copy-paste code giữa nhiều project rồi dần dần mỗi nơi lệch đi một chút.
- Người mới vào team không biết phải clone repo nào để chạy đúng ứng dụng.
- CI/CD khó thiết lập vì ranh giới app không rõ.
Twelve-Factor được viết ra để tạo ra một “từ vựng chung” cho những vấn đề kiểu này và đưa ra các nguyên lý giúp tránh software erosion — tức là hệ thống bị mục dần theo thời gian vì cách phát triển thiếu kỷ luật.
4) Hiểu đúng “codebase” là gì
Junior hay hiểu “codebase” là “một repo Git”. Hiểu vậy không sai hoàn toàn, nhưng hơi hẹp.
Theo tài liệu gốc, codebase có thể là:
- một repo duy nhất, hoặc
- một tập repo có chung root commit trong hệ quản lý phiên bản phân tán.
Điểm mấu chốt không phải là tranh luận monorepo hay polyrepo, mà là:
Mỗi app phải có một ranh giới code rõ ràng và một nguồn sự thật rõ ràng.
Nói cách khác:
- Twelve-Factor không bắt buộc mọi người phải dùng monorepo.
- Twelve-Factor cũng không cổ vũ việc một app bị xé thành nhiều mảnh rời rạc mà không còn định danh rõ cái nào là app nào.
- Cái nó quan tâm là: app này có codebase rõ chưa, có version control chưa, có deploy từ cùng nguồn rõ ràng chưa?
5) “Many deploys” nghĩa là gì?
Đây là chỗ nhiều bạn mới đọc lướt rất dễ bỏ qua.
Tài liệu gốc nói rõ: một app có một codebase, nhưng có thể có nhiều deploy. Deploy là một instance đang chạy của app. Ví dụ:
- production
- staging
- local development của từng developer
Điều này rất quan trọng vì nó dẫn tới một tư duy lành mạnh:
- Local của bạn không phải một “biến thể kỳ lạ” ngoài luồng.
- Staging không phải một “project khác”.
- Production không phải một “phiên bản bí ẩn” nobody knows.
Tất cả đều là những deploy khác nhau của cùng một app. Khác nhau ở version đang active hoặc config, nhưng vẫn cùng một codebase gốc. Tài liệu gốc còn nêu ví dụ: dev có thể có commit chưa lên staging, staging có thể có commit chưa lên production, nhưng chúng vẫn là các deploy khác nhau của cùng một codebase.
6) Ví dụ dễ hiểu bằng đời thường
Hãy nghĩ đến một cuốn sách.
- Codebase giống như bản thảo chính thức của cuốn sách.
- Deploys giống như các bản in:
- bản nháp trên bàn tác giả
- bản gửi biên tập viên
- bản phát hành chính thức
Các bản in có thể khác nhau chút về phiên bản, nhưng chúng đều xuất phát từ một bản thảo chính thức.
Điều nguy hiểm là khi bạn có:
- một nửa nội dung nằm ở file Word A,
- nửa còn lại ở file Word B,
- vài chương được copy sang file C để “dùng tạm”.
Lúc đó bạn không còn biết đâu là bản gốc nữa. Đó chính là thứ Factor I muốn ngăn từ sớm.
7) Ví dụ minh họa trong một ứng dụng mẫu
Ta dùng xuyên suốt series một ứng dụng mẫu: TaskFlow, một SaaS quản lý công việc cho đội nhóm.
Cách làm đúng
TaskFlow có:
- 1 repo cho web app/backend API
- 1 repo riêng cho worker xử lý email nền
- 1 repo riêng cho service đồng bộ dữ liệu sang CRM
Ở đây:
- web app là một app
- worker là một app
- sync service là một app
Ba thành phần này có thể tạo thành một distributed system, nhưng mỗi thành phần đều có codebase rõ ràng của riêng nó. Cách hiểu này khớp với tài liệu gốc: nếu có nhiều codebase thì đó là một distributed system, và mỗi component có thể tuân thủ Twelve-Factor riêng.
Cách làm sai
Team để:
- web app, worker, admin script, cron jobs, và 2 tool nội bộ chung trong một đống repo
- không có ranh giới rõ “cái nào là app chính”
- ai cần gì thì copy folder
shared_oldsang project khác
Hậu quả:
- bug fix ở service này không sang service kia
- dependency cập nhật lệch nhau
- deploy nhầm
- không ai dám xóa code vì sợ chạm vào app khác
8) Dấu hiệu hệ thống đang vi phạm factor này
Nếu bạn thấy các dấu hiệu sau, khả năng cao Factor I đang có vấn đề:
- Không trả lời ngay được: “App này nằm ở repo nào?”
- Nhiều app cùng sống trong một repo nhưng không có ranh giới rõ.
- Một app bị tách thành nhiều repo chỉ vì “team chia vậy cho tiện”, không có cách truy vết version tổng thể.
- Shared code được copy-paste giữa nhiều project thay vì đóng gói thành package/library.
- Production chạy từ một nhánh hoặc file zip “đặc biệt” mà không ai trong team dev dùng hằng ngày.
- Onboarding junior phải nghe kiểu: “em clone repo A trước, rồi copy thư mục từ repo B sang repo A, rồi chạy script riêng”.
Những dấu hiệu này không phải nguyên văn từ Twelve-Factor, nhưng chúng là hậu quả thực tế của việc không có một codebase rõ ràng cho mỗi app. Tinh thần gốc của factor là loại bỏ sự nhập nhằng giữa app, code và deploy.
9) Trường hợp thực tế đã được xác minh
Một ví dụ hiện đại được xác minh từ chính blog Twelve-Factor: Intuit cho biết họ đã dùng các nguyên lý Twelve-Factor như một framework định hướng cho phát triển phần mềm hiện đại trong nền tảng nội bộ của họ. Trong bài viết đó, họ nêu ArgoCD dùng Git làm “single source of truth” cho cấu hình ứng dụng, hỗ trợ tính nhất quán giữa các môi trường và việc triển khai từ một codebase rõ ràng, đồng thời tách config khỏi code.
Điều cần nói rõ để tránh hiểu sai:
- Đây là một ví dụ hiện đại về cách doanh nghiệp vận dụng tinh thần Twelve-Factor.
- Nó không có nghĩa mọi chi tiết của ArgoCD hay GitOps đều là nội dung gốc của Factor I.
- Nội dung gốc của Factor I vẫn là: một codebase, version control, nhiều deploy. Phần GitOps/ArgoCD là lớp diễn giải hiện đại dựa trên tinh thần đó.
10) Junior thường hiểu sai ở đâu?
Hiểu sai 1: “Factor này chỉ bảo dùng Git”
Không. Git chỉ là công cụ. Ý chính là có một nguồn sự thật được quản lý bằng revision control. Git rất phổ biến, nhưng không phải nội dung cốt lõi duy nhất.
Hiểu sai 2: “Một repo chứa nhiều service là sai hoàn toàn”
Không hẳn. Điều Twelve-Factor quan tâm là mối quan hệ giữa app và codebase phải rõ. Nếu bạn dùng monorepo nhưng vẫn xác định rành mạch từng app/thành phần, quy trình build/deploy độc lập, dependency rõ ràng, thì vấn đề không nằm ở việc “một repo hay nhiều repo”, mà ở ranh giới ứng dụng có rõ không. Đây là phần diễn giải thực tế từ nguyên lý gốc, không phải câu chữ nguyên văn của tài liệu. Nguyên lý gốc chỉ khẳng định quan hệ 1–1 giữa app và codebase.
Hiểu sai 3: “Local của em khác staging một chút cũng không sao”
Lệch quá nhiều sẽ dẫn đến bug khó lường. Twelve-Factor đặt nền cho việc xem local, staging, production đều là các deploy của cùng một app. Tư duy đó sẽ còn được nhấn mạnh mạnh hơn ở Factor X: Dev/Prod Parity.
Hiểu sai 4: “Shared code để chung luôn trong app cho tiện”
Tài liệu gốc nói khá rõ: nhiều app chia sẻ cùng codebase là vi phạm; phần dùng chung nên được tách thành library và đưa vào qua dependency manager.
11) Làm sai thì hậu quả gì?
Một số hậu quả rất thật trong dự án:
a) Không truy được nguồn gốc lỗi
Khi production lỗi, team không chắc production đang chạy từ commit nào hoặc nhánh nào.
b) Bug sửa không đồng bộ
Một đoạn code validation được copy sang 3 app khác nhau. App A sửa rồi, app B và C quên sửa.
c) Deploy rủi ro
CI/CD không biết “đầu vào chính thức” của app là gì, nên pipeline chắp vá, nhiều bước thủ công.
d) Onboarding chậm
Junior mới vào phải học “các mẹo truyền miệng” thay vì chỉ cần clone đúng repo và chạy đúng hướng dẫn.
e) Hệ thống lớn dần theo kiểu mục ruỗng
Ban đầu vẫn chạy được, nhưng mỗi tháng chi phí nhận thức tăng lên. Đây đúng kiểu “software erosion” mà tài liệu giới thiệu của Twelve-Factor muốn giúp tránh.
12) Áp dụng đúng trong team như thế nào?
Bước 1: Xác định ranh giới app
Mỗi thành phần có chạy/triển khai/vận hành độc lập không?
Nếu có, rất có thể đó nên được xem là một app riêng với codebase rõ ràng.
Ví dụ:
- API server
- background worker
- sync service
- admin dashboard
Không phải cứ liên quan nghiệp vụ với nhau là phải chung một app.
Bước 2: Chốt source of truth
Với mỗi app, trả lời rõ:
- Repo nào là repo chính thức?
- Nhánh phát hành thế nào?
- Commit nào lên staging?
- Commit nào lên production?
Bước 3: Shared code thì đóng gói thành dependency
Thay vì copy-paste:
- tách thành internal package
- dùng dependency manager
- version hóa rõ ràng
Đây là hướng đi mà tài liệu gốc nêu trực tiếp.
Bước 4: Xem mọi môi trường là deploy của cùng app
Local, staging, production phải cùng xuất phát từ codebase đó. Khác biệt nên nằm ở version đang chạy và config, chứ không phải “một đống code bí mật riêng cho production”.
Bước 5: Viết README/onboarding đúng nghĩa
Một junior mới vào nên có thể:
- clone đúng codebase
- cài dependency
- chạy app local
- biết rõ local đó là một deploy của app
13) Diễn giải trong bối cảnh hiện đại
Đây là phần mở rộng theo bối cảnh hiện đại, không phải câu chữ gốc của tài liệu năm 2011/2017.
Trong thời cloud-native, containers và Kubernetes làm hệ thống dễ tách nhỏ hơn, nhưng cũng khiến team dễ rơi vào bẫy “service hóa mọi thứ” mà không rõ ranh giới. Blog Twelve-Factor năm 2025 cũng thừa nhận bối cảnh hiện đại đã xuất hiện thêm độ phức tạp mới, và cộng đồng đang tìm cách diễn giải lại các nguyên lý kinh điển cho phù hợp hơn với platform hiện đại.
Với Docker/Kubernetes
Factor I gợi ý:
- image phải build từ source rõ ràng
- manifest deploy phải trỏ đến artifact/version rõ ràng
- không có chuyện “vào container sửa tay cho nhanh”
Với CI/CD
Factor I gợi ý:
- pipeline phải biết chính xác repo nào đại diện cho app
- release phải truy vết được về commit/source rõ ràng
Với GitOps
Tinh thần của Factor I rất hợp với tư duy “source of truth”, nhưng cần nhớ:
- GitOps là thực hành hiện đại
- còn Factor I là nguyên lý nền
- đừng đồng nhất hai thứ như thể chúng là một.
14) Checklist tự đánh giá
Hãy tự hỏi về hệ thống của bạn:
- Tôi có thể chỉ ra ngay codebase chính thức của app này không?
- Team có thống nhất repo nào là nguồn sự thật không?
- Local, staging, production có phải đều là deploy của cùng app không?
- Shared code có được tách thành package/library thay vì copy-paste không?
- Khi production lỗi, tôi có thể truy ngược về commit/version tương ứng không?
- Nếu app này thực chất là nhiều thành phần độc lập, team có nhận diện đó là distributed system và tách ranh giới rõ chưa?
Nếu bạn trả lời “không chắc” cho từ 2 câu trở lên, Factor I có lẽ đang là điểm cần sửa trước.
15) Tóm tắt nhanh
- Factor I yêu cầu: một app, một codebase rõ ràng, được quản lý bằng version control, nhiều deploy.
- Local, staging, production không phải các “project khác nhau”, mà là các deploy khác nhau của cùng app.
- Nếu có nhiều codebase, về bản chất bạn đang có một distributed system gồm nhiều thành phần/app.
- Nhiều app dùng chung một codebase là dấu hiệu xấu; shared code nên tách thành library/dependency.
- Đây là factor đầu tiên vì nó buộc team trả lời câu cơ bản nhất: “Rốt cuộc app của mình là cái gì?”
16) 3 câu hỏi tự kiểm tra
- Vì sao Twelve-Factor nhấn mạnh quan hệ 1–1 giữa app và codebase?
- “Many deploys” trong Factor I bao gồm những môi trường nào?
- Khi nhiều app cần dùng chung logic, vì sao tách thành library lại tốt hơn copy-paste code?
17) Bài tập nhỏ
Hãy chọn một dự án bạn đang làm và viết ra 5 dòng sau:
- Tên app
- Repo chính thức của app
- Các deploy hiện có: local / staging / production / khác
- Có shared code nào đang copy-paste không?
- App này thực sự là một app hay là nhiều thành phần của một distributed system?
Sau khi viết xong, bạn sẽ thấy khá nhanh app của mình đang “rõ ràng” hay “mập mờ”.
18) Áp dụng ngay vào dự án của bạn
Ngay hôm nay, bạn có thể làm 3 việc rất nhỏ:
- Viết một câu duy nhất trong README: “This repository is the source of truth for app X.”
- Liệt kê rõ các deploy đang tồn tại của app.
- Tìm một đoạn shared code đang copy-paste ở nhiều nơi và lên kế hoạch tách nó thành package/library.
Chỉ 3 việc này thôi cũng đã giúp Factor I bớt “lý thuyết” và bắt đầu đi vào thực tế.