옵션
집 Skill 개발자 도구 deprecation-and-migration

deprecation-and-migration

addyosmani/agent-skills addyosmani/agent-skills

구형 시스템, API 또는 기능을 단계적으로 폐지하고 사용자를 대체 솔루션으로 이전하는 과정을 안내하며, 여기에는 의사결정 프레임워크, 마이그레이션 패턴 및 제거 전략이 포함됩니다.

...모든 것을 확장하십시오
23
업데이트 된 시간 2026년 9월 3일

사용 중단 및 마이그레이션

개요

코드는 자산이 아니라 부담입니다. 코드의 모든 줄에는 수정해야 할 버그, 업데이트해야 할 종속성, 적용해야 할 보안 패치, 그리고 새로 합류하는 엔지니어 교육 등 지속적인 유지보수 비용이 따릅니다. 사용 중단은 더 이상 그 가치를 입증하지 못하는 코드를 제거하는 체계적인 절차이며, 마이그레이션은 사용자를 기존 환경에서 새로운 환경으로 안전하게 이동시키는 과정입니다.

대부분의 엔지니어링 조직은 무언가를 구축하는 데는 능숙하지만, 이를 제거하는 데는 서툰 경우가 많습니다. 이 기술은 바로 그 격차를 해소합니다.

사용 시점

  • 기존 시스템, API 또는 라이브러리를 새로운 것으로 교체할 때
  • 더 이상 필요하지 않은 기능을 단계적으로 폐지할 때
  • 중복된 구현 통합
  • 누구도 책임지지 않지만 모두가 의존하는 사멸된 코드 제거
  • 새로운 시스템의 수명 주기 계획 수립 (사용 중단 계획은 설계 단계부터 시작됩니다)
  • 레거시 시스템을 유지 관리할지, 아니면 마이그레이션에 투자할지 결정하기

핵심 원칙

코드는 부담이다

코드의 모든 줄에는 지속적인 비용이 발생합니다. 테스트, 문서화, 보안 패치, 의존성 업데이트가 필요할 뿐만 아니라, 주변에서 작업하는 모든 사람에게 정신적 부담도 줍니다. 코드의 가치는 코드 자체가 아니라, 그것이 제공하는 기능에 있습니다. 더 적은 코드, 더 낮은 복잡도, 또는 더 나은 추상화를 통해 동일한 기능을 제공할 수 있다면, 기존 코드는 제거되어야 합니다.

하이럼의 법칙은 제거를 어렵게 만든다

사용자가 충분히 많아지면, 버그, 타이밍상의 특이점, 문서화되지 않은 부작용 등 관찰 가능한 모든 동작에 의존하게 됩니다. 이것이 바로 기능 중단이 단순한 공지뿐만 아니라 적극적인 마이그레이션을 필요로 하는 이유입니다. 사용자는 대체 솔루션이 재현하지 못하는 동작에 의존하고 있을 때 “그냥 전환”할 수 없습니다.

사용 중단 계획은 설계 단계에서 시작된다

새로운 것을 구축할 때, “3년 후에 이 기능을 어떻게 제거할 것인가?”라고 자문해 보십시오. 깔끔한 인터페이스, 기능 플래그, 최소한의 노출 면적을 갖춘 시스템은 구현 세부 사항이 사방에 노출된 시스템보다 사용 중단 처리가 더 쉽습니다.

사용 중단 결정

무언가를 비추천하기 전에 다음 질문에 답하십시오:

1. 이 시스템이 여전히 독창적인 가치를 제공합니까?
   → 그렇다면 유지 관리하십시오. 그렇지 않다면 진행하십시오.

2. 이 시스템에 의존하는 사용자/소비자는 몇 명인가?
   → 마이그레이션 범위를 정량화하십시오.

3. 대체 솔루션이 존재하는가?
   → 없다면, 먼저 대체 솔루션을 구축하십시오. 대안이 없는 상태에서 비추천 처리하지 마십시오.

4. 각 소비자에 대한 마이그레이션 비용은 얼마인가?
   → 자동화가 간단하다면 진행하십시오. 수동 작업이고 많은 노력이 필요하다면 유지보수 비용과 비교해 보십시오.

5. 사용 중단을 하지 않을 경우 지속적인 유지보수 비용은 얼마입니까?
   → 보안 위험, 엔지니어의 시간, 복잡성으로 인한 기회 비용.

