如何避免巨型胶水方法?


21

在我目前的工作中,我曾几次被要求清理旧代码。通常,代码是迷宫式的,其背后的数据甚至更复杂。我发现自己将事情整理成漂亮,整洁的模块化方法。每种方法都做一件事并且做得很好。那时候事情开始往南走...

最终,我总是得到一个干净的API,并且没有真正的方法将它们捆绑在一起。解决方法是编写一个大的丑陋的“粘合”方法(通常充满条件语句),该方法最终调用我所有的“清洁”方法。

胶水方法通常最终是我试图清除的代码/数据缠结的简洁版本。它通常更具可读性,但仍然很烦人。

如何避免这种方法?这是数据纠结的征兆还是我做错事情的反映?


3
应该使用API​​。从混乱的混乱中,您创建了一个API,然后重新进行了混乱。也许这只是业务需求。但是您增加了价值,因为其他人可以使用您的API来轻松实现另一个粘合功能。无需拧手...
Aditya MP

1
我们是在这里谈论对象还是在整个地方都只是在玩笑?
Erik Reppen

3
我不认为这是该问题的重复部分,我的发言范围更广(比单个函数更大)。
cmhobbs

1
erik-我在这里谈论对象和方法。我已经处理了两个条件混乱,并将它们变成了API。问题是当需要调用API时出现的。不过,这里的第一个答案可能正是我要寻找的。
cmhobbs 2013年

2
那到底是什么副本?
MattDavey

Answers:


12

我将为您提供重构LedgerSMB的经验。我们决定尽早做一些不同的事情,并且仍然按照您描述的方式做,但是没有很多胶合方法(顺便说一下,我们有一些胶合方法,只是没有很多)。

两个代码库的生活

LedgerSMB依靠两个代码库生存了大约5年,在淘汰旧代码库之前,还有更多的时间。原来的代码库真是恐怖。错误的数据库设计,Perl的构造像IS->some_func(\%$some_object);和代码一样,确切地说明了为什么有时使用意大利细面条的隐喻(执行路径在模块之间,后面和语言之间蜿蜒,没有韵律或原因)。新的代码库通过将数据库查询移入存储过程,具有用于请求处理的更简洁的框架等来避免这种情况。

我们决定要做的第一件事是尝试逐模块重构模块。这意味着将特定区域中的所有功能移到新模块中,然后将旧代码挂接到新模块中。如果新的API是干净的,那没什么大不了的。如果不是新的API,那么事情就变得麻烦了,这就是在新API上加倍努力的邀请。

第二件事是,很多时候新代码必须访问旧代码中的逻辑。应尽可能避免这种情况,因为它会导致丑陋的胶合方法,但不能总是避免。在这种情况下,应尽量减少涂胶方法,并尽可能避免使用,但在必要时使用。

为了完成这项工作,您必须承诺重写特定区域中的所有功能。例如,如果您可以一次重写所有客户信息跟踪代码,则意味着从旧代码调用此代码的代码不难处理,并且可以最大程度地减少从新代码向旧代码的分发。

第二件事是,如果您拥有适当的抽象,则应该能够选择要调用的API级别以及如何保持该级别的清洁。但是,您应该考虑重写正在调用API的部分,以使它们也更加干净。

商业工具的许多领域都是不可简化的。您无法摆脱所有复杂性。但是,您可以通过专注于专门用于执行所需工作的干净API以及可建设性地利用该API的模块来进行管理。只有在考虑重写其余调用代码可能会更快之后,才应该使用Glue。


我想您可能已经砸到头了。胶水存在的原因可能是由于调用了我创建的接口的代码所致。我将等待更多的答复,以查看是否遗漏了任何内容,但我相信这可以很好地总结一下。
cmhobbs

1
“执行路径在模块之间,后台之间以及语言之间蜿蜒而行,没有韵律或理由”-这也使我想起了一些现代的OO做法。
user253751

8

这听起来像你所做的就是采取的一团糟什么precedural代码库并建立了一个可爱的模块化precedural代码库。

最终,我总是得到一个干净的API,并且没有真正的方法将它们捆绑在一起。解决方法是编写一个大的丑陋的“粘合”方法(通常充满条件语句),该方法最终调用我所有的“清洁”方法。

使用过程代码(即使伪装成OO),您总会在某种地方定义某种顺序的工作流,通常会像您所描述的那样充满复杂的条件分支。我怀疑代码的这种过程性质使您感到有些不对劲。这不一定是一件坏事,并且在使用遗留代码时可能是完全不可避免的


6

您应该像清理原始代码库一样清理难看的胶水方法。用整洁的模块化方法将其拆分。您可能有几行代码,它们执行一些任务,将这些行拆分为方法,如果您共享一些变量,则可以考虑将共享变量和新方法放在一个类中。


2
那你不明白吗?
Pieter B

3
@PieterB也许可以,但是当您以不同的方法执行不同的任务时,提取不同的依赖关系会更容易。提取新方法后,您可以进行另一次重构。
Paling

1

基本上,你不断添加抽象层,直到它看起来就在每一层对自己采取的。关于抽象的自相矛盾的事情是您增加了复杂性以减少它,因为当您阅读抽象的代码时,您一次只关心一层。如果每一层足够小以至于易于理解,那么紧靠多少层都没有关系。

这也是使抽象难以编写的原因。如果您试图一次将所有抽象层次都保留在脑海中,即使是像铅笔这样简单的事情也会使您弯曲。关键是按照自己喜欢的方式获得一层,然后完成,然后忘记构成该层的所有复杂性,并在下一层执行相同的操作。


0

听起来您只是通过考虑API的实现来重构API,却没有充分考虑使用该API的代码-即您正在谈论的“胶水代码”。

如果是这样,您可以尝试从另一端开始。重写有可能首先成为您的丑陋粘合代码的东西,并创建几个尚未实现的接口,这些接口将在该过程中成为您的API。到目前为止,请不要过多考虑此API的实际实现-如果您有直觉,可以这样做就可以了。然后才重写代码迷宫以符合该API。当然,在此过程中,API和粘合代码会有所更改,但应该更好地结合在一起。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.