代碼中的軟件工程


本文在中科大軟件學院孟寧老師的指導下完成,意在通過對小型程序的分析來幫助體會軟件工程方法、思想。

本文的參考資料及資源來自:軟件工程——碼農的自我修養

 1. VS Code開發環境配置

1.1 VS Code 安裝

    有關VS Code的安裝配置可以參考該資料:https://mp.weixin.qq.com/s/sU9Wh12JZqQyJfEBBafFAQ

    在本文中,我們對此進行簡單介紹。我們可以在VS Code官網下載,它是一款免費的輕量級IDE,通過擴展插件可以支持多種語言。

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

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. 總結

    孟寧老師於課堂上講解的各個知識點,使我對軟件工程中的開發思想、方法有了更深一步地理解。同時,經過這篇博客的書寫,我對這些知識的理解更上一層樓了,更為重要的是,動手能力也有所提高,在此深表感謝。

    最后,再次強調,參考資料於此:軟件工程——碼農的自我修養

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM