Hầu hết hướng dẫn dùng AI coding đều lấy ví dụ từ một project mới toanh: tạo component từ đầu, viết function đơn giản, generate boilerplate. Nghe hay đấy — nhưng thực tế công việc của phần lớn developer không phải như vậy.
Thực tế là: bạn đang maintain một codebase React đã 3-4 năm tuổi. Hàng chục module. Business logic phức tạp chằng chịt. Custom hook viết từ hồi chưa có React Query. Component nào cũng liên quan đến component khác theo những cách không ai document lại. Và bạn vừa được giao một ticket yêu cầu thêm tính năng vào đúng cái module không ai dám đụng vào.
Dùng AI trong tình huống đó khác hoàn toàn so với greenfield project. Bài này là những gì mình đúc kết được sau khi thực sự dùng Claude trong môi trường đó — không phải demo, mà là production codebase thật.
Vấn đề cốt lõi: Context window vs Codebase size
Trước khi đi vào tips cụ thể, cần hiểu tại sao dùng AI với legacy codebase khó hơn project mới.
AI chỉ làm việc tốt trong phạm vi những gì bạn cung cấp cho nó. Với project mới, bạn dễ dàng paste toàn bộ code liên quan vào — chỉ vài file, vài trăm dòng. Nhưng với codebase lớn, một tính năng có thể liên quan đến 15 file khác nhau, 3 custom hook, 2 context provider, và một đống business rule nằm rải rác. Không thể paste hết vào một lần chat.

Vấn đề không phải AI không đủ giỏi — mà là AI không có đủ context để làm đúng. Toàn bộ các tips dưới đây đều xoay quanh một mục tiêu: cung cấp đúng context, đúng lúc, đúng cách.
Tip 1: Viết CLAUDE.md trước khi làm bất cứ thứ gì khác
Đây là tip quan trọng nhất — và cũng là thứ ít người làm nhất vì nghe có vẻ “không phải code”.
CLAUDE.md là file đặt ở root của project, Claude Code tự động đọc file này mỗi khi bắt đầu làm việc trong project. Đây là nơi bạn brief AI về toàn bộ context quan trọng — một lần, dùng mãi.

