gitbook/代码精进之路/docs/76666.md
2022-09-03 22:05:03 +08:00

13 KiB
Raw Permalink Blame History

Q&A加餐丨关于代码质量你关心的那些事儿

专栏上线后有一些同学对于代码质量有关的问题还不是很清楚有很多疑问所以我特意做了一期Q&A来回答一下这些问题。

1. 有没有什么技巧可以不费力地查看源代码?

这是一个好问题。但遗憾的是,我们费力的程度,主要取决于代码的作者,而不是我们自己。我想了好久,也没有找到不费力气查看源代码的技巧。

通常我自己用的办法,有时候就像剥洋葱,从外朝里看;有时候也像挖井,找到地表的一小块地儿,朝下一直挖,直到我理解了代码的逻辑关系。

如果你刚开始接触我建议你先不要看代码先去看README再去看用户指南。先把软件干什么、怎么用搞清楚。然后再去看开发者指南搞清楚模块之间的关系、功能理解代码中的示例。最后再去看代码。

看代码的时候找一个顺手的IDE。IDE丰富的检索功能可以帮助我们找到一个方法在什么地方定义的有哪些地方使用了。

如果你还不知道要看哪一个源代码,先找一个例子开始。不管这个例子是开发指南里的,还是测试代码里的。先找出一个例子,把它读懂,然后阅读例子中调用的源代码。

比如你要是看到示例代码调用了Collections.unmodifiableList()方法,如果想了解它,就查看它的规范文档或者源代码。从例子开始剥每一个你关心的方法,一层一层地深入下去。

OpenJDK的代码评审很多时候代码量很大。代码评审的时候很多文档还没有出来。我一般是分层看的。先看用户接口设计的这部分代码这一部分的代码量一般比较少。看完用户接口的设计才能明白作者的思路和目标。这样自己就有了一个思路对代码的方向有了一个大致的了解。然后再看接口实现的代码看看实现和接口是不是吻合的。这个过程中我一般会记录下类和方法之间的依赖关系也会顺着依赖关系来理解代码的逻辑关系。

好的代码,有清晰的分割和层次,逻辑清晰,代码的行文一般也是简单直观,读起来比较容易。不好的代码,阅读起来就费力得多了。

2. 代码质量和工作效率的矛盾如何取舍?

这个问题有一个隐含的假设,就是代码质量和工作效率不可兼得。这本身是个常见的误区。这个误区也给了我们一个看似成立的借口:要么牺牲代码质量,要么牺牲工作效率。

代码质量和工作效率,是不是矛盾的呢?这取决于我们观察的时间、地点以及维度,甚至我们是怎么定义效率的。

如果给我们一个小时的时间,看看谁写的代码多。不顾及代码质量的也许会胜出(只是也许,我们后面再说为什么只是也许);认真设计、认真对待每一行代码的也许会败北(也只是也许)。

短期内代码写得多与否,我们可以把这个比喻成“走得慢,还是走得快”的问题。

如果给我们半年的时间,那些质量差的代码,编写效率也许可以和质量好的代码保持在同一水准,特别是软件还没有见到用户的时候。

如果给我们一年的时间,软件已经见到了用户,那么质量差的代码的编写效率,应该大幅度落后于优质代码了。甚至生产这些代码的团队,都被市场无情淘汰了。

看谁的代码能够长期赢得竞争,我们可以把这个比喻成“到得慢,还是到得快”问题。

为什么会这样呢? 一小时内,什么都不管,什么都不顾,怎么能不多产呢!

可是,不管不顾,并不意味真的可以高枕无忧。需求满足不了就会返工,程序出了问题也会返工,测试通不过还会返工······每一次的返工,都要你重新阅读代码,梳理逻辑,修改代码。

有很多时候,你会发现,这代码真是垃圾,没法改了,只有推倒重来。

这个时候再回过头看看这种代码编写的背景,你能说这是一种高效率的行为吗?

这就相当于一个马拉松比赛前1000米你在前头后来你就要往回跑。1000米这个槛有人跑一次就够了你要是跑七八次还谈什么效率呢。这种绝望的事情看似荒唐其实每天都会发生。

