204

今日教えられているソフトウェア エンジニアリングは、オブジェクト指向プログラミングと「自然な」オブジェクト指向の世界観に完全に焦点を当てています。ドメイン モデルをクラス モデルに変換する方法を説明する詳細な方法論があり、いくつかのステップと、ユース ケース図やクラス図などの多くの (UML) 成果物があります。多くのプログラマーはこのアプローチを取り入れており、オブジェクト指向アプリケーションをゼロから設計する方法について良い考えを持っています。

新しい誇大宣伝は関数型プログラミングであり、多くの本やチュートリアルで教えられています。しかし、関数型ソフトウェア エンジニアリングはどうでしょうか。Lisp と Clojure について読んでいるときに、次の 2 つの興味深い意見に出くわしました。

  1. 関数型プログラムは、トップダウンではなくボトムアップで開発されることが多い ('On Lisp', Paul Graham)

  2. 関数型プログラマーは、OO プログラマーがオブジェクト/クラスを使用するマップを使用します (「Clojure for Java Programmers」、Rich Hickley による講演)。

では、Lisp や Clojure などの関数型アプリケーションの体系的な (モデルベースの?) 設計の方法論は何でしょうか? 一般的な手順、使用するアーティファクト、それらを問​​題空間からソリューション空間にマッピングするにはどうすればよいですか?

4

13 に答える 13

168

ソフトウェア エンジニアリングの人々がまだ関数型プログラミングを発見していないことを神に感謝します。ここにいくつかの類似点があります:

  • オブジェクト指向の「設計パターン」の多くは、高階関数として捉えられています。たとえば、Visitor パターンは、機能の世界では「フォールド」として知られています (または、先のとがった理論家であれば、「カタモルフィズム」)。関数型言語では、データ型はほとんどがツリーまたはタプルであり、すべてのツリー型にはそれに関連付けられた自然なカタモルフィズムがあります。

    これらの高階関数には、「自由定理」とも呼ばれるプログラミングの特定の法則が伴うことがよくあります。

  • 関数型プログラマーは、OO プログラマーよりもダイアグラムをあまり使用しません。OO ダイアグラムで表現されるものの多くは、代わりに、または「モジュール型」と考える必要がある「シグネチャ」で表現されます。Haskell には「型クラス」もあり、これはインターフェース型に少し似ています。

    型を使用する関数型プログラマーは一般に、「型を正しく取得すると、コードは実質的にそれ自体で記述される」と考えています。

    すべての関数型言語が明示的な型を使用しているわけではありませんが、Scheme/Lisp/Clojure を学習するための優れた本であるHow To Design Programs本は、型に密接に関連する「データ記述」に大きく依存しています。

では、Lisp や Clojure などの関数型アプリケーションの体系的な (モデルベースの?) 設計の方法論は何でしょうか?

データの抽象化に基づく設計手法はどれもうまく機能します。たまたま、言語に明示的な型があると簡単だと思いますが、明示的な型がなくても機能します。関数型プログラミングに簡単に適応できる、抽象データ型の設計方法に関する優れた本は、Barbara Liskov と John Guttag による初版のプログラム開発における抽象化と仕様です。Liskov は、その業績の一部でチューリング賞を受賞しました。

Lisp に固有のもう 1 つの設計方法論は、作業している問題領域でどの言語拡張機能が役立つかを判断し、衛生的なマクロを使用してこれらの構造を言語に追加することです。この種の設計について読むには、Matthew Flatt の記事、Creating Languages in Racket を参照してください。記事はペイウォールの背後にある可能性があります。「ドメイン固有の埋め込み言語」という用語を検索すると、この種の設計に関するより一般的な資料を見つけることもできます。Matthew Flatt が扱っている内容を超えた特定のアドバイスや例については、おそらく Graham のOn LispANSI Common Lispから始めると思います。

一般的な手順、使用するアーティファクトは何ですか?