Với React codebase lớn, file này nên có:
# CLAUDE.md
## Tech stack
- React 18, TypeScript 5.x
- State management: Zustand (global), React Query v5 (server state)
- Styling: Tailwind CSS + shadcn/ui components
- Form: React Hook Form + Zod validation
- Router: React Router v6
## Cấu trúc thư mục
src/
features/ # Mỗi feature là một folder độc lập
orders/ # Ví dụ: module quản lý đơn hàng
components/ # Components chỉ dùng trong feature này
hooks/ # Custom hooks của feature
api/ # API calls và React Query hooks
types/ # TypeScript types
shared/ # Components/hooks dùng chung
store/ # Zustand stores
## Convention quan trọng
- Component: PascalCase, mỗi file một component
- Hook: bắt đầu bằng "use", camelCase
- API hook: bắt đầu bằng "use" + tên resource + action
Ví dụ: useOrderList, useOrderCreate, useOrderUpdate
- KHÔNG dùng class component, chỉ functional
- KHÔNG dùng default export với named component
## Business rules cần biết
- Order status flow: draft → pending → confirmed → shipping → delivered
- Chỉ admin role mới có thể cancel order ở status confirmed trở lên
- Price calculation luôn phải đi qua usePriceCalculation hook,
KHÔNG tính trực tiếp trong component
## Những thứ đang được refactor (cẩn thận)
- AuthContext đang được migrate sang Zustand auth store
- Tạm thời cả hai đang tồn tại song song, dùng Zustand store cho code mới
Mình estimate mỗi lần Claude đọc file này tiết kiệm khoảng 5-10 phút giải thích context lặp đi lặp lại. Với 20-30 lần tương tác mỗi ngày, con số đó không nhỏ.
Tip 2: Dùng “explain before touch” với code không quen
Với codebase lớn, bạn sẽ thường xuyên phải làm việc với module do người khác viết, hoặc code cũ của chính mình nhưng đã quên mất logic. Trước khi nhờ AI sửa gì đó, hãy cho nó đọc và giải thích trước.
Pattern mình hay dùng:
// Paste code vào, sau đó hỏi:
"Đọc đoạn code này và giải thích:
1. Component này làm gì, nhận props nào
2. Side effects nào đang xảy ra và khi nào
3. Dependencies quan trọng — nó đang dùng gì từ bên ngoài
4. Điểm nào trong code này dễ gây bug nhất nếu sửa"
Câu hỏi số 4 quan trọng nhất — nó buộc AI phải phân tích risk trước khi bạn đặt tay vào. Với code phức tạp, AI thường chỉ ra những dependency ẩn mà chính bạn không nhận ra khi đọc lướt.
Một biến thể hữu ích khác:
"Hook này có những edge case nào không được handle?
Nếu tôi cần thêm feature X vào đây, phần nào cần thay đổi
và phần nào có thể bị ảnh hưởng ngoài ý muốn?"
Tip 3: Provide context theo tầng — Đừng paste tất cả một lúc
Sai lầm phổ biến nhất: paste 10 file vào một lúc và hỏi “sửa feature này cho tôi”. AI sẽ cố gắng — nhưng với quá nhiều context, nó khó tập trung vào đúng phần quan trọng.
Cách làm tốt hơn là cung cấp context theo 3 tầng:
- Tầng 1 — Business context: Mô tả bằng lời tính năng đang cần làm, user flow, business rule liên quan. Không cần code ở bước này.
- Tầng 2 — Architecture context: Paste interface/type definitions và API contracts — những thứ define “hình dạng” của data. Thường chỉ vài chục dòng nhưng cung cấp rất nhiều context.
- Tầng 3 — Implementation context: Paste code cụ thể của phần cần sửa — và chỉ phần đó thôi.
Ví dụ thực tế khi thêm tính năng filter vào order list:
// Tầng 1 - Business context (nói bằng lời):
"Tôi cần thêm filter theo date range và status vào OrderList.
User chọn filter → URL params được update → list reload với data mới.
Filter phải persist khi user reload trang."
// Tầng 2 - Types (paste types/interfaces):
interface Order { id: string; status: OrderStatus; createdAt: Date; ... }
type OrderStatus = 'draft' | 'pending' | 'confirmed' | 'shipping' | 'delivered'
interface OrderFilterParams { status?: OrderStatus; dateFrom?: string; dateTo?: string }
// Tầng 3 - Code cụ thể (paste hook hiện tại):
// [paste useOrderList hook]
// Sau đó hỏi: "Sửa hook này để nhận OrderFilterParams và sync với URL"
Tip 4: Dùng AI để viết test trước khi refactor
Đây là use case mà AI thực sự tỏa sáng với legacy code — và thường bị bỏ qua.
Khi cần refactor một đoạn code cũ phức tạp, bước đầu tiên không phải là sửa code — mà là viết test để capture behavior hiện tại. Nếu test pass sau khi refactor, bạn biết mình không phá gì. Nếu fail, bạn biết chính xác phần nào bị ảnh hưởng.

