機能プログラミングのためのソフトウェアエンジニアリング方法はありますか? [閉まっている

StackOverflow https://stackoverflow.com/questions/4852251

質問

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

新しい誇大宣伝は機能的なプログラミングであり、多くの本やチュートリアルで教えられています。しかし、機能的なソフトウェアエンジニアリングはどうですか? LispとClojureについて読んでいる間、私は2つの興味深い声明について来ました:

  1. 機能的プログラムは、トップダウンの代わりにボトムアップ( 'on lisp'、ポールグラハム)であることが多いことがよくあります

  2. 機能プログラマーは、OOプログラマーがオブジェクト/クラスを使用するマップを使用します(「Javaプログラマー用のClojure」、Rich Hickleyによる話)。

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

役に立ちましたか?

解決

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

  • 多くのOO「設計パターン」は、高次関数としてキャプチャされます。たとえば、訪問者のパターンは、機能の世界では「折り畳み」として知られています(または、あなたが先のとがった理論家である場合、「catamorphism」)。機能的言語では、データ型はほとんどが木またはタプルであり、すべての木タイプにはそれに関連する自然なカタルフィアがあります。

    これらの高次関数には、多くの場合、プログラミングの特定の法則、別名「無料定理」があります。

  • 機能的なプログラマーは、OOプログラマーよりもはるかに少ない図を使用しています。 OO図で表現されているものの多くは、代わりにで表現されています 種類, 、または「署名」で、「モジュールタイプ」と考える必要があります。 Haskellには「タイプクラス」もあります。これは、インターフェイスタイプのようなものです。

    タイプを使用する機能的なプログラマーは、一般に「タイプを正しく取得したら、コードが実際に自分自身を書き込む」と考えています。

    すべての機能言語が明示的なタイプを使用するわけではありませんが、 プログラムを設計する方法 Bookは、学習スキーム/Lisp/Clojureの優れた本である「データの説明」に大きく依存しており、タイプに密接に関連しています。

では、機能的アプリケーションの体系的な(モデルベース?)設計、つまりLISPまたはClojureの方法論の方法は何ですか?

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

LISPに固有のもう1つの設計方法論は、作業中の問題ドメインでどの言語拡張機能が役立つかを決定し、衛生的なマクロを使用してこれらのコンストラクトを言語に追加することです。この種のデザインについて読むのに良い場所は、マシュー・フラットの記事です ラケットで言語を作成します. 。この記事はペイウォールの背後にある可能性があります。また、「ドメイン固有の埋め込み言語」という用語を検索することにより、この種のデザインに関するより一般的な資料を見つけることもできます。マシュー・フラットがカバーしているものを超えた特定のアドバイスと例のために、私はおそらくグラハムのから始めるでしょう Lispで 多分 ANSI CommonLisp.

一般的な手順は何ですか、どのようなアーティファクトを使用していますか?

一般的なステップ:

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

  2. 一般的なアクションまたは計算パターンを特定し、それらをより高次関数またはマクロとして表現します。リファクタリングの一環としてこのステップを踏むことを期待してください。

  3. タイプされた機能言語を使用している場合は、タイプチェッカーを早期に頻繁に使用してください。 LISPまたはClojureを使用している場合、ベストプラクティスは、最初にユニットテストを含む関数契約を作成することです。これは、MAXのテスト駆動型開発です。そして、あなたはあなたのプラットフォームに移植されたQuickCheckeckのあらゆるバージョンを使用したいと思うでしょう。 Clojurecheck. 。これは、高次関数を使用するコードのランダムテストを構築するための非常に強力なライブラリです。

他のヒント

Clojureについては、古き良きリレーショナルモデリングに戻ることをお勧めします。 ターピットから 心に強く訴える読み物です。

個人的には、OO開発からの通常の良い実践はすべて、機能プログラミングにも適用されることがわかりました。方法論の観点からは、根本的に異なることを実際に行う必要はありません。

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

いくつかの例:

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

  • デザインのサービスオリエンテーション - 典型的なサービスは実際には副作用を伴う機能であるため、実際にはFPの観点から非常にうまく機能します。 LISPの世界で支持される時々、ソフトウェア開発の「ボトムアップ」ビューは、実際には別の装いで優れたサービス指向のAPIデザインの原則であると思います。

  • テスト駆動型開発 - FP言語ではうまく機能しますが、実際には、純粋な機能は、ステートフル環境を設定する必要なく、明確で繰り返し可能なテストを書くのに非常にうまくいくからです。また、データの整合性を確認するために個別のテストを作成することもできます(たとえば、このマップには、OO言語でクラス定義がコンパイル時にこれを強制するという事実のバランスをとるために、私が期待するすべてのキーがあります)。

  • プロトタイ /反復 - FPと同様に機能します。ツール / DSLの構築とそれらをREPLで使用するのが非常に得意であれば、ユーザーと一緒にライブをプロトタイプすることができるかもしれません。

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

そのため、本や本はありませんが、sayingにあるように、不可能な価値を表現できないものにするための十分に確立されたアプローチがあります。

そうすることで、特定のタイプのデータを代わりに関数として表現することについてさまざまな選択を行うことができ、逆に、特定の機能を代わりにデータ型の結合として表すことができます。 。

それを考えると、あなたはあなたのADTを介して関数を書き込み、何らかのを確立するように 代数 - つまり、これらの機能のために保持される固定法があります。いくつかはおそらく等隊です - 複数のアプリケーションの後に同じです。いくつかは連想的です。一部は推移的です。

今、あなたは、うまく振る舞った法則に従って構成する関数を持っているドメインを持っています。シンプルな埋め込みDSL!

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

オブジェクト指向のデザインは、ソフトウェアエンジニアリングと同じものではありません。ソフトウェアエンジニアリングは、要件から作業システムへ、時間通りに、欠陥率が低い方法のプロセス全体に関係しています。機能的なプログラミングはOOとは異なる場合がありますが、要件、高レベルおよび詳細な設計、検証とテスト、ソフトウェアメトリック、推定、その他の「ソフトウェアエンジニアリングのもの」を廃止しません。

さらに、機能プログラムはモジュール性やその他の構造を示します。あなたの詳細なデザインは、その構造の概念の観点から表現する必要があります。

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

別の投稿への私の答えを参照してください:

Clojureは懸念をどのように分離しますか?

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

これは素朴で単純化されていると考えられるかもしれませんが、「デザインレシピ」(Felleisen et al。が彼らの本で提唱しているように、プログラミングに適用される問題解決への体系的なアプローチは HTDP)あなたが探しているように見えるものに近いでしょう。

ここで、いくつかのリンク:

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

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

行動駆動型開発は、ClojureとSBCLの両方で急速に発展するコードに自然に適していることがわかりました。機能的な言語でBDDを活用することの本当の利点は、問題をより小さな機能性に分解するというはるかに良い仕事をするため、手続き型言語を使用するときよりもはるかに細かい粒穀物単位テストを書く傾向があることです。

私は最近この本を見つけました:機能的および反応性ドメインモデリング

私はあなたの質問に完全に一致していると思います。

本の説明から:

機能的および反応性ドメインモデリングは、純粋な機能の観点からドメインモデルを考える方法と、より大きな抽象化を構築するためにそれらを構成する方法を教えてくれます。機能的なプログラミングの基本から始めて、複雑なドメインモデルを実装するために知っておくべき高度な概念とパターンに徐々に進歩します。この本は、代数データ型、タイプクラスベースの設計、副作用の分離などの高度なFPパターンが、読みやすさと検証可能性のためにモデルを構成する方法を示しています。

正直なところ、機能プログラムのレシピをデザインしたい場合は、Haskellのプレリュードなどの標準機能ライブラリをご覧ください。 FPでは、パターンは通常、高次手順(機能で動作する関数)自体によってキャプチャされます。したがって、パターンが見られる場合、多くの場合、そのパターンをキャプチャするために高次関数が単に作成されます。

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

リチャードバード教授とオックスフォード大学(英国)のプログラミンググループの代数に関連する「プログラム計算」 /「計算による設計」スタイルがありますが、これを方法論と見なすにはあまりにも大きなものではないと思います。

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

良い、

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

OOPは「状態」のために「パラレルプログラミング」が困難になっているため、今ではより人気があります。また、Google MapReduceのような問題には機能的なスタイルが適しています。

functioanlの人たちが壁にぶつかったとき[1.000.000行のコードを超えるシステムを実装しようとする場合]、それらのいくつかには、バズワードを含む新しいソフトウェアエンジニアリング方法論が付属しています:-)。彼らは古い質問に答えるべきです:私たちが一度にそれぞれの部分を「噛む」ことができるようにシステムを細かく分割する方法は? [機能的なスタイルを使用して、反復的で、進化的な方法で動作します。

機能的なスタイルがオブジェクト指向のスタイルに影響を与えることは確かです。機能システムから多くの概念を「まだ」し、OOP言語に適応しています。

しかし、機能プログラムはこのような大きなシステムに使用されますか?それらはメインストリームになりますか?それが問題です.

そして、このような大きなシステムを実装せずに、現実的な方法論を持ってくることはできません。最初に手を汚し、解決策を提案する必要があります。 「本当の痛みと汚れ」のないソリューションの提案は「ファンタジー」になります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top