天天看點

BUAA 2020 軟體工程 結對項目作業

Author: 17373051 郭駿

3.28添加:4.計算子產品接口的設計與實作過程部分,PairCore實作的細節

項目 内容
這個作業屬于哪個課程 2020春季計算機學院軟體工程(羅傑 任健)
這個作業的要求在哪裡 結對項目作業
我在這個課程的目标是 學習軟體工程的開發知識,培養工程化開發能力
這個作業在哪個具體方面幫助我實作目标 通過實操掌握結對開發基礎

目錄

  • 1.前言
  • 2.PSP表格
  • 3.接口設計思想
  • 4.計算子產品接口的設計與實作過程
  • 5.UML圖
  • 6.性能改進
  • 7.契約式設計
  • 8.單元測試展示
  • 9.異常處理說明
  • 10.界面子產品設計
  • 11.子產品對接
  • 12.結對過程
  • 13.結對程式設計
  • 14.附加題:支援松耦合
  • 後記:一點體會

  • 教學班級:005
  • 項目位址:https://github.com/abTaoTao/Pair_project_git
給定 N 個幾何圖形,詢問平面中有多少個點在至少 2 個給定的圖形上。

在此處先展示Code Quality Analysis的零警告圖檔。

BUAA 2020 軟體工程 結對項目作業

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 5
· Estimate · 估計這個任務需要多少時間
Development 開發 390 570
· Analysis · 需求分析 (包括學習新技術) 60
· Design Spec · 生成設計文檔 20
· Design Review · 設計複審 (和同僚稽核設計文檔)
· Coding Standard · 代碼規範 (為目前的開發制定合适的規範)
· Design · 具體設計 120
· Coding · 具體編碼
· Code Review · 代碼複審
· Test · 測試(自我測試,修改代碼,送出修改) 180
Reporting 報告 70 100
· Test Report · 測試報告 30
· Size Measurement · 計算工作量 10
· Postmortem & Process Improvement Plan · 事後總結, 并提出過程改進計劃
合計 465 675

  • 資訊隐藏

    這條原則指導我們,應當将類的屬性私有化,通過通路函數來實作,并且使用接口來連接配接層與層。我們在設計的過程中,做到了将類的屬性全部私有化。接口的實作方面,我們使用類的部分公有函數作為接口,做到了類與類之間的互動。

  • 接口設計

    我們在設計過程中,通過Point—Line/Circle—Core三層類的結構環環相扣,每兩層之間使用有限的公有函數進行互動。Line和Circle有互相使用對方求交點的方法,能夠輕松的調用交點求解程式,Line也包含了線段、射線和直線,在外層寫程式時不用關心到底是哪兩種圖形在求交點。

  • 松耦合

    類與類、層與層之間有着較好的隔離,如果出現問題或者需要增加需求,隻需要修改一個類中的代碼,而不需要去修改其調用的其他類。如Line和Circle,雖然需要互相求交點,但是修改其中一個類的代碼,可以無需改動另外一個類,因為接口是完善的,類之間的耦合度也是低的。

在C++中,我們并沒有使用抽象類的特性來幫助我們建構接口,因為抽象類在作為函數參數時的支援并不夠友善。在此提到的“接口”,指的是每個類的公有方法。

我們的程式由Point類打底,代表解題過程中的點,可以是線段/射線的端點,也可以是圖形之間的交點。我們為其預設了比較函數和指派方法,作為程式的基礎。

然後是Line類和Circle類。Line類包含線段、射線和直線,作為基礎題部分的解題骨幹。Line類的核心方法是

Line::getIntersect(Line l)

,可以幫助我們輕松求出兩條線之間的交點。Circle類是圓類,用于附加題。該類有對直線和圓求交點的方法。

主類為PairCore。這個類中包含了指令行參數分析函數,輸入正則比對函數,以及求交點輸出到檔案的函數。有

PairCore::parser(int argc, char* argv[])

方法,用于處理指令行參數的輸入,解析方式是簡單的字元串相等的條件判斷。

PairCore::text_handle()

方法是用于從檔案中讀入資料,按行讀入,第一行是數字,之後的每一行采用正規表達式的方式進行讀取,如果格式與正規表達式不比對則傳回報錯。同時我們也需要對輸入範圍進行特判。

PairCore::getIntersectionCount()

是用于計算幾何圖形交點的函數,其中包含三個循環,分别用于計算線與線、線與圓、圓與圓的交點。

本次作業中的核心函數,也是和上次作業很不一樣的地方,就是判斷求出來的點是否是兩個圖形的交點。由于線段、射線的範圍有限制,是以我們需要判斷點是否線上上。我們有函數

Line::isOnline(Point p)

來判斷點是否線上上。判斷的方法是與線的兩個端點進行比較。

