程序员,请优先提高代码的可读性

作者:数据轩 链接:请点击“阅读原文”

导语:

现在,当有人提及“优化”一词时,他们通常是指“优化执行时间”,除非他们明确表明要优化GPU的内存消耗,网络流量等等。

一 了解优化对象

当我开始编程时,所拥有的处理器执行速度很慢,内存空间也非常有限 —— 有时仅以KB衡量。因此,必须合理考虑内存的使用和优化。

在大学里,我们知道了优化的两个极端情况:

  • 你可以牺牲空间来换取执行速度的提升,
  • 或者通过执行重复操作来换取内存消耗的优化。

如今,没有人会太在意内存的使用(除了demoseners,嵌入式系统工程师,部分手游开发者),不仅是对于RAM空间,硬盘空间也是。 试想一下仅安装看门狗就耗费硬盘近25Gb 空间。 此外,我在谷歌浏览器选项卡中写这篇文章时,占用了130Mb的RAM空间。

实际上需要优化的对象有很多:

  • 随着智能手机市场的增长,电量损耗的优化备受关注;
  • 优化可读性可以让代码易于阅读和调试,从而缩短开发周期,降低开发成本;
  • 还有很多优化类型,此处不再赘述……

优化可读性——让代码更容易阅读、跟踪和理解。

你应该明白,你在优化时难以兼顾各个方面。 例如,当致力于性能优化时,你很可能让应用程序内存消耗增加,同时代码可读性也变差。

二 为何优化可读性

开发者大量工作时间并不是在编写代码,而是阅读代码,调试代码,查阅他人提交的开发文档,学习新的库等。

当阅读代码时,开发者实际上是充当代码解释器的角色(虽比不上计算机)—— 在他们的头脑中执行代码,并试图记住当前执行状态。 这就是程序员在阅读代码过程中被打搅脾气暴躁的原因。

时间== 金钱

你应该意识到一件很最重要的事,是你和你的同事浪费了大量时间。 即使是一个努力工作的开发者,在做下面的事时仍然浪费了大量时间:

  • 实现一些现在不需要,以后也可能永远用不到的功能。
  • 做一些没有实际价值的改进。 例如,花费一周时间优化一个函数的执行时间,而该函数在1小时内仅被调用10ms的时间。
  • 编写的代码难以调试,却还要试图从中找出错误。
  • 编写的代码他人难以理解。 注意,“他人”也可能是短短一周后的你。

上述情况是假设遇到问题的开发者经验丰富并且熟知高效算法和简洁代码如何书写,否则要列出的情况要更多。

三 优化可读性

唐纳德·克努特说过一句名言。 我敢打赌你听过很多次。

“在编程中,过早优化是万恶之源。 ” —— D.Knuth,1974

我遇到很多知道这句话的人,但真正理解这句话的却很少。 最常见的错误理解像这样:

  • —为何这么简单的任务,代码却如此复杂?
  • —我优化了X和Y,因为在将来……
  • —难道你没听说过早的优化是万恶之源吗?
  • —当然,但这并不是过早优化,我能肯定这样做程序执行效率会更高。

我想这是由于对过早优化这个词没有明确界定的原因。 这就是这些人一点也不认为他们那么做属于过早优化的原因。 那么,我们该如何界定这个词呢?

过早优化——在工作系统中分析和运行测试前的任何优化尝试。

除可读性之外任何修改都属于过早优化。 所以,与其说一个人不应该做什么,不如说应该做什么。 那么,这句引言可以这样理解:

优先提高可读性。

四 什么阻碍了开发者阅读代码

好吧,我们一致认为,我们应该让代码更易于阅读,这样可以节约时间和金钱,对吧?但这究竟意味着什么?

有迹象表明,下面两个基本方面极大地降低了开发者阅读代码的速度:

  1. 代码晦涩难懂,
  2. 代码难以跟踪。

五 代码艰涩难懂

遗憾的是,人们并不能像软件解释器那样,可以不必理会将两个数相加并调用一个函数这部分代码的功能(机械式的编译)。

为了查找代码异常的原因,程序员必须理解源程序中编写的代码实现了何种功能,编写的初衷是为了实现何种功能。

六 什么让代码晦涩难懂?

