为什么不重构呢?

重构是提高质量的重要工具。许多开发方法都依赖于重构,尤其是对于敏捷方法,在更多计划驱动的组织中也是如此。但事实上,是否以重构来处理设计中的某些问题呢?是否存在重构的障碍呢?

5a69d14c64cf20e24085f5903775d62a.png

不重构的原因

存在质量问题而不进行重构的理由可以分为以下几类:

资源

对所需资源的关注是不进行重构的一个经常被提到的原因。最常提到的资源是时间,比如“DDL不允许”,“有时候就是没有时间”或者单纯的“就是没有时间”。

风险

同样经常被提到的还有更改所涉及的风险,尤其是引入新的错误或其他问题,比如“这种重构很耗时间,而且引入错误的风险很大”,以及“反正还能用,管它干嘛”等等。

难度

另一个问题是进行更改的难度,比如“继承很难正确重构”和“这种重构通常很困难”等等。

投资回报率

虽然重构可能会带来好处,但也有成本,投资回报率也必须考虑,例如“必须再次权衡成本和好处,在承担重构、重测试等方面的成本之前,必须明确收益。”

技术

项目的特点限制了重构的能力。例如,必须实现超出限制的第三方接口,担心任何潜在的更改对系统其他部分的影响,对代码的熟悉程度,处理遗留代码,以及缺乏其他支持(如测试套件) ,尤其是“大量遗留代码库使重构变得困难”; “如果没有测试方法,系统可能被破坏”; 以及“没有时间进行重构的预算。”等等

管理

开发者并不总是能控制他们的时间使用。老板或客户更有发言权,比如“想要重构,但老板不喜欢”、“只关注截止日期的老板”、“客户不会为此付钱”等等。

工具

工具支持不足也被认为是不重构的一个原因,然而,这些的工具并不是那些进行重构的那些工具,某些重构非常痛苦,实际上是缺乏工具的支持。微软对 Windows 进行了某种形式的重构,确定了执行重构的挑战,例如管理组件间和分支间的依赖关系以及维护向下兼容,也许最令人惊讶的主题是完全不关心重构工具支持的存在和质量。

2440f26acaec4812a1cb6d5372eff17c.png

重构的障碍与时机

重构并非难在怎么做,而是难在何时开始做。对于一个高速发展的企业来说,停下来做重构从来就不是一个可接受的选项,“边开飞机边换引擎”才是公司想要的。当代码还不是很混乱的时候,重构的必要性不高,相比不小心重构出错导致熄火的风险来说,得过且过可能反而是一个明智之选。于是,各种技术债就这样慢慢积累起来,直到业务因为各种技术债快跑不动的时候,才不得不用一些激进的重构手段快速的解决历史顽疾。

代码分析未必有效

在软件工程中,往往使用每类加权方法(WMC)和继承树(Depth of Inheritance Tree,DIT) 来度量面向对象的设计,这些度量常常被表示为可能的设计问题,即WMC 或 DIT 的值越高,就越有可能出现问题。WMC 是类的大小度量的一种形式,最简单的形式是类中方法数量的计数。DIT 捕获继承层次结构的一个特征,它是从类到层次结构根的最长路径长度。然而,对软件系统的测量表明,有些类具有很多方法,或者在层次结构中非常深。它就需要重构么?

实际上,工程师更倾向于限制类的深度,而不是方法的数量,但是当超过某个深度限制时,开发者倾向于不做任何事情。

两个主要障碍

很多时候,无法确定 ROI 才是一个障碍,比如“如果不能对需要多长时间做出合理的估计,就不会管它。”也就是说,决定不重构并不是因为它被认为是一个坏主意,而是因为它的收益不确定。在特定情况下进行重构时,通常很少或根本不知道实际的 ROI 是什么。

一个潜在的障碍是很难将重构目标转化为重构操作。需要的是一个决策支持系统,使从业人员能够量化长期和短期效益。这将有助于为决定所需资源是否合理或是否容忍潜在风险提供信息,还允许开发人员和管理人员就是否重构做出明智的选择。

重构的时机

具体地,Martin Folwer在《重构》一书中提到,需要识别坏味道,并提出了进行重构的4种情况,即关于重构的CRUD:

  • 增:增加新功能的时候,发现需要重构来便于新功能的添加

  • 删:事不过三,消除重复

  • 改:修复缺陷,改Bug的时候

  • 查:代码评审的时候得到了很多建设性的意见

也就是说,设计没有表达出对需求的最新理解,或者需求没有被很好地实现,而且已经发现更好的实现方法,以及发现了一个能使某个设计变得简单、灵活的方法。实际上,重构的时机只是做出是否重构的判断时机。

另外,使用重构工具的两个好处是错误率更低,所需时间更少,因此好的工具支持应该在一定程度上解决开发人员的问题。只有当重构的决定已经做出时,重构工具的支持才会起作用。实际上,不使用自动化进行重构的原因可能包括信任、可预测性和复杂性。

4f2059c2552c635e9849443b9146baf9.png

小结

无论软件设计质量问题是如何识别的,开发者都无法通过重构来根本消除这些问题。减少甚至消除重构的障碍有可能显著提高软件质量。一种方法是提供目标导向的重构支持,而不是操作导向的重构支持。另一个办法是更好地量化效益,从而更好地告知是否重构的决定。

【关联阅读】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你想要重构 putchar 函数,可以考虑以下几个方面: 1. 参数类型:putchar 函数接受一个 char 类型的参数,表示要输出的字符。如果你想要重构该函数,可以考虑使用更通用的数据类型,如 int 或 unsigned int。这样可以在满足输出字符的同时,提高函数的通用性。 2. 函数名:putchar 函数的函数名比较特殊,如果你想要让函数名更符合一般的函数命名规范,可以考虑将其改为更具有代表性的名称,如 print_char 或 output_char 等。 3. 输出流:putchar 函数默认将字符输出到标准输出流中,如果你想要重构该函数,可以考虑让函数支持输出到其他的流中,如文件流或网络流等。 4. 错误处理:putchar 函数没有进行错误处理,如果你想要重构该函数,可以考虑增加错误处理的功能,如检查输出流是否有效等。 下面是一个简单的代码示例,用于重构 putchar 函数: ```c #include <stdio.h> int my_putchar(int c, FILE *stream) { if (stream == NULL) { return EOF; // 输出流不可用,返回错误值 } return fputc(c, stream); // 将字符输出到指定的流中 } int main(void) { char c = 'a'; my_putchar(c, stdout); // 输出字符到标准输出流中 return 0; } ``` 在上面的代码中,我们定义了一个新的函数 my_putchar,它接受两个参数:一个整型参数 c,表示要输出的字符,以及一个文件流指针参数 stream,表示要输出到哪个流中。我们在函数内部先进行了错误处理,检查输出流指针是否为空。如果输出流不可用,函数返回 EOF,表示输出失败。如果输出流可用,我们使用 fputc 函数将字符输出到指定的流中。在主函数中,我们调用 my_putchar 函数输出字符到标准输出流中。 需要注意的是,上面的代码仅为示例,实际的重构过程可能更加复杂,需要根据具体的需求和场景进行设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值