代码中的软件工程

本文根据孟老师课上《工程化编程实战——代码中的软件工程》中的相关内容,编译调试使用了孟宁老师的课程项目案例menu。并同时结合代码分析其中的软件工程方法、规范或软件工程思想。

参考资料:https://gitee.com/mengning997/se/blob/master/README.md

 

1. 编译调试环境配置

1.1安装vscode

下载地址:https://code.visualstudio.com/#alt-downloads

1.2 C/C++编译器下载

MinGw: http://www.mingw.org/

 

 

 1.3 环境变量配置

 

 

1.4 VS Code中配置C/C++开发环境

 

 

 2. 代码中的软件工程思想

2.1代码规范和代码风格

命名:合适的命名会⼤⼤增加代码的可读性;

• 类名、函数名、变量名等的命名⼀定要与程序⾥的含义保持⼀致,以便于阅读理解;

• 类型的成员变量通常⽤m_或者_来做前缀以示区别;

• ⼀般变量名、对象名等使⽤LowerCamel⻛格,即第⼀个单词⾸字⺟⼩写,之后的单词都 ⾸字⺟⼤写,第⼀个单词⼀般都表示变量类型,⽐如int型变量iCounter;

• 类型、类、函数名等⼀般都⽤Pascal⻛格,即所有单词⾸字⺟⼤写;

• 类型、类、变量⼀般⽤名词或者组合名词,如Member

• 函数名⼀般使⽤动词或者动宾短语,如get/set,RenderPage;

注释和版权信息:注释也要使⽤英⽂,不要使⽤中⽂或特殊字符,要 保持源代码是ASCII字符格式⽂件;

• 不要解释程序是如何⼯作的,要解释程序做什么,为什么这么做,以 及特别需要注意的地⽅;

• 每个源⽂件头部应该有版权、作者、版本、描述等相关信息。

良好的注释风格,可以帮助代码阅读者、维护者等人员快速明确地了解到代码所实现的功能等,方便Debug。

 

 

2.2 模块化设计

模块化(Modularity)是在软件系统设计时保持系统内各部分相对独⽴,以 便每⼀个部分可以被独⽴地进⾏设计和开发。这个做法背后的基本原理是关 注点的分离

模块化软件设计的⽅法如果应⽤的⽐较好,最终每⼀个软件模块都将只有⼀个单 ⼀的功能⽬标,并相对独⽴于其他软件模块,使得每⼀个软件模块都容易理解容 易开发。  从⽽整个软件系统也更容易定位软件缺陷bug,因为每⼀个软件缺陷bug都局限在 很少的⼀两个软件模块内。  ⽽且整个系统的变更和维护也更容易,因为⼀个软件模块内的变更只影响很少的 ⼏个软件模块。

因此,软件设计中的模块化程度便成为了软件设计有多好的⼀个重要指标,⼀般 我们使⽤耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。

耦合度是指软件模块之间的依赖程度,⼀般可以分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)和⽆耦合(Uncoupled)。

内聚度是指⼀个软件模块内部各种元素之间互相依赖的紧密程度。  理想的内聚是功能内聚,也就是⼀个软件模块只做⼀件事,只完成⼀ 个主要功能点或者⼀个软件特性(Feather)。

 

 

3.2的数据结构和逻辑实现被分离出来了。

我们可以发现内部实现的逻辑代码其实没有什么差别,但是通过将数据结构函数声明放到了linklist.h文件并且具体实现在linklist.c文件中。

2.3 可重用接口

接⼝就是互相联系的双⽅共同遵守的⼀种协议规范,在我们软件系统 内部⼀般的接⼝⽅式是通过定义⼀组API函数来约定软件模块之间的沟 通⽅式。换句话说,接⼝具体定义了软件模块对系统的其他部分提供 了怎样的服务,以及系统的其他部分如何访问所提供的服务。 在⾯向过程的编程中,接⼝⼀般定义了数据结构及操作这些数据结构 的函数;⽽在⾯向对象的编程中,接⼝是对象对外开放(public)的 ⼀组属性和⽅法的集合。函数或⽅法具体包括名称、参数和返回值等。

 

 上图借用了孟宁老师提供的工程源码文件中的某个源码文件。在这个文件中,可以看到其声明了许多接口,这些接口的实现会放在.c文件中。但不通过具体的实现代码,我们依然可以通过接口的名称、参数、返回值以及相关描述了解到大概的功能,这些接口的也可以被多次重复使用,提高了代码的复用性。

2.4 线程安全

线程(thread)是操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

可重入(reentrant)函数可以被多个线程并发执行,而通常不会导致由于共享数据而导致结果错误;不可重入函数则在多个线程并发执行时,如果不能保持线程互斥,那么就会导致结果的错误。对于软件工程而言,我们应该以比较悲观的方式去评估函数:即可重入函数不一定是线程安全的,可能是线程安全的函数就不是线程安全的函数,不可重入函数一定不是线程安全的函数。

首先,对于线程安全,我们所关注的焦点一般在以下几个方面:

    i. 所有的函数是不是都是可重入函数:分析函数有没有访问临界资源,若有则必须仔细分析其互斥的处理过程;

    ii. 不同的可重入函数有没有可能同时进入临界区:读写互斥应该如何去考虑;

    下面,同样地,通过孟宁老师所给出的代码,我们选择一段代码来加以解释:

 

 在需要进入临界区时,我们对代码进行了加锁操作以确保其他函数无法使用临界区的资源,当我们退出临界区后及时解锁供以其他函数访问,最后销毁互斥锁,这就是一个典型的线程安全代码。

 

posted @ 2020-11-10 21:29  千株松  阅读(154)  评论(0)    收藏  举报