代码中的软件工程——menu项目分析
本篇博客基于孟老师所提供的参考资料: https://gitee.com/mengning997/se/blob/master/README.md#%E4%BB%A3%E7%A0%81%E4%B8%AD%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B 通过一个menu项目,浅谈一些我对于软件工程的理解。感谢孟宁老师在此过程中提供的帮助 !
一. vscode环境配置
第一步,vscode中安装 C/C++扩展
第二步,安装C/C++编译器和调试器
直接在vscode里搜索Clang for XCode on macOS,就可以安装了。
第三步,安装Code Runner
在配置好环境之后,我的vscode执行起代码不是很方便,缺少直接点击run的按钮,经过查找资料发现,下载一个Code Runner插件之后就可以了。可以看见右上角出现了▶️的按钮,使得之后的使用便捷很多。
第四步,成功运行代码
打开孟老师给的程序,成功运行,表明环境配置成功。
二. 模块化设计
模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。这个做法背后的基本原理是关注点的分离 (SoC, Separation of Concerns),是由软件工程领域的奠基性人物Edsger Wybe Dijkstra(1930~2002)在1974年提出。
关注点的分离在软件工程领域是最重要的原则,我们习惯上称为模块化,翻译成我们中文的表述其实就是“分而治之”的方法。 关注点的分离的思想背后的根源是由于人脑处理复杂问题时容易出错,把复杂问题分解成一个个简单问题,从而减少出错的情形。
模块化软件设计的方法如果应用的比较好,最终每一个软件模块都将只有一个单一的功能目标,并相对独立于其他软件模块,使得每一个软件模块都容易理解容易开发。 从而整个软件系统也更容易定位软件缺陷bug,因为每一个软件缺陷bug都局限在很少的一两个软件模块内。 而且整个系统的变更和维护也更容易,因为一个软件模块内的变更只影响很少的几个软件模块。 因此,软件设计中的模块化程度便成为了软件设计有多好的一个重要指标,一般我们使用耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。
不难发现,在lab3.2中,仅有一个menu.c文件,所有的代码逻辑和变量申明全都包括其中,非常的混乱,可读性较差。
而为了体现模块化的思想,孟宁老师在代码lab3-3中引入了接口,将功能的实现与主代码程序分离开来。在这个文件夹中,menu.c为主程序,linklist.h为功能实现程序的接口,linklist.c为功能实现的具体代码。主程序通过调用接口中的函数实现自己所需要的功能。
三. 可重用接口
1 接口的概念:
尽管已经做了初步的模块化设计,但是分离出来的数据结构和它的操作还有很多菜单业务上的痕迹,我们要求这一个软件模块只做一件事,也就是功能内聚,那就要让它做好链表数据结构和对链表的操作,不应该涉及菜单业务功能上的东西;同样我们希望这一个软件模块与其他软件模块之间松散耦合,就需要定义简洁、清晰、明确的接口。 这时进一步优化这个初步的模块化代码就需要设计合适的接口。定义接口看起来是个很专业的事情,其实在我们生活中无处不在,比如我们看的电视剧中“天王盖地虎,宝塔镇河妖”就是黑社会接头定义的接口,比如两个人对话交流沟通使用的就是汉语普通话或标准英语这么一个接口规范。
接口就是互相联系的双方共同遵守的一种协议规范,在我们软件系统内部一般的接口方式是通过定义一组API函数来约定软件模块之间的沟通方式。换句话说,接口具体定义了软件模块对系统的其他部分提供了怎样的服务,以及系统的其他部分如何访问所提供的服务。 在面向过程的编程中,接口一般定义了数据结构及操作这些数据结构的函数;而在面向对象的编程中,接口是对象对外开放(public)的一组属性和方法的集合。函数或方法具体包括名称、参数和返回值等。
接口规格是软件系统的开发者正确使用一个软件模块需要知道的所有信息,那么这个软件模块的接口规格定义就必须清晰明确地说明正确使用本软件模块的信息。一般来说,接口规格包含五个基本要素: 接口的目的; 接口使用前所需要满足的条件,一般称为前置条件或假定条件; 使用接口的双方遵守的协议规范; 接口使用之后的效果,一般称为后置条件; 接口所隐含的质量属性。
可重用接口是用于实现软件重用开发的重要部分,它可以大大的提高软件的开发效率,同时一个实现良好的接口可以减少耦合。在menu项目中,我们用到了链表的数据结构,而在一个比较大的项目中,我们可能会多次用到链表的结构。因此,我们希望能写一个链表的通用模块,方便以后的重用。于是便有lab4中linktable.c和linktable.h文件。我们可以看到,在代码lab4的linktable.h中,插入了以下代码:
四. 线程安全
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。lab7.1中就对各个函数加入互斥锁实现了可重入函数,这样不同线程访问同一个可重入函数时,就不会导致数据不一致的情况。
五. 总结
通过本次的学习,我对代码模块化设计、可重用接口、线程安全等有了更深的理解。相信在之后的学习工作中能有更好的表现。