Friday, February 20, 2026

Mẻ code

Cuối tháng 4, trời nắng bể đầu, Sài Gòn thì vẫn bụi, mưa đầu mùa đâu chưa thấy. Từ trạm metro vào tới thang máy văn phòng, Phát mới thoát khỏi không khí quánh mùi khói xe và... mùi mồ hôi nách. Hít một hơi làm mới hai lá phổi, Phát xem qua Slack. Không tệ, Phát chưa coi hết các dòng status, nhưng cơ bản xanh nhiều hơn đỏ, còn cụ thể ra sao, chờ ly cà phê sáng hạ hồi phân giải.

Phát, 28 tuổi
Software Engineer

Phát không coi qua những báo cáo màu xanh. Xanh tươi, xanh mơn mởn, XanhSM. Xanh nghĩa là code đã xong và hệ thống kiểm tra cho qua. Đám code đó sẽ đi lên production vào đầu giờ chiều. Màu đỏ mới là công việc của Phát sáng nay. Đỏ lửa, đỏ đen, đèn đỏ. Đỏ nghĩa là đã có sai lệch giữa tư duy AI và kết quả kiểm tra độc lập. Code này cũng đi, mà đi đầu thai. Chỉ hai trong số tám tính năng làm tối qua cần coi lại. Mới mấy tháng trước, lúc còn đang probation, ngày nào báo cáo của Phát chỉ có màu của máu. Hàng triệu token hóa hư vô. Nguyên ngày làm việc hóa công cốc.

Sáng nay lại là code frontend bị sai. Không lạ. Mỗi mẻ code, Phát làm vừa backend lẫn frontend - AI chạy tốt nhất khi nó được giao trọn vẹn một tính năng. Đây cũng là cấu hình tốt nhất cho những hệ thống kiểm tra độc lập, có những vấn đề chỉ xuất hiện khi ghép hai nửa tưởng-là-đúng lại với nhau. Hồi trước, backend là lá ngọc cành vàng, sương sa hạt lựu, nâng trứng hứng hoa. Bây giờ điều này chỉ đúng cho phần lõi của những hệ thống đã đi vào ổn định. Khi sản phẩm vẫn đang tìm chỗ ngứa, ăn thua nhau giờ là ở frontend. Code backend nặng về logic khá phù hợp với tư duy của AI, hoặc có viết khác đi bình thường mà kết quả vẫn đúng thì cũng không mấy ai quan tâm. Frontend là cái mặt tiền, không thuận một cái là gai con mắt liền, mà trong vô hạn cách các nút ấn, chữ, và hình kết hợp với nhau, mô hình AI mới nhất nhiều khi cũng... chịu. Ta thường ngộ nhận AI làm đúng một việc đồng nghĩa với việc nó có tư duy, và chỉ nhớ về bản chất LLM là cái lò xổ số vào những lúc này.

Con bug thứ nhất... không phải nhóm này. Vụ khác. Làm translation lần đầu để trang web Anh-Việt đều dùng được. AI dịch rất mượt, Language Model mà, thay luôn mấy anh freelancer trên Upwork. Nhưng dịch một câu và dịch một hệ thống web là hai chuyện khác nhau. Cả tối qua, bào hết mấy lần context window mà vẫn chỗ thiếu, chỗ thừa, chỗ còn nguyên chuỗi thô notifications.task_assigned_to_client chằm dằm. Quét toàn bộ mã nguồn, từ giao diện, mã lỗi, đến email tuần tự, chỉn chu tưởng là phù hợp với AI nhưng hóa ra còn khó nhai với bộ nhớ tiêu chuẩn lắm, dù từ đầu năm nay đã tăng lên gấp đôi. Phát xóa code cũ đi - làm với AI xây mới nhiều khi dễ hơn sửa lại, bởi mới gọi là đi đầu thai dễ hơn tu thành chánh quả - rồi viết tay một cái plan mới, khoanh lại từng vùng cần dịch, hướng dẫn AI chia nhỏ việc để không tràn bộ nhớ. Xong xuôi.

