面對軟件錯誤構建可靠的分佈式系統-12附錄

附錄A 致謝

Erlang系統、OTP庫集、還有Erlang內置的所有應用都是許多人進行了大量的工作後的集體成果。

致謝部分總是很難寫的,因爲我不想弄丟任何對系統有貢獻的人,也不想出任何差錯——我將力圖做到準確,但是如果還有任何疏忽或差錯,我先在這裏表示歉意。

首先,我要感謝當初的管理者們,他們使得一切成爲可能。我在Ericsson時候的領導Bjarne Däcker大力支持我們的工作,爲了維護我們而積極地鬥爭——謝謝你,BjarneTorbjörn JonssonBjarne的領導)也爲了維護Bjarne而積極地鬥爭,謝謝你,Torbjörn,我從你身上學到了許多東西。Jane Walerud(即Open Source Erlang的幕後策劃者),Bluetail的常務懂事,是她教會我如何經營一家小公司。

現在輪到Erlang的開發者的一個大名單了。Erlang團隊的最初成員有我、Robert VirdingMike Williams。當初我編寫了Erlang的編譯器,Robert編寫了庫,Mike編寫了JAM仿真器。Robert和我寫過多個版本的Erlang仿真器,大部分是用Prolog寫的,後來MikeC重寫了一遍。兩年後,Claes Wikström(我們叫他Klacke)加入了進來,爲Erlang增加了分佈式的能力,Bogumil Hausman這時候發明了改進版的Erlang虛擬機,即BEAM1

還有CSLab的許多成員先後加入到我們的項目中,用Erlang編寫了許多程序,後來又去做其它的事情去了。Carl Wilhelm Wellin寫了yeccKlackeHans Nilsson寫了mnesiamnemosyneTony RogvallKlackeErlang語言增加了二進制語法,使得Erlang可以如此漂亮地支持網絡編程。Per Hedeland的耐心相當好,回答了我所有Unix方面的愚蠢的問題,確保了我們的系統能夠一直工作的很好,並且他主動解決了Erlang仿真器中的一些頑疾。Magnus Fröberg編寫了調試器。Torbjörn Törnkvist編寫了接口生成器,使得Erlang可以與C交互。

ErlangCSLab搬出來, OTP誕生的時候,我們的團隊擴大了,並且進

1 Bogdans Erlang Abstract Machine,即Bogdans Erlang虛擬機。


181

行了改組。Magnus FröbergMartin Björklund和我設計了OTP的庫結構和behaviour的結構,OTPbehaviour庫是在我們實驗室多年的思想積累之上編寫的。Klacke之前就編寫過一個類似於gen_server通用服務器Peter Högfelt之前也寫過另一個通用服務器,是監督樹模型的早期的版本。關於進程監督的許多思想來源於Peter在移動服務器項目中的工作。

我離開Ericsson之後,系統的日常維護和開發交給了新一帶的程序員們。Björn Gustavsson維護着仿真器模塊,Lars ThorsénKenneth LundinKent BoortzRaimo NiskanenPatrik NyblomHans BolinderRichard GreenHåkan MattssonDan Gudmundsson維護着OTP庫集。

而現在呈現在我們的用戶面前的Erlang/OTP系統,則是從與我們的忠實的用戶們的互動中,已經得到了非常顯著的提高。

我們的第一個用戶羣,即用Eralng構建第一個正式產品的團隊是:Mats PerssonKerstin ÖdlingPeter HögfeldÅke RosbergHåkan KarlssonHåkan Larsson

AXD301項目中,Ulf WigerStaffan Blau在首次用Erlang實現運營商級的應用做了許多意義非凡的開創性工作。

無論是Ericsson內部的用戶,還是Ericsson之外的用戶,都做得非常棒。英國的one-2-one公司(現在是T-mobile公司)的Sean Hinde簡直是一個人的Erlang工廠

最後要說,Erlangmailing list也是我們的靈感和勇氣的源泉。今天無論是任何人想要了解Erlang的任何事,他們只需要問一下Erlangmailing list,就可以很快得到一個準確而全面的回答。感謝mailing list中的所有人,特別是那些素未謀面,確有過很長很長的有意思的email來往的人。

最後,感謝我在SICS的朋友和同事們,感謝Seif Haridi教授,是他審閱了這篇論文。感謝Per Brand,是他鼓勵我寫這篇論文的。感謝分佈式系統實驗室的所有成員們,與他們的討論給我留下了深刻的印象。