下面情况是对于经验丰富的开发者而言,这些开发者熟悉代码开发使用的语言和程序中使用的算法(即他们有足够的知识来理解这段代码)。

  1. 代码不良。 单个字母的奇怪变量和1000行代码的冗长函数。
  2. 代码的格式不正确或不一致。
  3. 代码中包含冗余代码。
  4. 代码中包含未备注的低层次优化。
  5. 代码过于高明。

我将跳过前两条,因为无论如何你不应该阅读不良代码。 如果你所在的公司有人编写了不良代码,你应该纠正它们或者将其废弃。 当然,你必须为你的整个代码库执行严格的编程规范。

3. 代码中包含冗余代码

亦或所谓的行数优化。 嵌套函数调用和条件运算符的长行代码难以剖析。 当然,你可能会说这种观点是片面的。 但这些人觉得源程序代码越短越好,不必考虑可读性。

4. 未备注地层次优化

最初,代码的可读性很好,工作也很稳定,但有些人决定在某些方面对其进行优化。 经过认真剖析,这可能是一个很好的优化,但此时的代码看上去像是数组、位运算和幻数的结合体。 没有人知道代码在做什么,甚至代码应该做什么,因为完成优化的人没有提交任何说明。

也许你听说过优秀的代码不需要说明文档。 但是经过优化的代码(特别是优化效果很理想的情况)必须要有说明文档。

在你的代码库中,可能大部分的优化只是像这样的未备注行:

5. 代码过于高明

作为软件开发者,我们掌握越来越多的学术技巧并将其运用到实际代码开发中。 毕竟,我们是计算机科学家,而不只是码农!

有些语言甚至鼓励开发者使用前沿技术,使代码更具表现力和学术性。 当你用代码建立了一个非常健壮的系统,特别当你用数学方法证明了一个高深定理,而99.997%受过教育的人对这种方法都不理解,你就会有这种成就感。

即使代码被良好地封装成模块/类/函数并且这些模块包含完全可读的命令式代码,但其他人想要读懂这段代码,他们必须掌握整个代码的框架以及所有使用的相关技术和模式。

再一次强调,记住“其他人”可能就是一周后的你。

极可能这是我在工作中仅认识两个使用Scala语言人的原因。就我个人而言,非常喜欢Scala语言。 对我来说,它就是一个学术操场,我可以在那里建造玻璃城堡。 一旦你越了解它,它的越多特性也就能为你所用,你也就越明白它本质上只是一门编程语言(请不要在这里引用我!)。

虽不如Perl语言,但即使最漂亮的代码库也需要修改和更新。 现在,你需要寻找一个能够理解这些优美代码的人……

简洁高明的代码难以阅读似乎是有争议的。

“软件调试要比编写代码困难一倍,如果你发挥了最大才智编写代码,那么你的智商便不足以调试这个代码。 ” —— Brian Kernighan

七 代码难以跟踪

阅读代码时,通常需要频繁的从一个函数或类跳转到另一个函数或类。 掌握你使用的集成开发环境(IDE),可以节约很多阅读时间。 通过使用集成开发环境(例如Visual Studio)的“跳转至声明”,“查找使用”,“导航至”,“检查”等特性,你可以将整个代码看作是一幅连通图。

在Notepad中编写代码是不错的选择,但是如果你想有效的阅读代码,必须掌握一个集成开发环境。

那么,究竟什么是连通图呢?

连通图是在拓扑空间中连接的图,即图中任意两点之间都有一条通路。(来源)

换句话来说,在“连通”代码中,你可以方便的从一个方法中跟踪到另一个方法中,并在你头脑中建立这段代码的功能框架。

如果代码中某一部分链接被破坏(在这种情况下,集成开发环境不能帮助你实现函数间的跳转),通常你必须花一些时间自己查找链接。代码中被破坏的链部分越多,越难以跟踪,代码也就越难以阅读。

那么,为什么代码图会被断开?原因是多方面的,下面将列出一些常见情况:

  1. 使用字符串引用方法和属性

一些框架就喜欢这样做,他们将”回调”作为字符串传递并在需要时使用反射。 此时你需要使用CMD+F查找。

最可恶的是动态语言中的动态字符串…… 对这个问题,向JavaScript或AS3致敬!

2. 代码被分割成互不相连的部分

例如,你的代码一半使用C#编写,另一半是在可视化节点编辑器生成。 在这两者之间跳转非常不易。

