2013-10-13 35 views
44

在OCaml中編寫大型軟件項目的最佳實踐是什麼?在OCaml中設計大型項目

你如何構建你的項目?

OCaml的哪些功能應該也應該不用於簡化代碼管理?例外?一流的模塊? GADTs?對象類型?

構建系統?測試框架?宬?

我發現偉大的recommendations haskell,我認爲這將是一件好事,OCaml類似。

回答

57

我將在我熟悉的條件下回答一箇中等規模的項目,即100K和1M行源代碼以及最多10個開發人員。這是我們使用的是什麼,現在,一個項目兩個月前開始在2013年八月

構建系統和組織代碼:

  • 一個源能夠shell腳本定義PATH和其他變量爲我們的項目
  • 一個.ocamlinit文件在我們的項目的根目錄加載了一堆庫,當開始一個頂級會話時
  • omake,這是快速的(與平行構建-j選項);但我們避免犯瘋狂定製omake插件
  • 一個根Makefile文件包含了所有必要的目標(建立,構建,測試,清潔,更多)
  • 一級子目錄,而不是兩個
  • 最子目錄打造成爲OCaml的庫
  • 某些子目錄包含其他內容(設置,腳本等)
  • OCAMLPATH包含項目的根目錄;每個庫子目錄生成一個META文件,使用#require從頂層訪問項目的所有OCaml部分。
  • 只有一個OCaml的可執行文件,是爲整個項目(節省了大量的鏈接時,仍然不知道爲什麼)
  • 庫通過一個安裝腳本使用OPAM
  • 當地OPAM包軟件製作安裝,它沒有在官方OPAM庫
  • 我們使用OPAM開關,它是我們的項目命名的別名,避免在同一臺機器上與其他項目衝突

源代碼編輯:

  • emacs的與OPAM包OCP縮進和OCP-指數

源的控制和管理:

  • 我們使用Git和github上
  • 所有新的代碼是同行評審通過github上引入請求
  • 非opam非github庫的tarball存儲在一個單獨的git倉庫中(如果歷史記錄變得太大,可能會被吹掉)
  • bleeding現有在github〜邊緣的庫叉到我們的github帳戶,並通過我們自己的本地OPAM包

使用OCaml的安裝:

  • 的OCaml不會壞的編程習慣補償;教好口味超出了這個答案的範圍。 http://ocaml.org/learn/tutorials/guidelines.html是一個很好的起點。
  • 的OCaml 4.01.0使比以前重用記錄字段標籤和變型構造(即type t1 = {x:int} type t2 = {x:int;y:int} let t1_of_t2 ({x}:t2) : t1 = {x}現在工作)
  • 我們試圖在我們自己的代碼
  • 我們不使用類不使用camlp4語法擴展更容易和對象,除非通過一些外部庫
  • 以來的OCaml 4.01.0理論規定,我們應該更喜歡經典的變體在多態性變異
  • 我們使用異常錯誤提示,讓他們經歷愉快,直到我們的主服務器循環捉住他們和解釋他們作爲「內部錯誤」(默認),「壞請求」,或其他
  • 可以在本地使用Exit或Not_found等異常,但在模塊接口中我們更願意使用選項。

庫,協議框架:

  • 我們使用的電池爲從OCaml的標準庫丟失了所有商品的功能;對於其他我們有一個「util」庫
  • 我們使用Lwt進行異步編程,沒有語法擴展,並且綁定操作符(>> =)是我們使用的唯一操作符(如果您必須知道,我們會不情願地使用camlp4預處理來更好地對綁定點進行異常跟蹤)。
  • 我們使用HTTP和JSON第三方軟件進行溝通,我們希望所有的現代服務業提供背後nginx的此類API
  • 爲服務HTTP,我們運行我們自己的SCGI服務器(的OCaml SCGI)
  • 作爲HTTP客戶端,我們使用Cohttp
  • 的JSON序列化,我們使用atdgen

「雲」 服務:

  • 我們使用了很多他們的作爲它們通常便宜,易於與我們交互並解決可擴展性和維護問題。

測試:

  • 我們爲快速測試和一個緩慢的測試之一化妝/ omake目標
  • 快速測試是單元測試;每個模塊可以提供「測試」功能; test.ml文件運行測試列表
  • 慢速測試是那些涉及運行多個服務的測試;這些都是專門爲我們的項目製作的,但它們儘可能地覆蓋了作爲生產服務。除了我們設法不干擾生產的雲服務之外,所有產品都可以在Linux或MacOS上本地運行。

設置這一切有相當多的工作,特別是對不熟悉OCaml的人。目前還沒有框架能夠完成所有這些工作,但至少您可以選擇這些工具。

+0