一般的な手順:

  1. プログラム内のデータとその操作を特定し、このデータを表す抽象データ型を定義します。

  2. 共通のアクションや計算パターンを特定し、高階関数やマクロとして表現します。リファクタリングの一環として、この手順を実行することを期待してください。

  3. 型指定された関数型言語を使用している場合は、型チェッカーを早い段階で頻繁に使用してください。Lisp または Clojure を使用している場合、ベスト プラクティスは、最初に単体テストを含めて関数コントラクトを作成することです。これは、最大限のテスト駆動開発です。また、プラットフォームに移植された QuickCheck のバージョンを使用することをお勧めします。これは、あなたの場合はClojureCheckと呼ばれているようです。これは、高階関数を使用するコードのランダム テストを構築するための非常に強力なライブラリです。

于 2011-02-05T06:17:21.723 に答える
46

Clojure については、古き良きリレーショナル モデリングに戻ることをお勧めします。Out of the Tarpitは感動的な読み物です。

于 2011-01-31T15:07:54.500 に答える
38

個人的には、OO 開発の通常の優れたプラクティスはすべて、関数型プログラミングにも適用できることがわかりました。方法論の観点からは、根本的に異なることをする必要はありません。

私の経験は、近年 Java から Clojure に移行したことに由来しています。

いくつかの例:

  • ビジネス ドメイン/データ モデルを理解する- オブジェクト モデルを設計する場合でも、ネストされたマップを使用して機能的なデータ構造を作成する場合でも、同様に重要です。いくつかの点で、FP は機能/プロセスとは別にデータ モデルを考えるように促すため、より簡単になる可能性がありますが、それでも両方を行う必要があります。

  • 設計におけるサービス指向- 実際、FP の観点からは非常にうまく機能します。これは、典型的なサービスは、実際にはいくつかの副作用を伴う機能にすぎないためです。Lisp の世界で時折支持されるソフトウェア開発の「ボトムアップ」の考え方は、実際には、別の形をした優れたサービス指向 API 設計原則にすぎないと思います。

  • テスト駆動開発- FP 言語で適切に機能します。実際、純粋な関数は、ステートフルな環境をセットアップする必要なく、明確で再現可能なテストを作成するのに非常に適しているため、実際にはさらに優れている場合があります。データの整合性をチェックするために別のテストを作成することもできます (たとえば、オブジェクト指向言語ではコンパイル時にクラス定義がこれを強制するという事実とのバランスをとるために、このマップには私が期待するすべてのキーが含まれていますか)。

  • プロトタイピング / イテレーション- FP と同様に機能します。ツール/DSLの構築とREPLでの使用が非常に得意であれば、ユーザーとライブでプロトタイプを作成することさえできるかもしれません。

于 2011-01-31T15:27:02.280 に答える
13

OO プログラミングは、データと動作を密接に結び付けます。関数型プログラミングはこの 2 つを分離します。したがって、クラス図はありませんが、データ構造はあり、特に代数データ型があります。これらの型は、構成によって不可能な値を排除するなど、ドメインに非常に厳密に一致するように記述できます。

したがって、それに関する本や本はありませんが、ことわざにあるように、不可能な値を表現できないようにするための確立されたアプローチがあります。

そうすることで、特定のタイプのデータを代わりに関数として表現することについて、さまざまな選択を行うことができます。逆に、特定の関数を代わりにデータ型の結合として表現して、シリアル化、より厳密な仕様、最適化などを得ることができます。 .

次に、ある種の代数を確立するように、adts に関数を記述します。つまり、これらの関数に適用される固定の法則があります。いくつかは冪等かもしれません - 複数のアプリケーションの後でも同じです。一部は連想的です。一部は推移的などです。

これで、行儀の良い法則に従って構成する関数を持つドメインができました。シンプルな組み込み DSL!

ああ、そしてプロパティが与えられれば、もちろんそれらの自動化されたランダム化されたテスト (ala QuickCheck) を書くことができます..そしてそれはほんの始まりにすぎません.

于 2011-02-02T01:25:05.537 に答える
7

オブジェクト指向設計は、ソフトウェアエンジニアリングと同じものではありません。ソフトウェアエンジニアリングは、要件から稼働中のシステムに、時間どおりに、低い欠陥率で移行するプロセス全体と関係があります。関数型プログラミングはOOとは異なる場合がありますが、要件、高レベルで詳細な設計、検証とテスト、ソフトウェアメトリクス、推定、およびその他すべての「ソフトウェアエンジニアリング関連」を排除するものではありません。

