이번 업데이트의 핵심은 dry-operation과 web_pipe 프로젝트의 진화입니다.
dry-operation: 실패 경로 및 데이터베이스 트랜잭션 관리 개선
dry-operation은 ‘행복한 경로(happy path)’를 간소화하는 데 중점을 두지만, ‘불행한 경로(unhappy path)’ 또한 간과하지 않습니다.
- 실패 처리 #on_failure 훅 도입:
- 기존에는 개별 오퍼레이션이 로컬에서 실패를 관리했으나, 전역적인 오류 처리(예: 실패 로깅)를 위해 #on_failure 훅이 추가되었습니다.
- 이 훅은 오퍼레이션이 실패할 때 호출되어, 호출자와 독립적으로 공통된 실패 처리를 수행할 수 있도록 합니다.
ruby class CreateUser < Dry::Operation def call(input) attrs = step validate(input) step persist(attrs) user end private def on_failure(failure) log_failure(failure) end # ... end
- 데이터베이스 트랜잭션 전략:
- 전체 플로우를 트랜잭션으로 래핑하는 방식과 #transaction 메서드를 통해 원하는 오퍼레이션만 수동으로 래핑하는 두 가지 접근 방식이 검토되었습니다.
- 최종적으로 후자인 #transaction 메서드를 통한 수동 래핑 방식이 채택되었습니다. 이는 개발자가 데이터베이스 트랜잭션의 저수준 세부 사항을 명확히 인지하고, 비용이 많이 드는 작업을 트랜잭션 내에 포함하지 않도록 유도하기 위함입니다.
- 이 결정은 dry-operation이 전체 플로우보다는 개별 오퍼레이션의 조합성을 장려하는 설계 철학과 일치합니다.
- ROM 확장이 이 접근 방식의 첫 번째 구현 사례이며, 향후 다른 데이터베이스 라이브러리에 대한 지원도 추가될 예정입니다.
ruby class MyOperation < Dry::Operation include Dry::Operation::Extensions::ROM attr_reader :rom def initialize(rom:) @rom = rom end def call(input) attrs = step validate(input) user = transaction do new_user = step persist(attrs) step assign_initial_role(new_user) new_user end step notify(user) user end # ... end
web_pipe: Zeitwerk 통합 및 아키텍처 실험
-
web_pipe는 이제 Zeitwerk 기반의 Ruby Gem으로, 향상된 자동 로딩 기능을 제공합니다.
-
현재 web_pipe의 내부 아키텍처에 대한 광범위한 실험이 진행 중이며, 이는 상당한 내부 개편으로 이어질 수 있습니다.
-
핵심 아이디어는 web_pipe 자체에서 의존성 주입 책임을 제거하고, 대신 dry-auto_inject와 같은 전용 의존성 주입 도구에 의존하도록 하는 것입니다. 이는 모듈성을 높이고 각 컴포넌트의 역할을 더욱 명확히 하는 데 기여할 것으로 예상됩니다.