Vue 3 Composition API vs Options API cho thư viện component lớn
Vue 3 Composition API vs Options API: cách mỗi kiểu ảnh hưởng đến tái sử dụng, testing và onboarding cho thư viện component admin lớn và đội ngũ cộng tác viên.

Tại sao lựa chọn này quan trọng trong các thư viện component admin lớn
Một thư viện component lớn trong app admin không phải là trang marketing với vài nút bấm. Đó là hàng chục (hoặc hàng trăm) khối xây dựng lặp lại trên nhiều màn hình: bảng dữ liệu có sắp xếp và hành động hàng loạt, panel lọc, form với quy tắc validate, ngăn kéo và modal, luồng xác nhận, và các tiện ích nhỏ như bộ chọn ngày và guard phân quyền.
Vì những pattern này xuất hiện khắp nơi, các team thường sao chép và chỉnh sửa code để kịp deadline. Một bảng có thanh lọc tùy chỉnh, bảng khác có thanh lọc hơi khác, và chẳng mấy chốc bạn có năm phiên bản “gần như giống nhau”. Lúc đó câu hỏi Composition API vs Options API không còn là sở thích cá nhân nữa mà bắt đầu ảnh hưởng đến sức khỏe toàn bộ thư viện.
Điều thường phá vỡ trước hết là sự nhất quán. UI vẫn chạy, nhưng hành vi trôi dạt: một modal đóng bằng Escape ở chỗ này nhưng không ở chỗ khác; cùng một trường form validate on blur ở trang này nhưng validate on submit ở trang kia. Sau đó tốc độ giảm vì mỗi thay đổi đòi hỏi phải lùng sục các bản sao gần giống. Cuối cùng, sự tự tin giảm: mọi người tránh refactor vì không dự đoán được điều gì sẽ bị ảnh hưởng.
Ba quyết định thực tế quan trọng nhất trong thư viện chia sẻ:
- Tái sử dụng code: bạn đóng gói logic chung thế nào mà không tạo phụ thuộc rối rắm.
- Testing: bạn xác minh hành vi dễ dàng ra sao mà không cần test fragile, nặng UI.
- Onboarding: người đóng góp mới đọc một component và thay đổi an toàn nhanh thế nào.
Ví dụ đơn giản: admin của bạn có 20 trang danh sách, và product yêu cầu tính năng “Saved filters”. Nếu logic bảng, bộ lọc và đồng bộ URL rải rác và thiếu nhất quán, bạn sẽ phải triển khai chậm hoặc triển khai với lỗi. Kiểu API bạn chọn định hình liệu logic đó sống ở một chỗ tái sử dụng, nó được nối rõ ràng vào từng màn hình ra sao, và người mới có thể mở rộng dễ đến mức nào.
Nếu bạn xây dựng app admin Vue 3 (kể cả các team dùng Vue 3 bên trong nền tảng như AppMaster cho lớp UI web), quyết định sớm có thể tiết kiệm hàng tháng bảo trì sau này.
Options và Composition khác nhau thế nào trong code hàng ngày
Cách nhanh nhất để cảm nhận khác biệt là mở một component admin lớn và hỏi: “Tôi thay đổi hành vi cho tính năng này ở đâu?” Trong thư viện component, câu hỏi đó xuất hiện hàng ngày.
Với Options API, code được gom theo loại: data cho state, methods cho hành động, computed cho giá trị dẫn xuất, và watch cho side effect. Cấu trúc này dễ quét khi component nhỏ. Trong một bảng hoặc form lớn, logic cho một tính năng (như hành động hàng loạt hay validate trường) thường bị trải ra nhiều khối. Bạn có thể giữ ngăn nắp, nhưng cần kỷ luật và quy ước đặt tên nhất quán để tránh phải “nhảy quanh file”.
Với Composition API, code thường được gom theo tính năng. Bạn định nghĩa state liên quan, giá trị dẫn xuất, side effect và helper cạnh nhau, và có thể kéo logic lặp lại vào composables. Trong thư viện kiểu admin, điều này thường khớp cách suy nghĩ: “mọi thứ về lọc ở đây”, “mọi thứ về chọn hàng ở đây”. Nó cũng giảm trùng lặp giữa các component tương tự, như tái sử dụng usePagination giữa nhiều bảng.
Một khác biệt lớn hàng ngày là phụ thuộc xuất hiện thế nào.
- Options API có thể cảm thấy ẩn: một method có thể phụ thuộc
this.user,this.filters, vàthis.loading, và bạn chỉ biết khi đọc bên trong method đó. - Composition API có xu hướng rõ ràng hơn: khi một hàm đóng over
filtersvàloading, bạn thấy các biến đó được định nghĩa gần đó, và bạn có thể truyền chúng vào helper khi cần.
Nhược điểm là Composition API có thể ồn nếu mọi thứ bị đổ vào một setup() khổng lồ mà không có cấu trúc.
Quy tắc thực tế:
- Chọn Options API khi component chủ yếu là trình bày và có logic nhẹ.
- Chọn Composition API khi component có nhiều tính năng với quy tắc chia sẻ xuyên thư viện.
- Nếu chọn Composition API, thống nhất một bố cục đơn giản gom code theo tính năng (không phải “tất cả ref trước”).
- Nếu chọn Options API, bắt buộc quy tắc đặt tên và giữ logic liên quan gần nhau với comment ngắn và tên method nhất quán.
Cả hai đều có thể dùng được. Chìa khóa là chọn kiểu tổ chức khiến thay đổi tiếp theo trở nên hiển nhiên, chứ không phải khôn ngoan quá mức.
Tái sử dụng code: gì mở rộng gọn và gì trở nên lộn xộn
Trong app kiểu admin, tái sử dụng không phải là điều tùy chọn. Bạn lặp lại cùng hành vi trên hàng chục màn hình, và sai lệch nhỏ biến thành bug và ticket hỗ trợ.
Hầu hết nhu cầu tái sử dụng rơi vào một vài nhóm lặp lại: sắp xếp/lọc/phanTrang phù hợp backend, validate form và map lỗi, kiểm tra phân quyền và ẩn/hiện UI, đồng bộ query (params URL, saved views, filter mặc định), và hành động hàng loạt với quy tắc chọn hàng.
Tái sử dụng với Options API: mạnh nhưng dễ che giấu độ phức tạp
Với Options API, tái sử dụng thường bắt đầu bằng mixins, extends, hoặc plugin.
Mixins nhanh nhưng mở rộng tệ vì che giấu nguồn gốc của method hay computed. Hai mixin có thể va chạm tên method, và giờ bạn debug hành vi mà không thấy rõ trong file component. extends có thể trông sạch hơn mixin, nhưng vẫn tạo ra câu đố kế thừa nơi bạn phải đọc nhiều file để hiểu component thực sự làm gì. Plugin phù hợp cho mối quan tâm cấp app (directive toàn cục, service chia sẻ), nhưng không phải nơi tốt cho quy tắc nghiệp vụ thay đổi theo màn hình.
Khoảnh khắc lộn xộn thường xuất hiện khi tái sử dụng trở nên ẩn. Người mới không trả lời được “dữ liệu này đến từ đâu?” mà không tìm trong toàn bộ codebase.
Tái sử dụng với Composition API: composable giữ tính rõ ràng
Tái sử dụng trong Composition API thường xoay quanh composables: hàm nhỏ trả về refs, computed và handler. Lợi thế lớn là tái sử dụng xuất hiện ngay gần đầu component, và bạn có thể truyền tham số thay vì dựa vào context ẩn của component.
Ví dụ, usePagination có thể nhận defaults và phát ra thay đổi theo một dạng nhất quán, trong khi usePermissions có thể nhận role hiện tại và tên tính năng. Lúc đó, lựa chọn ít còn về cú pháp mà nhiều về việc thư viện của bạn ưa wiring rõ ràng hơn hay kế thừa ẩn.
Để giữ tái sử dụng có thể dự đoán, hãy đối xử mỗi đơn vị tái sử dụng như một API nhỏ: đặt tên rõ, định nghĩa input/output, và giữ một trách nhiệm. Nếu một composable bắt đầu xử lý phân trang, cache, phân quyền và thông báo, hãy tách nó. Dễ thay một phần mà không phá vỡ mọi thứ khác.
Xây dựng component form và table tái sử dụng mà không bị đau đầu
Trong app kiểu admin, form và bảng là nơi thư viện component tỏ ra có giá trị hoặc trở thành mê cung. Cả hai API đều có thể làm được. Sự khác biệt là cách bạn đóng gói hành vi chung như dirty state, map lỗi và luồng submit mà không làm cho mỗi component trở nên “đặc biệt”.
Với logic form chung, Options API thường hướng bạn tới mixins hoặc helper chia sẻ. Mixins tiện ban đầu, nhưng sau này khó trả lời câu hỏi cơ bản: “Lỗi của field này đến từ đâu?” hay “Tại sao submit bị disable?”.
Composition API làm cho tái sử dụng hiển nhiên hơn vì bạn có thể đưa logic vào composables (ví dụ useDirtyState, useFormErrors, useSubmitFlow) và thấy chính xác component form kéo vào gì. Trong thư viện lớn, rõ ràng này thường quan trọng hơn việc tiết kiệm vài dòng code.
Cách thực tế để giữ API component ổn định là coi surface public như một hợp đồng: props, emits và slots nên thay đổi hiếm khi, ngay cả khi bạn viết lại nội bộ. Hợp đồng này giống nhau ở cả hai style, nhưng Composition API thường làm refactor an toàn hơn vì bạn có thể thay thế một composable một lần mà không động tới template API.
Các pattern thường vẫn ổn khi thư viện lớn lên:
- Xây base components làm 1 việc tốt (BaseInput, BaseSelect, BaseTable), rồi compose chúng vào các feature component.
- Ưu tiên slots để linh hoạt layout (khu vực action, trạng thái rỗng, render cell) thay vì thêm props cho mọi trường hợp cạnh.
- Chuẩn hóa event sớm (ví dụ
update:modelValue,submit,rowClick) để app không phụ thuộc vào chi tiết nội bộ. - Giữ validate và định dạng gần input, nhưng giữ quy tắc nghiệp vụ ra ngoài (trong composables hoặc container).
Quá trừu tượng là cái bẫy phổ biến. Một “super form” xử lý mọi loại field, mọi quy tắc validate và mọi layout thường khó dùng hơn Vue thuần. Quy tắc tốt là: nếu một base component cần hơn vài props để đáp ứng nhu cầu các team, có thể nó nên chia thành hai component.
Đôi khi trùng lặp là lựa chọn đúng. Nếu chỉ một màn hình cần header bảng kỳ lạ với nhóm nhiều hàng, sao chép một đoạn nhỏ và giữ nó local. Các abstraction thông minh có chi phí bảo trì dài, đặc biệt khi có người mới vào và cố hiểu đâu là component “bình thường” và đâu là framework trong framework.
Nếu bạn quyết giữa Composition và Options cho thư viện form và table lớn, tối ưu cho độ dễ đọc luồng dữ liệu trước. Tái sử dụng tốt, nhưng không khi nó che khuất đường đi từ hành động người dùng tới event phát ra.
Ảnh hưởng đến testing: gì dễ xác minh hơn
Trong thư viện component, test thường rơi vào ba nhóm: logic thuần (format, validate, filter), rendering (hiển thị gì với state nhất định), và tương tác (click, input, keyboard, emits). Kiểu API bạn chọn thay đổi tần suất bạn có thể test nhóm đầu mà không mount toàn bộ component.
Test với Options API có xu hướng: “mount component, thao tác state instance, assert DOM.” Cách này ổn nhưng có thể khuyến khích test lớn vì logic trộn trong methods, computed, watch và lifecycle. Khi có lỗi, bạn cũng mất thời gian để biết đó là watcher timing, lifecycle side effect hay logic thuần.
Options API thường phù hợp cho:
- Luồng người dùng phụ thuộc thứ tự lifecycle (fetch on mount, reset on route change)
- Hành vi dựa trên watcher (auto-save, đồng bộ query)
- Phát event từ methods của component (
save(),reset(),applyFilter())
Composition API thay đổi cân bằng. Nếu bạn chuyển logic vào composables, bạn có thể unit test logic đó như các hàm thuần, với input nhỏ và kết quả rõ ràng. Điều đó giảm số test “mount và click” cần thiết, và làm lỗi cục bộ hơn. Nó cũng giúp kiểm soát phụ thuộc dễ hơn: thay vì mock global, bạn truyền dependency (hàm fetch, formatter ngày, hoặc permission checker) vào composable.
Ví dụ cụ thể: một AdminTable dùng chung với sắp xếp, phân trang và chọn hàng. Với Composition API, logic chọn hàng có thể nằm trong useRowSelection() và được test mà không cần render bảng (toggle, clear, select all, nhớ qua các trang). Sau đó bạn giữ một bộ test component nhỏ để kiểm tra template nối đúng nút, checkbox và event phát ra.
Để giữ test nhỏ và dễ đọc (bất kể style):
- Đặt quy tắc nghiệp vụ vào hàm thuần hoặc composables, không trong watchers.
- Giữ side effect (fetch, storage, timer) sau dependencies được injected.
- Ưa vài integration test tập trung cho mỗi component, không một test khổng lồ “mọi thứ”.
- Đặt tên state và event nhất quán xuyên thư viện (giảm setup test).
- Tránh coupling ẩn (như method A dựa vào watcher B chạy).
Nếu mục tiêu là chọn kiểu giúp test ổn định hơn, hướng tới ít hành vi dựa trên lifecycle hơn và nhiều unit logic cô lập mà bạn có thể kiểm chứng không cần DOM.
Onboarding người đóng góp mới: họ trở nên hiệu quả nhanh thế nào
Trong thư viện component admin lớn, onboarding ít liên quan tới dạy Vue mà nhiều tới giúp người ta tìm thứ, theo cùng convention, và cảm thấy an toàn khi sửa. Hầu hết chậm trễ đến từ ba khoảng trống: điều hướng (logic nằm đâu?), convention (làm thế nào ở đây?), và tự tin (thay đổi này không phá vỡ năm màn hình khác chứ?).
Với Options API, người mới thường chạy nhanh vào ngày đầu vì cấu trúc quen thuộc: props, data, computed, methods, watchers. Đổi lại, hành vi thực tế thường bị rải rác. Một tính năng như “lọc server-side” có thể bị chia giữa watcher, computed, hai method và một mixin. Mọi người có thể đọc từng khối, nhưng tiêu tốn thời gian để nối câu chuyện.
Với Composition API, lợi thế onboarding là logic liên quan có thể ngồi cùng nhau: state, side effect và helper ở một chỗ. Chi phí là học composable. Người mới cần hiểu pattern như useTableState() và cách reactive values chảy qua nhiều composable. Nếu không có ranh giới rõ, có thể cảm thấy như nhảy giữa các file mà không có bản đồ.
Một vài convention loại bỏ hầu hết câu hỏi, dù bạn chọn style nào:
- Dùng cấu trúc dễ đoán:
components/,composables/,types/,tests/. - Chọn pattern đặt tên và giữ nó (ví dụ:
useX,XTable,XForm). - Thêm docblock ngắn: component làm gì, props chính, event chính.
- Định một quy tắc “escape hatch” nhỏ (khi nào được phép thêm composable hoặc helper mới).
- Giữ một component “vàng” nhỏ thể hiện pattern ưa thích.
Ví dụ: nếu team bạn sinh một panel admin Vue 3 rồi tùy chỉnh nó (ví dụ app web được xây trên AppMaster và dev mở rộng), onboarding cải thiện nhiều khi có một chỗ rõ ràng để điều chỉnh hành vi bảng (sắp xếp, filter, pagination) và một chỗ rõ để điều chỉnh wiring UI (slots, column renderers, row actions). Rõ ràng đó quan trọng hơn API bạn chọn.
Các bước từng bước: chọn style và giới thiệu an toàn
Với thư viện UI admin lớn, cách an toàn nhất để quyết là bắt đầu với một tính năng có ranh giới rõ và coi nó như pilot, không phải rewrite toàn bộ.
Chọn một module có hành vi rõ và nhiều chỗ tái sử dụng, như lọc bảng hoặc validate form. Trước khi động code, ghi ra nó đang làm gì: đầu vào (props, query params, hành động người dùng), đầu ra (events, emits, thay đổi URL), và các trường hợp biên (empty state, reset, lỗi server).
Tiếp theo, đặt ranh giới. Quyết xem cái gì phải ở trong component (render, sự kiện DOM, accessibility) và cái gì có thể chuyển vào code chia sẻ (parse filters, debounce, build API params, trạng thái mặc định). Đây là nơi nhiều thư viện sai: nếu bạn chuyển quyết định UI vào code chia sẻ, bạn làm khó tái sử dụng.
Kế hoạch rollout thực tế:
- Chọn một component biểu thị pattern rõ và được nhiều màn hình dùng.
- Tách một đơn vị chung (composable hoặc helper thuần) với API nhỏ, rõ ràng.
- Thêm test tập trung cho đơn vị đó trước, dựa trên scenario admin thật.
- Refactor component đã chọn end-to-end dùng đơn vị mới.
- Áp dụng pattern tương tự cho một component nữa để xác nhận nó mở rộng.
Giữ API chia sẻ nhàm và hiển nhiên. Ví dụ useTableFilters() có thể nhận filters ban đầu và expose filters, apply(), reset(), và toRequestParams(). Tránh “ma thuật” đọc từ global state trừ khi đó là quy tắc cứng trong app.
Sau pilot, xuất một guideline nội bộ ngắn có một ví dụ để người đóng góp copy. Một quy tắc cụ thể tốt hơn tài liệu dài, ví dụ: “mọi logic lọc bảng đều ở composable; component chỉ bind control UI và gọi apply().”
Trước khi mở rộng, dùng định nghĩa done đơn giản:
- Code mới đọc giống nhau ở hai component khác nhau.
- Test bao phủ logic chia sẻ mà không mount UI đầy đủ.
- Người đóng góp mới có thể thay rule filter mà không chạm file liên quan.
Nếu team bạn cũng xây portal admin với công cụ no-code như AppMaster, mindset pilot tương tự giúp: chọn workflow (ví dụ approvals), định nghĩa hành vi, rồi chuẩn hóa pattern trước khi scale.
Các lỗi và bẫy thường gặp trong thư viện lớn
Vấn đề lớn nhất trong thư viện component hiếm khi là cú pháp. Chúng thường đến từ các quyết định cục bộ nhỏ tích tụ và làm cho việc tái sử dụng, test và bảo trì khó hơn.
Một bẫy phổ biến là mix pattern ngẫu nhiên. Nếu nửa thư viện dùng Options API và nửa còn lại dùng Composition API không có quy tắc, mọi component mới trở thành tranh luận phong cách. Bạn cũng có kết quả là giải pháp bị nhân bản theo nhiều cách khác nhau. Nếu cho phép cả hai, viết chính sách rõ: code mới dùng một style, legacy chỉ động khi cần, và logic chia sẻ nằm ở một chỗ đồng thuận.
Bẫy khác là “god composable”. Nó thường khởi đầu hữu ích như useAdminPage() hoặc useTable() rồi dần hấp thụ routing, fetch, cache, selection, dialog, toast và permission. Nó khó test vì một cuộc gọi kích nhiều side effect. Nó khó tái sử dụng vì mỗi màn hình chỉ cần 30% nhưng phải gánh toàn bộ độ phức tạp.
Watchers cũng là nguồn đau. Chúng dễ thêm khi thấy thứ gì đó lệch, nhưng bug timing xuất hiện sau (đặc biệt với async và debounce). Khi người dùng báo “đôi khi selection bị xóa”, bạn có thể mất nhiều giờ để tái hiện.
Các dấu hiệu đỏ thường cho thấy thư viện đang đi vào rắc rối:
- Component chỉ hoạt động khi dùng theo đúng thứ tự props và events.
- Một composable đọc/ghi global state mà không rõ ràng.
- Nhiều watcher cập nhật cùng một piece state.
- Refactor liên tục phá consumer screens theo cách nhỏ.
- Người đóng góp tránh chạm “file đó” vì rủi ro.
Bẫy cuối là phá API công khai khi refactor. Trong app admin, component như table, filter và field lan rộng nhanh. Đổi tên prop, thay event hoặc tweak slot có thể âm thầm phá hàng chục màn hình.
Cách an toàn hơn là coi API component như hợp đồng: deprecate thay vì xóa, giữ shim tương thích một thời gian, và thêm test sử dụng đơn giản mount component như consumer. Nếu bạn sinh giao diện Vue 3 bằng công cụ như AppMaster, điều này càng quan trọng: hợp đồng component ổn định giúp tái sử dụng và giữ thay đổi dự đoán được.
Kiểm tra nhanh trước khi quyết kiểu
Trước khi chọn Composition API, Options API hoặc mix, làm vài kiểm tra nhanh trên component thật trong thư viện. Mục tiêu đơn giản: dễ tìm logic, tái sử dụng an toàn và test các phần admin quan trọng.
1) Có ai đó tìm logic nhanh không?
Mở một component admin tiêu biểu (filter + table + permissions + bulk actions). Giả vờ bạn là người mới.
Một dấu hiệu tốt là khi người đóng góp trả lời được “logic lọc ở đâu?” hoặc “cái gì quyết định nút bị disable?” trong dưới 2 phút. Với Options API, điều này nghĩa là logic rõ ràng phân chia trong computed, methods và watcher. Với Composition API, setup() được tổ chức thành các block nhỏ đặt tên (hoặc composables) và tránh hàm khổng lồ.
2) Các tiện ích chia sẻ hoạt động như hàm, không phải phép thuật?
Dù chọn pattern nào, code chia sẻ nên có input/output rõ và ít side effect. Nếu helper chạm vào global state, mutate object được truyền, hoặc trigger network call mà không rõ ràng, tái sử dụng trở nên rủi ro.
Kiểm tra nhanh:
- Bạn có đoán được signature của composable/helper là trả gì không?
- Bạn có dùng nó ở hai component mà không cần setup ẩn không?
- Bạn có reset được state trong test mà không cần hack không?
3) Test có tập trung vào hành vi admin không?
App admin thất bại theo kiểu có thể đoán: filter sai, phân quyền rò rỉ, form validate không nhất quán, trạng thái bảng hỏng sau edit.
Thay vì test chi tiết triển khai (watcher vs ref), viết test quanh hành vi: “role X thì action Y bị ẩn”, “save hiện lỗi và giữ input”, “thay filter cập nhật query và empty state”. Điều này giữ test ổn định ngay cả khi refactor giữa các style.
4) Bạn có chuẩn cho trạng thái async không?
Thư viện lớn sinh nhiều luồng async nhỏ: load options, validate field, fetch rows, retry. Nếu mỗi component nghĩ ra loading/error riêng, onboarding và debug chậm.
Chọn một hình dạng cho async state (loading, error, retries, cancel). Composition API thường khuyến khích useAsyncX() composable, trong khi Options API có thể chuẩn hóa data() và methods chung. Dù sao, điều quan trọng là đồng bộ.
5) API public component có ổn định và tự giải thích không?
Coi component như sản phẩm. Props, event và slots là hợp đồng. Nếu hợp đồng đó thay đổi thường xuyên, mọi màn hình admin trở nên dễ vỡ.
Tìm comment giải thích intent (không phải cơ chế): prop nghĩa là gì, event được đảm bảo khi nào, và gì là internal. Nếu bạn dùng AppMaster cho phần nội bộ, tư duy này giúp: khối xây dựng ổn định làm màn hình tương lai ship nhanh hơn.
Kịch bản ví dụ và bước tiếp theo cho team bạn
Hình dung một trang “Users” bạn xây lại: thanh lọc (status, role, created date), bảng có chọn hàng, hành động hàng loạt (disable, delete, export), và phân quyền theo role (chỉ admins bulk delete, managers có thể edit role).
Với Composition API vs Options API, UI giống nhau, nhưng code thường tổ chức khác.
Trong Options API, bạn thường có một component lớn với data cho filters và selection, computed cho state dẫn xuất, và methods cho fetch, bulk actions và kiểm tra phân quyền. Tái sử dụng thường xuất hiện dưới dạng mixins hoặc helper module. Nó quen thuộc, nhưng logic liên quan có thể rải rác (fetch trong methods, đồng bộ query trong watcher, permissions trong computed).
Trong Composition API, bạn thường tách page thành các composable tập trung: một cho query và filters, một cho selection/bulk actions, một cho permissions. Component page trở thành lắp ráp các phần này, và logic cho mỗi concern ở cùng chỗ. Chi phí là cần tên rõ và convention thư mục để người đóng góp không cảm thấy mọi thứ “ma thuật trong setup”.
Tái sử dụng thường xuất hiện quanh các pattern admin: lọc đồng bộ URL, mẫu bảng server-side (pagination, sorting, select-all, guard hành động hàng loạt), kiểm tra phân quyền và ẩn/hiện action, và trạng thái empty/loading đồng nhất qua các trang.
Kế hoạch bước tiếp theo phù hợp với hầu hết team:
- Chọn style mặc định cho code mới, và chỉ cho ngoại lệ khi có lý do ghi ra.
- Định conventions: nơi đặt composables, cách đặt tên, gì được import và gì phải return.
- Thêm trang tham khảo nhỏ (như Users) làm tiêu chuẩn cho pattern và cấu trúc.
- Viết test cho phần tái sử dụng trước (filters, permissions, bulk actions), không phải layout.
- Nếu tốc độ quan trọng hơn tuỳ chỉnh sâu cho vài màn hình, cân nhắc sinh các màn đó bằng công cụ no-code như AppMaster, rồi giữ thư viện viết tay tập trung vào phần thực sự đặc thù.
Nếu bạn đã dùng AppMaster, nó giúp giữ cùng mô hình: hợp đồng component ổn định, và logic chia sẻ gói trong các đơn vị nhỏ, rõ ràng. Với những team cân nhắc no-code cho nội bộ, AppMaster (appmaster.io) được xây để sinh ứng dụng đầy đủ (backend, web và mobile) mà vẫn cho phép chuẩn hóa UI Vue 3 nơi cần thiết.
Nếu chỉ làm một việc tuần này, hãy biến trang Users thành mẫu và ép áp dụng nó trong review code. Một ví dụ rõ ràng sẽ tốt hơn một style guide dài.
Câu hỏi thường gặp
Ưu tiên Composition API nếu thư viện của bạn có các hành vi lặp lại như lọc, phân trang, hành động hàng loạt và điều kiện phân quyền. Nó giúp tách logic chung thành các composable và làm cho phụ thuộc rõ ràng hơn. Dùng Options API khi component chủ yếu mang tính trình bày và logic nhẹ.
Options API gom code theo loại (data, methods, computed, watch), nên logic của một tính năng thường bị phân tán. Composition API thường gom code theo tính năng, vì vậy mọi thứ liên quan đến “lọc” hay “chọn hàng” có thể nằm cùng nhau. Lựa chọn tốt nhất là kiểu tổ chức khiến thay đổi tiếp theo dễ tìm và an toàn để áp dụng.
Với Options API, việc tái sử dụng thường bắt đầu bằng mixins hoặc extends, điều này có thể ẩn nguồn gốc của methods và computed và gây xung đột tên. Với Composition API, tái sử dụng thường là composable có input/output rõ ràng, nên wiring được hiển thị trong component. Đối với thư viện chia sẻ, cách tái sử dụng rõ ràng duy trì được lâu hơn.
Hãy coi mỗi composable như một API nhỏ: một nhiệm vụ, tham số rõ ràng và kết quả dự đoán được. Nếu một composable bắt đầu xử lý phân trang, cache, phân quyền và thông báo cùng lúc, hãy tách nó thành các phần nhỏ hơn. Composable nhỏ dễ test, dễ tái sử dụng và ít gây side effect bất ngờ.
Giữ hợp đồng công khai ổn định: props, event phát ra và slots hiếm khi thay đổi. Đặt format input và validate cơ bản gần các component input, nhưng giữ quy tắc nghiệp vụ ở composables hoặc container. Như vậy bạn có thể refactor nội bộ mà không buộc mọi màn hình phải thay đổi.
Composition API thường giúp unit test logic mà không cần mount toàn bộ component, vì bạn có thể test trực tiếp các composable và hàm thuần. Options API thường đẩy bạn tới các test mount component, nơi watcher và lifecycle có thể tạo nhiễu. Dù dùng kiểu nào, tách biệt quy tắc nghiệp vụ khỏi wiring UI là điều giúp test nhỏ và ổn định.
Chuẩn hóa một hình dạng cho trạng thái async như loading, error và cách retry/cancel rõ ràng. Đừng để mỗi component tự sáng tạo convention riêng, vì debug sẽ chậm và không đồng nhất. Cả hai API đều có thể hiện thực quy chuẩn này miễn là làm đồng đều trên toàn thư viện.
Options API có thể dễ tiếp cận ngày đầu vì cấu trúc quen thuộc, nhưng người mới có thể phải nối các mảnh logic rải rác. Composition API nhanh hơn khi họ đã hiểu composable và convention thư mục của bạn, vì hành vi liên quan được gom lại và việc tái sử dụng hiển nhiên. Onboarding cải thiện nhiều nhất khi bạn cung cấp một component “vàng” làm mẫu và bắt buộc pattern đó trong review.
Chọn một tính năng ranh giới rõ và có nhiều chỗ tái sử dụng (ví dụ lọc bảng hoặc mapping lỗi form) và coi đó như pilot. Tách một đơn vị chung với API nhỏ, viết test tập trung cho nó, rồi refactor một component end-to-end. Chỉ khi pattern hoạt động trên ít nhất hai component mới mở rộng áp dụng rộng hơn.
Dấu hiệu xấu gồm các bản sao gần giống bị phân tán, chuỗi watcher dài gây xung đột, và component chỉ hoạt động khi props/events theo một thứ tự chính xác. Nếu mọi người tránh sửa “file đó” vì rủi ro, đó là dấu hiệu bạn cần hợp đồng rõ ràng hơn và tái sử dụng có tính hiển thị.


