这是重构ActiveRecord胖模型的正确方法吗?

时间:2021-09-13 20:57:12

If for example I've this ActiveRecord model:

例如,如果我有这个ActiveRecord模型:

app/models/order.rb

应用程序/模型/ order.rb

class Order < ActiveRecord::Base
  # model logic
end
require "lib/someclass.rb"

lib/somelass.rb

LIB / somelass.rb

class Order
  before_save :something
  # more logic here
end

Is that a good way to refactor/extract logic from model? Or maybe use concern class, service class or something else?

这是从模型重构/提取逻辑的好方法吗?或者也许使用关注类,服务类或其他什么?

2 个解决方案

#1


14  

Like someone told me a long time ago:

就像很久以前有人告诉我的那样:

Code refactoring is not a matter of randomly moving code around.

代码重构不是随机移动代码的问题。

In your example that is exactly what you are doing: moving code into another file

在您的示例中,这正是您正在做的事情:将代码移动到另一个文件中

Why is it bad?

为什么不好?

By moving code around like this, you are making your original class more complicated since the logic is randomly split into several other classes. Of course it looks better, less code in one file is visually better but that's all.

通过像这样移动代码,您将使原始类更复杂,因为逻辑被随机分成几个其他类。当然它看起来更好,一个文件中的代码更少在视觉上更好,但这就是全部。

Prefer composition to inheritance. Using mixins like this is asking to "cleaning" a messy room by dumping the clutter into six separate junk drawers and slamming them shut. Sure, it looks cleaner at the surface, but the junk drawers actually make it harder to identify and implement the decompositions and extractions necessary to clarify the domain model.

首选组合继承。使用像这样的mixins要求通过将杂物倾倒入六个独立的垃圾抽屉并将它们关上来“清理”凌乱的房间。当然,它在表面上看起来更干净,但垃圾抽屉实际上更难以识别和实现澄清域模型所必需的分解和提取。

What should I do then?

那我该怎么办?

You should ask yourself:

你应该问自己:

  • Which code goes together and could be part of a new class / module ?
  • 哪个代码组合在一起,可以成为新类/模块的一部分?
  • Where does it makes sense to extract code to somewhere else ?
  • 将代码提取到其他地方有意义吗?
  • Do I have some piece of code that is shared across my application ?
  • 我是否有一些代码在我的应用程序*享?
  • Can I extract recurrent patterns in my code base ?
  • 我可以在代码库中提取循环模式吗?

Extract Service Object

提取服务对象

I reach for Service Objects when an action meets one or more of these criteria:

当某个操作符合以下一个或多个条件时,我会访问服务对象:

  • The action is complex
  • 行动很复杂
  • The action reaches across multiple models
  • 该操作涉及多个模型
  • The action interacts with an external service
  • 该操作与外部服务交互
  • The action is not a core concern of the underlying model
  • 该行动不是基础模型的核心问题
  • There are multiple ways of performing the action
  • 有多种方法可以执行操作

Extract Form Objects

提取表单对象

When multiple model can be updated by a a single form submission, you might want to create a Form Object.

如果可以通过单个表单提交更新多个模型,则可能需要创建表单对象。

This enable to put all the form logic (name conventions, validations and so on) into one place.

这样就可以将所有表单逻辑(名称约定,验证等)放在一个地方。

Extract Query Objects

提取查询对象

You should extract complex SQL/NoSQL queries into their own class. Each Query Object is responsible for returning a result set based on the criterias / business rules.

您应该将复杂的SQL / NoSQL查询提取到自己的类中。每个查询对象负责根据标准/业务规则返回结果集。

Extract Presenters / Decorators

提取演示者/装饰者

Extract views logic into presenters. Your model should not deal with specific views logic. Moreover, it will enable you to use your presenter in multiple views.

将视图逻辑提取到演示者中。您的模型不应该处理特定的视图逻辑。此外,它还使您能够在多个视图中使用演示者。

More on decorators

更多关于装饰者

Thanks to this blog post to help me putting these together.

感谢这篇博文,帮助我将这些内容整合在一起。

#2


1  

Keeping the code in the same class moves logic, it doesn't extract it.

保持代码在同一个类中移动逻辑,它不会提取它。

Externalizing callback declaration is misleading and potentially dangerous. Callbacks are abused enough; forcing readers to hunt down related files is cruel.

外部化回调声明具有误导性和潜在危险性。回调被滥用了;强迫读者追捕相关文件是残酷的。

There's no general way to answer the question as asked; the "best" refactors depends on what's actually being refactoried. Lifecycle information should be obvious and precise, though.

根据要求,没有一般方法可以回答这个问题; “最好的”重构取决于实际被重构的内容。但是,生命周期信息应该是明显和精确的。

