성공적인 Ruby on Rails 애플리케이션의 숨겨진 위험: 침묵의 살인자들

RailsConf 2025 Silent Killers: Lessons from the Brink by Joe Leo

작성자
Ruby Central
발행일
2025년 07월 24일

핵심 요약

  • 1 성장하는 Rails 애플리케이션에서 발생하는 숨겨진 복잡성(침묵의 살인자들)을 식별하고 해결하는 방법을 다룹니다.
  • 2 표면적 모듈성, 거대 클래스, 데이터베이스에 숨겨진 로직 등 세 가지 주요 안티패턴과 그 해결책을 사례를 통해 제시합니다.
  • 3 아키텍처 건전성을 위한 DevOps 지표의 중요성, 테스트 커버리지, 그리고 안전하고 빠른 변경의 필요성을 강조합니다.

도입

이 강연, "Silent Killers, Lessons from the Brink"는 성공적으로 성장하고 있는 Ruby on Rails 애플리케이션 내부에 잠재된 심각한 문제, 즉 '침묵의 살인자들'을 다룹니다. 조 레오(Joe Leo)는 Def Method의 CEO이자 'The Well-Grounded Rubyist'의 공동 저자로서, 개발자들이 일상적인 개발 과정에서 무심코 내리는 결정들이 시간이 지남에 따라 축적되어 애플리케이션의 생존을 위협하는 존재로 변모하는 현상을 경고합니다. 본 강연은 이러한 안티패턴들을 명명하고, 식별하며, 피하는 방법, 그리고 이미 직면했을 때 벗어나는 전략을 Ruby on Rails 환경에 특화된 방식으로 제시합니다. 개발의 '항해'에 비유하여, 작은 장애물이 보이지 않게 성장하여 시스템 전체를 위협하는 '실존적 위협'이 될 수 있음을 강조하며, 숨겨진 복잡성을 이해하고 위기 전에 진단하여 Rails 애플리케이션의 생존 전략을 구현하는 것이 중요하다고 역설합니다.

강연은 세 가지 주요 안티패턴 사례를 통해 ‘침묵의 살인자들’을 구체적으로 설명합니다.

첫 번째 사례: ‘모듈성 신기루(The Modularity Mirage)’ 겉으로는 분리된 두 개의 Rails 애플리케이션(임차인 앱과 임대인 앱)이 실제로는 데이터베이스를 직접 공유하며 강하게 결합되어 있었던 경우입니다. 이는 표면적인 모듈성, 배포 환경의 불확실성(‘슈뢰딩거의 배포’), 그리고 신뢰할 수 없는 빌드 및 테스트 커버리지 부족(‘깨진 유리창’)으로 이어졌습니다. 그 결과, 잦은 프로덕션 롤백과 규제 벌금이라는 심각한 비즈니스 위협에 직면했습니다. 해결책으로는 Active Resource를 사용하여 직접적인 데이터베이스 결합을 해제하고 API 계약 테스트(VCR, Pact)를 도입하여 진정한 모듈성을 회복했습니다. 또한, 공유 로직을 프라이빗 젬으로 추출하고 Heroku API를 활용하여 리뷰 앱 설정을 자동화함으로써 배포 신뢰도를 높였습니다. 마지막으로, GitHub Actions 기반의 DORA 지표 구현을 통해 아키텍처의 건전성을 시각화했습니다. 이 사례는 표면적 모듈성의 위험성, 공유 데이터베이스가 숨겨진 닻 역할을 한다는 점, 그리고 DevOps 지표가 아키텍처 상태를 반영한다는 교훈을 남겼습니다.

