강연은 세 가지 주요 안티패턴 사례를 통해 ‘침묵의 살인자들’을 구체적으로 설명합니다.
첫 번째 사례: ‘모듈성 신기루(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 컨벤션과 임베디드 데이터베이스 로직의 혼합이 유지보수 경로를 분리시킨다는 점, 그리고 조인 모델이 과도한 정규화의 징후일 수 있음을 시사했습니다.