의무적 비추천 vs 권고적 비추천

유형 사용 시점 메커니즘
권고형 마이그레이션은 선택 사항이며, 기존 시스템은 안정적임 경고, 문서 제공, 권장 조치. 사용자는 본인의 일정에 따라 마이그레이션합니다.
의무적 기존 시스템에 보안 문제가 있거나, 발전을 저해하거나, 유지보수 비용이 감당할 수 없는 수준인 경우 확정된 마감일. 기존 시스템은 X일까지 제거됩니다. 마이그레이션 도구를 제공합니다.

기본적으로 권고 방식으로 진행합니다. 유지보수 비용이나 위험이 마이그레이션을 강제할 만한 타당한 사유가 있을 때만 강제 방식을 사용합니다. 강제 중단 시에는 마이그레이션 도구, 문서 및 지원을 제공해야 하며, 단순히 마감일만 공지해서는 안 됩니다.

마이그레이션 프로세스

1단계: 대체 시스템 구축

작동 가능한 대체 시스템이 없으면 사용 중단을 선언하지 마십시오. 대체 시스템은 다음 요건을 충족해야 합니다:

  • 기존 시스템의 모든 핵심 사용 사례를 포괄해야 합니다
  • 문서 및 마이그레이션 가이드가 구비되어 있어야 함
  • 실제 운영 환경에서 검증되어야 합니다(단순히 “이론적으로 더 낫다”는 수준이 아님)

2단계: 공지 및 문서화

## 사용 중단 공지: OldService

**상태:** 2025-03-01부로 사용 중단됨
**대체 서비스:** NewService (아래 마이그레이션 가이드 참조)
**제거 예정일:** 권고 사항 — 아직 확정된 기한 없음
**이유:** OldService는 수동 확장이 필요하며 가시성이 부족합니다.
            NewService는 이 두 가지를 모두 자동으로 처리합니다.

### 마이그레이션 가이드
1. `import { client } from 'old-service'`를 `import { client } from 'new-service'`로 교체하세요.
2. 구성을 업데이트하세요(아래 예시 참조).
3. 마이그레이션 검증 스크립트를 실행하세요: `npx migrate-check`

3단계: 점진적으로 마이그레이션하기

모든 소비자 애플리케이션을 한꺼번에 마이그레이션하지 말고, 하나씩 순차적으로 마이그레이션하십시오. 각 소비자 애플리케이션에 대해:

1. 더 이상 사용되지 않는 시스템과의 모든 접점을 파악하세요.
2. 대체 시스템을 사용하도록 업데이트하세요.
3. 동작이 일치하는지 확인하세요(테스트, 통합 점검).
4. 기존 시스템에 대한 참조를 제거하세요.
5. 회귀 현상이 없는지 확인하세요.

‘이탈(Churn) 규칙’: 사용 중단되는 인프라를 소유하고 있다면, 사용자를 마이그레이션하거나 마이그레이션이 필요 없는 하위 호환성 업데이트를 제공하는 책임이 있습니다. 사용 중단을 공지한 후 사용자에게 해결 방법을 맡겨서는 안 됩니다.

4단계: 기존 시스템 제거

모든 사용자가 마이그레이션을 완료한 후에만 다음 단계를 진행하십시오:

1. 활성 사용이 전혀 없는지 확인합니다(메트릭, 로그, 종속성 분석).
2. 코드를 제거합니다.
3. 관련 테스트, 문서 및 구성을 제거합니다.
4. 사용 중단 알림을 제거합니다.
5. 축하합니다 — 코드를 제거하는 것은 하나의 성과입니다.

마이그레이션 패턴

스트랭글러 패턴

기존 시스템과 새 시스템을 병행하여 운영합니다. 트래픽을 기존 시스템에서 새 시스템으로 점진적으로 전환합니다. 기존 시스템이 처리하는 트래픽 비율이 0%가 되면 시스템을 제거합니다.

1단계: 신규 시스템 처리량 0%, 기존 시스템 처리량 100%
2단계: 신규 시스템 처리량 10% (카나리아 테스트)
3단계: 신규 시스템 처리량 50%
4단계: 신규 시스템 처리량 100%, 기존 시스템 유휴 상태
5단계: 기존 시스템 제거

어댑터 패턴

기존 인터페이스의 호출을 새로운 구현체로 변환하는 어댑터를 생성합니다. 백엔드를 마이그레이션하는 동안 소비자는 기존 인터페이스를 계속 사용합니다.

