1 điểm bởi GN⁺ 2023-10-13 | 1 bình luận | Chia sẻ qua WhatsApp
  • The Twelve-Factor App là một phương pháp luận để vận hành và mở rộng ứng dụng web·SaaS trong thời gian dài, đồng thời đề cập đến tự động hóa cấu hình, tính di động, triển khai đám mây và triển khai liên tục
  • Không bị ràng buộc vào một ngôn ngữ lập trình cụ thể hay tổ hợp dịch vụ hỗ trợ như cơ sở dữ liệu, hàng đợi, bộ nhớ đệm trong RAM, nên có thể áp dụng cho nhiều loại ứng dụng dạng dịch vụ
  • Nội dung này dựa trên kinh nghiệm trực tiếp tham gia phát triển và triển khai hàng trăm ứng dụng trên nền tảng Heroku, đồng thời gián tiếp quan sát quá trình phát triển, vận hành và mở rộng của hàng trăm nghìn ứng dụng
  • Vấn đề cốt lõi là cung cấp một bộ từ vựng chung để giảm chi phí cộng tác và sự bào mòn phần mềm khi ứng dụng tăng trưởng một cách hữu cơ
  • Không chỉ dành cho các nhà phát triển xây dựng ứng dụng dịch vụ mà còn có thể được các kỹ sư vận hành dùng như một tiêu chuẩn thực tiễn để triển khai và quản lý

12 nguyên tắc vận hành cho ứng dụng SaaS

  • Phần mềm hiện đại thường được cung cấp dưới dạng ứng dụng web hoặc SaaS, và Twelve-Factor App là một phương pháp luận để xây dựng những ứng dụng như vậy
  • Mục tiêu là làm cho quá trình phát triển·triển khai·vận hành ứng dụng trở nên dễ dự đoán hơn
    • Sử dụng tự động hóa cấu hình theo kiểu khai báo để giảm thời gian và chi phí khi thành viên mới tham gia dự án
    • Thiết lập một hợp đồng rõ ràng với hệ điều hành nền tảng để tăng tính di động giữa các môi trường chạy
    • Được thiết kế để giảm gánh nặng quản trị máy chủ và hệ thống, đồng thời phù hợp với việc triển khai trên nền tảng đám mây hiện đại
    • Giảm khác biệt giữa môi trường phát triển và môi trường production để cho phép triển khai liên tục
    • Có thể mở rộng mà không cần thay đổi lớn về công cụ, kiến trúc hay thực hành phát triển
  • Phạm vi áp dụng không bị giới hạn ở một stack công nghệ cụ thể
    • Có thể áp dụng cho ứng dụng được viết bằng bất kỳ ngôn ngữ lập trình nào
    • Dịch vụ hỗ trợ bao gồm cơ sở dữ liệu, hàng đợi, bộ nhớ đệm trong RAM, v.v.

Bối cảnh được đúc kết từ kinh nghiệm Heroku

  • Những người đóng góp đã trực tiếp tham gia phát triển và triển khai hàng trăm ứng dụng trên nền tảng Heroku, đồng thời gián tiếp quan sát quá trình phát triển, vận hành và mở rộng của hàng trăm nghìn ứng dụng
  • Dựa trên kinh nghiệm và quan sát từ các ứng dụng SaaS thực tế, họ đã tổng hợp các thực hành lý tưởng cho việc phát triển ứng dụng
    • Chú ý đến dòng chảy mà trong đó ứng dụng tăng trưởng một cách hữu cơ theo thời gian
    • Đề cập đến cách nhiều nhà phát triển cộng tác trên cùng một codebase
    • Xem tránh chi phí bào mòn phần mềm là một mục tiêu quan trọng
  • Hình thức trình bày được lấy cảm hứng từ Patterns of Enterprise Application ArchitectureRefactoring của Martin Fowler

