본 발표는 루비 온 레일즈(Ruby on Rails) 애플리케이션의 유지보수성을 향상시키기 위한 모델 설계 및 관리 전략에 대해 심도 있게 다룹니다. 레일즈의 고유한 프레임워크 특성을 이해하고, 이를 바탕으로 이벤트형 모델, PORO(Plain Old Ruby Object), 그리고 폼 오브젝트와 같은 패턴을 적재적소에 활용하여 모델의 책임 범위를 명확히 하고 코드의 유지보수성을 높이는 방안을 제시합니다. 레일즈 개발 경험이 있는 엔지니어가 보다 견고하고 확장 가능한 코드를 작성할 수 있도록 장기적으로 유용한 지식을 제공하는 것을 목표로 합니다.
모델 설계의 시작점으로, 행위를 기록하는 이벤트형 모델(Event-type model)의 개념을 소개합니다. 주문(Order), 출하(Shipment), 결제(Payment)와 같이 ‘무엇인가를 하다’는 동사 형태의 이름을 가지는 이 모델은, 재고 증가와 은행 계좌 감소처럼 여러 모델에 걸쳐 발생하는 복잡한 처리 로직을 한곳에 모아 적절한 책무를 부여하는 데 유용합니다. 이는 레일즈 웨이(Rails Way)를 따르며 코드의 일관성과 설명력을 높이는 장점이 있습니다.
다음으로 PORO의 활용 방안에 대해 논합니다. PORO는 액티브 레코드(ActiveRecord)를 상속하지 않는 순수한 루비 클래스로, 데이터베이스 영속화가 필요 없는 객체(예: 외부 API 응답, 집계 결과, 임시 저장 데이터)나 이벤트형 모델로 적절히 표현하기 어려운 경우에 유용하게 사용될 수 있습니다. PORO 사용 시에는 팀 내에서 명확한 규칙(예: 클래스 이름은 반환 객체의 이름을 명사로 사용)을 정립하여 코드의 일관성을 유지하는 것이 중요합니다.
발표자는 서비스 레이어(Service Layer)의 광범위한 도입에 대해서는 다소 신중한 입장을 취합니다. 레일즈는 라우팅, 컨트롤러, 뷰, 모델 등 최소한의 레이어 분할을 통해 코드 구조의 복잡성을 줄이고 개발 생산성을 극대화하는 설계를 지향합니다. 모델은 ORM, 유효성 검사, 콜백, 비즈니스 로직 처리 등 다양한 역할을 수행하도록 설계되어 있으며, 이는 코드 응집성을 높이고 파일 수를 줄이는 효과를 가져옵니다. 서비스 레이어를 추가하는 것은 레일즈의 이러한 장점을 상쇄하고, 비즈니스 로직 코드를 모델과 서비스 객체 중 어디에 두어야 할지에 대한 혼란을 야기할 수 있습니다. 따라서 서비스 레이어 도입은 레일즈의 설계 철학을 깊이 이해한 후 신중한 판단이 필요합니다.
모델 분할, 즉 팻 모델(Fat Model) 문제를 해결하는 적절한 타이밍에 대해서도 구체적인 가이드라인을 제시합니다. 단순히 코드 라인 수가 많다고 모델을 분할하기보다는, 유효성 검증 로직에 조건부 분기(if/else)가 필요해져 코드가 복잡해질 때를 핵심적인 분할 시점으로 제안합니다. 레일즈 모델의 유효성 검사는 기본적으로 폼 입력 검증과 DB 저장 값 검증 두 가지 역할을 동시에 수행합니다. 그러나 애플리케이션이 성장하여 화면별로 요구되는 유효성 검사 규칙이 DB의 규칙과 달라지는 시점이 오면, 하나의 모델에서 조건부로 유효성 검사를 처리하는 것이 비효율적이고 코드를 이해하기 어렵게 만듭니다.
이러한 문제의 해결책으로 폼 오브젝트(Form Object)의 활용을 제안합니다. 폼 오브젝트는 특정 화면 또는 특정 목적을 위한 유효성 검사 및 데이터 처리를 담당하는 별도의 클래스입니다. ActiveModel::Model
과 ActiveModel::Attributes
모듈을 활용하여 모델과 유사하게 동작하는 폼 오브젝트를 생성하고, 화면별 유효성 검사 로직을 폼 오브젝트에 분리하여 작성합니다. 이를 통해 모델은 DB 관련 유효성 검사에 집중하고, 폼 오브젝트는 화면 입력에 대한 유효성 검사를 담당하게 되어 코드의 책임이 명확해지고 복잡성이 감소합니다. 이는 시간의 흐름에 따라 애플리케이션 설계가 변화해야 함을 보여주는 예시이며, 초기에는 모델이 두 가지 검증 역할을 모두 수행하다가 필요에 따라 폼 오브젝트로 분리하는 점진적인 접근 방식의 중요성을 강조합니다.
결론적으로 레일즈 애플리케이션의 성공적인 모델 설계와 지속 가능한 유지보수는 레일즈가 지향하는 바를 정확히 이해하는 데서 출발합니다. 행위 중심의 이벤트형 모델과 유연한 PORO의 적절한 활용, 그리고 레일즈의 밀결합 설계를 고려한 서비스 레이어 도입의 신중함은 중요한 설계 원칙입니다. 특히 유효성 검증 로직의 복잡성이 증가하는 시점을 모델 분할의 신호로 삼고 폼 오브젝트를 활용하여 책임을 분리하는 전략은 변화하는 요구사항에 효과적으로 대응하며 코드베이스를 건강하게 유지하는 핵심적인 방법입니다. 이러한 전략들은 레일즈 개발자가 보다 효율적이고 체계적으로 애플리케이션을 구축하고 관리하는 데 기여할 것입니다.