【軟件工程】結對編程總結

內容說明

項目 內容
這個做業屬於哪一個課程 羅傑
這個做業的要求在哪裏 結對編程-最長單詞鏈

1.Github地址

Githubgit

2.PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30
· Estimate · 估計這個任務須要多少時間 30
Development 開發 890
· Analysis · 需求分析 (包括學習新技術) 100
· Design Spec · 生成設計文檔 60
· Design Review · 設計複審 (和同事審覈設計文檔) 40
· Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 30
· Design · 具體設計 140
· Coding · 具體編碼 300
· Code Review · 代碼複審 80
· Test · 測試(自我測試,修改代碼,提交修改) 140
Reporting 報告 90
· Test Report · 測試報告 30
· Size Measurement · 計算工做量 30
· Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 30
合計 1010

3.Information Hiding, Interface Design, Loose Coupling

In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).github

Written another way, information hiding is the ability to prevent certain aspects of a class or software component from being accessible to its clients, using either programming language features (like private variables) or an explicit exporting policy.算法

—— wiki編程

信息隱藏是使用編程語言功能(如私有變量)或顯式導出策略來阻止其客戶端訪問類或軟件組件的某些方面的能力。在咱們的結對編程中,咱們將最終的接口設計爲兩個函數,而將具體的實現細節封裝在獨立的模塊中,外界不知道內部的運行細節,較好的實現了信息隱藏。編程語言

接口設計:按照題中的要求進行設計,沒有自行設計的接口。函數

鬆耦合:在此次開發中咱們將計算模塊的實現用Core.dll進行封裝。工具

4.計算模塊接口的設計與實現過程

在這裏咱們首先設計了一個Solver類用於實現對最長單詞鏈的計算,Node類實現存儲計算中所須要的各個單詞的節點數據。oop

算法的大體思路:考慮這是一個特殊的有向無環圖的最長路徑問題(無環狀況下),咱們能夠將全部首先將全部的單詞拓撲排序,按排序後的順序可使用動態規劃的算法實現尋找出最長的路徑。而對於有環的狀況,咱們使用了DFS搜索算法查找出最長路徑。性能

獨到之處:無環狀況下,按單詞首字母將單詞分爲26類,可能減小了單詞數量較多時的排序時間。單元測試

5.畫出UML圖顯示計算模塊部分各個實體之間的關係

6.計算模塊接口部分的性能改進

記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展現一張性能分析圖(由VS 2015/2017的性能分析工具自動生成),並展現你程序中消耗最大的函數

如下爲無環,單詞數量爲10000的運行狀況

從圖中能夠看出佔用時間最長的是計算出文本中的最長單詞鏈的函數,在這裏咱們考慮使用動態規劃算法來減小計算模塊所花的時間。

如下爲有環,單詞數量爲74的運行狀況

而對於有環的狀況,咱們這裏就實現了一個基礎的DFS算法,並採起了必定的剪枝策略,好比記錄已經遍歷過的點它的最長路徑,而後當遍歷到這個點的時候,判斷一下當前長度+當前點的最長路徑長度,若是小於當前發現的最長路徑長度,那就不須要繼續遍歷下去了,由於當前節點所能到達的最長路徑仍然小於當前最長路徑。用這些剪枝策略,減小了一些遞歸遍歷,必定程度上優化了算法。

7.Design by Contract, Code Contract

契約式設計具備以下的優缺點

  • 優勢:可以得到更優秀的設計,組件服務的提供方和使用方各自的義務被表述的更清晰,從而使設計更加系統化、更清楚、更簡單;契約能夠提升可靠性,能夠幫助開發者更好地理解代碼並有助於測試;契約式設計能夠簡化調試工做,便於將錯誤定位出來。
  • 缺點:設計具備良好契約的程序須要至關的開銷:撰寫契約須要時間,開發者須要時間學習撰寫良好契約的思想和技術,何況,並非每一個軟件都須要那麼高的質量。

在咱們的項目中,咱們在gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)中對傳入的參數進行了簡單的檢查,若不符合約定則經過assert跳出。完成測試後,咱們出於性能的考慮,刪除了assert語句,使用以下代碼進行檢查是否符合約定。

if (len <= 0)
    {
        throw IllegalInterfaceParaException();
    }
    if (head != 0 && !(head >= 'a' && head <= 'z') && !(head >= 'A' && head <= 'Z'))
    {
        throw IllegalInterfaceParaException();
    }
    if (tail != 0 && !(tail >= 'a' && tail <= 'z') && !(tail >= 'A' && tail <= 'Z'))
    {
        throw IllegalInterfaceParaException();
    }

