3

我将问题从 IRC 移到这里。

问题:我已经进入了一个我想要保持良好状态的代码库。我们不总是吗?

本着这种精神,在添加了一些覆盖率(如测试覆盖率)之后,我应用了几个已知的重构/改进来帮助完成这项任务。这是我所做的(实际上我做了更多,但这些是我的问题的相关部分):

  1. 添加了一些 PORO 对象以卸载在模型、控制器甚至视图中执行的一些任务。
  2. 使用 *decent_exposure* 来摆脱视图层所在的实例变量地狱。
  3. 使用draper实现了一些 for-views 装饰器,以避免在视图中包含太多逻辑。
  4. 为产生多个模型的操作添加了演示者。

现在,我(乐观地)预计这一切都会得到回报。确实更好,但是除了厨房水槽之外的所有东西都扔了之后,我本以为它会好得多。它不是。

由于我有一个视图层,它实际上是在单个操作上呈现 10-15 个部分,所以我担心我在控制器或视图层中更改内容的能力。每当我决定将帐户的成员称为“成员”或仅称为“用户”时,我都不想经历所有这些部分。我很关心这一点,因为模型层计划遭受更重大的变化。

我最初的想法(并且仍然坚持)是有愚蠢的观点。我希望我的大部分视图层完全避免知道他们正在渲染的模型。我想要一个知道如何做两件事的中间对象:从模型中提取它需要的数据,并呈现 HTML。在你告诉我我在这里违反了 SRP 之前,这个对象的真正责任可以理解为“向最终用户显示模型”。

在过度简化的情况下,我希望我的观点(至少上述这些观点)看起来像这样:

= some_object.render
= another_object.render

它听起来确实像装饰者模式,也听起来像演示者模式,至少我是这样的。

然后我开始认为我会对 MVC(至少是 rails 公开的 MVC)有很大的争议,所以我想知道这是否是最好的解决方案(除了明显的,在这个时间限制下几乎不可能,重写) ,所以我对投篮更有信心。

因此,在这种情况下,我真正的问题归结为:

a) 切换到 MVP、MVVM、MV 是否是解决这个问题的正确解决方案?

b) 如果是,你能告诉我我可以为这个 some_object.render 视图样式使用的最佳解决方案吗?

c)如果不是,能否告诉您如何避免这些部分和视图之间的硬依赖,而模型层可能需要数小时才能被显着重写?

d) 希望你不要来这里:YAGNI,所以之后修复?我很确定我会需要它。

我想到了另一种选择并带到了 IRC,不是真正的标题精神,而是一个有效的选择(尽管我认为手头的任务有点矫枉过正):

e) 添加一个服务层,并使我的视图映射到该服务层上的“逻辑”模型,因此我能够独立于视图更改物理模型。

4

2 回答 2

3

这个问题很难回答,主要是因为你的确切问题含糊不清。有趣的是,我认为这也是你觉得需要帮助才能继续前进的原因。

总结一下:

您已经重构为:

  • 愚蠢的观点
  • 干净的景色
  • 测试视图

不过,您的主要抱怨是:

我有一个视图层,它实际上是在单个操作上呈现 10-15 个部分,我担心我在控制器或视图层中更改内容的能力。我不想经历所有这些部分

我会做什么:

我会通过将相关视图合并在一起来解决“我有太多视图文件”。

我会通过组织我的视图以更好地适应代码实际变化的方式来解决“我找不到我的视图代码”。

笔记:

听起来您正面临两种反模式:

  • 解决方案蔓延(过度分解)
  • 过度使用模式

如果 10-15 个分音看起来过多,也许就是这样!每个部分都在代码库中重复使用吗?它们可以更好地分组(所以我可以渲染 1 而不是 3)?我可以发送一个部分数据来调整其渲染而不是创建 2 个部分吗?

听起来你可能在“责任分工”方面走得太远了,而且大量的观点正在阻碍你。也许重组是前进的道路?

寻找 MVP、MVVM 等是错误的方向。沉迷于模式可能会伤害你一点。例如,

# how is this:
= some_object.render

# different from this?
= render "some_object"

视图可以确定地负责“向最终用户显示模型”

我感觉到你的痛苦,有时代码量本身就是一个问题。组织和分组虽然技术含量低,但可能是解决它的最佳方法。

于 2012-08-21T02:34:18.987 回答
1

不是对您的问题的一般答案,但对于您提到的这个特定问题:

每当我决定将帐户的成员称为“成员”或仅称为“用户”时,我都不想经历所有这些部分。

使用 Rails i18n。它不仅适用于实际的 i18n,它也是一种干掉用户可显示术语和其他语言的好方法,就像这样。

这可能是您问题的一般答案的线索:可能不只有一个答案,可能有不同的答案来提高代码不同方面的可维护性和可理解性。

这东西很难,可能不要相信任何说有灵丹妙药的人,如果你只是按照他们说一切都会好的方式去做——尤其是如果他们在不知道更多细节的情况下说的话,那么一般/您给我们的项目/问题的一般描述。

但我不认为演示者/装饰者的方法有什么问题,如果它似乎能让事情变得更好的话。请记住保持简单;如果您可以摆脱纯粹的无魔法 ruby​​ 装饰器/演示器,我认为这比使用一些奇特的神秘实现的 rails 引擎要好。永远记住,我们的目标是让事情尽可能简单(而不是更简单),这样你就走在了正确的道路上。(是的,有时我意识到我为了保持简单而把事情复杂化了。哎呀)。

对于我认为你的问题的另一部分,

我有时会在我的模型上使用装饰器来提供返回部分名称以用于呈现它们的方法。我不确定当我这样做时我是否对解决方案完全满意,但是,嘿,这与 Rails 自己猜测模型部分名称的神奇方式(可能有 -以某种方式自定义或参数化,但没有人能记住/找到它)。而且我认为它比some_object.render. 相反,更像render :partial => some_object.render_partial_name, :object => some_object.

或者你可以提供你提到的那个中间对象,它基本上是一个演示者类型的东西,实际上与上面非常相似,尽管具有不同的对象图:

PresentWidget.new( some_object ).render

但是你必须使用一些魔法来制作一个能够适当调用 ActionView 渲染的单独对象。一些神奇的 Rails Presenter 引擎可以帮助您做到这一点。但我总是被太多的魔法关闭。

或者你可以看看细胞。我经常认为我想要 Cells 来解决这样的问题,尽管我个人在开始尝试使用它时,总是以“太多魔法,太多与铁轨打架”而告终,然后再次放弃它。

和一个类似的堆栈溢出问题,也没有任何特别令人惊叹的解决方案,但也许它会给你一些想法:对象的动态部分名称

不过,在所有选项中,我个人不会为模型本身提供#render方法。将独立演示者连接到 ActionView 以便它可以调用render是一回事,像这样将模型连接到其中似乎更糟。

最后,你确定重写不比重写好?

在您花费所有时间思考并实施这种架构之后——您可能会发现首先重写该东西会更快,您一直说您没有时间去做。如果您很清楚如何将其重写为更清洁,但不明显如何在顶部添加这个奇怪的元 rigamarole 以更清洁......为什么不做显而易见的事情呢?在上面添加这些东西自然也会重写/重构。

于 2012-08-21T03:14:02.860 回答