Concerns, services, decorators, facades, etc. are good mechanisms that support refactoring. Without knowing what's being refactored it's impossible to provide meaningful advice regarding what's "best".

关注点,服务,装饰器,外墙等是支持重构的良好机制。在不知道被重构的内容的情况下,不可能就什么是“最佳”提供有意义的建议。

#1


14  

Like someone told me a long time ago:

就像很久以前有人告诉我的那样:

Code refactoring is not a matter of randomly moving code around.

代码重构不是随机移动代码的问题。

In your example that is exactly what you are doing: moving code into another file

在您的示例中,这正是您正在做的事情:将代码移动到另一个文件中

Why is it bad?

为什么不好?

By moving code around like this, you are making your original class more complicated since the logic is randomly split into several other classes. Of course it looks better, less code in one file is visually better but that's all.

通过像这样移动代码,您将使原始类更复杂,因为逻辑被随机分成几个其他类。当然它看起来更好,一个文件中的代码更少在视觉上更好,但这就是全部。

Prefer composition to inheritance. Using mixins like this is asking to "cleaning" a messy room by dumping the clutter into six separate junk drawers and slamming them shut. Sure, it looks cleaner at the surface, but the junk drawers actually make it harder to identify and implement the decompositions and extractions necessary to clarify the domain model.

首选组合继承。使用像这样的mixins要求通过将杂物倾倒入六个独立的垃圾抽屉并将它们关上来“清理”凌乱的房间。当然,它在表面上看起来更干净,但垃圾抽屉实际上更难以识别和实现澄清域模型所必需的分解和提取。

What should I do then?

那我该怎么办?

You should ask yourself:

你应该问自己:

  • Which code goes together and could be part of a new class / module ?
  • 哪个代码组合在一起,可以成为新类/模块的一部分?
  • Where does it makes sense to extract code to somewhere else ?
  • 将代码提取到其他地方有意义吗?
  • Do I have some piece of code that is shared across my application ?
  • 我是否有一些代码在我的应用程序*享?
  • Can I extract recurrent patterns in my code base ?
  • 我可以在代码库中提取循环模式吗?

Extract Service Object

提取服务对象

I reach for Service Objects when an action meets one or more of these criteria:

当某个操作符合以下一个或多个条件时,我会访问服务对象:

  • The action is complex
  • 行动很复杂
  • The action reaches across multiple models
  • 该操作涉及多个模型
  • The action interacts with an external service
  • 该操作与外部服务交互
  • The action is not a core concern of the underlying model
  • 该行动不是基础模型的核心问题
  • There are multiple ways of performing the action
  • 有多种方法可以执行操作

Extract Form Objects

提取表单对象

When multiple model can be updated by a a single form submission, you might want to create a Form Object.

如果可以通过单个表单提交更新多个模型,则可能需要创建表单对象。

This enable to put all the form logic (name conventions, validations and so on) into one place.

这样就可以将所有表单逻辑(名称约定,验证等)放在一个地方。

Extract Query Objects

提取查询对象

You should extract complex SQL/NoSQL queries into their own class. Each Query Object is responsible for returning a result set based on the criterias / business rules.

您应该将复杂的SQL / NoSQL查询提取到自己的类中。每个查询对象负责根据标准/业务规则返回结果集。

Extract Presenters / Decorators

提取演示者/装饰者

Extract views logic into presenters. Your model should not deal with specific views logic. Moreover, it will enable you to use your presenter in multiple views.

将视图逻辑提取到演示者中。您的模型不应该处理特定的视图逻辑。此外,它还使您能够在多个视图中使用演示者。

More on decorators

更多关于装饰者

Thanks to this blog post to help me putting these together.

感谢这篇博文,帮助我将这些内容整合在一起。

#2


1  

Keeping the code in the same class moves logic, it doesn't extract it.

保持代码在同一个类中移动逻辑,它不会提取它。

Externalizing callback declaration is misleading and potentially dangerous. Callbacks are abused enough; forcing readers to hunt down related files is cruel.

外部化回调声明具有误导性和潜在危险性。回调被滥用了;强迫读者追捕相关文件是残酷的。

There's no general way to answer the question as asked; the "best" refactors depends on what's actually being refactoried. Lifecycle information should be obvious and precise, though.

根据要求,没有一般方法可以回答这个问题; “最好的”重构取决于实际被重构的内容。但是,生命周期信息应该是明显和精确的。

Concerns, services, decorators, facades, etc. are good mechanisms that support refactoring. Without knowing what's being refactored it's impossible to provide meaningful advice regarding what's "best".

关注点,服务,装饰器,外墙等是支持重构的良好机制。在不知道被重构的内容的情况下,不可能就什么是“最佳”提供有意义的建议。