さらに、関数型プログラムはモジュール性やその他の構造を示します。詳細な設計は、その構造の概念の観点から表現する必要があります。

于 2012-04-02T21:22:03.483 に答える
5

1 つのアプローチは、選択した関数型プログラミング言語内で内部 DSL を作成することです。「モデル」は、DSL で表現された一連のビジネス ルールです。

于 2011-01-31T15:06:18.383 に答える
5

別の投稿に対する私の回答を参照してください。

Clojure は関心の分離にどのようにアプローチしますか?

FP アプローチを使用する大規模なアプリケーションをどのように構築するかについて、この主題についてさらに書く必要があることに同意します (さらに、FP 駆動型 UI を文書化するためにさらに多くのことを行う必要があります)。

于 2011-01-31T15:14:32.023 に答える
3

これは素朴で単純化されていると思われるかもしれませんが、「デザイン レシピ」 (Felleisen 氏らの著書HtDPで提唱されている、プログラミングに適用される問題解決への体系的なアプローチ) は、あなたが探しているものに近いと思います。

ここに、いくつかのリンクがあります:

http://www.northeastern.edu/magazine/0301/programming.html

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.86.8371

于 2011-02-01T16:46:49.600 に答える
2

ビヘイビア駆動開発は、Clojure と SBCL の両方でコードを迅速に開発するのに自然に適合することがわかりました。関数型言語で BDD を活用することの本当の利点は、手続き型言語を使用する場合よりもはるかに細かい粒度の単体テストを作成する傾向があることです。これは、問題をより小さな機能の塊に分解する作業がはるかに優れているためです。

于 2011-04-19T01:02:33.777 に答える
2

リチャード・バード教授とオックスフォード大学 (英国) のプログラミング代数グループに関連する「プログラム計算」/「計算による設計」スタイルがあります。

個人的には、AoP グループの作品は好きですが、自分でこのようにデザインを実践する規律はありません。しかし、それは私の欠点であり、プログラム計算の欠点ではありません。

于 2011-02-06T17:50:15.977 に答える
1

正直なところ、関数型プログラムの設計レシピが必要な場合は、Haskell の Prelude などの標準関数ライブラリを参照してください。FP では、通常、パターンは高次の手順 (関数を操作する関数) 自体によってキャプチャされます。そのため、パターンが見られる場合、多くの場合、そのパターンをキャプチャするために高次関数が単純に作成されます。

良い例は fmap です。この関数は、関数を引数として取り、それを 2 番目の引数のすべての「要素」に適用します。これは Functor 型クラスの一部であるため、Functor の任意のインスタンス (リスト、グラフなど) をこの関数の 2 番目の引数として渡すことができます。2 番目の引数のすべての要素に関数を適用する一般的な動作をキャプチャします。

于 2011-02-06T17:09:19.533 に答える
-7

良い、

一般に、多くの関数型プログラミング言語は、大学で「小さなおもちゃの問題」のために長い間使用されています。

OOPは「状態」のために「並列プログラミング」が難しいため、現在人気が高まっています.また、Google MapReduceのような目前の問題には関数型スタイルが適している場合もあります.

機能担当者が壁にぶつかったとき [1.000.000 行のコードを超えるシステムを実装しようとする] と、そのうちのいくつかは流行語を使った新しいソフトウェア エンジニアリング方法論を持ってくるでしょう :-)。彼らは古い質問に答える必要があります: システムをピースに分割して、各ピースを一度に 1 つずつ「噛む」ことができるようにする方法は? [機能的スタイルを使用して、反復的で漸進的な進化的方法で作業します。

Functional Style がオブジェクト指向スタイルに影響を与えることは確かです。

しかし、関数型プログラムは、このような大規模システムに使用されるでしょうか? それらは主流になるでしょうか? それが問題です。

そして、そのような大規模なシステムを実装せずに現実的な方法論を実現することはできず、手を汚します。最初に手を汚してから、解決策を提案する必要があります。解決策 ・「リアルな苦労や汚れ」のない提案は「空想」になります。

于 2013-05-31T20:38:49.887 に答える