代码中的软件工程

本文在中科大软件学院孟宁老师的指导下完成,意在经过对小型程序的分析来帮助体会软件工程方法、思想。git

本文的参考资料及资源来自:软件工程——码农的自我修养程序员

 1. VS Code开发环境配置

1.1 VS Code 安装

    有关VS Code的安装配置能够参考该资料:https://mp.weixin.qq.com/s/sU9Wh12JZqQyJfEBBafFAQshell

    在本文中,咱们对此进行简单介绍。咱们能够在VS Code官网下载,它是一款免费的轻量级IDE,经过扩展插件能够支持多种语言。编程

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

1.2 C/C++编译器下载

    在VS Code中,当咱们经过加载扩展插件来实现支持时,它并不会包含语言的编译器与调试器。这里所说的编译器与调试器,对于C++而言,即为MinGw。安全

    C/C++编译器则为MinGw: http://www.mingw.org/数据结构

    下载完成并安装后,咱们能够获得如下目录:并发

    

1.3 环境变量配置

    一般状况下,在安装MinGw时,会建议或者要求咱们将其添加到环境变量中。但若是咱们忘记了配置,也能够经过如下方法手动进行配置。模块化

    首先,咱们须要获取到MinGw在咱们系统中的安装位置,如上所示,即为:C:\MinGw 。函数

    以后,右键点击此电脑 -> 选择属性 -> 高级系统设置 -> 环境变量,在此处能够管理咱们计算机的环境变量。咱们找到下方系统变量中的Path选项:

    

    经过编辑Path选项,新建添加新环境变量地址,填入上述安装位置。须要注意的是,咱们此时需填入C:\MinGw\bin。

    以上即为C/C++编译器的环境安装配置过程。对于其余语言,如Java、Python、Golang,咱们都可以采用此种方法。

    咱们能够经过命令提示符查看MinGw的安装是否成功,使用gcc -v指令:

    

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

1.4.1 加载C/C++扩展

    在VS Code左侧扩展选项中,咱们搜索C++便可搜索到插件,点击Install后便可安装完成:

    

1.4.2 task.json与launch.json配置

    VS Code经过 task.json 配置文件来获取编译程序的方式,经过修改task.json就能够利用VS Code进行gcc编译源码了。

    一个参考的task.json文件配置以下:

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "gcc build active file",
            "command": "gcc",
            "args": [
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"//
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

    关于task.json的格式,能够参考如下文档:https://go.microsoft.com/fwlink/?LinkId=733558

    

    VS Code经过launch.json配置文件中的配置来调用调试器对程序进行调试。经过快捷键Ctrl+Shift+P,搜索launch.json,能够打开launch.json进行配置。

    一个参考的launch.json的配置文件以下:

    

{

    "version": "0.2.0",
    "configurations": [
        {
            "name": "gcc build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "gcc build active file",
            "miDebuggerPath": "C:\\MinGW\\bin\\gdb.exe" // 此处为上述的MinGw安装地址
        }
    ]
}

    关于launch.json文件的配置,能够参考如下文档:https://go.microsoft.com/fwlink/?linkid=830387

1.4.3 验证安装

    能够看到,运行如下示例成功,说明环境配置成功!

    

    

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

2.1 代码注释风格

    良好的注释风格,能够帮助代码阅读者、维护者等人员快速明确地了解到代码所实现的功能等,方便Debug。一个优秀的代码注释风格以下,这是孟宁老师所给出的案例,很是值得学习:

    

    从中,能够清楚地看到,这个文件中的代码的文件名、做者、模块名、语言类型、运行环境、版本时间以及描述等,对咱们理解代码十分有帮助。

2.2 模块化设计

2.2.1 模块化原理

    模块化(Modularity)是指,在指软件系统设计时保持系统内各部分相对独立,以便每个部分能够被独立地进行设计和开发。这样使得咱们在开发过程当中,每个模块都执行本身单一的功能目标,能够独立于其余软件模块,这样也就方便了开发人员之间的配合。

    模块化的基本原理是关注点的分离(Soc,Separation of Concerns),翻译成中文其实大概即是“分而治之”。

2.2.2 模块化程度

    在实际的软件设计开发中,咱们通常使用耦合度(Coupling)和内聚度(Cohesion)来做为软件模块化程度的高低,它们一样是判断一个软件设计优良程度的重要参考。

    耦合度,是指一个软件中各个模块之间的依赖程度,从高到低在大体上能够分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)。咱们所追求的是松散耦合,它代表咱们所设计的软件各个模块的依赖程度较低,是比较好的设计。

 

     内聚度,是指一个软件模块内部各类元素之间互相依赖的程度。理想的内聚是功能内聚,也即一个模块只作一件事,只完成一个主要功能。

2.2.3 模块化设计:源码分析

    在实现模块化设计时,咱们能够将多种数据封装成结构体、将实现功能封装成一个文件,能够帮助咱们简化代码:

    

    

    

    在上图中,咱们将数据结构以及函数声明放在一个linklist.h的头文件中,其实现放在linklist.c文件,须要调用时再在main函数中去调用,这样就实现了较低的耦合度,也方便咱们做为程序员去debug。

2.3 软件模块接口

2.3.1 接口的定义

    接口是通讯双方共同遵照的一种规范,在软件系统内部通常的接口方式是经过一组API函数来约定软件模块之间的沟通方式。面向对象与面向过程的语言在对接口的是实现通常不相同。前者的接口是对象对外开放的一组属性和方法的集合;后者则是数据结构和操做这些数据结构的函数等。

2.3.2 接口的应用

    

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

2.4 线程安全

2.4.1 线程的基本概念

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

2.4.2 可重入与线程安全

    线程安全问题都是由全局变量及静态变量引发的。若每一个线程中对全局变量、静态变量只有读操做,而无写操做,通常来讲,这个全局变量是线程安全的;如有多个线程同时执行读写操做,通常都须要考虑线程同步,不然就可能影响线程安全。

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

2.4.3 线程安全:代码分析

    首先,对于线程安全,咱们所关注的焦点通常在如下几个方面:

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

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

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

    

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

3. 总结

    孟宁老师于课堂上讲解的各个知识点,使我对软件工程中的开发思想、方法有了更深一步地理解。同时,通过这篇博客的书写,我对这些知识的理解更上一层楼了,更为重要的是,动手能力也有所提升,在此深表感谢。

    最后,再次强调,参考资料于此:软件工程——码农的自我修养

相关文章
相关标签/搜索