# 設置風格
我們已經覆蓋了配置項目時的大多數一次性任務:選擇一個許可證,安排初始的網站等等。但是開始一個新項目時最重要的方面是會變化的。選擇一個郵件列表地址很容易;而保證列表的對話不走題且有效率則完全是另一回事情。如果項目經過多年的關閉,內部的開發,重新開始時開發過程將會改變,你需要準備開發者來應對這種變化。
第一步是最難的,因為未來管理的先例和預期都沒有設置。正式的規則還沒有帶來項目的穩定性,而是由開發過程中共享的難以穩定的團體智慧帶來。也許有已經寫好的規則,但通常是通過難以預料的,不斷進化的協議來引導項目。寫好的規則不能定義其描述的項目文化,即使后來也是近似而已。
這里是如此解決問題的一些原因。成長和高轉化率不會像一般人想象的那樣損壞社會規范的積累。只要變化不要*太*快,就有時間讓新來者學會如何做事,在他們學會之后,他們自己就會來加強這種方式。考慮一下數世紀以來兒童歌曲的發展。現在孩子們演唱的歌曲和幾百年前有大致相同的韻腳,即使現在的孩子從來沒有生活在那個時代。小點的孩子聽到大點的孩子唱歌,然后當他們長大了,他們又會在更小的孩子面前演唱。孩子不是故意參與這個傳遞程序,當然,這些歌曲的傳承確實是因為有規律和重復的傳遞。自由軟件項目不會以世紀(我們還不能知道)作為測量的時間刻度,但是變化和傳遞非常類似。轉化率更快,不管怎樣,必須以更活躍和慎重的傳遞投入來作為補償。
人們通常會期望和尋找社會規范的事實,會成為這種努力的輔助。這也是人類的做法。在任何以共同努力統一的團隊中,加入者都會憑直覺尋找可以將自己標記為團隊一部分的行為。盡早設定先例的目標是讓這些“組內”行為對于項目發生作用;一旦建立,多半會生生不息。
通過特定實例,你可以設置好的先例。這不必是一個完整的列表,但是通過盡早設置這樣的協作情緒的方法,可以大大的幫助項目。從物理上講,每個開發者都在自己的房間獨立工作,但是你可以設法讓他們*感覺*是在一個房間一起工作。他們這樣的感覺越多,就會在項目上花費更多的時間。我選擇了這些例子,因為這些實例來自Subversion項目([http://subversion.tigris.org/](http://subversion.tigris.org/)),而我從一開始就參與并觀察了這些實例。但是這不僅僅對Subversion有效;大多數開源項目中都會遇到類似的情形,這是開個好頭的好機會。
### 避免私下討論
即使你已經將項目公開,你和你的創始人也會經常希望通過私下討論來解決困難的問題。這在項目的開始階段尤其明顯,因為此時需要做出許多重要的決定,而只有少量志愿者能夠勝任。你會發現公開討論的明顯缺點:郵件對話本身的延遲性,需要保留足夠的時間來達成一致,處理自以為是的幼稚的志愿者(每個項目都有;有些將來會成為明星貢獻者,而有些會永遠保持幼稚),也就是那些不能理解你為什么只希望解決問題X,而X明顯是大問題Y的子集的人。秘密決定并使之成為*既成事實*,或者至少成為聯合和有影響力的投票集團的堅實推薦,確實非常有吸引力。
不要這樣做。
盡管公開討論可能很笨重,但是從長遠來看這樣做更合適。私下里做出重要的決定就像是將貢獻者排斥出項目一樣。沒有重要的志愿者會愿意呆在這樣一個由秘密委員會做重要決定的環境里。此外,公開討論也會從其副作用中獲益,無論是多么短暫的技術問題,一經發起都會一直討論下去:
-
討論有助于訓練和教育新開發者。你不知道有多少雙眼睛在關注著討論;即使大多數人不會參與,仍然可能有很多人在靜靜的跟蹤,收集軟件的信息。
-
討論會訓練*你*如何向不熟悉軟件的人們解釋技術問題。這種技巧需要練習,你不能從已經知道你所知道的人那里獲得這種練習。
-
之后,討論和結論將會一直存放在公共歸檔中,可以保證以后的討論不會回到同樣的步驟中。見[Chapter?6, *交流*](# "Chapter?6.?交流")的[the section called “歸檔的顯著使用”](# "歸檔的顯著使用")。
最后,很有可能某個人會提出一個你從想到過的好主意,給對話帶來真正的貢獻。很難說這有多大的可能;這僅僅由代碼的復雜程度和需求的專業程度決定。但是如果允許我使用軼事作為證據,我會證明這樣做比直覺所期望的結果更好。在Subversion項目,我們(創始人)相信我們面對的是一組深入而復雜的問題,為此我們痛苦思考了幾個月,我們很明確的懷疑在新建立的郵件列表中的會有任何人做出真正的貢獻。所以我們選擇了一條比較懶惰的方式,開始通過私下郵件討論技術想法,直到項目的一個觀察者[[10](#)]嗅出了問題,并要求將討論公開。眨了眨眼我們這樣做了—后來的結果讓我們十分驚訝,我們很快便獲得了許多有見地的回復和建議。大多數情況下人們提供的想法都是我們從來沒有想到的。結果是郵件列表中一下子多了許多*非常*英明的人;他們只是在等待正確的誘餌。可以肯定地是公開討論比私下討論會保持更長的時間,也能得到更多的產出,花費額外的時間是值得的。
我們不必把問題總結為:“團結就是力量”(我們已經見過許多更成功的團隊),但可以確認的是有一些事情適于在團隊中完成。首先是有了大量的審閱;其次是快速產生大量的想法。想法的質量由其所針對的思想決定,當然,在你用挑戰性的問題刺激他們之前,你無法判斷這些思考者是那種人。
當然,也有許多討論必須在私下進行,通過此書我們會看到這種例子。但是我們有一個指導原則*如果沒有保持秘密的原因,那就公開進行。*
要想使之發生,我們需要行動。僅僅保證自己所有的通告公開是不夠的。你也需要勸說其他人放棄不必要的私下討論。如果某個人嘗試開始沒有必要的私下討論,你要義不容辭的立刻進行恰當的元討論。在你將討論成功的引入公開場所之前,不要對原始主題做出任何回復,或者去確定私下進行是否必須。如果你一貫如此,人們會很快會意,并開始首選公開論壇進行討論。
### 防無禮于未然
從項目的一開始,你就應該保持論壇中粗魯和無禮行為的零容忍。零容忍不是指技術上的實質強制。當有人侵犯其他用戶,你不需要將其從郵件列表中刪除,或因為其無禮的回復而收回其回復權限。 (理論上講,可能最終你必須訴諸這類行動,但應該是其他方法失敗之后才采用—這需要清晰的表述,而不應該是項目開始的情況。)零容忍指的僅僅是決不漏掉任何此類壞行為。例如,有人發布的技術回復中摻雜了對某一個項目開發者的*個人偏好的*攻擊,*首先*你應該緊急回復來指明這種*個人偏好的*攻擊,并指出作為技術問題本身,應該只包含技術內容。
不幸的是這并不很容易,更普遍的是,建設性的討論演變為破壞性的論戰。人們會在郵件里談事情,而永遠不會面對面談論。討論的主題只是放大了這種效果:在技術問題中,人們經常感覺對大多數問題有一個唯一的答案,而對此答案的異議只能被解釋為無知或愚蠢。某人技術提議的愚蠢與某人本身的愚蠢不算太遠。實際上,有時候很難說出技術爭論和人身攻擊從哪里開始,這也是激烈回復或懲罰不是好主意的一個原因。相反,當你發現此類事件發生,你應當回復來強調保持友善討論的重要性,而不要指責任何人是故意為害。可惜這種“軟規則”回復有點像幼兒園老師教導學生學習好的行為:
> *首先,請減少帶有個人傾向的回復;例如,稱J的安全層設計對“計算機安全基本原理的幼稚和無知”。這樣說對錯都有可能,但是無論何種情況,我們都無法進行討論。J真心誠意地提出意見。如果存在Bug,請指出來,我們會進行修正并得到新的設計。我確定M對于J并無人身攻擊,但是措辭是不合適的,我們會努力保持事務的建設性。*
> *現在,對于這個建議。我認為M所說的是正確的...*
因為此回復的不自然,會有顯著的效果。如果你對于壞的行為保持一貫的行動,而不是要求攻擊方進行道歉和承認,這樣就讓人們可以自由的冷靜下來,而在下一次能夠表現的更有禮貌一點—他們會的。這樣做能成功的訣竅是不要將元討論作為主題。它必須放在一邊,成為回復主要部分的簡短序言。通過順便提及指出“我們這里不是這么做的”,然后轉移到真正的內容,這樣你就給了人們一些可以回復的話題。如果有人抗議他們不應該受到你的責難,只需要拒絕討論這個問題。除了不回復(如果你認為他們只是精力過剩,不需要回復),也可以說你為反應過度而道歉,而且在郵件中很難感到這種微妙之處,然后回到主題。絕不在任何時候要求一個人為不合適行為作出承認,無論是公開還是私下的。如果他們選擇隨自己的意愿進行道歉,那樣很好,但是要求他們那么做只會導致怨恨。
總體目標是將好的禮節視為“團隊內”的行為。這可以幫助項目,因為開發者會由于論戰而流失(即使是他們喜愛和希望提供支持的項目)。你可能甚至不知道他們為什么離開;有些人可能一直潛伏在郵件列表,考慮到加入到項目需要的厚臉皮,就會決定放棄加入。保持論壇的友善是一個長期生存策略,在項目還比較小的時候,這很容易。一旦這成為了文化的一部分,你就不是唯一提升這種文化的人。所有人會一起維護。
### 實踐明顯的代碼評審
促進開發生產率的一個最好的辦法就是讓人們互相察看代碼。需要一些技術基礎設施來進行有效的支持—特別是提交郵件應該開啟;更多細節見[the section called “提交郵件”](# "提交郵件")。提交郵件的作用就是每當有人提交了源代碼的修改,就會發送一封包含日志信息和變更差異(見[the section called “版本控制詞匯表”](# "版本控制詞匯表")的[*差異(diff)*](#))的郵件。 *代碼評審*是在代碼來到時對提交郵件進行評審,尋找Bug和可能的改進的實踐。[[11](#)]
代碼評審同時滿足多個目標。這是開源世界的同級評審中最明顯的一個例子,直接促進維護軟件的質量。軟件的每一個Bug都是提交進來的,而且沒有被發現;因此,關注的眼睛越多,將會帶入越少的Bug。但是代碼評審也有非直接的目標:它確認了人們所真正關心的東西,因為很明顯一個人不會去花時間評審他不關心的功能。當人們知道會有人花時間評價他的工作,他們就會傾盡全力。
評審必須是公開的。即使有時我與其他開發者坐在同一個物理房間,我們中的一個做出了提交,我們也盡量不在房間中進行口頭評審,而是將其發送到開發郵件列表。所有人會從看到發生的評審獲益。人們緊跟著評論,有時會在其中發現瑕疵,即使沒有發現,這也會一直提醒他們評審是一個預期的,有規律的活動,就像刷盤子和割草坪。
在Subversion項目,開始時并沒有建立有規律的代碼評審實踐。無法保障所有的提交會得到評審,盡管如此,還是會有人在看到感興趣的代碼塊時看一下修改。一些小Bug確實能夠,也應該被發現。一個叫Greg Stein的開發者,從以前的工作知道代碼評審的重要性,決定通過評審*每個單獨提交*到源代碼庫的每一行來設立一個范例。每當有人提交,郵件列表就會緊跟著出現Greg的郵件,解剖這次提交,分析可能的問題,偶爾還會贊揚一下聰明的代碼。很快,他就發現了其他人會略過而不會注意的Bug和非最優的代碼實踐。更深刻的是,他從沒有抱怨他是唯一評審所有提交的人,盡管這樣做占用了他很多時間,但是他確實一有機會就會盛贊代碼評審。不久之后,其他人,包括我也開始了有規律的提交評審。我們的動機是什么?不是Greg有意識的讓我們為此感到羞愧。而是他已經證明代碼評審是值得花費時間的方法,它的貢獻與編寫新的代碼不相上下。一旦他證明了這一點,它就成為預期的行為,以至于如果一個提交者發現沒有人對其提交有任何反應,他會感到擔心,甚至會在列表中訊問是否有人愿意花時間為其評審。不久之后,Greg得到一個工作,他也沒有更多時間為Subversion工作,結束了有規律的評審。但是之后,他的習慣深深影響了我們,似乎這樣做是天經地義的。
從第一個提交就開始評審。差異評審中最容易檢查出來的問題包括安全漏洞、內存泄露、注釋不足或API文檔問題、位偏移錯誤、調用/被調用不匹配以及其他在較小的上下文就能發現的問題。然而,即使這類未能將重復的模式抽象到一處的較大規模問題,在經過有規律的評審后也可以被定位出來,因為對以前差異的記憶提醒了對當前差異的評審。
不要擔心你未能發現任何需要回復的內容,或者你不是很清楚代碼的每個部分。通常幾乎每一次提交都會要說什么事情;即使你沒有發現任何事情可以提問,你還是可能發現一些事情可以對其稱贊。最重要的是讓每個提交者清楚,他們所做的事情都正在被關注和理解。當然,代碼評審不能讓程序員逃脫在提交之前評審和測試他們所做變更的責任;人們不應該依靠代碼評審來捕捉本應該他自己捕捉的問題。
### 將一個封閉項目開放時,對于改變的影響要格外敏感
如果你開放一個已存在的項目,其中已經有了許多習慣于在封閉源代碼環境下工作的活躍開發者,你必須確保每個人理解正要發生的重大變化—你必須設身處地的為他們著想。
想象一下他們面對的情形:以前,所有的代碼和設計決定都是由一組程序員做出,他們對軟件有差不多相等的熟悉程度,而且都是從同一個管理中接受相同的壓力,而且清楚其他人的長處和弱點。現在你讓他們將代碼暴露給隨機的陌生人監視,而他們只會根據代碼形成判斷,而不會考慮造成這種決定的商業壓力。這些陌生人會詢問很多問題,這些問題讓已有的開發者發現無論如何為文檔苦干,*仍然*不足(不可避免的)。最關鍵的是,這些新來者是未知的,未露面的實體。如果你的一個開發者已經感覺到他的技藝不夠安全,想想一下當新來者指出他所寫代碼的Bug時的嚴重性,更嚴重的,在他的同事面前。除非你有一個擁有完美編碼員的團隊,這是不可避免的—實際上,對于每一個人開始都會發生這種情況。這不是因為他們不是好程序員;只是因為任何超過一定規模的程序都會有Bug,而同級評審可以發現一些此類Bug(見本章前面的[the section called “實踐明顯的代碼評審”](# "實踐明顯的代碼評審"))。而此時,新來者開始本身并沒有受到同級評審的支配,因此他們在熟悉項目之前不能貢獻代碼。對你的開發者,感覺指責正在到來,絕不會離開。因此,要小心這些老手的人心散了。
防止發生這種情況的最佳方法是警告每個人即將發生的情況,告訴他們開始的不適是完全正常的,鼓勵他們一切都會好起來的。有一些警告應該在私下發生,在項目開放以前。但是你也會發現如果在公共列表中提醒人們會有好處,告訴他們這是項目開發的新方式,需要一段時間來調整。你能做的最好的事情是通過實例進行引導。如果你看到你的開發者無法回答足夠多的新手問題,那么只要告訴他們回答更多也于事無補。也許他們對于何種問題需要保證回復沒有太好的感覺,或者他們對于如何排定代碼工作和新的外部溝通交流負擔的優先級沒有感覺。讓它們參與進來的方法是你自己參與進去。作為一個公開郵件列表,確保在那里回答一些問題。當你沒有回答某個問題的技能時,要明確的交給能做的開發者—然后觀察確保有回答或至少是一個回應。當然現在還是有長期開發者進行私下討論的誘惑,因為他們一貫如此。請確定你已經訂閱了可能發生問題的內部郵件列表,并且告知他們此類討論應該立刻公開。
對于開放的封閉項目,還有一些其它的長期關注。[Chapter?4, *社會和政治的基礎架構*](# "Chapter?4.?社會和政治的基礎架構")探索了混合付費和未付費開發者的技巧,[Chapter?9, *許可證,版權和專利*](# "Chapter?9.?許可證,版權和專利")討論了當公開的私有代碼基包含其它組織編寫或“擁有的”軟件時所必須承擔的法律義務。
[[10](#)] 我們這里不是為了還債,而是實踐我前面講的說教:這位觀察者的名字是Brian Behlendorf,他指出了除隱私原因以外,保持所有討論公開的普遍重要性。
[[11](#)] 無論如何,這是開源項目常見的做法。在更集中式的項目中,“代碼評審”也也意味著許多人坐在一起,一起察看打印的源代碼,尋找特定的問題和模式。
- 前言
- 為什么寫這本書?
- 誰應該讀本書?
- 資料來源
- 致謝
- 免責聲明
- 1. 介紹
- 歷史
- 現狀
- 2. 起步
- 從你擁有的開始
- 選擇許可證并應用
- 設置風格
- 通告
- 3. 技術基礎設施
- 一個項目需要什么
- 郵件列表
- 版本控制
- Bug跟蹤
- IRC / 實時聊天系統
- RSS供稿
- Wikis
- 網站
- 4. 社會和政治的基礎架構
- 慈善獨裁者
- 共識為基礎的民主(Consensus-based Democracy)
- 寫下所有的內容
- 5. 金錢
- 參與的類型
- 長期雇傭
- 作為一些個體出現,而不是一個整體
- 公開你的動機
- 錢不能讓你可愛
- 契約
- 資助非編程活動
- 市場營銷
- 6. 交流
- 人如其文
- 避免常見的陷阱
- 刺兒頭
- 處理成長
- Bug跟蹤系統中無對話
- 公開性
- 7. 打包、發布和日常開發
- 版本號
- 發布分支
- 穩定發布版本
- 打包
- 測試和發布
- 維護多發布線
- 發布和日常開發
- 8. 管理志愿者
- 從志愿者中獲取最多
- 像分擔技術任務一樣分擔管理任務
- 轉化
- 提交者
- 榮譽
- 分叉
- 9. 許可證,版權和專利
- 術語
- 許可證的方面
- GPL和許可證兼容性
- 選擇一個許可證
- 版權分配和所有權
- 雙許可證模式
- 專利
- 深入資源
- A. 自由版本控制系統
- B. 自由Bug跟蹤系統
- C. 為什么我要關注車棚的顏色?
- D. 報告bug的樣例指導
- E. 版權