두 번째 사례: ‘심해의 리바이어던(The Leviathan Beneath)’ 코로케이션 및 네트워킹 마켓플레이스 애플리케이션에서 발생한 문제입니다. 이 시스템은 Rails 백엔드와 React 프론트엔드의 명확한 분리를 표방했으나, 실제로는 복잡한 기능 추가에 대한 두려움이 만연했습니다. 원인은 수개월간 깨져 있던 CI 빌드, JavaScript 유닛/통합 테스트의 부재(느리고 불안정한 피처 스펙에만 의존), 무시된 1,500개 이상의 Code Climate 경고, 그리고 ‘리바이어던 클래스’(God 클래스)로 불리는 거대한 모델(Project, Quote 클래스가 20개 이상의 책임을 가짐)에 있었습니다. 또한, Active Support Concerns가 보이지 않는 복잡성을 추가하는 ‘컨선 크립(Concern Creep)’ 현상도 나타났습니다. 이로 인해 빌드 프로세스에 대한 신뢰가 상실되고, 개발 계획과 예측이 크게 빗나가며, 비즈니스가 새로운 서비스 카테고리로 확장하지 못하는 정체 상태에 빠졌습니다. 해결을 위해 백엔드에서는 비즈니스 로직을 서비스 클래스 및 Interactor 젬으로 분리하고 Statesman 젬을 이용해 상태 관리를 외부에 위임하여 모델의 책임을 분산했습니다. 프론트엔드에서는 Redux 연결을 모듈화하고 코드 분할을 도입했으며, React Testing Library를 활용하여 유닛 및 통합 테스트를 강화했습니다. 또한, 깨진 빌드를 수정하고 Code Climate 경고 중 가장 중요한 것들을 선별적으로 해결하며, 신규 및 리팩토링 코드에 대한 80% 테스트 커버리지 목표를 설정하여 메트릭에 대한 신뢰를 회복했습니다. 이 사례는 복잡성이 무시되면 증폭되고, 시스템의 진정한 건전성은 안전하고 빠른 변경 능력에 있음을 보여주었습니다.

세 번째 사례: ‘바닥의 침전물(The Silt Below)’ 거의 20년 된 장기 운영 Rails 애플리케이션에서 발견된 문제입니다. 이 앱은 겉으로는 잘 관리된 것처럼 보였으나, structure.sql 파일에 수십 개의 복잡한 PostgreSQL 함수가 하드코딩되어 애플리케이션 로직이 데이터베이스 깊숙이 숨겨져 있었습니다(‘심해의 로직’). 또한, 과도한 정규화로 인해 여러 조인 모델이 불필요하게 사용되고 있었으며, 컨트롤러에 원시 SQL 쿼리가 포함되어 있었습니다. 이러한 문제들은 변경 시마다 마이그레이션과 수동 SQL 편집을 요구하여 개발 속도를 저하시키고 취약성을 증가시켰습니다. 더 심각하게는, 이러한 복잡한 데이터베이스 로직을 다룰 수 있는 ‘전문가’만이 유지보수와 기능 추가에 기여할 수 있게 되어 팀 전체의 기여도를 제한하는 결과를 초래했습니다. 아직 완전히 해결되지는 않았지만, 계획된 해결책으로는 모든 PostgreSQL 함수를 식별하고 분류한 후, 가능한 한 schema.rb로 전환하여 애플리케이션 계층에서 로직을 관리하는 것입니다. 또한, 전환 과정에서 계약 테스트를 추가하고, SQL을 Active Record 스코프나 ARL로 점진적으로 재작성하며 서비스 객체를 추출할 예정입니다. 이 사례는 structure.sql 파일에 대한 면밀한 검토의 필요성, Rails 컨벤션과 임베디드 데이터베이스 로직의 혼합이 유지보수 경로를 분리시킨다는 점, 그리고 조인 모델이 과도한 정규화의 징후일 수 있음을 시사했습니다.

결론

이 강연은 Ruby on Rails 애플리케이션에서 발생하는 '침묵의 살인자들'이 어떻게 비즈니스에 치명적인 위협이 될 수 있는지를 명확하게 보여줍니다. 표면적인 모듈성, 거대 클래스, 데이터베이스에 숨겨진 로직과 같은 안티패턴들은 초기에 인지하지 못하면 시스템을 정체시키고, 개발 비용을 증가시키며, 궁극적으로 비즈니스 확장을 저해합니다. 강연자는 이러한 문제들을 해결하기 위한 구체적인 기술적 접근 방식(Active Resource, API 계약 테스트, 서비스 클래스, Interactor, Statesman, React Testing Library 등)을 제시하며, 단순히 코드를 수정하는 것을 넘어 팀의 개발 문화와 메트릭에 대한 신뢰를 회복하는 것의 중요성을 강조합니다. 궁극적으로, 건강한 시스템의 진정한 척도는 '안전하고 빠른 변경'이 가능하느냐에 달려 있음을 역설하며, 개발자들이 숨겨진 복잡성을 인지하고 적극적으로 대처함으로써 애플리케이션의 장기적인 생존과 비즈니스 성장을 보장할 수 있다는 강력한 메시지를 전달합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!