작성자는 복잡한 비즈니스 로직이 코드베이스 전반에 걸쳐 분산되어 발생하는 문제를 해결하기 위해 ‘Operations’라는 Rails Engine을 고안했습니다. 이 개념은 비즈니스 프로세스의 논리 흐름을 나타내며, 컴퓨터 과학적으로는 일종의 상태 머신 또는 그래프로 볼 수 있습니다. 각 노드는 의사결정(decision) 또는 동작(action)을 수행합니다. 작성자는 Flutter의 위젯 계층이나 ActiveRecord의 선언적 유효성 검사 및 관계 정의처럼, Ruby의 메타 프로그래밍을 활용하여 선언적인 인터페이스를 구축하고자 했습니다.
초기 스케치에서는 Tasks::Job
을 상속받아 starts_with
, ends_with
, decision
, step
, next_step
과 같은 키워드를 사용하여 비즈니스 흐름을 정의했습니다. 하지만 이 방식은 직관적이지 않다고 판단하여, 이후 Tasks::DecisionTree
를 기반으로 inputs
, outputs
, decision
(with if_result_is
) 및 일반 메서드를 활용하는 형태로 발전시켰습니다. 그러나 이 역시 메서드의 내부 동작과 다음 흐름을 한눈에 파악하기 어렵다는 단점이 있었습니다.
최종적으로 ‘Operation’이라는 명칭을 사용하며 Operations::Task
를 기반으로 한 프레임워크를 개발했습니다. 이 프레임워크의 핵심 특징은 다음과 같습니다:
- 선언적 정의:
inputs
,optional
,starts_with
,decision
,action
,result
등의 DSL(Domain Specific Language)을 사용하여 비즈니스 로직의 흐름을 명확하게 선언합니다. - 의사결정 및 동작 분리:
decision
블록은 조건을 평가하고 다음 단계를 지정하며,action
블록은 실제 작업을 수행하고go_to
를 통해 다음 단계로 이동합니다. - 스테이트리스 핸들러: 각 핸들러는 상태를 가지지 않아 개별 테스트가 용이하며, 복잡한 종단 간(end-to-end) 테스트의 필요성을 줄여줍니다.
- 입력 매개변수 저장: 작업 완료 후에도 입력 매개변수를 데이터베이스에 저장함으로써 실패 진단에 유용한 정보를 제공합니다.
- 작업 위임: ‘Operation’ 클래스 자체는 로직의 흐름을 정의하고, 실제 복잡한 작업은 다른 객체에 위임하여 클래스의 목적(라이브 문서화)을 유지합니다.
이를 통해 개발자는 복잡한 비즈니스 로직을 플로우차트 형태로 시각화하고, 이를 Operations::Task
를 활용한 간결하고 읽기 쉬운 Ruby 코드로 변환하여 시스템의 동작 방식을 명확하게 이해하고 관리할 수 있게 됩니다.