Rails 애플리케이션에서 비즈니스 로직을 캡슐화하는 방식은 다양하며, 각기 다른 철학과 장단점을 가집니다. 강연에서는 다음과 같은 주요 접근 방식들이 논의되었습니다.
1. ActiveJob을 활용한 비즈니스 로직 캡슐화
- 개념: ActiveJob은 주로 백그라운드 작업을 위해 사용되지만, 단일 책임을 수행하는 객체라는 점에서 비즈니스 로직 캡슐화 도구로 활용될 수 있습니다.
- 장점: 별도의 Gem 설치나 새로운 학습 없이 Rails 기본 기능을 활용할 수 있어 진입 장벽이 낮습니다.
- 고려사항: 비동기 작업의 특성(결과 보장, 롤백, 보고)을 이해하고 사용해야 합니다. 동기/비동기 사용 의도를 명확히 구분하는 것이 중요합니다.
2. 서비스 객체(Service Objects) 패턴
- 개념: 비즈니스 로직을 컨트롤러나 모델에서 분리하여 독립적인 Ruby 객체로 만드는 일반적인 접근 방식입니다.
services
또는service_objects
와 같은 별도의 디렉토리에 배치하는 경우가 많습니다. - 장점: 관심사의 분리를 통해 코드의 가독성과 유지보수성을 높입니다.
- 고려사항: 너무 많은 디렉토리 생성은 오히려 복잡성을 증가시킬 수 있으며, 명명 규칙이 모호해질 수 있습니다.
3. Active Interaction Gem
- 개념:
active_interaction
은 인터랙터(Interactors) 패턴을 구현하는 Gem으로, 입력 값에 대한 타입 힌팅(Type Hinting)과 유효성 검사를 지원합니다. - 장점: 입력과 출력이 명확하여 테스트하기 용이하며, Rails 컨벤션과 유사하여 학습 곡선이 완만합니다.
run
및run!
메서드를 통해 성공/실패 객체를 반환하거나 예외를 발생시킵니다. - 논의: 인터랙터를 모델과 같은 디렉토리에 함께 배치하는 코로케이션(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’ 등 다양한 명칭이 존재하며, 이는 개발팀 내에서 혼란을 야기할 수 있습니다. 일관된 명명 규칙을 정립하는 것이 중요합니다.