# Xem trước khi dựng software factory đầu tiên

[Jo Van Eyck](https://homus.dev/speakers/jo-van-eyck) · [Jo Van Eyck](https://homus.dev/orgs/jo-van-eyck)

> Demo factory từ GitHub issue tới PR có bằng chứng, cùng các điều kiện tiên quyết: môi trường, type, test hexagonal, lint, sandbox, review, chi phí.

Topics: Software Factory, Coding Agents, Workflow, Agents

Canonical: https://homus.dev/talks/watch-this-before-you-build-your-first-software-factory

## 1. Dark factory, software factory và ý chính của video

Video mở ra bằng một cảnh đùa: Jo Van Eyck đeo đèn pin trên đầu, xin lỗi người xem vì vừa phải đi sửa một sự cố trong "dark factory" của anh. Anh giải thích đó là thuật ngữ có lẽ bạn đã nghe trên internet dạo gần đây (tính đến lúc video đăng ngày 05/10/2026): software factory, hay dark factory. Jo quyết định tự nghiên cứu và tự dựng một factory, và hôm nay anh muốn nói về điều anh nghĩ là bước tiếp theo của cả thế giới agentic engineering: software factory.

![Slide tiêu đề Building your first software factory, Advanced agentic engineering without shooting yourself in the foot](https://homus.dev/photos/iPq_aCk3EsE-0213.jpg)

Slide mở đầu: "Building your first software factory", dòng dưới ghi "Advanced agentic engineering without shooting yourself in the..." kèm ba emoji (đầu nổ tung, bàn chân, túi tiền), một cách chơi chữ "tự bắn vào chân", vào đầu và vào ví.

Anh nói rõ: video này không phải để khoe software factory "siêu ngầu" của anh. Ý chính anh muốn truyền tải là các primitive đã có sẵn, mọi người đang tìm ra cách để làm nó chạy, và chuyện này không phải khoa học tên lửa. Nhất là nếu bạn là một engineer làm một mình, một team một người, hay một product team nhỏ đang build một app, thì theo Jo (video đăng ngày 05/10/2026), bạn có thể dựng software factory của mình trong vài ngày chứ không phải vài tháng, thậm chí vài giờ nếu bạn cứ thế vibe code nó. Đó là nội dung của cả video, và "thôi lảm nhảm đủ rồi", anh đi thẳng vào chủ đề.

Khi nói tới khái niệm software factory, Jo dùng đúng định nghĩa của Addy Osmani: software factory là một quy trình lặp lại được quanh công việc phần mềm. Với Jo, đó là đoạn đường từ một issue tới code đã merge và chạy trên production. Với người khác, factory có thể đi xa hơn thế.

Câu trích trên slide là: "A software factory is a repeatable loop around software work", ký tên Addy Osmani, và chú thích nguồn trỏ tới bài "Human judgment doesn't leave the software factory. It relocates." trên blog của Addy Osmani.

![Sơ đồ The agentic software factory inside OpenAI với các khối Codex, CI, Agentic code review, Agentic deploy, Production, Perf Factory, Sevbot](https://homus.dev/photos/iPq_aCk3EsE-0121.jpg)

Sơ đồ "The agentic software factory inside OpenAI" từ bài của Gergely Orosz (The Pragmatic Engineer): người "builder" định nghĩa outcome, Codex viết code, CI build và test, agentic code review, nhánh "Low-risk change?" quyết định có cần một engineer review thêm không, rồi agentic deploy, production, Perf Factory và Sevbot xử lý sự cố (sơ đồ như trên slide của video đăng ngày 05/10/2026).

Đây là một ví dụ về software factory: factory nội bộ của OpenAI để build Codex. Jo nói anh nghĩ nó dùng để build Codex, và sơ đồ lấy từ The Pragmatic Engineer, nơi cũng viết nhiều về những chủ đề này. Theo sơ đồ đó (như Jo trình bày trong video đăng ngày 05/10/2026), ý tưởng là bạn có một đầu vào cho hệ thống, cho factory của bạn, có thể là issue tracker, hoặc các sự cố từ production, những thứ như vậy. Sau đó cả một loạt việc tự động được kích hoạt: code được viết, CI chạy, review được agent thực hiện tự động, deploy diễn ra tự động, PR được "trông" (babysit) cho tới khi rollout xong. Tức là cả một vòng lặp từ một sự cố hoặc một feature request cho tới phần mềm ship được. Đó là hình dạng của thứ mà video bàn tới hôm nay.

Trước khi đi tiếp, Jo giới thiệu app anh dùng để dựng factory của mình. Anh thừa nhận: đúng, nó là một app to-do list, hoặc không hẳn, nhưng về quy mô thì khá giống một to-do list. Nhưng anh khẳng định cách làm này scale được. Anh tự nhận đây lại là một câu "tin tôi đi" (trust me, bro), nhưng anh không biết nói gì khác: theo kinh nghiệm của Jo (video đăng ngày 05/10/2026), cách này chạy được cho các backend enterprise nặng, chạy được cho những thứ đòi hỏi bảo mật cao. Factory chạy được, kèm theo một số disclaimer nghiêm túc, hay đúng hơn là các điều kiện tiên quyết, mà anh sẽ nói ở phần sau.

## 2. App mẫu DogTrainr và bộ công cụ của Jo

Trước tiên, Jo cho xem nhanh setup của anh để mọi người cùng hiểu đang nói về cái gì. Đây là repository (link ở phần nguồn bên dưới), app mẫu nằm trong đó. Đó là một app TypeScript đơn giản có backend và frontend. Anh nghĩ mình dùng Express và React, đại loại thế. Anh không nghĩ công nghệ dùng là gì quan trọng lắm; dự đoán của anh là trong tương lai gần, các lựa chọn sẽ hội tụ về một tập nhỏ hơn. README của repo (đọc ngày 23/10/2026) ghi frontend là React 19, React Router 7, Vite, backend là Express lưu dữ liệu bằng file JSON, test bằng Vitest, Testing Library và Supertest, và nói rõ đây là app demo cho mục đích học và trình bày, không dùng cho production.

App rất cơ bản. Jo là người mê chó, nên đây là một to-do list cho con chó của anh: về cơ bản là lịch huấn luyện hằng ngày. Anh có thể chấm điểm từng buổi tập, ghi chú, những thứ tương tự. Có cả phần analytics để anh xem con chó của mình, tên là Django, đã tập đi dây xích (leash training) năm nay ra sao.

![Trang hồ sơ chó Django trong app DogTrainr với kế hoạch Regular week, lịch tuần tháng 9 năm 2026 và hai bài Leash training, Recall](https://homus.dev/photos/iPq_aCk3EsE-0347.jpg)

Trang hồ sơ của Django trong DogTrainr: ảnh chú chó chạy trên tuyết, kế hoạch "Regular week", dải lịch theo tuần, và hai bài tập trong ngày là Leash training và Recall, mỗi bài có nút "Check off".

Vậy đó là một app cơ bản. Đúng, lại là một app to-do. Và đúng, theo Jo, cách này scale. Anh bảo mọi người tự tìm hiểu, tự thử nghiệm.

Giờ, để có "hiệu ứng demo", Jo khởi động factory và cho build một feature mới để mọi người thấy nó trông và cảm giác ra sao. Anh dùng herdr, một terminal multiplexer biết về agent (agent aware), nhưng anh nói đây là lần đầu và lần cuối bạn nghe về nó, vì dùng gì thật sự không quan trọng. Coding harness anh dùng là Pi, vì theo Jo (video đăng ngày 05/10/2026) Pi mở, cực kỳ dễ hack và miễn phí, nên nó là một harness tuyệt vời để vọc. Rồi anh khởi động factory.

Jo cho biết lúc quay video (đăng ngày 05/10/2026) anh dùng Opus 5.5 làm model chính hằng ngày, nhưng factory của anh không phụ thuộc vào model (model agnostic), và anh dùng các model khác nhau cho các việc khác nhau; anh sẽ nói kỹ ngay sau.

Về chuyện herdr thì nó rất hay, nhưng Jo nói thẳng: nếu bạn muốn sống trong Ma trận thì được, còn đây không phải là trải nghiệm người dùng cho software factory của bạn. Nếu bạn đang nhìn 8, 12, 16 phiên tmux song song, theo anh bạn bị điên rồi. Anh 30 tuổi, à xin lỗi, hơn 30 tuổi, và bộ não của anh không được tạo ra cho việc này. Nên đây không phải hình thái cuối cùng của agentic coding. Theo dự đoán của Jo, hình thái cuối cùng sẽ giống một khung chat tương tác nơi bạn và nhiều người cùng làm việc. Còn cho factory của anh, hay ít nhất là cho bản demo, anh dùng một thứ siêu đơn giản và miễn phí (tính đến video đăng ngày 05/10/2026) mà bạn tự dùng được.

## 3. Chief of staff, fleet agent và một GitHub issue cố tình thiếu thông tin

Thứ đó là GitHub Issues. Jo sẽ chỉ tạo GitHub issue và để factory build từ đó. Nếu bạn làm một mình hay trong một team nhỏ, cách này chạy ổn. Nếu bạn là một doanh nghiệp lớn, anh khuyên đừng chuyển mọi thứ sang một issue tracker mới: cứ dùng cái bạn đang có, vì theo Jo (video đăng ngày 05/10/2026) agent tích hợp được tốt với mọi thứ miễn là nó có API.

Rồi anh nhìn vào cái factory. Có rất nhiều thứ đang diễn ra trên màn hình, anh sẽ đi vào chi tiết sau, nhưng nguyên tắc là: anh có một thứ giống như "chief of staff", hay "first mate" nếu bạn muốn (có người gọi nó là first mate). Đó là một agent có thể nói chuyện với thế giới bên ngoài; trong trường hợp của anh là GitHub Issues và GitHub repository của anh.

Sau đó là cả những fleet agent được spawn ra mỗi khi có việc cần làm. Theo Jo (video đăng ngày 05/10/2026), herdr khá hay ở chỗ bạn có thể tách các fleet agent khác nhau vào các pane khác nhau, nên những thứ thuộc về nhau có thể nằm chung một pane. Nhưng một lần nữa, anh nhắc đây không nên là mối quan tâm chính của bạn khi build software factory.

Có lẽ đáng nói là ở góc dưới bên trái màn hình có một kiểu observability plane, nơi anh thấy issue nào đang ở trong factory và chúng đang ở giai đoạn nào, cái gì đang chạy. Theo Jo, đây là thứ bạn cần đầu tư một chút: factory của tôi tốn bao nhiêu, cái gì đang chạy, những câu hỏi như thế.

Topology Jo mô tả trong demo: chief of staff nói chuyện với GitHub, mỗi issue có một feature owner, feature owner spawn fleet (worker, rồi reviewer), và một observability plane cho biết cái gì đang chạy.

Factory đã chạy, giờ anh giao việc cho nó xem mọi chuyện ra sao. Anh tạo một GitHub issue mới. Như đã nói, anh không nghĩ tmux sẽ là UI cuối cùng, và anh cũng không nghĩ GitHub Issues sẽ là UI cuối cùng, hoặc có thể là có nếu nó tiến hoá thêm một chút.

Anh tạo issue và cố tình viết thiếu (under specify) những gì mình muốn, để khoe vài tính năng của factory. Anh chỉ ghi muốn implement một feature đơn giản là "csv export", rồi thêm "of training sessions". Như vậy là không nói đủ. Việc này cố tình thiếu thông tin vì agent của anh phải gắn cờ là chưa đủ rõ. Kế hoạch là: làm một vòng planning, làm một phiên "grilling". Đó là điều sẽ xảy ra, và anh gửi issue đi.

Nếu nhìn xuống dưới lớp vỏ, sau tấm màn, sẽ thấy anh có một cơ chế polling. Jo kể (video đăng ngày 05/10/2026) nhiều người dùng một thứ như Hermes hay một agent trợ lý cá nhân nào đó để làm việc này, nhưng theo anh một shell script đơn giản cũng chạy tốt không kém. Trên màn hình, script đang "chọc" vào factory, nó nhặt issue lên, và foreman sẽ spawn cả một fleet agent; anh sẽ nói thêm sau. Factory đã khởi động.

Jo nhắc rằng nếu ai theo dõi anh một thời gian sẽ biết anh từng có một "coding maturity ladder" từ một năm trước (tính từ video đăng ngày 05/10/2026). Nhìn vào hướng đi của mọi thứ bây giờ, anh không nghĩ cái thang đó đủ tham vọng.

## 4. AI fluency ladder, xem lại sau một năm

![Slide AI coding maturity ladder với năm nấc: Chat, Mid-loop generation, In-the-loop agentic coding, On-the-loop agentic coding, Multi-agent coding](https://homus.dev/photos/iPq_aCk3EsE-0841.jpg)

Slide "AI coding maturity ladder" một năm trước của Jo, từ dưới lên: Chat, Mid-loop generation, In-the-loop agentic coding, On-the-loop agentic coding, Multi-agent coding.

Jo nói những nấc dưới cùng, như mid-loop generation, kiểu "autocomplete cay" (spicy autocomplete), thì anh không nghĩ bạn còn cần đi qua giai đoạn đó nữa. Ý tưởng ban đầu của cái thang là bạn phải đi qua từng nấc trước khi lên nấc tiếp theo. Giờ anh nghĩ bạn có thể nhảy thẳng vào in-the-loop agentic coding, tức là bạn và một agent pair programming trong một phiên tương tác.

Tuy vậy, anh vẫn nghĩ khi mới bắt đầu bạn cần ở giai đoạn đó, vì bạn cần có cảm giác về cách những thứ này hoạt động. Ban đầu, bạn cần thấy các coding harness và các model thất bại ở đâu, kém ở đâu trong bối cảnh cụ thể của bạn, để bạn có thể làm cho môi trường tốt hơn cho agent. Và bạn không làm được điều đó nếu không "lội bùn" một thời gian. Bạn có thể làm bằng cách cho agent đọc các phiên làm việc của bạn rồi phân tích dữ liệu, nhưng lời khuyên của anh cho engineer mới bắt đầu là: hãy bắt đầu ở in the loop.

Tức là mở một phiên Claude Code, Codex hay bất cứ công cụ nào bạn dùng, và build feature theo kiểu tương tác. Nhưng đó không nên là trạng thái cuối. Nếu bạn muốn tăng đáng kể năng suất và tầm ảnh hưởng của mình, bạn cần leo cái thang này.

Theo Jo (video đăng ngày 05/10/2026), on-the-loop agentic coding là thứ anh vừa nói: bốn hay sáu phiên chạy đồng thời trong một cửa sổ tmux ở đâu đó, hoặc trong pane Codex của bạn có sáu thread chạy cùng lúc, và bạn cứ nhảy qua nhảy lại giữa chúng. Việc này vui được một thời gian, rồi bạn kiệt sức, hoặc bạn chán ngấy vì phải trông chừng (babysitting) hay vì phải chuyển ngữ cảnh liên tục.

Bạn cần lên một nấc nữa, nấc anh từng gọi là multi-agent coding, nhưng giờ nó là cấp factory, cấp "bếp nhà hàng Michelin", hay cấp "làm vườn". Ở đó bạn nói chuyện với một, có thể hai, ba agent, nhưng chủ yếu là một agent, và trong agent đó bạn đã mã hoá cách bạn làm việc.

Ở đây Jo diễn giải lại ý của poteto (Lauren Tan, anh nghĩ đó là tên của họ): bạn nên thấm nhuần, hay chưng cất (distill), tất cả best practice của mình vào skill, vào custom agent instruction, vào lint rule, vào bất cứ thứ gì, để bạn chỉ việc giao việc cho một agent chief of staff, và agent đó sẽ spawn các fleet theo đúng cách bạn nghĩ về công việc phần mềm.

Ví dụ, nếu bạn nghĩ điều thực sự quan trọng là có một agent engineer trước tiên làm phân tích rồi mới implement, rồi có một agent QA làm review đối kháng (adversarial review)...

## 5. Ẩn dụ tuýp kem đánh răng

... thì nếu đó là cách bạn nghĩ về việc build phần mềm, hãy mã hoá điều đó vào factory của bạn, vào "bếp Michelin" của bạn. Điểm của Jo là cái thang này lỗi thời khá nhanh, nhưng anh vẫn nghĩ ba nấc trên cùng còn phù hợp. In-the-loop agentic coding có thể thấy vui, nhưng bạn đang tự giới hạn mình nếu cứ ở đó, và bạn cần đặt một số thứ vào chỗ trước khi leo cao hơn. Leo cái thang này không phải không tốn công.

![Hình một tuýp kem đánh răng bị bóp thắt ở giữa, kem phọt ra ở hai đầu](https://homus.dev/photos/iPq_aCk3EsE-1223.jpg)

Ẩn dụ tuýp kem đánh răng: phần giữa tuýp bị bóp thắt lại, kem dồn ra hai đầu. Phần giữa là việc viết code, hai đầu là việc trước và sau khi code.

Đây là một ẩn dụ. Jo nói anh không thích nó lắm, nó không phải ẩn dụ hay nhất, nhưng anh không nghĩ ra cái nào tốt hơn. Đây là cảm giác của các engineer: họ thấy mình bị bóp. Nhưng theo anh đây cũng là điều đã xảy ra, hay đúng hơn là đã bị áp đặt lên nghề của chúng ta. Nó không còn là thứ bạn tự chọn tham gia nữa. Hoặc đi theo agentic, hoặc ra khỏi nghề, ít nhất là theo Jo (video đăng ngày 05/10/2026) nó bắt đầu có cảm giác như vậy.

Ý của anh với ẩn dụ tuýp kem là: nhìn vào những gì một software engineer điển hình làm trong công việc, phần ở giữa, phần viết code, thì theo Jo (video đăng ngày 05/10/2026) không còn động lực kinh tế nào để engineer tự viết code nữa. Phần code ở giữa quy trình đã bị bóp lại. Đây là thứ agent làm hoàn toàn ổn, và về mặt kinh tế chẳng có lý do gì để con người làm việc ở giữa tuýp kem này. Tuýp kem này là tuýp sự chú ý của bạn: bạn không nên ở giữa nữa, bạn không nên viết code. Điều bạn nên làm là ở phía trước việc viết code và ở phía sau việc viết code.

Phía trước việc viết code là chuyện product: làm một phiên "grill me", những thứ như thế, viết spec, bạn muốn gọi nó là gì cũng được. Vậy là ở phía trước cần nhiều việc hơn trước. Ngày xưa bạn có thể làm việc này trong lúc viết code, và nghĩ ra những câu cần hỏi product owner hay khách hàng. Giờ bạn không thể như vậy nữa. Theo Jo (video đăng ngày 05/10/2026), agent có thể làm việc này rất tốt, rất nhanh, nhưng bạn cần kéo ít nhất những quyết định quan trọng lên phía trước.

Đó là phần đầu của tuýp kem, ít nhất là với engineer. Phần cuối là bạn cần đầu tư, đầu tư nghiêm túc vào kỹ năng verification và validation: guardrail, CI pipeline, những thứ như vậy. Theo Jo, đây là nơi rất nhiều công việc engineering dồn về. Nó dồn về product và đặc tả, nhưng nó cũng dồn rất nhiều về bên phải: build và engineer những hệ thống có thể...

## 6. Điều kiện tiên quyết: evidence chứ không phải trust

... tự verify chính nó, hoặc để agent verify công việc của chính chúng. Đây là nơi phần lớn công sức engineering của Jo dồn vào lúc này (theo video đăng ngày 05/10/2026). Đó là ẩn dụ tuýp kem anh dùng: chúng ta đang bị bóp, và sự chú ý của chúng ta phải dồn về các giai đoạn đầu và cuối, không phải giai đoạn viết code, hoặc ít nhất là không nhiều như trước.

Có một số điều kiện tiên quyết cần thiết để factory chạy tự động và để leo những nấc thang tự chủ đó. Có người gọi đây là chuyện agent của bạn, hay bạn, cần leo một "thang tin tưởng" (trust ladder). Jo không thích chữ trust, vì niềm tin là thứ... anh tự sửa giữa câu: khó có được, dễ đánh mất.

Anh không nghĩ đây là chuyện niềm tin, hoặc chỉ một phần là chuyện niềm tin. Bạn phải thấy các agent này làm việc ổn định một thời gian thì mới tin được, kiểu như "tôi không cần nhìn từng dòng code" hay "tôi không cần trông một phiên đang chạy". Nên đúng là có phần chuyện niềm tin, nhưng anh không nghĩ nó nên dựa trên cảm tính (vibes based) hay dựa trên niềm tin; anh nghĩ nó nên dựa trên bằng chứng (evidence based). Theo lập luận của Jo (video đăng ngày 05/10/2026), nếu 100% hay 99% pull request của bạn có chất lượng cao,

chúng được đảm bảo qua test suite, chúng được đảm bảo có formal verification hay bất cứ thứ gì bạn muốn dùng làm bằng chứng, và nếu bằng chứng đó được tạo ra đều đặn với chất lượng cao ổn định, thì bạn có thể leo thang. Với Jo, đây không hẳn là chuyện niềm tin mà là chuyện bằng chứng. Vậy các điều kiện tiên quyết là gì?

Lập luận của Jo: thứ cho phép bạn bớt nhìn code không phải cảm giác tin tưởng mà là bằng chứng được tạo ra đều đặn trong mỗi PR.

Trước khi bạn có thể bắt đầu làm việc on the loop và với các fleet agent, Jo nghĩ điều kiện đầu tiên là codebase, hay môi trường của bạn, phải sẵn sàng cho việc đó. Nhìn vào rất nhiều doanh nghiệp, theo kinh nghiệm của anh (video đăng ngày 05/10/2026) họ chưa sẵn sàng, và đây là rào cản lớn. Codebase có thể viết bằng một ngôn ngữ legacy nào đó, COBOL chẳng hạn. Đó không phải vấn đề; code không thực sự là vấn đề. Vấn đề nằm ở các "đường nối" (seams).

Ý anh với seams là: phần lớn phần mềm doanh nghiệp không chạy được trên một máy của developer, hoặc không chạy được bên trong một máy ảo hay một Docker container duy nhất. Và theo kinh nghiệm của anh (video đăng ngày 05/10/2026), đó là thứ rất cần: bạn cần chạy được phần mềm của mình trong một Docker image, một cloud VM, một micro VM, gì cũng được. Dùng cái gì không quan trọng lắm, nhưng bạn cần chạy được một phần lớn phần mềm của mình trong một môi trường ảo, hoặc ít nhất trên một máy vật lý không phải loại server khổng lồ chạy một hệ thống quản lý nội dung nào đó.

## 7. Môi trường sẵn sàng cho agent, context và ngôn ngữ có type

Vì thế Jo nghĩ các công ty product nhỏ và những người khởi nghiệp một mình có lợi thế rất lớn, vì đây là một điều kiện tiên quyết thiết yếu cho kiểu công việc này.

Điều kiện tiếp theo là context. Context ở đây là mọi thứ một agent cần để hình dung ra công việc của nó: architecture diagram, phân tích codebase, những thứ như vậy. Anh không đi sâu vào phần này vì đã có rất nhiều nội dung nói về nó.

Sau đó là thứ anh vừa nói: phần bằng chứng, tức phần đuôi của tuýp kem. Bạn cần những thứ như ngôn ngữ có type. Jo kể anh ngày càng nghiêng về TypeScript. Anh có tự làm một số micro benchmark, và theo số đo của chính anh (video đăng ngày 05/10/2026), dù Rust rất ngầu nhưng Rust chậm kinh khủng. Anh khá thích TypeScript. Anh cũng có vài ngôn ngữ "cưng" của riêng mình, nhưng chúng có vẻ không đạt điểm cao trên benchmark của anh, nên anh đang học cách buông bỏ. Giờ anh viết phần lớn đồ cá nhân bằng TypeScript.

Bên cạnh type, bạn cần một test suite mạnh. Anh sẽ nói chi tiết ngay sau ý anh là gì, vì anh thấy rất nhiều lời khuyên trên internet kiểu "bạn nên viết end-to-end test, kệ unit test đi". Anh đồng ý với vế sau, không đồng ý với vế trước, và sẽ đi sâu ngay sau đây.

Bạn cũng cần những thứ như lint rule, vulnerability scanner, code analysis, static code analysis. Vậy là có một số điều kiện tiên quyết. Nghe thì có vẻ rất "enterprise", nghe có vẻ tốn kém. Nhưng Jo nghĩ bạn có thể làm tất cả miễn phí (theo anh, video đăng ngày 05/10/2026).

Ba nhóm điều kiện tiên quyết Jo liệt kê trước khi chạy agent theo fleet: môi trường ảo hoá được, context, và các validation gate ở đuôi tuýp kem.

Vậy anh quay lại ví dụ software factory của mình và cùng xem một số thứ này. Thứ đầu tiên: type. Anh dùng TypeScript nên mọi thứ đều có type. Tại sao điều đó hữu ích, tại sao anh nhấn mạnh tầm quan trọng của type? Theo Jo (video đăng ngày 05/10/2026), type thu hẹp không gian lời giải: nó đặt ràng buộc lên những gì agent có thể nghĩ ra, và nó bắt những lỗi rất ngớ ngẩn từ sớm. Nếu bạn viết Python, JavaScript hay một ngôn ngữ không có type nào đó, bạn phải chạy đoạn code đó mới nhận được vòng feedback đầu tiên.

## 8. Type system, unit test và cái bẫy end-to-end

Có type, bạn chỉ cần bấm compile và chạy type check, và việc đó bắt được cả một lớp lỗi. Nếu bạn khai thác type tốt hơn (anh có nói trong các video trước), bạn có thể thiết kế input, hay ràng buộc input vào hệ thống, sao cho chỉ những input hợp lệ mới đi qua được nhờ type system. Theo Jo, type là một thành phần thiết yếu trong stack software factory hiện đại. Nhưng nói về type thế là đủ: lời khuyên của anh lúc này (video đăng ngày 05/10/2026) là cứ dùng TypeScript. Còn nếu bạn là một công ty lớn với hàng triệu dòng code Java hay .NET, những ngôn ngữ đó chạy hoàn toàn ổn. Đừng port app sang TypeScript chỉ vì anh nói thế; chỉ cần đảm bảo bạn có một type system.

Type quan trọng, và test cũng quan trọng. Lúc nãy anh có chê unit test. Những unit test không còn mấy giá trị là các micro test. Anh thấy rất nhiều người khi nói unit test là ý họ là test một method trong một class nào đó, mock mọi dependency, những thứ điên rồ như vậy. Theo anh, việc đó chưa bao giờ là ý hay. Anh thừa nhận đây là một nhận định gây tranh cãi, nhưng đó là quan điểm của anh trong 15 năm, à, 10 năm qua. Chưa bao giờ là ý hay, kể cả nếu bạn là một lập trình viên XP theo test-driven development khó tính, nhưng anh lạc đề rồi. Và hôm nay chúng chắc chắn không phải ý hay.

Anh cũng nghĩ bạn không nên viết mọi test theo kiểu end-to-end. Đó là quan điểm anh thấy mỗi ngày trên X và YouTube (lúc video đăng ngày 05/10/2026), và theo Jo đó cũng là một ý rất tệ. Vì chính những người nói "bạn nên test mọi thứ end-to-end qua public API của hệ thống" lại là những người nói câu tiếp theo: "ôi không, CI của chúng tôi mất 25 phút và nó là bottleneck mới". Jo hỏi lại: thế bạn nghĩ sao? Tự gây thương tích, có ai không?

Anh đứng ở đâu đó giữa hai thái cực, dựa trên hexagonal design, clean design, bạn muốn gọi là gì cũng được.

![Sơ đồ hexagonal architecture: lõi Entities ở giữa, vòng Interactors và Repositories, vòng ngoài Transport layer và Data sources nối tới HTTP, SQS, DB, GRPC API, REST API](https://homus.dev/photos/iPq_aCk3EsE-2016.jpg)

Lõi Entities ở giữa, quanh nó là Interactors và Repositories, vòng ngoài là Transport layer và Data sources nối ra HTTP, SQS, DB, GRPC API, REST API.

Nguyên tắc là bạn nên nghĩ codebase của mình có một bên trong và một bên ngoài. Bên trong là nơi business logic, nơi kiến thức cốt lõi về product của bạn sống. Bên ngoài là các dependency gây đau đầu: web framework như Express, hạ tầng database như SQL, Postgres, hay hạ tầng cloud như blob storage. Và bạn nên tập trung automated test theo hai hướng khác nhau.

Một là cái lõi bên trong đẹp đẽ, không có dependency. Anh test lõi bằng các test ở mức cao, nhưng chỉ chạm vào lõi. Chúng không dựng database, không dựng LocalStack hay hạ tầng cloud, và không nhất thiết dựng web framework của anh.

## 9. Test trong memory, integration test và custom lint rule

Đôi khi có dựng web framework, vì nhiều web framework hỗ trợ tự động hoá test theo cách này. Nhưng anh không dựng bất kỳ thứ bên thứ ba gây đau đầu nào như database, Twitter API hay gì khác. Anh tạo fake cho mọi thứ, theo nghĩa đen. Theo Jo (video đăng ngày 05/10/2026), agent đã viết fake rất giỏi được một thời gian rồi.

Nếu bạn chỉ cần nói "cho tôi một fake database". Và ý anh không phải là một database in-memory, kiểu SQLite gì đó. Ý anh thực sự là một abstraction, nếu bạn biết domain-driven design thì đó là repository abstraction. Nó có thể là SQL database trên production, hoặc trong test của anh thì chín trên mười lần chỉ là một class chứa một dictionary hay một bảng tra cứu, tất cả nằm trong memory, nhưng có cùng abstraction với database production.

Anh làm vậy với mọi dependency: với API bên thứ ba như Twitter, với hạ tầng cloud, những thứ như thế. Và nếu bạn thiết kế code theo kiểu hexagonal này, hoặc nếu bạn bảo agent thiết kế code theo cách này (anh tự nhắc mình đó mới là điều nên nói), thì bạn có thể viết test cho toàn bộ phần lõi màu đỏ bên trong ở mức cao. Bạn có thể diễn đạt chúng thành các kịch bản mà người dùng cuối, một PO hay một người làm product hiểu được.

Bạn không phải lặn vào những chi tiết khó chịu. Và lợi ích lớn nhất của cách làm này là các test chạy hoàn toàn trong memory. Jo kể anh có một product cấp enterprise đang build với 4.000 test kiểu này, và theo số đo của anh (video đăng ngày 05/10/2026) chúng chạy trong vài mili giây, không phải vài phút, không phải vài giờ, mà là mili giây. Khi chạy toàn bộ bộ 4.000 test theo cách này, CI của anh mất tối đa năm phút chứ không phải một giờ.

Nên với những người nói CI là bottleneck: có thể đúng nếu bạn build native app và test UI của chúng một cách nặng nề qua tự động hoá trên trình duyệt. Còn nếu bạn là engineer chủ yếu làm backend thì theo Jo, không đời nào, đó là skill issue. Anh nhận mình lạc đề một chút rồi đi tiếp.

Cách Jo phân bổ test theo hexagonal design: phần lớn test nằm ở lõi và chạy trong memory với fake, một ít test chạm database thật ở điểm tích hợp, chỉ một nắm test gần end-to-end.

Từ nãy anh mới nói về phần bên trong của hình lục giác. Tất nhiên bạn cần test các điểm tích hợp. Anh có test đánh vào một SQL database thật, nhưng chúng chỉ test phần nhỏ đó. Một lần nữa, nếu dùng các abstraction của domain-driven design như repository làm lớp bọc quanh database, anh có một số test dựng một Postgres database thật, chạy database migration để tạo bảng, chèn ít dữ liệu, rồi có vài test kiểm tra: đọc dữ liệu được không? Ghi dữ liệu được không? Cập nhật dữ liệu được không?

Những thứ như vậy. Anh còn có lẽ có một nắm test "gần như end-to-end" chạy trong một Docker container, nhưng phần lớn test của anh nằm ở hình lục giác trung tâm và ở các điểm tích hợp đó. Đó là bài "xả" lạc đề của anh về test automation, nhưng theo anh nó thực sự quan trọng. Và nếu có một kỹ năng mà engineer vẫn còn tạo khác biệt được, theo Jo đó chính là những việc như thế này.

Đủ về test. Anh có nhắc tới linter, và ý anh không chỉ là autocomplete hay, xin lỗi, format code cho đẹp. Cái đó quan trọng, và nó có trong app mẫu. Nhưng ý anh là làm những việc hay ho hơn với linter. Anh tìm lại thứ mình muốn nói: anh dùng ESLint và có một số rule ở đây,

nhưng bạn có thể đi rất xa với việc định nghĩa custom lint rule. Ví dụ, anh có những rule nói rằng app được build theo một kiểu vertical slice architecture: có một mảng code chuyên quản lý chó, rồi một mảng code khác quản lý kế hoạch huấn luyện chẳng hạn, và chúng không biết về nhau, hoặc khi cần biết về nhau thì có những interface cụ thể giữa chúng.

Một phần của code về chó không được tự tiện thò tay vào mọi ngóc ngách của code huấn luyện. Đây là chuyện tư duy về modularity và interface. Theo Jo (video đăng ngày 05/10/2026), agent khá giỏi việc này nhưng chúng hay đi đường tắt, nên anh dùng các lint rule nói rằng nếu bạn đang viết code về chó thì không được tham chiếu code huấn luyện, đại loại vậy. Những rule này được kiểm mỗi lần chạy linter, tức là mỗi lần agent sửa code.

Và theo kinh nghiệm của Jo (video đăng ngày 05/10/2026), agent giữ code modular rất tốt nếu có một thứ như vậy được đặt sẵn. Vì khi build fail và agent nhận feedback kiểu "bạn đang đi đường tắt ở đây", chúng có thể lặp lại, tự sửa lỗi của mình và tuân theo thiết kế bạn mong muốn mà bạn không cần có mặt. Nếu đi xem các trace, hay trajectory của agent đang diễn ra trong factory của anh lúc này, bạn sẽ thấy chúng vi phạm các rule này rồi lặp lại để sửa.

Ví dụ custom lint rule của Jo: hai vertical slice chỉ nói chuyện qua interface; agent đi đường tắt sẽ bị linter chặn và phải lặp lại cho tới khi đúng thiết kế.

Nhắc tới factory, anh quay lại xem nó. Factory đã khởi động xong và trên GitHub có một comment mới. Việc này xảy ra mỗi khi... anh bảo để lùi lại một bước đã.

## 10. Quay lại demo: feature owner, worker và phiên grill

Anh mở lại "sự điên rồ tmux" (tmux insanity). Một workspace mới đã được tạo: "feature 37", ứng với issue số 37 của codebase này, và vài agent đã được spawn. Anh đi vào workspace đó. Topology agent của anh như sau.

Anh có một chief of staff, hay first mate, hay foreman. Rồi mỗi issue có một feature owner. Một agent được spawn và việc của nó là đồng bộ với GitHub, spawn fleet agent, những việc như vậy. Lúc này nó mới spawn một agent tên là worker. Đây là agent làm phân tích kỹ thuật và implement.

Nó làm cả phần grilling (ý anh là skill grilling của Matt Pocock) lẫn phần implement. Trên màn hình, nó đã grill xong và tìm ra một số câu hỏi còn bỏ ngỏ. Nó lấy spec, bắt đầu xem codebase, rồi nói: được rồi, ở đây có quá nhiều chỗ mơ hồ, tôi không chắc phải build cái gì.

Nếu phiên grill không có câu hỏi nào bỏ ngỏ, nó sẽ cứ thế đi tiếp và bắt đầu build. Nhưng như ta thấy, nó có câu hỏi, và chúng được đăng ngược lại lên GitHub, nên anh có thể xem. Còn nhiều chi tiết hay khác nhưng anh sẽ nói sau.

![GitHub issue 37 csv export of training sessions với comment Design Questions (from worker) gồm tám câu hỏi Q1 đến Q8 kèm Recommendation và Alt](https://homus.dev/photos/iPq_aCk3EsE-2746.jpg)

Issue #37 "csv export of training sessions": tài khoản bot của factory đăng comment "Design Questions (from worker)" với tám câu hỏi, mỗi câu có một Recommendation và một phương án Alt, kèm lời dặn trả lời ngay trong một comment để feature owner chuyển lại cho worker.

Comment trên màn hình yêu cầu trả lời ngay trong một comment trả lời trên issue (trích từng câu hoặc đánh số câu trả lời), vì feature owner đang polling và sẽ tự động chuyển câu trả lời tới worker. Tám câu hỏi lần lượt là: Q1 phạm vi, xuất buổi tập của con chó nào (đề xuất: từng con một, con đang xem); Q2 khoảng thời gian (đề xuất: toàn bộ thời gian của con chó đó); Q3 có gồm các buổi đã lên kế hoạch nhưng chưa lưu không (đề xuất: không, chỉ xuất các buổi đã ghi nhận, hoàn thành hoặc bỏ qua); Q4 nút xuất đặt ở đâu (đề xuất: nút "Export CSV" trong mục "Sessions" của trang hồ sơ chó); Q5 các cột và thứ tự (đề xuất: Date, Training, Status, Score, Notes, sắp theo ngày tăng dần); Q6 endpoint backend hay tạo Blob ở client (đề xuất: endpoint backend `GET /api/dogs/:dogId/sessions/export.csv` trả về text/csv); Q7 tên file và định dạng (đề xuất: Content-Disposition attachment, UTF-8 có BOM, CRLF, quoting theo RFC 4180); Q8 kết quả rỗng thì sao (đề xuất: một CSV hợp lệ chỉ có dòng header, mã 200).

Vậy là có vài câu hỏi bỏ ngỏ, anh trả lời nhanh. Một điều xảy ra với grilling, theo trải nghiệm của Jo (video đăng ngày 05/10/2026), là rất nhiều lần các đề xuất mặc định như ở đây đều rất tốt, thỉnh thoảng có một câu anh nói "không, đó không phải vấn đề". Nhưng anh thực sự thích grilling vì nó buộc anh...

... phải nghĩ về vấn đề. Đó là lý do anh giữ nó trong factory, giữ nó trong các workflow của mình. Lần này anh thích gần như mọi câu trả lời. Anh kể feature này, đúng issue này, anh đã làm rất nhiều lần; nó là một trong các eval cho factory của anh. Anh thấy (video đăng ngày 05/10/2026) nhiều model hay có một câu hỏi bỏ ngỏ kiểu feature này nên implement chỉ ở frontend hay ở backend, và lần này nó chọn backend, anh khá thích như vậy.

Nên anh chỉ trả lời "looks good to me", và giờ một trong các agent trong workspace đó sẽ nhặt lên và làm tiếp. Anh định đi tiếp, nhưng rồi dừng lại xem nhanh vài điểm thú vị.

## 11. Model đắt hay model rẻ có hướng dẫn, và worker chạy trong Docker

Feature owner của anh (bạn không thấy được, hoặc có thấy) đang chạy Opus. Theo Jo, đây là một trong các model thông minh hơn, vì feature owner phải làm rất nhiều việc phân xử (anh dùng chữ arbitrage) và phải tự hình dung mọi thứ. Model "ngựa thồ" anh dùng trong demo này là DeepSeek Flash. Và anh nhận thấy (theo trải nghiệm của Jo, video đăng ngày 05/10/2026): hoặc là bạn dùng một model rất giỏi như Sol, Fable, Astra, Opus hay gì đó,

và theo Jo (video đăng ngày 05/10/2026) nó không cần nhiều cầm tay chỉ việc nhưng sẽ đốt thủng túi bạn; hoặc bạn mã hoá cách làm việc bạn muốn: đây là workflow của tôi, đây là định nghĩa công việc phải trông thế nào, đây là các best practice của tôi.

Nếu bạn làm vậy, nếu bạn cầm tay chỉ việc một chút và đưa một ít best practice vào, ví dụ đặt vào skill, thì theo Jo (video đăng ngày 05/10/2026) bạn có thể dùng những model rẻ hơn nhiều mà không mất chất lượng.

Đó là lý do anh dùng DeepSeek, hay thậm chí Luna. Anh nói "thậm chí", nhưng theo anh Luna là một model khá tuyệt (theo video đăng ngày 05/10/2026), miễn là bạn không phải nhìn các session trace của nó, vì chúng làm anh hơi phát điên. Trên màn hình, factory đã nhặt việc lên và đang tiến triển tốt.

Cách Jo phân model trong demo (video đăng ngày 05/10/2026): model thông minh cho vai cần phán đoán, model rẻ cho phần việc nặng, bù bằng cách mã hoá best practice vào skill.

Một điều cuối anh muốn nhấn mạnh, và để làm vậy anh phải mở Docker: anh chạy ít nhất là các worker, tức những agent viết code thật và làm phần việc nặng, bên trong một Docker container.

Đó là một container tự làm, image có trong GitHub repository của anh (thư mục factory-image, theo video đăng ngày 05/10/2026). Nhưng nó chỉ là một Docker container, hay Docker image, cơ bản. Anh nghĩ nó có quyền truy cập mạng, dù nó không thực sự cần (theo Jo, video đăng ngày 05/10/2026). Nên có lẽ anh nên dựng firewall cho nó. Điểm của anh là: sandboxing agent đang có rất nhiều chuyện để bàn, nhất là khi agent đang hack cả bên thứ ba (theo Jo, video đăng ngày 05/10/2026). Nhưng sandboxing agent không khó đến thế. Anh nghĩ với một dev làm một mình thì có lẽ là quá tay, còn với dev làm một mình mà có đồ nhạy cảm trên máy thì không.

Và bạn có thể đi theo một trong hai, ba hướng. Hướng anh làm ở đây là đặt nó trong Docker container: cách này chạy được, bạn cần một ít hiểu biết kỹ thuật. Có vài điểm cần lưu ý, nhất là nếu bạn làm trên Windows. Anh đùa: ai lại làm trên Windows chứ? Nhưng anh phải làm trên Windows, nên phải chịu những nỗi đau này, và theo trải nghiệm của Jo (video đăng ngày 05/10/2026) hệ thống file rất chậm nếu chạy Docker trên Windows.

## 12. Sandboxing: Docker, Amp Orbs, T3 Code và tài khoản bot cho agent

Vậy là có vài điểm cần lưu ý, nhưng theo Jo (video đăng ngày 05/10/2026) hoàn toàn làm được, rất dễ làm. Có điều anh không chắc Docker nên là trạng thái cuối. Có một số lựa chọn thay thế khá hay, và với người khởi nghiệp một mình, engineer làm một mình, anh thích hai cái.

![File factory-config.json mở trong VS Code với khối tiers và khối sandbox: enabled, image software-factory-agent:latest, contextWindow, limits cpus memory pids, network, nodeModulesCache](https://homus.dev/photos/iPq_aCk3EsE-3335.jpg)

File `.agents/factory-config.json` trong repo demo: khối "tiers" gán model cho từng vai, khối "sandbox" bật container với image `software-factory-agent:latest`, giới hạn CPU, memory, số process, chế độ network và cache node_modules.

Khối sandbox trong file cấu hình factory của Jo, như trên màn hình:

```
"sandbox": {
"enabled": true,
"image": "software-factory-agent:latest",
"contextWindow": 872000,
"limits": {
"cpus": 2,
"memory": "4g",
"pids": 512
},
"network": "default",
"nodeModulesCache": {
"enabled": true,
"tmpfsSize": "1g",
"paths": [
"node_modules",
"app/node_modules",
"app/backend/node_modules",
"app/frontend/node_modules"
]
}
}
```

Cũng trong file đó, khối "tiers" gán model cho từng vai: foreman, worker, reviewer và merger chạy DeepSeek V4.1 Flash, còn feature owner chạy Claude Opus 5.5 qua GitHub Copilot (theo cấu hình trên màn hình, video đăng ngày 05/10/2026).

Cái đầu tiên Jo gọi là Amp Orbs: Amp là sản phẩm anh gọi là "Sourcegraph Amp", và họ có một tính năng tên là Orbs. Theo mô tả của Jo (video đăng ngày 05/10/2026), Orbs về cơ bản là các VM nơi agent của bạn làm việc, một primitive hay mà anh bảo nên xem thử. Cái thay thế là một công cụ tên là T3 Code, và còn có Cursor.

Có rất nhiều thứ. Nhưng theo Jo (video đăng ngày 05/10/2026), T3 Code hay ở chỗ bạn có thể đăng ký thiết bị của chính mình. Nếu bạn có một laptop dư nằm đâu đó, một máy tính dư, hay máy chơi game, bạn có thể nối nó vào setup T3 Code của mình. Rồi bạn có thể giao việc từ bất cứ đâu, từ điện thoại hay máy tính ở chỗ làm, spawn agent mới và chúng sẽ làm việc trên bất kỳ máy nào bạn đã đăng ký.

Vậy là anh thích Amp Orbs và T3 Code, nhưng nếu không có tiền, bạn có thể không sandbox mà cứ YOLO, hoặc dùng Docker. Theo Jo (video đăng ngày 05/10/2026), Docker dựng rất đơn giản. Rồi factory đã chạy thêm vài phút.

Anh vào kiểm tra công việc. Một pull request đã được tạo, và anh mở nó ra. Pull request có vài tính năng hay. Điều đầu tiên anh muốn nhấn mạnh là nó không phải do anh gửi,

mà do "Clank" của anh gửi. Clank là tài khoản bot của anh. Mỗi khi anh cho coding agent quyền truy cập GitHub, Twitter, Discord hay gì đó, chúng dùng credential riêng của chúng. Theo Jo (video đăng ngày 05/10/2026), GitHub cho phép thêm một tài khoản phụ là tài khoản bot.

Nên bạn có thể làm việc này miễn phí trên GitHub (theo anh, tính đến video đăng ngày 05/10/2026). Hiện tại, cấp credential cho agent là rất nhiều việc thủ công; với rất nhiều dịch vụ, bạn không thể tạo API key ngắn hạn. Nhưng với GitHub, anh chọn cách tạo thêm một tài khoản

và cho tất cả coding agent dùng tài khoản đó khi commit, push, những việc như vậy. Anh muốn nhấn mạnh việc agent của anh không commit code dưới tên anh, để anh có thể giới hạn những gì chúng được làm trên các repository của anh, và để chúng không làm lộ...

Ý của Jo với tài khoản bot: agent không làm việc dưới tên chủ, nên có thể giới hạn quyền và tránh để chúng đọc hay làm lộ những gì không nên.

## 13. Pull request có bản app chạy thật để bấm thử

... thông tin riêng tư của anh, hay làm việc trên, đọc những codebase mà chúng không nên đọc. Theo Jo, đó là một việc nhỏ bạn làm được để tăng bảo mật. Rồi anh đi xem pull request này.

Một điều hay là mỗi pull request, khi bạn còn ở giai đoạn nhìn pull request (anh nghĩ đó là chuyện tạm thời, ít nhất là việc nhìn từng pull request), tức là trong lúc bạn xây dựng niềm tin dựa trên bằng chứng rằng mọi thứ chạy được, anh đổ tất cả bằng chứng vào pull request. Trong lúc còn xây niềm tin, anh thấy rất hữu ích khi được xem chính app, hay code mình đang làm. Ví dụ với app nhỏ này, mỗi pull request spawn

một máy ảo ở đâu đó chạy đúng phiên bản app đó, và anh có thể bấm thẳng vào để xem hoặc tương tác với phiên bản đó. Feature cần implement là một nút xuất CSV, và nút export nằm trên trang hồ sơ của con chó. Trên màn hình là nút mới đó, và bạn có thể thử feature mới trong phiên bản app này xem nó có chạy như mong đợi không. Để làm được việc này cần một ít setup.

![Trang hồ sơ Django trong bản preview của pull request, có nút Export CSV mới ở mục Sessions](https://homus.dev/photos/iPq_aCk3EsE-3643.jpg)

Bản app chạy từ nhánh của pull request: trang hồ sơ Django giờ có nút "Export CSV" ở mục Sessions, đúng vị trí worker đề xuất trong câu Q4.

Bạn cần chạy được nhiều phiên bản song song, nghĩa là cần worktree, các Docker container riêng, thậm chí các máy riêng. Theo Jo (video đăng ngày 05/10/2026), hiện tại đây là một cách khá tốn kém, phải có nhiều micro VM hay VM. Nhưng có lẽ đó là nơi chúng ta sẽ tới trong vài tháng hay vài năm nữa. Dù sao, như đã thấy, anh có thể tương tác với phiên bản app này trước khi merge, một tính năng hay.

Và anh làm được tất cả từ bên trong pull request. Thêm một loại bằng chứng nằm trong pull request (trong chừng nào bạn còn cần xây sự tự tin rằng mọi thứ chạy như mong đợi) là thứ anh đã làm một video trước đây. Anh không thích nhìn code do AI viết

như bước đầu tiên. Anh thích những thứ ở mức cao hơn. Ví dụ, theo Jo (video đăng ngày 05/10/2026), Dex Horthy có một skill tên là "show me", vẽ sequence diagram hoặc flowchart bằng ASCII từ code của bạn, cho thấy code đang làm gì.

Anh dùng một góc nhìn tĩnh hơn, về cơ bản là một UML diagram cho những thứ mới được thêm vào. Nhưng tuỳ bạn: nếu bạn thích video

giải thích từng bước app, nếu bạn thích UML diagram như anh, thì tuỳ bạn, miễn là tìm được cách cho thấy cái gì đã thay đổi mà không phải đọc từng dòng code.

Những gì Jo gom vào mỗi PR trong lúc còn xây sự tự tin dựa trên bằng chứng: không phải diff để đọc từng dòng, mà là các bằng chứng ở mức cao hơn.

## 14. Diagram, screenshot và agentic review đáng thêm token

Với Jo, đó là UML. Anh tự nhận mình "cổ lỗ" và làm nhiều việc enterprise. Còn gì nữa trong PR? Có screenshot. Anh thấy nhiều người còn làm cả video giải thích tương tác, rất hay. Nhưng nếu anh thấy screenshot trong các PR làm frontend,

làm nổi bật các màn hình đã đổi hay trải nghiệm người dùng đã đổi, thì điều đó giúp rất nhiều để xây sự tự tin và verify rằng mọi thứ chạy như mong đợi. Anh nói rõ không bảo bạn phải làm tất cả những thứ này; đây là cái chạy được cho anh, cứ chọn những gì bạn muốn làm. Mọi thứ trông ổn, và anh chuyển sang xem vài thứ khác.

Coding agent của anh, tức một trong các agent của fleet làm phần lập trình, đã làm thay đổi và tạo pull request mới. Sau đó first mate, foreman hay feature owner của anh spawn một agent reviewer. Đó là một file skill rất đơn giản nói rằng bạn nên chú ý những thứ không thể ép buộc bằng unit test hay lint rule: architecture bị vi phạm theo những cách tinh vi, hoặc có vấn đề gì đó với test. Anh có thể đi vào chi tiết, nhưng như trên màn hình, reviewer gắn cờ một số thứ, rồi worker nhận feedback đó và lặp lại để sửa.

Đó là ý tưởng chính: có một vòng, hoặc vài vòng nếu bạn muốn, feedback từ agent, worker tự động sửa, và lặp vài lần như vậy cho tới khi chất lượng khá ổn.

Vòng review đối kháng giữa hai agent mà Jo mô tả: reviewer chỉ soi những gì unit test và lint rule không bắt được, worker sửa, lặp một hay vài vòng.

Anh đã mã hoá tất cả các quy tắc review PR, nhưng việc review là agent làm chứ không phải anh. Nên anh không phải ở gần máy tính trong lúc tất cả chuyện này diễn ra. Quy tắc của anh (theo video đăng ngày 05/10/2026) là: nếu phải tốn thêm 30% token, không phải ngoài việc chỉ sinh code,

mà để chụp screenshot, làm một lượt review PR hay review code trước khi anh phải nhìn vào code, thì kể cả nếu nó chỉ tăng chất lượng code một chút thôi, vẫn đáng. Nhưng theo trải nghiệm của Jo (video đăng ngày 05/10/2026), nó tăng chất lượng code rất mạnh; chỉ một lượt review cũng đáng 30% token thêm đó.

Tuỳ bạn, nhưng anh không ngại trả thêm một chút cho việc làm feature để có chất lượng cao hơn, vì như vậy "đường băng" trước khi codebase của anh biến thành slop sẽ dài hơn nhiều. Nếu bạn chưa thử adversarial code review, tức là có một agent riêng review theo các quy tắc review bạn định nghĩa, anh khuyên hãy dành thời gian thử; theo anh nó thực sự giúp ích. Trong lần chạy này có vài vi phạm architecture. Có vài vấn đề về tính nhất quán. Có vài chỗ hack type check, đi đường tắt,

## 15. Review agent, SonarCloud và static code analysis

và review agent đã gắn cờ tất cả, rồi một commit mới xuất hiện để xử lý feedback đó. Ta cũng thấy một việc khác đã xảy ra: "Address SonarCloud feedback". Repo này chạy trên GitHub, là một repository công khai miễn phí (tính đến video đăng ngày 05/10/2026),

![Comment Review của agent reviewer trên pull request 38 với bốn mục architecture-violation, consistency-type-file, correctness, test-coverage](https://homus.dev/photos/iPq_aCk3EsE-4123.jpg)

Comment "Review" của agent reviewer trên PR #38 với bốn mục: [architecture-violation] route export nhúng luật domain vào adapter, [consistency-type-file], [correctness] một double cast che lỗi type, [test-coverage] test bỏ sót buổi tập đã lưu; dòng cuối liệt kê các mục đã kiểm như architecture, completeness, semver, naming-types, test-coverage, screenshots.

và bạn có thể dùng SonarCloud, một công cụ static code analysis. Theo Jo (video đăng ngày 05/10/2026), bạn có một số phút mỗi tháng miễn phí; còn nếu bạn làm trong môi trường doanh nghiệp, hay đang build một product mang lại tiền cho bạn, thì anh khuyên nên mua license Sonar nếu bạn quan tâm.

Anh cho xem một báo cáo Sonar trông thế nào để cụ thể hơn. Đây là CI pipeline của anh, gồm lint và test. Lint rule thì đã nói rồi, còn test backend

là toàn bộ dải test theo hexagonal design của anh, tất cả phần đó. Nhưng bạn thấy có cả một bước Sonar analysis. Anh nghĩ phải quay về một commit trước đó. Đúng rồi, commit đầu tiên kích hoạt vài cảnh báo, và bạn thấy chúng ở đây,

ví dụ nói rằng code đang dùng sai một method thay thế chuỗi, hoặc nên dùng một method khác. Jo nói thẳng anh không biết nó nghĩa là gì và cũng chẳng quan tâm. Rồi có một vấn đề về regular expression cũng nên sửa. Theo Jo (video đăng ngày 05/10/2026), đây là một công cụ phân tích code tất định (deterministic), và nó cũng được nối vào flow của anh. Bạn có thể cấu hình nó: mọi doanh nghiệp anh làm việc đều có những cấu hình SonarCloud cực kỳ tuỳ biến. Còn anh chỉ dùng profile mặc định, kiểm những thứ mặc định là bảo mật, hiệu năng và chất lượng code, và để agent xử lý những cảnh báo đó.

Anh quay lại pull request. Vậy là anh có adversarial code review, có automated test, có static code analysis, và mọi thứ diễn ra khi anh ở ngoài vòng lặp. Anh không phải nhìn tất cả những thứ này và phát điên vì đọc trace của DeepSeek hay Luna mỗi khi dùng model rẻ hơn (theo trải nghiệm của Jo, video đăng ngày 05/10/2026). Có vài commit sửa tất cả những thứ đó.

Rồi còn có bước tạo diagram cũng đang diễn ra. Và phần cuối khá thú vị, dù lúc quay nó đang bị bug nên anh bảo đừng nhìn vào các con số: anh theo dõi một PR tốn bao nhiêu, một feature tốn bao nhiêu.

Ở đây báo cáo nói feature này tốn ba euro, với một chút Opus cho chief of staff và một ít DeepSeek Flash qua một dịch vụ API trung gian cho model. Nhưng giá DeepSeek bị sai (theo số liệu Jo kể trong video đăng ngày 05/10/2026)...

Các lớp kiểm tra Jo xếp trước khi anh nhìn tới PR: review của agent, CI (lint và test), rồi phân tích tĩnh tất định bằng SonarCloud (setup trong video đăng ngày 05/10/2026).

## 16. Theo dõi chi phí mỗi feature, và câu hỏi có còn nhìn code không

... theo lời Jo (video đăng ngày 05/10/2026), hôm đó anh chỉ trả 22 cent cho DeepSeek, trong khi báo cáo nói nó tốn khoảng một đô rưỡi. Con số đó không đúng.

Nhưng ý tưởng là nó chạy đúng với các model anh dùng trong công việc. Nên anh có một ý niệm đại khái một feature tốn bao nhiêu, và khi thay đổi factory rồi chạy các eval, anh thấy được nó rẻ hơn, đắt hơn hay giữ nguyên. Khi chuyển sang model rẻ hơn,

chất lượng có giữ nguyên so với giá không? Theo Jo, rất thú vị khi có một góc nhìn về chi phí của mỗi lần chạy factory, và đó là điều anh đang cố làm với phần nhỏ này. Điểm chính là có một pull request đang chờ anh.

Bảng "Factory Cost Report" mà factory đăng vào PR liệt kê chi phí theo từng vai; Jo dùng nó để so sánh mỗi khi chỉnh factory hay thử model rẻ hơn (con số trong bản demo đang bị lỗi giá, như anh nói).

Anh còn chưa nhìn code, nhưng khá chắc nó đạt chuẩn của anh. Một điều thú vị là code review agent, lượt review đối kháng, đã gắn cờ chuyện có domain logic nằm trong code routing. Anh không thích điều đó,

nhất là với chuyện hexagonal design của anh: routing và domain logic nên tách riêng. Nhưng reviewer agent đã gắn cờ, implementing agent đã sửa. Nên anh thậm chí không thấy cái khoảnh khắc code tệ như vậy.

Tất cả đã được sửa trước khi anh thấy PR này. Và như ta thấy, nó đã refactor và tạo một export service. Điều này khớp hơn với cách anh tự viết. Theo Jo, rất hay khi anh không phải có mặt để liên tục nhắc nhở, liên tục lái các agent này

về hướng anh thích code phải như thế nào. Tất cả diễn ra khi anh ở chỗ khác. Nếu bạn làm việc này một thời gian, theo kinh nghiệm của Jo (video đăng ngày 05/10/2026), bạn sẽ để ý rằng rất nhiều PR, kiểu 90% trở lên, bạn không có nhận xét gì cả. Nó trông ổn. Và bạn bắt đầu cho chúng auto-complete. Anh nghĩ điều đó hoàn toàn ổn.

Đó là việc xây sự tự tin vào hệ thống của bạn. Nhưng nó đi kèm một lưu ý. Với anh, lưu ý đó là toàn bộ cuộc tranh luận về dark factory: chúng ta có nên nhìn code nữa không? Có nên biết code trông thế nào nữa không? Nếu làm tất cả những điều trên, anh thấy (video đăng ngày 05/10/2026) code trông khá giống như anh mong đợi, kể cả khi anh đã lâu không đụng vào code. Nó sinh ra đúng những abstraction anh mong đợi.

Đó là nhờ một thứ mà Kent C. Dodds gọi là primitives: trong code frontend và backend của anh có những khối xây dựng anh cứ dùng đi dùng lại, và anh không phát minh lại một cách truy cập dữ liệu mới. Anh có một cách truy cập dữ liệu, và agent của anh nên theo đúng một cách truy cập dữ liệu đó.

## 17. Primitives, dim factory, heresies và quét dọn định kỳ; PR thành workspace của agent

Đó là thứ Kent gọi là primitives. Với Jo, anh là fan lớn của functional programming, fan lớn của domain-driven design, vertical slice, CQRS, tất cả mớ thuật ngữ kỹ thuật đó.

Anh có một cách build backend rất riêng. Mỗi khi bắt đầu một app mới, anh gieo sẵn các primitive đó. Anh có một ví dụ truy cập dữ liệu trông thế nào, một ví dụ một test tốt trông thế nào. Đó là một thứ anh có chú ý tới,

rồi anh mã hoá tất cả các quy tắc này, kiểu truy cập dữ liệu phải luôn theo pattern này, vào lint rule hoặc vào quy tắc review PR. Và đó là thứ anh cần thỉnh thoảng đi quét. Nên khi nói tới dark factory,

hay giữ đèn sáng, hay ở đâu đó giữa hai thứ, anh nghe người ta dùng thuật ngữ "dim factory" (factory mờ), và đó là cách anh thích nghĩ về nó. Phần lớn thời gian anh không nhìn code.

Vị trí Jo chọn: dim factory, phần lớn thời gian không nhìn code nhưng vẫn định kỳ đi vào code mà không chặn PR.

Anh không nhìn các phiên agent. Anh cứ để chúng "nấu" rồi nhìn kết quả, hoặc thỉnh thoảng nghịch app. Nhưng đôi khi anh vẫn lặn vào code, theo cách không chặn (non-blocking). PR vẫn có thể auto-complete.

Chuyện đó hoàn toàn ổn. Nhưng anh thích thỉnh thoảng dành thời gian trong code để chắc rằng các primitive vẫn nguyên vẹn. Steve Yegge, tác giả của "Vibe Coding" và Gas Town,

gọi đây là heresies (dị giáo): những pattern xấu, những anti-pattern được coding agent cấy vào codebase của bạn, và theo Jo (video đăng ngày 05/10/2026) chúng có xu hướng lan nhanh như cháy rừng. Đó là thứ Jo khá nhạy cảm.

Nên anh thỉnh thoảng nhìn code để chắc rằng mọi primitive vẫn nguyên vẹn và mỗi feature mới đều dùng các primitive đó. Vậy là anh có nhìn code. Anh không nhìn từng PR, không nhìn từng dòng code được sinh ra,

nhưng anh thích những đợt quét định kỳ làm bằng tay. Bạn có thể viết agent cho việc này, nhưng anh thích làm tay để xem các primitive: các khối xây dựng có còn đó không? Design system ở frontend có còn nguyên vẹn không? Các abstraction ở backend có còn nguyên vẹn không?

![Slide với bốn gạch đầu dòng về cleanup pass bên cạnh ảnh đen trắng một người thợ quét ống khói](https://homus.dev/photos/iPq_aCk3EsE-4913.jpg)

Slide "sweeping" kèm ảnh một người thợ quét ống khói: rác sẽ lọt vào (Rot will leak in); review tất định, của người hay của agent đều sẽ sót; các lượt dọn dẹp là cách tốt để giữ liên lạc với code; giữ các primitives nguyên vẹn và đẩy heresies ra khỏi hệ thống.

Anh gọi việc này là sweeping, quét dọn, như một cách gợi lại nghề thợ quét ống khói ngày xưa. Anh làm đều đặn và vẫn làm bằng tay, nhưng bạn cũng có thể tự động hoá. Điểm của anh là

dù bạn thiết kế factory tốt tới đâu, slop vẫn sẽ lọt vào codebase. Theo Jo (video đăng ngày 05/10/2026), bạn có thể cầm máu lâu hơn nhiều so với một năm trước, nhưng chuyện đó vẫn có thể xảy ra. Đó là lý do anh có xu hướng làm các đợt quét này và tập trung vào các primitive như đã nói: các khối xây dựng có còn nguyên vẹn không.

Một điểm rút ra cuối cùng: Jo không thích PR, hay đúng hơn là anh đã không thích chúng trong thời kỳ trước AI, vì chúng là một yếu tố gây tắc nghẽn, chúng được tạo ra cho open source và chưa bao giờ dành cho những team làm việc sát nhau. Đó là triết lý của anh.

Nhưng trong thời đại AI, anh lại quay về dùng PR. Đầu năm nay (theo video đăng ngày 05/10/2026), PR là cách để nhìn code trước khi nó được merge vào main. Giờ nó giống một workspace tạm thời hơn, nơi các agent này và các reviewer có thể nói chuyện với nhau và cộng tác. Nên với anh, PR không còn là một cổng chặn trong các codebase của anh nữa.

Chúng là workspace cho agent. Và đó cũng là nơi bằng chứng được gom lại: tất cả screenshot, tất cả các lần chạy CI xanh. Đó là lý do anh vẫn dùng PR. Và như anh đã nói, chuyện PR trở thành bottleneck,

CI trở thành bottleneck, anh nghĩ đó là chuyện nhảm nhí. Hoặc không hẳn: với loại phần mềm anh build, backend nặng, business logic nặng, theo Jo bạn có thể scale CI lên 100 lần mà nó không thành bottleneck nếu bạn làm test automation có chiến lược hơn một chút, thay vì cứ test end-to-end mọi thứ. Vậy là anh bắt đầu dùng lại PR vì đúng lý do này, nhưng anh không

coi nó là một cổng chất lượng chặn lại, hay là chỗ con người phải duyệt. Anh coi nó là không gian cộng tác cho các agent của anh, và cho anh với các agent mỗi khi anh làm việc on the loop nhưng muốn lái một chút, ví dụ tham gia phiên grilling. Nó là một audit trail, một evidence package. Và anh cũng complete rất nhiều pull request trên những codebase mà anh đã dựng các thứ factory này, nơi anh đã thấy đủ nhiều PR mà bản thân không có nhận xét nào. Nên anh cứ để nó chạy, và thỉnh thoảng đi quét.

Trên slide "Rebirth of the PR": PR của bạn nên thôi là một "diff" để review hay làm cổng chất lượng một cách khổ sở; thay vào đó, hãy coi nó là một evidence package.

## 18. AI factory psychosis và tổng kết

Một ý "ném thêm" trước phần tổng kết: tuần trước (so với lúc quay video đăng ngày 05/10/2026), Jo thấy một tweet của Solomon Hykes nói rằng có một kiểu "AI psychosis" mới, và nó tên là AI software factory. Anh nghĩ Solomon có lý. Theo Jo, rất nhiều người đang bỏ rất nhiều thời gian

![Tweet của Solomon Hykes ngày 22 tháng 9 năm 2026 về một giai đoạn AI psychosis mới: factories, so sánh gross và net developer productivity](https://homus.dev/photos/iPq_aCk3EsE-5136.jpg)

Tweet của Solomon Hykes ngày 22/09/2026 trên slide: "We're entering a new phase of AI psychosis - factories", rồi đề nghị so hai con số: gross developer productivity (bạn ship bao nhiêu code) và net developer productivity (bạn ship bao nhiêu code, trừ đi thời gian làm việc trên factory của bạn; phần chữ giữa câu bị khung camera che).

để thử nghiệm những thứ này. Nhưng anh vẫn nghĩ đây là điểm đến cuối, là hướng mọi thứ đang đi và nên đi. Tuy vậy, lời cảnh báo của Solomon là thứ anh khuyên nên ghi nhớ: nếu bạn được trả tiền để build product, hay bạn đang ở một startup build product, đừng dành nhiều thời gian build factory hơn thời gian nghĩ về product của bạn. Hãy dành nhiều thời gian thiết kế factory hơn thời gian viết code

cho product, nhưng đừng để nó thành nỗi ám ảnh. Bạn không ở đây để build framework factory open source tiếp theo; nếu bạn đang làm vậy thì càng tốt cho bạn. Nhưng anh thấy rất nhiều engineer lạc lối trong việc mân mê các công cụ này. Còn anh, một khi harness và factory đã dựng xong và cho kết quả từ tốt tới rất tốt, anh (video đăng ngày 05/10/2026) không đụng vào nó nữa cho tới khi có model mới ra, lúc đó anh có thể gỡ bỏ một nửa factory vì model đã giỏi hơn. Nên đừng làm quá. Vậy đó là bản demo nhỏ về một software factory.

Nhưng điểm của video không phải "mua software factory tuyệt vời của tôi" hay "clone repository của tôi". Theo Jo, có những repository tốt hơn ngoài kia. Nếu muốn xem một cái, anh khá thích super-simple-software-factory của IndyDevDan. Theo anh (video đăng ngày 05/10/2026), nó là một bộ khởi đầu (bootstrap) tuyệt vời. Nếu bạn tìm một template để dùng, hay để chỉ coding agent vào đó để build cái của riêng bạn, anh gợi ý xem phiên bản của IndyDevDan. README của repo này (đọc ngày 23/10/2026) tự mô tả là các workflow lặp lại được gồm agent cộng code, đóng gói thành một skill và "đóng dấu" vào bất kỳ repo nào, với Python tất định nắm đồ thị và coding agent là các node bị giới hạn bên trong.

Điểm của video là: đi từ coding tương tác với agent sang làm việc on the loop nhiều hơn và làm software factory theo kiểu poteto cần rất nhiều điều kiện tiên quyết.

Thông điệp cuối của Jo: leo thang để không bị kẹt trong các phiên tương tác, rồi nhận ra sự chú ý của chính bạn là ràng buộc lớn nhất.

Nhưng theo Jo, điều đó hoàn toàn khả thi nếu phần mềm và môi trường của bạn được xây theo cách thân thiện với agent, và anh đã đưa ra vài gợi ý trong video. Điểm rút ra của anh là: hãy đến đó, leo cái thang này, nâng cấp bản thân để bạn không còn ngồi trong những phiên tương tác. Rồi bạn sẽ cảm nhận nỗi đau trở thành bottleneck mới, và bạn bắt đầu để ý rằng token thì đắt, nhưng sự chú ý của bạn có lẽ mới là ràng buộc lớn nhất. Vì vậy bạn cần tìm cách để không phải nhìn từng dòng code và không phải trông coding agent cả ngày.

Những thành phần factory đã bàn, anh nghĩ, là đòn bẩy bạn có thể dùng và nên dùng. Anh rất tò mò muốn xem mọi người làm gì với các khối xây dựng này, mời mọi người kể lại ở phần bình luận, và hẹn gặp lại lần sau. "Bye-bye. Keep building."

## Nguồn và liên kết

- Tên gốc: Watch this before you build your first software factory
- Sự kiện: [YouTube](https://homus.dev/events/youtube)
- Video gốc: [https://www.youtube.com/watch?v=iPq_aCk3EsE](https://www.youtube.com/watch?v=iPq_aCk3EsE)

- Kênh YouTube Jo Van Eyck (Jo Van Eyck): [youtube.com/channel/UCqxnGGhdpQ21yiqPvNuieAQ](https://www.youtube.com/channel/UCqxnGGhdpQ21yiqPvNuieAQ)

- Repo demo của video, app DogTrainr cùng cấu hình factory (đọc ngày 23/10/2026): [github.com/jovaneyck/software-factory-demo](https://github.com/jovaneyck/software-factory-demo)

- Addy Osmani, "Human judgment doesn't leave the software factory. It relocates.", nguồn của định nghĩa software factory: [addyosmani.com/blog/human-judgment-doesnt-leave-the-software](https://addyosmani.com/blog/human-judgment-doesnt-leave-the-software/)

- Gergely Orosz, The Pragmatic Engineer, "Inside OpenAI's agentic software factory": [The Pragmatic Engineer: Inside OpenAI's agentic software factory](https://newsletter.pragmaticengineer.com/p/openai-software-factory)

- IndyDevDan, super-simple-software-factory (đọc ngày 23/10/2026): [github.com/disler/super-simple-software-factory](https://github.com/disler/super-simple-software-factory)

Nguồn: https://homus.dev/talks/watch-this-before-you-build-your-first-software-factory · cập nhật 2026-10-23
