結對編程博客

 

結對編程博客

一、GitHub項目地址

Word_Chain前端

二、PSP表格

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

 

三、看教科書和其它資料中關於Information Hiding, Interface Design, Loose Coupling的章節,說明大家在結對編程中是如何利用這些方法對接口進行設計的

  • Information Hiding:ios

    信息隱藏指在設計和肯定模塊時,使得一個模塊內包含的特定信息(過程或數據),對於不須要這些信息的其餘模塊來講,是不可訪問的。git

    • 信息集中化。減小函數之間的耦合,函數間僅經過不多的的變量來協做處理數據。github

    • 隱藏變量。儘可能使用private變量,並儘可能避免其餘類須要訪問本類的數據。算法

  • Interface Design:編程

    頁面佈局的首要目的就是爲了頁面功能的秩序感,使其在頁面功能的分類以及輕重緩急的表現上更加合理,符合用戶的心智模型。後端

    • UI使用了vertical spacer,各個選項增長了中文註釋,而且有錯誤提示。數據結構

  • Loose Coupling:ide

    鬆耦合的目標是最小化依賴。鬆耦合這個概念主要用來處理可伸縮性、靈活性和容錯這些需求。

    • 減小函數之間的耦合,在不一樣模塊之間的的交互的信息儘量的少。

四、計算模塊接口的設計與實現過程

計算模塊主要有6個類,Core類DFS類Error類Input類PreProcess類RingDfs類

Input類用於從輸入中提取所須要的信息,如模式、開頭結尾、路徑等。

PreProcess類用於處理數據,包括分割單詞,並依據分割出的單詞生成圖,輸出結果等。

DFS類用於尋找圖中是否有環。

RingDfs類用於根據生成的圖進行搜索,尋找符合要求的最長路徑。

Core類用於封裝。

Error類用於異常時報錯。

Input類

方法名 做用 調用方法
Input(int num, char * paras[]) 根據程序參數,提取相應信息,如各種參數,文件路徑等 本類私有方法,Error(string str)方法
Input(string str); 根據輸入字符串提取相應信息 本類私有方法
int getMode() 返回指定的單詞鏈類型,1爲單詞數,2爲字母數  
int getIfRing() 返回是否容許環  
int getHead() 返回指定的單詞鏈開頭,0爲無限制,不然爲字母的ASCII碼值  
int getTail() 返回指定單詞鏈結尾,規則同上  
string getPath() 返回輸入的文件路徑  
string getInput() 返回輸入的完整字符串,用於調試  

PreProcess類

方法名 做用 調用方法
PreProcess(char* wordss[], int len, int r); 根據輸入的單詞表、長度、是否有環,判斷是否合法並生成圖 本地私有方法,Error(string str)方法
PreProcess(string str, int n, char* words[], int r) 根據輸入的包含全部單詞的字符串、長度、是否有環,生成單詞表與圖。單詞表char* []是爲了知足接口要求。 本地私有方法
PreProcess(string str, int r) 根據輸入的路徑與是否有環,生成單詞表與圖 本地私有方法
void printGraph() 打印合並同首尾單詞後的圖  
void printRingGraph() 答應元素  
void print(vector <string> ary) 根據輸入的容器,將其中單詞按順序輸出至solution.txt  
void VecToStr(char* result[], vector <string> ans) 將圖轉化爲單詞表格式,以知足同接口要求 Error(string str)方法

DFS類

方法名 做用 調用方法
DFS(PreProcess pp) 生成實例  
void getGraph() 獲取已生成好的圖  
bool hasRing() 判斷圖中是否有除了自環之外的環  

RingDFS類

方法名 做用 調用方法
RingDFS(PreProcess pp) 生成實例,pp中含有圖等信息  
vector <string> initDFS(int mode, int head, int tail, int ring) 根據輸入的各種參數,以及獲取到的圖,搜索符合要求的單詞鏈,並返回結果 本地私有方法,Error(string str)方法

Core類