Với legacy code, viết test thủ công tốn rất nhiều thời gian vì phải đọc hiểu hết business logic. AI làm việc này rất tốt:
"Đây là custom hook usePriceCalculation của project mình:
[paste hook]
Project dùng Vitest + React Testing Library.
Hãy viết test coverage cho tất cả các case:
1. Happy path với các input hợp lệ
2. Edge case: quantity = 0, discount > 100%, null values
3. Business rule: discount chỉ áp dụng khi total > 500k
Đừng mock những gì không cần thiết."
Sau khi có test, refactor thoải mái — AI đã capture behavior của code cũ, bạn chỉ cần đảm bảo test vẫn xanh.
Tip 5: Nhờ AI tạo “impact analysis” trước mỗi thay đổi lớn
Với codebase lớn, sửa một chỗ hay ảnh hưởng đến 5 chỗ khác theo những cách không ngờ tới. Trước khi commit bất kỳ thay đổi nào đáng kể, mình có thói quen nhờ Claude phân tích impact:
"Tôi muốn thay đổi signature của useAuth hook từ:
{ user, isLoading }
sang:
{ user, isLoading, permissions }
Đây là danh sách files đang import useAuth:
[paste list files hoặc grep result]
Hãy phân tích:
1. Files nào bị ảnh hưởng trực tiếp (cần update ngay)
2. Files nào có thể bị ảnh hưởng gián tiếp
3. Breaking changes nào cần xử lý
4. Thứ tự migration an toàn nhất"
Kết hợp với output của lệnh grep/ripgrep để tìm nơi đang dùng hook:
rg "useAuth" src/ --type ts --type tsx -l
Paste kết quả đó vào chat — AI có danh sách file chính xác để phân tích, không cần đoán mò.
Tip 6: Dùng AI để “decode” business logic ẩn trong code
Legacy codebase hay có một loại code đặc biệt: business rule được encode thẳng vào code mà không có comment nào giải thích tại sao. Những magic number, conditional chain kỳ lạ, hay validation logic không rõ nguồn gốc.
// Đoạn code này làm gì và tại sao?
if (order.status === 'confirmed' &&
differenceInHours(new Date(), order.confirmedAt) < 2 &&
!order.items.some(item => item.type === 'digital') &&
order.paymentMethod !== 'bank_transfer') {
showCancelButton = true
}
Nhờ AI giải thích:
"Đoạn code này đang check điều kiện gì để hiện nút cancel?
Hãy diễn giải thành business rule dạng plain text,
sau đó suggest cách refactor để readable hơn —
nhưng KHÔNG thay đổi logic, chỉ restructure."
Output thường là một đoạn comment rõ ràng và code được refactor thành function có tên descriptive như canCancelOrder(order) — thứ mà code review sẽ cảm ơn bạn.
Tip 7: Pattern “Stranger in a codebase” cho onboarding nhanh
Khi bạn được assign vào một module chưa bao giờ làm — hoặc khi join team mới và cần hiểu nhanh codebase — hãy dùng AI theo pattern này:
// Bước 1: Cho AI xem cấu trúc thư mục
"Đây là cấu trúc thư mục của module Orders:
[paste tree output]
Hãy giải thích mối quan hệ giữa các folder và
đây khả năng là feature-based hay layer-based architecture?"
// Bước 2: Cho AI xem entry point
"Đây là file index.tsx của module:
[paste code]
File này orchestrate gì và data flow trông như thế nào?"
// Bước 3: Deep dive vào phần cần làm
"Tôi cần thêm feature X vào module này.
Dựa trên những gì đã biết, file nào tôi cần đọc trước tiên
và tôi nên bắt đầu từ đâu?"
3 bước này thường đủ để mình có mental model tốt về một module mới trong 30-45 phút — thay vì mất nửa ngày đọc code lần lượt từng file.
Tip 8: Giao việc theo “slice” nhỏ, không phải feature lớn
Với codebase phức tạp, prompt kiểu “implement toàn bộ feature X” hiếm khi cho ra kết quả dùng được trực tiếp — vì AI không có đủ context để làm đúng toàn bộ.
Thay vào đó, chia nhỏ feature thành các “slice” độc lập và xử lý từng cái:
// ❌ Prompt quá rộng:
"Implement feature export order list ra Excel"
// ✅ Chia thành slices:
// Slice 1: Types và interface
"Define TypeScript types cho export config:
columns nào được export, format nào, filter nào được apply"
// Slice 2: Custom hook
"Viết useOrderExport hook nhận ExportConfig,
gọi API endpoint /api/orders/export,
handle loading/error state và trigger file download"
// Slice 3: UI component
"Viết ExportButton component dùng useOrderExport hook vừa tạo,
có dropdown chọn format (xlsx/csv), disable khi đang export"
// Slice 4: Integration
"Integrate ExportButton vào OrderList header,
đảm bảo nó nhận đúng filter params đang active"
Mỗi slice nhỏ, AI có đủ context, output chất lượng cao hơn. Và quan trọng hơn: bạn review và hiểu từng phần trước khi tiếp tục — không có kiểu “AI generate xong mình paste vào không biết nó làm gì”.
Tip 9: Dùng AI để document — Ngay khi bạn đang hiểu code
Thời điểm tốt nhất để document là ngay sau khi bạn hiểu một đoạn code phức tạp — còn fresh trong đầu. Nhưng lúc đó bạn thường đang bận implement tiếp, không có thời gian viết doc.
Workflow mình hay dùng: sau khi AI giải thích một đoạn code và mình đã hiểu, mình hỏi thêm:
"Dựa trên những gì chúng ta vừa thảo luận về hook này,
hãy viết JSDoc comment đầy đủ bao gồm:
- Mô tả purpose của hook
- Giải thích từng parameter
- Return values và type của chúng
- Ít nhất 2 ví dụ sử dụng
- Những edge case hoặc gotcha quan trọng"

