【问题标题】:What do folks use app/services/ in rails applications人们在 Rails 应用程序中使用什么 app/services/
【发布时间】:2018-09-26 21:34:33
【问题描述】:

现在我和他们都会在 ruby​​ on rails 生态系统中遇到这种情况:

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

你也可以看一个例子here

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

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

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

什么 gem/plugin 创建了 app/services 文件夹? vanilla rails 应用程序最初并未附带它。

sidetone:我个人对实例化服务有疑问。我觉得 ametuer 程序员滥用类和实例化。我觉得类和实例化是“为了一件事”,而服务是“做”的事情 所以 mixins/defs/include 应该是我觉得应该走的路。

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

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

    Rails Service Objects: A Comprehensive Guide 提供了使用服务对象管理与 Twitter 对话或封装可能跨多个模型的复杂数据库事务的示例。

    Service Objects in Ruby on Rails…and you 显示创建服务对象来管理新用户注册过程。

    EngineYard 博客发布了Using Services to Keep Your Rails Controllers Clean and DRY,其中包含一个处理信用卡的服务对象示例。

    如果您正在寻找起源,Service objects in Rails will help you design clean and maintainable code. Here's how. 是 2014 年他们出现的时候。

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

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

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

    如果这听起来很像函数的作用,那你是对的!他们甚至建议使用call 作为服务上的公共方法名称,就像Proc 一样。您可以将服务对象视为一种命名和组织大型子例程的方式。

    Anatomy of a Rails Service Object 解决了服务对象和关注点之间的区别。它涵盖了服务对象相对于模块的优势。它详细介绍了什么是好的服务对象,包括......

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

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

    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
    

    使用基本的createdestroy 方法和关联以及一些回调,在列表中添加和删除用户的过程非常简单。

    现在你的老板想要一个精细的订阅流程,它可以进行大量日志记录、跟踪统计信息、向 Slack 和 Twitter 发送通知、发送电子邮件、进行大量验证……现在,简单的 createdestroy 变得复杂工作流联系 API 并更新多个模型。

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

    相反,您可以编写 SubscriptionRegistrationSubscriptionRemove 服务对象。这些可以包括发布和存储统计数据以及执行背景检查等的能力(或者更有可能将其放入更多服务对象中)。它们各有一个公共方法:SubscriptionRegistration.perform(user, list)SubscriptionRemove.perform(subscription)。 User、List 和 Subscription 不需要知道任何关于它的信息。您的模型保持苗条并做一件事。您的每个服务对象都做一件事。

    至于您的具体问题...

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

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

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

    你会的。 app/ 中的所有内容都会在 Rails 5 中自动加载。

    【讨论】:

    • 说:“服务对象用于不适合正常 MVC 范式的事物”。我觉得这是非常误导的。我喜欢邀请作者浏览github.com/rubocop-hq/rubocop/tree/master/lib。这是很棒的代码,但您找不到单个 MVC 或 Service 对象。无需借助 MVC 或服务对象就可以“完成 sh**”。事实上,如果你尊重 smalltalk (OO) lisp (functional) 传统,我觉得实现这个 Service 抽象是错误的方法
    • 作者的热门标签是 perl、c、mysql(几乎没有 OO 或功能性),所以我很想听听(答案)将 ruby​​ 或 rails 作为 SO profile 中的顶级标签的人
    • @american-ninja-warrior 您询问了 Rails 和 MVC 中使用哪些服务对象。当然,你可以在没有它们的情况下完成 sh**。你可以在没有 subroutines 的情况下完成 sh** (我已经看到了一些东西,伙计)。使用 rubocop 作为反例,它既不是 Rails 也不是 MVC,让我觉得我没有很好地解释它。需要明确的是,这不是面向服务的架构。没有通信协议。服务对象是一种组织 OO 代码以保持您的类干燥和集中的模式。您不必相信我的话,答案中链接了其他人的文章。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    • 2014-08-12
    • 2015-03-12
    相关资源
    最近更新 更多