同時,我們需要判斷輸入的線是否重合,即便在同一條直線上,也有可能是沒有交點或者有一個交點。我們有函數

Line::relation(Line l)

來判斷兩條線的關系。如果兩條線在同一直線上,則我們會對兩條線的端點坐标進行判斷,進而能夠判斷出他們真實的交點個數。

算法的獨到之處在于,早早為Point類寫好了比較函數,将此後的許多位置關系判斷轉化為端點坐标的位置判斷,簡化了問題。

UML類圖如下所示。

BUAA 2020 軟體工程 結對項目作業

我們使用VS的性能分析器對2000條線、500個圓的情況進行了分析,得到的圖如下所示:

BUAA 2020 軟體工程 結對項目作業

可以看到,在

Line::getIntersect

這個方法上耗費的CPU達到32%,讓我們感到不可思議。我們進入代碼之後,檢視了語句的CPU使用率。

BUAA 2020 軟體工程 結對項目作業
BUAA 2020 軟體工程 結對項目作業

可以看到,語句大部分時間花在了對vector的建立、修改和傳回上。由于兩條線之間的交點隻能是1個或者0個,是以我們可以不用vector<Point>作為傳回值,而是用Point作為傳回值,并判斷該Point是否存在。修改之後的占比如圖所示。

BUAA 2020 軟體工程 結對項目作業

我們在優化上大概耗費了20分鐘。

契約式設計要求設計者對軟體設計正式、準确、可驗證的接口規範,定義了先驗條件、後驗條件和不變式,這些規範稱為“契約”。

這種方法的優點:

  • 通過規範化的注釋,能夠直接驗證程式正确性。
  • 設計時着重功能而非具體實作,不用擔心具體的實作流程。
  • 明确接口的功能之後,設計者和開發者都能夠得到足夠的資訊。

這種方法的缺點:

  • 程式的正确性驗證有時代價會非常大,甚至可能無法檢錯。
  • 正确而規範的設計十分困難,會出現滿足設計而不滿足功能的情況。
  • 存在一些難以或無法用契約設計的功能。

在結對作業中,這種思想确實可以讓我們寫出正确性較為完備的程式,但是卻難以幫助我們對程式進行優化。同時,在從設計到實作的過程中,我們常常需要絞盡腦汁,甚至不得已去修改設計。因而,在結對的過程中,我們沒有過分依賴契約式設計,隻是做到了一般的設計—開發的流程。

部分單元測試代碼展示:

BUAA 2020 軟體工程 結對項目作業

單元測試通過截圖:

BUAA 2020 軟體工程 結對項目作業

單元測試覆寫率截圖:

BUAA 2020 軟體工程 結對項目作業

我們構造測試資料的思路是:從一般到特殊,從簡單到複雜,從白箱到黑箱。

我們的測試代碼有題目的樣例代碼、最簡單情況的代碼、特殊情況(重合、平行、端點相交、射線相背等)的樣例設計,以及一些能夠觸發異常的樣例。此外,我們還使用随機資料生成器生成了一點随機且複雜的情況加入測試,用于檢測我們的考慮是否完備。

我們設計了13種異常,每種異常都有其對應的錯誤碼。錯誤碼和異常的對應關系在程式中有所展現,代碼如下:

錯誤代碼 錯誤資訊 測試樣例
-1 線段之間存在重合

2

S 0 0 2 2

S 1 1 3 3

-2 線段和射線之間存在重合 R 1 1 3 3
-3 射線之間存在重合
-4 直線與某條線重合

L 0 0 2 2

S -1 -1 -2 -2

-5 圓與圓重合 C 0 0 2
-6 輸入的兩個交點重複

1

L 1 1 1 1

-7 坐标超出(-100000,100000)的範圍 L 100000 1 1 1
-8 輸入圓的半徑不大于0 C 0 0 -2
-9 分析圖形資訊時出錯 asdfg
-10 分析圖形個數時出錯 L 1 1 2 2
-11 幾何圖形個數與輸入的數目不比對
-12 多餘的不在末尾的換行符

L 2 2 3 3

L 0 5 5 0

-13 指令行參數錯誤 intersect.exe -p point.txt

如果在指令行模式下發生異常,則程式會将錯誤資訊輸出到同目錄下的error.txt中。

界面子產品采用C#的Winform來開發。由于這是我們第一次使用C#,也是第一次開發GUI程式,在設計上難免會存在一些不足。

界面設計如圖所示,我們的界面子產品有兩個視窗。

BUAA 2020 軟體工程 結對項目作業

第一個視窗(Form1)是輸入輸出圖形資訊的視窗。如果GUI使用不當,會有相應的錯誤提示。右邊的清單是現有的圖形資訊,可以通過滑鼠點選來進行删除。

從檔案導入之後不會直接開始繪制,而是将檔案中的點資訊加入到現有的點清單中,提供了相對高的靈活性和可操作性。