为什么会这样呢? 因为在软件开发的过程中,遗留的问题需要弥补,这就类似于往回跑。所以,走得快,不一定到得快。

你不妨记录一下三个月以来,你的工作时间,看看有多少时间是花在了修修补补上,有多少时间是花在了新的用户需求上。这样,对这个问题可能有不一样的感受。

另外,是不是关注代码质量,就一定走得慢呢?

其实也不是这样的。比如说,如果一个定义清晰,承载功能单一的接口,我们就容易理解,编码思路也清晰,写代码就又快又好。可是,简单直观的接口怎么来?我们需要花费大量的时间,去设计接口,才能获得这样的效果。

为什么有的人一天可以写几千行代码,有的人一天就只能写几十行代码呢?这背后最重要的一个区别就是心里有没有谱,思路是不是清晰。几千行的代码质量就比几十行的差吗? 也不一定。

你有没有遇到这样的例子,一个同学软件已经实现一半了,写了十万行代码。另一个熊孩子还在吭哧吭哧地设计接口,各种画图。当这个同学写了十五万行代码的时候,完成一大半工作的时候,那个熊孩子已经五万行代码搞定了所有的事情。你想想,效率到底该怎么定义呢?

那个熊孩子是不是没有能力写二十万行代码呢?不是的,只要他愿意,他也许可以写得更快。只是,既然目标实现了,为什么不去聊聊天,喝喝咖啡呢?搞这么多代码干啥!你想想,效率能用代码数量定义吗?

就单个的程序员而言,代码质量其实是一个意识和技能的问题。当我们有了相关的意识和技能以后,编写高质量的代码甚至还会节省时间。如果我们没有代码质量的意识,就很难积累相关的技能,编写代码就是一件苦差事,修修补补累死人。

有很多公司不愿意做代码评审,效率也是其中一个重要的考量。大家太注重一小时内的效率,而不太关切一年内的效率。如果我们将目光放得更长远,就会发现很多不一样的东西。

比如说代码评审,就可以减少错误,减少往回跑的频率,从而节省时间。代码评审也可以帮助年轻的程序员快速地成长,降低团队出错的机率,提高团队的效率。

有一些公司,定了编写规范,定了安全规范,定了很多规范,就是执行不下去,为什么呢? 没有人愿意记住那么多生硬的规范,这个时候,代码评审就是一个很好的方法,有很多眼睛看着代码,有反馈,有讨论,有争议,有建议,团队能够更快地形成共识,找出问题,形成习惯,共同进步。看似慢,其实快。

英文里,有一句经典的话 “Run slowly, and you will get there faster”。汉语的说法更简洁因为慢,所以快”。

一般情况下,通常意义上的软件开发,如果我们从产品的角度看,我认为高质量的代码,会提升工作的效率,而不是降低工作效率。

当然,也有特殊情况。比如我们对质量有着偏执般的追求,这时候,效率就不是我们的首选项。也有情况需要我们在五秒以内眨眼之间就给出代码,这时候,质量也不是我们的首选项。

代码的质量该怎么取舍呢?这取决于具体的环境,和你的真实目标。

3. 你加入了Java SE团队经历了从JDK 1.5.0到JDK 12的整个迭代过程这个阶段中Java开发的流程都经历了哪些迭代

在十多年间Java开发的流程有很多大大小小的调整。影响最大的我觉得主要有三个。

第一个变化是更加开放了。Java开源以后不仅仅是把代码开放出来开发流程也开放了出来。OpenJDK有详细的开发人员手册告诉大家怎么参与到OpenJDK社区中来。

OpenJDK开放了Java改进的流程这就是JEPJDK Enhancement-Proposal & Roadmap Process。每一个Java的改进从雏形开始一直到改进完成都要经过OpenJDK社区的讨论、评审。什么都要经过OpenJDK讨论这效率不是变慢了吗其实这种开放反而加快了Java的演进。

创新性的想法第一时间就送到用户面前,接受用户的审视。

