--- name: principle-migrate-callers-then-delete-legacy-apis description: 레거시 API를 삭제하기 전에 모든 호출자를 마이그레이션하기 --- # 원칙: 레거시 API를 삭제하기 전에 모든 호출자를 마이그레이션하기 리팩토링할 때는 두 단계로 진행하세요: 1. **새로운 API를 추가하고** 모든 호출 지점을 마이그레이션합니다 2. **레거시 API를 삭제**합니다 한 번에 두 가지를 모두 하지 마세요 — 즉, 레거시 함수의 시그니처를 한 번에 인플레이스로 변경하거나, 인터페이스를 변경하면서 동시에 모든 호출자를 업데이트하지 마세요. ## 이유 - **검증이 쉬워집니다**: 각 단계를 독립적으로 빌드하고 테스트할 수 있습니다 - **변경 사항이 국소화됩니다**: 먼저 호출 지점만 바꾸고, 그 다음 한 곳에서만 레거시 코드를 제거합니다 - **되돌리기가 더 쉽습니다**: 문제가 발생하면 각 단계를 독립적으로 되돌릴 수 있습니다 - **대규모로 확장됩니다**: 수백 개의 호출 지점이 있어도 여전히 2단계 프로세스입니다 ## 방법 1. 새 API를 나란히 추가합니다 (새 함수, 새 필드, 새 엔드포인트) 2. 각 호출자를 마이그레이션하고 각 그룹 후에 확인합니다 3. 모든 것이 마이그레이션되면 레거시 API를 삭제합니다 타입 시스템이 있다면, 레거시 API를 `@deprecated`로 표시하거나 린트 오류를 발생시켜 새로운 호출을 방지하세요. ## 예시 **나쁜 예** (단 하나의 큰 변경): ```typescript // 이전: function getUserById(id: number): User // 새로운: 단일 커밋에서 UUID로 변경하고 100개의 호출 지점을 모두 업데이트 function getUserById(id: string): User { ... } ``` **좋은 예** (2단계): ```typescript // 1단계: 새 API 추가, 호출자 마이그레이션 function getUserByUuid(id: string): User { ... } function getUserById(id: number): User { // 레거시 shim: 여전히 작동하지만 더 이상 사용되지 않음 } // 2단계: 모든 호출자가 getUserByUuid()를 사용한 후, 레거시 제거 // function getUserById를 삭제 ``` ## 대규모 마이그레이션의 경우 수십 개 이상의 파일이 있는 경우: 1. 레거시를 유지하고 새 API를 추가합니다 2. 호출자를 그룹으로 마이그레이션합니다 (모듈별, 레이어별) 3. 각 그룹 후에 커밋하고 빌드합니다 4. 모든 호출이 마이그레이션되면 레거시를 제거합니다 grep 또는 타입 체커를 사용하여 레거시 사용이 남아있지 않은지 확인하세요. ## 관련 원칙 - **sequence-verifiable-units**: 각 단계가 빌드되고 커밋 가능해야 합니다 - **make-operations-idempotent**: 마이그레이션이 멈추거나 롤백되면 재시작할 수 있어야 합니다 - **boundary-discipline**: 공개 API를 안정적으로 유지하고, 비공개 API는 한 번에 리팩토링합니다