我們确實支援圖形的繪制,也支援圖形的添加和删除,但是這兩個過程在我們的界面中是分離的,即沒有做到像GeoGebra一樣能夠實時繪制圖形和交點。

BUAA 2020 軟體工程 結對項目作業

第二個視窗(Form2)是我們的繪制結果視窗。該視窗使用Winform的Panel進行繪制,整個繪制過程為造輪子過程,即沒有成熟的坐标系子產品供我們使用,是以效果相對簡陋,且不支援縮放和平移。不過由于結對程式設計隻有短短的兩周,且中間經曆了很多别的作業,是以沒有在此處過于苛求。程式預設将所有的圖形都畫進視窗中,是以如果圖形的橫縱軸跨度較大,則觀感會欠佳。

輪子中的關鍵代碼是如何掌握好視窗的邊界位置。我們相當于要将所有圖形的坐标範圍(minx,miny)-(maxx,maxy)映射到我們的畫闆(0,0)-(720,720)上。映射過程的核心代碼如下:

float k, dx, dy;
if (maxx - minx < 1 && maxy - miny < 1)
{
    k = 1;
    dx = minx;
    dy = miny;
}
else
{
    if ((maxx - minx) > (maxy - miny))
    {
        k = maxx - minx;
        dx = minx;
        dy = miny - (maxx - maxy - minx + miny) / 2;
    }
    else
    {
        k = maxy - miny;
        dx = minx - (-maxx + maxy + minx - miny) / 2;
        dy = miny;
    }
}
           

這裡的k是縮放比例,dx和dy是x軸和y軸的平移距離。對于每個點的坐标,我們隻需要進行如下變換:

x = (x0 - dx) * 720 / k, y = (y0 - dy) * 720 / k

即可。

dll為前端留下了兩個接口,分别用于GUI展示和指令行測試。

/*GUI展示
dll從同目錄下的lines.pair按格式讀入幾何圖形的資訊,
求解後将得到的點的坐标存入同目錄下的points.pair檔案。
函數的傳回值>=0,代表交點個數。<0則代表出現異常,傳回異常代碼。
*/
int solve();
/*指令行展示
dll從同目錄下的commands.pair按格式讀入指令行參數,按要求處理。
函數的傳回值>=0,代表交點個數。<0則代表出現異常,傳回異常代碼,不寫檔案。
報錯部分的代碼由前端完成,将錯誤資訊存在同目錄下error.txt中。
*/
int command();
           

可以看到這兩個接口的互動幾乎全部依賴于檔案和傳回值,沒有進行參數傳遞。

主要的原因在于,C#和C++的标準有諸多不同,比如C#不支援指針,char為兩個位元組長度,string類和C++的string類不能公用等。我們嘗試無論怎麼傳參數,都無法達到我們想要的效果,隻能傳一些簡單的數字。是以我們幹脆制定了檔案讀入的标準。

如果我們使用C++的GUI開發,可能不會出現這樣的問題,這是我們需要反思的一點。

結對過程主要通過QQ語音+Live Share的方式完成。由于網絡原因,常常出現Live Share斷線的情況,極大的影響了我們的工作效率。不過在我們的不懈努力之下,最終還是完成了本次作業。證據如下所示:

BUAA 2020 軟體工程 結對項目作業

  • 優點
    • 程式設計過程互相監督,不會存在摸魚的情況,随時思考随時交流,思維更加集中
    • 兩人共審同一份代碼,對代碼的品質和正确性都有更高的保證。
    • 兩人一起工作,集思廣益,對于困難的問題可能會更快産出解答。
  • 缺點
    • 度過磨合期很困難,要互相習慣對方的程式設計速度、思維、風格。
    • 對于“駕駛員”來說,寫代碼的“領航員”過度插手可能會帶來反效果。
結對人員 隊友
思維較快,思考更迅速連貫 思考全面,單元測試完善
難以習慣隊友的代碼風格、程式設計習慣等,磨合期較難受 節奏難以同步

我們選擇交換dll的團隊是(17373052, 17373053)團隊。

他們的dll設計與我們大緻相同,除了檔案的命名方式以外,其他大緻相同。

合并時遇到的問題有:

  • 他們并非由GUI和command兩個函數構成,而是隻有一個函數

    run()

    ,由指令行參數進行區分。無論是否需要繪制,都會将點的資訊存在points.txt中。我們修改了我們的讀寫方式,以适配他們的核心子產品。
  • 他們的異常處理傳回資訊和我們不一樣。他們的

    run()

    函數隻定義了兩種異常:輸入異常和重合異常。我們為此修改了異常的傳回資訊。

經測試,指令行和GUI都可以正常使用。

BUAA 2020 軟體工程 結對項目作業

BUAA 2020 軟體工程 結對項目作業