MVC의 ‘V’ 재조명
2022년에도 고전적인 MVC(Model-View-Controller) 아키텍처에서 뷰 레이어를 구축하는 것이 유효한지에 대한 의문이 제기되곤 합니다. 현재 많은 프로젝트가 백엔드와 프론트엔드를 분리하여 운영하지만, 이는 개발 비용 증가와 인프라 복잡성 등 숨겨진 비용을 초래할 수 있습니다. GitHub와 같은 대규모 애플리케이션이 여전히 멀티 페이지 Rails 애플리케이션으로 운영되며 ERB 템플릿을 활용하는 사례는 서버 주도 MVC 방식의 잠재력을 보여줍니다. 또한, Phoenix LiveView에서 영감을 받은 Hotwire와 같은 ‘HTML over-the-wire’ 접근 방식은 JavaScript 없이도 반응형 웹 인터페이스를 구축할 수 있는 대안을 제시하며, 이는 SPA의 필요성을 다시금 고려하게 만듭니다. 결국, 어떤 방식이든 코드 구조를 합리적으로 관리하는 것이 중요하며, 여기서 ✨컴포넌트✨의 역할이 부각됩니다.
컴포넌트의 장점
프론트엔드 개발에서 컴포넌트 방식은 이미 보편화되어 있으며, 이는 컴포넌트가 고립성, 테스트 용이성, 재사용성, 조합성 등 좋은 코드의 특성을 모두 갖추고 있기 때문입니다. 반면, Rails의 기존 partials 및 뷰 헬퍼 방식은 결합도가 높고 데이터 흐름이 예측 불가능하며 테스트가 어렵다는 단점을 가집니다. ViewComponent는 이러한 문제를 해결하기 위해 Ruby 객체와 연결된 템플릿(ERB/Slim 등)이라는 간단한 아이디어를 기반으로 합니다. 컴포넌트는 일반 Ruby 객체처럼 인스턴스화하고 Rails의 #render
메서드로 렌더링하며, 이를 통해 예측 가능성(유지보수성)과 Ruby OOP의 강력한 기능을 뷰에 도입합니다.
특히, ViewComponent는 테스트 측면에서 혁신적입니다. 컴포넌트 테스트는 PORO(Plain Old Ruby Objects) 테스트만큼 용이하며, 기존 요청/시스템 테스트보다 훨씬 빠르고 안정적입니다. 이는 뷰 코드에 대한 신뢰를 높이고 통합 테스트의 부담을 줄여줍니다. 또한, 백엔드와 프론트엔드 팀 간의 개발 패러다임을 일치시켜 프론트엔드 개발자가 백엔드 뷰 코드에 쉽게 접근하고 수정할 수 있도록 돕는 큰 이점이 있습니다.
컴포넌트 활용법
ViewComponent를 효과적으로 사용하기 위해서는 몇 가지 원칙을 준수해야 합니다. 프론트엔드 커뮤니티에서 확립된 모범 사례들을 백엔드 환경에 맞게 적용하는 것이 중요합니다.
- 헬퍼가 아닌 실제 동작 테스트: 컴포넌트의 Ruby 클래스 내 메서드보다는 컴포넌트의 퍼블릭 인터페이스인 템플릿의 실제 동작(조건부 로직, 계산 등)을 테스트해야 합니다. 이를 통해 뷰 레이어의 높은 테스트 커버리지를 확보할 수 있습니다.
- 전역 상태 전달에 컨텍스트 사용:
current_user
와 같이 자주 사용되는 전역 데이터는dry-effects
와 같은 라이브러리를 통해 컨텍스트로 전달하여 ‘인자 드릴링(argument drilling)’ 문제를 피할 수 있습니다. 단, 과도한 사용은 데이터 흐름 추적을 어렵게 하므로 주의해야 합니다. - 깊게 중첩된 컴포넌트 트리 피하기: 컴포넌트 트리가 깊어지는 것을 방지하기 위해 데이터를 직접 전달하기보다 컴포넌트 자체를 슬롯(
renders_one
,renders_many
)을 통해 전달하는 방식을 활용합니다. 이는 컴포넌트의 재사용성을 높이고, ‘Smart’ 컴포넌트(애플리케이션 특정 로직)와 ‘Dumb’ 컴포넌트(재사용 가능한 UI 요소)를 분리하는 데 도움이 됩니다. - 단일 책임 원칙 준수: 큰 템플릿은 피하고, 컴포넌트가 하나의 책임만 갖도록 분해해야 합니다. 이는 코드 이해도를 높이고 리팩토링 및 재사용을 용이하게 하여 코드 품질을 향상시킵니다.
- 컴포넌트 내 DB 쿼리 피하기: 뷰는 데이터를 렌더링하는 역할을 하며, 데이터를 가져오는 역할은 컨트롤러에서 수행해야 합니다. 컴포넌트 내에서 DB 쿼리를 수행하면 N+1 문제와 같은 성능 저하를 유발할 수 있으므로, 데이터를 미리 로드하여 전달하는 것이 바람직합니다. 개발 단계에서는 컴포넌트의 DB 쿼리를 완전히 금지하는 설정도 고려할 수 있습니다.
이러한 가이드라인을 준수함으로써 ViewComponent를 활용한 개발 과정에서 발생할 수 있는 일반적인 함정을 피하고, 보다 견고하고 유지보수 가능한 코드를 작성할 수 있습니다.