소프트웨어 유지보수는 단순히 앱을 구동하거나 새로운 기능을 구현하고 버그를 수정하는 것을 넘어섭니다. 이는 코드 리팩토링, 최신 패턴 적용, 종속성 업데이트, 보안 취약점 패치, 테스트 스위트 강화, 성능 개선, 그리고 기술 부채 관리 등 광범위한 활동을 포함합니다. 발표자는 리팩토링을 통해 코드베이스의 품질을 지속적으로 개선하고, 불필요한 코드를 삭제하며, 종속성을 선제적으로 관리하는 것이 중요하다고 역설합니다. 또한, CI/CD 속도를 유지하고 테스트 커버리지를 확장하는 것의 중요성을 강조합니다.
장기 유지보수는 기술 부채를 효과적으로 관리하고, 개발자와 사용자 모두의 만족도를 높이며, 새로운 기능을 신속하게 제공할 수 있는 환경을 조성하는 데 필수적입니다. 오래된 애플리케이션에서 기술 부채는 피할 수 없으므로, 이를 효과적으로 관리하는 체계적인 워크플로우를 구축하는 것이 핵심입니다.
Harvest는 유지보수를 팀 전체의 공유된 책임으로 간주하고 여러 전략을 적용합니다. 첫째, ‘보이스카우트 규칙(Boy Scout Rule)’에 따라 모든 커밋에서 코드를 발견했을 때보다 더 나은 상태로 남깁니다. 둘째, 프로젝트 관리 단계에서 유지보수 시간을 기능 추정 시 고려하며, 엔지니어는 코드베이스 상태에 기반하여 제품 관리자와 기능 정의를 돕습니다. 셋째, 구현 단계에서는 최신 패턴을 사용하고 종속성을 선제적으로 업데이트하며, 작업 중 발견하는 불필요한 코드를 개선하거나 삭제합니다.
코드 리뷰 및 PR 과정에서도 유지보수를 강조합니다. 클린업과 리팩토링을 분리하고, 미래를 위해 상세한 PR 설명을 작성하며, 리뷰어들은 코드 변경뿐만 아니라 종속성 업데이트, 테스트, 성능 등 유지보수 측면도 면밀히 검토합니다. 품질 보증(QA) 팀은 기능 검증을 넘어 사용자 경험, 성능, 문서화 등을 점검하며, 신뢰할 수 있는 테스트 스위트와 프로덕션 모니터링(Bugsnag, DataDog, Grafana)은 안전한 배포에 필수적입니다. Harvest는 소규모 PR, 자동화된 CI/CD(Argo), 기능 플래그, 롤백 전략을 통해 배포 위험을 최소화합니다.
Harvest는 유지보수를 위한 전담 팀도 운영합니다. ‘Delta Force’는 매 스프린트마다 엔지니어가 교체되며, 스쿼드 외 버그, 일회성 요청, 문제 해결, 소규모 개선 사항을 처리하여 팀원의 전반적인 시스템 이해도를 높입니다. ‘Platform Development’ 팀은 엔지니어링 생산성, 로컬 환경 설정, 린팅(Rubocop), 자동화, CI/CD, 관측 가능성, 핵심 시스템 기능, 주요 업그레이드(Rails, Ruby) 및 보안을 담당합니다.
의사 결정 과정에서는 ‘애자일 스파이크(Agile Spikes)’를 활용하여 기능 개발 전 불확실한 부분을 탐색하고 PoC(Proof of Concept)를 통해 계획 및 추정을 개선합니다. 이를 통해 기존 기능 확장, 전체 재작성, 또는 현상 유지 중 결정을 내립니다. 종속성 관리는 Dependabot과 Renovate를 활용하여 자동화하며, Renovate는 유연한 설정으로 내부 종속성까지 관리합니다. bundle outdated
와 같은 명령어를 통해 종속성 상태를 확인하고, bundle-outdated-formatter
와 같은 도구로 업데이트를 용이하게 합니다.
특히 까다로운 리팩토링을 위해 Harvest는 ‘Scientist Gem’이라는 Ruby 라이브러리를 사용합니다. 이는 프로덕션 환경에서 기존 코드(control)와 새로운 코드(candidate)를 동시에 실행하고, 사용자에게는 기존 코드의 결과를 제공하면서 백그라운드에서 두 결과의 불일치를 보고합니다. 이를 통해 위험 없이 새로운 로직을 검증하고 리팩토링의 신뢰도를 높일 수 있습니다. Harvest는 이를 권한 모델, SQL 쿼리, 캐싱, 커스텀 인증 로직 개선 등 다양한 핵심 경로에 성공적으로 활용했습니다.