我还无法在我的课程上教学生如何掌握技能,从而让他们成为这些最好的程序员。如果我们没有教授计算机科学中最为重要的原理,我们又怎么能做到这一点呢?这个问题困扰我多年。我问自己,有可能教出伟大的程序员吗?
也许,编程只是某种与生俱来的天赋。要么有天赋,要么没天赋,没法后天教授。后来,我读到一本书,这也是我最喜欢的一本书之一——的Talent Is Overrate。在这本书中,Colvin给出了不同领域中关于学习的例子,从音乐、到数学、到国际象棋,尝试给出这个问题的答案。
在某个领域中,将最好的人和那些平庸的人区分开来的,并不是所谓的某种与生俱来的天赋。真正让精英脱颖而出的是他们曾经凝心聚力、聚精会神、涉猎广泛地练习。这才是区分他们的“照妖镜”,在读完这本书后,我意识到,软件设计也是如此。只要找到让人们不断正确练习的方法,教授软件设计一定是有可能的!
那么接下来的问题是,谁来教这些呢?问题是,大多数教员是无法教授的。因为没有课堂会教授软件设计,学习并成为伟大的软件设计师的唯一方法,就是编写大量的软件并获得丰富的经验。
但是教职员并不做这些事情,当你还是本科生的时候,会写一点代码,但不会得到太多的反馈。因为没有人真正教你如何更好地编写代码,然后,当你成为教授的时候,大多数人立即觉得编程是本科生的事情。因此,他们自己不再编写代码。最终,教员们对于什么是软件设计的关键思想,以及如何教授这些思想,毫无经验可言。
可我不是一个典型的教授。我喜欢编写代码,编写代码是我生命的意义所在,也是我一生中最喜欢干的事情。如果我每年不写个5000到1万行的代码。我感觉这一年过的很糟糕。在我的职业生涯中,我大概编写了30万行代码甚至更多。我曾经参与软件开发团队,从头开发了3种操作系统,5个文件存储系统。我写过脚本语言,编了几个toolkit,2个调试器,5个各种各样的,两个并行编译系统,等等。
我编写了大量的代码,软件设计令我着迷。因此,基于我的开发经验,我试图探寻并理解,是什么让程序更复杂或更简单,并且易于管理。我对此至少有一些认知。
那么,第三个问题是,你怎么才能教这些东西。我为此与人争论不休,最终决定,自己来尝试。因此,我在斯坦福大学开设了一门新的课程,CS190即软件设计工作坊,这门课不像大多数传统计算机科学课程那样讲,其教授方式更像是我在高中学习英语写作方式。
在高中,教师给我们布置一些东西去写,学生们都要写一个草稿,然后老师阅读这个草稿,并且提出批评意见,用标记出来,将其打回给学生,学生再重新写,这个过程会迭代几次,并不断得到反馈、重写;然后学生就学会如何写了。
我认为这里有两个很重要的关键过程。第一是,你必须得到高质量的反馈。第二是,你需要能够领会并融合这些反馈,从而才能看到结果变得更好。因为,用正确的方法做事情和用错误的方法做事情,高下立判。
在计算机科学课堂上,我敢说,至少在斯坦福的课堂上并没有这么做。很少有课堂能够对于学生编写的代码的质量给出任何反馈;而这些反馈,恰恰对于代码能够工作很重要。在极少的一些课堂上,学生得到了反馈,但他们没有机会返工并融入这些反馈,重构程序或修复bug,因此,他们没有经历不断迭代的学习过程,也没有机会在同一件事情上不断地尝试。
在 CS190 课程中,我尝试每季度迭代一次的方式,整个过程大概分3个单元。第一个单元持续3周时间,学生编写一个我期待他们能够在3周内编写的最大的程序。通常这个程序要有几千行代码,并且他们要从头开始编写,我不会给他们提示、模版或者代码框架,他们必须从头开始设计一切。在他们完成第一次尝试之后,我们做代码评阅,学生要阅读彼此的代码,我们在课堂上做设计评阅。每个项目要展示他们的设计部分,然后,从那些阅读了设计的其他学生那里获取评论。
我会阅读每个单独的项目,然后,我会和学生面谈并回顾我的评阅,这些评阅相当广泛。然后,学生在课程的第二个阶段修改自己的项目。我也会给他们的项目增加一些更有难度的内容,然后,我们做第二轮的代码评阅。
然后进入第三个阶段,学生再次从头开始编写一个完全不同的程序。这个程序要重新设计,他们需要在3周时间内完成。然后,经过另一论的代码评阅,他们就可以结课了。
类应该深。这是什么意思呢?把类想象成一个矩形,其中,矩形的面积就是这个类所提供的功能性。矩形的上边是接口,即用户要使用这个类所必须了解的一切。因此,功能性是好东西。功能多的类,可能比那些功能少的类要好。
尽管接口是必须要有的,但接口是有成本的,接口越复杂,要学会使用这个类就越难,因此,我们想要的类是功能尽可能多,接口尽可能少。
因此,浅的类不具备这样的特点,它没有太多的功能,却有一个相当复杂的接口。浅的类给你的回报不多,因为你要花很多时间去学习如何使用它,并且一旦学会使用它,也不会从中获益良多,相反,深的类有很多功能,但在这些功能之上的接口却相当简单。
深的类就很好。特别是深的类,让我们有了杠杆来对抗复杂性。我自己在软件设计方面尝试做的最重要的事情,就是尝试管理复杂性。复杂性是万恶之源。它使得软件开发变得很难,因此,好的软件设计的相当一部分工作,都和如何消除复杂性有关。但是,并不是所有的复杂性都能够消除的,因此,软件设计的另一部分工作就是,努力隐藏复杂性。
极少数人拥有关于复杂性的经验,并且他们不一定经常能见到复杂性。例如,如果你有一个复杂的函数,并且用一个相当简单的接口将其放入到一个类中,那么,你已经有效地隐藏了复杂性。
我们来看下一个主题,战术性编程和战略性编程。好的软件设计还有一个最重要的要素,就是要有正确的思维方式,有两种不同的思维方式,我称之为战术性编程和战略性编程。
其中一种思维方式是,主要目标是让下一件事情工作,不管是开发新功能还是修复bug,你都希望它尽可能快地工作。这似乎是一个合理的目标,这是战术性方法。你告诉自己,要关注于内容能够工作。
我想要做的是通用性更好的设计,我通常努力并让代码整洁,但是,如果我采取只是一小点捷径,就会让下一个功能工作,没问题,你说服自己这很好。问题是这很快会导致更高的复杂性,因为每次添加一个功能,每次修复一个bug
都在添加有一个小的陷阱,这增加了复杂性。
而且不仅是你在这么做,项目中的其他人也这么做,结果,复杂性构建起来了
最终得到了一个糟糕的设计,复杂性变得无法管理。这种情况叫做技术债务。
对于复杂性来说,你必须意识到的最重要的事情之一是,它是不断增加的也就是说,当一个系统高度复杂的时候,不是因为某一个人犯了大错误并且这个错误让系统高度复杂。高度复杂性来自于一堆鸡毛蒜皮的小事情,其中每一个都人畜无害,但是一个有一个地叠加起来,形成了一大堆的复杂性。
还有一个问题是,一旦形成高度复杂性,没有简单的修复方法。不可能毕其功于一役,让复杂性全消失。你可能必须修复成百上千问题,因此,一旦系统变得复杂,几乎不可能再令其脱身。因此,我的建议是战术性方法将会导致问题,能工作的代码是远远不够的。你的代码必须能工作,但这不够。我赞成的是战略型方法编程。
战略型编程驱动你朝向最重要的目标,也就是要有整洁的设计。为什么需要整洁的设计呢?因为它将使你未来的开发更难快,快速实现当下的功能不是最重要的,我们还需要能够保持未来的开发快速进行。
在项目的任何周期、任何节点,可能大多数开发都不是面向未来的,我们不希望只是为了让今天的事情更快一些,就搞乱一切。因此,必须努力并且把复杂性最小化,必须关心所有那些小细节。不要让这些小麻烦在系统中堆积。
考虑这一点的另一种方法是投资思维。花一点额外的时间来解决当前开发中的问题,但是这么做,最终会让你未来的开发工作更快,这就是它的回报。
总结一下,我现在认为,伟大的程序员是可以教会的,但遗憾的是,目前还无法做到。其次,我认为有一系列原理正在浮现,虽然我还无法将其尽述。当我开始考虑教这门课的时候,会有一个疑问,是只有一种方式去做软件设计吗,还是说有可能两个不同的人用完全不同的方式去做软件设计,并且都能够获得成功?我也说不准。但随着课程的结束和本书的出版,我相信这本书总的原理是正确的做事方式。我的长期目标是希望,这本书引发大家关于软件设计的讨论,让社区意识到软件设计的重要性。因此,也期待大家对本书的意见和反馈。期望我们能够对于软件设计的原理达成一些共识。
作者:约翰.奥斯特豪特(John Ousterhout)
斯坦福大学计算机科学教授,美国国家工程院院士,曾任的计算机科学教授;获得了包括ACM软件系统奖、ACM Grace Murray Hopper奖、美国国家科学基金会总统青年研究者奖和加州大学伯克利分校杰出教学奖等多项荣誉;聚焦于与构建软件系统的基础设施相关的广泛主题,包括、操作系统、存储系统、开发框架和编程语言;在工业界有14年的经验,创办了Scriptics 和Electric Cloud两家公司;Tcl脚本语言的创建者,并且以和存储系统的相关工作而闻名。
约翰.奥斯特豪特(John Ousterhout)的
1. 作者专业,内容靠谱:约翰.奥斯特豪特,斯坦福大学计算机科学教授,具有丰富的工业界经验和学术成就,是Tcl的创建者,曾获多个技术奖项。
2. 系统化解决软件复杂性:全面探讨软件设计中的复杂性管理,提供具体方法以实现复杂软件系统的有效模块化。
3. 实用的设计哲学:与热销书的《》进行对比,强调的选择,教导读者如何区分软件设计中的重要事项。
4. 内容全面更新:第二版在前一版基础上增加了新的设计策略和案例,提供更多实用的设计知识和技巧。
本书深入探讨了软件设计中的核心问题:如何将复杂的软件系统分解为可以相对独立实现的模块(例如类和方法),从而降低其复杂性并提高开发效率。本书首先介绍了软件设计中的基本问题,即复杂性的本质。其次,讨论了有关如何处理软件设计过程的“哲学”问题,如通用设计的重要性、与《代码整洁之道》中设计哲学的对比,以及如何将重要的东西和不重要的东西区分开等内容。最后,总结了在软件设计过程中应遵循的一系列设计原则,以及一系列识别设计问题的警示信号。
本书适合软件工程师、计算机科学专业的学生、教育者、对软件设计和开发感兴趣的自学者和技术管理者阅读。通过应用本书中的思想,读者可以最大限度地降低大型软件系统的复杂性,从而更快地以更低的成本编写软件,并构建更易于维护和增强的系统。
因篇幅问题不能全部显示,请点此查看更多更全内容