如何说服管理层重新格式化整个Java代码库是安全的

18
如何向管理层证明对大型代码库中的所有.java文件进行批量重新格式化(以符合公司的编码标准)是安全的,并且不会影响功能。答案必须取悦非技术人员和技术人员。注意:重新格式化仅限于空格更改-不包括“整理导入”或“重新排列成员变量,方法等”。

21
为什么要费这个劲呢?这是浪费钱。只需要制定一个政策,即如果你要进入文件进行更改,则重新格式化该文件以符合当前标准。如果没有人需要进入文件修复错误或进行更改,那么代码看起来怎么样并不重要。如果你有时间做这件事,显然是因为你没有足够的实际工作要做。 - CaffGeek
3
你知道你不必手动做那件事吗? - Pascal Thivent
9
最大的问题在于重新格式化会破坏差异比较,所以这里有点困难。 - Pascal Thivent
2
@lavinio,如果没有人需要更改文件,谁会在意它是否可读?根据需要进行更改即可。如果我需要阅读/编辑文件,我会花几分钟清理它。如果不需要,为什么要浪费时间呢? - CaffGeek
2
@Chad:一般来说,我认为同时更改格式和功能是一个不好的想法。这会使版本控制更加混乱。 - Brian
显示剩余8条评论
24个回答

38
如果只是重新格式化,那么不应该改变编译器的输出。在重新格式化之前和之后对构建进行哈希(MD5 应该足够好),如果每个文件的哈希值相同,那么显然它不能改变行为。无需运行测试等 - 如果输出一字不差地相同,很难看到测试会如何开始失败。(当然,运行测试可能有所帮助,但它们不会证明与相同的二进制文件相比任何事情。)
编辑:正如评论中指出的那样,二进制文件包含行号。确保使用 -g:none 进行编译以省略调试信息。这应该可以处理行号更改 - 但是如果您正在更改名称,则这是更严重的更改,并且确实可能是破坏性更改。
我假设您可以重新格式化和重建而无需任何人关心 - 只有将重新格式化的代码检查回源代码控制才会引起任何关注。然而,如果您的“格式化”更改了字段等的顺序,则可能会产生重大影响。

2
相反,JVM严重依赖符号引用。因此,你代码中使用的任何类、接口、方法或字段都将其名称(字符串)插入到Class文件中。另外,如果你使用调试模式编译,则任何变量名称甚至源行号的更改都会导致不同的Class文件。 - H-H
@HH:当然,你关于行信息的说法是正确的。但格式化不应该改变名称。 - Jon Skeet
实际上,一个更复杂的比较将仅涉及Class文件中的代码部分(所有索引都用引用名称替换)。这听起来像是一个不错的项目 :) - H-H
@Jon,虽然您没有涉及商业论点,但我发现您的技术回答最有帮助,因此选择了您的答案。MD5更容易解释(同一哈希=相同文件)比Java编译器的工作方式(并提供了一个低级的可重复测试)。 - jtsampson
@HH:一个“更复杂的比较”更有可能存在错误。 - Brian

