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

7.7 KiB
Raw Blame History

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
Maintainability
Code Maintainability
Software Sustainability
none A 0.9 applied
software-quality
maintainability
refactoring
technical-debt
code-quality
2026-05-10 pending
language framework
TypeScript 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

// 매 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

🤖 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