8.計算模塊部分單元測試展現

在測試計算模塊的以前,咱們首先測試了一下命令行參數處理模塊是否正確:

TEST_METHOD(TestMethod1)
        {
            // TODO: 在此輸入測試代碼
            argc = 3;
            argv[1] = "-c";
            argv[2] = "input.txt";
            tag = -1;
            headCh = '\0';
            endCh = '\0';
            isRing = false;
            filename = std::string();
            getopt(argc, argv, tag, headCh, endCh, isRing, filename);

            Assert::AreEqual(1, tag);
            Assert::AreEqual(headCh, '\0');
            Assert::AreEqual(endCh, '\0');
            Assert::IsFalse(isRing);
            Assert::AreEqual(0, filename.compare("input.txt"));
        }

        TEST_METHOD(TestMethod2)
        {
            // TODO: 在此輸入測試代碼
            argc = 3;
            argv[1] = "-w";
            argv[2] = "input.txt";
            tag = -1;
            headCh = '\0';
            endCh = '\0';
            isRing = false;
            filename = std::string();
            getopt(argc, argv, tag, headCh, endCh, isRing, filename);

            Assert::AreEqual(0, tag);
            Assert::AreEqual(headCh, '\0');
            Assert::AreEqual(endCh, '\0');
            Assert::IsFalse(isRing);
            Assert::AreEqual(0, filename.compare("input.txt"));
        }

相似的TEST_METHOD咱們寫了6個,用以測試各項參數讀入處理後,tag、headCh、endCh、isRing和filename是否正確。

而後,咱們又對計算模塊的單詞個數最多字符串單詞長度最長字符串這兩個方法進行了單元測試:

  • 單詞個數最多字符串int gen_chain_word();
TEST_METHOD(TestMethod1)
        {
            // TODO: 在此輸入測試代碼
            int wordIndex = 0;
            char **result;
            char headCh = '\0';
            char endCh = '\0';
            bool isRing = false;
            char *wordlist[100];

            wordlist[0] = new char[20]{ "annzcclv" };
            wordlist[1] = new char[20]{ "klebwukqbui" };
            wordlist[2] = new char[20]{ "qhqkibinpyew" };
            wordlist[3] = new char[20]{ "fkapwouje" };
            wordlist[4] = new char[20]{ "mitecsqa" };
            wordlist[5] = new char[20]{ "mogowquzdsmto" };
            wordlist[6] = new char[20]{ "oxkyhmgemdfpq" };
            wordlist[7] = new char[20]{ "hzvreibfb" };
            wordlist[8] = new char[20]{ "phgxdlmyrw" };
            wordlist[9] = new char[20]{ "kuckfwlghglua" };
            wordlist[10] = new char[20]{ "ucqavnwkqseyy" };
            wordlist[11] = new char[20]{ "quhxkzqxf" };
            wordlist[12] = new char[20]{ "iwoegjfbxhu" };
            
            wordIndex = 13;
            result = new char*[wordIndex];

            int ans = gen_chain_word(wordlist, wordIndex, result, headCh, endCh, isRing);
            
            Assert::AreEqual(4, ans);
            Assert::IsFalse(std::strcmp(result[0], "mogowquzdsmto"));
            Assert::IsFalse(std::strcmp(result[1], "oxkyhmgemdfpq"));
            Assert::IsFalse(std::strcmp(result[2], "quhxkzqxf"));
            Assert::IsFalse(std::strcmp(result[3], "fkapwouje"));
        }
        
