web-dev-qa-db-ja.com

OCamlで大規模なプロジェクトを設計する

OCamlで大規模なソフトウェアプロジェクトを作成するためのベストプラクティスは何ですか?

プロジェクトをどのように構成しますか?

コード管理を簡素化するためにOCamlのどの機能を使用すべきか、使用すべきではありませんか?例外?ファーストクラスのモジュール? GADT?オブジェクトタイプ?

システムを構築しますか?テストフレームワーク?ライブラリスタック?

私はhaskellにとって素晴らしい recommendations を見つけました、そして私はOCamlのために似たようなものを持っているのは良いことだと思います。

49
John Rivers

私が精通している条件、つまり10万から100万行のソースコードと最大10人の開発者の中規模のプロジェクトに答えるつもりです。これは、2か月前の2013年8月に開始されたプロジェクトで現在使用しているものです。

ビルドシステムとコード編成:

  • 1つのソース可能なシェルスクリプトは、プロジェクトのPATHおよびその他の変数を定義します
  • プロジェクトのルートにある1つの.ocamlinitファイルは、トップレベルセッションを開始するときに多数のライブラリをロードします
  • omake、これは高速です(並列ビルドの場合は-jオプションを使用)。しかし、私たちはクレイジーなカスタムomakeプラグインを作ることを避けます
  • 1つのルートMakefileには、すべての重要なターゲット(セットアップ、ビルド、テスト、クリーンなど)が含まれています。
  • 2つではなく1つのレベルのサブディレクトリ
  • ほとんどのサブディレクトリはOCamlライブラリに組み込まれています
  • 一部のサブディレクトリには他のもの(セットアップ、スクリプトなど)が含まれています
  • OCAMLPATHには、プロジェクトのルートが含まれています。各ライブラリサブディレクトリはMETAファイルを生成し、プロジェクトのすべてのOCaml部分に#requireを使用してトップレベルからアクセスできるようにします。
  • プロジェクト全体で1つのOCaml実行可能ファイルのみがビルドされます(リンク時間を大幅に節約できますが、理由はわかりません)
  • ライブラリは、opamを使用したセットアップスクリプトを介してインストールされます
  • ローカルopamパッケージは、公式のopamリポジトリにないソフトウェア用に作成されています
  • プロジェクトにちなんで名付けられたエイリアスであるopamスイッチを使用して、同じマシン上の他のプロジェクトとの競合を回避します

ソースコードの編集:

  • opamパッケージocp-indentおよびocp-indexを使用したemacs

ソース管理と管理:

  • gitとgithubを使用します
  • すべての新しいコードは、githubプルリクエストを介してピアレビューされます
  • 非opam非githubライブラリのtarballは、別のgitリポジトリに保存されます(履歴が大きくなりすぎると吹き飛ばされる可能性があります)
  • ブリーディング-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を使用してサードパーティのソフトウェアと通信し、すべての最新のサービスがそのようなAPIを提供することを期待しています
  • hTTPを提供するために、nginxの背後で独自のSCGIサーバー(ocaml-scgi)を実行します
  • hTTPクライアントとしてCohttpを使用します
  • jSONシリアル化には、atdgenを使用します

「クラウド」サービス:

  • それらは通常安価で、操作が簡単で、スケーラビリティとメンテナンスの問題を解決するため、かなり多く使用しています。

テスト:

  • 高速テスト用と低速テスト用の1つのmake/omakeターゲットがあります
  • 高速テストは単体テストです。各モジュールは「テスト」機能を提供する場合があります。 test.mlファイルはテストのリストを実行します
  • 遅いテストとは、複数のサービスの実行を伴うテストです。これらは私たちのプロジェクトのために特別に作成されていますが、生産サービスとして可能な限りカバーしています。本番環境に干渉しない方法を見つけたクラウドサービスを除いて、すべてがLinuxまたはMacOSのいずれかでローカルに実行されます。

これをすべて設定することは、特にOCamlに精通していない人にとっては、かなりの作業です。これらすべてを処理するフレームワークはまだありませんが、少なくともツールを選択することができます。

59
Martin Jambon

オアシス

Pavelの回答に追加するには:

免責事項:私はOASISの作者です。

OASISには、OPAMパッケージをすばやく作成するのに役立つoasis2opamと、Debianパッケージを作成するためのoasis2debianもあります。これは、パッケージをアップロードするためのほとんどのタスクを自動化する「リリース」ターゲットを作成する場合に非常に役立ちます。

OASISには、アップロード用のtarballを自動的に作成するoasis-dist.mlというスクリプトも付属しています。

これをすべて https://github.com/ocaml.org で見てください。