謝謝大家!


182 183

附錄B 編程規範和約定

Erlang進行程序開發的

編程規範和約定1

K Eriksson, M Williams, J Armstrong

1996313

摘要

本文描述了用Erlang編寫系統的一些編程規範和建議。

註釋

本文檔只是一個初步文檔,並不完整。

EBCBase System的使用在這裏並沒有做要求,如果要使用Base System,那麼就應該在設計的很早的階段就遵守它。這些要求已經寫入了1/10268-AND 10406 UenMAPStart and Error Recovery一文。

1 這裏發表的是對Ericsson內部文檔(EPK/NP 95:035)重新整理後的版本——原文已經作爲Open Source Erlang的配套資料的一部分公開發布。


184

目錄

1 目的.................................................................................................................................187

2 結構和Erlang術語............................................................................................................187

3 軟件工程原則...................................................................................................................188

3.1 從一個模塊導出的函數越少越好........................................................................188

3.2 儘量降低模塊間的依賴........................................................................................188

3.3 將公用的代碼放入庫中........................................................................................189

3.4 複雜的髒的代碼隔離到單獨的模塊中........................................189

3.5 不要對調用者如何使用函數調用的結果作出任何假設....................................190

3.6 抽象出代碼的共用樣式或行爲............................................................................191

3.7 自頂向下................................................................................................................191

3.8 不要優化代碼........................................................................................................191

3.9 牢記最小驚詫原則..........................................................................................191

3.10 盡力消滅副作用..................................................................................................192

3.11 不要讓私有數據結構從模塊中泄漏出來..................................................192

3.12 使代碼達到最大確定性(deterministic.........................................................195

3.13 不要防禦式編程..........................................................................................196

3.14 用設備驅動隔離硬件接口..................................................................................196

3.15 doundo都在一個函數裏做...............................................................................196

4 錯誤處理...........................................................................................................................198

4.1 將錯誤處理代碼和正常情況代碼分離................................................................198

4.2 標明錯誤內核........................................................................................................198

5 進程、服務器和消息.......................................................................................................198

5.1 將一個進程的實現放在一個模塊中....................................................................198

5.2 利用進程來組織系統............................................................................................199

5.3 註冊進程................................................................................................................199

5.4 給系統中的每個真正的併發活動註冊唯一一個並行進程................................199

5.5 每個進程應該只有一個角色........................................................................199

5.6 在服務器和協議處理器中儘可能地使用通用函數............................................200

5.7 給消息打上標籤....................................................................................................200

5.8 清掉未知消息........................................................................................................201

5.9 編寫尾遞歸的進程處理函數................................................................................202

5.10 接口函數..............................................................................................................203

5.11 超時......................................................................................................................204

5.12 捕獲退出信號(trapping exits........................................................................204

6 一些Erlang的特別約定....................................................................................................204

6.1 使用record作爲標準數據結構..............................................................................204

6.2 使用選擇器(selector)和構造器(constructor..............................................204

6.3 給返回值打標籤....................................................................................................205

6.4 使用catchthrow時要極其小心..........................................................................205

6.5 使用進程字典(process dictionary)時要極其小心...........................................206

6.6 不要使用import.....................................................................................................207

6.7 導出(export)函數..............................................................................................207


185

7 特別的詞彙和風格約定...................................................................................................208

7.1 不要編寫深度嵌套的代碼....................................................................................208

7.2 不要編寫很大的模塊............................................................................................208

7.3 不要編寫很長的函數............................................................................................208

7.4 不要編寫很長的代碼行........................................................................................208

7.5 變量名....................................................................................................................208

7.6 函數名....................................................................................................................209

7.7 模塊名....................................................................................................................209

7.8 程序格式保持一致風格........................................................................................210

8 代碼文檔化.......................................................................................................................210

8.1 註明代碼歸屬........................................................................................................210

8.2 提供代碼中對規格說明的引用............................................................................211

8.3 將所有錯誤文檔化................................................................................................211

8.4 將消息中的所有的標準數據結構文檔化............................................................211

8.5 註釋........................................................................................................................211

8.6 註釋每個函數........................................................................................................212

8.7 數據結構................................................................................................................213

8.8 文件頭,版權........................................................................................................213

8.9 文件頭,修訂歷史................................................................................................213

8.10 文件頭,描述......................................................................................................213

8.11 不要註釋過時代碼——刪除它..........................................................................214

8.12 使用一個源代碼控制系統..................................................................................214

9 最普遍的錯誤...................................................................................................................214

10 必備文檔.........................................................................................................................215

10.1 模塊描述..............................................................................................................215

10.2 模塊描述..............................................................................................................215

10.3 進程......................................................................................................................216

10.4 錯誤消息..............................................................................................................216


186

1 目的

本文羅列了在使用Erlang說明和編寫軟件系統時應該考慮的一些方面。本文並不嘗試對與Erlang的使用沒有太大關係的一般的需求和設計活動給出一個完整的描述。

2 結構和Erlang術語

Erlang系統被劃分成模塊(module)。模塊由函數(function)和屬性(attribute)組成。函數要麼只能在模塊內部可訪問,要麼被導出(exported),即能夠被其它模塊中的函數調用。屬性由-開頭,被放在模塊的開頭處。

Erlang編寫的系統,所有的工作(work)都是由進程(process)來完成的。一個進程是一個可以使用其他模塊中函數的作業(job)。進程之間通過發送消息(sending message)來進行通信,一個進程可以決定準備接收什麼消息,而其它的消息就排隊等待,直到進程準備好接收它們。

一個進程可以通過與其它進程建立連接(link)來監控其它進程的存在。當一個進程終結時,會自動向與之相連的進程發送一個退出信號(exit signal),收到一個退出信號以後,一個進程的默認行爲就是終結掉自己,並向與之相連的所有進程傳播該退出信號。一個進程可以通過捕獲退出信號(trap exits)來改變這種默認行爲,這樣可以把發送給一個進程的所有退出信號轉換成正常消息。

純函數(pure function)是一個不管處於什麼樣的上下文中,只要使用的參數相同,就會返回相同結果的函數。這也是我們平常期望的一個數學函數的行爲。一個非純函數的函數我們說它具有副作用(side effects)。

如果一個函數做了下面的這些事情,一般就會產生副作用:a)發送一個消息;b)接收一個消息;c)調用exitd)調用任何會改變一個進程的環境或操作模式的BIF(例如get/1put/2erase/1process_flag/1等等)。

