微型重构代码以提高质量是否有用,还是只是“移动代码”而没有太多好处?


12

我遇到了在一个地方完成所有工作的整体代码-从数据库加载数据,显示HTML标记,充当路由器/控制器/动作。我开始应用SRP将数据库代码移动到其自己的文件中,从而为事物提供了更好的命名,而且看起来都不错,但是随后我开始怀疑为什么要这样做。

为什么要重构?什么目的?它没用吗?有什么好处?请注意,我基本上保留了整体文件,但只重构了与需要进行某些工作的区域相关的较小部分。

原始代码:

举一个具体的例子,我遇到了以下代码片段-它通过已知的产品ID或用户选择的版本ID加载产品规格:

if ($verid)
    $sql1 = "SELECT * FROM product_spec WHERE id = " . clean_input($verid);
else
    $sql1 = "SELECT * FROM product_spec WHERE product_id = " . clean_input($productid) ;
$result1 = query($sql1);
$row1 = fetch_array($result1);
/* html markup follows */

重构:

由于我正在做一些工作,要求我在代码的此特定部分中进行更改,因此我将其更改为使用存储库模式,并将其升级为使用面向对象的MySQL工具:

//some implementation details omitted 
$this->repository = new SpecRepository($mysql);
if ($verid)
    $row1 = $this->repository->getSpecByVersion($verid);
else 
    $row1 = $this->repository->getSpecByProductId($productid);
/* html markup follows to be refactored or left alone till another time*/

//added new class:
class SpecRepository extends MySqlRepository
{

    function getSpecByVersion(int $verid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE id = ?
        ", $verid)->getSingleArray();
    }

    function getSpecByProductId(int $productid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE product_id = ?
        ", $productid)->getSingleArray();
    }
}

我应该这样做吗?

回顾这些变化,代码仍然存在,代码具有相同的功能,但是在不同的文件,不同的名称,位置,使用的是更多面向对象的样式,而不是过程式的。实际上,有趣的是,尽管重构的代码具有相同的功能,但看起来却显得肿得多。

我预见到一些答案,说“如果您不知道重构的原因,那就不要这样做”,也许我会同意。我的理由是随着时间的推移提高代码质量(我希望我会遵循SRP和其他原则来这样做)。

这些理由足够好吗?还是我浪费时间在这种“重新排列代码”上?总体而言,这听起来有点像踩水-花费时间,并且就SRP而言,它变得更加“分离”,但是尽管我有良好的意愿,但我感觉自己并没有做出令人惊奇的改进。因此,讨论是否最好像以前那样保留代码而不进行重构。

我为什么要重构?

就我而言,我正在为新产品线添加新功能,因此我必须遵循类似产品线的现有代码结构,或者编写自己的代码。


OT,但要考虑的一点是Select * from ..可以认为是反模式。参见stackoverflow.com/q/3639861/31326
Peter M

1
@PeterM:除非您正在编写ORM,否则这种情况select *将成为“最佳实践”。
罗伯特·哈维

@RobertHarvey在这种情况下,我在质疑为什么编写自己的ORM:D
Peter M

我已经针对更多不相关的原因进行了重构。一旦收益超过成本,减少技术债务是一件好事。看起来这是您的情况。问题是:您是否有适合您的测试以确保代码仍然按预期运行?
Laiv

1
在重构IMO时,可靠性应该是主要指标,而不是与可变性相关的可维护性,因为可靠性首先减少了事物发生变化的原因。它提高了稳定性,并且完全稳定可靠的代码满足了所有需要执行的工作,因此维护成本很少,因为它几乎不需要更改。设法减少事物改变的原因,而不是试图使它们尽可能容易地改变。寻求前者也往往会给后者一些。

Answers:


13

在您提供的具体示例中,重构可能没有必要,至少现在还没有必要。但是您看到了将来有可能使用更混乱的代码,这将导致更长,更繁琐的重构,因此您主动采取了行动并清理了一切。

我还要说的是,您在这里获得的好处是,至少从我的角度来看,作为一个不了解您的代码库的人,代码更易于理解。


一般来说:

重构是否使其他开发人员更容易理解您的代码?

重构是否使增强代码更容易?

重构是否使维护代码更容易?

重构是否使调试更容易?

如果对这些问题的回答都是“是”,那是值得的,而不仅仅是“移动代码?

如果所有这些答案都是“否”,那么也许就不需要重构它了。

就LoC而言,代码库的最终大小可能会更大(尽管某些重构可以通过简化冗余代码来缩小代码库),但是如果有其他收获,那也不应该是一个因素。


9

如果要拆装整体,则重构确实会膨胀。

但是,您已经发现了好处。

