Một codebase do AI tạo cho Web, Mobile và API
Xem cách một codebase duy nhất do AI tạo có thể cung cấp cho ứng dụng web, mobile và API bằng logic chia sẻ, mô hình dữ liệu nhất quán và phát hành an toàn hơn.

Một codebase do AI tạo nghĩa là gì
“Một codebase” hiếm khi có nghĩa là một UI chạy ở mọi nơi. Trên thực tế, nó thường có nghĩa là một repository và một tập quy tắc chia sẻ—với các bề mặt phân phối riêng (web app, mobile app, API) đều phụ thuộc vào cùng các quyết định nghiệp vụ cơ bản.
Logic chia sẻ vs. UI chia sẻ
Một mô hình tư duy hữu ích là chia sẻ những phần không bao giờ được mâu thuẫn:
- Luật domain: các phép tính, kiểm tra điều kiện, giá cả, luồng công việc, các bất biến.
- Use case: “tạo đơn hàng,” “huỷ đăng ký,” “hoàn tiền,” v.v.
- Hợp đồng dữ liệu: dạng request/response, quy tắc xác thực, mã lỗi.
Trong khi đó, bạn thường không chia sẻ toàn bộ lớp UI. Web và mobile có mẫu điều hướng, kỳ vọng về truy cập (accessibility), giới hạn hiệu năng và khả năng nền tảng khác nhau. Chia sẻ UI có thể có lợi trong một vài trường hợp, nhưng đó không phải là định nghĩa của “một codebase.”
AI thay đổi điều gì (và điều gì không thay đổi)
Mã do AI tạo có thể tăng tốc đáng kể:
- khởi tạo project (thư mục, script build, component cơ bản)
- sinh endpoint CRUD và client
- tạo test và fixture từ ví dụ
Nhưng AI không tự sản sinh ra kiến trúc mạch lạc. Nếu không có ranh giới rõ ràng, nó có xu hướng nhân bản logic giữa các app, trộn concerns (UI gọi trực tiếp mã database), và tạo các xác thực “gần giống” ở nhiều nơi. Hiệu quả thực sự đến từ việc định nghĩa cấu trúc trước—rồi dùng AI để lấp đầy phần lặp lại.
Kết quả cần hướng tới
Một codebase hỗ trợ bởi AI thành công khi nó mang lại:
- Nhất quán: web, mobile và API thực thi cùng một tập quy tắc.
- Tốc độ: tính năng mới được triển khai một lần và xuất hiện ở mọi nơi.
- Dễ bảo trì: thay đổi được cô lập, review, test và phát hành có thể dự đoán.
Mục tiêu và ràng buộc cho việc phân phối Web, Mobile và API
Một codebase duy nhất chỉ hoạt động khi bạn rõ ràng về những gì nó phải đạt được—và những gì không nên chuẩn hoá. Web, mobile và API phục vụ các khán giả và mẫu sử dụng khác nhau, ngay cả khi chia sẻ cùng luật nghiệp vụ.
Đối tượng bạn phục vụ (và cách phục vụ)
Hầu hết sản phẩm có ít nhất ba “cửa vào”:
- Người dùng web (khách hàng, admin, đội hỗ trợ) mong đợi điều hướng nhanh, khả năng truy cập tốt và cập nhật dễ dàng.
- Người dùng mobile mong trải nghiệm gần gũi với native, hỗ trợ kết nối gián đoạn và tiết kiệm pin/điều kiện mạng.
- Tích hợp bên thứ ba (đối tác, hệ thống nội bộ, công cụ tự động) cần API ổn định, hợp đồng rõ ràng và xử lý lỗi dự đoán được.
Mục tiêu là sự nhất quán về hành vi (luật, quyền, phép tính)—không phải trải nghiệm giống hệt.
Không phải mục tiêu: đừng ép UX giống nhau
Một lỗi phổ biến là coi “một codebase” là “một UI.” Điều đó thường sinh ra app web như mobile hoặc mobile như web—cả hai đều gây khó chịu.
Thay vào đó, hướng tới:
- Chia sẻ logic domain và xác thực
- Chia sẻ mô hình dữ liệu và hợp đồng API
- Thiết kế trình bày và tương tác riêng theo nền tảng
Những ràng buộc cần thiết kế sớm
Chế độ ngoại tuyến: Mobile thường cần truy cập đọc (và đôi khi ghi) khi mất mạng. Điều đó nghĩa là lưu trữ cục bộ, chiến lược sync, xử lý xung đột và quy tắc “nguồn chân lý” rõ ràng.
Hiệu năng: Web quan tâm đến kích thước bundle và thời gian tương tác; mobile quan tâm đến thời gian khởi động và hiệu quả mạng; API quan tâm độ trễ và throughput. Chia sẻ mã không có nghĩa là gửi các module không cần thiết tới mọi client.
Bảo mật và tuân thủ: Authentication, authorization, audit trail, mã hoá và lưu trữ dữ liệu phải nhất quán trên mọi bề mặt. Nếu bạn hoạt động trong không gian có quy định, tích hợp yêu cầu như logging, consent và quyền ít nhất ngay từ đầu—không phải như vá lỗi sau này.
Kiến trúc tham chiếu: các lớp và trách nhiệm
Một codebase duy nhất hoạt động tốt nhất khi được tổ chức thành các lớp rõ ràng với trách nhiệm nghiêm ngặt. Cấu trúc đó cũng khiến mã do AI tạo dễ review, test và thay thế mà không phá vỡ các phần không liên quan.
Luồng ở mức cao
Đây là hình dạng cơ bản mà hầu hết đội converge:
Clients (Web / Mobile / Partners)
↓
API Layer
↓
Domain Layer
↓
Data Sources (DB / Cache / External APIs)
Ý tưởng chính: giao diện người dùng và chi tiết vận chuyển nằm ở rìa, trong khi luật nghiệp vụ ở trung tâm.
Những gì được chia sẻ
“Lõi có thể chia sẻ” là mọi thứ nên hành xử giống nhau ở mọi nơi:
- Domain (logic nghiệp vụ): quy tắc giá, kiểm tra điều kiện, chuyển trạng thái đơn hàng, vv.
- Xác thực: quy tắc input và thông điệp lỗi ánh xạ tới mã lỗi nhất quán.
- Mạng + schema: kiểu request/response, serialization và test hợp đồng.
Khi AI tạo tính năng mới, kết quả tốt nhất là: nó cập nhật luật domain một lần, và mọi client hưởng lợi tự động.
Những gì nên khác nhau
Một số mã tốn kém (hoặc rủi ro) khi ép vào một abstraction chia sẻ:
- Component UI: hệ design web khác controls native.
- Điều hướng và luồng người dùng: routing trình duyệt khác stack mobile.
- Khả năng thiết bị: push notification, biometric, camera, lưu trữ ngoại tuyến.
Quy tắc thực tế: nếu người dùng có thể thấy nó hoặc OS có thể phá nó, giữ nó riêng cho app. Nếu đó là quyết định nghiệp vụ, giữ nó trong domain.
Trách nhiệm theo lớp
- API layer: authentication, rate limit, ánh xạ HTTP/GraphQL tới domain commands.
- Domain layer: luật thuần khiết và use cases, ít phụ thuộc.
- Data sources: database và dịch vụ bên thứ ba sau interfaces để implementation có thể đổi mà không phải viết lại logic nghiệp vụ.
Lớp domain chia sẻ (Logic nghiệp vụ)
Lớp domain chia sẻ là phần codebase nên cảm thấy “tẻ nhạt” theo nghĩa tốt: có thể dự đoán, dễ test và tái sử dụng ở mọi nơi. Nếu AI hỗ trợ sinh hệ thống, lớp này là nơi neo giữ ý nghĩa dự án—để màn hình web, luồng mobile và endpoint API đều phản ánh cùng một bộ luật.
Bắt đầu với danh từ và động từ
Xác định khái niệm cốt lõi của sản phẩm như entity (thứ có danh tính theo thời gian, như Account, Order, Subscription) và value object (thứ được định nghĩa bởi giá trị, như Money, EmailAddress, DateRange). Rồi nắm bắt hành vi dưới dạng use case (hoặc application services): “Create order,” “Cancel subscription,” “Change email.”
Cấu trúc này giữ domain dễ hiểu với người không chuyên: danh từ mô tả những gì tồn tại, động từ mô tả hệ thống làm gì.
Giữ luật nghiệp vụ không phụ thuộc UI
Logic nghiệp vụ không nên biết nó được kích hoạt bởi cú chạm nút, submit form web hay request API. Thực tế, điều đó nghĩa là:
- Không import framework (không controller web, view mobile, hoặc annotation ORM trong mã domain)
- Không dùng chuỗi UI (dùng mã lỗi hoặc key thay cho thông điệp cứng)
- Không giả định mạng (domain không nên “gọi API”; nó nên biểu đạt luật)
Khi AI tạo mã, sự tách biệt này dễ mất—models bị nhét các concerns UI. Xem đó như tín hiệu cần refactor.
Một tập quy tắc xác thực cho mọi nơi
Xác thực là nơi sản phẩm thường drift: web cho phép thứ gì đó mà API từ chối, hoặc mobile xác thực khác. Đặt xác thực nhất quán vào lớp domain (hoặc module xác thực chia sẻ) để mọi bề mặt thực thi cùng quy tắc.
Ví dụ:
EmailAddressvalidate format một lần, tái sử dụng cho web/mobile/APIMoneyngăn tổng âm, bất kể giá trị tới từ đâu- Use case enforce các quy tắc giữa các trường (ví dụ: “ngày kết thúc phải sau ngày bắt đầu”)
Nếu làm tốt, API layer trở thành bộ dịch, web/mobile là presenter—và domain layer là nguồn chân lý duy nhất.
API Layer: Hợp đồng dẫn dắt mọi thứ khác
API layer là “mặt công khai” của hệ thống—và trong một codebase do AI tạo, nó nên là phần neo giữ mọi thứ khác. Nếu hợp đồng rõ ràng, web app, mobile app và cả service nội bộ có thể được sinh và kiểm thử dựa trên cùng một nguồn chân lý.
Bắt đầu với hợp đồng theo kiểu API-first
Định nghĩa hợp đồng trước khi sinh handler hay wiring UI:
- Endpoints và resource: danh từ nhất quán (ví dụ
/users,/orders/{id}), lọc và sắp xếp có dự đoán. - Lỗi: hình dạng lỗi ổn định (code, message, details), kèm cách dùng HTTP status rõ ràng.
- Phân trang: chọn một cách (cursor-based thường dễ mở rộng) và chuẩn hoá các trường response.
- Versioning: quyết định sớm (path
/v1/...hoặc header) và document quy tắc ngừng hỗ trợ.
Sinh types và client từ một schema
Dùng OpenAPI (hoặc công cụ schema-first như GraphQL SDL) như artifact chuẩn. Từ đó, sinh:
- Server stubs (routes, scaffold xác thực)
- Typed client cho web và mobile
- Model request/response chia sẻ giảm drift
Điều này quan trọng với mã do AI tạo: model có thể sinh nhiều mã nhanh, nhưng schema giữ mọi thứ đồng bộ.
Quy tắc nhất quán ngăn lỗi tinh vi
Đặt vài nguyên tắc không thương lượng:
- Đặt tên:
snake_casehoặccamelCase, không cả hai; khớp giữa JSON và types sinh. - Status codes: 200/201/204 cho thành công, 400 cho xác thực, 401/403 cho auth, 409 cho conflict.
- Idempotency: yêu cầu
Idempotency-Keycho thao tác rủi ro (thanh toán, tạo đơn), và định nghĩa hành vi retry.
Xử lý hợp đồng API như một sản phẩm. Khi nó ổn định, mọi thứ khác dễ sinh, test và release hơn.
Web App: Tích hợp logic chia sẻ mà không coupling
Web app hưởng nhiều từ logic nghiệp vụ chia sẻ—và bị tổn thất khi logic đó bị rối với concerns UI. Yếu tố then chốt là xem lớp domain chia sẻ như một “động cơ headless”: nó biết luật, xác thực và luồng, nhưng không biết component, route hay API trình duyệt.
Lựa chọn render: SSR vs CSR (và vì sao quan trọng)
Nếu dùng SSR (server-side rendering), mã chia sẻ phải an toàn khi chạy trên server: không dùng trực tiếp window, document hay storage trình duyệt. Đó là một quy tắc tốt: giữ hành vi phụ thuộc trình duyệt trong một adapter web mỏng.
Với CSR (client-side rendering), bạn có nhiều quyền tự do hơn, nhưng kỷ luật vẫn cần. Dự án chỉ CSR thường “vô tình” import mã UI vào module domain vì mọi thứ chạy trong trình duyệt—cho đến khi cần thêm SSR, edge rendering hoặc test chạy trên Node.
Quy tắc thực tế: module chia sẻ nên xác định được (deterministic) và không phụ thuộc môi trường; mọi thứ chạm cookies, localStorage hoặc URL thuộc lớp web app.
Ranh giới trạng thái: trạng thái domain vs trạng thái UI
Logic chia sẻ có thể expose trạng thái domain (ví dụ: tổng đơn hàng, eligibility, flag suy diễn) thông qua object thuần và hàm thuần. Web app nên sở hữu trạng thái UI: spinner, focus form, animation tối ưu, visibility modal.
Điều này giữ cho state management trong React/Vue linh hoạt: bạn có thể đổi thư viện mà không phải viết lại luật nghiệp vụ.
Mối quan tâm riêng của web cần cách ly
Lớp web nên xử lý:
- Accessibility (markup semantic, điều hướng bằng phím, ARIA)
- Routing (cấu trúc URL, deep links, redirect server)
- Lưu trữ trình duyệt (cookie/session,
localStorage, caching)
Xem web app như một adapter dịch tương tác người dùng thành domain commands—và dịch kết quả domain thành màn hình có khả năng truy cập.
Mobile App: Logic chia sẻ với khả năng native
Mobile hưởng lợi nhất từ lớp domain chia sẻ: quy tắc giá, eligibility, xác thực và luồng nên hành xử giống web và API. UI mobile trở thành “vỏ bọc” quanh logic chia sẻ—tối ưu cho thao tác cảm ứng, kết nối gián đoạn và tính năng thiết bị.
Mẫu nền tảng nên thiết kế
Ngay cả khi chia sẻ logic, mobile có các mẫu hiếm khi map 1:1 với web:
- Điều hướng: model trạng thái điều hướng trong lớp app (screens, tabs, modal), trong khi quyết định domain (ví dụ, “người dùng phải xác minh email trước khi checkout”) ở mã chia sẻ.
- Tác vụ nền: xem sync, upload như job rõ ràng với giới hạn thời gian và khả năng resumable.
- Push notification: parse payload trong lớp app, rồi chuyển sang logic chia sẻ để quyết định hành động tiếp theo.
- Deep link: route trong lớp app, dùng logic chia sẻ để validate quyền và fetch dữ liệu cần thiết.
Ngoại tuyến trước tiên: cache, sync và chiến lược xung đột
Nếu kỳ vọng dùng mobile thực sự, giả sử ngoại tuyến:
- Cache các read model cục bộ (key-value hoặc SQLite) với chính sách độ cũ rõ ràng.
- Queue các write như intent/event (ví dụ: “tạo nháp đơn hàng”), rồi sync khi có mạng.
- Định nghĩa quy tắc xung đột từ đầu (last-write-wins, merge do server quyết định, hoặc giải quyết bởi người dùng).
- Triển khai retry với backoff và idempotency keys để API có thể chấp nhận bản duplicate an toàn.
Những mối quan tâm riêng của mobile
- Kích thước app: giữ lớp chia sẻ modular để chỉ ship những gì app cần.
- Pin/dữ liệu: gom gói các cuộc gọi mạng và tránh polling gây tốn kém.
- Quyền truy cập: yêu cầu khi cần (camera, location), và giữ kiểm tra permission ngoài mã domain để policy khác nhau theo nền tảng.
Mô hình dữ liệu, Auth và Quyền trên mọi bề mặt
Một “codebase duy nhất” sụp đổ nhanh nếu web, mobile và API mỗi bên phát minh ra hình dạng dữ liệu và luật bảo mật riêng. Cách khắc phục là coi model, authentication và authorization như quyết định sản phẩm chia sẻ, rồi mã hoá chúng một lần.
Một nguồn chân lý cho mô hình dữ liệu
Chọn một nơi lưu model, và để mọi thứ khác sinh ra từ đó. Các lựa chọn phổ biến:
- Schema-first: định nghĩa entity và quy tắc xác thực trong file schema (OpenAPI/JSON Schema), rồi sinh types cho API, web và mobile.
- Module chia sẻ: giữ type model và validator trong package chia sẻ (thường là package “domain”) mà mọi app import.
- Hybrid: file schema cho hợp đồng bên ngoài, module chia sẻ cho quy tắc domain nội bộ.
Điều then chốt không phải công cụ—mà là tính nhất quán. Nếu “OrderStatus” có 5 giá trị ở client này và 6 ở client kia, mã do AI sinh sẽ compile và vẫn phát hành bug.
Authentication: session, token và lưu trữ an toàn
Authentication nên cảm nhận giống nhau với người dùng, nhưng cơ chế khác theo mặt:
- Web thường ưu cookie-based sessions (bảo vệ CSRF tốt, lưu trữ trình duyệt đơn giản).
- Mobile và client bên thứ ba thường cần token-based auth (access token + refresh token).
Thiết kế một luồng duy nhất: login → access ngắn hạn → refresh khi cần → logout và vô hiệu hoá trạng thái server. Trên mobile, lưu bí mật trong secure storage (Keychain/Keystore). Trên web, ưu httpOnly cookies để token không lộ cho JavaScript.
Authorization: quy tắc trung tâm, thực thi ở API
Quyền nên được định nghĩa một lần—tốt nhất là gần luật nghiệp vụ—rồi áp dụng ở mọi nơi.
- Tập trung kiểm tra ở domain (ví dụ,
canApproveInvoice(user, invoice)). - Thực thi ở API để đảm bảo an ninh.
- Nhân rộng ở UI chỉ để ẩn/khóa hành động, không để bảo vệ dữ liệu.
Điều này ngăn drift “mobile chạy nhưng web không” và cho phép AI tạo mã theo hợp đồng rõ ràng, có thể test.
Chiến lược build, phát hành và triển khai
Một codebase thống nhất chỉ giữ được tính thống nhất nếu build và release dự đoán được. Mục tiêu là cho phép các đội ship API, web và mobile độc lập—không phải fork logic hay “đặt điều kiện” cho môi trường.
Monorepo vs multi-repo
Monorepo (một repo, nhiều package/app) thường phù hợp nhất cho một codebase duy nhất vì logic domain, hợp đồng API và client UI tiến hoá cùng nhau. Bạn có thay đổi nguyên tử (một PR cập nhật hợp đồng và tất cả consumer) và refactor dễ hơn.
Multi-repo vẫn có thể thống nhất, nhưng bạn sẽ trả chi phí về phối hợp: version hóa package chia sẻ, publish artifact và đồng bộ thay đổi phá vỡ. Chọn multi-repo chỉ khi rào cản tổ chức, bảo mật hoặc quy mô khiến monorepo không khả thi.
Mục tiêu build và artifact
Xem mỗi bề mặt như một target build riêng tiêu thụ package chia sẻ:
- Artifact dịch vụ API: ảnh container hoặc bundle serverless từ package API.
- Bundle web: tài sản tĩnh + runtime server (nếu SSR) từ package web.
- Build mobile: Android (AAB/APK) và iOS (IPA) do pipeline native tạo, nhưng nhập logic chia sẻ như dependency.
Giữ output build rõ ràng và có thể lặp lại (lockfile, toolchain cố định, build xác định được).
CI/CD và tách môi trường
Pipeline điển hình: lint → typecheck → unit tests → contract tests → build → security scan → deploy.
Tách config ra khỏi code: biến môi trường và secret nằm trong CI/CD và secret manager, không trong repo. Dùng overlay riêng cho dev/stage/prod để cùng một artifact có thể được promote giữa môi trường mà không cần build lại—đặc biệt với API và runtime web.
Kiểm thử và hàng rào chất lượng cho mã chia sẻ
Khi web, mobile và API phát hành từ cùng một codebase, testing không còn là “một checkbox” mà là cơ chế ngăn một thay đổi nhỏ làm hỏng ba sản phẩm cùng lúc. Mục tiêu đơn giản: phát hiện vấn đề ở nơi rẻ nhất để sửa và chặn thay đổi rủi ro trước khi đến tay người dùng.
Kim tự tháp test thực dụng cho codebase chia sẻ
Bắt đầu với domain chia sẻ (logic nghiệp vụ) vì nó dùng lại nhiều nhất và là nơi dễ test nhất mà không cần hạ tầng chậm.
- Unit tests (domain layer): Kiểm tra luật như giá, eligibility, quyết định quyền, chuyển trạng thái và các edge case. Chạy nhanh và chiếm phần lớn suite.
- Integration tests (API layer): Chứng minh API chạy end-to-end với serialization, xác thực và truy cập dữ liệu thực. Tập trung vào luồng quan trọng hơn là mọi góc cạnh.
- UI tests (mỗi client): Một số kiểm tra giá trị cao để xác nhận các hành trình chính (sign-in, checkout, submit form) hoạt động thực tế. Chúng chậm, nên dùng như “báo động khói”, không phải bằng chứng toàn diện.
Cấu trúc này đặt đa phần niềm tin vào logic chia sẻ, đồng thời bắt lỗi “wiring” nơi các lớp gặp nhau.
Contract testing để giữ client và API khớp nhau
Ngay cả trong monorepo, API vẫn dễ thay đổi sao cho compile được nhưng phá UX. Test hợp đồng ngăn drift âm thầm.
- API-to-client contracts: Khóa shape request/response, định dạng lỗi và status code. Nếu API trả trường mới bắt buộc hoặc thay enum, contract test sẽ fail trước khi merge.
- Schema như một cổng: Nếu bạn publish OpenAPI/GraphQL schema, coi thay đổi schema là artifact cần review. Thay đổi phá vỡ cần approval rõ ràng và kế hoạch migrate.
Hàng rào chất lượng bảo vệ release
Test tốt rất quan trọng, nhưng các quy tắc xung quanh cũng quan trọng.
- Gate PR: Yêu cầu pass unit + integration tests, lint/format và coverage tối thiểu cho domain layer.
- Feature flag: Ship an toàn bằng cách ẩn behavior chưa hoàn thiện sau flags bật theo môi trường hoặc nhóm người dùng.
- Staged rollout: Triển khai cho người dùng nội bộ trước, rồi một phần nhỏ traffic production, rồi toàn bộ.
- Kế hoạch rollback: Làm rollback thành một outcome chính thức—versioned releases, migration DB có thể đảo ngược (hoặc an toàn khi forward), và tiêu chí “dừng dây chuyền” rõ ràng.
Với những hàng rào này, các thay đổi do AI hỗ trợ có thể thường xuyên mà không mong manh.
Dùng AI mà không mất kiểm soát kiến trúc
AI có thể tăng tốc một codebase duy nhất, nhưng chỉ khi nó được đối xử như một kỹ sư trẻ tốc độ cao: giỏi tạo bản nháp, không an toàn để merge trực tiếp. Mục tiêu là dùng AI để lấy đà mà vẫn để con người chịu trách nhiệm cho kiến trúc, hợp đồng và tính mạch lạc lâu dài.
AI hữu ích nhất ở đâu (và rủi ro thấp)
Dùng AI để tạo “phiên bản đầu” bạn thường viết theo kiểu máy móc:
- Scaffold dự án (thư mục, module boilderplate, feature skeleton)
- Tài liệu API và ví dụ dựa trên hợp đồng hiện có
- Test suite (unit test cho domain, contract test cho endpoint)
- Migration và script seed data
- Refactor lặp lại (đổi tên trường, tách module), sau khi bạn định nghĩa kế hoạch
Quy tắc tốt: để AI sinh mã dễ kiểm chứng bằng đọc hoặc chạy test, không phải mã âm thầm thay đổi ý nghĩa nghiệp vụ.
Hàng rào bảo vệ kiến trúc
Đầu ra AI nên bị giới hạn bởi quy tắc rõ ràng, không phải cảm nhận. Đặt các quy tắc này nơi mã ở:
- Chuẩn code: linter/formatter, quy tắc đặt tên và quy tắc “không truy cập DB trực tiếp từ UI”.
- Quy tắc kiến trúc: ranh giới phụ thuộc (ví dụ domain không import API/web/mobile), thực thi bằng tooling hoặc build check đơn giản.
- Checklist PR: “Hợp đồng thay đổi? Cập nhật OpenAPI + client types + test.” “Luật domain mới? Thêm test domain.”
Nếu AI gợi ý lối tắt vi phạm biên giới, trả lời là “không” dù nó biên dịch được.
Quản trị: làm cho AI có thể kiểm tra được
Rủi ro không chỉ là mã xấu—mà còn là quyết định không được ghi nhận. Giữ trail kiểm toán:
- Lưu prompt và phản hồi quan trọng kèm work item (ticket ID, link PR).
- Ghi lại quyết định kiến trúc (ADR) cho thay đổi hợp đồng, model auth, hoặc khái niệm domain mới.
- Yêu cầu thay đổi API phải rõ ràng: versioned, document và có test hợp đồng.
AI giá trị nhất khi lặp lại được: đội có thể thấy tại sao cái gì đó được sinh, verify nó, và sinh lại an toàn khi yêu cầu thay đổi.
Ghi chú công cụ: AI tôn trọng ranh giới
Nếu bạn áp dụng AI ở mức hệ thống (web + API + mobile), tính năng quan trọng nhất không phải tốc độ sinh thô—mà là khả năng giữ đầu ra phù hợp với hợp đồng và phân lớp.
Ví dụ, Koder.ai là nền tảng vibe-coding giúp đội xây web, server và mobile qua giao diện chat—vẫn sinh mã nguồn thật, có thể export. Trong thực tiễn, điều đó hữu ích cho workflow trong bài viết: bạn có thể định nghĩa hợp đồng API và luật domain, rồi nhanh chóng lặp trên giao diện React web, backend Go + PostgreSQL và app Flutter mà không mất khả năng review, test và thực thi ranh giới kiến trúc. Các tính năng như planning mode, snapshot và rollback phù hợp với kỷ luật “sinh → verify → promote” trong codebase thống nhất.
Khi nào không nên dùng một codebase duy nhất (và làm gì thay thế)
Một codebase duy nhất có thể giảm trùng lặp, nhưng không phải lựa chọn “tốt nhất” mặc định. Khi mã chia sẻ bắt đầu ép UX cồng kềnh, làm chậm release hoặc che giấu khác biệt nền tảng, bạn sẽ mất thời gian đàm phán kiến trúc hơn là giao giá trị.
Trường hợp nên tách codebase
Tách codebase (hoặc ít nhất tách UI layer) thường hợp lý khi:
- UI tùy biến cao là sản phẩm. Nếu web và mobile cần mô hình tương tác khác biệt hoàn toàn (gesture, ngoại tuyến toàn diện, camera-first, animation phức tạp), UI chia sẻ thường thành thỏa hiệp.
- Hạn chế nền tảng nghiêm ngặt. Quy trình review App Store, quyền phần cứng, giới hạn chạy nền và yêu cầu truy cập đặc thù có thể cần implement riêng.
- Chu kỳ phát hành khác nhau. Mobile phát hành hàng tháng trong khi web hàng ngày. Monorepo chặt có thể biến mỗi thay đổi thành sự kiện phối hợp.
Các chế độ thất bại thường gặp
- Chia sẻ UI quá nhiều: “Một UI cho tất cả” dẫn đến trải nghiệm tồi nhất cho mọi người.
- Trừu tượng rò rỉ: module “chia sẻ” vẫn lộ chi tiết web/mobile (routing, storage, token), khiến mọi consumer dễ vỡ.
- Drift version: đội copy-paste mã chia sẻ để chạy nhanh, rồi fix chỉ landing ở một nơi.
Checklist quyết định (và làm gì thay thế)
Hỏi trước khi quyết một codebase duy nhất:
- Logic domain có thể chia sẻ sạch trong khi giữ UI native không?
- Các đội nền tảng cần tự chủ về tooling, thời gian phát hành và thử nghiệm không?
- API có đủ ổn định để client tiến hoá độc lập không?
Nếu thấy dấu hiệu cảnh báo, lựa chọn thực tế là domain chia sẻ + hợp đồng API, với web và mobile app tách biệt. Giữ mã chia sẻ tập trung vào luật nghiệp vụ và xác thực, và để mỗi client sở hữu UX và tích hợp nền tảng.
Nếu bạn muốn giúp chọn hướng, so sánh các lựa chọn trên /pricing hoặc duyệt mẫu kiến trúc liên quan trên /blog.
Câu hỏi thường gặp
Does “one AI-generated codebase” mean one UI that runs everywhere?
Nó thường có nghĩa là một repository và một tập quy tắc chia sẻ, chứ không phải một ứng dụng giống hệt trên mọi nền tảng.
Thực tế, web, mobile và API chia sẻ lớp domain (luật nghiệp vụ, xác thực, use case) và thường là một hợp đồng API duy nhất, trong khi mỗi nền tảng giữ UI và tích hợp riêng của mình.
What should be shared across web, mobile, and API—and what shouldn’t?
Chia sẻ những thứ không bao giờ được mâu thuẫn:
- Luật domain (giá, điều kiện, luồng công việc, các bất biến)
- Use case (tạo đơn hàng, huỷ đăng ký, hoàn tiền)
- Xác thực + mã lỗi
- Schema/hợp đồng API (OpenAPI/GraphQL) và các type được sinh
Giữ các component UI, điều hướng và tích hợp thiết bị/trình duyệt riêng theo nền tảng.
What does AI change in the architecture, and what stays the same?
AI làm nhanh phần scaffold và công việc lặp lại (CRUD, client, test), nhưng nó không tự động tạo biên giới kiến trúc tốt.
Không có kiến trúc rõ ràng, mã do AI tạo thường:
- sao chép logic giữa các app
- trộn lẫn concerns (UI truy cập trực tiếp tới nguồn dữ liệu)
- tạo các xác thực hơi khác nhau ở nhiều nơi
Dùng AI để lấp đầy những lớp đã xác định rõ, không để nó tự phát minh lớp kiến trúc.
What’s a good reference architecture for a single shared codebase?
Một luồng đơn giản và tin cậy là:
- Clients (web/mobile/partners) gọi API layer
- API layer chuyển request thành domain use cases
- Domain gọi interface của data source (DB/cache/ external APIs)
Điều này giữ luật nghiệp vụ ở trung tâm và giúp việc test cũng như thêm phần do AI tạo trở nên dễ review hơn.
How do we prevent validation drift between web, mobile, and the API?
Đặt xác thực vào một nơi (lớp domain hoặc module xác thực chia sẻ), rồi tái sử dụng nó ở mọi mặt.
Các mẫu thực tế:
- validate các value object như
EmailAddressvàMoneymột lần - enforce các quy tắc giữa các trường trong use case (ví dụ: khoảng kết thúc phải sau khoảng bắt đầu)
- trả về mã lỗi ổn định (UI có thể map mã thành thông điệp)
Điều này ngăn “web chấp nhận, API bác bỏ” xảy ra.
How can the API contract become the “source of truth” for the whole system?
Dùng một schema chuẩn như OpenAPI (hoặc GraphQL SDL) và sinh từ đó:
- server stubs và scaffold xác thực request
- typed client cho web và mobile
- model request/response chia sẻ
Rồi thêm test hợp đồng để các thay đổi phá vỡ schema bị phát hiện trong CI trước khi deploy.
What does “offline-first” mean when sharing logic with a mobile app?
Thiết kế ngoại tuyến có chủ đích thay vì “hy vọng caching hoạt động”:
- cache các read model cục bộ với chính sách độ cũ rõ ràng
- queue các write như intent/event rồi sync khi có mạng
- định nghĩa quy tắc xung đột (server-authoritative, merge, hoặc do người dùng giải quyết)
- dùng retry với backoff và idempotency keys
Giữ lưu trữ ngoại tuyến và sync trong lớp app mobile; luật nghiệp vụ nằm trong domain chia sẻ.
How should auth and permissions work across web, mobile, and APIs?
Dùng một luồng khái niệm chung, triển khai phù hợp cho từng mặt:
- Web: thường dùng session cookie (giúp giảm rủi ro token bị JS truy cập)
- Mobile/third-party: access + refresh token, lưu trong secure storage (Keychain/Keystore)
Quyền truy cập (authorization) nên được định nghĩa tập trung (ví dụ canApproveInvoice) và bắt buộc thực thi ở API; UI chỉ nhân rộng các kiểm tra để ẩn/khóa hành động chứ không để bảo vệ dữ liệu.
How do builds and releases stay manageable in a unified codebase?
Xem mỗi surface như một build target riêng tiêu thụ các package chia sẻ:
- API: artifact container hoặc bundle serverless
- Web: bundle tĩnh + runtime SSR nếu cần
- Mobile: build native iOS/Android nhập logic chia sẻ
Trong CI/CD chạy: lint → typecheck → unit tests → contract tests → build → security scan → deploy, và giữ secrets/cấu hình ngoài repo.
How do we use AI to speed up development without losing architectural control?
Dùng AI như một kỹ sư trẻ nhanh nhẹn: hữu ích để tạo bản nháp, nhưng không nên merge khi chưa có review.
Các hàng rào tốt:
- bắt buộc ranh giới phụ thuộc (domain không import web/mobile/API)
- yêu cầu cập nhật schema + client khi hợp đồng thay đổi
- bắt buộc unit test domain cho quy tắc mới
- lưu ADR và prompt quan trọng kèm PR/ticket
Nếu output của AI vi phạm quy tắc kiến trúc, từ chối ngay cả khi mã biên dịch được.