36
在商业环境中,您面临两个挑战。
1.技术
2.政治
从技术角度来看,重新格式化程序是一项成熟的技术。结合哈希/校验和,只要语言不敏感于空格,您在技术上就可以安全地这样做。您还需要确保在没有主要分支等待合并的停机时间内进行此操作。真正的更改将无法与重新格式化分开,因此请分别执行它们。对于任何正在处理分支的人来说,合并可能非常困难。最后,我只会在实施完整的测试用例覆盖之后才执行它。由于原因2...
从政治上讲,如果您不知道如何说服管理层,那么您怎么知道这是安全的?更具体地说,对于在大型政治红色组织中工作的开发人员,您需要确保涵盖所有基础知识。
我在2010年提出的论点可能有些聪明,但解析器、重新格式化程序、漂亮的打印机只是软件;它们可能会被您的代码库触发错误,尤其是在C++中。在没有单元测试的情况下,对于大型代码库,您可能无法验证最终结果是相同的。
作为开发人员,我很偏执,这个想法让我感到不安,但只要您使用:
1.源代码控制
2.适当的测试覆盖率
那么你就没问题了。
然而,请考虑一下:管理层现在已经意识到您正在进行一个“大规模更改”的百万行项目。在您重新格式化后,一个以前未发现的错误被报告。您现在是导致此错误的主要嫌疑人。安全是否“安全”有多种含义。对于您和您的工作来说可能不安全。
这听起来很陈腐,但几年前我记得发生了类似的事情。在一个夜间维护窗口之后,我只对一个IIS服务器进行了重新配置和重启,第二天收到了一个错误报告。几天来,大家都认为是我搞砸了或者部署了新代码。没有人直接这么说过,但我从一位副总裁那里看到了这样的眼神。最终我们追踪到一个已经存在于代码中、之前已经推送过但直到一个QA人员最近更改了一个测试用例才出现的错误,但老实说,有些人甚至不记得这一点;他们只记得第二天遇到了一个新的错误。

编辑:回应jtsampson的编辑。你的问题不是如何做到,而是“如何说服管理层它是安全的”。也许你应该问,“它是安全的吗?如果是,如何安全地实现它。”我的陈述指出了你的问题的讽刺之处,即你假设它是安全的,却不知道如何做到。我欣赏重新格式化的技术方面,但我要指出的是,在任何非微不足道的事情中都存在风险,除非你把正确的人放在那个位置,否则它可能会被搞砸。这项任务会减少程序员的其他任务吗,使他们分心几天?它会与其他编码器未提交的修订冲突吗?源代码是否正在进行修订?是否有任何嵌入式脚本是空格敏感的,例如Python?任何东西都可能产生意想不到的副作用;对于我们的环境来说,很难得到一个没有人在分支上工作的时间窗口,大规模的重新格式化会使他们的合并变得非常丑陋。因此,我不喜欢大规模手动或自动重新格式化。


1
+1:如果你有足够的测试来确信它是安全的,那么你可能也能说服其他人。 - S.Lott
2
好的,我的回答有点泛泛。由于OP说他只有.java文件,那么每个.class文件的MD5 / SHA校验和对我们来说就足够了。然后我们的工作就是向管理层解释哈希如何工作。 - codenheim
2
除了空格以外,添加任何其他内容都会影响MD5 / SHA总和。 - Chris K
4
在 .java 文件中添加空格不应该影响 .class 文件的校验和。 - codenheim
1
mrjoltcola,感谢您的回复。然而,您最初的答案并没有回答我的问题 - 它更像是一个陈述。但是根据评论,似乎您同意Jon Skeet在下面的技术方法建议(不确定谁首先发布了md5想法)。 - jtsampson
显示剩余5条评论

13

采取务实的方法:

  1. 构建应用程序。
  2. 保存应用程序。
  3. 重新格式化代码。
  4. 构建应用程序。
  5. 比较二进制文件的差异。

有些代码直到运行时才生成二进制文件(JSP、ASP和其他所有活动页面技术)。如果您的应用程序没有使用这些技术,那么我认为这是一个好主意。 - codenheim
4
楼主说的是 ".java" 文件,它们已经全部编译过了。 - lavinio
Lavino,感谢您的回复,这似乎与Jon Skeet上面和下面的几个答案类似。我认为这是一个不错的方法,至少从技术上来说。 - jtsampson

8

我会用四个词。

源代码控制。 单元测试。


