总结:
经过为期十二周的软件工程(C编码实践篇)学习,我从对软件工程的一无所知,到现在基本了解开发软件过程中的一些注意事项、规则和方法,可以说是获益匪浅。同时,课程配套的实验也大大提升了我的编码能力,特别是代码模块化、封装这一块,我感觉我能够更深入地理解程序的逻辑,编写代码思路也更加清晰、有条理。
先对课程章节内容进行回顾和整理:
1、课程简介
简单地说,学习软件工程能够让人在软件开发时少走一些弯路。
2、熟悉Linux编程环境
为什么要学习用Linux系统?1、专业的程序员应该了解unix类的操作系统。2、大多数服务器用Linux系统。3、Linux环境下做开发可以彻底掌控设计。
个人感觉,在Linux下开发,过程会比较清晰,但效率暂时偏低,需要较长时间的使用才能彻底掌握vim等工具。另外还有一个好处,就是会减少程序员对系统的依赖,能够更快适应其它平台。
3、代码风格规范
这一章详细讲了缩进、命名、注释等代码编排的风格规范,对我产生了重大的影响。以前我也知道代码风格的重要性,却没有去认真了解一般规范是怎样的,只是按照自己觉得怎么好看、怎么方便去写。经过老师点拨,我尝试采用公认规范去写,的确感觉代码比以前有条理得多,十分易于阅读,特别是在改bug的时候。现在我已经完全形成了编写规范代码的习惯!
4、基本的模块化设计(separation of concerns)
代码设计中的一些常见方法:
KISS(keep it simple & stupid):一个函数或一个方法,只做一件事。扩展开来,在设计上,一个系统、一个子系统、一个模块、一个类等也只做一件事。
using design to frame thecode(matching design with implementation):including pseuducode,在从设计到实现的过程中加入伪代码要好于直接将设计翻译成代码。
不要和陌生人说话原则(Law of Demeter):一个对象应当对其他对象有尽可能少的了解。
合理利用Control Structures、DataStructures来简化代码:采用合适的控制结构和数据结构能大大简化代码。
一定要有错误处理:Debug版本中所有的参数都要验证是否正确;Release版本中从外部(用户或别的模块)传递进来的参数要验证正确性。
5、可重用模块的接口设计(天王盖地虎,宝塔镇河妖)
简单地说就是造轮子,要求达到高内聚低耦合的设计目标,方便重复使用。
常见接口设计规范有:参数化上下文,生死相依原则,移除前置条件,简化后置条件等,另外还需编写开发者指南,供用户阅读使用。
这里要考虑一个接口通用的问题,并不是越通用越好,因为过于通用需要考虑很多情况,导致模块臃肿、效率低下,因此应该not too specific, not too general。
6、callback函数
用callback函数设计接口能够方便地实现多态,使接口更加通用而避免考虑许多情况,用户使用起来也更简洁。但callback的做法是把某些实现丢给了用户,也算造成了一些不必要的麻烦,应该尽量少用callback。
这里还提到了信息隐藏,一般地说,定义和实现需要隐藏,而声明和接口暴露给用户。
7、函数的可重入性(reentrant)及线程安全浅析
可重入函数:可以由多于一个任务并发使用,而不必担心数据错误。相反,不可重入(non-reentrant)函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用本地变量,要么在使用全局变量时保护自己的数据。
线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
函数的可重入性与线程安全之间的关系:
可重入的函数不一定是线程安全的;
可重入的函数在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题(可能是线程安全的也可能不是线程安全的);
不可重入的函数一定不是线程安全的。
8、子系统的可重用设计
尽管已经为链表设计好接口,但要避免错误:手里有把锤子,看哪里都是钉子。menu子系统比较特殊,与链表等常用模块不同,接口不需要太通用,但为了可用于不同的项目,也不能太具体(够用就好)。同时为了方便工程编译,应该写Makefile文件,可以用automake或autoconf。
为了让menu子系统功能更强大,可用strtok和getopt等函数使其支持带参数命令。
9、代码背后的设计思想
设计方法论:不断地重构
几个重要的设计指导原则:
Modularity
Interfaces
Information hiding
Incremental development
Abstraction
Generality
为方便修改完善实验报告,更正理解有误或不准确的地方,现将课程实验做成以下目录列表:
实验一、写一个hello world小程序
掌握Linxu系统常用指令ls、mkdir等,掌握vim、git的使用。
实验二、命令行菜单小程序v1.0
代码风格的原则:简明、易读、无二义性,编写一个符合代码风格规范的命令行菜单小程序,可实现有限的几个功能。
实验三、内部模块化的命令行菜单小程序v2.0
将程序划分为业务逻辑层和数据存储层,采用单向链表作为数据存储结构。
实验四、用可重用的链表模块来实现命令行菜单小程序v2.5
将链表设计成可重用的模块,添加若干接口。
实验五、用callback增强链表模块来实现命令行菜单小程序v2.8
用callback函数设计链表模块接口,让链表模块更好地适应用户的需求。
实验六、将menu设计为可重用的子系统
对menu进行封装,添加相应接口,编写范例代码,并采用make进行工程编译。改进menu,使其支持带参数命令。
顺便分享一下老师喜欢的名言:
“天下事有难易乎?
为之则难者亦易矣,
不为则易者亦难矣。” ——彭端淑《为学》
“夫事未有不生于微而成于著,
圣人之虑远故能谨其微而治之,
众人之识近故必待其著而后救之,
治其微则用力寡而功多,
救其著则竭力而不能及也。” ——《资治通鉴》