软件工程学习总结

来源:互联网 发布:淘宝电子烟店铺排名 编辑:程序博客网 时间:2024/05/20 14:42

胡杭 + 原创作品转载请注明出处 + 《软件工程(C编码实践篇)》MOOC课程http://mooc.study.163.com/course/USTC-1000002006

实验一报告
实验二报告
实验三报告
实验四报告
实验五报告
实验七报告

熟悉Linux编程环境

为什么要学习用Linux系统?
1、专业的程序员应该了解unix类的操作系统。
2、大多数服务器用Linux系统。
3、Linux环境下做开发可以彻底掌控设计。

Vim 有三种模式:一般模式,编辑模式,命令行模式

编译一个 C 文件我们可以使用 gcc ,我们可以将 C 文件作为 gcc 的参数,用 -o 加上我们自定义的编译后的可执行文件名称,比如gcc hello.c -o hello,最后生成的可执行文件为 hello , ./hello 即可执行

代码风格规范

从 hello world 开始不断迭代调试使代码长的越来越像一个命令行的菜单小程序
写代码要小步快跑不断迭代,罗马不是一天建成的

声明:做实际项目并不鼓励从头开始写代码,而是找已有的类似项目做逆向工程和再工程

  • 代码风格的大原则:简明、易读、无二义性
  • 缩进:4 个空格
  • 行宽:< 100 个字符
  • 复杂表达式中用 () 清晰表达逻辑优先级
  • 所有 {} 都独占一行且成对对齐
  • 不要把多条语句和多个变量定义放在同一行

命名:

  • 类型/类/函数名/变量名等的命名一定要与程序里的含义保持一致,以便于阅读理解
  • 类型的成员变量通常用 m_ 或 _ 来做前缀
  • 一般变量使用 lowerCamel 风格,即第一个单词首字母校小写,之后的单词首字母都大些,第一个单词一般用来表示变量类型,比如
  • int 型变量: iCounter
  • 类型/类/函数名一般都用 Pascal 风格,即所有单词首字母大写
  • 类型/类/变量一般用名次或组合名次,如 Member
  • 函数名一般用动词或动宾短语,如 get/set , RenderPage

注释

  • 注释也要使用英文,不要使用中文或特殊字符,要保持源代码是 ASCII 字符格式文件
  • 不要解释程序是如何工作的(How)
  • 要解释程序做什么(What),为什么这么做(Why),以及特别需要注意的地方
  • 每个源文件头部都应该有版权、作者、版本、描述等相关信息

基本的模块化设计(separation of concerns关注点的分离)

代码设计中的一些常见方法:

  1. KISS(keep it simple & stupid):
    一个函数或一个方法,只做一件事。
    扩展开来,在设计上,一个系统、一个子系统、一个模块、一个类等也只做一件事。

  2. using design to frame the code(matching design with implementation):including pseuducode(伪代码);设计通常为每一个程序组件提供一个框架。然后用自己的专业知识和创造性来编写代码以实现设计;在从设计到实现的过程中加入伪代码要好于直接将设计翻译成代码。

  3. 不要和陌生人说话原则(Law of Demeter):一个对象应当对其他对象有尽可能少的了解。迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解。例如包装类(wrapper class),本地化外部接口(Localize input and output),经纪人/代理人/中介。

  4. 合理利用Control Structures、Data Structures来简化代码:采用合适的控制结构和数据结构能大大简化代码。

  5. 一定要有错误处理:程序的主要功能(80% 的工作)大约仅用 20% 时间,而错误处理(20% 的工作)却要 80% 的时间。Debug版本中所有的参数都要验证是否正确;Release版本中从外部(用户或别的模块)传递进来的参数要验证正确性。

包容变化是模块化的主要作用。
软件 = 程序 + 软件工程。
用函数指针调用一个函数。
包容功能的变化。
Vim 中的拷贝:v:可视化选择;y:拷贝;p:粘贴。
“开-闭”原则:开放拓展,封闭修改。
业务逻辑层 和 数据存储层。
将系统模块放在不同的源文件中。
抽象实际上是选择性地忽略一些细节。
goto 语句不是不能用,而是要用的恰当。
断言 & 错误处理:肯定如何时用断言;可能发生时用错误处理。

可重用模块的接口设计(天王盖地虎,宝塔镇河妖)

#ifndef _TEST_H_#define _TEST_H_

防止include重复的宏。

接口

  • 接口定义了软件单元对外提供的服务。
  • 函数名,参数和返回值是接口的三个显性的要素。
  • 接口的分类:共享数据或变量名;call-in functions;call-back functions;同步调用接口;异步调用接口(信号量,消息队列等方式实现)。

架构设计目标:高内聚低耦合,简单地说就是造轮子,要求达到高内聚低耦合的设计目标,方便重复使用。
Common Coupling - 共享数据区或变量名
Stamp Coupling - 复杂的数据结构(结构化数据)在模块间传递
Data Coupling - only data values 在模块间传递

通用性:
1. 参数化上下文信息
2. 移除前置条件
3. 简化后置条件

常见接口设计规范有:参数化上下文,生死相依原则,移除前置条件,简化后置条件等,另外还需编写开发者指南,供用户阅读使用。

这里要考虑一个接口通用的问题,并不是越通用越好,因为过于通用需要考虑很多情况,导致模块臃肿、效率低下,因此应该not too specific, not too general。

callback函数

用callback函数设计接口能够方便地实现多态,使接口更加通用而避免考虑许多情况,用户使用起来也更简洁。但callback的做法是把某些实现丢给了用户,也算造成了一些不必要的麻烦,应该尽量少用callback。

这里还提到了信息隐藏,一般地说,定义和实现需要隐藏,而声明和接口暴露给用户。

函数的可重入性(reentrant)及线程安全浅析

可重入函数:可以由多于一个任务并发使用,而不必担心数据错误。相反,不可重入(non-reentrant)函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用本地变量,要么在使用全局变量时保护自己的数据。

线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

函数的可重入性与线程安全之间的关系:

  • 可重入的函数不一定是线程安全的;

  • 可重入的函数在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题(可能是线程安全的也可能不是线程安全的);

  • 不可重入的函数一定不是线程安全的。

子系统的可重用设计

尽管已经为链表设计好接口,但要避免错误:手里有把锤子,看哪里都是钉子。menu子系统比较特殊,与链表等常用模块不同,接口不需要太通用,但为了可用于不同的项目,也不能太具体(够用就好)。同时为了方便工程编译,应该写Makefile文件,可以用automake或autoconf。

为了让menu子系统功能更强大,可用strtok和getopt等函数使其支持带参数命令。

代码背后的设计思想

设计方法论:不断地重构

几个重要的设计指导原则:

  • Modularity
  • Interfaces
  • Information hiding
  • Incremental development
  • Abstraction
  • Generality

总结体会:

软件工程中收获最大的就是代码的可读性和设计代码中使用封装和接口,隐藏信息,降低耦合的重要性。在menu小程序迭代开发的过程,我进一步地了解到c的callback机制、程序如何设计能更好地复用等知识,对软件工程有了更深的理解。在中大型项目,甚至是小型项目中,软件工程的思想都是非常重要的。

致谢

感谢孟宁老师这两个多月以来在学习上的指导与帮助,我从中收获了很多。

原创粉丝点击