서비스 클래스에 대해 다시 생각하다: 한 레일즈 개발자의 10년

今改めてServiceクラスについて考える 〜あるRails開発者の10年〜 / Tomohiro Hashidate (joker1007) - Kaigi on Rails 2025

작성자
Kaigi on Rails
발행일
2025년 11월 25일

핵심 요약

  • 1 서비스 클래스와 폼 클래스는 복잡성 해결의 만능 해결책이 아니며, 핵심은 도메인 이해와 ActiveRecord의 효과적인 관리입니다.
  • 2 팀 개발 환경에서 예측 가능하고 일관성 있는 코드 구조를 유지하며, 개발자 간의 공통 인식을 형성하는 것이 지속적인 개발의 핵심입니다.
  • 3 모듈러 모놀리스 아키텍처와 같은 구조적 접근을 통해 컴포넌트 간의 경계를 명확히 하고, 코드 가시성을 제어하는 것이 중요합니다.

도입

발표자는 '퍼펙트 루비 온 레일즈'의 공동 저자인 Joker8007(하시 토모히토)입니다. 그는 10년 전 서비스 클래스의 활용을 주장했으나, 2016년 말에는 "서비스 클래스를 만들지 말아달라"고 후회하는 트윗을 남기며 상반된 입장을 보였습니다. 이번 발표는 이러한 경험을 바탕으로 서비스 클래스에 대한 10년간의 성찰을 공유하며, 도메인 주도 설계(DDD)의 영향과 함께 Rails 개발에서 서비스 클래스의 역할과 한계에 대해 깊이 있게 탐구합니다.

서비스 클래스의 등장과 초기 정의

서비스 클래스는 Rails 3.1~3.2 시대에 Fat Model(비대해진 모델) 문제에 대한 해결책으로 부상했습니다. 당시 발표자는 ‘퍼펙트 레일즈’에서 서비스 클래스를 컨트롤러와 모델 사이의 인터페이스로 정의하며, 비즈니스 로직을 캡슐화하고 유비쿼터스 언어(Ubiquitous Language)에 기반한 명명의 중요성을 강조했습니다. 이는 도메인 주도 설계(DDD)의 영향을 받은 것으로, 소프트웨어 개발에서 비즈니스 도메인 이해의 중요성을 인지하고 있었습니다.

서비스 클래스 활용의 어려움과 한계

그러나 발표자는 시간이 지나면서 서비스 클래스 사용의 어려움을 깨달았습니다. “신중하게 사용하라”는 기준이 사람마다 다르고, 비즈니스 도메인에 대한 이해도 차이로 인해 ‘단순히 복잡한 것’에 쉽게 이름을 붙이는 경향이 있었습니다. 특히 Active Record의 데이터 조작과 기능의 행위를 적절히 분리하는 것이 매우 어려웠으며, 이는 팀 개발 시 공통 인식 부족으로 이어져 코드의 일관성을 해치는 주된 원인이 되었습니다. Rails의 기본 레이어(Controller-Model-View)는 어디에 무엇이 있을지 예측하기 쉬운 강력한 공통 인식을 제공하는데, 서비스 클래스의 무분별한 도입은 이러한 프레임워크의 장점을 훼손할 수 있습니다.

폼 클래스의 역할과 근본적인 문제

최근 논의되는 폼 클래스는 서비스 클래스와 유사하게 단일 Active Record 클래스의 책임으로 처리하기 어려운 문제의 해결책으로 제시됩니다. 폼 클래스는 화면/액션과 연동되어 명명하기 쉽고, Active Model 및 Active Record 인터페이스와의 친화성이 높다는 장점이 있습니다. 그러나 폼 클래스 역시 Active Record에 기인한 진정한 의존성 문제(예: 여러 폼/서비스에서 Active Record 메서드를 호출할 때 발생하는 수정의 파급 효과)를 해결하지 못합니다. 결국 Active Record를 효과적으로 정리하는 것에서 벗어날 수 없으며, 이는 Rails의 큰 과제 중 하나입니다.

도메인 컨텍스트 이해와 모듈러 모놀리스

근본적인 해결책은 도메인 컨텍스트를 깊이 이해하고 컨텍스트 맵을 만드는 것입니다. 복잡한 시스템에서는 바운디드 컨텍스트(Bounded Context)를 통해 시스템의 각 컴포넌트와 그 상호작용을 명확히 정의하고, 의존성을 한 방향으로 유지하여 경계를 넘는 영향이 없도록 제어해야 합니다. 루비(Ruby) 세계에서는 모듈(Module)을 이용한 이름 공간과 디렉터리 구성으로 이를 시도했으나, 현대에는 모듈러 모놀리스(Modular Monolith)가 현실적인 대안으로 부상하고 있습니다. 모듈러 모놀리스는 분산 시스템의 복잡성을 피하면서도 컨텍스트 경계를 명확히 하고 강제하는 것을 목표로 합니다. Shopify의 Packwerk나 개발 중인 Ruby Boxes(네임스페이스)는 이러한 가시성 제어와 컴포넌트 간 의존성 검증을 위한 도구로 활용될 수 있습니다.

지속적인 판단과 개선의 중요성

컨텍스트 매핑과 컴포넌트 분할은 한 번에 완벽하게 이루어지는 것이 아니라, 코드와 멘탈 모델을 오가며 지속적으로 판단하고 개선해야 하는 과정입니다. 이는 ‘상류(upstream)’ 작업으로 불리며, 개발팀 전체가 꾸준히 노력해야 합니다.

결론

결론적으로, 발표자는 서비스 클래스나 폼 클래스 자체의 중요성보다는, 팀이 지속적으로 협력하여 개발하는 과정의 어려움에 초점을 맞춥니다. 개발자들이 코드를 쉽게 이해하고 예측하며, 놀라움이 적은 개발 경험을 제공하는 것이 핵심입니다. 이를 위해 읽기 쉬운 코드를 작성하고, 이해하기 쉬운 구조를 유지하며, 도메인 컨텍스트 매핑을 통해 지속적인 개선을 추구해야 합니다. 정답은 없으며, 끊임없이 함께 고민하고 발전해나가는 자세가 중요합니다. 좋은 시스템 설계는 순간적인 결정이 아니라, 지속적인 개발 흐름을 유지하고 새로운 개발자가 쉽게 이해하며 비즈니스가 의도한 대로 발전할 수 있는 상태를 꾸준히 유지하는 것을 의미합니다.

댓글 0

로그인이 필요합니다

댓글을 작성하거나 대화에 참여하려면 로그인이 필요합니다.

로그인 하러 가기

아직 댓글이 없습니다

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