如果在之前和之后通过了相同的测试,那对我来说听起来是安全的。 - S.Lott
PaddySLacker,作为一名开发人员,我同意。但作为一个QA业务人员,很难相信单元测试覆盖了所有情况。然而,既然我们已经拥有这样的测试套件,那也将是技术(经验)方法的一部分,用于证明。 - jtsampson
作为一名开发者,我不相信单元测试可以覆盖所有情况。但是,我完全相信相反的命题。单元测试永远无法覆盖每一个可能性。 - David Thornley
@David Thornley 我同意对于非平凡的代码来说,单元测试(或任何测试)永远无法覆盖所有情况,即使代码覆盖率达到100%。但是,如果您有足够的单元测试,您可以相当确信,在清理代码之前和之后,代码的行为没有发生改变。除非计划在将来以任何方式都不修改此代码库,否则这种更改真的不是什么大问题,并且比将来添加新功能的风险要小得多。 - Paddyslacker
如果您进行合理的更改,而单元测试仍然通过,则可以相当有信心地认为您没有破坏任何东西。但是,对于大型自动更改的确认,我对使用它们感到不太满意。 - David Thornley

5

嗯,这样做并不安全,而且你不太可能说服他们。作为一个管理了很多开发项目的人,我永远不会在任何商业代码库中考虑采用它,因为任何收入都依赖于此。我并不是说按照你喜欢的方式编写代码没有优点,但你的格式化很可能涉及到代码更改的部分,几乎不可能完全匹配。这意味着即使风险很大,获得的好处却微不足道。如果你必须这样做,请一边修复代码缺陷,一边逐步进行,不要一次性全部修改。对于你们程序员来说这可能是一个好决定,但对于管理层来说这将是一个可怕的决定。


我不同意。有了自动化单元测试和源代码控制可以回滚,这应该是一件轻而易举的事情。 - Paddyslacker
假设您的代码覆盖率达到100%,并且重新格式化不会在功能上更改任何代码 - 这种情况永远不会发生。我从未遇到过这样做的开发人员,他们可以抵制诸如从函数中单个退出点之类的事情,或者无论当前格式的宠物怨恨是什么。这根本不是一个简单的问题,在任何商业代码库中都是自杀行为 - 客户有什么好处?风险根本不值得。在修复错误时逐步进行。 - Simon
我也不同意,但理由不同。直觉上,如果仅仅改变Java源文件的格式就会对应用程序的功能产生负面影响(让我们坚持只进行空格更改而不重新排序静态成员变量),那么作为一种语言,Java早就失败了。 - jtsampson
@jtsampson:我不太确定Java,但我可以找到一个情况,即删除空格将更改C++程序。这是一种病态情况,但没有人谈论过对格式良好的代码进行大规模重新格式化。我认为C++并没有在很久以前失败。 - David Thornley
@jtsampson 你假设重新格式化只是移动空格。我的整个观点是,将要进行重新格式化的人永远无法抵制改变超出空格之外的代码的诱惑。考虑在if/elseif/else块中使用大括号,我敢打赌这种更改会受到影响。如果进行重新格式化的人不了解当前实现的所有细节(因为他们几乎肯定没有编写过代码),那么在重新格式化时产生逻辑错误的可能性就非常大。这样做根本不值得。 - Simon
显示剩余2条评论

4
我们谈到的管理是哪一方面的?他们是否精通技术,了解代码格式以及Java如何处理空格?因为如果他们不懂,我认为他们没有资格做出这样的技术决定(即此类问题应委托给负责代码的人)。但是如果他们或您试图说服您的“架构师”或类似人员,那么这就是关于信任第三方工具的问题。建议使用声誉良好的格式化程序,除此之外,您无法做太多事情,因为您并未编写该格式化程序。
顺便说一句,让我分享一个轶事。我们的架构师在某个时候决定重新格式化所有文件。在数千个Java文件中,尚未发现任何错误(这是半年前的事情)。这使我相信Eclipse Java源代码的格式化程序。这种格式化的好处包括:
- 一些格式不良的类现在更容易阅读。 - 到处都是相同的格式化。
但它也有一些负面影响:
- 代码格式化程序并不完美。有时手动格式化的代码更易读。特别是对于真正糟糕的代码(行太长,嵌套if太多等),格式化程序很难处理。 - 您是否有其他代码分支,例如需要偶尔修补的旧版本?因为您可以忘记合并具有不同代码风格的分支(至少在使用SVN时是这样)。 - 您正在触及所有文件(有时几乎每一行),并同时破坏了所有文件的历史记录。这会影响可追溯性。 - 实际上,每个开发人员都有自己的代码格式,这是一个小小的好处,因为您开始学习该格式,您可以立即识别代码段的作者。
我个人认为负面影响超过了正面影响。它听起来像一个好主意,但实际上您获得的收益并不像您想象的那么多。当您遇到一些格式极差的代码时,只需重新格式化该类或该方法,将其视为迈向大目标的一小步。

