对于程序员来讲,一个排序函数可能只需要十多行代码,不需要特殊的专门工具就可以完成,你甚至可以使用记事本完成。但是对于一个大的项目——比如微软的office,大约会有4000万行代码,这是一个程序员所不能独立完成的。为了写大型程序,程序员用各种工具和方法,这些工具和方法论构成了今天的“软件工程”学科。
把大项目分解成小函数,可以让多人同时工作。程序员不用关心整个项目、关心自己的函数就好了。如果你的任务是写排序算法,你只需要确保高效和正确就可以了。然而把代码打包成函数是依旧不够的,如果只是这样,微软office会有几十万个函数,虽然比4000万行代码要好一些,但还是太多了。解决方法是:把函数打包成层级,把相关代码都放在一起,打包成“对象(objects)”——这个解决方法在我学习框架时感受颇深。例如,汽车软件中可能有几个和定速巡航有关的函数,比如:设定速度、逐渐加速减速、停止定速巡航,因为这些函数都相关,可以包装成一个“定速巡航对象”。
但是还不止如此,我们还可以做更多。“定速巡航”只是引擎软件的一部分,可能还有“火花塞点火”“燃油泵”和“散热器”。我们可以做一个“引擎对象”来包括所有“子”对象,而且除了子对象,引擎对象可能有自己的函数:比如开关引擎;它也会有自己的变量,比如汽车行驶了多少英里。总的来说,对象可以包其它对象、函数和变量。
当然,引擎对象只是汽车对象的一部分,还有传动装置、车轮、门、窗等。
作为程序员,如果想设“定速导航”,要一层层向下,从最外面的对象往里找,最后找到想执行的函数:Car.Engine.CruiseControl.setCruiseSpeed(55)。编程语言经常用类似这样的语法,把函数打包成对象的思想叫“面向对象编程(object priented proigramming)”。这种思想和之前类似,通过封装组件隐藏复杂度:之前把晶体管打包成了逻辑门,现在软件也这么做,这样就又提升了一层抽象。
把大型软件(如汽车软件)拆成一个个更小单元,适合团队合作。一个团队负责定速巡航系统,团队里的一位程序员负责其中一些函数,类似建摩天大楼:有电工装电线、管道工配管…有着成百上千人做其他事情,在不同岗位同时工作,各尽其能,直到整栋楼完成。回到定速巡航的例子,定速巡航要用到引擎的其它函数来保持车速,而这些函数的代码不由定速巡航团队负责,而是另一个团队负责。因为是其他团队的代码,定速巡航团队需要文档(document)帮助理解代码都做什么,以及定义好的“程序编程接口(API)”。API帮助不同程序员合作,不同知道具体细节,只要知道怎么使用就行了。例如“点火控制”对象中,可能有“设置发动机转数”函数、“检查火花塞电压”函数、“点燃单个火花塞”函数。定速巡航团队可以使用设置发动机转数(setRPM)函数,然后不使用该对象中的其他函数,例如“点燃单个火花塞”函数。
API控制哪些函数和数据让外部访问,哪些仅供内部。对于“面向对象”的编程语言,可以指定函数是public或者private来设置权限。如果函数标记成private,意味着只有同一个对象内的其他函数能调用它。在这里例子里,只有内部函数比如setRPM才能调用fireSparkplug函数。setRPM函数是public,所以其他对象也可以调用它,比如之前提到的定速巡航(setCruiseSpeed)。“面向对象编程”的核心是,隐藏复杂度,选择性的公布功能。因为做大型项目很有效,所以广受欢迎。
计算机上几乎所有软件,游戏机里几乎所有游戏,都是使用“面向对象的编程语言(object oriented programming language)”写的,比如C++,C#,Objective-C等。其他流行“OO”语言,你可能听过python和java。有一点很重要:代码在编译前就只是文字而已,你可以使用记事本或任何文字处理器写代码。但是现代软件开发者会用专门的工具来写代码,工具里集成了很多有用的功能,帮助写代码、整理、编译和测试代码等等。因为集成了所有东西,所以叫做“集成开发环境(Integrated Development Environments,IDE)”。所有IDE都有些代码的界面,还带一些有用功能,比如代码高亮,来提高可读性。许多IDE提供实时检查,比如拼写。大型项目有很多源代码文件,IDE帮助开发者整理和看代码。很多IDE还可以直接编译和运行,并且在程序运行出错时提供报错信息并定位到出错代码的,这就叫做“调试(debug)”。调试是非常重要的,大多数程序员会花70%~80%时间调试,而不是在写代码。好的工具能极大帮助程序员防止和解决错误。
除了写代码和调试,程序员工作的另一个重要部分是给代码写“文档(document)”。文档一般放在一个叫readme的文件里。告诉其他程序员,看代码前先看这个文件。文档也可以写成“注释(ccoment)”直接放进源代码里。注释是标记过的一段文字,编译代码时,注释会被忽略,注释存在的唯一作用就是帮助开发者理解代码。好文档能帮助开发者很长一段时间后也能理解自己的代码,这对其他需要阅读代码的人来说也很重要。最糟糕的事情就是拿到一堆代码但是却没有任何注释和文档。
文档还可以提高代码的复用性(code reuse)。与其让程序员一遍遍写同样的东西,可以直接用别人写好的来解决问题。读文档看怎么用就行,不用读代码。除了IDE,还有一个重要软件帮助团队协作,叫做源代码管理(source control),也叫作版本控制(version control,revision control),比如GIT,SVN。苹果或微软这样的大型软件公司,会把代码放到一个中心服务器上,叫做“代码仓库(repository)”。程序员想改一段代码时,可以直接检出(check it out,意思应该是指直接同步到本地的仓库中甚至IDE中)。一般这种操作可以直接在IDE中完成,然后开发者在自己的电脑上编辑代码并测试。如果代码没问题了,所有测试通过了,可以把代码放回仓库中,这个就叫做提交(commit)。当代码被检出,而且可能被改过了,其他开发者就不会动这一段代码,防止代码冲突和重复劳动。这样多名程序员可以同时写代码,建立庞大的系统。代码的主版本(master)应该总是编译正常并尽可能少bug,但有时bug还是会出现。幸运的是,源代码管理可以跟踪所有变化。如果发现bug,全部或部分代码可以“回滚(rolled back)”到之前的稳定版。“源代码管理”也记录了谁改了什么代码,因此可以真正地在出错的地方溯源。
测试一般由个人或小团队完成。测试可以统称为“质量保证测试”(QA),严格测试软件的方方面面,模拟各种可能情况,看软件会不会出错——基本上就是在找bug。解决大大小小的错误需要做很多工作,但对确保软件质量至关重要,让软件在各种情况下按预期进行。你可能听过“beta版”软件,意思是软件接近完成,但不是100%完全测试过。公司有时候会向公众发布beta版以帮助发现问题。还有一种版本叫做“alpha版本”,alpha版本一般很粗糙、错误很多,经常只在公司内部测试。
以下是本集的总结:
十六、软件工程
最新推荐文章于 2024-01-14 11:55:38 发布