为什么你写的代码如此难以理解?

前言:

初学代码,就已经遇到代码难以理解的问题,比如:定义的变量过多,自己也分不清哪个是哪个;不爱写注释,没办法看出一段代码在执行什么任务;命名超随意、不通俗,估计那堆东西只有自己能看懂……哦不,可能过一段时间,自己也看不懂了……因此转载此篇,自我敲打……


文章转自:微信公众号 程序人生

以下是正文

******************************************************************************************************************


“我到底在想些什么?!?”


凌晨1:30分,我正盯着我不到一个月前写的一段代码。当时一看简直是件艺术品!不但完全说得通,而且优雅、简单、令人叹为观止。而此时再看到这段代码的时候,却和当初的情况完全不同。明天就到截止日期了,而我在刚才还发现了一个bug。现在再一看,当时所认为的简单和逻辑也都说不通了。可以肯定的是,这段代码是我写的,那么我应该有足以能够理解这段代码的智慧吧?


然而这种情况我已经经历过不止一次了,于是我便开始认真地去思考一个问题,那就是:为什么我的代码在我开始编写的时候很清楚,而当我几周或几个月后回过头再来看的时候,它们却变得如此让人费解。



题1,过度复杂的心智模型

想要理解为什么当你休息了一段时间后,再回头看自己写的代码,会令你感到费解的原因。首先第一步,是要理解心智模型的问题。你写的所有代码,几乎都是在试图解决现实世界的问题。在你写代码之前,你需要理解你所要试图解决的问题。这往往也是编程里最难的一步。


为了解决现实世界的问题,我们首先需要形成该问题的心智模型,并以此作为你的编程目的。接下来你需要形成实现编程目的的方案模型,我们姑且称为语义模型(semantic model)。不要混淆你的编程目的和此目的的解决方案。我们倾向于主要考虑解决方案方面的问题,而常常忽略构建目的的模型。


问题2,语义模型到代码的糟糕转化

一旦你形成了最好的语义模型,你就可以将其转化为代码了。我们称之为句法模型(syntactic model)。你接下来就是将语义模型的含义转换成计算机能够理解的语法。


如果你有个非常不错的语义模型,但在转化为代码时搞砸了,那么你在之后某个时间段再回头修改代码时,你将会比较痛苦。当你脑子里还有语义模型时,把你的代码映射到语义模型上还是会比较容易的。例如,此时你回忆起变量“x”实际上代表一条记录被创建的日期、而“y”代码记录被删除的日期,这并非难事儿。然而当你3个月后脑海中已经没有这个语义模型,再回过头来看这段代码时,就很难理解同样的变量名了。


把语义模型转化为句法的任务就是尽可能多地留下线索,这将会让你在今后回查时,能够重建起当初的语义模型。



问题3,没有足够的组块

在心理学中,组块被定义为单个实体的信息分组。那么,这该如何应用到编程上呢?作为一名开发者,在你积累经验时,你会开始看到重复的模式在你的解决方案中反复出现。极具高度影响力的设计模式:《可重用的面向对象软件》(Elements of Reusable Object-Oriented Software)是第一本整理和解释一些模式的书。尽管如此,组块不仅仅用在设计模式和面向对象。在函数式编程(FP)里,存在大量的众所周知的标准函数,它们具有相同的用途。算法是组块的另一种形式(稍后会详细介绍)。


当你使用组块(设计模式、算法和标准函数)时,它会让你停下来思考,你编写的代码是如何运行的,而不是考虑它做了什么。这缩短了你的语义模型(你的代码)和句法模型(你脑中的模型)的距离。这个距离越短,在后期你就越容易重建你的心智模型。



问题4,费解的用法

目前,我们主要讨论了如何结构化你的类、方法和变量命名。心智模型的另一个重要部分是理解这些方法是如何被使用的。再次强调,当你最初形成心智模型时,这是很清楚的。当你后来返回时,就非常难以重建你的类和方法的所有有意图的用法了。通常这是因为不同的用法散布在你的程序其它地方。有时甚至跨许多不同的项目。


我就是在这种情况下发现测试用例是非常有用的。除了相应地知道一个修改是否破坏了代码的明显好处之外,测试还为你的代码提供了一整套的示例用例。你不必搜遍上百个文件,只需通过查看测试就能得到引用的全景。


注意为了达到这个目的,您需要有一组完整的测试用例。如果你的测试仅仅覆盖了一部分,而你认为测试是完整的,那么你之后将陷入困境。


问题5,不同模型之间没有清晰的路径

通常,你的代码从技术角度看,常常是非常好、非常优雅的,但是从程序意图到语义模型、再到代码会存在非常不自然的跳跃。考虑你选择的一堆模型的透明性是很重要的。从程序意图到语义模型,再到代码的过程需要尽可能平滑。你应该通过每个模型看到对应问题的每个模型的各个方面。多数情况下,最好选择一个特定的类结构或算法,而不是孤立地考虑它的优雅,而是能够连接各种模型下,并为重构意图留下一条自然的路径。当你从抽象的编程意图走到具体的代码时,你所做的选择应该被清晰的代码所驱动,这样你就可以在接下来表现出更抽象的模型。


问题6,发明算法

作为程序员,我们经常认为,我们为了解决问题而发明着算法。但这几乎是不可能的。在多数情况下,已经有现成的算法可以被组合在一起解决你的问题了。像最短路径搜索法、字符串相似度算法、粒子群算法等。大部分编程是以正确的组合、选择现存算法来解决你的问题。如果你正在发明新算法,那么,要么你不知道合适的算法、要么你正忙于你的博士论文。


最后总结

作为一名程序员,你的目标是构建一个最简单的语义模型来解决你的问题。将语义模型尽可能地转换为一个句法模型(代码),并提供尽可能多的线索,便于你之后无论哪个人看你的代码,都能重建像你最初脑子里的、相同的语义模型。


设想一下,当你走过被你的代码照亮的那片丛林时,也要记得在你的身后留下面包屑。相信我,当你需要找到回去的路时,丛林仍将充满着黑暗、朦胧和不详。


这听起来很简单,实际做起来是很难的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值