通过“管理”,我指的是除了我之外的所有人——包括技术娴熟和非技术娴熟的人。感谢您的轶事,这稳定地证实了我认为的情况。您提到源代码控制的观点已经被注意并理解了。故意将其从这个问题中省略以缩小我的可能回答范围。我们即将举行一个活动,需要将我们的SVN树移动到一个新位置,并且不允许从旧分支进行合并(这将最小化此问题),这就是我提出这个问题的原因。 - jtsampson

2

在重新格式化后,您的单元测试是否通过?如果是,那么您已经向管理层推销了这个想法!

如果您正在处理未经测试的代码,则需要做出更艰难的论据。


2
你想让代码符合公司编码标准,并希望说服管理层吗?
简单:安装CheckStyle,将其纳入你的流程中,遵循你的编码指南,并向他们展示整个代码库在CheckStyle上惨败。

WizardOfOdds,感谢您的评论。我已经将其连接并针对公司的编码标准进行了键入,包括一个用于测试代码中被视为不重要的情况的抑制文件。这是个人项目的一部分,旨在发布此问题之前。在重新格式化之前,我们有800,000个违规行为,格式化后有100,000个违规行为 - 这绝对是技术方面的论据。 - jtsampson

2

这是技术与业务不匹配的典型例子。

技术人员想这么做是因为它可以使代码难以阅读,但除非情况极其糟糕,否则真正的原因是它冒犯了普通程序员通常敏感和审美的特点。

业务人员希望管理风险。如果有一些好处并且没有商业利益,那么风险可以承担,除非你认为未来使用重新格式化的源代码进行开发更便宜、更快或者更安全,但老实说这很难说服人。

几乎任何变化都会带来风险。这里的风险是较小的,但从管理层的角度来看也不是完全不存在的,并且几乎没有好处。

还有另一个问题需要考虑:这种改变可能会对源代码控制造成混乱。由于最近的更改是重新格式化,所以跟踪谁更改了什么变得更加困难,您需要比较修订版本,这比简单的“责备”或“注释”命令更加繁琐。

此外,如果您有多个活动分支,代码的重新格式化将对您的合并造成混乱。


当我第一次看到这个问题时,我没有考虑到你所谈论的问题。 - Ravi Wallau
感谢您的评论,您提出了一些非技术方面的好观点,这些观点在大多数发布的答案中被忽略了。 - jtsampson
@jtsampson - 顺便问一下,你的公司是销售软件还是为销售其他产品的公司生产软件?这将影响Cletus在第二段提到的平衡。 - Nicholas White

1

如果您使用Eclipse作为开发平台,可以将所有代码加载到本地工作空间中。通过向管理层展示“Problems”选项卡,证明没有问题。

然后,逐个右键单击并格式化每个项目-再次证明不会引入任何问题。

您可以在本地工作站上进行此操作,而不会对存储库造成任何损害。

老实说,如果您的管理层如此缺乏技术能力以至于会害怕格式化源代码,那么在格式化后未出现问题证明代码仍然良好应该足以说明问题。

更不用说,您可能会在源代码控件中标记旧版本,对吧?


“问题”选项卡仅显示无法编译的代码-它不会显示可能引入的任何微妙行为更改。 - Nicholas White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接