// 어댑터: 기존 인터페이스, 새로운 구현
class LegacyTaskService implements OldTaskAPI {
  constructor(private newService: NewTaskService) {}

  // 기존 메서드 시그니처, 새로운 구현체로 위임
  getTask(id: number): OldTask {
    const task = this.newService.findById(String(id));
    return this.toOldFormat(task);
  }
}

기능 플래그 마이그레이션

피처 플래그를 사용하여 소비자를 하나씩 기존 시스템에서 새 시스템으로 전환하세요:

function getTaskService(userId: string): TaskService {
  if (featureFlags.isEnabled('new-task-service', { userId })) {
    return new NewTaskService();
  }
  return new LegacyTaskService();
}

좀비 코드

좀비 코드란 누구도 책임지지 않지만 모두가 의존하고 있는 코드를 말합니다. 적극적으로 유지 관리되지 않고, 명확한 소유자가 없으며, 보안 취약점과 호환성 문제가 누적됩니다. 징후:

  • 6개월 이상 커밋이 없으나 해당 코드를 사용하는 활성 소비자가 존재함
  • 담당 유지보수자나 팀이 지정되지 않음
  • 아무도 수정하지 않는 테스트 실패
  • 알려진 취약점이 있는 종속 라이브러리가 있으나 아무도 업데이트하지 않음
  • 더 이상 존재하지 않는 시스템을 참조하는 문서

대응 방안: 소유자를 지정하여 적절히 유지 관리하거나, 구체적인 마이그레이션 계획을 세워 해당 기능을 단계적으로 폐지하십시오. 좀비 코드는 방치된 상태로 남아 있을 수 없습니다. 투자를 받거나 제거되어야 합니다.

흔히 있는 변명

변명 현실
"아직도 작동하는데, 왜 제거해야 하나요?" 아무도 유지보수하지 않는 작동하는 코드는 보안 부채와 복잡성을 축적합니다. 유지보수 비용은 눈에 띄지 않게 증가합니다.
"나중에 누군가에게 필요할지도 몰라" 나중에 필요해지면 다시 만들면 됩니다. ‘혹시 모르니’라는 이유로 사용하지 않는 코드를 보관하는 것은 다시 만드는 것보다 더 많은 비용이 듭니다.
"마이그레이션 비용이 너무 많이 든다" 마이그레이션 비용을 향후 2~3년 동안의 지속적인 유지보수 비용과 비교해 보세요. 장기적으로 보면 마이그레이션이 대개 더 저렴합니다.
"새 시스템을 완성한 후에 이 기능을 단계적으로 폐지할 겁니다" 사용 중단 계획은 설계 단계부터 시작됩니다. 새 시스템이 완성될 때쯤이면 새로운 우선순위가 생길 것입니다. 지금부터 계획을 세우세요.
"사용자들이 스스로 마이그레이션할 것이다" 그렇지 않을 것입니다. 도구, 문서, 인센티브를 제공하거나, 직접 마이그레이션을 수행하십시오(이탈 규칙).
"두 시스템을 무기한으로 모두 유지 관리할 수 있습니다" 동일한 기능을 수행하는 두 시스템은 유지보수, 테스트, 문서화, 온보딩 비용을 두 배로 늘립니다.

주의 신호

  • 대체 수단이 없는 사용 중단 예정 시스템
  • 마이그레이션 도구나 문서가 없는 지원 종료 공지
  • 수년간 권고 사항으로만 남아 진전이 없는 ‘부드러운’ 사용 중단
  • 관리자가 없고 여전히 사용 중인 ‘좀비 코드’
  • 사용 중단된 시스템에 새로운 기능이 추가된 경우 (대신 대체 시스템에 투자해야 함)
  • 현재 사용량을 측정하지 않은 채로 사용 중단
  • 활성 사용자가 전혀 없는지 확인하지 않고 코드를 제거하는 경우

검증

사용 중단 절차 완료 후:

  • 대체 시스템이 실제 운영 환경에서 검증되었으며 모든 핵심 사용 사례를 포괄해야 함
  • 구체적인 단계와 예시가 포함된 마이그레이션 가이드가 마련되어 있음
  • 모든 활성 소비자가 마이그레이션되었습니다(메트릭/로그를 통해 확인됨)
  • 기존 코드, 테스트, 문서 및 구성 항목이 완전히 제거되었습니다
  • 코드베이스에 더 이상 사용 중단된 시스템에 대한 참조가 남아 있지 않습니다
  • 사용 중단 알림이 제거되었습니다(이미 그 역할을 다했기 때문입니다).