爲什麼不是async而不是lwt?那麼不需要任何camlp4。另外,不要在任何地方使用ocamlnet? – rgrinberg

+0

在兩個地方你說OCaml 4.01.0使一些可能的東西。你能說出4.01.0的哪個功能呢?這會改善你已經很好的答案。謝謝。 –

+0

@rginberg OCamlnet是單片機,它的網絡庫不能很好地與Lwt搭配使用。我們使用OCamlnet的Netstring部分的精簡版本,它不依賴於OCamlnet的C代碼。 –

5

這一個可能不完全回答你的問題,但這裏是我關於構建環境體驗:

我真的很感激OASIS。它有一套很好的功能,不僅可以幫助構建項目,還可以編寫文檔和支持測試環境。

生成系統

  • OASIS生成從說明書(_oasis文件),它的工作原理基本上與建築物腳本setup.ml文件。它接受-configure,-build,-test,-distclean標誌。我在處理不同的GNU和其他通常使用Makefiles的項目時習慣了他們,我發現可以在這裏自動使用它們,這很方便。
  • Makefiles。除了生成setup.ml之外,還可以使用上述所有選項生成Makefile。

結構

通常我的項目,該項目是由OASIS建有至少三個目錄:src_buildscriptstests

  • 在前一個目錄中,所有源文件都存儲在一個目錄中:source(.ml)和interface(.mli)文件存儲在一起。可能是如果項目太大,值得引入更多的子目錄。
  • _build目錄受OASIS構建系統的影響。它存儲源文件和目標文件,我喜歡這些構建文件不會受到源文件的干擾,所以我可以很容易地刪除它,以免出現問題。
  • 我在scripts目錄中存儲多個shell腳本。其中一些用於測試執行和接口文件生成。
  • 所有用於存儲在單獨目錄中的測試的輸入和輸出文件。

接口/文檔

使用的接口文件(.mli)有優點和缺點我。它確實有助於查找類型錯誤,但是如果您有它們,則在對代碼進行更改或改進時,也必須對它們進行編輯。有時忘記這會導致令人討厭的錯誤。

但我喜歡接口文件的主要原因是文檔。我使用ocamldoc自動生成(OASIS支持此功能-doc標誌)html頁面與文檔。在我看來,只需在界面中編寫描述每個函數的註釋就足夠了,而不是在代碼中插入註釋。在OCaml中,函數通常簡短且簡潔,如果需要在那裏插入額外的註釋,可能會更好地分割函數。

也請注意-i標誌爲ocamlc。編譯器可以自動生成模塊的接口文件。

測試

我沒有找到支持測試(我想有一些ocamltest應用程序)一個合理的解決方案,這就是爲什麼我用我自己的腳本執行和驗證用例。幸運的是,當setup.ml-test標誌一起運行時,OASIS支持執行自定義命令。

我不會長時間使用OASIS,如果有人知道其他很酷的功能,我也想知道它們。

另外,它你不知道OPAM,這絕對值得一看。沒有它,安裝和管理新軟件包是一場噩夢。

10

OASIS

爲了增加帕維爾答案:

免責聲明:我是OASIS的作者。

OASIS還有oasis2opam,可以幫助快速創建OPAM包和oasis2debian來創建Debian軟件包。如果您想要創建一個「發佈」目標,以自動執行上傳程序包的大部分任務,這非常有用。

OASIS還附帶一個名爲oasis-dist.ml的腳本,該腳本自動創建用於上傳的tarball。

看這一切在https://github.com/ocaml.org

測試

我用OUnit做了所有的考試。如果你習慣於xUnit測試,這很簡單而且非常高效。

源控制/管理

免責聲明:我forge.ocamlcore.org的擁有者/維護者(又名forge.o.o)

如果你想使用git,我建議使用github上。這對審查非常有效。

如果您使用darcs或subversion,您可以在forge.o.o上創建一個帳戶。

在這兩種情況下都有一個公共郵件列表,您必須發送所有提交通知,以便每個人都可以看到它們並對其進行檢查。您可以在forge.o.o上使用Google羣組或郵寄列表。

我建議有一個很好的網頁(github或forge.o.o),並在每次提交時創建OCamldoc文檔。如果您擁有龐大的代碼庫,這將幫助您從頭開始使用OCamldoc生成的文檔(並快速修復它)。

我建議在達到穩定階段時創建tarball。不要只依靠檢查最新的git/svn版本。這個技巧在過去爲我節省了幾個小時的工作。正如馬丁所說,將所有tarball存儲在一箇中心位置(一個git存儲庫是一個好主意)。

+0

如何組織您的項目以將您的單元測試合併到OASIS構建中?你在哪裏放置測試文件,以及如何執行測試?例? – brooks94