人们在 Rails 应用程序中使用 app/services/ 做什么

2024-02-11

我时常会在 ruby​​ on Rails 生态系统中遇到这种情况:

class LocalizeUrlService
class Services::UpdateUserRegistrationForOrder
class ProductionOrderEmailService
UserCart::PromotionsService.new(
Shipping::BulkTrackingService.new(bulk_update, current_spree_user)

您还可以查看示例here https://github.com/RailsApps/rails-devise-pundit/blob/master/app/services/create_admin_service.rb

然而,在例如“Ruby On Rails Guides”的官方示例中,我从未见过这一点。这让我相信这是一个来自与 Rails/OOP 不同的另一种语言/范式的概念。

这种范式/趋势从何而来?有教程/书吗 这些人受到了影响吗?这些人是否对几年前的 SOA 趋势持抵制态度?

将代码放入 app/service/blah_service.rb 是一个好主意吗? 如果是,什么逻辑/代码可以被视为“服务”材料。 是否有任何类型的代码可以/不属于服务?

什么 gem/plugin 创建了 app/services 文件夹?最初并没有附带原生 Rails 应用程序。

sidetone:就我个人而言,我对实例化服务有疑问。我觉得类和实例化被业余程序员滥用了。我觉得类和实例化是“为了某件事”,而服务是“做”某事 所以我觉得 mixins/defs/include 应该是正确的选择。


服务对象适用于那些不太适合正常 MVC 范例的事物。它们通常用于业务逻辑,否则会使您的模型或控制器过于臃肿。通常,它们没有状态(保存在模型中)并且执行诸如与 API 或其他业务逻辑对话之类的操作。服务对象可让您的模型保持精简且集中,并且每个服务对象也精简且专注于做一件事。

Rails 服务对象:综合指南 https://www.toptal.com/ruby-on-rails/rails-service-objects-tutorial有使用服务对象来管理与 Twitter 对话或封装可能跨多个模型的复杂数据库事务的示例。

Ruby on Rails 中的服务对象……还有您 https://hackernoon.com/service-objects-in-ruby-on-rails-and-you-79ca8a1c946e显示创建服务对象来管理新用户注册过程。

EngineYard 博客发布使用服务保持 Rails 控制器清洁干燥 https://www.engineyard.com/blog/keeping-your-rails-controllers-dry-with-services以进行信用卡处理的服务对象为例。

如果你要寻找根源,Rails 中的服务对象将帮助您设计干净且可维护的代码。就是这样。 https://www.netguru.co/blog/service-objects-in-rails-will-help是从2014年他们出现的时候开始的。

服务的优点是将应用程序的核心逻辑集中在一个单独的对象中,而不是将其分散在控制器和模型中。

所有服务的共同特征是它们的生命周期:

  • 接受输入
  • 执行工作
  • 返回结果

如果这听起来非常像函数的作用,那么你是对的!他们甚至建议使用call作为服务上的公共方法名称,就像Proc https://ruby-doc.org/core/Proc.html。您可以将服务对象视为一种命名和组织大型子例程的方法。

Rails 服务对象剖析 https://multithreaded.stitchfix.com/blog/2015/06/02/anatomy-of-service-objects-in-rails/解决服务对象和关注点之间的区别。它涵盖了服务对象相对于模块的优点。它详细介绍了如何构成良好的服务对象,包括......

  • 不存储状态
  • 使用实例方法,而不是类方法
  • 公共方法应该很少
  • 方法参数应该是值对象,要么被操作,要么需要作为输入
  • 方法应该返回丰富的结果对象而不是布尔值
  • 依赖服务对象应该可以通过私有方法访问,并在构造函数中或延迟创建

例如,如果您有一个为用户订阅列表的应用程序,则可能具有三种模型:用户、列表、订阅。

class List
  has_many :subscriptions
  has_many :users, through: :subscriptions  
end

class User
  has_many :subscriptions
  has_many :lists, through: :subscriptions
end

class Subscription
  belongs_to :user
  belongs_to :list
end

使用基本的方法,在列表中添加和删除用户的过程非常简单create and destroy方法和关联,也许还有一些回调。

现在,您的老板想要一个复杂的订阅流程,该流程可以进行广泛的日志记录、跟踪统计数据、向 Slack 和 Twitter 发送通知、发送电子邮件、进行广泛的验证......现在什么是简单的create and destroy变成一个联系 API 和更新多个模型的复杂工作流程。

您可以将所有这些内容编写为关注点或模块,将所有这些内容包含到这三个以前简单的模型中,然后编写大的Subscription.register and Subscription.remove类方法。现在,您的订阅可以发推文并发布到 Slack 并验证电子邮件地址并执行背景调查吗?诡异的。您的模型现在充斥着与其核心功能无关的代码。

相反,你可以写SubscriptionRegistration and SubscriptionRemove服务对象。这些可以包括发布推文、存储统计数据以及执行背景检查等的能力(或更可能将其放入更多服务对象中)。他们每个人都有一个公共方法:SubscriptionRegistration.perform(user, list) and SubscriptionRemove.perform(subscription)。用户、列表和订阅不需要了解任何相关信息。您的模特保持苗条身材并只做一件事。每个服务对象只做一件事。

至于你的具体问题...

这种范式/趋势从何而来?

据我所知,这是“胖模型/瘦控制器”趋势的结果;我就是这样想到的。虽然这是个好主意,但你的模特通常会变得太胖。即使有模块和关注点,将其塞进一个类中也会变得太多。通常会使模型或控制器膨胀的其他业务逻辑进入服务对象。

什么 gem/plugin 创建了 app/services 文件夹?

你做。一切都在app/在 Rails 5 中自动加载。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

人们在 Rails 应用程序中使用 app/services/ 做什么 的相关文章

随机推荐