テスト

OUnit を使用してすべてのテストを実行します。 xUnitのテストに慣れている場合、これは単純で非常に効率的です。

ソース管理/管理

免責事項:私はforge.ocamlcore.org(別名forge.o.o)の所有者/保守者です

Gitを使用したい場合は、githubを使用することをお勧めします。これはレビューに非常に効率的です。

DarcsまたはSubversionを使用している場合は、forge.o.oでアカウントを作成できます。

どちらの場合も、すべてのコミット通知を送信する公開メーリングリストを用意しておく必要があります。そうすれば、誰もがそれらを表示して確認できます。 Googleグループまたはforge.o.oのメーリングリストのいずれかを使用できます。

コミットするたびに、OCamldocドキュメントを含むNice Web(githubまたはforge.o.o)ページを作成することをお勧めします。巨大なコードベースがある場合、これはOCamldocで生成されたドキュメントを最初から使用するのに役立ちます(そしてそれをすばやく修正します)。

安定した段階になったら、タールボールを作ることをお勧めします。最新のgit/svnバージョンをチェックするだけに頼らないでください。このヒントにより、過去の作業時間を節約できました。 Martinが言ったように、すべてのtarballを中央の場所に保存します(gitリポジトリはそのための良いアイデアです)。

10
gildor

これはおそらくあなたの質問に完全には答えませんが、ビルド環境に関する私の経験は次のとおりです。

本当に感謝しています [〜#〜] oasis [〜#〜] 。プロジェクトの構築だけでなく、ドキュメントの作成やテスト環境のサポートにも役立つ、優れた機能セットを備えています。

ビルドシステム

  • OASISは、仕様からsetup.mlファイル(_oasisファイル)を生成します。これは、基本的にビルドスクリプトとして機能します。 -configure-build-test-distcleanフラグを受け入れます。さまざまなGNUや、通常Makefileを使用する他のプロジェクトで作業している間、私はそれらにかなり慣れていました。ここでそれらすべてを自動的に使用できると便利です。
  • Makefile。 setup.mlを生成する代わりに、上記のすべてのオプションを使用してMakefileを生成することもできます。

構造

通常、OASISによって構築された私のプロジェクトには、少なくとも3つのディレクトリがあります:src_buildscripts、およびtests

  • 前者のディレクトリでは、すべてのソースファイルが1つのディレクトリに保存されます。ソース(.ml)ファイルとインターフェイス(.mli)ファイルは一緒に保存されます。プロジェクトが大きすぎる場合は、サブディレクトリを追加する価値があります。
  • _buildディレクトリは、OASISビルドシステムの影響下にあります。ソースファイルとオブジェクトファイルの両方がそこに保存され、ビルドファイルがソースファイルに干渉しないのが好きなので、何か問題が発生した場合に簡単に削除できます。
  • 複数のシェルスクリプトをscriptsディレクトリに保存します。それらのいくつかは、テストの実行とインターフェイスファイルの生成用です。
  • テスト用のすべての入力ファイルと出力ファイルは、別のディレクトリに保存します。

インターフェース/ドキュメント

インターフェイスファイル(.mli)の使用には、私にとって長所と短所の両方があります。タイプエラーを見つけるのは本当に役立ちますが、タイプエラーがある場合は、コードを変更または改善するときにもそれらを編集する必要があります。これを忘れると、厄介なエラーが発生することがあります。

しかし、私がインターフェースファイルが好きな主な理由はドキュメントです。 ocamldoc を使用して、ドキュメントを含むhtmlページを自動的に生成します(OASISはこの機能を-docフラグでサポートします)。私の意見では、インターフェイスの各関数を説明するコメントを記述し、コードの途中にコメントを挿入しないで十分です。 OCamlでは、関数は通常短く簡潔であり、そこに追加のコメントを挿入する必要がある場合は、関数を分割する方がよい場合があります。

ocamlc-iフラグにも注意してください。コンパイラは、モジュールのインターフェイスファイルを自動的に生成できます。

テスト

テストをサポートするための合理的な解決策が見つかりませんでした(ocamltestアプリケーションが欲しい)。そのため、ユースケースの実行と検証に独自のスクリプトを使用しています。幸い、OASISは、setup.ml-testフラグで実行されている場合のカスタムコマンドの実行をサポートしています。

私はOASISを長い間使用していません。他の優れた機能を知っている人がいたら、それらについても知りたいと思います。

また、あなたが気づいていないなら [〜#〜] opam [〜#〜] 、それは間違いなく一見の価値があります。それがなければ、新しいパッケージをインストールして管理することは悪夢です。

5