结对编程收获
結對編程收獲
——我和我的伙伴分到了Core組,他負責生成編寫四則運算表達式函數,而我負責編寫計算函數以及整體框架和接口
這一次結對編程不僅學到了不少編程技術,更在交流合作中發現了自己以往的問題,因為我一直以來是一個偏愛獨來獨往的人,寧愿在合作中多干活,也不愿意別人對我的構想指手畫腳,不過這一次是無法避免的了。
編程收獲:
?
1、實戰經驗:
這是一次難得的C++實戰經驗,或者說是一次面向對象語言的實踐,C++更抽象一層的數據類型及其方法將我從以往繁重的體力活(用C語言編寫)中解救出來,我也充分地利用了它不同于C的特性,將整個小項目的結構都編寫得比較優美(至少是學習計算機語言以來)。(最后附上核心內部接口與外部接口)
2、開發流程:
結隊編程的效率=成員單獨的效率-交流所帶來的損耗,因此成員之間任務的耦合性越大,帶來的損耗也越大,所以在合作的過程中,我有如下想法:
1)前期:最好采用和-分-和的討論方法。
(1)和:成員需要全部參與到代碼整體脈絡的討論當中,然后盡量地以減小任務耦合度為原則分配任務。
(2)分:當兩者(或者幾個人)任務存在可能的交叉時,成員需要單獨地進行交流,對設計的版塊進行細致討論。(這一階段非常重要,只有細致地討論、設計才有助于盡早地發現BUG,這對開發周期有百利而難有一害)
(3)和:然而兩者(或者幾個人)交流完畢后,不能急匆匆地開始開發,需要重新召開組會,交流各個版塊的設計思想,并至少需要一個統領全局的人明確整體的脈絡,發現中間可能存在的沖突、重疊,然后提供改進的建議。
2)開發:有幾個需要注意的問題
(1)如果數據結構存在重疊,即后者可能用到前者的數據結構時,那么他們的耦合度可以判定為高,需要共同設計代碼、編寫代碼,并且開發時只有一人編寫,而另一人需要實時觀察、跟進。而兩者(或者幾個人)任務只是接口級別的,則可判定為低,需要事先約定好接口的類型,然后分別開發自己的模塊,最后組建為一個類。
(2)測試代碼要跟進上每一個函數,尤其是項目越大這一點越是關鍵,雖然有一些函數因為參數表的問題難以編寫測試類,然而并不能省略,因為之后的查錯可能會把人逼瘋。
3)歸并:需要在線(最好是面對面)的交流
在各個同學便寫完代碼需要歸并在一起的時候,可以按照樹的結構逐步上提,當然每一個節點都是一個更高層次的功能來確定的。這時候需要進行面對面的聯合測試,因為這樣在對接的時候能充分化解歧義,并且前后調用函數的編寫人可以互相交流容易忽視的點,可能出現的異常。
3、開發周期:
這次我充分吸收了上次個人編程時受到的教訓,以逐次迭代的思想,我每開發一個新的模塊時都列寫出可能用到的最基本的函數,獨立地進行編寫、測試。事實上這樣的經歷是輕松+愉快的,在后期的調試中,至少沒有在算法邏輯上遇到明顯的問題。(當然C++這點沒有Java做得好,Java的@Test注解對函數的測試是更加輕松的,也可能我學的C++太淺顯了,畢竟從Java到C++的過渡只用了6個小時)
4、開發感想:
讀了其他同學的收獲,我感覺我上文所述的方案有些許遺憾,因為我太在意去除耦合性,讓每個人去做獨立的工作,卻忽略了兩個人一起編程(人數更多可能就不管用了)所帶來的其他效益(這里的一起是指同時做一件事情)。因為兩個人獨立思考一種算法的時候能夠發現更多的漏洞,這里我也有提到,也就是最初第一和第三步的公共討論部分;另外互相監督能促使隊友更高效地工作,而不是時不時就去看一眼其他無關的內容;最后還能減少debug的時間,領航員對駕駛員的代碼大致了解的時候可能有不同于你的固有認識,我想這個方面的確可能是兩個人合作的效率大于單干效率之和的。
接口處理:
?
?
1、前后接口討論的重要性:
誠如上文所言,在最初的討論中所有成員都應該參加,但是這次并沒有邀請UI組(甚至最開始的時候還沒有考慮到要聯系UI組,因為接口函數看上去已經確定了)。也如后來UI同學在群里抱怨的,雖然邏輯上各組之間差異不大,但是他們最初想得太美好了,接口參數表、返回值、甚至編寫語言的不同讓UI組的工作一下子重了不少。我們在之后的第二天找到了UI組的同學,不過他們討論的積極性也不高,所謂的對接組內討論也不了了之。
2、人性化、例程:
這一次我們的接口設計是比較成功的,因為據反饋有好幾組UI都對我們的接口表示滿意,我想這一方面得益于我在對接口設計時充分考慮到(a)盡可能少的調用函數完成盡可能多的事情(b)C語言仍然是所有同學熟練掌握的語言,并且它幾乎成為各種編程語言會優先支持的外部語言;另一方面我也不厭其煩地在每一個版本中編寫Test工程對dll進行測試,更對接口編寫實際的使用例程并且不斷進行更新,這樣充分考慮用戶感受使我們贏得了贊譽。
代碼展現:
?
?
1、留給UI組的接口
?
extern "C" __declspec(dllexport) void SettingCal(int numOfOperand, int numOfQuestion, double rangeOfQuestion, bool addition, bool subtraction, bool multiplication, bool division, bool power, bool brackets, int precision, bool properFraction, bool decimalFraction);extern "C" __declspec(dllexport) void GenerateAndCalc();extern "C" __declspec(dllexport) const char* getExpression(int count);extern "C" __declspec(dllexport) const char* getAnswer(int count);extern "C" __declspec(dllexport) int numOfQuestion(); View Code?
2、內部的代碼框架
?
struct ReversePolishType {stack<double> OPTR; //操作數棧stack<char> OPND; //操作符棧 };struct fractionType {//假分數形式int numerator; //分子int denominator; //分母 };struct RPT_FractionType {//真分數的逆波蘭式表示stack<fractionType> OPTR;stack<char> OPND; };class OperationClass { private: //B同學:int numOfQuestion; //題目的數量int numOfOperand; //操作數的數量double rangeOfQuestion; //題目中的數值范圍//運算符的種類bool addition;bool subtraction;bool multiplication;bool division;bool power;bool brackets;int precision; //精度bool properFraction; //是否支持真分數bool decimalFraction; //是否支持小數//都不支持說明支持整數 //計算整形、小數形式的算式static ReversePolishType ReversePolishNotation(string Input)throw(...); //計算整形、小數形式的算式:根據string生成逆序波蘭式static double CalReversePolishNotation(ReversePolishType expression)throw(...); //計算整形、小數形式的算式:根據逆波蘭式計算結果//計算分數形式的算式static RPT_FractionType RPN_FractionType(string Input)throw(...); //計算分數形式的算式:根據string生成逆序波蘭式static fractionType CRPN_FractionType(RPT_FractionType expression)throw(...); //計算分數形式的算式:根據逆波蘭式計算結果//分數形式的加、減、乘、除、乘方static fractionType fraAdd(fractionType a, fractionType b)throw(...);static fractionType fraSub(fractionType a, fractionType b)throw(...);static fractionType fraMul(fractionType a, fractionType b)throw(...);static fractionType fraDiv(fractionType a, fractionType b)throw(...);static fractionType fraPow(fractionType a, int b)throw(...);//A同學:string generate()throw(...);string generate1()throw(...);string generate2()throw(...);string generate3()throw(...);string generate0()throw(...); public:OperationClass(); //無參構造方法//提供給UI的屬性、方法 //對象的屬性vector<string> expression; //存儲生成的表達式vector<string> answer; //存儲表達式的計算結果void Setting(int numOfOperand, int numOfQuestion, double rangeOfQuestion, bool addition, bool subtraction, bool multiplication, bool division, bool power, bool brackets, int precision, bool properFraction, bool decimalFraction);/*設置屬性:操作數數量,題目數量,數值范圍,加法?減法?乘法?除法?乘方?(真分數?or小數?最后兩項只可選其一,否則拋出異常)*/void GenerateAndCalc();void Generate(); //生成表達式,并存儲在string當中void CalcAllExpression(); //對題目表達式依次進行計算,將結果string數組返回//獲得對象的屬性int getNumOfQuestion(); //獲取題目數量設定值//B同學提供給A同學的方法 //計算表達式expression //返回double類型的答案double CalcDouble(string expression)throw(...); //整數/小數形式表達式:對輸入表達式字符串進行運算,然后以數值形式返回double CalcFrationDouble(string expression)throw(...); //分數形式表達式:對輸入表達式字符串進行運算,然后以數值形式返回//返回string類型的答案string Calc(string expression)throw(...); //整數/小數形式表達式:對輸入表達式字符串進行運算,然后以數值形式返回string CalcFration(string expression)throw(...); //分數形式表達式:對輸入表達式字符串進行運算,然后以數值形式返回 }; View Code?
轉載于:https://www.cnblogs.com/Trinidad/p/8893597.html
總結
- 上一篇: Problem Collection I
- 下一篇: Codeforces 552C Vany