Chuyển đến nội dung chính

Bài 19: Technical Debt & Maintainability

Quản lý nợ kỹ thuật khi dùng Vibe Coding. GitClear data về code churn. Refactoring strategies. Dead code detection. Documentation generation. Architectural decisions. Long-term maintainability.

💻 Lập trình — Bài 19 Bài 19: Technical Debt & Maintainability

Vibe Coding với GitHub Copilot: Từ Cơ bản đến Nâng cao

Phần 6: Vibe Coding chuyên nghiệp — Quality, Security & Production

xdev.asia

1. Vibe Coding và Technical Debt

Vibe Coding tăng tốc viết code, nhưng nếu không cẩn thận sẽ tạo ra nợ kỹ thuật nhanh hơn bao giờ hết.

Dữ liệu từ GitClear (2025):

Metric Trước AI (2022) Sau AI (2025) Thay đổi
Code churn 3.3% 7.1% +115%
Lines added/dev/month 1,100 1,800 +64%
Lines deleted/dev/month 200 550 +175%
Moved/copy code 5% 11% +120%

Code churn = code viết ra rồi sửa hoặc xóa trong vòng 2 tuần. Con số tăng gấp đôi cho thấy AI tạo code chưa đúng ngay từ đầu.

2. Nguyên nhân Technical Debt từ Vibe Coding

2.1. Duplication — Code lặp

AI sinh code mới thay vì reuse:

// AI tạo helper function mới
function formatDate(date: Date): string {
  return date.toLocaleDateString('vi-VN');
}

// Mặc dù project đã có: // src/utils/date.ts → formatDate()

2.2. Inconsistency — Không nhất quán

// File A: AI dùng async/await
const data = await fetchUsers();

// File B: AI dùng .then() fetchUsers().then(data => { ... });

// File C: AI dùng callback fetchUsers((err, data) => { ... });

2.3. Over-abstraction — Phức tạp hóa

// AI hay tạo Factory + Strategy + Builder cho task đơn giản:
class TaskBuilderFactory {
  createBuilder(type: string): TaskBuilder {
    // 50 lines of over-engineering
  }
}

// Thực tế chỉ cần: function createTask(data: CreateTaskInput): Task { return prisma.task.create({ data }); }

3. Phát hiện Technical Debt

3.1. Dead code detection

// Dùng knip để tìm dead code:
npx knip

// Output: Unused files: src/utils/old-helper.ts Unused exports: TaskBuilderFactory (src/builders/task.ts) Unused dependencies: moment, lodash

3.2. Duplication detection

// Dùng jscpd:
npx jscpd src/

// Output: Found 12 clones across 8 files Total duplicated lines: 156 (8.3% of total)

3.3. Complexity analysis

// Dùng Copilot để phân tích:
@workspace Analyze cyclomatic complexity of all functions.
List functions with complexity > 10 and suggest refactoring.

4. Refactoring với AI

4.1. Extract duplicates

// Prompt:
I have similar date formatting logic in 5 files.
Extract into a shared utility module.
Show me which files to update and what to extract.

4.2. Simplify complex functions

// Prompt:
This function has 15 if-else branches.
Refactor using:
- Strategy pattern for different task types
- Early returns to reduce nesting
- Extract validation into separate function
Keep the same behavior, add tests to verify.

4.3. Standardize patterns

// Prompt:
Our codebase has inconsistent error handling:
- Some files use try/catch
- Some use .catch()
- Some don't handle errors at all

Standardize all API calls to use async/await with a shared error handler middleware. Show me the changes needed file by file.

5. Documentation Generation với AI

// Prompt cho API documentation:
Generate OpenAPI 3.0 spec for all endpoints in src/routes/.
Include request/response schemas, auth requirements,
and example values.

// Prompt cho code documentation:
Add JSDoc comments to all exported functions in src/services/.
Include parameter descriptions, return types, and usage examples.
Explain the business logic, not just the code.

Architecture Decision Records (ADR)

// Prompt:
Create an ADR for our decision to use Prisma ORM with PostgreSQL.
Include:
- Context: why we needed an ORM
- Options considered: Prisma, TypeORM, Knex, Drizzle
- Decision and rationale
- Consequences and trade-offs
Follow the format in docs/adr/template.md

6. Ngăn ngừa Technical Debt

6.1. Custom instructions cho consistency


## Code Consistency Rules
  • Use async/await for all asynchronous operations
  • Import from @/utils for shared utilities
  • Follow barrel export pattern (index.ts)
  • Error handling: use AppError class with status codes
  • Date formatting: use dayjs, never native Date methods
  • API responses: use { data, error, meta } format
  • Check existing utilities before creating new ones

6.2. Architecture guardrails

// eslint-plugin-boundaries — enforce architecture:
{
  "rules": {
    "boundaries/element-types": [2, {
      "default": "disallow",
      "rules": [
        // Controllers can import services, not other controllers
        { "from": "controllers", "allow": ["services", "types"] },
        // Services can import repositories, not controllers
        { "from": "services", "allow": ["repositories", "types"] },
      ]
    }]
  }
}

6.3. Regular debt sprints

// Dùng AI để plan refactoring sprint:
@workspace Analyze the codebase and identify:
1. Top 5 files with highest complexity
2. Most duplicated code patterns
3. Unused dependencies and dead exports
4. Files that violate our architecture boundaries
Prioritize by impact and create a refactoring plan.

7. Metrics theo dõi Technical Debt

Metric Tool Target
Code churn GitClear, git log analysis <5% trong 2 tuần
Duplication jscpd, SonarQube <3% total codebase
Dead code knip, ts-prune 0 unused exports
Complexity ESLint complexity rule Max 15 per function
Dependency freshness npm outdated, Renovate No major behind
Test coverage Jest coverage >80% overall

8. Tổng kết

Quy tắc vàng: Vibe Coding tốt khi bạn có thể đọc hiểu và maintain mọi dòng code AI sinh ra. Nếu bạn không hiểu code AI viết, đó là technical debt.

Chiến lược Công cụ
Prevention Custom instructions, architecture rules
Detection knip, jscpd, SonarQube, AI review
Resolution AI-assisted refactoring, debt sprints
Monitoring Metrics dashboard, CI/CD gates

Bài cuối: Vibe Coding trong Team & Production — enterprise adoption, CI/CD, collaboration, và tương lai của Vibe Coding.