2008-09-19 23 views
12

需要重构的想法,我继承了一个怪物箭反模式

它伪装成一个.NET 1.1应用程序处理符合医疗赔付文本文件(ANSI 835)的标准,但它是一个怪物。正在处理的信息涉及医疗保健索赔,EOB和报销。这些文件由在前几个位置具有标识符的记录和根据该类型记录的规格格式化的数据字段组成。某些记录ID是控制分段ID,它划分了与特定事务类型相关的记录组。

要处理的文件,我的小怪物读取第一个记录,确定的那种交易是将要发生,然后开始处理基于什么样的交易也正在处理其他记录。要做到这一点,它使用嵌套的if。由于有多种记录类型,因此需要做出多项决策。每个决策都涉及一些处理和2-3个需要根据以前的决定作出的其他决定。这意味着嵌套如果有很多嵌套。这就是我的问题所在。

如果是715线长这一个嵌套。恩,那就对了。七百和十五青少年线。我没有代码分析专家,所以我下载了几个免费的分析工具,并用49一麦凯布圈复杂度的评价,他们告诉我,这是一个相当高的数字了上来。亚特兰大地区的花粉计数较高,其中100为高标准,新闻称“今天的花粉计数为1,523”。这是我曾经见过的箭头反模式最好的例子之一。在最高处,缩进深度达15个标签。

我的问题是,你会建议什么方法重构或重组这样的事情?

我花了一些时间来寻找的想法,但没有给我一个很好的立足点。例如,用一个警戒条件代替一个等级是一种方法。我只有其中一个。一窝下来,十四个去。

也许有一个设计模式可帮助。命令链会成为解决这个问题的方法吗?请记住,它必须保持在.NET 1.1中。

感谢您的任何和所有的想法。

回答

2

A state machine看起来像是一个合乎逻辑的开始,如果你可以摆动它,就使用WF(听起来你不能)。

您仍然可以实现一个无WF,你就必须自己做。然而,从一开始就把它看成一个状态机可能会给你一个更好的实现,然后创建一个程序性怪物来检查每个动作的内部状态。

图你的状态,是什么原因导致的过渡。应该将处理记录的实际代码分解出来,并在状态执行时调用(如果该特定状态需要它)。

所以状态1的执行调用你的“读取记录”,然后根据该记录转换到另一种状态。

下一个状态可能会读取多个记录和呼叫记录处理指令,然后转换回状态1。

1

从描述来看,状态机可能是处理它的最好方法。有一个枚举变量来存储当前状态,并将处理实现为记录上的循环,使用开关或if语句根据当前状态和输入数据选择要执行的操作。你也可以很容易地派遣工作分开使用函数指针的基础上,国家职能,也一样,如果它变得太笨重。

2

一两件事,我在这些情况下,做的是使用“组合方法”的格局。有关此主题,请参阅Jeremy Miller's Blog Post。基本的想法是使用IDE中的重构工具来提取小的有意义的方法。一旦你完成了,你可能会进一步重构和提取有意义的类。

1

有时我用栈相结合的状态模式。

它非常适用层次结构;一个父元素知道什么状态推入栈来处理一个子元素,但是一个子元素不需要知道任何有关它的父元素的信息。换句话说,孩子不知道下一个状态是什么,它会发出信号,这是“完全”和被弹出堆栈。这有助于通过保持依赖性单向来将状态彼此分离。

它的伟大工程与SAX解析器处理XML(内容处理器只是push和pop状态的元素进入和退出,以改变其行为)。 EDI也应该适应这种方法。

+0

有趣的想法。我无法想象这会在代码中看起来如何。 – 2008-09-19 22:11:13

20

我只是在工作中,本周是相似的(虽然不是可怕的)一些遗留代码为你所描述的。

没有一两件事,将让你出这一点。 state machine可能是您的代码所需的最终形式,但这不是而是可以帮助您达到目标,在解开已有的混乱之前,您也不应该决定这样的解决方案。

我将采取的第一步是编写为现有代码的测试。这个测试并不是要显示代码是正确的,而是要确保在重新开始重构时不会破坏某些东西。获取大量的数据进行处理,将其提供给怪物,并获得输出。这是你的试金石。如果你可以使用代码覆盖工具来做到这一点,你会看到你测试的内容不包括在内。如果可以的话,构建一些也将使用此代码的人造记录,然后重复。一旦你觉得你已经完成了这项任务,你的输出数据就会成为你测试的预期结果。

重构不应该改变代码的行为。请记住。这就是为什么你已经知道输入和已知的输出数据集来验证你不会破坏的东西。这是你的安全网。

现在重构!

一对夫妇的事情,我这样做,我发现有用:

反转if声明

一个巨大的问题,我只是读代码的时候我找不到相应的else声明,我注意到,很多块看起来像这样

if (someCondition) 
{ 
    100+ lines of code 
    { 
    ... 
    } 
} 
else 
{ 
    simple statement here 
} 

通过倒置if我可以看到简单的情况,然后移动到第知道另一个人已经做了什么更复杂的块。不是一个巨大的变化,但帮助我理解。

提取方法

我用这一个lot.Take一些复杂的多路块,神交它,在它自己的方法,一边推它。这让我更容易看到代码重复的地方。

现在,希望你没有破坏你的代码(测试仍然通过吧?),并且你有更多的可读性和更好的理解程序代码。看看它已经改进了!但是您之前编写的测试并不够好......它只会告诉您,您复制了原始代码的功能(错误和全部),而这只是您所覆盖的行,因为我确定您会发现你无法知道如何击中或者根本无法击中的代码块(我在我的工作中都见过)。

现在,所有的大牌模式开始发挥作用了大的变化是,当你开始看你怎么可以在一个适当的面向对象的方式重构这个。这只猫的皮肤不止一种,它会涉及多种图案。不知道你正在解析的这些文件格式的详细信息,我只能围绕一些有用的建议,可能会或可能不是最好的解决方案。

Refactoring to Patterns是一个伟大的书,以协助explainging是在这些情况下有用的模式。

你试图吃掉一头大象,而且也没有其他办法做到这一点,但在一次一口。祝你好运。

+1

Upvoted为大象类比。这就是重构的本质。它是一点一点的。 – troelskn 2008-09-28 22:27:13

2

我会不羁使用提取方法的开始。如果您目前的Visual Studio IDE中没有它,您可以获取第三方插件,或者在较新的VS中加载项目。 (它会尝试升级您的项目,但你会仔细地忽略这些更改,而不是在检查它们。)

你说,你有代码缩进15个级别。开始约1/2出,并提取方法。如果你能想出一个好名字,就使用它,但如果你不能,那就抽出来。再分成两半。你不打算在这里找到理想的结构;你正试图将代码分解成适合你的大脑的代码。我的大脑不是很大,所以我会一直打破它,直到它不再受伤。

当你去,寻找那些似乎比其他人不同的任何新的长期方法。使这些进入新班级。只需使用一个简单的类,现在只有一种方法。嘿,使方法静态是好的。不是因为你认为自己是好班级,而是因为你对一些组织非常不满。

经常检查,你可以检查你的工作,以后了解历史,准备好做一些“真正的工作”,而不需要合并,并且保存你的队友很难合并的麻烦。

最终你会需要回去,并确保方法名是好的,您已经创建有意义的一套方法,清理新类等

如果你有一个高度可靠的Extract Method工具,您可以在没有良好的自动化测试的情况下离开。 (例如,我会相信VS。)否则,请确保你没有破坏任何东西,否则结果会比开始时更糟糕:使用一个根本不起作用的程序。

配对伴侣在这里会很有帮助。