1. 程式人生 > >結對編程心得---------優秀的隊友是成功的一半

結對編程心得---------優秀的隊友是成功的一半

all urn 別人 toolbar 編程心得 HA some 可能 fault

一,結對編程的收獲

1.團隊分工

結對編程作業大部分的時間都是采取共同編寫代碼,即“一個做駕駛員,一個做領航員”,駕駛員負責敲鍵盤,領航員在一側提供建議、檢查錯誤或幫忙搜索相關的資料。

就這次團隊項目而言,我們合作還是很愉快的。清明節的後兩天我和朱池葦同學一起學習了Qt。由於朱池葦同學的工程能力比較強,所以大部分程序都是朱池葦同學作為駕駛員,而我(劉鼎乾)則作為領航員,與朱池葦同學對問題進行討論,查找資料,檢查錯誤等。

2.結對編程的意義

我覺得結對編程確實具有非常重要的意義:

  • 一個人編寫代碼,總是有種燈下黑的現象。可能你自己犯的很微小的錯誤,你花了大把大把的時間,還是搞不出來。而另一個人只需要看一下就能指出,這提高了復審效率。
  • 可以不斷從別人那裏學習,提高自己的水平。這次結對編程,我從朱池葦大佬那裏學到了很多,比如良好的代碼風格,清晰的編碼思路,以及熟練的調試技巧等
  • 通過兩個人的討論,更好的解決問題等。

3.代碼的可讀性

以前數據結構的助教說我的代碼可讀性差,這是為什麽呢,這裏附一段我以前寫過的代碼:

技術分享圖片
 1  unsigned long long  a;
 2     int b;
 3     for(int i=0;i<10000;i++)
 4     {
 5          cin >> a >> b;
 6       switch (b)
 7         {
 8         case 1:
 9             charu(a);
10             break;
11         case 0:
12             chaxun(a);
13             break;
14         default:
15             break;
16         }
17 
18     }
19 
20     cout << n2 << "/" << n1 << endl;
21     cout << m2 << "/" << m1 << endl;
22     return 0;
技術分享圖片

a是什麽,b是什麽,n1 n2又是幹什麽的呢?不僅沒有註釋,而且用的變量名也非常不好。

而這本書給了很多提高代碼規範的建議,比如:

  • 縮進,一般以4個空格
  • 行寬,不多於100個字符
  • 用括號清楚地表達優先級
  • 斷行與空白的{}行

技術分享圖片
 if (condition1)
{
      Do something;
}
 else 
{
     Do something else;
}
技術分享圖片

一般用這種方式會讓人覺得層次清晰,邏輯分明

  • 命名!想我之前寫的那段程序,最主要的問題之一就在於沒有命名。我以前覺得命名無所謂,但現在覺得,好的命名要讓人能夠見名知意,這對提高代碼可讀性是重要的,很多程序員為了一個好的名字還想半天。一般可用下劃線來構造很好地命名。

註釋,沒有註釋的代碼讓人讀起來很痛苦,而好的註釋主要是告訴別人這個程序在做什麽,為什麽這麽做,以及需要註意的東西。這樣別人讀起你的代碼才不會很痛苦。

於是乎我們就要問,為什麽我們需要好的代碼規範?為什麽我們需要別人看懂我們的代碼?

這在結對編程中,尤其重要。假如說沒有人看得懂你的代碼,結對編程也就只是紙上談兵了。

4.好隊友的重要性

這次結對編程,我從我的隊友朱池葦同學身上學到了很多。他的工程能力很強,代碼可讀性也很好,而且思路也很清晰。能經常和這樣的隊友結對編程,我突然對能否最終調試成功充滿了信心。這說明了,結對編程的隊友有多重要。

二、對接的收獲

UI主要工作量集中在設計界面,代碼量並不大,大概在300行左右(除開Qt Creator生成的代碼,自動生成的代碼在1500行左右)。但是對接的時候,各組Core的API甚至邏輯功能的差別,給我們帶來了巨大的麻煩。

首先是邏輯層面,有的組要求加減、乘除分別綁定,而有的組要求可以單獨支持任一種運算;有的組要求小數和分數不能同時存在,而有的組要求一個式子裏既有小數又有分數,這樣的情況下,同樣的UI界面不可能滿足所有Core的要求(比如QRadioButton選項互斥,而QCheckBox可以復選,不支持復選的  core用了QCheckBox,就會造成非法輸入),也許需要根據不同的core發布不同版本的UI。但這個工作量顯然太大了。