Ngó tới con bug số hai, Phát nhăn, nó nghĩ, con bug này dễ quá mà sao vẫn làm sai?! Một trường dữ liệu mới được thêm vào giao diện nhưng không được lưu xuống database. Quá đơn giản, sửa cũng rất nhanh. Nhưng đội AI của Phát có 4 "chú", uống token như Humvee uống xăng bên Iran, mà vẫn bị những lỗi nghé ọ như này thì không đáng. Đội AI của Phát tốn token hơn nhiều một câu lệnh độc lập, nhưng bù lại tụi nó tự lên kế hoạch, viết code, rồi kiểm tra chéo lẫn nhau. Một hệ thống như vậy, trên lý thuyết, có thể chạy cả ngày mà không cần con người giám sát. Mục tiêu không phải là làm nhanh hay chậm. Mục tiêu là AI tự bơi - nhiều nhất có thể. Một khi AI tự bơi thành công, nó trở thành một cỗ máy chạy ngày chạy đêm, chạy đa luồng, chạy không quan tâm tới Peta (People for the Ethical Treatment of Agents), tốc độ là một hệ quả tự nhiên. Không nhảy vào sửa trực tiếp, Phát phải truy cho ra tại sao các chú AI bỏ qua con bug abc này. Thói quen của Phát là sửa code, giờ phải sửa AI để sửa code, nó thấy như ăn phở mà không có rau sống, nhưng anh lead dặn hoài.

Trưa. Phát nghĩ là đã tìm ra lỗ hổng trong logic của AI làm nó dừng code khi kiểm tra chưa xong - mẹ đẻ con bug số hai. Nghĩ tới cuốc bộ hai cái ngã tư trong cái lò bê tông Sài thành mà hết muốn ăn. May quá, công ty có canteen. Đường đến canteen ngang qua phòng máy. Dàn quạt làm mát chạy êm, chỉ nghe ì ì. Chắc tại còn mới, ai biết ba hồi nó kêu chả khác gì dàn máy lạnh, cùng một thứ mà. Phòng máy này là một thử nghiệm. Một cái máy đẻ code chạy ngày đêm đốt token như Snoop Dogg đốt cỏ - liên tục và không dừng lại. Model càng thông minh càng đốt token. Ngành này chưa ai tìm ra cách làm AI thông minh hơn mà ít tốn token. Chỉ dùng mỗi model thông minh nhất thì lương kỹ sư sợ cũng theo không kịp. Model nguồn mở thua kém model độc quyền tầm 6 tháng 1 năm, nhưng chỉ tốn tiền phần cứng và tiền điện. Liệu có thể tạo ra kết quả tốt tương đương model đắt tiền bằng cách cho model rẻ chạy nhiều lần hơn - đây là thử nghiệm kéo giá RAM lên tới nóc. Cơm xong, trên đường chích caffein Phát thấy mấy anh DevOps lui cui lôi máy ra ngoài, nghe bảo là để thêm RAM. Lời nhắc xem công ty có thanh lý phần cứng không đã được ghi nhận.

Team Phát năm người họp sau giờ nghỉ trưa. Mọi người báo cáo kết quả tối qua, Lần đầu tiên có một mẻ đạt 100%. Xanh, mơ một giấc mơ màu xanh 🎶. Phát nói về con bug số hai và bà mẹ của nó (con bug, không phải Phát). Người khác nhắc đã tới lúc cập nhật lại file AGENTS.md của hơn chục repo sau hơn hai tuần. Anh Tech Lead so sánh kết quả thử nghiệm đầu tiên giữa model độc quyền và model nguồn mở của một team khác. Phía QA chỉ ra vài vấn đề hạn chế sự tự chủ của AI mỗi khi liên quan đến repo Task Assignment - tới lúc phải dọn lại. Cả nhóm xúm nhau giáo dục lại AI, nhồi thêm 50 dòng prompt vào bộ mẫu. AI sẽ phải kiểm tra nhiều hơn, mỗi đầu việc chắc sẽ chạy chậm hơn 10-20 phút, nhưng nếu tỉ lệ thành công tăng 10%, đây là một cái giá nhỏ.

