모놀리식 CLI에서 모듈식 플러그인으로: 스트랭글러 피그 패턴 적용
Source: Dev.to
TL;DR – 안전한 마이그레이션 전략
- 명령을 외부 플러그인으로 추출 (베타로 배포)
- 플러그인을 코어에 의존성으로 추가 (v2.x – 파괴적 변경 없음)
- 피드백을 수집하고, 반복하며, 안정화
- v3.0.0에서 의존성 제거 (파괴적 변경, 하지만 준비됨)
- 사용자는 필요한 것만 설치
Result: safe migration + independent plugin evolution
문제: CLI가 유지보수 불가능해지는 이유
Your CLI probably started like this:
cli/
├── commands/
│ ├── deploy.js
│ └── status.js
├── utils/
│ └── helpers.js
└── index.js
깨끗하고. 단순하며. 모든 것이 제자리에 있습니다.
Six months later:
cli/
├── commands/ (37 files)
├── utils/ (23 files)
├── services/ (15 files)
├── integrations/ (12 files)
└── shared/ (who even knows?)
Now you’re dealing with:
- 강한 결합 – 모든 명령이 10개 이상의 유틸리티 파일을 import
- 공유 상태 악몽 – 모든 것이 접근하는 전역 설정
- 위험한 릴리즈 – 하나의 변경으로 전체 CLI를 테스트해야 함
- 느린 개발 – 기능 추가에 수주간의 조정이 필요
- 파괴적 변경 지옥 – 한 부분을 진화시키면 전체가 깨짐
Sound familiar? You’ve built a monolith.
=> 익숙하신가요? 당신은 모놀리스를 만들었습니다.
백엔드 교훈: 모놀리스를 모듈러로 전환하기
옛 방식 (모놀리식 API)
Everything in one codebase
↓
Tightly coupled domains
↓
Coordinated releases
↓
High‑risk deployments
↓
Slow feature velocity
현대 방식 (마이크로서비스 / 모듈러)
Thin API Gateway
↓
Isolated domain services
↓
Independent deployments
↓
Versioned contracts
↓
Fast, safe iterations
핵심 인사이트: 도메인을 격리하고, 명확한 경계를 설정하며, 독립적인 진화를 가능하게 합니다. 이는 CLI에도 적용됩니다.
해결책: Core + 플러그인 아키텍처
얇은 Core
Your core should be boring and stable:
core/
├── auth/ // Auth logic
├── config/ // Config management
├── dispatcher/ // Command routing
├── utils/ // Cross‑cutting concerns
└── plugin-loader/ // Plugin discovery
The core provides infrastructure and gets out of the way.
플러그인
Each plugin is a self‑contained domain:
plugins/
├── deploy-plugin/
│ ├── commands/
│ ├── tests/
│ ├── README.md
│ └── package.json // Independent versioning!
├── logs-plugin/
└── backup-plugin/
각 플러그인:
- 하나의 책임만을 가짐
- 자체 시맨틱 버전을 가짐
- 독립적으로 설치 (
npm i @cli/deploy-plugin) - 다른 플러그인에 영향을 주지 않고 변경 가능
- 완전 격리된 테스트
마이그레이션 전략: 스트랭글러 피그 패턴
The Strangler Fig Pattern (Martin Fowler) lets you migrate gradually without a risky big‑bang rewrite.
단계 1 – 외부 플러그인을 베타로 배포
# Release your first plugin in beta
npm publish @my-cli/deploy-plugin@1.0.0-beta.1
npm publish @my-cli/logs-plugin@1.0.0-beta.1
왜 베타인가? 사용자는 테스트에 옵트인할 수 있고, 빠르게 반복할 수 있으며, 파괴적 변경이 예상됩니다.
// deploy-plugin/package.json
{
"name": "@my-cli/deploy-plugin",
"version": "1.0.0-beta.1",
"main": "dist/index.js",
"peerDependencies": {
"@my-cli/core": "^2.0.0"
}
}
단계 2 – 플러그인을 Core에 의존성으로 추가 (임시)
// core/package.json
{
"name": "@my-cli/core",
"version": "2.5.0",
"dependencies": {
"@my-cli/deploy-plugin": "^1.0.0-beta.1",
"@my-cli/logs-plugin": "^1.0.0-beta.1"
}
}
- 사용자는
core를 설치하면 → 플러그인이 자동으로 함께 설치됩니다 - 기존 사용자에게 파괴적 변경 없음
- 플러그인은 초기 도입자에게 독립적으로 동작
단계 3 – 명령을 점진적으로 마이그레이션
v2.5.0 (Initial Beta)
deploy → Plugin (bundled as dependency)
logs → Legacy in core
backup → Legacy in core
v2.8.0 (Beta 2)
deploy → Plugin (bundled as dependency)
logs → Plugin (bundled as dependency)
backup → Legacy in core
각 단계는 안전하게 배포되며, 사용자는 차이를 느끼지 못하고 플러그인은 실제 환경에서 성숙합니다.
단계 4 – 대전환: 의존성 제거 (v3.0.0)
// core/package.json (v3.0.0)
{
"name": "@my-cli/core",
"version": "3.0.0",
"dependencies": {
// No more plugin dependencies!
},
"peerDependencies": {
// Plugins are now optional
}
}
사용자를 위한 마이그레이션 가이드
# Old way (v2.x) – everything bundled
npm install -g @my-cli/core
# New way (v3.x) – install what you need
npm install -g @my-cli/core
npm install -g @my-cli/deploy-plugin # only if you need deploy
npm install -g @my-cli/logs-plugin # only if you need logs
왜 이것이 메이저 버전인지: 파괴적 변경 – 플러그인이 더 이상 자동 설치되지 않아 사용자는 더 많은 제어권을 갖고, 설치 용량이 작아지며, 설치 속도가 빨라집니다.
단계 5 – 사용자는 필요에 따라 설치
# Minimal installation (just core utilities)
npm install -g @my-cli/core
# À la carte (only what I use)
npm install -g @my-cli/core @my-cli/deploy-plugin
# Everything (opt‑in to all plugins)
npm install -g @my-cli/all # metapackage
장점
- 작은 설치 용량 (예: 15 MB vs 250 MB)
- 빠른 시작 시간
- 각 플러그인의 독립적인 진화
- 보다 안전하고, 제어된 릴리즈
By treating your CLI like a microservice ecosystem and applying the Strangler Fig Pattern, you can transition from a monolithic codebase to a modular, plugin‑driven architecture with minimal risk and maximum flexibility.
=> CLI를 마이크로서비스 생태계처럼 다루고 스트랭글러 피그 패턴을 적용하면, 모놀리식 코드베이스에서 모듈형 플러그인 기반 아키텍처로 최소한의 위험과 최대한의 유연성을 가지고 전환할 수 있습니다.