Cuối cùng, mình cũng đã đú trend "vibe-coding" để khám phá tiềm năng của nó. Dù gọi là "vibe-coding", mình không hoàn toàn phụ thuộc 100% vào AI, nhưng phải thừa nhận rằng mình thực sự ấn tượng với một số mô hình AI mới hiện nay, đặc biệt là các mô hình có khả năng suy luận (reasoning models) như Gemini 2.5 Pro (hoặc các phiên bản thử nghiệm tiên tiến) và DeepSeek R1.
Những trải nghiệm "thủ công" ban đầu với AI Coding
Trước đây, mình không thường xuyên sử dụng AI để lập trình. Những lần thử nghiệm ban đầu của mình khá thủ công và thường theo một vòng lặp kém hiệu quả:
- Sao chép mã nguồn và dán vào một mô hình như ChatGPT để yêu cầu thêm chức năng hoặc tái cấu trúc (refactor).
- Sao chép mã nguồn từ ChatGPT trở lại dự án, sau đó chạy thử và gặp lỗi.
- Sao chép thông báo lỗi và gửi lại cho ChatGPT.
- Sao chép mã đã sửa từ ChatGPT vào dự án, và rồi... lại phát sinh lỗi khác. Quá trình này lặp lại từ bước 3.
Chỉ cần gặp phải tình trạng dự án không chạy được khoảng hai lần là mình cảm thấy nản lòng và từ bỏ.
Sau này, một số IDE đã tích hợp các giải pháp để khắc phục những vấn đề trên, giúp người dùng không còn phải thực hiện thao tác sao chép-dán thủ công giữa trình soạn thảo và ChatGPT. Thậm chí, các AI Agent còn có khả năng tự động sửa lỗi khi dự án gặp sự cố. Tuy nhiên, cá nhân mình không sử dụng các công cụ này mình dùng Neovim cơ mà. Do đó, trong bài viết này, mình sẽ chia sẻ nhanh cách "vibe-coding" trên Neovim.
Chuẩn bị "Gia Vị" cho Vibe Coding: Thiết lập trên Neovim
Để thực hiện "vibe-coding" trên Neovim, chúng ta cần cài đặt plugin avante.nvim. Bạn có thể tham khảo hướng dẫn cài đặt chi tiết tại liên kết của plugin. Trong cấu hình Neovim cá nhân, mình đã loại bỏ một số dependencies không cần thiết và vì dự định "vibe-coding" bằng Gemini, mình sẽ thiết lập provider="gemini". Đây là cấu hình của mình:
{
"yetone/avante.nvim",
cmd = { "AvanteChat", "AvanteToggle" },
version = false, -- Never set this value to "*"! Never!
opts = {
-- add any opts here
-- for example
provider = "gemini",
gemini = {
-- @see https://ai.google.dev/gemini-api/docs/models/gemini
model = "gemini-2.5-pro-exp-03-25",
timeout = 30000, -- timeout in milliseconds
temperature = 0, -- adjust if needed
max_tokens = 32768,
},
highlights = {
---@type AvanteConflictHighlights
diff = {
current = "DiffDelete",
incoming = "DiffAdd",
},
},
selector = {
provider = "snacks",
provider_opts = {},
},
},
-- if you want to build from source then do `make BUILD_FROM_SOURCE=true`
build = "make",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"stevearc/dressing.nvim",
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
"echasnovski/mini.icons",
},
}
Tiếp theo, bạn cần export biến môi trường GEMINI_API_KEY để avante.nvim không yêu cầu bạn nhập mỗi khi khởi chạy plugin:
# Thêm dòng này vào .bashrc (hoặc .zshrc, .profile tùy theo shell bạn dùng)
# để không phải export lại
export GEMINI_API_KEY="YOUR_REAL_API_KEY"
Thực Chiến Vibe Coding: Hồi Sinh Dự Án đã bỏ quên
Sau khi hoàn tất các bước thiết lập, chúng ta sẽ "cook" dự án nào đây? Mình chợt nhớ đến một dự án đã bị "bỏ quên" (abandoned) từ lâu – đây chính là thời điểm thích hợp để khởi động lại nó.
Ý tưởng và những thách thức ban đầu
Sơ lược về ý tưởng của dự án "bỏ quên" này: trước đây, mình dự định xây dựng một ứng dụng đọc PDF (PDF Reader) cá nhân hóa, với các tính năng cơ bản sau:
- Render được PDF trên web – kể cả những cuốn sách dày hàng nghìn trang.
- Hiển thị được các chú thích (annotations) và đánh dấu (highlights).
- Thêm, sửa và xóa được chú thích (sử dụng IndexedDB trên trình duyệt).
- Hỗ trợ Google Translate (một tính năng mà trình đọc PDF mặc định trên Chrome thường thiếu, gây khó chịu khi đọc tài liệu tiếng Anh).
- Tích hợp AI để tóm tắt đoạn văn hoặc trang hiện tại.
Sau khi không tìm thấy ứng dụng đọc PDF nào trên mạng đáp ứng đủ yêu cầu, mình đã quyết định tự xây dựng "từ đầu" (from the ground up) bằng pdf.js, và nó không đơn giản chút nào. Sau một buổi tối mày mò, mình cũng đã render một trang PDF lên giao diện (có hỗ trợ text-layer chuẩn chỉnh).
Cách hoạt động của pdf.js là nó sẽ đọc tệp PDF của bạn, sau đó trả về một đối tượng PDFPageProxy. Nhiệm vụ của bạn là render PDFPageProxy này vào một phần tử canvas. Một câu hỏi đặt ra là: làm thế nào để có thể chọn (bôi đen) văn bản trong canvas? Thông thường, bạn không thể làm điều này trực tiếp. pdf.js giải quyết vấn đề này bằng cách render một div được gọi là TextLayer, phủ lên trên (overlay) canvas và đặt thuộc tính opacity của TextLayer là 0. Bạn sẽ cần tự mình thiết lập phần này.
Render được một trang đã khó, vậy với cuốn sách 500 đến vài nghìn trang thì phải xử lý thế nào? Tất nhiên, chúng ta sẽ không render tất cả các trang cùng một lúc. Thay vào đó, chỉ render khoảng 5-10 trang xung quanh trang hiện tại. Khi người dùng cuộn đến đâu, ứng dụng sẽ tải các trang tương ứng – đảm bảo DOM luôn chỉ chứa 5-10 trang. Ví dụ, nếu bạn cuộn đến trang 95 và chỉ định chỉ tải 10 trang, các trang được hiển thị sẽ là từ 90 đến 100. Kỹ thuật này được gọi là Virtual Scroll, thường bị nhầm lẫn với Lazy-loading. Cần lưu ý rằng đây là hai khái niệm khác nhau: Lazy-loading tập trung vào việc khi nào tải dữ liệu (tải khi người dùng cuộn đến), trong khi Virtual Scroll quan tâm đến số lượng phần tử được hiển thị cùng một lúc trên DOM. Ứng dụng PDF Reader của mình sẽ kết hợp cả hai kỹ thuật này, và mình đã sử dụng thư viện @tanstack/react-virtual cho việc này.
Từ bỏ và trở lại nhờ AI
Sau hơn một tuần loay hoay, ứng dụng của mình cũng đã có một vài tính năng cơ bản: render được tệp PDF và hiển thị được các chú thích cũng như đánh dấu có sẵn trong tệp. Tuy nhiên, đến giai đoạn này, mình cảm thấy nản v~ và thế là dự án đắp chiếu từ đó.
Gần đây, khi bắt đầu tích hợp AI vào Neovim để thử nghiệm "vibe-coding", mình nhớ đến dự án cũ này và nhận thấy đây là cơ hội tốt để áp dụng AI. Kết quả thực sự rất ấn tượng: mình chỉ mất khoảng 2 ngày để hoàn thiện các tính năng còn lại. Điều đáng nói là phần lớn công việc chỉ là đưa ra vài câu lệnh (prompt) cho AI, thay vì phải "cày cuốc" (try-hard coding) như khi dev các tính năng trước đó.
Dưới đây là hình ảnh ứng dụng sau khi hoàn thiện:
My PDF Reader
Vibe coding My PDF Reader
Suy Ngẫm về Vibe Coding: Được và Mất
AI: Công cụ đắc lực nhưng không phải là tất cả
Không thể phủ nhận sự đóng góp to lớn của AI trong trường hợp này. Tuy nhiên, cần làm rõ rằng mình không "vibe-coding" 100% ứng dụng PDF Reader này. Thực tế, mình đã hoàn thành khoảng 50% dự án, bao gồm những phần phức tạp nhất như tương tác với pdf.js, tải và hiển thị chú thích hay các liên kết trong tệp PDF. AI đã tiếp tục phát triển phần còn lại dựa trên source code đó.
Mình không chắc sẽ mất bao lâu nếu "vibe-coding" toàn bộ cái app từ đầu. Có lẽ mình cũng sẽ cảm thấy nản nếu liên tục phải điều chỉnh prompt mà AI vẫn không thực hiện đúng ý, đặc biệt khi sử dụng một mô hình có khả năng suy luận sâu như Gemini 2.5 Pro, nó có bước "thinking" trước khi phản hồi và update source code nên đợi khá lâu. Dù vậy, chất lượng đầu ra của nó khá tốt, và mình ít khi gặp lỗi sau khi nó update code. Nếu có, thường chỉ là vấn đề về giao diện người dùng (UI) không hoàn toàn như ý và mình cần prompt thêm để điều chỉnh.
Khi "lười code" trở thành một khả năng?
Mình cũng đã áp dụng phương pháp này vào một vài dự án khác, và sau một thời gian sử dụng... đúng là mình cảm thấy mình có xu hướng "lười" code hơn. Khi chỉ với vài câu lệnh, AI có thể tạo ra hàng trăm, thậm chí hàng nghìn dòng code – một khối lượng công việc mà nếu tự làm có thể mất cả ngày hoặc hơn – việc người dùng trở nên lười code hơn là điều dễ hiểu. Nó giống như việc bạn có thể ngồi lên xe máy và vít ga vèo cái đi vài km thì việc đi bộ có ý nghĩa gì ở đây nếu mục đích cuối cùng của bạn cũng chỉ là đến cũng một vị trí đó.
Dev như mình liệu có bị "cooked"
Nếu AI có thể mang lại kết quả tốt như vậy, liệu vai trò của lập trình viên (dev) có còn cần thiết? Chúng ta đã nói nhiều về AI, nhưng đừng quên người điều khiển AI – chính là chúng ta. Mình là người hướng dẫn AI từng bước, chỉ định công nghệ và kiến trúc (tech stack) mà nó sẽ sử dụng.
Giả sử mình không phải là dev, làm thế nào mình có thể điều khiển AI một cách hiệu quả? Nếu chỉ đơn thuần "chat" với AI, rất có thể nó sẽ sử dụng những thư viện đã lỗi thời hoặc những công nghệ mà nó được huấn luyện nhiều nhất, thay vì lựa chọn giải pháp tối ưu cho ứng dụng. Hơn nữa, dù các mô hình AI hiện tại ít mắc lỗi hơn trước, chúng không hoàn hảo. Hầu hết các công cụ AI đều có cảnh báo rằng "AI có thể mắc lỗi, hãy kiểm tra kỹ hoặc sử dụng như một tài liệu tham khảo." Khi xảy ra lỗi hoặc bug, nếu không có kiến thức về lập trình, bạn sẽ xử lý ra sao? Liệu AI Agent có thể tự sửa lỗi hoàn toàn? Trải nghiệm cá nhân của mình cho thấy, đôi khi nhấn nút "sửa lỗi" ba lần mà vấn đề vẫn còn đó. Nguyên nhân có thể do thư viện đã thay đổi API sau thời điểm mô hình AI được huấn luyện, khiến nó không nhận biết được sự thay đổi này.
Lời khuyên từ trải nghiệm cá nhân
Dưới đây là một vài lời khuyên bạn có thể tham khảo:
- Nếu mục tiêu của bạn là học hỏi kiến thức lập trình mới, hãy hạn chế việc để AI tạo mã nguồn thay bạn.
- Nếu bạn đã nắm vững cách xây dựng một tính năng cụ thể, việc sử dụng AI để tiết kiệm thời gian là hoàn toàn hợp lý.
- Kiến thức thực sự được củng cố khi bạn đối mặt với vấn đề và tự mình tìm ra giải pháp. Nếu giao hoàn toàn bước này cho AI, bạn có thể sẽ không học được nhiều, hoặc kiến thức đó sẽ nhanh chóng bị lãng quên vì thiếu sự trải nghiệm và ghi nhớ sâu sắc.
Lời kết
"Vibe-coding" và các công cụ AI hỗ trợ lập trình chắc chắn đang mở ra những chân trời mới, giúp chúng ta tăng tốc độ phát triển và tập trung vào các khía cạnh sáng tạo hơn của dự án. Tuy nhiên, vai trò của lập trình viên trong việc định hướng, kiểm soát và tinh chỉnh kết quả vẫn vô cùng quan trọng. Hãy xem AI như một người đồng hành mạnh mẽ, chứ không phải là một sự thay thế hoàn toàn cho tư duy và kỹ năng của con người.
Tuyên bố giao phó 1 phần trách nhiệm cho AI =))
Và bài viết này có sự biên tập của AI, nhưng mà cũng đừng phủ nhận công sức mình ở đây nhé, mình viết hết cả bài rồi xong nhờ con AI nó biên tập lại cho câu từ chuyên nghiệp hơn thôi. Cũng giống như trong coding mình nhờ AI refactor lại code nhiều hơn nhờ nó generate code mới cho mình.