서비스 객체의 한계와 문제점
기존의 CreateShiftService
와 같은 서비스 객체는 300줄이 넘는 코드로 확장되면서 다음과 같은 심각한 문제를 야기했습니다:
* 불분명한 흐름: 비즈니스 로직의 실제 실행 순서가 private 메서드 내부에 숨겨져 파악하기 어려웠습니다.
* 취약한 오류 처리: 일부 단계는 중단되고 일부는 그렇지 않아 일관성이 부족했으며, 오류 발생 시 반환 값이 모호했습니다.
* 비원자적 작업: 알림 전송과 같은 사이드 이펙트가 전체 트랜잭션을 롤백해야 하는지에 대한 고민이 필요했습니다.
* 어려운 테스트: 특정 분기 하나를 테스트하기 위해 전체 모놀리식 구조를 테스트해야 하는 비효율성이 있었습니다.
DryCases 아키텍처와 워크플로우 엔진
이러한 문제 해결을 위해 dry-monads
젬과 Railway Oriented Programming 패러다임을 기반으로 DryCases라는 내부 프레임워크를 개발했습니다. DryCases는 강력하고 선언적인 DSL을 통해 비즈니스 워크플로우를 정의합니다.
* 선언적 워크플로우: check
, db
, step
, tee
와 같은 키워드를 사용하여 워크플로우의 전체 흐름을 코드 상단에 명확하게 선언합니다.
* check
: 사전 유효성 검사 등 실패 시 즉시 중단되는 단계.
* db
: 데이터베이스 트랜잭션 내에서 실행되는 단계.
* step
: 일반적인 비즈니스 로직 실행 단계.
* tee
: 실패해도 전체 워크플로우를 롤백하지 않는 사이드 이펙트(예: 알림 전송).
* 명확한 성공/실패 경로: Success
또는 Failure
모나드를 반환하여 성공 경로와 실패 경로를 명확하게 분리하고 일관된 오류 처리를 가능하게 합니다.
DryCases의 주요 이점
DryCases는 Rails SaaS 개발에 다음과 같은 혁신적인 이점을 제공합니다:
* 견고한 멀티테넌시: 모든 워크플로우 단계에서 account
컨텍스트를 명시적으로 전달하여 테넌트 간의 데이터 누수를 방지하고 보안을 강화합니다.
* 뛰어난 테스트 용이성: 각 워크플로우 단계를 개별적으로 단위 테스트할 수 있으며, 전체 UseCase에 대한 통합 테스트를 통해 모든 단계의 연동을 검증할 수 있습니다.
* 깔끔한 프론트엔드 통합: UseCase의 Failure
심볼(예: :invalid_params
, :shift_overlap
)을 프론트엔드 오류 메시지나 UI 상태에 직접 매핑하여 사용자 경험을 개선합니다.