TEST_METHOD(TestMethod3)
        {
            // TODO: 在此輸入測試代碼
            int wordIndex = 0;
            char **result;
            char headCh = '\0';
            char endCh = '\0';
            bool isRing = false;
            char *wordlist[100];

            wordlist[0] = new char[20]{ "annzcclv" };
            wordlist[1] = new char[20]{ "klebwukqbui" };
            wordlist[2] = new char[20]{ "qhqkibinpyew" };
            wordlist[3] = new char[20]{ "fkapwouje" };
            wordlist[4] = new char[20]{ "mitecsqa" };
            wordlist[5] = new char[20]{ "mogowquzdsmto" };
            wordlist[6] = new char[20]{ "oxkyhmgemdfpq" };
            wordlist[7] = new char[20]{ "hzvreibfb" };
            wordlist[8] = new char[20]{ "phgxdlmyrw" };
            wordlist[9] = new char[20]{ "kuckfwlghglua" };
            wordlist[10] = new char[20]{ "ucqavnwkqseyy" };
            wordlist[11] = new char[20]{ "quhxkzqxf" };
            wordlist[12] = new char[20]{ "iwoegjfbxhu" };

            wordIndex = 13;
            result = new char*[wordIndex];
            headCh = 'k';

            int ans = gen_chain_word(wordlist, wordIndex, result, headCh, endCh, isRing);

            Assert::AreEqual(3, ans);
            Assert::IsFalse(std::strcmp(result[0], "klebwukqbui"));
            Assert::IsFalse(std::strcmp(result[1], "iwoegjfbxhu"));
            Assert::IsFalse(std::strcmp(result[2], "ucqavnwkqseyy"));
        }
  • 單詞長度最長字符串int gen_chain_char();
TEST_METHOD(TestMethod2)
        {
            // TODO: 在此輸入測試代碼
            int wordIndex = 0;
            char **result;
            char headCh = '\0';
            char endCh = '\0';
            bool isRing = false;
            char *wordlist[100];

            wordlist[0] = new char[20]{ "annzcclv" };
            wordlist[1] = new char[20]{ "klebwukqbui" };
            wordlist[2] = new char[20]{ "qhqkibinpyew" };
            wordlist[3] = new char[20]{ "fkapwouje" };
            wordlist[4] = new char[20]{ "mitecsqa" };
            wordlist[5] = new char[20]{ "mogowquzdsmto" };
            wordlist[6] = new char[20]{ "oxkyhmgemdfpq" };
            wordlist[7] = new char[20]{ "hzvreibfb" };
            wordlist[8] = new char[20]{ "phgxdlmyrw" };
            wordlist[9] = new char[20]{ "kuckfwlghglua" };
            wordlist[10] = new char[20]{ "ucqavnwkqseyy" };
            wordlist[11] = new char[20]{ "quhxkzqxf" };
            wordlist[12] = new char[20]{ "iwoegjfbxhu" };

            wordIndex = 13;
            result = new char*[wordIndex];

            int ans = gen_chain_char(wordlist, wordIndex, result, headCh, endCh, isRing);

            Assert::AreEqual(4, ans);
            Assert::IsFalse(std::strcmp(result[0], "mogowquzdsmto"));
            Assert::IsFalse(std::strcmp(result[1], "oxkyhmgemdfpq"));
            Assert::IsFalse(std::strcmp(result[2], "quhxkzqxf"));
            Assert::IsFalse(std::strcmp(result[3], "fkapwouje"));
        }
TEST_METHOD(TestMethod9)
        {
            // TODO: 在此輸入測試代碼
            int wordIndex = 0;
            char **result;
            char headCh = '\0';
            char endCh = '\0';
            bool isRing = false;
            char *wordlist[100];

            wordlist[0] = new char[20]{ "rlqokvxuq" };
            wordlist[1] = new char[20]{ "vvitmqskdyeap" };
            wordlist[2] = new char[20]{ "llkgasgiuzlgx" };
            wordlist[3] = new char[20]{ "cxadwktc" };
            wordlist[4] = new char[20]{ "yinrlisikdjq" };
            wordlist[5] = new char[20]{ "cbrcxzoyigcv" };
            wordlist[6] = new char[20]{ "roeuzja" };
            wordlist[7] = new char[20]{ "pwwbogbwp" };
            wordlist[8] = new char[20]{ "rjztssi" };
            wordlist[9] = new char[20]{ "vypbjouumrc" };
            wordlist[10] = new char[20]{ "vgorbjxqpap" };
            wordlist[11] = new char[20]{ "vrczrlwavkfq" };

            wordIndex = 12;
            result = new char*[wordIndex];
            isRing = true;

            int ans = gen_chain_char(wordlist, wordIndex, result, headCh, endCh, isRing);

            Assert::AreEqual(5, ans);
            Assert::IsFalse(std::strcmp(result[0], "vypbjouumrc"));
            Assert::IsFalse(std::strcmp(result[1], "cxadwktc"));
            Assert::IsFalse(std::strcmp(result[2], "cbrcxzoyigcv"));
            Assert::IsFalse(std::strcmp(result[3], "vvitmqskdyeap"));
            Assert::IsFalse(std::strcmp(result[4], "pwwbogbwp"));
        }