方法名 做用 調用方法
int gen_chain_word(char* words[], int len, char* result[], char h ead, char tail, bool enable_loop) 根據輸入的單詞表、長度、參數等,搜索單詞數量最多的符合要求的單詞鏈 Input::Input
int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop) 根據輸入的單詞表、長度、參數等,搜索字母數量最多的符合要求的單詞鏈 同上

Error類

方法名 做用 調用方法
void Error(std::string str) 根據輸入的報錯信息拋出異常  

算法基於bfs的改進(改進原理見第6部分),基本原理簡單易懂。對於無環的狀況下,建圖時合併了同首尾單詞,只保留字母數量最大的單詞。

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

 

 

 

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

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

 

可見,大部分時間花在了建圖時的各類關於內存的操做上。這是由於在優化了無環的搜索算法後,將搜索部分的複雜度限制在了O(26x26),速度很快,所以關於內存的各種操做成爲了最佔用時間的操做。

對於算法的具體優化以下

對於無環的搜索,按以下方法建圖:由於無環,因此以26個字母爲節點,單詞爲邊,以a開頭b結尾的單詞,表現爲由節點a指向節點b的一條邊。

在搜索算法上,以遞歸BFS搜索爲基礎,在節點b的遞歸退出時,便可確保b日後的全部路徑均已遍歷,所以能夠獲得以b爲開頭,能搜索到的最長符合要求的單詞鏈長度,保存該長度,記爲L(b)。以後若其餘節點訪問節點b時,好比上述例子中的a節點訪問b節點,不須要再次進入b遞歸,只須要比較(L(b))與(由a指向b的邊長度)之和,與本來的L(a)的大小,並將大者保存爲新的L(a)便可。

這樣,在全部節點遞歸結束後,獲得了每一個節點日後所能達到的符合要求的單詞鏈的最大長度。根據此信息輸出最長路徑便可。

該算法確保了每條邊只走一次,不會重複走同一條邊(同一個單詞),所以,在無環的基礎上其複雜度爲O(26x26)。

可是,在有環的問題中,由於環的存在以及該方法沒法判斷L(b)中有哪些節點,所以可能會致使重複走同一條邊,該算法沒法使用。

七、看Design by Contract, Code Contract的內容 ,描述這些作法的優缺點, 說明你是如何把它們融入結對做業中的

契約式設計就是按照某種規定對一些數據等作出約定,若是超出約定,程序將再也不運行,例如要求輸入的參數必須知足某種條件。

咱們要求發現了bug以後,先對輸入進行測試,保證了輸入符合約定以後,再將相關模塊交給負責人修改。

八、計算模塊部分單元測試展現。 展現出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路

部分單元測試代碼以下:

 

這兩部分測試數據,測試的是方法Input Input(string str),方法Input Input(int num, char* paras[])。兩個方法的做用分別是根據輸入的字符串,或程序的參數提取相應的設置信息,文件路徑等。

測試的思路是構造符合被測方法輸入數據結構要求的數據,並儘可能複雜,以達到更高的分支覆蓋率。

以圖中的測試用例爲例,由於測試的是處理輸入的方法,所以在構造輸入數據時儘可能構造較爲複雜的輸入,即儘可能輸入更多的參數,以覆蓋較多的分支。

對於異常測試,測試代碼以下:

 

catch方法中經過判斷異常信息是否符合預期的方式,來判斷是否觸發了所要測試的異常。

同時,在應該觸發異常的代碼下一行加入一條永假的斷言Assert::AreEqual("Error Test Didn't Throw Error!", " ");,以確保經過的測試,是觸發了正確的異常,而不是沒有觸發異常致使沒有進入catch,根本沒有運行catch中的斷言。

九、計算模塊部分異常處理說明