一个项目是好还是坏做还是不做该怎么做这都在用户可以“挑剔”的范围内。Java的演进也从少数的专家委员会模式变更为小步快走的大集市模式。

OpenJDK也开放了Java代码评审的流程。现在几乎所有的变更都是通过OpenJDK进行的。为什么要变更变更的是什么变更带来的影响有哪些都要描述得清清楚楚。而且任何人都可参与评审都可以发表意见。如果有兼容性的影响用户会在第一时间发现而不是等到系统出了问题再来修补。透明化带来的好处就是有更多的眼睛盯着Java的变更代码的质量会更好潜在的问题也会更少。

第二个变化是研发节奏更快了。Java的版本演进从传统的好几年一个版本变更为半年一个版本。两三年一个版本的演进模式使得Java的任何改进都要两三年以后见。即使这些改进已经成熟了也得在代码库里躺着到不了用户的场景里。没有用户反馈产品的质量也就没有经过真实的检验了没有改进的真实建议。这其实是一种浪费效率会变低。

第三个变化是自动化程度提高了。现在OpenJDK提交的每一个变更都会自动运行很多的测试。如果这个变更引起了测试错误测试系统会给参与者发邮件指明出错的测试以及潜在的怀疑对象。变更提交前我们也可以发出指令运行这些测试。这些自动化的测试可以提高代码的质量减轻工程师的压力提高工作的效率。

4. 您是JDK 11 TLS 1.3项目的leader在这个项目中你对代码安全又是怎么理解的呢

代码的安全,我一直以为是一个见识问题。一个安全问题,你见识到了,认识到了,你就会在代码里解决掉。没有认识到安全问题,可能想破脑袋,也不知道问题出在哪。

比如说TLS 1.3废弃掉了密码学的很多经典算法包括RSA密钥交换、链式加密算法等。如果去你去查看经典的密码学教材你会发现这些算法都被看做牢不可破的算法全世界的每一粒沙子都变成CPU也破解不了它们。

可是站在2019年再来看这些算法各有各的问题有的破解也就是几分钟的事情。那我们还应该使用这些算法吗当然要想办法升级。可现实是你根本不知道这些算法已经有问题了。当然也想不到去升级使用这些算法的应用程序。这就是我们说的见识。知道了你才能想到去解决。

见识是一个坏东西,需要我们看得多、见得多,才能够拥有。甚至,需要付出代价,比如遭受到黑客攻击。

见识也是一个好东西,见得越多,看得越多,你构筑起来的竞争优势就越明显。随着阅历的增长,见识也会增强,竞争力就提高了。

如果一个东西,每个人三秒就可以掌握,那当然是好的。但同时,它就算不上你的优势了。即使有优势,也只是三秒钟的差距。

另一个常见的问题,就是认为安全的代码牺牲效率。

编写安全的代码,会不会牺牲工作的效率呢?一般情况下,这对效率的影响几乎可以忽略不计。 比如说,一个公开接口,我们不应该信任用户输入的数据,应该检查用户输入数据的边界和有效性。做这样的检查,增加不了多少代码量,反而会让我们的思路变得清晰。再编写具体的业务逻辑的时候,编码的效率就变高了,甚至还会减少代码量。

就拿TLS 1.3来说当废弃掉一些经典的算法时一幅全新的画面就出现在我们面前。TLS协议的设计更加简单更有效效率也会翻倍地提升。

代码质量、工作效率、软件性能、代码安全,这些东西可以作为基准,但是不适用拿来对比。如果非要单纯地从概念上对比,看看有没有冲突,没有一点儿现实意义。安全的代码会牺牲软件性能吗? 不一定。重视代码质量,就会牺牲工作效率吗?也不一定。

今天挑了几个同学的问题来回答。其实关注代码质量这种事情,就像爬山一样,每个人都会,但不是所有人都能爬到最后。会当凌绝顶,一览众山小。当自己在山峰上爬得越来越高的时候,再回过头,你会发现自己和身边的人已经不一样了。

如果你觉得这篇文章对你有所启发,欢迎你点击“请朋友读”,把它分享给你的朋友或者同事。