“就我而言,我正在为新产品线添加新功能。”

您不能在不破坏事物的情况下非常轻松地向整体添加功能。

您说过,相同的代码正在获取数据并进行标记。太好了,直到您想要更改要选择和操作的列以在特定条件下显示。突然,您的标记代码在某些情况下停止工作,因此您必须进行重构。


是的,但是即使对于新功能,我也可以继续添加到整体中:)即,我将添加一个新if/else块并按照原始代码样式添加SQL语句,然后将新的HTML标记放入同一整体中文件中。要更改列,我会找到负责容纳SQL行的if / else块,并编辑该SQL以对列进行更改,而不会破坏该文件。
丹尼斯

使用重构方法,我很可能会先转到整体中的if / else块,以查看是否需要转到单独的存储库文件来更改SQL。或者,如果我最近在处理那个整体,那么我将直接进入存储库文件,而绕过该整体。或者,如果我搜索我的代码库中的特定SQL搜索会把我到新的库文件也绕过巨石
丹尼斯

2

如果我知道我必须在该项目上工作几个月甚至几年,我会考虑进行重构。如果我必须在这里和那里进行更改,那么我会抵制自己动摇代码的冲动。

重构的首选方式是当我拥有带有某种自动化测试的基本代码时。即使如此,我也必须非常小心自己所做的更改,以确保一切正常。如果您在本应工作的领域以外的其他地方提供错误,很快就会失去信任。

我重视重构的原因如下:

  • 我对代码了解得更好
  • 我删除重复的代码,因此,如果我在某个地方有错误,则不必在代码复制粘贴的每个地方都进行搜寻
  • 我创建具有明确定义的角色的类。例如,我可以重复使用同一存储库来合并HTML页面,XML feed或后台作业。如果数据库访问代码仅存在于HTML类中,则不可能实现
  • 如果变量,方法,类,模块,文件夹与当前情况不符,我将对其重命名;我comment的代码通过变量名,方法名
  • 我结合单元测试和重构来解决复杂的错误
  • 我可以灵活地替换整个模块,软件包。如果当前的ORM已过时,越野车或未维护,则如果未在整个项目中扩展,则更易于替换。
  • 我发现了可以为客户提供建议的新功能或改进。
  • 我创建了可重用的组件。这是最大的好处之一,因为在该项目中完成的工作本可以重新用于其他客户/项目。
  • 我通常从最笨拙,硬编码,古怪的解决方案开始,然后在我了解更多信息后便对其进行重构。这个稍后的时刻可能是今天或几天之后。我不想花太多时间来architect解决问题。这将在编写时出现-来回重写代码。

在理想的情况下,重构应该通过单元测试,集成测试等进行验证。如果没有,请尝试添加它们。另外,某些IDE可能会有所帮助。我通常使用一个需要付费的插件。我想花很少的时间进行重构,并且要非常高效。

我还介绍了错误。我知道为什么有些质量保证人员在问are you guys doing refactoring? because everything stopped working!这是团队必须承担的风险,我们始终必须对此保持透明。

这些年来,我发现持续重构提高了我的生产率。添加新功能要容易得多。同样,大型重建并不需要像代码库不适应产品发展那样经常进行的整体重写。也很有趣。


这几乎是一次否定表决-“计算机程序员”中没有“ I”。用“我”表示我是“我”(否定表决),或者表示现在和将来使用代码的开发人员?
mattnz

我也注意到了它,但我在措辞上加上了它。我也曾担任过多年的独立开发人员,当我写下这个答案时,我主要是从这种经验中重申。我可以取代Ito虽然。
Adrian Iftode '17

1

我认为您要问自己的问题不是“有好处吗?” 但是“谁来为这项工作付费?”

我们都可以争论直到几天结束为止的感知收益,但是除非您有一个客户相信这些收益并对其价值进行足够的评估以支付更改的费用,否则您不应该这样做。

当您在某个开发团队中某个地方来查看代码并希望对其进行重构以使其“更好”时,这太容易了。但是,在产品已经可用时,在“更好的代码”上赋予价值是非常困难的。

“加快新功能的开发”之类的事情并没有减少它,因为它们只是降低了成本。您需要产生销售。


1

我认为重构是一项不错的投资。

否则,您将很快遭受技术债务(未解​​决的问题,错误的代码(仅在特定条件下有效)等)。直到软件不再可维护之前,技术债务很快就会越来越大。

但是要使重构有效,您还必须投资测试。您应该创建自动化测试,理想情况下应该具有单元测试和集成测试。这使您免于破坏现有代码。

如果您必须说服上司或同事,则应该阅读一些有关敏捷方法(例如SCRUM)和测试驱动开发的书。

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.