Nửa sau, anh em chia nhau công việc cho mẻ code đêm nay. Tính năng mới, cập nhật tính năng cũ, sửa lỗi, và đủ loại thập cẩm. Không như con người muốn làm những việc liền mạch nhau, AI không quan tâm. Nó có thể có một context window nhỏ, nhưng không hề có chi phí context switching. Thay vào đó, mọi người dành thời gian để bàn AI đã có đủ context chưa và làm sao check var khi nó làm xong. Lòi ra hai việc mà anh Tech Lead nghĩ AI chưa sẵn sàng tự bơi. Phát được giao một trong hai. Nó không phiền, còn thấy mừng. Quay lại với code sau cả ngày viết prompt là cơ hội chuyển cảnh cho đầu óc được tươi mới. Cũng là cơ hội đánh giá hệ thống AI xây có một cái nền tốt hay lỏng lẻo - chạm vào là sập. Lỡ mà trúng vế sau, sắp tới chắc mệt, nhưng biết sớm còn hơn không biết. Quan trọng hơn, Phát không muốn giao AI những việc mà tự nó không biết làm.

Họp xong cũng hơn 3 giờ chiều. Ngày nào cũng họp như vậy. Phát không biết cuộc họp gọi là gì, từ lúc Phát vào công ty, mọi người đã họp đều đều như vậy. Nó là buổi retrospective, sharing, họp đầu tuần - giao ban (iteration planning meeting) và vân vân cuộn lại làm một. Những cuộc họp này từng riêng lẻ và diễn ra hàng tuần, hàng tháng. Nhưng thời buổi tính năng mới bị sao chép trong vài ngày và mỗi mẻ code toàn màu đỏ là một ngày không lấy lại được, y như những ngày nó phải học TTHCM, hàng ngày là tần suất cần thiết để giữ cỗ máy code chạy hiệu quả.

Sau giải lao tám xàm với anh mấy project manager còn đang lan man định nghĩa thế giới hậu Agile, Phát quay lại mặt đất. Nó cần chuẩn bị cho ca buổi tối. Phát nhận 9 đầu việc. Chi tiết từng việc, việc nào làm trước, việc nào làm sau, cái nào chặn cái nào, đều được ghi lại trong một cái sớ dài thòng. Kèm với bản spec và kiến trúc tổng, AI cần có đủ context để không phải đoán mò, chỉ tập trung vào code. 8 việc đầu Phát đọc kỹ như hợp đồng vay ngân hàng và sửa lại những phần có thể gây nhầm lẫn. Làm với AI giờ không khác làm phần cứng, khuôn mà sai thì thành phẩm không thể chuẩn. Khi đầu óc tù mù trong đống specs, Phát coi vào việc số 9 - là việc có lẽ AI chưa sẵn sàng tự bơi. Không còn làm người giám sát, nó "ngồi xuống" cầm tay AI chỉ việc. Phát viết trước vài đoạn code mẫu. AI viết đoạn tiếp theo. Phát đọc lại, rồi viết phần tiếp theo. Hai bên ping pong qua lại một lúc, code đã được hòm hòm. Đó trờ thành văn mẫu cho AI để đêm nay làm tiếp các phần tiếp theo.

Thoáng đã tới 5 giờ. Ngày dài, ngoài trời nắng cũng dịu lại. Nếu Phát ở ngoài trời, chắc nó sẽ nói gió từ sông đang thổi man mát, nhưng nó ở trong lồng kính máy lạnh chạy phà phà sáng giờ. Làm việc cả một ngày là để chuẩn bị cho lúc này. Phát bấm Enter, lần lượt prompt, specs, design, và hầm bà lằng các tài liệu khác, được tải lên cho AI. Từ chỗ ngồi, Phát nghe thấy tiếng quạt từ phòng máy lên thêm một số, chạy ro ro. Không chỉ có Phát, nhiều người khác cũng bắt đầu ra lệnh cho đội AI của mình. Người đã hết xí quách, Phát chia hai màn hình, một bên là màn hình terminal AI đang chạy Optimus 6.2, một bên là bài báo thông cáo Optimus 7 vừa được giới thiệu. Việc ngày hôm nay AI làm không được, ngày mai có khi sẽ thành công. Việc đầu tiên đã code và kiểm tra xong. Vẫn xanh. 

5:59 Phát ra về. Phòng máy vẫn chạy đều đều. Đội AI tiếp tục đi từ việc này qua việc khác. Sáng mai, Phát sẽ nhận kết quả của mẻ code này. Xanh hay đỏ bây giờ là việc của AI, cuộc sống của anh thanh niên Phát giờ mới bắt đầu. Ngoài trời đúng thật gió đang thổi man mát.

Saigon, 22.04.2028

---

