Ruby on Rails 애플리케이션의 비즈니스 로직 캡슐화 전략: 서비스 객체와 다양한 접근 방식

Objects to Encapsulate Business Logic - Julian Pinzon Eslava and Adam Rice

작성자
jeff
발행일
2025년 04월 23일

핵심 요약

  • 1 Rails 애플리케이션에서 비즈니스 로직을 캡슐화하는 다양한 패턴(ActiveJob, 서비스 객체, 인터랙터, Dry::Operation, 순수 Ruby 객체)과 그 장단점을 탐구합니다.
  • 2 Active Interaction과 Active Record Associated Objects와 같은 특정 Gem 활용 사례 및 모델 내 코로케이션(co-location)을 통한 구조화 방안이 논의되었습니다.
  • 3 순수 Ruby 객체 사용의 간결성과 테스트 용이성을 강조하며, 비동기 작업 처리 시 ActiveJob의 활용과 그에 따른 고려사항이 제시되었습니다.

도입

본 강연은 Ruby on Rails 애플리케이션에서 비즈니스 로직을 효과적으로 캡슐화하고 조직하는 다양한 접근 방식에 대해 다룹니다. 개발자들이 흔히 겪는 '어디에 코드를 배치할 것인가'에 대한 고민을 중심으로, 서비스 객체(Service Objects)를 비롯한 여러 패턴과 도구의 장단점을 심층적으로 분석합니다. 이는 단일한 정답보다는 각 팀과 프로젝트의 특성에 맞는 최적의 솔루션을 찾아가는 과정을 공유하는 데 목적이 있습니다.

Rails 애플리케이션에서 비즈니스 로직을 캡슐화하는 방식은 다양하며, 각기 다른 철학과 장단점을 가집니다. 강연에서는 다음과 같은 주요 접근 방식들이 논의되었습니다.

1. ActiveJob을 활용한 비즈니스 로직 캡슐화

  • 개념: ActiveJob은 주로 백그라운드 작업을 위해 사용되지만, 단일 책임을 수행하는 객체라는 점에서 비즈니스 로직 캡슐화 도구로 활용될 수 있습니다.
  • 장점: 별도의 Gem 설치나 새로운 학습 없이 Rails 기본 기능을 활용할 수 있어 진입 장벽이 낮습니다.
  • 고려사항: 비동기 작업의 특성(결과 보장, 롤백, 보고)을 이해하고 사용해야 합니다. 동기/비동기 사용 의도를 명확히 구분하는 것이 중요합니다.

2. 서비스 객체(Service Objects) 패턴

  • 개념: 비즈니스 로직을 컨트롤러나 모델에서 분리하여 독립적인 Ruby 객체로 만드는 일반적인 접근 방식입니다. services 또는 service_objects와 같은 별도의 디렉토리에 배치하는 경우가 많습니다.
  • 장점: 관심사의 분리를 통해 코드의 가독성과 유지보수성을 높입니다.
  • 고려사항: 너무 많은 디렉토리 생성은 오히려 복잡성을 증가시킬 수 있으며, 명명 규칙이 모호해질 수 있습니다.

3. Active Interaction Gem

  • 개념: active_interaction은 인터랙터(Interactors) 패턴을 구현하는 Gem으로, 입력 값에 대한 타입 힌팅(Type Hinting)과 유효성 검사를 지원합니다.
  • 장점: 입력과 출력이 명확하여 테스트하기 용이하며, Rails 컨벤션과 유사하여 학습 곡선이 완만합니다. runrun! 메서드를 통해 성공/실패 객체를 반환하거나 예외를 발생시킵니다.
  • 논의: 인터랙터를 모델과 같은 디렉토리에 함께 배치하는 코로케이션(co-location) 방식이 모델과의 관련성을 높여 편리할 수 있습니다.

4. Dry::Operation (dry-rb 스위트)

  • 개념: 함수형 프로그래밍 패러다임을 따르는 dry-rb 스위트의 일부로, 상태를 가지지 않는(stateless) 연산 객체를 지향합니다.
  • 고려사항: Rails의 객체 지향적 사고방식에 익숙한 개발자에게는 학습 곡선이 높고, 상태 없는 객체 관리가 어려울 수 있습니다. 오류 처리를 위한 ‘Result Object’ 패턴을 사용합니다.

5. 순수 Ruby 객체 및 Active Record Associated Objects

  • 개념: 특별한 Gem 없이 순수 Ruby 객체를 사용하여 비즈니스 로직을 캡슐화하는 방식입니다. 강연자는 Creator 패턴과 같이 모델의 역할을 데이터 저장소로 제한하고, 실제 비즈니스 로직은 별도의 순수 Ruby 객체(예: UserCreator)에 위임하는 방식을 선호합니다.
  • Active Record Associated Objects: Casper’s gem을 통해 모델에 연관된 객체를 정의하고, 해당 객체가 비즈니스 로직을 처리하도록 합니다. 이는 ActiveJob과의 통합을 통해 비동기 작업 스케줄링을 용이하게 합니다.
  • 장점: 새로운 프레임워크나 Gem을 학습할 필요 없이 Ruby의 기본 문법으로 코드를 이해하고 작성할 수 있어 코드베이스의 진입 장벽을 낮춥니다. 모델 내에 논리적으로 연관된 클래스를 중첩하여 관리할 수도 있습니다.
  • 고려사항: 테스트 전략(모델 테스트 vs. 연관 객체 테스트)에 대한 고민이 필요합니다.

오류 처리 및 명명 규칙

  • 오류 처리: ‘Fail fast’ 전략(예외 발생)과 ‘Result Object’ 패턴(성공/실패 객체 반환)의 장단점이 논의되었습니다. API 호출과 같이 다양한 오류 유형이 발생할 수 있는 경우, 계층적인 예외 클래스를 정의하여 관리하는 것이 유용합니다.
  • 명명 규칙: ‘Service’, ‘Interactor’, ‘Operation’, ‘Creator’ 등 다양한 명칭이 존재하며, 이는 개발팀 내에서 혼란을 야기할 수 있습니다. 일관된 명명 규칙을 정립하는 것이 중요합니다.

결론

Rails 애플리케이션에서 비즈니스 로직을 캡슐화하는 데에는 여러 유효한 접근 방식이 존재하며, '최고의' 방법은 프로젝트의 요구사항과 팀의 선호도에 따라 달라질 수 있습니다. ActiveJob의 예상치 못한 활용부터 Active Interaction, dry-rb, 그리고 순수 Ruby 객체에 이르기까지, 각 방법은 고유한 장점과 고려사항을 가집니다. 궁극적으로는 코드의 가독성, 유지보수성, 그리고 테스트 용이성을 높이는 방향으로 결정되어야 하며, 불필요한 복잡성을 피하고 Ruby와 Rails의 기본적인 컨벤션을 최대한 활용하는 것이 중요합니다. 지속적인 경험 공유와 논의를 통해 각 팀에 최적화된 비즈니스 로직 관리 전략을 발전시켜 나갈 수 있습니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

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