12 yếu tố

  • I. Codebase: Có một codebase được quản lý phiên bản và nhiều môi trường triển khai
  • II. Dependencies: Khai báo và cô lập dependency một cách tường minh
  • III. Config: Lưu cấu hình trong môi trường
  • IV. Backing services: Xem dịch vụ hỗ trợ như các tài nguyên được gắn kết
  • V. Build, release, run: Tách biệt nghiêm ngặt giai đoạn build và giai đoạn chạy
  • VI. Processes: Chạy ứng dụng như một hoặc nhiều process không trạng thái
  • VII. Port binding: Cung cấp dịch vụ ra bên ngoài bằng port binding
  • VIII. Concurrency: Scale-out bằng mô hình process
  • IX. Disposability: Tăng độ vững chắc bằng khởi động nhanh và kết thúc êm ái
  • X. Dev/prod parity: Giữ môi trường phát triển, staging và production giống nhau nhiều nhất có thể
  • XI. Logs: Xem log như một luồng sự kiện
  • XII. Admin processes: Chạy tác vụ quản trị như các process dùng một lần

1 bình luận

 
GN⁺ 2023-10-13
Ý kiến trên Hacker News
  • 12-Factor App là một bộ khuyến nghị được tạo ra năm 2011, dựa nhiều hơn vào Heroku và những hạn chế của hạ tầng dạng container thời đó, chứ không giống một tài liệu dựa sâu trên các nguyên tắc kỹ thuật
    Ví dụ, lập luận rằng nên đưa cấu hình vào biến môi trường là vì các tác giả làm ở Heroku, và Heroku khi đó điền biến môi trường thông qua các trường nhập liệu của ứng dụng web
    Nếu muốn theo dõi lịch sử cấu hình bằng quản lý phiên bản, dùng GitOps, dùng ConfigMap của k8s, hoặc đặt tệp cấu hình trên volume được mount, thì nhìn chung tất cả đều là lựa chọn ổn. Vì chúng tách trạng thái cấu hình khỏi trạng thái triển khai ứng dụng
    Tôi xem tài liệu này là một guideline có hại, vì nó nhầm lẫn giữa rừng và cây, và đưa ra khuyến nghị phù hợp với tính năng sản phẩm của công ty viết ra nó hơn là với các nguyên tắc kỹ thuật thực sự

    • Đúng là nó chịu ảnh hưởng ở mức nào đó từ cách Heroku hoạt động, nhưng ConfigMapGitOps không đáp ứng được các yêu cầu bảo mật và khả dụng giống như cấu hình/biến môi trường của Heroku
      Nếu muốn lưu cấu hình an toàn trong Kubernetes, cuối cùng bạn sẽ dùng Secrets, và nó cũng có dạng khóa-giá trị như biến môi trường. Nếu muốn có mức bảo mật tương tự trong Git, bạn cần một lớp mã hóa, khi đó việc so sánh diff bị hỏng và cần thêm công cụ
      Cuối cùng lại quay về lý do vì sao các công cụ triển khai cấp cao như Heroku được tạo ra
    • Giờ không còn ai gọi là 12 factor nữa, nhưng nhờ nó mà mọi người vẫn đang tuân theo các nguyên tắc phổ biến. 12-Factor là tài liệu có trước khi Docker và Kubernetes trở thành chủ đạo
      Nguyên tắc xem log là stream vẫn đúng. Hãy ghi log ra STDOUT thay vì vào file, rồi để orchestrator đọc và lưu lại
      Cấu hình được lấy từ môi trường. Tùy cách triển khai, ứng dụng có xu hướng đọc cấu hình từ các nguồn khác nhau, chẳng hạn .env ở local và kho bí mật ở production
      Port binding cũng tương tự: ứng dụng mở port, rồi đặt thứ như nginx ở phía trước để cấu hình reverse proxy. Service và ingress của K8S đảm nhiệm vai trò đó
      Phê phán lớn nhất có thể dành cho 12-Factor ngày nay là tài liệu thực ra không được viết tốt, và giả định rằng người đọc đã biết chính xác nó đang nói về điều gì
    • Heroku không phát minh ra biến môi trường, cũng không phải là bên đầu tiên nghĩ đến việc dùng chúng cho cấu hình ứng dụng. Đây là cách làm đã được dùng từ lâu trước Heroku
      Tuy nhiên, cũng phải công nhận công lao của Heroku trong việc phổ biến khái niệm này và mở rộng việc sử dụng nó
    • “Lưu cấu hình trong môi trường” không nhất thiết có nghĩa là đưa cấu hình vào biến môi trường. Nó có nghĩa là cấu hình đến từ môi trường hosting, chứ không phải từ chính ứng dụng
      Không phải kiểu thêm settings.json vào máy trước khi khởi động ứng dụng, mà là cùng một source khi được triển khai lên cụm AKS ở Azure EU north thì dùng các giá trị được cấu hình trong cụm đó, còn khi được triển khai lên cụm RPi Zero Docker Swarm trong khung ảnh Ikea thì dùng cấu hình của cụm đó
      Tên cụm đó là Gibson
    • Các ứng dụng 12-Factor vốn đưa cấu hình vào biến môi trường thì việc chuyển sang ConfigMap rất đơn giản. Ngược lại, các ứng dụng nghiệp vụ ngày nay với layout ConfigMap phức tạp, tệ nhất là phụ thuộc trực tiếp vào API k8s, sẽ trở thành địa ngục khi migrate sang thứ gì đó xuất hiện sau k8s
  • Tôi cảm thấy từng mục này đều có thể bị phản bác khá hợp lý
    Thứ nhất, nguyên tắc một ứng dụng một repository không sai về căn bản. Nhưng cũng không có vấn đề gì khi phát triển trong cùng một repository nhiều ứng dụng được liên kết chặt về mặt chức năng và chia sẻ chu kỳ release, nhưng cần triển khai riêng để có được lợi ích của các process tách biệt và khả năng scale độc lập. Tôi nghĩ đến việc tách public API và worker process, chẳng hạn Sidekiq của Ruby, Celery của Python, hay các Kafka consumer thông thường
    Thứ hai, câu “ứng dụng 12-Factor không phụ thuộc vào sự tồn tại ngầm định của các package toàn hệ thống” thực tế rất khó đạt được nếu không dùng thứ như Nix. Sự phụ thuộc vào API system call của kernel cũng bị rò rỉ ra ngoài, và hầu hết ứng dụng Rust đều phụ thuộc ngầm vào glibc, trừ musl. Ngoài các bản phân phối slim như Alpine, glibc hiện diện trên các bản phân phối Linux lớn. Tôi cho rằng Docker cũng là một chỗ dựa cần thiết để giảm nhẹ vấn đề này
    Thứ ba, lưu cấu hình trong biến môi trường có vẻ mong manh hơn. Việc buộc đưa secret vào môi trường có thể làm giảm bảo mật, và khiến ta từ bỏ cấu hình dạng file có cấu trúc, vốn có thể hưởng lợi từ type safety, autocomplete trong IDE và parsing tự động. Với biến môi trường, bạn phải tự triển khai parser cho các giá trị cấu hình phức tạp không phải chuỗi. Trên thực tế, chúng cũng thường được lưu dưới dạng file .env và commit vào repository, nên lập luận về an toàn khi commit cũng trở nên vô nghĩa

    • Bạn đang diễn giải sai chỉ dẫn đó. Bản gốc nói về các thư viện hỗ trợ được cài bằng hệ thống đóng gói theo ngôn ngữ như CPAN hoặc Rubygems, và giải thích rằng các thư viện như vậy có thể được cài dưới dạng “site packages” toàn hệ thống
      Nó không có nghĩa là đừng phụ thuộc vào hệ điều hành, bao gồm glibc, mà là đừng khiến ứng dụng chỉ chạy được khi một package của trình quản lý package cho ngôn ngữ cụ thể đã được cài trên máy
      Tôi đồng ý với các điểm còn lại. Đặc biệt, câu chuyện biến môi trường có vẻ giống việc các tác giả giả định cách làm phổ biến trong phát triển Ruby thời đó là tốt nhất rồi viết ra, hơn là một lời khuyên thực sự có cơ sở
    • Nếu chúng được triển khai riêng thì chúng không chia sẻ chu kỳ release. Rốt cuộc, một lúc nào đó có thể chạy một tổ hợp phiên bản không khớp. Ví dụ, chỉ một mảnh có thể triển khai thất bại
      Vì vậy phải chuẩn bị cho tình huống đó, và để dễ kiểm thử các tổ hợp phiên bản khác nhau, tôi nghĩ repository riêng là tốt hơn
      Phần lớn ngôn ngữ cấp cao không phụ thuộc vào một glibc cụ thể. Nếu runtime của ngôn ngữ đó hoạt động đúng, ứng dụng cũng chạy trên đó. Tất nhiên trong một số trường hợp bạn sẽ dùng thứ như Docker. Việc khó không có nghĩa là không có giá trị
    • Nếu đó là phần căn bản thì tôi không đồng ý. Tôi nghĩ phần lớn thế giới đồng ý với tôi và với các nguyên tắc 12-Factor hơn
    • Tôi đồng ý với góc nhìn về quy tắc đầu tiên, và sẵn sàng đặt nhiều ứng dụng liên quan trong cùng một repository. Vì không có cơ sở nào được đưa ra cho việc vì sao một repository chỉ nên chứa một ứng dụng, nên có thể bỏ qua quy tắc đó
      Các ngôn ngữ động hoặc ngôn ngữ managed thường có thể bỏ qua phần lớn rắc rối liên quan đến package hệ thống
    • Hiệu dụng của monorepo có dạng chữ U. Phần lớn dự án nằm đâu đó ở giữa, đặc biệt là các dự án do các đội kỹ thuật độc lập quản lý, không có đội nền tảng/DevOps tập trung/hay ngày nay gọi là gì cũng được
  • Nhìn chung thì tôi thích, nhưng đã có quá nhiều lần người không chuyên kỹ thuật hoặc chỉ biết nửa vời về kỹ thuật lôi “12 factor” ra như một lá thẻ vàng vạn năng để trì hoãn release, đến mức gần như tôi đã bỏ qua hoàn toàn
    Thật ra “agile” cũng tương tự. Tôi hiểu ý đồ của những guideline kiểu này, nhưng giá trị thực tế của chúng có vẻ hữu ích hơn nhiều cho những người chỉ có thể mang lại lãnh đạo kỹ thuật kiểu tháp ngà

    • Về nguyên tắc, bỏ qua hoàn toàn cũng tệ không kém những người đối xử với nó như giáo điều bắt buộc
      Tôi từng gặp trường hợp junior engineer quá nhiệt tình hoặc người muốn làm kiến trúc sư dùng bài viết 12-Factor như yêu cầu bắt buộc cho mọi lần phát hành
      Những thứ này là mục tiêu tốt đáng theo đuổi, nhưng trong thực tế phải giải thích một cách dứt khoát và nhất quán rằng để release thì cần thỏa hiệp, và phải chọn phần nào sẽ làm chậm hoặc trì hoãn
    • Người ta gọi đó là giáo điều bị vũ khí hóa. Dù vậy, tôi vẫn thấy còn đỡ hơn những người khăng khăng theo DRY đến mức tạo ra các hàm helper generic không thể hiểu nổi chỉ để giảm 3–4 dòng code lặp
    • Cần phải đưa ví dụ. Giống như hầu hết mọi thứ, nó phụ thuộc vào ngữ cảnh và có vùng xám, nhưng tôi nghĩ đa số developer dùng 12-Factor như sao Bắc Đẩu
      Sẽ không chặn release chỉ vì một sai lệch nhỏ, nhưng nếu nhìn tổng thể mà không phù hợp thì ít nhất nên xem đó là nợ kỹ thuật. Nếu một release nào đó thụt lùi nghiêm trọng ở một mục, thì chặn lại, hoặc ít nhất buộc phải xem xét kỹ hơn vì sao họ cho rằng sự đánh đổi đó đáng giá, là điều công bằng
    • Không giáo điều nào được cản trở việc triển khai trong phạm vi MVP. Sau khi vượt ra khỏi MVP, mọi thứ chưa xử lý được dưới góc nhìn best practice đều trở thành nợ kỹ thuật
      Nếu tổ chức đã chọn 12FA làm best practice thì nên đáp ứng, nhưng không được để nó chặn triển khai
      12FA không phải là một ô checkbox duy nhất cần tick. Khi sản phẩm trưởng thành, có thể, và phần lớn là nên, triển khai bằng cách thêm từng mục một vào sản phẩm, nếu cần thì chia nhỏ hơn nữa
      Nếu ngay từ đầu đã làm engineering tốt, tức là có abstraction và interface phù hợp, không hardcode mọi thứ, thì chuyện này không nên là vấn đề
      YAGNI cũng bị lạm dụng chẳng kém 12FA. Điều thiếu lớn nhất ở 12FA là ví dụ cụ thể để junior engineer có thể tham khảo
    • Trước đây tôi từng gặp vấn đề như vậy, và giải pháp là có quy trình được tài liệu hóa rõ ràng rồi chỉ mọi người về đó
      Tôi đã học cách nhìn nhận những vấn đề này với thiện chí. Cần xem vì sao họ nêu vấn đề, quy trình hiện tại có không rõ ràng, có khiếm khuyết, hay thiếu độ tin cậy không
      Nếu phát hiện lo ngại hợp lý thì chỉ cần thay đổi quy trình và cập nhật tài liệu
  • Twelve-Factor App nói hãy dùng environment cho cấu hình, còn Docker nói đừng dùng environment cho cấu hình, vì không an toàn
    Tôi thích và dùng nhiều pattern của 12-Factor, nhưng một số được viết trong bối cảnh VPS. Khi đó environment ổn định, an toàn và cố định hơn, còn trong container thì environment có thể bị đưa vào một layer nào đó
    Trong thời đại container, mục cụ thể này khá gây đau đầu. Docker secrets cũng không phải lúc nào cũng khớp tốt, nên để làm cho nó chạy được phải cần đủ kiểu nhào lộn

    • Có thể giải thích chi tiết hơn không? Tôi tò mò environment variable không an toàn ở điểm nào. Nếu secret phải tồn tại trong suốt vòng đời ứng dụng thì tôi không biết lựa chọn thay thế nào tốt hơn
      Việc inject secret vào app dưới dạng environment variable không có nghĩa là toàn bộ quá trình xử lý bên ngoài đó cũng không an toàn. Ví dụ container AWS ECS có hỗ trợ tích hợp để lấy secret từ Secret Manager lúc khởi động rồi truyền vào environment variable: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/...
      Secret được lấy tại thời điểm container khởi động, từ Secret Manager bằng IAM credential của ứng dụng đang chạy. Vì vậy nó phải có quyền đối với secret đó
      Lợi ích của việc dùng environment variable dường như hoàn toàn phụ thuộc vào cuối cùng nó được thiết lập như thế nào. Với cơ chế kiểu này thì tôi không thấy nhược điểm lớn nào
      Nhược điểm chính có thể thấy là malware thông thường muốn dump environment variable có thể bắt được giá trị, nhưng nếu bạn không tránh việc lưu secret vĩnh viễn trong bộ nhớ thì việc chống mối đe dọa đó phần lớn chỉ gần như là obfuscation
    • Ngược lại, nếu không có hỗ trợ từ platform thì không có nhiều lựa chọn thay thế dễ dàng. Ít nhất nó khuyến khích tách cấu hình khỏi code, và giúp để secret bên ngoài hệ thống quản lý phiên bản
    • Vì lý do này tôi chưa bao giờ thích cách đưa secret vào environment variable. Những debug console cẩu thả vô tình làm lộ environment variable xảy ra thường xuyên đến mức đáng ngạc nhiên
      Việc private key bị lộ như vậy là điều thật sự nên tránh
      Cách mount secret vào filesystem bằng k8s thì tôi không thấy có vấn đề gì đặc biệt. Tất nhiên tất cả những điều này phụ thuộc vào môi trường triển khai
      Đôi khi environment variable là lựa chọn ít tệ hơn. Vì secret vốn dĩ lúc nào cũng khó
    • Có thể lập luận rằng không nên xem bất kỳ input nào là “an toàn để tiêu thụ”. Nếu viết app code theo hướng phòng thủ, bạn sẽ không bao giờ giả định ENV là an toàn hoặc đúng dạng mong đợi, mà phải làm sạch trước khi dùng
      Nếu mù quáng tin input chỉ vì là single-tenant, thì sau này khi điều kiện thay đổi do một cú xoay hướng kinh doanh tùy ý, bạn sẽ gặp những bug khó truy vết và nhiều đêm dài
    • Nhìn lại thì tên của section đó lẽ ra nên là tách cấu hình khỏi code, đúng như đã viết trong đoạn đầu tiên
  • Trong vài năm qua tôi đã thảo luận nhiều về app 12-Factor và cũng thấy không ít nhầm lẫn. Trang 12-Factor rất hay, nhưng chủ yếu phù hợp với những người đã hiểu vì sao các mục đó quan trọng.
    Với những người không biết lý do đằng sau các quy tắc, cần có giải thích sâu hơn. Vì vậy tôi đã làm video “What are 12 Factor Apps and Why Should You Care?”[1], và nghe nói một số công ty dùng nó để đào tạo nhân viên mới mảng engineering/DevOps, khá hữu ích.
    Dù học ở đâu, app 12-Factor vẫn đáng để bỏ ra một hai giờ tìm hiểu. Phần lớn “quy tắc” là những điều cần nhận thức; trước khi tự mắc lỗi và chịu đau đớn để học, chúng không hiển nhiên ngay.
    [1] https://youtu.be/REbM4BDeua0

    • Cũng giống unit test. Ý tưởng viết code để test code là điều quá hiển nhiên với tôi từ khi bắt đầu lập trình, nên tôi đã ngạc nhiên vì sao người khác mất lâu đến vậy mới chấp nhận nó.
      Khái niệm “unit test” bắt đầu có traction vào khoảng cuối thập niên 90, và tôi thấy nhẹ nhõm khi có một nhân vật có thẩm quyền đứng ra ủng hộ.
      Lý do tôi không tự làm trước khi Kent Beck công bố JUnit là vì code tôi đang làm không có cấu trúc tốt để được điều khiển bởi code khác. Do biến toàn cục, trạng thái lan rộng, phụ thuộc vào hệ thống bên ngoài và layout hệ thống tệp cụ thể, cùng việc bỏ qua tính mô-đun, nên hầu như không thể chạy gì ngoài ngữ cảnh mà nó được thiết kế cho.
      Tất cả những thứ đó đều là “thiết kế tệ”, nhưng vẫn kịp deadline, nên ai cũng làm vậy. Tôi từng hy vọng rằng khi unit test có traction, lập trình viên sẽ thoát khỏi kiểu thiết kế nguyên khối.
      Sau 25 năm chứng kiến unit test cho getter/setter, và một unit test khổng lồ tạo cả cơ sở dữ liệu in-memory vì mọi hàm trong app chỉ cần chạy thôi cũng đòi cơ sở dữ liệu live, rồi cuối cùng thất bại và bị comment out, tôi đã mất niềm tin rằng unit test sẽ trở thành thứ gì đó hơn một checkbox vô nghĩa. Ai cũng điền vào vì đó là “best practice”, nhưng không dừng lại để nghĩ vì sao mình làm.
  • Tôi luôn ít đồng ý nhất với lời khuyên về cấu hình. Cấu hình thường do nhiều chủ thể định nghĩa, và nhiều khi cả developer cũng định nghĩa, nên thường tốt nhất là đóng gói các giá trị mặc định hợp lý cùng ứng dụng, rồi cho phép ghi đè bằng file theo từng môi trường và biến môi trường.
    Với hầu hết ứng dụng phía server, cách này linh hoạt nhất. Nhiều khi ta đã biết cấu hình nên như thế nào, và nó nên được quản lý trong source control, nhưng secret thì phải được inject lúc chạy.
    Nếu không muốn tốn thời gian cấu hình khổng lồ cho dev, test và production, cấu hình cần có ghi đè phân cấp.

    • Vấn đề là “giá trị mặc định hợp lý” là mặc định cho dev hay cho production.
      Nếu là cho dev, cuối cùng nó sẽ phá production; còn mặc định cho production có thể chẳng có ý nghĩa gì trong dev.
    • Bối cảnh khi 12-Factor App được viết là có thể bật/tắt mode bằng biến môi trường như RAILS_ENV=test.
      Một cách nghĩ về phần cấu hình là: “Chiến lược cấu hình này có hợp với container không?” Khi build image, bạn có trạng thái đĩa tĩnh, nơi các thay đổi sẽ không được giữ lại trừ khi tạo image mới.
      Nếu cấu hình chỉ dựa trên file, bạn phải build một image hoàn toàn mới để chuyển đổi hành vi giữa test và production.
      Việc cho phép thay đổi cấu hình độc lập với đĩa gốc giúp cô lập thay đổi. Bạn cần phân biệt được ứng dụng hỏng vì deployment, tức quá trình tạo image, bị lỗi, hay vì cấu hình sai.
      Khi tách việc tạo image khỏi thay đổi cấu hình, bản thân câu hỏi đó biến mất.
    • Nếu hệ thống đã ngăn được việc instance QA kết nối vào tài nguyên production, thì có thể chấp nhận deploy phần lớn cấu hình cùng app.
      Ví dụ, không được cho phép một lỗi con người đủ dễ đoán như việc QA gửi 100.000 lần thử lại bị từ chối xác thực vào queue xử lý production.
      Tuy vậy, nhiều cấu hình không phải về hạ tầng, mà thường là những vấn đề như nên nối bean ResolverStrategy nào trong từng môi trường.
    • Có thể, và có lẽ nên, có các giá trị mặc định hợp lý.
      Cấu hình nên được quản lý phiên bản, nhưng nên được quản lý tách khỏi source code. Vì cấu hình mô tả bản thân deployment, chứ không phải image dùng để deploy.
    • Tôi không rõ có lý do gì khiến cả giá trị mặc định cũng không nên được biểu diễn dưới dạng cấu hình. Nếu ý là vậy thì tôi nghĩ nó không trái với 12-Factor.
  • Đây chắc chắn là một chuẩn mực engineering có ảnh hưởng. Giờ có rất nhiều abstraction dễ dùng của các dịch vụ hosting như Render hay Vercel, nên hơi lạ khi nghĩ rằng tài liệu này được viết năm 2012, và khi đó web app, xét về các thực hành chung được chấp nhận, còn giống miền Tây hoang dã hơn nhiều.

  • Điều thiếu lớn trong tài liệu này là sự biện minh cho các quy tắc. Gần như toàn bộ chỉ là quy tắc.
    Khó đánh giá quy tắc có tốt hay không, và tài liệu này không giúp làm điều đó.

  • Chỉ nhìn tiêu đề, tôi tưởng đây là bình luận về xác thực hai bước. Kiểu như một app đòi ảnh hộ chiếu, quét khuôn mặt, bằng lái xe, tin nhắn SMS, Google Authenticator, link email, mật khẩu và vân tay chỉ để đăng nhập một lần.

    • Tôi đoán đó là một sàn giao dịch tiền mã hóa tập trung điển hình.
    • Cũng gần giống những gì một sàn chứng khoán hay sàn tiền mã hóa điển hình yêu cầu trước khi cho phép giao dịch.
  • Thời kỳ đầu của Docker, tôi đã làm khá nhiều việc để khiến WordPress hoạt động giống một Twelve-Factor App.
    Theo truyền thống, WordPress không hoạt động như vậy, và ở mức nào đó thì cũng dễ hiểu. WordPress lớn lên trong một thế giới nơi các server sống lâu, có đĩa cục bộ ghi được và bền vững, là chuyện phổ biến.
    Sau đó tình hình chắc đã thay đổi nhiều. Đây là chuyện khoảng năm 2016, nhưng đó thật sự là một thử thách thú vị.

    • Tôi nhớ lúc học được cách làm server trở nên stateless, tức lưu thông tin session vào cơ sở dữ liệu và không ghi ra đĩa.
      Tôi ngạc nhiên vì mọi thứ trở nên đơn giản đến mức nào, và có thể load balance nhiều node mà không phải bận tâm đến session stickiness.
      Tất nhiên, theo những cách khác thì lại khó hơn, chẳng hạn cần một DB riêng cho session.