1. 程式人生 > >Week2 結對程式設計總結

Week2 結對程式設計總結

黃金點遊戲 - 結對程式設計總結

這篇隨筆是關於上週的黃金點遊戲的一個總結。文中會根據作業要求介紹我們結對程式設計小組的工作內容、結果以及過程中的一些觀察和思考。

在開始實現之前,用PSP表格記錄下你預估完成專案需要的時間。

PSP表格:Personal Software Process,這裡我們使用這種模型來回顧我們完成這次作業的流程和時間安排,但由於我們這次作業要做的是個很簡單的 bot, 所以有些 PSP 中提到的環節並不存在於我們的工作內容中,所以用-表示省略。由於我們是非常緊密的結對程式設計,幾乎所有時間都是在一起討論和寫程式碼的,所以不存在程式碼規範和設計複審等流程。(唯一的程式碼複審時間出現在第一天晚上我自己把基本框架寫完,等到第二天我們再一起往裡面加東西)

PSP各個階段 預估時間(hrs) 實際時間(hrs)
計劃 1 2
開發 9 7.5
· 需求分析 2 1
· 生成設計文件 - -
· 設計複審 - -
· 程式碼規範 - -
· 具體設計 1 0.5
· 具體編碼 4 3
· 程式碼複審 0 0.5
· 測試 2 3
報告 2.5 2.5
· 測試報告 - -
· 計算工作量 0.5 0.5
· 事後總結 2 2
總共花費的時間 12.5 12

看教科書和其他資料中關於Information Hiding, Interface Design, Loose Coupling的章節,說明你們在結對程式設計中是如何利用這些方法對介面進行設計的。

這個問題可能不適用於這次我們的結對程式設計作業。在瞭解了上面幾個名詞的概念之後,發現他們更加適用於大型專案的設計。而我們的專案僅僅只用到了幾個函式。不過一些思想是可以體現在函式設計上的。在之後的大型專案中,我們可能會用到這些設計思想幫助提高程式質量。

描述重要模組介面的設計與實現過程。設計包括程式碼如何組織,比如會有幾個類、幾個函式,他們之間的關係是如何的,關鍵函式是否需要畫出流程圖?說明你的演算法的關鍵(不必列出原始碼),以及獨到之處。

首先簡單介紹一些我們的 bot 的設計思路:
我們參考 Q-learning 的思想,但是實際並沒有嚴格遵循它的模式,而是基於 state-action 這種組合模式,實現了一個簡單的可線上學習的決策模型。
我們希望我們的 bot 能做什麼事?
當開始新的一局遊戲,我們希望我們的 bot 能利用此局之前的所有玩家輸入和黃金點值的資訊,計算出這一輪應該輸出的兩個 candidate 數。
具體到我們的決策模型下,我們希望在新的一句開始時,我們的 bot 能根據歷史資訊為當前局判斷出一個狀態,然後在一個動態可學習的狀態-動作概率矩陣中找出當前狀態下成功概率最高的一個動作,這個動作就是某一種我們設計的計算 candidate 的方法。
於是我們的最主要的工作就成了如何人工設計一組狀態和動作,剩下的就只需要利用 Input 判斷狀態,然後查表選擇動作就行了。
關於動作的設計,我們將一個動作(計算 candidate)劃分為三個步驟,每個步驟存在三種可選擇的操作,這樣下來就一共可以得到 9 種動作。
這種動作的設計指導我們一一對應寫出了狀態的劃分,但最終我們是通過一個概率矩陣來刻畫兩者之間的對應關係,並且這個矩陣中的概率會隨著遊戲結果而更新(這個過程可以認為是在學習一組策略)
理論上當我們用訓練資料跑完400輪遊戲後,更新的到的概率矩陣就是一組”學好的策略“。然而我們知道這種東西對訓練資料的依賴性很大,所以我們最終決定選擇線上學習的方式,即正式比賽初始時用的概率矩陣是均勻分佈的,從頭更新。

幾個重要的函式:

函式名稱 輸入 輸出 功能
create_state_dict() 自定義的狀態劃分標準 一個多級字典 建立狀態字典(實際上是狀態-動作概率矩陣
get_s() 所有歷史資訊 三個子狀態的值(對應多級字典的索引) 根據輸入資訊判斷當前狀態
get_a() 經過處理的狀態資訊 計算得到的 candidate 根據狀態選擇動作計算 candidate
update() 歷史資訊中相應輪的黃金點值 根據歷史資訊更新狀態-動作概率矩陣

再說一下所謂線上學習的事情,假設現在遊戲進行到了 300 輪,那這時候我們會得到前 299 輪的資料。這時候,在計算輸出當前局的我們的結果之前,我們先會拿前 299 輪資料做一次訓練。即經過 299 輪更新,用這時候的概率矩陣去預測當前狀態(round 300)應該如何計算輸出值。這樣也導致我們的執行時間線性增長,到後面需要一兩秒才能輸出結果。

閱讀有關UML的內容。畫出UML圖顯示計算模組部分各個實體之間的關係(一個圖即可)。

在閱讀了 UML 有關的內容後,發現在軟體工程中提的最多的是 UML 類圖。但是我們這次的作業程式碼很簡單,並沒有用到類,幾個重要的函式在上面有給出簡單介紹。所以就沒有畫出類圖。有時間會補充一個簡單的流程圖。

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

Design by Contract:
優點:
規範的描述可以減少程式設計過程中的錯誤。
程式的魯棒性強,質量高,更加可靠,不易發生異常錯誤。
缺點:
對於簡單的程式,可能這樣的要求會顯得累贅。

程式的程式碼規範、設計規範。你們倆如何達成共識、採用什麼規範?程式中是否有異常處理?你如何處理各種異常?

之前說過我們倆是”緊湊的“結對程式設計,所有 coding 的時間都是一個人在寫另一個人在看的,所以不考慮其他人蔘與的情況,我們是沒必要程式碼規範的,由於兩人相關經驗有限,並沒有對某種設計規範很熟悉,所以在這次有限的時間內就沒有采用什麼設計規範。達成共識很簡單:我們每寫一個函式或變數,就同時告訴隊友這是個什麼東西,這個命名是如何想到的(例如,我想寫一個 get_s函式獲取當前局的狀態,就一邊寫一邊告訴對方我們這個函式是獲取 state 的,所以是 get_s)

描述介面模組的詳細設計過程。你的程式有使用者介面麼?在部落格中詳細介紹你如何設計你的介面模組。

沒有使用者介面。我們做只是一個 bot,這個 bot 不會和使用者有直接的互動,按照遊戲的進行方式,程式只需要通過 stdout 輸出兩個數字就行。

描述介面模組與其他模組的對接。詳細描述UI模組的設計與其他模組的對接,並在部落格中截圖實現的功能。介面/控制/資料模組體現了MVC的設計模式了麼?

根據上一個模組的說明, 這個模組對我們這次的作業並不適用.

描述結對的過程。提供兩人在討論的結對照片。遮擋和美化都是允許的。

我(左)和我隊友(右)

(突然發現《構建之法》裡面提到的結對程式設計要求兩個人使用同一個鍵盤,然而我們這種操作只是在程式碼測試階段,方便兩者都能很快的修改某一處地方)
(而且從那 it 借來的電腦的鍵盤佈局有點反人類233)

結對的過程整體來說是很緊密的,從一開始的討論,對問題的定義開始,我們就是一起在討論室討論。因為兩個人都是女生,交流起來都很有耐心,沒有什麼障礙。並且我們倆是同專業的同學,再加上我覺得我們兩個水平差不多(所以不存在一個大佬全程帶著飛這種情況),所以討論過程中有啥不清楚的都會直接問,這個相互反覆闡述想法的過程能很好地幫助我們理解問題和發現問題,我覺得這是很好的。我們基本上是比較嚴格的復現了《構建之法》中的”領航員“和”駕駛員“模式,並且輪流交換角色,且不說效率究竟如何,但是這個過程是比較舒適且能夠保持整個下午都是專注的狀態。

看教科書和其他參考資料中關於結對程式設計的章節,說明你們採用了哪種合作方式,以及結對程式設計的優點和缺點。a) 結對的每個人的優缺點在哪裡(需列出至少三個優點和一個缺點)?b) 你如何說服你的夥伴改進他/她的缺點?請考慮一下三明治方法。
就像上一段說的,我們是”緊湊的“結對,比較嚴格的復現了《構建之法》中的”領航員“和”駕駛員“模式。
我們在第一天晚上做的事情大概就是把問題的定義和要做的事情弄明白,這個階段由於不涉及coding,所以不存在”領航“和”駕駛“的動作,要我說大概就是”領航員“和”駕駛員“在出發前的某一個晚上,規劃這次行程,的模式。
結對程式設計的優點

  1. 兩個人幹活不容易摸魚,有時候一個人幹活,如果遇到一時無法解決的問題就容易開小差,幹別的事去了。兩個人就不會這樣,所以主要寫程式碼的那天下午我們都覺得這麼長時間下來我們能保持專注,挺難得的。
  2. 兩個人寫東西會有反覆的闡述自己想法和理解別人想法的過程,這個過程可以幫助我們得到更好的解決方案