GitHub에서 보기
---
name: deprecation-and-migration
description: Guides the process of deprecating old systems, APIs, or features and migrating users to replacements, including decision frameworks, migration patterns, and removal strategies.
---

# Deprecation and Migration

## Overview

Code is a liability, not an asset. Every line of code has ongoing maintenance cost — bugs to fix, dependencies to update, security patches to apply, and new engineers to onboard. Deprecation is the discipline of removing code that no longer earns its keep, and migration is the process of moving users safely from the old to the new.

Most engineering organizations are good at building things. Few are good at removing them. This skill addresses that gap.

## When to Use

- Replacing an old system, API, or library with a new one
- Sunsetting a feature that's no longer needed
- Consolidating duplicate implementations
- Removing dead code that nobody owns but everybody depends on
- Planning the lifecycle of a new system (deprecation planning starts at design time)
- Deciding whether to maintain a legacy system or invest in migration

## Core Principles

### Code Is a Liability

Every line of code has ongoing cost: it needs tests, documentation, security patches, dependency updates, and mental overhead for anyone working nearby. The value of code is the functionality it provides, not the code itself. When the same functionality can be provided with less code, less complexity, or better abstractions — the old code should go.

### Hyrum's Law Makes Removal Hard

With enough users, every observable behavior becomes depended on — including bugs, timing quirks, and undocumented side effects. This is why deprecation requires active migration, not just announcement. Users can't "just switch" when they depend on behaviors the replacement doesn't replicate.

### Deprecation Planning Starts at Design Time

When building something new, ask: "How would we remove this in 3 years?" Systems designed with clean interfaces, feature flags, and minimal surface area are easier to deprecate than systems that leak implementation details everywhere.

## The Deprecation Decision

Before deprecating anything, answer these questions:

```
1. Does this system still provide unique value?
   → If yes, maintain it. If no, proceed.

2. How many users/consumers depend on it?
   → Quantify the migration scope.

3. Does a replacement exist?
   → If no, build the replacement first. Don't deprecate without an alternative.

4. What's the migration cost for each consumer?
   → If trivially automated, do it. If manual and high-effort, weigh against maintenance cost.

5. What's the ongoing maintenance cost of NOT deprecating?
   → Security risk, engineer time, opportunity cost of complexity.
```

## Compulsory vs Advisory Deprecation

| Type | When to Use | Mechanism |
|------|-------------|-----------|
| **Advisory** | Migration is optional, old system is stable | Warnings, documentation, nudges. Users migrate on their own timeline. |
| **Compulsory** | Old system has security issues, blocks progress, or maintenance cost is unsustainable | Hard deadline. Old system will be removed by date X. Provide migration tooling. |

**Default to advisory.** Use compulsory only when the maintenance cost or risk justifies forcing migration. Compulsory deprecation requires providing migration tooling, documentation, and support — you can't just announce a deadline.

## The Migration Process

### Step 1: Build the Replacement

Don't deprecate without a working alternative. The replacement must:

- Cover all critical use cases of the old system
- Have documentation and migration guides
- Be proven in production (not just "theoretically better")

### Step 2: Announce and Document

```markdown
## Deprecation Notice: OldService

**Status:** Deprecated as of 2025-03-01
**Replacement:** NewService (see migration guide below)
**Removal date:** Advisory — no hard deadline yet
**Reason:** OldService requires manual scaling and lacks observability.
            NewService handles both automatically.

### Migration Guide
1. Replace `import { client } from 'old-service'` with `import { client } from 'new-service'`
2. Update configuration (see examples below)
3. Run the migration verification script: `npx migrate-check`
```

### Step 3: Migrate Incrementally

Migrate consumers one at a time, not all at once. For each consumer:

```
1. Identify all touchpoints with the deprecated system
2. Update to use the replacement
3. Verify behavior matches (tests, integration checks)
4. Remove references to the old system
5. Confirm no regressions
```

**The Churn Rule:** If you own the infrastructure being deprecated, you are responsible for migrating your users — or providing backward-compatible updates that require no migration. Don't announce deprecation and leave users to figure it out.

### Step 4: Remove the Old System

Only after all consumers have migrated:

