如何成功實施結對編程
在我做咨詢工作的三年半時間里,我(跟客戶)談論結對編程的時間比其他任何話題都多。一般來講,客戶的開發(fā)人員都從來沒有結對過,也根本沒有這個念頭。而且更糟的是,那些搞商務的總覺得兩個人坐在一臺機器前面是浪費。
不過即使有著這些成見,等我們離開的時候,業(yè)務人員跟開發(fā)人員也已經坐到一起結對了。
成功實施結對是很困難的,不過一旦你用上我學到的經驗,一切皆可能。
我假設本文的讀者曾經有過一些結對的經驗,也正在尋找?guī)椭M織實施結對的方法。身處不同角色的人都可以從本文中得到一些啟發(fā),不過它的主要目標受眾還是那些致力于在團隊中推廣結對編程的開發(fā)人員或是團隊領導。
結對空間的配置
就我的經驗來看,把結對環(huán)境配置好可以向成功實施結對邁出很大的一步。下面描述了我最喜歡的配置,不過你還是得按照自己的具體情況進行調整:
◆方桌可以讓大家挨著坐得很舒服。Nat Pryce也用過圓桌,結果也挺不錯。不過你面前正好對著一條弧線,干活的時候就會難受;最好別這樣干。
◆買到性能最好的開發(fā)機器。如果結對用的機器比他們自己用的機器更好,他們就會更喜歡用前者。此外,你只需要給兩個人買一臺機器就行了,這樣購買能力還能高點。
◆帶雙DVI輸出的視頻卡。分離器也行,不過效果不好。最好是能夠有雙DVI輸出,可以把分辨率調到最高。
◆兩個24"或者30"的顯示器。兩個大顯示器(跟兩套鍵盤鼠標配合起來),顯示同一個桌面,可以讓結對的人感覺到他們都是在用自己的機器。
◆兩套鍵盤鼠標。每個人都可以用自己的那套,不過可能有的人就喜歡兩個人用一套鍵盤鼠標。
我的想法是,一定要讓大家有一個盡量舒服的工作環(huán)境,至少要跟他們用自己的機器干活一樣舒服。
讓大家離開自己的桌子(和耳機)是很難的,不過要是讓他們在一個條件更差的環(huán)境里工作可就太蠢了。你應該把地方搞得舒舒服服的,讓大家可以心甘情愿的過來。
把環(huán)境弄好以后,你便向成功邁出了第一步,也是很大的一步;然后你還要保證把機器配置好。我一般都是給一臺機器做個鏡像,然后用它配置其他機器。每 周重鏡像一次也挺好的。開發(fā)人員常常會在需要的時候在結對機器上裝一個新工具,或者加一個別名(alias),但是其他結對機器上不一定也有這工具或是別 名。我發(fā)現定期重鏡像會強迫團隊成員去更新鏡像,而不是每次只管自己的機器。
#T#鏡像里面放哪些東西也要看具體團隊。從理論上講,要想讓整個團隊在編輯器、桌面布局等方面達成一致,你非得弄個頭昏腦脹不可。不過實際來看,任 何一個配得上自己工資的程序員都希望能夠用最理想的工具工作。有的時候,每個人的心中都有一個自己看來最理想的工具,不過總會有一個工具勝出。如果沒有明 確的最佳選擇,那就先選一個標準工具,用起來再說。有一個裝滿了各種最佳工具的鏡像,就可以保證每個人在任何結對機器上都可以高效工作了,這個結果很令人滿意。
不過別想一開始就能把鏡像搞定。創(chuàng)建鏡像也是一個迭代式的過程,團隊應當持續(xù)改進。
我在布置同地結對環(huán)境上做 的很成功。幾乎每個人都有一個會議室,當你許諾開放的辦公環(huán)境能提高20%的生產率的時候,人們自然愿意放棄些私人空間(同地結對的情況下,20%的提高 是很容易做到的)。在DRW(我當前的雇主)里,我們拆掉了一個個小格子,坐在桌前望過去可以一馬平川。我們放棄了“個人”空間來換取結對環(huán)境。想干點自 己私事的時候,就可以拿個筆記本到會議室里去。
我堅信,如果沒有很好的結對環(huán)境,即便是你采取了本文中的其他建議,那估計也會是失敗的結局;不過有些讀過這篇文章的人也不同意我的觀點。但我們都 對一點保持意見一致:一定要盡可能的消除過程實施中的障礙,這絕對忽視不得。以我的個人經驗看來,最大的障礙莫過于給大家提供舒適的工作環(huán)境,但就像讀者 所說的那樣,萬事萬物并無絕對。
一次只關注一個人
我從不相信強迫人們做結對能有效果。有些人喜歡結對,有些人不喜歡。無論如何,要是強迫人們去做結對,他們就不會給你好臉色的。
我用的是慢慢生根發(fā)芽的方式。一般我先專門跟那些不太確定結對是否有效,但是能夠接受這想法的人結對。用不了多久他們就會喜歡結對勝于單獨工作了。這時候我就可以去跟下一個不太接受這想法的人結對。先摘下觸手可及的果實,然后再去找最排斥結對的人。
通常我不會放棄那些拒絕結對的“頑固分子”。在我去努力“勸降”他們之前,你往往會發(fā)現以下兩種變化中的一種
◆他們注意到除了他們以外,整個團隊的生產力都有顯著提高,所以他們來詢問他們是不是也能參加到結對中。
◆他們注意到除了他們以外,整個團隊的生產力都有顯著提高,他們不得不最終離開。顯而易見,不能融入團隊的人往往表現較差。通常,這些人也能看到這一切,而選擇新的方向。
根據我的經驗,90%的情況下,那些你想保留住的員工,最終會喜歡上結對。當然,你也得好好考慮一下,由于失去那些堅決反對結對的員工,而給你 的項目和業(yè)務所帶來的影響。有的時候,你可以把他們換到別的一些讓他們不覺得抵觸或者有壓力的崗位,這也合情合理。另外的時候,讓他們離開可能更加合適。
澄清一點,這世上還是有很多不錯的開發(fā)人員不相信結對的。但是我認為他們當中的絕大多數很可能從來沒有正確地使用過結對。當然即使正確地結對過,他 們中的大部分人仍然有可能還是更傾向一個人編程。我往往會認為這些人都是不錯的,只是并不合適那些主要有結對組成的團隊。傾向于結對,并不表示你就是天 才。同樣地,不喜歡結對也不表示你就不是天才了。
從長遠的角度來看,我相信在一個團隊內部,如果對結對編程有著不同的理解是不利的。根據我的經驗,不管是支持結對的,還是反對結對的,大家都認為在 一個團隊里面有兩種不同的觀點是極度低效的。通常的結果就是團隊中人與人之間不斷地為了這個話題進行斗爭,把寶貴的時間都花在了爭吵和互相責怪、推委上面 去了。
交換結對
如果你跟某個人一起工作,他不排斥結對,但是不確定結對是否可行,那就可以常常跟他結對,甚至一直結對。最開始的幾次結對嘗試算是適應階段,這個時 候應該給他們提供最佳的結對工作環(huán)境。不過一旦有人度過了實驗階段,開始享受結對的樂趣,那么最好就換個人來結對。按我的個人經驗來看,結對的時間最少一 天,最多兩天。當然這也要看具體環(huán)境,但在我過去的編程生涯中,這個數據倒還是保持恒定的。
跟一個人結對多長時間效率最高?從不同的視角來看會得到不同的結論。我在上面那段話中提到過,我一般跟同一個人至少結對一天,最多不超過兩天。從其 他角度出發(fā),我可能會建議每個迭代交換一次結對,隨意混亂結對。這兩樣我都覺得有點極端,但我也認識到,在特定的環(huán)境下他們也可能是明智的選擇。藉由頻繁 交換結對,我們會在兩處收獲頗豐:
人們在工具(如grep、IDE)、領域、模式、測試等等方面各有專長。在實現你當前的特征時,跟這方面的專家一起結對就是個相當不錯的主意。
在團隊中,你有時會從別人身上學習,有時會去指導別人;跟不同的團隊成員一起工作,會讓你更好地掌握扮演不同角色所花的時間。
交換結對能夠大幅度提升效率,從而帶來了更高的實施成功率。
誰來當駕駛員
新接觸結對的人常問這種問題:你們難道不是同時編碼么?簡單一句話:不。我們可以通過“乒乓結對編程”的方式來解決有人編碼太少或者太多的問題。
“乒乓結對編程”(又稱“乒乓結對”)指的是兩個人交換編寫測試和實現代碼。也許用“乒乓結對測試驅動開發(fā)”這個冗長一些的名字會更為準確,不過也就更麻煩了。結對的流程看起來可能是下面這個樣子:
1. 開發(fā)者1號寫一個失敗的測試。
2. 開發(fā)者2號編寫僅僅夠用的代碼,讓測試通過
3. 開發(fā)者2號寫一個失敗的測試
4. 開發(fā)者1號編寫僅僅夠用的代碼,讓測試通過
5. 回到第一步。周而復始。
在引入結對的時候,“乒乓結對”可以很見成效。
無論如何,過了開頭幾天以后,結對中每個人所扮演的角色往往就會決定了“誰應該敲鍵盤”。
結對中的指導者
不管給了什么任務,在一對人里面,幾乎都會有一個對問題了解的更加清楚一些。在這種情況下,讓了解問題更少的人來當駕駛員則更有意義。指導者應該把 思維模式調整一下,從“我怎么來交付這個功能”變成“我該怎么領導我這對人,從而針對這個問題給出正確的解決方案”。在扮演指導者這個角色的時候,他應該 是傳道授業(yè)解惑,而不是鞠躬盡瘁實現代碼。你該聽說過這句話:授人以魚不若授人以漁。
注意:我發(fā)現無論是學習、實施,還是已經進入結對的穩(wěn)定階段以后,這角色都很有價值。在學習和實施結對編程的時候,意識到自己是一名指導者,并有效地進行知識傳播,就可以跟另一半建立起強烈的自信和信任關系。在穩(wěn)定階段,當一個指導者可以在完成特征的過程中傳播知識。#p#
扮演指導者的角色可以有很好的機會從宏觀上考慮全局。你也許會想出一個更簡單的辦法可以解決手頭的問題。如果我想出一個更有效的解決問題的方式,我 首先會教會另一半怎么用最開始的方式完成任務(如果有時間限制的話),然后對另一個念頭做一個快速探測,如果解決方案較優(yōu),那對方就可以理解為什么我們要 切換過去,如果還不如最開始那一個,我們也可以很容易做還原。
結對中的學習者
有了指導者,另外一個人就肯定是學習者了。學習者的任務只有一個:控制結對用的機器,徹底弄清楚問題,用自己覺得最顯而易見的解決方式來實現任務。 如果這個方案可行,指導者就可以提供一些必要的指導。如果方案中有缺陷,指導者也很容易對方案中的不足之處加以指點,為改進指明方向。
無論是指導者還是學習者,這種分類都不是長期固定的。這得看當前所進行的活動。我可能是RoR的專家,另一個伙伴則可能是SQL和JavaScript的專家。實現一個特征的時候我們會多次交換角色。重要的是得弄清楚什么時候作交換,并對自己的角色進行調整。
這里有一條規(guī)則,學習者應該承擔大部分駕駛員的任務。
不感興趣的&精力不集中的結對伙伴
有時候,你的結對伙伴對手頭的任務不感興趣。跟了無生趣的結對伙伴一起工作決不會讓人興趣盎然。只有兩個人齊心協力,才能從結對編程中得到最佳的解 決方案。很顯然,無精打采的人是不會好好協作的,所以解決方案也很難是最優(yōu)解。最好的情況下,即使解決方案已經足夠完美,但另外一個人的時間卻被完全浪費 了。
一個結對伙伴不感興趣必然是有些原因。當然,要弄清楚為什么一個結對伙伴不感興趣,就涉及到個人問題,是不能按照一般方式來解釋。
精力不集中的結對伙伴,就像描述的那樣,很容易被周圍的環(huán)境所影響。他們往往花在打字上的時間比較少,因為他們總是忙著幫助別人。他們不是沒有 價值的。事實上,他們通常能對他們的結對伙伴正在編寫的代碼做出巨大的貢獻。當然,他們很少100%投入,因為他們經常在同一時間嘗試去幫助多對結對伙伴 解決問題。有一些精力不集中的結對伙伴也會花很多時間在查郵件和別的輔助工作上。
Joel Spolsky相信開放式的工作環(huán)境很有意思,但不夠高效。雖然我不同意這個觀點,但我也明白一些精力不集中的結對伙伴是怎么樣很容易地就讓經理們得出這個結論的。
我曾經是個精力不集中的結對伙伴。我也曾經和幾個精力不集中的結對伙伴們一起工作過。我相信我們每個人都不時地會遇到這種情況。過去我看到過通 過制訂一些政策來管理精力不集中的結對伙伴。比如,“個人的筆記本不能帶入開發(fā)區(qū)域”這條規(guī)則就在我之前的項目中出現過。這條規(guī)則能幫助大家解決些問題, 但它也帶來了新的別的問題。
不感興趣和精力不集中的結對伙伴所帶來的最大的問題是他們不能100%投入到結對編程中去,這樣就影響到了生產力的提高。如果你發(fā)現你遇到了一個不感興趣或者精力不集中的結對伙伴,不煩嘗試一下這幾個方法,可能能幫到你。
我個人比較喜歡的對付精力不集中結對伙伴的方法是運用乒乓結對。乒乓結對迫使雙方都同時關注同一點。這個建議的另外一個好處在于它不需要制訂任 何別的可能帶來副作用的規(guī)定。乒乓結對編程可以幫助一個不感興趣的結對伙伴轉變成一個有貢獻的結對伙伴。當然,通常他們的貢獻跟他們100%專注所應有的 貢獻還是有差距的。我發(fā)現,當你跟一個精力不集中的結對伙伴打交道的時候,假裝混亂會更有幫助。
假裝混亂可能很枯燥,真的很枯燥。你一般已經知道需要去做什么。通常你腦子里也有了解決方案。你可以獨自一人實現這個方案,而把精力不集中的那 個結對伙伴晾在一邊。不幸的是,根據我的經驗,人們實際上往往就是這么干的。但是,簡單的把他們晾在一邊不是最佳的長期解決方案。那個結對伙伴可能在某天 被要求去改進你當時的那個解決方案。如果他們做不到,因為他們當時沒關注過,你可能被從你新的任務中調回來解決這個問題。更糟糕的情況是,你可能已經離開 了,那么關于這段代碼一切情況也就成了永遠的迷了。
所以,假裝混亂很枯燥,但它對團隊最有利。不去實現那個方案,相反地,你去問你的結對伙伴:我們怎么來完成這個?不要接受他們的第一個答案。他 們的第一個答案很可能很快給出,但難以置信的丑陋。給出些你的觀點,但不是告訴他們你有方案了。相反地,一直問問題。這樣很有可能,你將會慢慢明白他們的 方案了。即使你很快明白了他們的方案也沒關系,你還是假裝不明白。你得迫使你那個不感興趣的結對伙伴寫出前3個測試,并且編寫代碼讓測試通過。此時,你可 以接過鍵盤,寫些測試方法,但要求他們來實現。隨后慢慢地一步步地轉入乒乓結對的方式,但不要很快地跳過而直接采用乒乓結對。你需要迫使你那個不感興趣的 結對伙伴去編寫大概65%的代碼。不用花很長時間,一個不感興趣的結對伙伴就能轉變成一個100%起作用的結對伙伴了。這對大家都有好處。
檢查語法的結對伙伴
智力上的鴻溝可能會導致一個伙伴除了做點語法檢查以外其他什么都干不了。過去這些年里我著實見過很多次了,而且這最近也發(fā)生在了我身上。我接了個新 工作,在第二天上,我跟公司里最資深的一個工程師結對,把他從前給.net寫的一個庫用java實現。我對這個領域很陌生。我從前也沒做過真正專業(yè)的 java開發(fā)。我從來沒見到過這個庫的.net版本。我從來沒用過跟這個庫進行交互的通信系統(tǒng)。我從來沒用過IntelliJ來編java程序。等等。
我對我的結對伙伴一點作用都起不上。這個任務還相當緊迫,我們之間的信息差異實在太大,所以除了指出點語法錯誤之外,我一直都保持安靜。偶爾我也會敲鍵盤,但也是在結對伙伴告訴我要敲些啥的情況下。
雖然我一般都提倡結對,但是如果一個人除了語法建議以外什么忙都幫不上,那就該換個方式來使用他的時間。另外,如果一個有經驗的伙伴被要求把速 度降下來去解釋一些東西,那當前的任務就肯定要多花些時間才能完成。當經驗上的差距能被彌補,這通常來說是最有效的學習。當然如果經驗上的差距太大,以至 于沒法彌補或者影響到了成功地交付,那么就應該拆散這對重新組合。
不該結對的時候
有幾種情況下最好不要使用結對編程,包括一個結對成員的作用僅僅是檢查語法。另外一些可能更合適你一個人去搞定的場景包括:
◆當讀一個未來可能有幫助的代碼庫的時候
◆當你和一個跟你經驗上差距太大的人一起專研一個復雜的解決方案或者查一個怪異的錯誤的時候。通常結對編程不適合既探索問題又帶新人。
記住這些,很重要的,上述情況都不是進行結對的最好時機。但這不意味著你永遠不應該在這些情況下去結對。當然你如果正在結對做這些事情,你應該 意識到你的結對伙伴可能不感興趣或者不能產生價值。要知道一種快速的阻礙團隊引入結對編程的方法就是讓一些人去做些不產生價值的事情。
不是每個任務都需要一個結對伙伴的。當然,需要結對的任務的數量遠遠多于不需要的。
Dan North在審閱這篇文章的時候指出:可能不是任務的數量,而是任務的種類。任何跟交付直接相關的開發(fā)活動(編寫代碼,編寫測試,構建)在做了結對后往往 都有更好的質量。至于那些跟交付間接相關的,比如研究,調查和行政瑣事,如果用結對,那么回報率就小了很多。所以通常不這么做。
核心結對時段(Core Pairing Hours)
平均而言,你如果覺得結對不是最適合你當前的問題,那么就立刻停止結對。然而,我通過定義每天你有多少小時預留著做結對編程(核心結對時段)獲得了 不少成功的例子。典型的,核心結對時段是你工作時間的60%到70%。舉個例子,如果你從早上8點開始工作到下午5點,那么你的核心結對時段可能從早上 10點到下午4點。
在核心結對時段,你不是被要求一定要結對工作(你永遠不應該“被要求一定”結對)。但是你應該騰出時間,做好結對的準備。如果你正在做的事情由 你一個人來做更好,那就別去結對。當然,如果你沒在結對,但結對的話更有益,那還猶豫什么呢,或者讓你自己準備好去跟別的需要結對的人一起工作??赡艿?話,把一些適合一個人完成的任務拖到核心結對時段結束以后去做,也會有幫助。舉個例子,你在下午2點被分派到了一個中等優(yōu)先級的錯誤,你的結對伙伴對這個 錯誤所用到的庫一無所知,那么你等到4點以后再去看這個問題可能更加合適一點。
所以說核心結對時段非常不錯,它讓你的工作時間有足夠靈活性。
人們反對結對的首要原因是人們“需要自己的時間”,不可能“每天結對8小時”。這個反對意見我總覺得很有意思,因為我不認為大家每天就得結對8小 時,我認為每個人都有資格掌握他們自己的時間。我個人就傾向于每天70%的時間做結對。我有些朋友傾向于60%,另外些95%。我不確定誰是對的,但沒人 是100%的。特別是剛剛引入結對的階段,很重要的一點就是,一旦覺得結對有益,那么就結對,反之就停止。
做可能管用的最簡單的事
“做可能管用的最簡單的事”是一句被大多數敏捷開發(fā)人員常常掛在嘴邊的話,但想做到卻不容易。如果你做得實在太簡單了,你會被批評為目光短淺。然而 如果你做得太復雜,你又會被說成浪費了你自己的時間和那些需要維護這個方案的人的時間。當然,結對編程能幫助你,讓你對你的方案更有信心:簡單但足夠管 用。
在結對過程中,你要有恒心,堅持做可能管用的最簡單的事情。如果你正在結對,你有可能正在實現一個能夠滿足絕大部分使用要求的優(yōu)雅的方案。通過堅持做最簡單的方案,你能更快地完成功能,更快地維護現有功能。這個巨大的進步會幫助你推廣你的想法:使用結對編程非常棒。
強制執(zhí)行代碼審查
如果你想提高代碼質量,就該找團隊成員來審查代碼。實際上,有些制度(SOX,HIPPA)要求所有產品代碼都得經過審查。要是你打算推行結對編 程,而且又有一顆聰明的大腦,認識到強制執(zhí)行結對很容易失敗,那就不妨強制執(zhí)行代碼審查。在審查的時候,既可以采取傳統(tǒng)方式,又可以作結對。結對和代碼審 查之間的主要差別是,后者是評判,并且表示出某人對代碼的所有權,同時令人滋生防備心理;但前者則是協作。自己的代碼被別人審查通常都是個很痛苦的過程, 用不了多久大家就會換成結對的。
強制做任何工作都是有風險的,我一般把它作為下下策。
結論
被人“允許”結對不會取得成功。要想成功的話,就要讓團隊享受結對的樂趣,并且從中獲得生產力的提升。如果你從這個角度來實施結對的話,成功的概率就會高很多。所以,在你把上面的想法付諸實踐的時候,請注重一下團隊建設和效率。