與測試命令行參數處理模塊相似,咱們對gen_chain_wordgen_chain_char進行了headCh、endCh和isRing這幾個參數的各類狀況的測試,充分考慮了各個分支,達到了比較好的測試效果。最終咱們的整體覆蓋率以下:

9.計算模塊部分異常處理

WordRingsException:當默認狀況下輸入出現單詞環時拋出

IllegalInterfaceParaException:當調用接口時傳入不合理的參數時(如len <= 0,head或tail既不爲'\0'也不是字母時)

IllegalParametersException:命令行參數出現錯誤時

FileNotExitException:輸入的文本不存在時

10.命令行模塊的詳細設計過程

命令行處理咱們採用最簡樸的字符串比較方法,依次對參數進行分析:

對於整體咱們處理了不含有「-w」「-c」的異常(由於此時咱們不知道該如何選擇最長字符串),同時在每個分支中,咱們也都進行了異常處理,如既有「-w」又有「-c」的,或是「-h」「-t」後面沒有字母或是否是字母字符等等狀況。

命令行處理模塊將從控制檯讀入的信息處理好後,將信息儲存在tag,headCh,endCh,isRing和filename中,供getFileInput()方法調用。

11.命令行模塊與計算模塊的對接

命令行模塊引入了定義接口的頭文件,直接能夠經過調用定義的兩個接口實現計算最長單詞鏈的過程。

12.描述結對的過程

總的來講本次結對編程的體驗很不錯,開始很順利,過程當中雖然遇到了或大或小的麻煩,但咱們共同克服,最後寫出的項目質量也還不錯。

剛開始的時候,咱們還不是很適應「駕駛員」、「領航員」的模式,基本就是商量着寫代碼,但效率也還不錯,設計的時候兩我的相互補充,也避免了未考慮到某些方面的狀況發生。很快咱們就將「有向無環圖」的狀況完成,並進行了測試,性能還不錯。不過以後的「有向有環圖」的設計就陷入了僵局,咱們除了暴力深度搜索想不出什麼比較好的方式(事實是咱們最後也仍是暴力搜索),一度兩人都在摸魚。不事後來,咱們決定先將其完成,而後再進行剪枝來優化(畢竟測試數據集也不是很大),很快也將「有向有環圖」的狀況完成。最後的單元測試和錯誤處理模塊,咱們也很順利地完成。

整體來講此次結對編程讓咱們體驗到了這種新的編程模式,可以和隊友在交流碰撞,產生新的想法和點子,互相糾正、互相補充,這種經歷十分難得,於我我的而言也是一次很大的提高。不過,這都是創建在我和個人隊友是平日關係密切、很熟悉的前提下,若是在公司中採起這種方式,我就不是很確定效率會如何了。

最後,奉上結對編程留念圖:

13.說明結對編程的優勢和缺點。結對的每個人的優勢和缺點在哪裏

  1. 結對編程的優勢和缺點
    • 優勢:可以在結對編程的過程當中使得代碼都至少被兩我的檢查過,能夠提升程序的質量,同時兩我的更容易想出好的點子。
    • 缺點:在編程效率上可能會比兩我的各自完成本身的部分要低一些。
  2. 結對的每個人的優勢和缺點
成員 優勢 缺點
蔣鋒 思考問題比較奇葩,能發現一些可能比較好的點子;肯花時間進行項目;善於學習別人的優勢 喜歡給項目寫入新的BUG
張哲維 有獨立思想,適合擔任領導者;動手能力強,coding神速;考慮問題比較全面 不能及時發現蔣鋒寫入的BUG

14.PSP表格回填

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 20
· Estimate · 估計這個任務須要多少時間 30 20
Development 開發 890 890
· Analysis · 需求分析 (包括學習新技術) 100 120
· Design Spec · 生成設計文檔 60 30
· Design Review · 設計複審 (和同事審覈設計文檔) 40 20
· Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 30 40
· Design · 具體設計 140 120
· Coding · 具體編碼 300 360
· Code Review · 代碼複審 80 50
· Test · 測試(自我測試,修改代碼,提交修改) 140 150
Reporting 報告 90 100
· Test Report · 測試報告 30 10
· Size Measurement · 計算工做量 30 20
· Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 30 40
合計 1010 1010
相關文章
相關標籤/搜索