警告:這篇文檔中就包含有壞代碼的例子。


187

3 軟件工程原則

3.1 從一個模塊導出的函數越少越好

模塊是Erlang的基本代碼結構實體。一個模塊可以包含有大量的函數,但是隻有包含在導出列表中的函數才能夠在模塊外部被調用。從一個模塊的外部看,模塊的複雜性決定與它所導出的函數的個數。一個只導出一、兩個函數的模塊肯定比導出幾十個函數的模塊更容易理解。

用戶希望一個模塊的導出函數/非導出函數的比率越低越好,這樣他只需要理解導出函數的功能就足夠了。

還有,只要模塊的外部接口保持不變,模塊代碼的編寫者和維護者可以任意改變模塊的內部結構。

3.2 儘量降低模塊間的依賴

一個調用了許多不同模塊中的函數的模塊要比只調用了很少的幾個模塊中的函數的模塊要難以理解得多。

這是因爲每次我們修改一個模塊的接口時,我們必須要檢查所有調用了該模塊的地方。降低這種模塊間的相互依賴將會簡化這些模塊的維護工作。

我們可以通過減少一個特定模塊調用的不同模塊的數量來簡化我們的系統結構。

還要注意,模塊間的調用依賴關係最好形成的是樹型結構而不是環狀結構。例如:


188

而不要是:

3.3 將公用的代碼放入庫中

公用的代碼應該放入庫中。這個庫應該是相關的函數的集合,應該努力使得庫中包含的是同類型的函數。因此,像一個叫lists的庫只包含對列表操作的函數,這是一個好的決策;而一個叫lists_and_maths的庫既包含對列表的操作的函數,也包含有數學運算的函數,就不是一個好的決策。

最好的庫函數是沒有副作用的。含有帶副作用的函數的函數的庫限制了其可複用性。

3.4 複雜的髒的代碼隔離到單獨的模塊中

一個問題的解決通常需要綜合用到淨代碼和髒代碼,那麼就把淨代碼和髒代碼放入彼此隔離的模塊中。

髒代碼是指做了一些髒事情的代碼。如:

      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章