閱讀Erlang官方文檔經常可以讀到下面兩句:

  •   "xxx implemented using this module will have a standard set of interface functions and include  functionality for tracing and error reporting. It will also fit into an OTP supervision tree. Refer to OTP Design Principles for more information."
  •  " xxx comply to the OTP design principles".

    一句是說某模塊包含了一系列標準的接口函數來實現跟蹤和錯誤報告,這個模塊符合加入監控樹的要求,去OTP設計原則相關的章節查詢更多信息.后面一句就簡單了,說xx模塊的實現時符合OTP設計原則的.但是Erlang文檔組織的問題,文檔中并沒有對OTP設計原則給出嚴格的定義和解釋.你可能會搜索到下面的鏈接:

http://www.erlang.org/documentation/doc-5.6/pdf/design_principles.pdf

呵呵,這個僅僅是Erlang老版本的文檔而已.本文是我學習OTP設計原則的一點總結

 

OTP設計原則定義

The OTP Design Principles is a set of principles for how to structure Erlang code in terms of processes, modules and directories.

這句來自http://www.erlang.org/doc/design_principles/des_princ.html 給出了OTP設計原則的大致定義即:OTP設計原則是如何按照進程,模塊,文件夾的概念來組織代碼的一系列原則.無論用什么技術實現,設計都是解決代碼如何組織的問題.還記得我們曾經提到過設計的三層視角嗎?(猛擊這里穿越:http://www.cnblogs.com/me-sa/archive/2008/04/15/ooview.html)從概念層確定要做什么,到規約視角確定各部分之間的關系,實現視角最終通過代碼實現功能,經過這三個視角從宏觀到微觀的設計過程,代碼結構逐步確定.在Erlang的特定語境下,組織代碼的方式就是:進程,模塊,文件夾;

 

Erlang代碼的物理組織方式 

   模塊和文件夾是代碼的物理組織方式,代碼組織的最小單元是模塊(module),模塊放在不同的文件夾中,下面是一個典型的文件夾布局:

doc  存放程序文檔和配置文件
include  存放頭文件.hrl
priv  類似于Reference文件夾,存放需要引用的第三方類庫
src  源代碼文件夾
ebin 編譯的目標文件夾,存放beam文件

 

Erlang代碼的功能邏輯組織方式

    Erlang的設計哲學是把獨立的活動通過進程表達;Erlang代碼的功能邏輯組織方式,其實就是在講如何組織進程.

    Erlang/OTP進程組織的方式是監控樹(supervision tree),監控樹用worker和supervisor的概念把進程分成兩類.worker完成實際的運算工作,supervisor的職責就是監控worker的行為,如果worker出錯就通過重啟的方式使worker正常工作.監控樹將代碼組織成層級結構,我們可以基于這種架構泛型建立起一個逐級可控的容錯系統.下面是開源項目log4erl的監控樹結構:

 


   不是所有監控樹中的進程都可以成為supervisior和worker,對進程還是有特殊要求的:A.支持調試sysdebugfacilities B.能夠響應系統消息. 所謂系統消息是在監控樹中使用的有特殊意義的消息,比如trace輸出,掛起或恢復進程執行.要滿足上面的兩個要求對于開發者需要做什么呢?我們有兩個選擇:

  • 使用標準behavior實現
  • 使用sys和proc_lib模塊

    在stdlib文檔的behavior章節可以看到gen_server gen_fsm gen_event supervisior都實現了跟蹤和錯誤報告的功能,并可以處理系統消息.監控樹中進程都按照相同的模式編寫,結構上有很多類似.比如supervisor的區別僅僅在于監控哪個進程.很多worker也都是server-client,fsm(有限狀態機),和event handler的關系.Behaviours 規范化了這些通用模式,把一個進程的實現代碼分成兩部分:通用部分和回調接口.通用部分由Erlang/OTP類庫實現,其實我覺得應該稱之為框架更合適一些,回調接口函數由我們來完成,并把這些函數導出.由于回調函數往往不會被開發者直接調用,開始的時候很容易出現的問題就是忘掉導出回調函數,特別是初始化函數init.使用behavior開發是通過犧牲一點點效率來獲得通用性和一致性.對于復雜性的系統來說,一致性至關重要,一致性帶來的是更高的可讀性,可維護性.標準的Erlang的behavior有:

gen_server 實現通用client-server關系  

gen_fsm        實現有限狀態機

gen_event    實現事件處理功能

supervisor  實現監控樹中的supervisor

我們在代碼中顯示添加-behaviour(Behaviour),編譯的時候編譯器會檢查對應behavior的回調函數,如果缺失或者沒有導出會有警告.

  這些標準的behavior內部實現使用的是sys和proc_lib,所以我們可以直接使用這兩個模塊達到同樣的效果,后面我會有專門的文章說這兩個模塊.

 Erlang/OTP中的能完成特定功能集合的組件被稱為application.  監控樹是進程的組織方式,application是Erlang功能的組織方式.

 

總結一下:

  1. Erlang OTP設計原則關注的是Erlang代碼的組織方式
  2. Erlang代碼分割存放在不同的模塊,模塊存放在不同的文件夾
  3. Erlang代碼的邏輯組織方式是監控樹
  4. 可以成為supervisior和worker需要支持跟蹤,錯誤報告以及響應系統消息
  5. 標準behavior實現了上述要求,也可以通過sys和proc_lib模塊實現
  6.  監控樹是進程的組織方式,application是Erlang功能的組織方式

 

  純理論的東西總是顯得空洞,后面的文章中我們會不斷回顧這部分內容,將理論和編程實踐做對應.

  周末愉快!