另外則是每個組的接口參數不同,需要編寫不同的接口轉換代碼,而且代碼量的高低,很大取決於API的好壞。本次所有Core中的API主要分為三個檔次:

第一檔:接口函數少,傳參合理,可以直接把UI獲取的用戶作為函數參數。這樣的接口,對接代碼量是最小的。

這是第一檔的接口代碼:

技術分享圖片
 //setting
set_setting(oNum-1,ui->oUppRange->value(),ui->precisionSpin->value(),ui->fraction->isChecked(),ui->real->isChecked(),ui->mulDiv->isChecked(),ui->power->isChecked());

// generate one question and one answer (loop this)
std::string *question = new std::string();
std::string *answer = new std::string();
generate(&question,&answer);
ui->questionBrowser->setText(QString::fromStdString(*question));
ui->answer->setText(QString::fromStdString(*answer));
技術分享圖片

第二檔:接口函數多,傳參合理。這是本次大部分組core的API所處在的檔次,這種API把setting的每一個參數分別設置為一個函數,需要單獨傳輸,但是參數設計合理,可以直接將用戶輸入作為函數參數。這樣的接口,setting的代碼量較大,有時需要做用戶輸入到core接口的轉換(例如“是否支持小數/分數”的參數是0,1,2,但UI得到的數據是選擇框是否被選中的布爾型,因此要先做邏輯判斷,再進行轉換)。

 這是第二檔所需要的接口轉換代碼(為了避免可以看出是哪一組,我對函數名作了修改):

技術分享圖片
//setting
core.setQueNum(ui->qNum->value()); core.setDataNum(ui->oNum->value()); core.setRange(ui->oUppRange->value());
core.setAccuracy(ui->precisionSpin->value());
//set operator type if(((ui->mulDiv->isChecked())&&(ui->power->isChecked()))==true) core.setOprType(3); else if(ui->mulDiv->isChecked()==true) core.setOprType(2); else core.setOprType(0);
//set operand type if(ui->fraction->isChecked()&&(!ui->real->isChecked())) core.setDataType(2); else if(ui->real->isChecked()&&(!ui->fraction->isChecked())) core.setDataType(1); else if((!ui->real->isChecked())&&(!ui->fraction->isChecked())) core.setDataType(0);

//generate all questions
question=core.getQue();
answer=core.getAns();
ui->questionBrowser->setText(QString::fromStdString(question[0]));
ui->answer->setText(QString::fromStdString(answer[0]));

//loop this (i is defined in the header file)
if(i<totalQNum)
{
ui->questionBrowser->setText(QString::fromStdString(question[i]));
ui->answer->setText(QString::fromStdString(answer[i]));
i++;
}
 

技術分享圖片

第三檔:最差的一檔,函數多,而且參數設置不合理。

某一組,曾經將所有的函數的傳入參數全部設置為了字符串!!!這意味著什麽?意味著UI組要將所有得到的整形、布爾型先進行邏輯判斷,再轉化成對應的字符串,最後再調用接口函數。而當我們為這個組的接口編寫了復雜的轉換代碼並實現了之後,這個組將API改回了直接傳參的模式。(就不貼代碼了)。

(這裏對號入座太簡單,在這裏對那一組說聲抱歉,但是我實在很想吐槽這一點)

不難想到,實際上這種輸入為字符串的方式一定也給core組增加了工作量,那麽他們為什麽會這樣做?

我可以理解這個core組的想法,可以說出發點是非常好的,他們希望自己的接口更加“易懂”,對於最終用戶,什麽東西最好懂?當然是自然語言!比如,字符串“precision”代表了“精度”,“+-*/”代表“加減乘除”,函數的功能是簡單易懂的。但是他們忽略了一點,這種考慮應當是相對於最終用戶,也就是使用這個軟件的人而言的,而不是相對UI編寫者而言的。對於UI編寫者,只需要定義清晰易懂的變量名、提供能夠理解的API文檔,就足夠了。而如何用自然語言去通俗易懂地表述輸入要求,應當是我們UI組所考慮的內容。

結對編程心得---------優秀的隊友是成功的一半