Chọn tech stack cho vibe coding: Tư duy kiến trúc giải pháp

Bạn muốn làm một trading terminal cá nhân. Trong đầu đã có bảng giá, biểu đồ nến, danh mục theo dõi, bộ lọc cổ phiếu và vài chỉ báo tự tính. Bạn mở coding agent rồi gõ: “Hãy xây cho tôi ứng dụng này.”
AI lập tức hỏi lại: dùng Python hay TypeScript, Streamlit hay Next.js, lưu Firebase hay PostgreSQL, chạy trên máy hay đưa lên cloud?
Đây không phải những câu hỏi phụ. Chúng quyết định sản phẩm sẽ được làm trong vài ngày hay kéo dài vài tháng; dễ sửa hay phải đập đi làm lại; có chi phí vận hành dễ dự đoán hay phát sinh một chuỗi dịch vụ khó kiểm soát.
Qua nhiều lần làm thư viện Python, dashboard dữ liệu, website, ứng dụng desktop, công cụ dòng lệnh và thử nghiệm trên mobile, mình rút ra một điều: AI làm giảm rất nhiều công sức viết code, nhưng không thay mình quyết định nên xây thứ gì, theo cách nào và chấp nhận đánh đổi điều gì.
Naming convention, coding convention và Git giúp dự án có trật tự sau khi đã bắt đầu viết code. Trước những phần đó còn một quyết định quan trọng hơn: kiến trúc giải pháp và tech stack.
Tóm tắt nhanh
Nếu chỉ cần nhớ một ý trong bài, hãy nhớ thứ tự này:
Chọn trải nghiệm cần tạo → làm rõ dữ liệu và quy trình → xác định giới hạn → chọn kiến trúc → cuối cùng mới chọn công nghệ.
Thứ tự quyết định trong kiến trúc giải pháp: chọn công nghệ ở bước cuối cùng thay vì bắt đầu bằng ngôn ngữ
Một số lựa chọn mình thường ưu tiên:
| Nhu cầu | Điểm bắt đầu thường hợp lý |
|---|---|
| Dashboard phân tích cá nhân | Python + Streamlit |
| Biểu đồ Python đơn giản | vnstock_chart hoặc Matplotlib |
| Biểu đồ tương tác và tùy biến | Pyecharts hoặc một thư viện dựa trên ECharts, TradingView Advanced Chart cho trải nghiệm đồ thị kỹ thuật hoàn chỉnh |
| Website có nhiều màn hình, tài khoản và luồng sử dụng | Node.js + Next.js |
| Ứng dụng mobile chạy trên iOS và Android | React Native, thường bắt đầu cùng Expo |
| Ứng dụng desktop cần gọn và kiểm soát tốt lớp hệ thống | Rust ở lõi, có thể kết hợp Tauri cho giao diện |
| Trải nghiệm terminal có cấu trúc | TUI bằng Rust |
| Công cụ cho data science | Python làm giao diện sử dụng; Rust xử lý phần lõi cần hiệu năng |
| Thử nghiệm dữ liệu nhỏ trên một máy | SQLite, DuckDB hoặc file Parquet tùy cách truy vấn |
| Ứng dụng cần backend dựng nhanh | Firestore, Supabase hoặc MongoDB tùy mô hình dữ liệu |
| Dữ liệu quan hệ và hệ thống đã vận hành ổn định | PostgreSQL, có thể dùng dịch vụ quản lý hoặc tự vận hành |
| Dịch vụ cần tối ưu chi phí hạ tầng và có người tự quản trị | VPS |
Đây không phải bảng đáp án. Mỗi lựa chọn đều có điều kiện đi kèm. Phần còn lại của bài giải thích cách tìm ra điều kiện đó.
Tech stack và kiến trúc giải pháp khác nhau thế nào?
Tech stack là tập hợp công nghệ dùng để xây và vận hành sản phẩm: ngôn ngữ lập trình, framework, cơ sở dữ liệu, thư viện giao diện, công cụ kiểm thử và nơi triển khai.
Nếu ví sản phẩm như một căn bếp, tech stack là danh sách thiết bị và vật liệu: bếp, lò, tủ lạnh, dao, thớt và hệ thống điện.
Kiến trúc giải pháp, hay solution architecture, là cách những thành phần đó được sắp xếp để giải quyết đúng nhu cầu. Ai sử dụng? Dữ liệu đi vào từ đâu? Phần nào chạy trên máy người dùng, phần nào chạy trên máy chủ? Nếu mất mạng thì sao? Bí mật được giữ ở đâu? Khi dữ liệu tăng mười lần, khối nào sẽ chịu tải?
Nói đơn giản:
- tech stack trả lời “dùng những gì?”;
- kiến trúc giải pháp trả lời “ghép chúng thế nào, để làm gì và trong giới hạn nào?”.
Một danh sách công nghệ hiện đại chưa tạo thành một giải pháp tốt. Giống như mua đủ thiết bị bếp chuyên nghiệp chưa có nghĩa món ăn sẽ hợp với người dùng.
Đừng bắt đầu bằng câu hỏi “nên dùng ngôn ngữ nào?”
Khi có ý tưởng mới, phản xạ dễ gặp nhất là hỏi AI:
Tôi nên dùng Python, JavaScript hay Rust?
Câu hỏi này đến quá sớm. Trước đó, hãy trả lời năm câu hỏi bình dân hơn.
1. Ai sẽ dùng và dùng ở đâu?
Một dashboard chỉ mình bạn mở trên laptop khác hoàn toàn một website phục vụ nhiều người. Một ứng dụng được mở vài lần mỗi tuần khác một bảng giá cần hoạt động liên tục trong phiên.
Hãy mô tả một buổi sử dụng thật:
- người dùng đang ngồi trước máy tính hay cầm điện thoại;
- họ cần xem nhanh hay cần thao tác chuyên sâu;
- họ có sẵn Python hay chỉ muốn mở đường dẫn;
- một người dùng hay nhiều người cùng lúc;
- dữ liệu có riêng tư hay có thể chia sẻ;
- mất mạng có tiếp tục làm việc được không.
Chỉ riêng câu trả lời này đã loại bỏ rất nhiều lựa chọn không cần thiết.
2. Kết quả quan trọng nhất là gì?
“Làm trading terminal” vẫn còn quá rộng. Bạn cần xác định hành động chính:
- theo dõi bảng giá;
- xem biểu đồ và chỉ báo;
- lọc cổ phiếu theo tiêu chí;
- ghi nhật ký giao dịch;
- chạy nghiên cứu trên dữ liệu lịch sử;
- gửi cảnh báo;
- hay thực hiện lệnh qua tài khoản đã được cấp quyền.
Mỗi hành động tạo ra một kiến trúc khác. Một màn hình nghiên cứu lịch sử có thể chờ vài giây để tính toán. Một bảng theo dõi trong phiên lại cần cập nhật liên tục. Một chức năng gửi yêu cầu tới hệ thống giao dịch còn đòi hỏi xác thực, kiểm tra trạng thái và xử lý lỗi nghiêm ngặt hơn nhiều.
3. Dữ liệu đi qua những bước nào?
Với ứng dụng tài chính, hãy vẽ đường đi của dữ liệu trước khi vẽ giao diện:
Nguồn người dùng được phép truy cập
↓
Kết nối và lấy dữ liệu
↓
Chuẩn hóa tên cột, kiểu dữ liệu và đơn vị
↓
Lưu tạm hoặc lưu lâu dài
↓
Tính toán và kiểm tra
↓
API hoặc lớp phục vụ giao diện
↓
Biểu đồ, bảng và cảnh báoNếu chưa nói được dữ liệu đang ở bước nào, AI rất dễ trộn việc lấy dữ liệu, tính toán và hiển thị vào cùng một file. Bản thử nghiệm có thể chạy, nhưng chỉ cần thay nguồn hoặc thêm màn hình là mọi thứ mắc vào nhau.
Đây cũng là lý do data contract và schema dữ liệu cần được nghĩ tới từ sớm. Giao diện có thể thay, nhưng ý nghĩa của open, close, kỳ báo cáo hay đơn vị tiền không nên thay theo từng màn hình.
4. Bạn đang làm bản thử hay nền móng dài hạn?
Một bản thử nghiệm có nhiệm vụ trả lời: “Ý tưởng này có hữu ích không?” Nó không cần giải quyết trước mọi bài toán của ba năm tới.
Ngược lại, một công cụ đã được dùng hằng ngày cần quan tâm tới sao lưu, cập nhật, phân quyền, theo dõi lỗi và khả năng phục hồi.
Sai lầm phổ biến là xây bản thử như hệ thống ngân hàng: quá nhiều dịch vụ, hàng đợi và lớp trừu tượng trước khi có người dùng. Sai lầm ngược lại là đưa nguyên bản thử vào vận hành lâu dài rồi vá tiếp trên một cấu trúc không có ranh giới.
Kiến trúc tốt không phải kiến trúc lớn. Nó là kiến trúc vừa với giai đoạn hiện tại và còn một đường nâng cấp hợp lý.
5. Bạn sẵn sàng tự vận hành tới đâu?
Chi phí phần mềm không chỉ nằm trên hóa đơn cloud. Nó còn nằm ở thời gian cập nhật hệ điều hành, sao lưu cơ sở dữ liệu, xử lý chứng chỉ, theo dõi dịch vụ và phục hồi khi máy chủ lỗi.
Nếu không muốn làm các việc đó, trả thêm cho nền tảng quản lý có thể rẻ hơn tổng thời gian bị lấy mất. Nếu đã quen Linux, Docker, sao lưu và giám sát, VPS có thể đem lại quyền kiểm soát cùng chi phí tài nguyên dễ dự đoán hơn.
Đừng so VPS và PaaS chỉ bằng giá niêm yết. Hãy cộng cả chi phí vận hành của chính mình.
Chọn theo hình thức sản phẩm trước, chọn framework sau
Một cách ra quyết định dễ áp dụng là xác định “vỏ” của sản phẩm trước. Người dùng sẽ gặp sản phẩm dưới dạng notebook, dashboard, website, mobile app, desktop app hay terminal?
Xác định vỏ sản phẩm và trải nghiệm người dùng trước khi quyết định framework
Dashboard đơn giản: ưu tiên Streamlit
Nếu mục tiêu là biến một quy trình phân tích Python thành giao diện có bộ lọc, bảng và biểu đồ, Streamlit thường là lựa chọn đầu tiên của mình.
Lý do không phải Streamlit làm được mọi loại website. Lý do là nó giữ khoảng cách từ notebook tới ứng dụng rất ngắn. Người làm dữ liệu có thể tiếp tục dùng Pandas, hàm phân tích và biểu đồ Python quen thuộc, rồi thêm lớp giao diện mà chưa cần học toàn bộ frontend. Tài liệu chính thức cũng định vị Streamlit là framework Python để tạo data app và có sẵn cách làm việc với bảng, biểu đồ, kết nối dữ liệu, ứng dụng nhiều trang và xác thực.1
Streamlit phù hợp khi:
- người dùng chính là bạn hoặc một nhóm nhỏ;
- luồng sử dụng xoay quanh nhập tham số, chạy tính toán và xem kết quả;
- tốc độ tạo bản thử quan trọng hơn việc tùy biến từng chi tiết giao diện;
- logic phân tích đã nằm trong Python.
Mình sẽ cân nhắc chuyển sang web stack đầy đủ khi ứng dụng có nhiều loại người dùng, luồng điều hướng phức tạp, yêu cầu giao diện theo nhận diện riêng, cập nhật liên tục hoặc cần kiểm soát chặt cách trình duyệt tải dữ liệu.
Nếu muốn bắt đầu thực hành, bài Streamlit là gì? Tạo app Python phân tích dữ liệu chứng khoán đi sâu hơn vào lựa chọn này.
Biểu đồ trong Python: bắt đầu từ mức tương tác cần thiết
Mình không chọn thư viện biểu đồ vì ảnh demo đẹp nhất. Mình chọn theo cách người dùng cần đọc và thao tác với biểu đồ.
vnstock_chart hoặc Matplotlib cho kết quả tĩnh, dễ kiểm soát
Nếu cần một biểu đồ đưa vào notebook, báo cáo hoặc ảnh chia sẻ, lựa chọn đơn giản thường hiệu quả nhất. vnstock_chart giúp rút ngắn các nhu cầu biểu diễn dữ liệu thị trường quen thuộc; Matplotlib phù hợp khi cần kiểm soát kỹ từng thành phần và làm việc cùng hệ sinh thái Python.
Biểu đồ tĩnh có một ưu điểm hay bị đánh giá thấp: dễ lưu lại làm bằng chứng cho một lần phân tích. Khi cần tái lập kết quả, một hình được tạo từ dữ liệu và cấu hình cố định thường dễ kiểm chứng hơn một màn hình tương tác phụ thuộc trạng thái người dùng.
Pyecharts khi người dùng cần khám phá
Nếu cần rê chuột để xem giá trị, phóng to một giai đoạn, bật tắt chuỗi dữ liệu hoặc kết hợp nhiều lớp thông tin, Pyecharts là lựa chọn mình ưu tiên trong Python. Nó đưa khả năng của Apache ECharts vào cách viết quen thuộc hơn với người dùng Python.
Đánh đổi là biểu đồ tương tác có thêm trạng thái, cấu hình và hành vi phía trình duyệt. Vì vậy, đừng dùng tương tác chỉ để trông hiện đại. Hãy dùng khi thao tác đó giúp người đọc trả lời một câu hỏi mà biểu đồ tĩnh khó trả lời.
Web app: Node.js và Next.js khi trải nghiệm web là sản phẩm chính
Khi sản phẩm cần URL riêng cho từng màn hình, đăng nhập, phân quyền, form, API, nội dung có thể được tìm kiếm và giao diện phản hồi tốt trên nhiều kích thước màn hình, mình thường chọn Node.js cùng Next.js.
Next.js cung cấp sẵn cấu trúc cho routing, lấy dữ liệu, render phía máy chủ hoặc trình duyệt, caching và nhiều nhu cầu phổ biến của ứng dụng web.2 Điều đó giúp AI agent làm việc trong một không gian có convention rõ, thay vì tự ghép nhiều thư viện rời rạc ngay từ đầu.
Nhưng Next.js không phải bước nâng cấp bắt buộc của mọi dashboard. So với Streamlit, bạn sẽ phải quan tâm nhiều hơn tới trạng thái giao diện, ranh giới server–client, API, xác thực, build và triển khai. Hãy nhận lấy độ phức tạp đó khi trải nghiệm web thật sự tạo ra giá trị.
Một terminal phân tích nhiều màn hình có thể dùng cấu trúc như sau:
Trình duyệt
├─ Bảng giá, biểu đồ, bộ lọc
├─ Tài khoản và cấu hình cá nhân
└─ Gửi yêu cầu phân tích
↓
Lớp web và API bằng Next.js
↓
PostgreSQL ── Tác vụ nền ── Lớp phân tích Python
↓
Nguồn dữ liệu người dùng được quyền kết nốiKhông nhất thiết mọi khối phải xuất hiện từ ngày đầu. Sơ đồ chỉ giúp mỗi trách nhiệm có chỗ đứng và có thể tách ra khi nhu cầu thật xuất hiện.
Mobile app: React Native trước, native sau khi có lý do rõ ràng
Nếu cùng một sản phẩm cần chạy trên iOS và Android, mình thường bắt đầu bằng React Native. Nó cho phép chia sẻ phần lớn logic và cách tổ chức giao diện giữa các nền tảng, trong khi thành phần hiển thị vẫn ánh xạ tới giao diện native. Tài liệu React Native khuyến nghị người làm ứng dụng mới bắt đầu với một framework như Expo, đồng thời vẫn cho phép viết phần native khi cần.3
Điều cần nói chính xác là một codebase không có nghĩa mọi dòng code đều dùng chung. Camera, thông báo, thanh toán, quyền hệ điều hành và các chi tiết giao diện vẫn có thể cần xử lý riêng cho iOS hoặc Android.
Mình chỉ ưu tiên Swift cho iOS hoặc Kotlin cho Android ngay từ đầu khi:
- trải nghiệm phụ thuộc sâu vào khả năng riêng của hệ điều hành;
- hiệu năng giao diện và cảm giác native là lợi thế cạnh tranh chính;
- sản phẩm chỉ tập trung một nền tảng;
- hoặc dự án đã đủ lớn để duy trì đội ngũ riêng cho từng hệ điều hành.
Đây là quyết định về chi phí duy trì, không phải cuộc thi xem ngôn ngữ nào “xịn” hơn.
Desktop app: Rust ở lõi, nhưng không nhất thiết viết mọi pixel bằng Rust
Với desktop app, lựa chọn của mình nghiêng về Rust thay vì đóng gói toàn bộ trình duyệt bằng Electron khi sản phẩm cần gọn, kiểm soát tốt tài nguyên và làm việc sâu hơn với hệ điều hành.
Trong thực tế, một hướng cân bằng là Tauri: giao diện vẫn có thể dùng công nghệ web quen thuộc, còn lớp ứng dụng và tác vụ hệ thống dùng Rust. Tauri tận dụng webview có sẵn của hệ điều hành thay vì đóng gói một browser engine riêng, nên ứng dụng tối thiểu có thể nhỏ hơn đáng kể.4
Electron vẫn hợp lý nếu:
- đội ngũ đã rất mạnh JavaScript và cần ra sản phẩm nhanh;
- phụ thuộc vào thư viện chỉ có trong hệ sinh thái web;
- kích thước gói và mức dùng bộ nhớ không phải ưu tiên lớn;
- lợi ích từ một runtime đồng nhất quan trọng hơn việc bám vào webview của từng hệ điều hành.
Nói “desktop dùng Rust” vì vậy chưa đủ. Câu đầy đủ nên là: dùng Rust cho phần cần hiệu năng, an toàn bộ nhớ hoặc quyền hệ thống; chọn lớp giao diện theo năng lực đội ngũ và trải nghiệm cần tạo.
Terminal app: TUI phù hợp khi bàn phím là cách làm việc chính
TUI là giao diện chạy trong terminal nhưng có bố cục, bảng, menu và phím tắt, thay vì chỉ in từng dòng chữ. Với người thường xuyên làm việc qua SSH, quản lý máy chủ hoặc theo dõi tác vụ, TUI có thể nhanh và tập trung hơn giao diện web.
Mình ưu tiên Rust cho TUI khi công cụ cần chạy lâu, phản hồi nhanh, phân phối thành một file thực thi và kiểm soát tốt tài nguyên. Hệ sinh thái như Ratatui cung cấp các khối để dựng bảng, biểu đồ và bố cục terminal.
Nếu chỉ cần một công cụ nội bộ nhỏ và toàn bộ logic đã ở Python, chuyển sang Rust ngay có thể làm chậm việc thử nghiệm. Python cùng Textual hoặc một CLI có cấu trúc đôi khi là điểm bắt đầu hợp lý hơn. Hãy chọn Rust khi lợi ích vận hành đã rõ, không phải chỉ vì TUI bằng Rust nghe có vẻ đúng bài.
Python ở lớp ngoài, Rust ở phần lõi
Python có lợi thế rất lớn trong tài chính và data science: cách viết dễ tiếp cận, notebook quen thuộc, thư viện phân tích phong phú và cộng đồng rộng. Vì vậy, với công cụ dành cho người phân tích, mình muốn giao diện sử dụng vẫn là Python.
Rust phù hợp với phần lõi khi có một trong các nhu cầu:
- phép tính lặp lại nhiều và đã đo được là điểm nghẽn;
- xử lý song song hoặc quản lý bộ nhớ cần chặt chẽ;
- muốn phân phối phần lõi dưới dạng mã đã biên dịch;
- cần tái sử dụng cùng logic trong Python, desktop hoặc dịch vụ nền.
Các công cụ như PyO3 cho phép viết module native bằng Rust rồi gọi từ Python.5 Cách ghép này giữ trải nghiệm quen thuộc ở bên ngoài và đưa tối ưu xuống phần người dùng không cần chạm tới.
Tuy nhiên, biên dịch không tự động biến code thành bí mật tuyệt đối. Mã máy vẫn có thể bị phân tích. Rust cũng không tự làm mọi hàm nhanh hơn Python. Chỉ nên đưa một phần xuống Rust sau khi đã đo, xác định đúng điểm nghẽn và chấp nhận thêm độ phức tạp của quá trình build, kiểm thử và phát hành đa nền tảng.
Chọn cơ sở dữ liệu: đừng chỉ nhìn “nhỏ” hay “lớn”
Kích thước dữ liệu là một biến, nhưng chưa đủ để chọn cơ sở dữ liệu. Với ứng dụng tài chính, mình thường xem thêm:
- dữ liệu có nhiều quan hệ và cần
JOINkhông; - cách truy vấn đã ổn định hay còn thay đổi liên tục;
- có cần đẩy thay đổi tới mobile ngay sau khi dữ liệu đổi không;
- dữ liệu chủ yếu được đọc theo thời gian hay theo từng tài khoản;
- có cần giao dịch nhiều bước, ràng buộc và tính nhất quán chặt không;
- người làm dự án muốn tự vận hành hay dùng dịch vụ quản lý.
SQLite, DuckDB và Parquet cho khởi đầu cục bộ
Nếu chỉ một người dùng trên một máy, chưa chắc bạn cần cơ sở dữ liệu cloud.
- SQLite phù hợp với dữ liệu ứng dụng có cấu trúc, cần đọc ghi đơn giản và gói trong một file.
- DuckDB phù hợp với truy vấn phân tích trên dữ liệu dạng bảng, đặc biệt khi làm việc cùng Parquet.
- Parquet phù hợp để lưu dữ liệu bảng theo cột, dễ đưa vào quy trình phân tích và trao đổi giữa nhiều công cụ.
Khởi đầu cục bộ giúp giảm hạ tầng và làm rõ schema trước khi thêm bài toán đồng bộ, tài khoản và phân quyền.
Firestore khi cần dựng nhanh trải nghiệm web hoặc mobile
Cloud Firestore là cơ sở dữ liệu NoSQL dạng tài liệu, hỗ trợ SDK cho web, mobile và server, cơ chế lắng nghe thay đổi cùng chế độ offline trên mobile/web.6 Nó phù hợp khi dữ liệu tự nhiên đi theo document, ứng dụng cần đồng bộ client nhanh và bạn muốn giảm phần backend phải tự dựng.
Điểm cần cân nhắc là cách truy vấn, chỉ mục, quy tắc bảo mật và chi phí theo lượt đọc ghi. Dữ liệu báo cáo tài chính có nhiều quan hệ hoặc các truy vấn phân tích thay đổi liên tục có thể không tự nhiên với mô hình document.
MongoDB khi dữ liệu dạng tài liệu là lựa chọn có chủ đích
MongoDB cũng không phải “database dùng thử rồi bỏ khi lớn”. Nó có thể vận hành ở quy mô lớn. Lý do chọn nên là mô hình document linh hoạt phù hợp với dữ liệu và cách truy cập, không phải vì dự án chưa nghiêm túc.
Với dữ liệu thị trường có schema rõ, cần nối nhiều bảng và kiểm soát ràng buộc, mình thường thấy cơ sở dữ liệu quan hệ dễ lý giải hơn. Với hồ sơ hoặc nội dung có cấu trúc thay đổi nhiều và thường được đọc nguyên cụm, document database có thể tự nhiên hơn.
Supabase là PostgreSQL được đóng gói dễ bắt đầu hơn
Supabase cung cấp một PostgreSQL đầy đủ, kèm xác thực, lưu trữ, API, cơ chế thông báo thay đổi dữ liệu và giao diện quản trị.7 Vì vậy, không nên nói “bắt đầu bằng Supabase, lớn lên thì chuyển sang PostgreSQL” như hai loại cơ sở dữ liệu khác nhau.
Đường phát triển đúng hơn là:
Supabase quản lý PostgreSQL cho bạn
↓ khi có lý do vận hành rõ ràng
PostgreSQL do dịch vụ khác quản lý hoặc tự chạy trên hạ tầng riêngSchema và SQL có thể giữ phần lớn, nhưng xác thực, lưu trữ file, cơ chế đồng bộ, function và chính sách truy cập vẫn cần kế hoạch chuyển đổi riêng.
PostgreSQL khi quan hệ và tính nhất quán trở thành trung tâm
Mình ưu tiên PostgreSQL cho hệ thống đã có mô hình dữ liệu rõ, nhiều quan hệ, cần transaction, ràng buộc, migration và truy vấn phân tích đáng tin cậy. Đây thường là hướng phù hợp cho tài khoản, danh mục, cấu hình, nhật ký và metadata của một ứng dụng tài chính.
PostgreSQL không loại bỏ nhu cầu lưu file. Dữ liệu lịch sử dung lượng lớn có thể nằm trong object storage hoặc Parquet; PostgreSQL giữ metadata, quyền, trạng thái và phần dữ liệu cần truy vấn giao dịch. Kiến trúc tốt không bắt một công cụ làm mọi việc.
Hosting: VPS hay PaaS là lựa chọn về trách nhiệm
PaaS là nền tảng lo giúp phần lớn việc build, chạy, cấp chứng chỉ và mở rộng ứng dụng. VPS là một máy chủ ảo mà bạn có nhiều quyền kiểm soát hơn, đồng nghĩa phải tự chịu nhiều trách nhiệm hơn.
| Tiêu chí | PaaS | VPS |
|---|---|---|
| Bắt đầu | Nhanh, ít cấu hình hệ thống | Cần biết Linux, mạng và cách triển khai |
| Chi phí ban đầu | Có thể thấp hoặc miễn phí cho thử nghiệm | Thường trả theo máy chủ cố định |
| Chi phí khi dùng nhiều | Có thể tăng theo tài nguyên và dịch vụ | Dễ dự đoán hơn nếu tải ổn định |
| Vận hành | Nền tảng xử lý nhiều phần | Bạn chịu trách nhiệm cập nhật, sao lưu, giám sát |
| Kiểm soát | Theo giới hạn của nền tảng | Linh hoạt hơn về tiến trình, lưu trữ và mạng |
| Khả năng chuyển đi | Tùy mức phụ thuộc tính năng riêng | Thường dễ mang container và dữ liệu sang máy khác hơn |
Mình thường chọn VPS khi ứng dụng đã có tải tương đối dễ đoán, cần chạy nhiều dịch vụ cùng máy và có khả năng tự vận hành. Với bản thử, một PaaS giúp đưa sản phẩm tới người dùng sớm có thể là lựa chọn tốt hơn, dù giá tài nguyên nhìn riêng lẻ cao hơn.
Tiết kiệm 10 đô la tiền máy chủ nhưng mất hai ngày mỗi tháng để chữa deploy không phải là tối ưu chi phí.
Sáu mẫu giải pháp để bắt đầu trao đổi với AI
Các mẫu dưới đây là điểm xuất phát, không phải bản thiết kế hoàn chỉnh.
Mẫu 1: Dashboard phân tích cá nhân
Python
├─ Kết nối và chuẩn hóa dữ liệu
├─ Pandas hoặc Polars cho xử lý
├─ vnstock_chart / Matplotlib / Pyecharts
└─ Streamlit cho giao diện
Lưu trữ: Parquet, DuckDB hoặc SQLite
Triển khai: chạy trên máy cá nhân; chỉ đưa lên server khi cần chia sẻĐây là mẫu mình ưu tiên để kiểm tra một quy trình phân tích có thực sự hữu ích trước khi xây sản phẩm lớn hơn.
Mẫu 2: Trading terminal cá nhân trên web
Next.js + TypeScript
├─ Giao diện bảng, biểu đồ và bộ lọc
├─ API cho cấu hình và truy vấn
└─ Xác thực người dùng
Python service
└─ Phân tích dữ liệu và tác vụ định lượng
PostgreSQL
└─ Tài khoản, watchlist, cấu hình và nhật ký
Parquet / object storage
└─ Dữ liệu lịch sử dung lượng lớnNếu chỉ có một người dùng và chưa cần truy cập từ nhiều máy, mẫu này có thể là quá nhiều. Hãy bắt đầu bằng Streamlit hoặc desktop trước.
Mẫu 3: Mobile companion cho danh mục theo dõi
React Native + Expo
├─ iOS
└─ Android
Backend API
├─ Tài khoản và watchlist
├─ Đồng bộ cấu hình
└─ Gửi thông báo
PostgreSQL hoặc Firestore
└─ Chọn theo quan hệ dữ liệu và nhu cầu đồng bộ ngay khi có thay đổiMobile app không nên trực tiếp giữ khóa dịch vụ quan trọng hoặc thực hiện logic nhạy cảm mà không có lớp bảo vệ phù hợp.
Mẫu 4: Desktop app gọn, chạy đa nền tảng
Tauri
├─ Frontend bằng React, Vue hoặc framework web quen thuộc
└─ Rust cho file, tiến trình, cập nhật và tác vụ hệ thống
SQLite / DuckDB
└─ Dữ liệu và cấu hình cục bộNếu toàn bộ công cụ vốn đã là Python và chỉ cần đóng gói nhanh cho một nhóm nhỏ, một giải pháp đóng gói Python có thể ít công sức hơn. Rust chỉ đáng thêm vào khi lợi ích vận hành đủ rõ.
Mẫu 5: Thư viện phân tích Python cần tăng tốc
Python API
├─ Cú pháp quen thuộc
├─ DataFrame và notebook
└─ Validation, tài liệu, thông báo lỗi
Rust core
├─ Vòng lặp tính toán nặng
├─ Xử lý song song
└─ Thành phần cần biên dịch
PyO3 / maturin
└─ Cầu nối và quá trình đóng góiĐừng chuyển cả dự án sang Rust. Đo trước, tách đúng điểm nghẽn, giữ Python cho lớp mà người phân tích trực tiếp sử dụng.
Mẫu 6: TUI theo dõi tác vụ và dữ liệu
Rust + Ratatui
├─ Bảng trạng thái
├─ Nhật ký cập nhật liên tục
├─ Phím tắt
└─ Cấu hình tác vụ
SQLite hoặc file cấu hình
└─ Trạng thái cục bộTUI phù hợp cho người vận hành quen terminal. Nó không phải lựa chọn tốt nếu sản phẩm cần tiếp cận người dùng đại chúng hoặc phụ thuộc mạnh vào biểu đồ phức tạp.
Cách dùng AI để thiết kế giải pháp thay vì xin một đáp án
AI hữu ích nhất khi được yêu cầu so sánh và phản biện, không phải khi được hỏi “stack tốt nhất là gì?”.
Bạn có thể bắt đầu bằng một bản mô tả như sau:
## Mục tiêu
Tôi muốn làm dashboard theo dõi danh mục và nghiên cứu cổ phiếu cho cá nhân.
## Người dùng
- Một người trong giai đoạn đầu.
- Dùng trên laptop, thỉnh thoảng mở bằng điện thoại.
## Công việc chính
- Chọn mã và khoảng thời gian.
- Xem biểu đồ giá, chỉ báo và bảng tài chính.
- Lưu watchlist và cấu hình bộ lọc.
## Dữ liệu
- Lấy qua quyền truy cập của chính người dùng.
- Dữ liệu lịch sử cập nhật theo lô; bảng giá cập nhật thường xuyên hơn.
- Cần ghi rõ nguồn và thời điểm truy xuất.
## Giới hạn
- Ưu tiên làm bản dùng được trong hai tuần.
- Một người phát triển cùng AI.
- Muốn giữ chi phí hạ tầng thấp.
- Đã quen Python, chưa giỏi frontend.
## Yêu cầu dành cho AI
1. Đề xuất ba kiến trúc từ đơn giản đến mở rộng.
2. Với mỗi phương án, giải thích điều được, điều mất và dấu hiệu cần nâng cấp.
3. Chỉ ra phần nào chưa đủ thông tin để quyết định.
4. Không viết code trước khi tôi chọn phương án.Yêu cầu cuối cùng rất quan trọng. Nếu AI viết code quá sớm, cuộc trò chuyện sẽ bị kéo theo cấu trúc đầu tiên nó nghĩ ra. Khi đó, bạn dễ dành thời gian sửa code thay vì xem lại bài toán.
Đừng hỏi AI một lần rồi coi đó là kiến trúc
Một quy trình thiết kế cùng AI có thể đi qua bốn vòng:
- Làm rõ nhu cầu: AI hỏi lại các tình huống sử dụng, dữ liệu, giới hạn và tiêu chí thành công.
- Đưa ra phương án: ít nhất hai hoặc ba cách, từ đơn giản tới phức tạp.
- Phản biện: yêu cầu AI đóng vai người vận hành, người bảo mật và người sẽ bảo trì sau sáu tháng để tìm điểm yếu.
- Ghi quyết định: lưu lại lựa chọn, lý do, phương án bị loại và dấu hiệu cần xem xét lại.
Quy trình bốn vòng trao đổi với AI để hoàn thiện kiến trúc giải pháp trước khi viết code
Phần ghi quyết định có thể rất ngắn:
Quyết định: bắt đầu bằng Streamlit và DuckDB.
Lý do: một người dùng, logic đã ở Python, cần kiểm tra quy trình trước.
Chưa chọn Next.js: chi phí giao diện và vận hành chưa tạo thêm giá trị ở giai đoạn này.
Xem xét lại khi: cần nhiều tài khoản, chia sẻ qua web hoặc giao diện mobile trở thành nhu cầu thường xuyên.Sau vài dự án, những ghi chú này trở thành kinh nghiệm thật của bạn. Bạn không chỉ nhớ “lần trước dùng Streamlit”, mà hiểu vì sao nó hợp ở lúc đó và điều gì khiến mình đổi sang giải pháp khác.
Học kiến trúc bằng cách quan sát sản phẩm mình thích
Khi dùng một sản phẩm tốt, mình thường thử hình dung các khối phía sau:
- màn hình nào cần dữ liệu cập nhật liên tục;
- phần nào có thể được tính sẵn;
- dữ liệu nào chỉ nằm trên máy;
- thao tác nào cần máy chủ xác nhận;
- vì sao ứng dụng vẫn dùng được khi mất mạng;
- chức năng nào có thể là một dịch vụ độc lập;
- đâu là chỗ chi phí sẽ tăng khi số người dùng tăng.
Bạn có thể kiểm tra giả thuyết bằng thông tin công khai và những gì sản phẩm cho phép quan sát:
- đọc tài liệu kỹ thuật, bài viết kiến trúc và thông báo tuyển dụng;
- xem ứng dụng web tải những loại tài nguyên nào trong Developer Tools;
- quan sát thời gian phản hồi, hành vi offline và cách đồng bộ;
- xem kích thước app, quyền hệ điều hành và ghi chú phát hành;
- tìm SDK, thư viện hoặc giao thức mà sản phẩm công khai sử dụng.
Mục tiêu không phải “bóc” bí mật của người khác. Không vượt xác thực, quét hạ tầng hoặc thử khai thác một hệ thống khi không được phép. Bài tập này dùng dấu hiệu công khai để luyện khả năng đặt giả thuyết kiến trúc, rồi chấp nhận rằng một phần suy luận có thể sai.
Một câu hỏi hay để nhờ AI hỗ trợ là:
Dựa trên các hành vi tôi quan sát được, hãy đưa ra ba kiến trúc có thể giải thích chúng. Nêu bằng chứng ủng hộ, điểm chưa chắc chắn và cách kiểm tra bằng nguồn công khai.
Đây là cách học tốt hơn việc hỏi “ứng dụng X dùng tech stack gì?” rồi nhận một danh sách công nghệ không có bối cảnh.
Những sai lầm mình muốn tránh khi chọn tech stack
Chọn theo xu hướng thay vì theo công việc
Một framework đang được nhắc nhiều không làm nó phù hợp với một dashboard cá nhân. Công nghệ mới thường có ít ví dụ, ít kinh nghiệm vận hành và AI cũng dễ tạo ra code dựa trên phiên bản cũ hoặc trộn nhiều cách dùng.
Dùng microservices khi một chương trình còn chưa có người dùng
Tách thành nhiều dịch vụ chỉ có ích khi ranh giới trách nhiệm, cách triển khai độc lập hoặc nhu cầu tải đã đủ rõ. Nếu chưa, bạn đang đổi một codebase dễ theo dõi lấy mạng, xác thực giữa dịch vụ, log phân tán và nhiều điểm có thể lỗi.
Nghĩ rằng “sau này chuyển cũng dễ”
Chuyển framework giao diện, cơ sở dữ liệu hay nền tảng hosting hiếm khi chỉ là đổi cấu hình. Dữ liệu, xác thực, tác vụ nền, file, quyền và quy trình deploy đều có thể gắn với lựa chọn cũ.
Không cần tránh mọi phụ thuộc. Chỉ cần biết mình đang phụ thuộc vào đâu và giữ phần logic quan trọng tách khỏi dịch vụ bên ngoài ở mức hợp lý.
Tối ưu hiệu năng trước khi đo
Python thường bị nghi ngờ đầu tiên khi ứng dụng chậm, nhưng nguyên nhân có thể là gọi API lặp lại, tải quá nhiều dữ liệu, truy vấn thiếu chỉ mục hoặc render lại toàn bộ giao diện.
Chuyển sang Rust trước khi đo có thể tạo thêm một hệ thống build phức tạp mà không sửa đúng điểm nghẽn.
Để AI tự thêm dịch vụ
Coding agent có xu hướng giải quyết mỗi nhu cầu bằng một package hoặc dịch vụ mới. Sau vài vòng, dự án có thêm hàng đợi, cache, nền tảng xác thực, dịch vụ email và ba cơ sở dữ liệu dù chưa có nhu cầu vận hành tương ứng.
Hãy yêu cầu AI giải thích trước mỗi phụ thuộc mới:
- vấn đề cụ thể nào đang được giải quyết;
- vì sao code hiện tại không đủ;
- chi phí vận hành và rủi ro khóa vào nền tảng;
- cách gỡ bỏ nếu thử nghiệm không thành công.
Một bảng chấm điểm đơn giản cho dự án của bạn
Khi còn phân vân giữa hai phương án, hãy chấm từ 1 đến 5 theo các tiêu chí sau:
| Tiêu chí | Câu hỏi cần trả lời |
|---|---|
| Tốc độ tạo bản dùng được | Bao lâu người dùng đầu tiên có thể thử? |
| Độ quen thuộc | Bạn và AI có đủ tài liệu, ví dụ và khả năng kiểm chứng không? |
| Phù hợp trải nghiệm | Công nghệ có phục vụ đúng web, mobile, desktop hay terminal không? |
| Phù hợp dữ liệu | Mô hình lưu trữ và truy vấn có tự nhiên không? |
| Chi phí vận hành | Ai cập nhật, sao lưu, giám sát và xử lý sự cố? |
| Khả năng kiểm thử | Có thể kiểm chứng logic và dữ liệu độc lập với giao diện không? |
| Đường nâng cấp | Dấu hiệu nào khiến kiến trúc cần thay đổi? |
| Khả năng rút lui | Có xuất dữ liệu và thay một thành phần mà không viết lại mọi thứ không? |
Không cộng điểm một cách máy móc rồi chọn số cao nhất. Bảng này buộc những đánh đổi vốn mơ hồ phải được viết ra. Có dự án ưu tiên tốc độ thử nghiệm; có dự án ưu tiên dữ liệu riêng tư hoặc khả năng chạy offline. Trọng số nằm ở mục tiêu, không nằm trong framework.
Từ kiến trúc tới code: thứ tự của chuỗi know-how
Khi kiến trúc đã được chọn, những chủ đề trước đó mới nối lại thành một quy trình hoàn chỉnh:
- Kiến trúc giải pháp: sản phẩm gồm những khối nào và trách nhiệm của từng khối.
- Tech stack: công nghệ nào phù hợp để dựng mỗi khối.
- Data contract và schema: dữ liệu đi qua các khối theo cấu trúc và ý nghĩa nào.
- Naming convention: toàn dự án dùng cùng một từ vựng.
- Coding convention: code được tổ chức, kiểm tra và bàn giao ra sao.
- Git: thay đổi được chia, review, lưu dấu và phục hồi thế nào.
AI có thể hỗ trợ ở mọi tầng. Nhưng nếu tầng trên chưa rõ, nó sẽ tự đưa ra giả định rồi viết hàng nghìn dòng code theo giả định đó. Công việc của vibe coder không còn chỉ là mô tả giao diện. Công việc quan trọng hơn là quản lý các quyết định.
Điều cần nhớ
Solution architect nghe như một chức danh cao siêu, nhưng phần tư duy nền tảng rất gần với đời thường: hiểu mình đang giải quyết việc gì, chia nó thành các khối, chọn công cụ vừa đủ và biết trước điều gì sẽ khiến lựa chọn phải thay đổi.
Bạn không cần trở thành kiến trúc sư phần mềm trước khi làm ứng dụng đầu tiên. Hãy bắt đầu bằng một dự án nhỏ, ghi lại lý do chọn stack, nhờ AI đưa ra phương án đối lập và xem lại quyết định sau khi đã vận hành thật.
Qua vài vòng như vậy, bạn sẽ dần nhìn một dashboard và hình dung được lớp dữ liệu, tính toán, API, giao diện và hạ tầng phía sau. Quan trọng hơn, bạn sẽ biết phần nào mình thực sự hiểu và phần nào chỉ đang đoán.
Tech stack tốt không phải tech stack có nhiều công nghệ nhất. Đó là tập hợp công cụ nhỏ nhất giúp bạn tạo đúng trải nghiệm, kiểm chứng được kết quả và còn đủ sức duy trì sản phẩm sau khi cảm giác hào hứng ban đầu đã qua.
Nội dung phục vụ học tập, nghiên cứu và tham khảo. Các lựa chọn công nghệ trong bài phản ánh kinh nghiệm và ưu tiên của tác giả, không phải đáp án duy nhất cho mọi dự án. Phiên bản, mức giá và khả năng của từng nền tảng có thể thay đổi; hãy kiểm tra tài liệu hiện hành trước khi triển khai.
Footnotes
-
Streamlit Docs, Streamlit documentation. ↩
-
Next.js, About React and Next.js. ↩
-
React Native, Create native apps for Android, iOS, and more using React. ↩
-
Tauri, What is Tauri?. ↩
-
PyO3, The PyO3 user guide. ↩
-
Firebase, Cloud Firestore documentation. ↩
-
Supabase Docs, Database overview. ↩