Bài viết là một lát cắt hư cấu về viễn cảnh công nghệ năm 2028. Mọi sự trùng hợp với người thật hay tổ chức ngoài đời thực đều là ngẫu nhiên.

English version is available at my Substack.

Tuesday, February 17, 2026

The future is weird

I am not in the business of future prediction, so this is not one of those the-singular-is-near kind of things. The future written here might not be very far either, like a few months or a couple of years max down the road. I guess what I am trying to say is that this might not be a very good prediction. That is a fair warning from your truly.

If you are still here, then strap in!


The future is waterfall

I am quite invested in vibe coding. I have had the whole workflow figured out - until the next LLM release screws it up, story of another time. From requirements to technical design, I basically end up with fat Jira tickets. They are longer than anything I write for myself, not that I am a prolific Jira user to begin with. The idea is that, between the ticket and the codebase, LLM has all the context it needs to finish the work on its own.

The one thing this workflow handles horribly is requirement changes. If the change is non-trivial, I would have to update a whole bunch of artifacts. Yes, I can accommodate the changes. But I have to do it. How one change affects the project is not something I can hand over to LLM in a single prompt yet. So it is just annoying.

I also notice that the current generation of LLM isn’t exactly built for interactive work like a true pair programmer. I have had many successes revising implementation plans with LLM, but far fewer stories revising the code. Between revising code in interactions and changing the plan, giving LLM a fresh start, many times the former seems like just sunk cost fallacy. LLM either gets it right the first time or it doesn’t.

I find vibe code rewards big planning, so… my workflow has increasingly been more Waterfall. I was taught Waterfall was bad, and I should feel bad. I think Waterfall got its bad rap from its slow feedback time. But LLM is much, much faster at producing code. If I chunk the scope of work well, I usually have stuff to show in a couple of days. Agile isn’t exactly holding its candle well either. I like to think RAPID will be the next methodology ;)

The future calls for multi-agent orchestration

I don’t usually vibe code with just one LLM instance. Staring at the screen while the agent does its thinking and chunking was mesmerizing the first time I figured out the secret sauce. After that, it is just meh. I tend to have 2-3 instances run in parallel instead. Token!

That is about as much parallelism as my brain can handle though. Beyond that, it is torturous. A stronger human might say that is weak, to which I respond: you are absolutely right! But as long as one has to manhandle the instances, there is a physical limit to how this gonna scale. And while I get to shut down my laptop at 6 PM, who on God’s green earth gives these LLM instances the right to rest?! There is no Peta for bot yet!

2026 started with a Gas Town-shaped bang. Steve Yegge is known for his rants. His writing can’t be described as well-structured thoughts, but it’s entertaining. What else can one ask for?

I don’t buy the messiness of Gas Town, I hope the future is cleaner and has better token efficiency. But I love the analogy that Gas Town to LLM is like k8s to Docker.

In my sweet dream, months from now, I will spend my afternoon planning. At 5 PM, I hit a big red button that says “Start” - it is very important for my well-being that the button is red and big. An engine starts to hum and produce code. I watch the metrics for an hour before calling it a day. The engine purrs through the night. The next morning, I come to the office and realize that the whole night of work, $2000 worth of tokens, has produced complete garbage. Marvelous!

The future rewards M-shaped people

I wrote about this before. And it is not the future, it is now. This point just goes really well with multi-agent orchestration. To operate such a (costly) engine, you cannot afford to say “I don’t know what it is producing, it passes the tests, so it is good enough for me”. I mean, technically you can, but I am afraid there are people better qualified for your job then, because they can judge and calibrate the outcome.

I had this back in 2025 and I think it is still correct
This is not my original idea - the concept is widespread on the internet. The traditional model has been the T-shaped professional: the vertical bar represents depth of related skills and expertise in a single field, whereas the horizontal bar is the ability to collaborate across disciplines. In software development, this meant being, say, a backend engineer who understands enough frontend and DevOps to collaborate effectively.

But LLM doesn’t just allow us to do things better. Contrary to the popular belief that AI accelerates brain rot, I find that motivated people learn faster with AI support. The other day, my staff engineer gave Claude Code access to the Postgres source code and proceeded to drill down some very technical questions that otherwise would be impossible for us to have that expertise in a short amount of time. LLM gives us access to the consultancy we didn’t have before.