結對程式設計的缺點

  1. 效率問題,之前說到我們在工作過程中有”反覆的闡述自己想法和理解別人想法的過程“。首先,這種過程本身就是比較耽誤時間的花費耐心的(雖然我們這次並沒有嚴重到這種程度),另外我們很難說這樣反覆商榷的出來的結論究竟是不是大概率比一個人做出來的要好。
  2. 時間安排問題。因為要遵循書上說的結對程式設計模式,我們必須找到兩個人都有時間的時候來幹活,這樣在時間安排上會有些不方便,而且有時候都有空閒的時間並不一定能同時滿足兩個人的工作習慣。

個人的優缺點
優點:

  1. 尊重對方,說話有耐心有條理,溝通無障礙無衝突。
  2. 合作意識強,願意花時間兩人坐在一起討論問題和寫程式碼。
  3. 具備一些我不是很熟練的能力(例如 debug)
    缺點:
    這是我們倆都有的缺點,就是寫出來的程式碼不太好看,函式功能設計得比較雜。
    如何說服隊友改進缺點
    這次過程中,合作很順利,我覺得我隊友挺好說話的,所以沒有遇到這種情況。不過書中的三明治方法看起來的確不錯,之後有機會會考慮用到。

在你實現完程式後,請在PSP表格中記錄下你在開發各個步驟上實際花費的時間。說明差異的原因。

這一列得內容也寫在上面的表格中了,其中計劃的時間比預估要長。因為第一次討論過程中,發現我和隊友對於問題的定義有些出入,所以我們花了一些時間討論統一意見。
然後具體編碼的時間並沒有那麼長,因為發現經過討論後得到的方案挺簡單的,寫起來並不麻煩。

收穫、心得體會

寫這篇隨筆的過程中又從頭把這次的作業梳理了一遍,發現程式碼中存在很多不足的地方,整個設計思路也沒有很清晰。
當時可能是由於時間比較緊張,對自己後面能否實現程式碼也沒有信心,所以在簡單討論之後就開始寫程式碼了,並沒有做充分的前期記錄和設計複審工作。
講道理,在動手寫程式碼之前把要做的事情寫下來梳理一遍,後面的問題會少很多,出了問題也好找原因。但這次就是迷迷糊糊地想出一點頭緒之後就開始寫程式碼了嗎,幸好期間和隊友一直保持溝通,最後寫出來地東西還算有點條理。可能這也是結對程式設計地優點之一吧。說到工作內容,老實說我們組的策略考慮並不周全,其他隊伍大多考慮了”搗亂策略“,這個我們是沒用的,我們兩個人都比較保守,這也導致我們對整個局勢的預估出現了偏差,在第二盤激烈震盪的黃金點走勢中表現得很不理想。不過看到第一盤的結果,我想我們的 adaptive 的策略算是有點用的。
總的來說,以後寫東西會更加註意前期的文件工作,至少要先理清楚整個流程,寫下來,然後在開始寫程式碼,並且寫程式碼時明確自己在做什麼。