iBetter Books
수정

Ch 05. 버전 관리와 유지보수

패키지를 배포했다고 끝이 아닙니다. 사용자들이 이슈를 제기하고, 새로운 기능을 요청하고, Dart 버전이 올라가면서 유지보수가 필요합니다. 버전을 어떻게 올려야 할지, breaking change는 어떻게 처리해야 할지를 알아야 합니다.

시맨틱 버저닝

Dart 패키지는 시맨틱 버저닝(Semantic Versioning, SemVer)을 따릅니다. 버전 번호는 MAJOR.MINOR.PATCH 형식입니다.

  • PATCH (0.1.0 → 0.1.1): 버그 수정. 하위 호환성을 유지합니다.
  • MINOR (0.1.0 → 0.2.0): 새 기능 추가. 하위 호환성을 유지합니다.
  • MAJOR (0.1.0 → 1.0.0): Breaking change. 하위 호환성이 깨집니다.

MAJOR가 0인 경우(0.x.x)는 초기 개발 단계를 의미합니다. API가 아직 안정적이지 않으므로 사용자들은 MINOR 업그레이드도 주의해야 합니다.

버전별 시나리오

dart_validator를 예로 각 버전 상황을 살펴봅니다.

버그 수정: 0.1.0 → 0.1.1

이메일 검사 정규식에서 .co.kr 같은 이중 도메인을 잘못 처리하는 버그를 발견했습니다. 정규식만 수정하면 됩니다. 기존 API는 그대로입니다.

# 수정: pubspec.yamlversion: 0.1.1
// 수정: CHANGELOG.md
## 0.1.1

- Fixed: `isEmail` 정규식이 이중 도메인(`.co.kr`)을 올바르게 처리하지 못하던 문제를 수정했습니다.

## 0.1.0

- Initial release.

새 기능 추가: 0.1.1 → 0.2.0

사용자 요청으로 주민등록번호 형식 검사 메서드를 추가합니다. 기존 메서드는 변경 없습니다.

// 수정: lib/src/validators.dart (Validators 클래스에 추가)

  static final RegExp _krIdRegex = RegExp(
    r'^\d{6}-[1-4]\d{6}$',
  );

  /// 주민등록번호 형식인지 검사합니다.
  ///
  /// 형식(XXXXXX-XXXXXXX)만 검사하며 실제 유효성은 검사하지 않습니다.
  static bool isKrId(String value) => _krIdRegex.hasMatch(value);
# 수정: pubspec.yamlversion: 0.2.0
// 수정: CHANGELOG.md
## 0.2.0

- Added: `Validators.isKrId` — 주민등록번호 형식 검사 메서드를 추가했습니다.

## 0.1.1
...

Breaking change: 0.2.0 → 1.0.0

ValidatorChain의 생성자 파라미터 이름을 value에서 input으로 변경해야 하는 상황입니다. 기존 코드가 위치 파라미터로 사용 중이라면 영향이 없지만, 명명된 파라미터로 변경한다면 breaking change입니다.

Breaking change는 사전에 deprecated 경고를 통해 사용자에게 알려주는 것이 좋습니다.

// 수정: lib/src/validator_chain.dart

class ValidatorChain {
  final String _value;

  /// 검사할 [value]로 체인을 시작합니다.
  ///
  /// [value] 파라미터는 다음 메이저 버전에서 [input]으로 변경됩니다.
  @Deprecated('Use ValidatorChain.fromInput instead. Will be removed in 1.0.0.')
  ValidatorChain(this._value);

  /// 검사할 [input]으로 체인을 시작합니다.
  ValidatorChain.fromInput(String input) : _value = input;
  // ... 나머지 메서드
}

MINOR 버전에서 @Deprecated를 추가하고, 다음 MAJOR 버전에서 실제로 제거합니다. 사용자들은 그 사이에 코드를 마이그레이션할 수 있습니다.

CHANGELOG.md 작성 원칙

CHANGELOG는 사용자 관점에서 작성합니다. 내부 리팩터링은 사용자에게 중요하지 않을 수 있습니다.

// 수정: CHANGELOG.md

## 1.0.0

- **Breaking**: `ValidatorChain(value)` 생성자를 제거했습니다.
  `ValidatorChain.fromInput(input)`을 사용하세요.
- Added: `Validators.isKrId` — 주민등록번호 형식 검사.
- Fixed: `isEmail` 이중 도메인 처리 오류.

## 0.2.0

- Added: `Validators.isKrId` — 주민등록번호 형식 검사 메서드 추가.
- Deprecated: `ValidatorChain(value)` — 1.0.0에서 제거 예정.
  `ValidatorChain.fromInput(input)`으로 마이그레이션하세요.

## 0.1.1

- Fixed: `isEmail` 정규식이 이중 도메인(`.co.kr`)을 올바르게 처리하지 못하던 문제.

## 0.1.0

- Initial release.

변경 유형 앞에 Added, Fixed, Changed, Deprecated, Removed, Breaking을 명시하면 사용자가 빠르게 파악할 수 있습니다.

GitHub Releases 활용

버전 배포와 함께 GitHub Releases를 만들면 사용자들에게 알림이 전달됩니다.

# 버전 태그 생성git tag v0.2.0git push origin v0.2.0

GitHub에서 "Create release from tag"를 클릭하고 CHANGELOG 내용을 붙여넣으면 됩니다. 사용자들이 "Watch" → "Releases only"로 설정해두면 새 버전이 나올 때마다 알림을 받을 수 있습니다.

GitHub Actions를 이용하면 태그를 푸시할 때 자동으로 pub.dev에 배포할 수도 있습니다. 이 내용은 PART 09에서 다룹니다.

의존성 업데이트 대응

Dart SDK가 새 버전이 나오면 pubspec.yaml의 SDK 제약 조건을 업데이트해야 할 수 있습니다. 또한 dev_dependencies의 lints, test 패키지도 주기적으로 올려주는 것이 좋습니다.

# 업데이트 가능한 의존성 확인dart pub outdated# 자동 업데이트dart pub upgrade --major-versions

dart pub outdated 명령은 현재 버전, 최신 호환 버전, 최신 버전을 표로 보여줍니다. 새 버전으로 올렸을 때 테스트가 통과하면 안전하게 업데이트할 수 있습니다.

이번 챕터 정리

  • 시맨틱 버저닝 MAJOR.MINOR.PATCH 규칙을 이해했습니다.
  • 버그 수정, 기능 추가, breaking change 각 상황에서 버전을 어떻게 올려야 하는지 배웠습니다.
  • @Deprecated로 사전 경고를 주고 MAJOR 버전에서 제거하는 패턴을 익혔습니다.
  • CHANGELOG.md를 사용자 관점에서 작성하는 원칙을 정리했습니다.
  • GitHub Releases와 연동하는 방법을 알았습니다.

PART 07이 완성되었습니다. 우리는 dart_validator 패키지를 처음 설계부터 배포, 유지보수까지 전 과정을 경험했습니다. 다음 PART에서는 Flutter 앱을 만들고, PART 06에서 만든 todo_server와 연동합니다.