16 一切皆概念:程序的“好”是指什么?
你好,我是李云。这一讲我想和你聊一聊什么是好程序。
在15讲我们聊如何提高编程水平时,你可能就留下了“什么是好程序”这个疑问。也是,如果我们一边讲如何提高编程水平,一边却不知什么是好程序,那提高水平这事就缺了目标感。在进一步讨论什么是好程序前,我想先问你一个问题:你认为编程的本质是什么?
编程的本质
当我在公开课和企业内训课上问学员这个问题时,得到的答案无外乎“为了实现功能”和“为了满足需求”,不知你是否也这么认为呢?不过,基于你的生活经验,但凡包含“本质”这两个字的问题,你的经验会告诉自己,提问人想要的回答没那么简单。
对于这个问题,我给出的回答是:编程的本质,是为了实现程序员与计算机,以及程序员之间的交流。你乍一听到这个观点,可能觉得有新意,也可能有疑惑,特别是针对更重要的后半句。什么,后半句还更重要?
前半句很好理解,程序员与机器交流的结果,就是“实现功能”和“满足需求”。不过,这个本质并不会给人带去太大的困扰,就是功能实现错了或没有满足需求,也是容易发现的,咱也大概率会采取修正的行动。
为了方便理解,后半句还可以表达为:编程的本质是程序员之间基于编程语言的交流。换句话说,程序员所写的程序不只是给机器读,还得考虑到他人也得读。与前半句不同的是,后半句的背后隐含了程序员之间无意识的相互折磨,甚至可以说,由此造就了程序员在职场所面临的最大痛苦和无力感——再乱的代码也得硬撑着维护下去。程序员所共同信仰的代码,最后却摧毁了彼此的信任。
什么是好程序
那怎样的程序才是“好”呢?一听到这个问题你可能会想到好的程序应符合一些具体的原则。比如,面向对象设计的SOLID原则、避免代码冗余的DRY原则、让程序简单的KISS原则,等等。这些原则确实能给我们的编程工作提供更具体的指导,不过我担心因为太具体而让你“只见树木,不见森林”,看得没那么透彻。那我就来说说我所看到的“森林”吧。
基于我对编程本质的理解,我对好程序的第一层理解是:让人易于理解的程序才是好程序。每个程序员都可以写出让计算机易懂的程序,但要写出让人易于理解的程序却很难。不过,下一个问题又来了,“什么是易于理解?”
回想我在通信行业工作时,某天有位同事问我,“你有没有觉得C语言写的程序好懂,用C++语言写的却绕来绕去难懂?”这个问题的背后,其实是在表达面向过程所写的代码,比面向对象所写的代码更易懂,那是不是意味着,用C++所写的程序就一定比用C写的更难懂呢?当然不是!
我这位同事的问题在于,他因为没有完全掌握面象对象编程,所以读C++的代码时就会觉得绕。如果你同时掌握了面象对象和面向过程编程,那么一定会认同面象对象是比面向过程,抽象层次更高的编程方法论。
这么一来,当我们说程序的“易于理解”指的是在同一个抽象层次下的比较,而不是跨抽象层次下的比较。这就好比,对于初学者来说,学习骑自行车可能看起来比走路更困难,因为他们需要掌握平衡等新技能。然而,一旦掌握了骑自行车的技能,对于骑自行车的人来说,进行长距离旅行就会比徒步更加轻松和高效。这是因为自行车的发明本就是为了使远行变得更加容易。在这个比方中,重点在于对于那些已经习惯并掌握了某项技能的人来说,使用该技能会感觉更自然和容易,而这正反映了在同一抽象层次内进行理解和比较的重要性。
你注意到了吗?当有了这个共识后,你可能进一步要问,程序易于理解的核心是什么?这是一个非常好的问题,要回答好,得从软件行业自身的特质去找,其实已经有前人很好地思考过了这一问题,比如,《人月神话》的作者布鲁克斯(Frederick P.Brooks, Jr.)就是很重要的一位。不过,他的表达方式有点不同。
1986年,布鲁克斯在他的论文《没有银弹:软件工程中的根本和次要任务》中指出,所有软件开发活动包括根本任务和次要任务。根本任务是打造构成抽象软件实体的复杂概念结构,次要任务是使用编程语言表达这些抽象实体,并在空间和时间限制内将它们映射成机器语言。
换句话说,我们在编程时,其实包含无意识的两大步骤:第一步完成的是根本任务,即构思好概念和概念之间的关系,这一步我称之为“软件设计”;第二步完成的是次要任务,即在满足时间冗余度和空间冗余度的情形下,将概念用编程语言表达出来,这一步就是编码工作。
布鲁克斯指出,过去软件生产效率的巨大进步得益于在次要任务上投入了巨大的努力。比如,新的编程语言、更快的处理器等。然而,除非次要任务占整个软件开发活动的90%,否则即便将次要任务所花费的时间缩减到零,也不能带来软件生产效率数量级的提高。这就是“没有银弹”四个字的核心所指。即便进入21世纪的今天,这一论断依然成立。软件行业在根本任务的生产效率上,并没有取得次要任务那样质的进步。
回到“程序易于理解的核心是什么”这个问题上,我对好程序的第二层理解是:好程序有着清晰、颗粒度合适、连贯且一致的概念。强调概念质量的背后,表达的是对程序的软件设计质量的高要求,这样的程序才易于理解。你可能好奇了,这对程序员的能力,又提出了什么要求呢?那就是需要程序员有良好的概念能力。
概念能力是指个体理解、分析和处理复杂概念和问题的能力。这种能力通常涉及从现象中抽象出关键信息,形成整合的观念和理论,进而能够对复杂的情境进行有效的理解和处理。你知道吗?概念能力是人类应对复杂度的一种独特能力,帮助我们理解并解决大量个例问题。比如,咱这门课程里提出的“职业发展四部曲”、“职场生命周期理论”就是很好的例子。还有,概念能力还意味着创新、创造的出现。以前面提到的远行为例,从古致今出现了马、自行车、火车、汽车、飞机,帮助我们提升远行的效率和舒适度,每种工具的出现伴随着创造的问世和新的概念被塑造。
新概念的提出一开始会带来更高的概念成本,需要我们花一定的时间去学习和掌握。可一旦概念被普及,就能提升沟通的效率。那我们为什么最终会喜欢新的概念呢?因为概念将大大降低大脑需要处理的信息量,降低生物能耗,是进化带给我们的一种生存能力使然。
在工作中,你可能听到过“分而治之”这个词,讲的是对一个复杂的软件系统,用以大化小、拼积木的方法来实现。当你知道了程序中概念的核心作用后,就可以理解为,复杂的软件系统是通过概念的切分与塑造来实现的。希望这样的表达,能进一步强化你对程序中概念的重要性这一认识。
当程序有了良好的概念就一定是好程序吗?回忆一下咱的工作场景,咱并非只为了懂而去读程序,更是为了维护或增强。换句话说,读程序并不只是为了学,更是为了要干。这就引出了我对好程序的第三层理解:好程序是让人容易修改的。你意识到了吗?程序是否容易修改,也在检验我们对概念的切分与塑造是否合理。那些“面条状”的难改代码,正是因为没有恰当地塑造概念以及厘清概念之间的关系而带来的。
好了,现在我讲完了什么是好程序。不过,或许你会有个困惑,会问:“程序的性能、算法、内存开销等要素,为何没有作为好程序的评价指标?”
我对编程的一个核心理念是,好程序是通过优化而演进出来的。因此,只要程序易懂又好改,其他的问题都不是问题。回顾一下咱的工作经历,最大的痛苦正是来自程序的难懂与难改。这个理念的背后,还符合程序员自身的成长规律,咱是不是时常对自己之前写的代码不满意呢?而引起不满的最主要原因,就是难懂和难改。
总结时刻
好了,让我们对这讲的内容做一个总结。什么是好程序是每位程序员都非常关心的事,这关系到程序员提升编程水平的努力方向。
基于咱的工作经验,我们知道好程序最直接的特点是得让人容易理解,这也是我们与程序打交道时所面临的首要痛点。你想啊,如果程序都让人难懂,那工作效率能高吗?
要写出易于理解的程序说来简单,但要做到并不容易,因为容易理解只是程序的“面子”,而“里子”是需要塑造清晰的概念,这一步也是布鲁克斯所认为的软件开发活动中的根本任务。基于你的编程体验,想必你也会认同布鲁克斯的观点吧。基于我的工作经验,我认为清晰、颗粒度合适、连贯且一致的概念,是程序易于理解的关键。
当然了,程序易于理解的目的,不只是为了学习,还是为了对程序进行改变。进一步意味着,对程序中的概念和概念之间的关系提出了要求。总之,概念是好程序的一切。为了让你印象更深刻,我画了下面这张图,帮助你记住“一概两易”。
这张图也告诉我们,程序员在提升自己编程水平的同时,也在历练自己的概念能力。这种能力所包含的,不只是为了软件系统的需要来恰当地切分和塑造概念,还有具备理解和驾驭更复杂和抽象概念的能力。后者好比,在前面远行的例子中,我们希望成为能骑自行车的人,而非只能光脚走路的人。
最后,我想请你思考,这一讲对你理解“高内聚,低耦合”这六个字,有什么启发吗?期待你留言与我分享交流。
我们下一讲见。
- pyhhou 👍(2) 💬(2)
“高内聚,低耦合” 让我想到了另外一个衡量程序好坏的概念——正交,这两者类似。两个相互正交的模块在功能和逻辑上均无重叠,对一个模块的修改不会影响到另一个模块,并且也没有重复代码,利于维护,模块和模块的职责也非常清晰,出了 bug 也可以快速定位问题。 正交这个概念用在团队管理上也是一样的,如果团队成员之间负责的事情不重叠,做的事情不重复,职责清晰,这样相互之间交流都会很清晰,合作也会顺畅。反过来,假设一个成员负责 A,B,C,另外一个成员负责 B,C,D,做一个项目成员之间相互依赖,这样职责混乱,很难管理不说,也很难高效做事。 最后,感谢老师的分享,老师有没有什么关于软件设计和写好程序的书籍推荐?感觉写好代码还得多读多练
2024-04-23 - 6点无痛早起学习的和尚 👍(1) 💬(1)
看到老师对“pyhhou”留言的回复,有个疑问了,那在职业不同的发展阶段,如果权衡软件设计能力、写好程序能力的占比呢?比如职业前期、中期、后期等等
2024-06-18 - 浅歌随风 👍(0) 💬(1)
“高内聚,低耦合”是恰当切分概念的结果,降低了程序的修改风险。结合恰当地塑造概念,可使程序即易读,又好修改。
2024-04-16