Cisco Maro의 애플리케이션은 2006년 Rails 1.0으로 시작하여 2022년에는 5백만 라인 이상의 Ruby 코드와 600명 이상의 월별 활성 기여자를 가진 거대한 모놀리스로 성장했습니다. 이러한 급격한 확장 과정에서 초기 개발 시 확립되지 않았던 Rails 베스트 프랙티스와 맞물려 다음과 같은 문제점이 발생했습니다.
주요 문제점
-
높은 복잡성: 대규모 모델 및 컨트롤러로 인해 코드 이해, 변경, 테스트가 어려워졌습니다.
-
낮은 테스트 커버리지: 복잡한 구조로 인해 테스트 작성이 부담이 되어 수동 테스트 의존도가 높아졌습니다.
-
낮은 응집도 및 높은 결합도: 비즈니스 로직이 컨트롤러, 뷰, 모델에 산재하여 특정 도메인에 대한 책임이 불분명해졌습니다.
-
협업의 어려움: 조직 전체의 합의 없이는 코드 개선이 어려워 팀의 자율성이 저해되었습니다.
해결 전략: 비즈니스 로직 모듈화
이러한 문제를 해결하기 위해, 발표자들은 Rails의 전통적인 MVC 아키텍처를 넘어 비즈니스 로직을 Rails 컨스트럭트로부터 분리하는 모듈화 접근 방식을 채택했습니다. 이는 궁극적으로 복잡성을 줄이고 테스트 용이성, 팀의 자율성 및 책임감을 높이는 것을 목표로 합니다.
- 컨트롤러에서 비즈니스 로직 추출:
- 컨트롤러 내의 복잡한 액션들을
UpdateWaterTankSettings와 같은 작고 테스트하기 쉬운 순수 Ruby 객체(PORO)로 분리했습니다. - 결과적으로 컨트롤러는 HTTP 요청 처리 및 응답 전송에만 집중하게 됩니다.
- 컨트롤러 내의 복잡한 액션들을
- 뷰(ERB)에서 비즈니스 로직 추출:
- ERB 템플릿 내에 혼재된 비즈니스 로직을
CoffeeMachineConfiguration과 같은 PORO로 옮겼습니다. - 이를 통해 뷰 테스트의 어려움을 해소하고, 로직에 대한 커버리지 및 복잡도 측정이 용이해졌습니다.
- ERB 템플릿 내에 혼재된 비즈니스 로직을
- 모델에서 비즈니스 로직 추출:
- 모델이 코드를 끌어당기는 자석(junk drawer)이 되는 것을 방지하기 위해
broadcast_details와 같은 핵심 로직을CoffeeMachineBroadcastDetails와 같은 별도의 클래스로 분리했습니다. - 이는 모델 속성과의 암묵적 결합을 줄이고, 테스트 용이성을 높이며, 코드의 응집도를 향상시킵니다.
- 모델이 코드를 끌어당기는 자석(junk drawer)이 되는 것을 방지하기 위해
도메인 기반 조직화
추출된 순수 Ruby 객체들은 domain/coffee_machine과 같은 도메인별 디렉토리 및 네임스페이스에 배치됩니다. 이는 팀이 특정 도메인에 대한 소유권을 가지고, 조직 전체의 합의 없이도 코드 개선을 실험하고 책임감을 가질 수 있도록 합니다. 각 팀은 도메인 디렉토리 내에서 코드 조직 방식(예: 서브도메인 또는 서비스/시리얼라이저 패턴)을 자율적으로 결정할 수 있습니다.