5 phút để paste vào code và commit. Người tiếp theo làm việc với file đó — kể cả là chính bạn 3 tháng sau — sẽ cảm ơn.
Tip 10: Thiết lập Project trong Claude để không nhắc lại context
Nếu bạn đang dùng Claude.ai, tính năng Projects cho phép bạn upload tài liệu và đặt custom instructions áp dụng cho toàn bộ conversation trong project. Đây là phiên bản “cloud” của CLAUDE.md.
Những thứ nên upload vào Claude Project:
- Architecture decision records (ADR): những quyết định kỹ thuật quan trọng và lý do — giúp AI hiểu tại sao code lại được viết theo cách đó
- API documentation: schema của backend API mà frontend đang consume
- Component library docs: danh sách components có sẵn trong design system của project
- Coding conventions: những rule không có trong lint config nhưng team đang follow
Custom instructions nên bao gồm tech stack, naming convention, và những “không được làm” cụ thể — ví dụ “không dùng any trong TypeScript”, “không tự tạo component mới nếu đã có trong /shared”.
Tổng kết — Checklist khi dùng AI với legacy codebase
Mỗi lần bắt đầu một task mới với AI trong codebase lớn, mình chạy qua checklist này:
- ☐ CLAUDE.md đã có đủ context về tech stack, convention, business rule chưa?
- ☐ Giải thích business context trước khi paste code
- ☐ Paste types/interfaces làm tầng context trung gian
- ☐ Nhờ AI giải thích code cũ trước khi nhờ sửa
- ☐ Viết test trước khi refactor đoạn code quan trọng
- ☐ Chia feature thành slices nhỏ, không giao một lần
- ☐ Chạy impact analysis trước thay đổi lớn
- ☐ Document ngay khi hiểu xong, không để sau
Không phải lúc nào cũng cần đủ 8 bước — task nhỏ thì skip được vài cái. Nhưng với task phức tạp hoặc module chưa quen, bỏ qua bất kỳ bước nào thường sẽ tốn thời gian sửa sai nhiều hơn là tiết kiệm được.
Điều mình thấy rõ nhất sau khi áp dụng những thứ này: thời gian “hiểu code” giảm đi đáng kể, thời gian “implement” tăng lên tương ứng. Và đó là ratio đúng — developer giỏi không phải người gõ code nhanh, mà là người hiểu đúng trước khi gõ.
Chúc anh em code vui! 🚀
Tags: #claude #claudecode #aicoding #reactjs #legacy #refactor #typescript #tips #developer
Hầu hết hướng dẫn dùng AI coding đều lấy ví dụ từ một project mới toanh: tạo component từ đầu, viết function đơn giản, generate boilerplate. Nghe hay đấy — nhưng thực tế công việc của phần lớn developer không phải như vậy.
Thực tế là: bạn đang maintain một codebase React đã 3-4 năm tuổi. Hàng chục module. Business logic phức tạp chằng chịt. Custom hook viết từ hồi chưa có React Query. Component nào cũng liên quan đến component khác theo những cách không ai document lại. Và bạn vừa được giao một ticket yêu cầu thêm tính năng vào đúng cái module không ai dám đụng vào.