7.7 KiB
7.7 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-유지보수성-maintainability | 유지보수성(Maintainability) | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
유지보수성(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.
매 응용
- Code review checklist.
- Refactoring prioritization (의 churn × complexity).
- Technical debt tracking (Jira label, CODEOWNERS).
- Onboarding speed (의 maintainability 의 의 의 ramp-up time).
💻 패턴
SRP (Single Responsibility) refactor
// 매 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)
// 매 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)
# 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)
{
"rules": {
"complexity": ["error", { "max": 10 }],
"max-lines-per-function": ["warn", { "max": 50, "skipComments": true }],
"max-depth": ["warn", 3]
}
}
Churn × complexity heatmap
# 매 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)
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")
// 매 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 |