Files
2nd/10_Wiki/Topics/AI_and_ML/유지보수성(Maintainability).md
T
2026-05-10 22:08:15 +09:00

229 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: wiki-2026-0508-유지보수성-maintainability
title: 유지보수성(Maintainability)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Maintainability, Code Maintainability, Software Sustainability]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [software-quality, maintainability, refactoring, technical-debt, code-quality]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: TypeScript
framework: General
---
# 유지보수성(Maintainability)
## 매 한 줄
> **"매 code 의 written once 의 의 — 의 read 100x, modified 10x 의 의."**. 매 maintainability 의 의 future-self / future-team 의 의 cost 의 의 — 의 readability + modularity + testability + documentation 의 의 composite quality. 매 2026 의 의 LLM-assisted maintenance (Claude Code, Cursor) 의 의 의 well-structured code 의 의 의 의 — 의 LLM 의 의 fast & accurate refactor.
## 매 핵심
### 매 maintainability 의 dimension
- **Readability**: 의 명확한 이름 의 의 SRP, low cyclomatic complexity (< 10).
- **Modularity**: high cohesion, low coupling — module boundary 의 의.
- **Testability**: pure function 의 의, dependency injection, deterministic.
- **Documentation**: ADR (architecture decision record), inline 의 "why" comment.
- **Observability**: structured logging, tracing, metric — 의 production 의 의 의 의.
### 매 metric (proxy)
- **Cyclomatic complexity**: < 10 per function (radon, eslint complexity rule).
- **Lines per function**: < 50 (의 의 split).
- **Test coverage**: > 70% line, > 60% branch.
- **PR review time**: < 24h (proxy for code clarity).
- **Bus factor**: ≥ 2 reviewer per module.
### 매 응용
1. Code review checklist.
2. Refactoring prioritization (의 churn × complexity).
3. Technical debt tracking (Jira label, CODEOWNERS).
4. Onboarding speed (의 maintainability 의 의 의 ramp-up time).
## 💻 패턴
### SRP (Single Responsibility) refactor
```ts
// 매 BAD: 의 function 의 의 do everything
async function processOrder(orderId: string) {
const order = await db.orders.findOne({ id: orderId });
if (!order) throw new Error('not found');
const tax = order.items.reduce((s, i) => s + i.price * 0.1, 0);
const total = order.items.reduce((s, i) => s + i.price, 0) + tax;
await stripe.charge(order.userId, total);
await sendgrid.send({ to: order.email, subject: 'Receipt', body: `...${total}` });
return total;
}
// 매 GOOD: composed of single-responsibility units
async function processOrder(orderId: string): Promise<number> {
const order = await fetchOrder(orderId);
const total = computeTotal(order);
await chargePayment(order.userId, total);
await sendReceipt(order.email, total);
return total;
}
```
### Dependency injection (testability)
```ts
// 매 BAD: hard dependency
class UserService {
async create(email: string) {
const user = await prisma.user.create({ data: { email } });
await sendgrid.send({ to: email }); // 의 untestable
}
}
// 매 GOOD: inject
interface Mailer { send(msg: { to: string }): Promise<void>; }
interface UserRepo { create(data: { email: string }): Promise<User>; }
class UserService {
constructor(private repo: UserRepo, private mailer: Mailer) {}
async create(email: string) {
const user = await this.repo.create({ email });
await this.mailer.send({ to: email });
return user;
}
}
// 매 test 의 의
const fakeMailer = { send: vi.fn() };
const fakeRepo = { create: async (d) => ({ id: '1', ...d }) };
new UserService(fakeRepo, fakeMailer).create('a@b.com');
```
### ADR (Architecture Decision Record)
```markdown
# ADR-0042: 매 PostgreSQL 의 의 (vs MongoDB)
## Status
Accepted — 2026-04-15
## Context
주문 의 nested item, 다대다 user-org 관계 의 transaction.
## Decision
PostgreSQL 16 + Prisma 의 의.
## Consequences
- (+) Strong consistency, mature ecosystem
- (+) JSONB 의 의 flexibility 의 의
- (-) Sharding 의 의 application-level
- (-) Horizontal scale 의 의 read replica 의 의
```
### Module boundary (hexagonal-ish)
```
src/
├── domain/ # 매 pure business logic, 의 framework dep
│ ├── user.ts
│ └── order.ts
├── application/ # 매 use case (orchestration)
│ └── checkout.ts
├── infrastructure/ # 매 DB / HTTP / queue adapter
│ ├── prisma-user-repo.ts
│ └── stripe-payment.ts
└── interface/ # 매 HTTP / gRPC controller
└── http-routes.ts
```
### Cyclomatic complexity check (eslint)
```json
{
"rules": {
"complexity": ["error", { "max": 10 }],
"max-lines-per-function": ["warn", { "max": 50, "skipComments": true }],
"max-depth": ["warn", 3]
}
}
```
### Churn × complexity heatmap
```bash
# 매 git 의 의 churn 의 의 의 의 file 의 의
git log --since="6 months ago" --name-only --pretty=format: \
| sort | uniq -c | sort -rn | head -20
# 매 의 의 의 file 의 의 cyclomatic complexity 의 의
npx complexity-report-cli src/
# → churn high + complexity high 의 의 의 refactor 의 의
```
### Structured logging (observability)
```ts
import pino from 'pino';
const log = pino({ level: process.env.LOG_LEVEL ?? 'info' });
async function checkout(userId: string, cartId: string) {
log.info({ userId, cartId, op: 'checkout.start' });
try {
const result = await processOrder(cartId);
log.info({ userId, cartId, total: result.total, op: 'checkout.ok' });
return result;
} catch (e) {
log.error({ userId, cartId, err: e, op: 'checkout.fail' });
throw e;
}
}
```
### "Why" comment (의 "what")
```ts
// 매 BAD: 의 의 의 의
// increment counter
counter++;
// 매 GOOD: explains why
// 매 retry budget exhausted — fall through to dead-letter queue
// (의 spec § 3.2: retries are best-effort, not guaranteed)
counter++;
if (counter > MAX_RETRIES) await dlq.send(msg);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Greenfield project | Hexagonal boundary + ADR from day 1 |
| Legacy refactor | Strangler fig pattern + churn-driven priority |
| Hot path optimization | Profile first, complexity budget 매 micro-optimization 의 |
| Team < 5 | Lightweight (README + inline comments) |
| Team > 20 | ADR + CODEOWNERS + module ownership |
| AI-assisted maintenance | Type-strict + test-rich (의 LLM 의 의 verify) |
**기본값**: SRP + DI + ADR + structured log + eslint complexity rule + 70% test coverage.
## 🔗 Graph
- 부모: [[Software_Engineering]] · [[Code_Quality]]
- 변형: [[Refactoring]] · [[Clean_Architecture]] · [[Hexagonal_Architecture]]
- 응용: [[Technical_Debt]] · [[ADR]] · [[Code_Review]]
- Adjacent: [[Testability]] · [[Observability]] · [[Onboarding]]
## 🤖 LLM 활용
**언제**: refactor proposal (extract function, rename), ADR draft, complexity review, test scaffold.
**언제 X**: subjective architectural call (의 team consensus 의 의), legacy domain knowledge (의 인터뷰 의 의).
## ❌ 안티패턴
- **God class / God function**: 의 1000-line 의 의 — split.
- **Premature abstraction**: 매 1 use case 의 의 abstract base class — YAGNI.
- **Comment 의 의 의 stale**: code 의 의 의 의 의 — 의 의 의 의 의 의 wrong 의 의.
- **Circular dependency**: module A → B → A — refactor 의 의.
- **Missing tests on critical path**: payment, auth — 의 coverage > 90%.
- **Mutable global state**: 매 untestable, 의 reasoning 의 의.
## 🧪 검증 / 중복
- Verified (Martin Fowler refactoring catalog, Clean Architecture by Uncle Bob, Google Engineering Practices, ISO/IEC 25010).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — maintainability dimensions + patterns |