全部的異常以下:

  • 輸入錯誤

    • Chain Type Parameter Error

      在已經輸入過-w-c參數,即指定過單詞鏈類型的狀況下,再次輸入這兩個參數。

      單元測試:

      try 
      {
      Input input("-w -c ..\Pair_Programming\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Chain Type Parameter Error";
      Assert::AreEqual(s, str);
      }
    • Head Duplicate Definition Error

      在已經使用-h指令規定過開頭的狀況下,再次指定開頭。

      單元測試:

      try
      {
      Input input("-w -h a -h a ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Head Duplicate Definition Error";
      Assert::AreEqual(s, str);
      }
    • Lack Space Error

      在一次性輸入全部參數時,參數之間、-h指令與制定的開頭字母之間應有空格。沒有空格時拋出次異常。

      單元測試:

      try
      {
      Input input("-w -ha ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Lack Space Error";
      Assert::AreEqual(s, str);
      }
    • Head Letter Error

      指定的開頭字符不是字母。

      單元測試:

      try
      {
      Input input("-w -h + ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Head Letter Error";
      Assert::AreEqual(s, str);
      }
    • Tail Duplicate Definition Error

      使用-t指令指定過結尾的狀況下再次使用該指令。

      單元測試:

      try
      {
      Input input("-w -t a -t a ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Tail Duplicate Definition Error";
      Assert::AreEqual(s, str);
      }
    • Tail Letter Error

      制定的結尾字符不是字母。

      單元測試:

      try
      {
      Input input("-w -t + ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Tail Letter Error";
      Assert::AreEqual(s, str);
      }
    • Ring Parameter Duplicate

      屢次使用-r參數。

      單元測試:

      try
      {
      Input input("-w -r -r ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Ring Parameter Duplicate";
      Assert::AreEqual(s, str);
      }
    • Parameter Type Error

      輸入的參數不符合規定。

      單元測試:

      try
      {
      Input input("-w -z ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Parameter Type Error";
      Assert::AreEqual(s, str);
      }
    • Lack Chain Type Parameter

      在輸入中沒有使用-w-c制定指定單詞鏈類型。

      單元測試:

      try
      {
      Input input("-h a ..\\Pair_Programming\\DFSTest2.txt");
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Lack Chain Type Parameter";
      Assert::AreEqual(s, str);
      }
  • 數據錯誤

    • Input File Doesn't Exit

      輸入的文件路徑不存在。

      單元測試:

      try
      {
      PreProcess pp ("noFile.txt", 0);
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Input File Doesn't Exit";
      Assert::AreEqual(s, str);
      }
    • Multiple Self Ring Found

      在不容許有環的狀況下,出現了多個自環。

      單元測試:

      try
      {
      PreProcess pp("..\\Pair_Programming\\PPErrorTest1.txt", 0);
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Multiple Self Ring Found";
      Assert::AreEqual(s, str);
      }

      其中,PPPErrorTest1.txt的內容以下:

      bc
      cc
      cd
      df
      ff
      beee
      eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
      eeeeeeeee
      ef
      fg
      gb

       

    • No Word Chain in File

      輸入的文件中單次數量小於2,不構成單詞鏈。

      單元測試:

      try
      {
      PreProcess pp("..\\Pair_Programming\\PPErrorTest2.txt", 0);
      }
      catch (string str)
      {
      string s = "No Word Chain in File";
      Assert::AreEqual(s, str);
      }

      其中,PPErrortEST2.TXT文件內容以下:

      bc
    • Ring Detected When not Allowed

      在沒有使用-r參數,的狀況下,單詞鏈中出現了環。

      單元測試:

      try
      {
      PreProcess pp("..\\Pair_Programming\\DFSTest1.txt", 0);
      DFS dfs(pp);
      dfs.getGraph();
      dfs.hasRing(0);
      Assert::AreEqual("Error Test Didn't Throw Error!", " ");
      }
      catch (string str)
      {
      string s = "Ring Detected When not Allowed";
      Assert::AreEqual(s, str);
      }

      其中,DFSTest1.txt文件的內容以下:

      bc
      cc
      cd
      df
      ff
      beee
      eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
      ef
      fg
      gb

十、界面模塊的詳細設計過程

開發平臺

使用的是Qt Creator 3.4.2進行開發的,因爲Qt自帶了前端設計的功能,開發起來比較簡單。

一、設計界面

使用的是Qt Creator自帶的設計面板,操做簡單隻須要拖拽便可,如下是具體設計。

 

二、編寫後端

在設計好了界面以後,只須要編寫好slots函數就可在設計面板中簡單的關聯(代碼未所有貼出)

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
   Q_OBJECT

public:
   explicit MainWindow(QWidget *parent = 0);
   ~MainWindow();

private:
   Ui::MainWindow *ui;
   bool H;
   int wc;
   bool R;
   bool T;
   QString tmp;
   bool fFile;
private slots:
   void setC(bool b);
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include "qtextbrowser.h"
#include <string>
#include <QFile>
#include <QDir>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   //ui->hideButton->hide();
}

MainWindow::~MainWindow()
{
   delete ui;
}
void MainWindow::setC(bool b){
   this->wc = b?2:1;
}

編寫完成後,須要作的就是將函數與組件關聯起來,一樣在設計面板中操做。

 

 

關於Qt的信號槽機制,具體能夠看這篇博客,因爲是在設計模板中關聯的,因此並不須要手動編寫connect函數。

十一、界面模塊與計算模塊的對接

首先,將計算模塊打包成dll文件,爲了使用方便,將統一的接口gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)與接口gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop)定義爲函數而非類方法。

打包好後,將生成的Core.dll文件複製到工程的debug文件夾或release文件夾中,經過如下代碼導入兩個上述接口:

typedef int(*ptr_word)(char* words[], int len, char* result[], char head, char tail, bool enable_loop);
typedef int(*ptr_char)(char* words[], int len, char* result[], char head, char tail, bool enable_loop);
HINSTANCE CoreDLL = LoadLibrary("Core.dll");
ptr_word gen_chain_word = (ptr_word)GetProcAddress(CoreDLL, "gen_chain_word");
ptr_char gen_chain_char = (ptr_word)GetProcAddress(CoreDLL, "gen_chain_char");

導入後,即可以直接調用兩個函數。

十二、描述結對的過程

在結對的過程當中,首先咱們在一塊兒預估各個難度的複雜度,以後對於部分邏輯極爲簡單且不重要的部分如讀入等,進行分工,並行開發提升速度。對於核心的部分,如搜索算法的完成、優化等,咱們按照結對編程的原則,一人寫一人檢查,確保沒有BUG以及算法的正確性。

 

1三、看教科書和其它參考書,網站中關於結對編程的章節, 明結對編程的優勢和缺點。結對的每個人的優勢和缺點在哪裏

  • 優勢:在複審中對於能以找到的bug,結對編程可以避免鑽牛角尖,增長debug的速度。在編寫代碼過程當中,結對編程有助於促進兩方思考,避免遺漏,增長正確性。也能相互監督保證代碼質量。

  • 缺點:對於一些比較簡單的代碼,結對編程會拖累雙方的進度,影響項目進程。對於兩我的都不擅長的領域,就沒有結對的必要。

個人優缺點:

  • 積極交流,認真負責,複審仔細

  • 比較拖沓

同伴的優缺點:

  • 主動負責,思路敏捷,完成工做多

  • 缺少交流

1四、PSP表格

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

1五、鬆耦合

咱們與學號1606109三、16061155的隊伍進行了鬆耦合測試,結果正確,對方使用我方Core.dll的運行結果截圖以下:

在剛開始耦合時出現了問題,由於在對於head的定義中,咱們組的邏輯是當head不爲0即認爲是規定的開頭字母,但接口內部沒有檢查其正確性,而對方認爲head不規定時爲'0' 出現問題後,咱們組在接口內部加2上了對於參數的合法性判斷,以後沒有其餘問題。

以後咱們還與1606116七、16061170組進行了耦合,運行正確,沒有問題。

相關文章
相關標籤/搜索