依赖注入框架和其他XML配置工具也是。虽然没有明确说明,但编写XML配置文件也属于编程。 这就是所谓的的声明式编程(更不用说那些构建基于XML命令式语言的疯狂的人)。

3. 巨大的图节点

20个链接跳转到这个包含1000行代码的函数?。。哎哟。 你不需要包含这种节点的图。

4. 一切都过于抽象

通过跳转至声明,你可到达一个接口或者一个抽象类,必须弄清楚有哪些实现。 依赖注入,抽象工厂和其他所有反对依赖的方法使得这一切变得更糟。 代码图中节点间的联系过于抽象。

这样说来,我讨厌依赖注入(DI)和扩展标识语言(XML)。但DI是一个很棒的工具,它可以让你避免书写面条式代码并让程序的架构更加模块化,更具可测试性。但像其他好的事物一样,过度依赖必然产生负面效果。

我曾在审查一个应用程序时感到完全气馁,因为我意识到自己弄不明白程序从何处开始。。。例如它的入口点在哪。 这一切都是在程序开始时从XML配置工具自动生成。但我确实讨厌XML配置工具。

所以,到这里你应该已经学会:

  • 掌握你的集成开发环境,
  • 尽可能保持代码图连通,
  • 首先编写简单代码,
  • 编写不必要的代码,就是在浪费金钱。

强迫自己编写简单的代码,避免在早期阶段优化确实有一定难度,这需要花费时间。

-- 完 --

原文发布于微信公众号 - java思维导图(java-mindmap)

原文发表时间:2018-07-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开源优测

[接口测试 - 基础篇] 02 你应该掌握的Python3接口测试内功

概述 本文主要介绍基于Python3进行接口测试时,应该掌握Python3哪些基本的能力,主要从以下几个方面进行说明。 Python3基本语法 ...

3496
来自专栏AlgorithmDog的专栏

Akka 使用系列之二: 测试

通过上一篇文章,我们已经大致了解怎么使用 Akka,期待细致用法。这篇文章将介绍如何用 Akka-testkit 对 Akka 程序进行测试。 ? ...

2107
来自专栏程序员互动联盟

【编程基础】聊聊C语言-磨刀不误砍柴工

看到上篇讲的《程序和编程语言》引发了大家的热议,小编很是激动。不过被人评论说是不懂编程,小编还真是郁闷了一下下,在此声明小编可是货真价实的“程序猿”哦。言归正传...

4039
来自专栏Leetcode名企之路

【工程】在线诊断系统设计与实现

本文分享一些在线问题诊断的经验,主要是业务层面,服务层面的在线问题诊断一般需要依赖服务监控系统和报警系统来辅助定位问题。

1142
来自专栏编程派的专栏

提升 Python 编程效率的十点建议

程序员的时间很宝贵,Python这门语言虽然足够简单、优雅,但并不是说你使用Python编程,效率就一定会高。要想节省时间、提高效率,还是需要注意很多地方的。 ...

1.1K0
来自专栏木宛城主

浅谈 SOLID 原则的具体使用

SOLID 是面向对象设计5大重要原则的首字母缩写,当我们设计类和模块时,遵守 SOLID 原则可以让软件更加健壮和稳定。那么,什么是 SOLID 原则呢?本...

2229
来自专栏机器之心

放弃Python转向Go语言:我们找到了以下9大理由

选自Stream 作者:Thierry Schellenbach 机器之心编译 参与:黄小天、李亚洲 转用一门新语言通常是一项大决策,尤其是当你的团队成员中只有...

63811
来自专栏HappenLee的技术杂谈

C++雾中风景12:聊聊C++中的Mutex,以及拯救生产力的Boost

C++从11开始在标准库之中引入了线程库来进行多线程编程,在之前的版本需要依托操作系统本身提供的线程库来进行多线程的编程。(其实本身就是在标准库之上对底层的操作...

993

为什么我们从Python切换到Go?

切换到新的编程语言向来是关键一步,尤其是当你的团队只有一位成员有该语言的使用经验时。今年年初,我们将 Stream 的主要编程语言从Python 切换到 Go。...

3352
来自专栏听雨堂

工作流参考模型点评

工作流参考模型点评 工作流参考模型是由WFMC提出来的,对工作流管理系统的实现推荐的一个参考模型。 下面分别对各个组件进行解释: 1) Work...

2146

扫码关注云+社区

领取腾讯云代金券