```
1. Verify zero active usage (metrics, logs, dependency analysis)
2. Remove the code
3. Remove associated tests, documentation, and configuration
4. Remove the deprecation notices
5. Celebrate — removing code is an achievement
```

## Migration Patterns

### Strangler Pattern

Run old and new systems in parallel. Route traffic incrementally from old to new. When the old system handles 0% of traffic, remove it.

```
Phase 1: New system handles 0%, old handles 100%
Phase 2: New system handles 10% (canary)
Phase 3: New system handles 50%
Phase 4: New system handles 100%, old system idle
Phase 5: Remove old system
```

### Adapter Pattern

Create an adapter that translates calls from the old interface to the new implementation. Consumers keep using the old interface while you migrate the backend.

```typescript
// Adapter: old interface, new implementation
class LegacyTaskService implements OldTaskAPI {
  constructor(private newService: NewTaskService) {}

  // Old method signature, delegates to new implementation
  getTask(id: number): OldTask {
    const task = this.newService.findById(String(id));
    return this.toOldFormat(task);
  }
}
```

### Feature Flag Migration

Use feature flags to switch consumers from old to new system one at a time:

```typescript
function getTaskService(userId: string): TaskService {
  if (featureFlags.isEnabled('new-task-service', { userId })) {
    return new NewTaskService();
  }
  return new LegacyTaskService();
}
```

## Zombie Code

Zombie code is code that nobody owns but everybody depends on. It's not actively maintained, has no clear owner, and accumulates security vulnerabilities and compatibility issues. Signs:

- No commits in 6+ months but active consumers exist
- No assigned maintainer or team
- Failing tests that nobody fixes
- Dependencies with known vulnerabilities that nobody updates
- Documentation that references systems that no longer exist

**Response:** Either assign an owner and maintain it properly, or deprecate it with a concrete migration plan. Zombie code cannot stay in limbo — it either gets investment or removal.

## Common Rationalizations

| Rationalization | Reality |
|---|---|
| "It still works, why remove it?" | Working code that nobody maintains accumulates security debt and complexity. Maintenance cost grows silently. |
| "Someone might need it later" | If it's needed later, it can be rebuilt. Keeping unused code "just in case" costs more than rebuilding. |
| "The migration is too expensive" | Compare migration cost to ongoing maintenance cost over 2-3 years. Migration is usually cheaper long-term. |
| "We'll deprecate it after we finish the new system" | Deprecation planning starts at design time. By the time the new system is done, you'll have new priorities. Plan now. |
| "Users will migrate on their own" | They won't. Provide tooling, documentation, and incentives — or do the migration yourself (the Churn Rule). |
| "We can maintain both systems indefinitely" | Two systems doing the same thing is double the maintenance, testing, documentation, and onboarding cost. |

## Red Flags

- Deprecated systems with no replacement available
- Deprecation announcements with no migration tooling or documentation
- "Soft" deprecation that's been advisory for years with no progress
- Zombie code with no owner and active consumers
- New features added to a deprecated system (invest in the replacement instead)
- Deprecation without measuring current usage
- Removing code without verifying zero active consumers

## Verification

After completing a deprecation:

- [ ] Replacement is production-proven and covers all critical use cases
- [ ] Migration guide exists with concrete steps and examples
- [ ] All active consumers have been migrated (verified by metrics/logs)
- [ ] Old code, tests, documentation, and configuration are fully removed
- [ ] No references to the deprecated system remain in the codebase
- [ ] Deprecation notices are removed (they served their purpose)

모든 파일

0개 파일

deprecation-and-migration 설치

스킬 파일을 다운로드하여 .claude/skills/ 디렉터리에 압축을 풀어주세요.

ZIP 다운로드

저장소를 클론하고 스킬 파일을 프로젝트에 복사하세요.

git clone https://github.com/addyosmani/agent-skills/tree/main/skills/deprecation-and-migration # Copy SKILL.md to your .claude/skills/ directory

복사 복사
빠른 설정: 스킬 폴더를 .claude/skills/로 복사하세요. Claude가 해당 스킬을 자동으로 감지하여 사용합니다.

관련 스킬

algorithmic-art
업데이트 된 시간 2026년 8월 27일
tech-debt-tracker
업데이트 된 시간 2026년 8월 29일
receiving-code-review
업데이트 된 시간 2026년 9월 3일
senior-backend
업데이트 된 시간 2026년 8월 30일
OR