개발자 노트

ActiveRecord 고찰 본문

컴퓨터 언어/Ruby

ActiveRecord 고찰

jurogrammer 2021. 2. 19. 11:32

Active Record 고찰

참고자료

1. steveklabnik.com/writing/the-secret-to-rails-oo-design
2. blog.carbonfive.com/does-my-rails-app-need-a-service-layer
3. bamboolab.eu/blog/being-more-effective-in-rails-with-services
4. www.codewithjason.com/rails-service-objects
5. sites.google.com/site/unclebobconsultingllc/active-record-vs-objects
6. medium.com/root-engineering/separating-data-and-code-in-rails-architecture-3a031e17706b

의문

레일즈에서는 DB에서 데이터 조회시 컨벤션으로 active record를 사용합니다. 하지만, 실무에서 프로젝트가 커짐에 따라 "active record 컨벤션을 지키는 것이 좋을까?"란 의구심이 생겼습니다. 그래서 자료를 찾아보고 나름의 결론을 이 글을 작성해봅니다.

Active Record란 무엇일까?

rails guides

Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic.

active record는 MVC모델에서 Model에 해당하는 부분이며, 비즈니스 데이터를 표현하고, 로직을 담는 역할을 합니다.

어떤 부분에서 문제일까?

1. SRP 위반

대표적으로 User class를 고려해보겠습니다. 가장 하는 일이 많을 수 있는 active record이죠? 주문 배송 비즈니스를 고려해볼게요.

1) 보안

해당 유저가 인증된 유저인지 확인하는 메서드가 필요할 수 있죠?

2) 포인트

소유하고 있는 포인트가 있는지 확인할 수 있습니다. 사용할 수도 있고, 내역도 볼 수 있겠죠?

3) 주문

주문내역이 있는지, 잘 배송되고 있는지 조회할 수 있습니다.

간단히 적어봤는데도 벌써 3가지 이상의 도메인이 user class내에 섞여있습니다. 이게 좋은 방법일까요? 이대로 쭉 작성한다면 코드가 1000줄도 가뿐히 넘겨버리겠네요. SRP를 철저히 위배하고 있습니다.

2. Object 특성을 지니지 못함

이부분은 엉클 밥의 말을 따라보겠습니다. data structure같으면서도 객체지향의 성향을 띄고 있습니다. 하지만 data structure에 가깝죠. 객체지향이라면 자신의 상태 값을 노출시키면 안됩니다. 하지만 active record는 자신의 상태를 노출시킬 뿐더러, 변경할 수 있을 여지까지 줍니다.

그리고 OOP의 특징인 상속을 하기 어렵습니다.

따라서 data structure에 가깝다 볼 수 있죠.

어떻게 사용해야 할까?

controller...?

결국 Object의 특성을 지니기 어렵고, SRP을 위반하기 쉬운 방법이 바로 Thin controller, Fat model라고 볼 수 있죠.

그럼, 모델에 비즈니스 로직을 못 넣는다면 컨트롤러에 넣어야 할까요? 그건 또 아니라고 봅니다. MVC모델에서 컨트롤러는 View에 보내기 위한 데이터를 전달해주는 역할만 해야 합니다. 또한, 비즈니스 로직을 컨트롤러에 넣는다면 다른 컨트롤러에서 비즈니스 로직을 재사용하기 어렵겠죠.

 

컨트롤러와 Active record사이에 하나의 Layer가 더 필요하다는 느낌이 오죠? 특정 서비스 요청에 대해 모델에서 데이터를 요청하여 비즈니스 로직을 수행하는 역할을 하는 레이어요.

Spring을 써보신 분이라면 생각나는게 있으실겁니다. 네, 맞아요 우리에겐 Service Layer가 필요합니다.

Service Layer

이점

service layer를 생성하면 다음과 같은 이점이 생깁니다.

1. 도메인에 따른 비즈니스 로직 구분

위에서 보안, 포인트, 주문에 대한 도메인을 따로 분리해서 관리할 수 있게되죠. 위 각 도메인도 꽤 큰 편이니깐

app/services/security
app/services/point
app/services/order

정도로 패키지를 나누고, 각각에 맞는 서비스 클래스를 작성해주면 될겁니다. 주문 내역 서비스는

app/services/order/order_list_service.rb

로 생성하면 되겠죠?

그리고 이 서비스에서는 주문 내역을 확인할 수 있도록 user, order active record를 조회하여 요청에 맞도록 처리해주면 됩니다.

2. 서드파티 라이브러리 사용 작업 처리

서드 파티 라이브러리를 이용한 작업에도 유용한 레이어가 됩니다.

예를 들어서 주문내역을 조회하여 server side에서 PDF를 생성해보려 합시다. Active Record에 넣는게 좋을까요? PDF를 생성하려면 레이아웃을 작성하고, 라이브러리에 맞게 데이터를 전처리해야 합니다. 이 모든 로직이 Active Record에 들어가는게 어색하지 않은가요?

하지만, service layer를 두었다면 OrderPDFService클래스에 로직을 담아두면 그만입니다. 훨씬 SRP에 적합하게 되겠죠.

주의점

rails에서 DI framework를 지원해주지 않기 때문에 서비스 객체 생성시 concrete class에 의존할 수 있습니다. decoupling이 필요한 서비스라면 이 부분을 고려하여 개발하는 것이 좋을 것 같습니다.

결론

서비스가 작다면, Active Record를 사용하는 것이 명쾌할 때가 있습니다. ruby가 추구하는 easy-to-use scripting language에는 적합하다 볼 수도 있겠네요. 하지만, 명쾌함 뒤에도 상태 값이 변경될 수 있다는 여지가 존재할 수 있죠. 그래서 서비스가 크든 작든 유지보수를 위해서라면 active record에 비즈니스 로직을 넣는 것은 지양해야할 일이 아닌가 싶습니다.

하지만, 모든 선택은 트레이드 오프가 있으니... 왜 안 좋은 방법인지, 좋은 방법인지를 이해하고 상황에 맞게 판단하시면 좋을 것 같습니다.

반응형

'컴퓨터 언어 > Ruby' 카테고리의 다른 글

Yield에 대하여 부제 : 함수형 프로그래밍  (0) 2020.07.22
Comments