Instead of knowing one thing really deeply (the hallmark of individual contributors in the past), it allows us to know many things deeply, hence the M-shaped analogy (m - lowercase - would have been better, I was clueless what to take of the capital M initially). This shift is profound for career development. The traditional advice of “specialize or generalize” is becoming obsolete. The future of career advancement lies in being able to connect multiple domains of deep expertise.

 

The future cares more about latency than elegance

I used to agonize over code. Variable names. Function boundaries. The perfect abstraction. I was taught that good code is elegant code, and elegant code is maintainable code. The logic was sound: you write code once, you read it a hundred times, so optimize for reading.

But what if you write code once and never read it?

Vibe coding can be quite wasteful. I am encouraged not to bother with the perfect abstraction, just focus on the problem at hand. A script to migrate some data. A one-off analysis. A prototype to test an idea. LLM generates it. I run it. I delete it. If I need it again, I regenerate it. The regeneration takes two minutes. The careful crafting would have taken two hours. It is a future of quantity over quality. Many people I know would hate this. I hate it too, reading Zen and the Art of Motorcycle Maintenance in my formative years. But I am afraid this is happening regardless of my preference.

This changes what “good” means. Good code used to mean elegant code. Now good code means fast-to-produce code. Latency is the new elegance. The question isn’t “is this beautiful?” but “how quickly can I get something that works?” 


The future doesn’t look kindly on some best practices

This realization sent me down a rabbit hole. How many best practices are solutions to problems that AI simply doesn’t have?

Take “keep functions short.” I was taught 20 lines max. The reasoning: humans have limited working memory. We can’t hold a 500-line function in our heads. So we break things into digestible chunks. But Claude processes massive functions without breaking a sweat. If anything, too many tiny abstractions make it harder for Claude to follow the flow. The function length rule was never about the code. It was about the human brain.

Comments and static documentation that drift from reality within a week? While they might be useful in some specific situation, like the user should not have access to the source code, but if people have access? LLM can just read the actual code and tell me what it does now, not what someone wrote it did six months ago.

Story point estimation? When Claude can prototype something in twenty minutes, “how many points is this?” becomes “let me just try it and see.” The estimation ritual was about managing uncertainty over weeks of human effort. The uncertainty shrinks when the effort shrinks.

Not all practices are heading for the graveyard though. Some survive, but for different reasons. DRY used to exist because humans forget to update all instances when logic changes. Copy-paste five times, change it in four places, spend three hours debugging the fifth. Classic. AI doesn’t have this problem. It can regenerate boilerplate on demand without breaking a sweat.

But DRY still matters. Less code means more context fits in the LLM’s context window. Every duplicated block is tokens that could have been spent helping Claude understand the rest of your codebase. The practice survived, but the why behind it shifted completely.

I have been coding professionally for 15 years now. I tend to look at myself as an old guard of (some) old values. I groan at kids using Python shell to query instead of raw SQL. I feel like in the coming time, dogmatic vs pragmatic will give me some serious cognitive dissonance.


The future cares about audit, not review

If humans aren’t writing the code, and humans aren’t reading the code, how do we know the code is any good? The answer used to be code review. But when LLM generates a 500-line PR in ten minutes, and the 3 previous PRs were reasonably good…my attention drifts.

I find myself caring more about things I can verify without reading every line. The obvious stuff: does it have tests? Do the tests actually test behavior, not just chase coverage? Can I trace requirements to implementation without understanding the implementation itself?

But increasingly I care about the generation process, not just the output. What was the plan before the code was generated? What context did the agent have access to? Enough context? Too little? Too much noise? Did it have the right files in its window, or was it hallucinating an API that doesn’t exist? Did it follow the technical design, or did it improvise?

These questions feel strange. I’m not reviewing the code. I’m reviewing the conditions under which the code was born. It’s like judging a student’s exam by checking whether they had the right textbook open, not by grading their answers.

The future looks like layers of automated verification with humans doing spot checks. AI writes code. Different AI reviews code. Static analysis runs. Humans audit the audit - sampling PRs to calibrate confidence, checking that the verification system itself is trustworthy.

Artisanal code review is declining. Not because the wisdom doesn’t matter, but because it is not always required.

---

Tldr; The future is fat Jira tickets, multi-agent orchestration humming through the night. It needs M-shaped people who can man the beast - with enough depth across domains to know when the machine is producing gold versus garbage.