Scalaのシステム設計を再発明する


35

何年も前に、私はオブジェクト指向ソフトウェア工学の修士号を取得しました。プロジェクトの開始、要件、分析、設計、アーキテクチャ、開発など、すべてをカバーしました。これまでの私のお気に入りのITブックは、オブジェクト指向ソフトウェアの開発、経験ベースのアプローチ(IBM-1996)でした。当時の真の専門家グループによって作成された本。オブジェクト指向の分析、設計、開発手法に対する作業成果物中心のアプローチについて説明しています。

私はデザインと開発を行い、ゲームのトップで満足していましたが、少し時代遅れに感じ始めました。アジャイルムーブメントはその日のファッションになり、新しいヒップワードでよく知られている反復的かつ漸進的なアプローチを再ブランド化しました。「要件」または「アーキテクチャ」と言ったとき、あたかもこれらのことが魔法に取って代わられたかのように、突然、経験の浅い開発者は眉をひそめ始めました。

設計と開発は楽しさを失い、私はIT業界全体を取り残そうとしていました。

それからScalaを発見しました。ああ、ほこりっぽい道の柔らかい雨のように。すべてが明確になり、空気が再び甘くなり、私のハードドライブの小さな光が夜中深く点滅し、私の発見の世界で私を楽しませてくれました。

システム設計が好きです。私はプログラマーというよりも、建築家です。分析、設計、思考、議論、改善が大好きです。シンプルでクリーンで鮮明なデザインが大好きです。

純粋なScalaソリューションをどのように設計しますか?

確かに従来のシーケンス図、相互作用図、オブジェクト図などは、命令型と機能型のオブジェクト指向システムを融合させるために、すべて置き換えるか、改善することができます。確かに、まったく違うものの始まりがあります!

肥大化した複雑さを探しているのではなく、柔軟なシンプルさを探しています。Scalaは実際はシンプルで簡単ですが(違いはありますが)、ヨガパンツのように要件に合わせて拡張できます。この素敵な言語には、簡単に始められ、要件やドメインに合わせて拡張できる設計システムが必要です。確かにUMLはそうではありません!

それでは、純粋なScalaシステムをどのように設計するのでしょうか?ちょっと想像してみてください。完全なシステムをゼロから設計する余裕があり、Scalaのみを使用することを知っています- モデルはどのように見えますか?構造と動作を説明するには、どのような種類の図が必要ですか?オプション、マッチ、ミックスイン、シングルトンオブジェクトなどを、新しくて軽量で革新的なツールセットではなく、既存のモデリングテクニックを拡張する複雑さに引き込まずに、どのようにモデリングしますか。

そのような設計/プロセス/ソリューションは存在しますか、それとも発明する時ですか?


+1は、「ヨガパンツのように要件に合わせて拡張できます」。
ラッセル

FWIW、UMLとScalaについての質問を見ましたが、これはあなたにとって興味深いかもしれません。また、関数側に移動する場合、カテゴリ理論表記法を検討する価値があるかもしれません。グレゴリー・メレディスは通常、それに関するいくつかの興味深いプレゼンテーションにリンクしていますが、彼が彼のブログに何を持っているかはわかりませんが、とにかくチェックする価値があるはずです。
ダニエルC.ソブラル

それはたくさんの価値があります;-)それは私に掘る方向を与えます。ありがとうダニエル
ジャック

価値のあるチェック、Scalaの「変更された」UML github.com/mnn/Dia2Scala/blob/master/other/Notation.md
WeiChing Lin

回答:


12

私はこの質問に本当に答えることはできませんが、いくつか考えを述べさせてください。

私は大学のコンピューターエンジニアリングの学生で、前学期と私とグループは、主な言語がScalaである大規模なソフトウェアプロジェクトを行いました。従来の方法で設計を行いました。ユースケース、ドメインモデル、シーケンス図、UMLクラス図。通常の負荷。そして、すでにご存知のように、それらは適合度が低いです。いくつかの理由があります。

まず、シーケンス図を検討します。シーケンス図の感触は、いくつかの安定した、長命の、半自律的な俳優が互いに話し合っているようなものです。Scalaでは、オブジェクトは短時間作成される傾向があります。さらに、ケースクラスは、データのみでコードを持たない「ダム」オブジェクトを推奨するため、メッセージを渡すという概念は適切ではありません。しかし、シーケンス図の最も難しい課題は、ファーストクラスの関数を組み込む良い方法がないことです。あちこちでコールバックのみを使用するオブジェクト指向設計では、それを機能させることができますが、それが制御を転送する主な手段である場合、シーケンス図は実際のコードのほとんどを反映していません。

UMLクラス図はScalaにより適しています。はい、ミックスインはうまくいきませんが、それはオーバーホールではなく「微調整」できるものです。しかし、私はそれがポイントを逃しているかもしれないと思います。

Scalaに「ダムオブジェクト」がある理由をもう一度考えてください。メソッドなしでケースクラスを記述する場合:

case class NewInvite(user: User, league: League)

メンバーのタイプは、あなたがそれらで何ができるかについて何かを約束するため、メソッドは必要ありません。実際、彼らはすべてを約束します。そして、プログラム内のすべてのスコープで、スコープ内の変数とその型は、その時点でコードがどこに行くことができるかを約束します。

ですから、少し戻って、タイプ自体を細かく考えるのではなく、コードがどのコンテキストに住んでいるのか、プログラマー(そして最終的にはユーザー)に何が約束されているのかについてプログラムを設計してください)これらの各コンテキストで、Scalaにより適した説明を見つけます。しかし、私はここで推測しているだけであり、この分野でさらに多くの調査が必要であることは正しいと思います。


「プログラマーに約束されているもの」-それには素敵なリングがあります;
ジャック

12

UMLは、80年代後半から90年代前半の「バブル戦争」から生まれました。常に表記法の妥協案であり、設計手法ではありません。UMLに起因するカラムニーの多くは、「ステップ1:クラスモデルを描画する」という設計メソッドの結果です。

古い方法を再活性化するほど、新しい設計方法は必要ないことをお勧めします。責任の定義と割り当てから始めて、実装の理解に移り、それらのアイデアを伝えるために適切な表記法と表現を使用します。

責任

CRCは、他のオブジェクト指向言語と同様にScalaでも機能します。つまり、非常にうまく機能しています。アクターを擬人化して、彼らのコラボレーションを理解することにより、責任の配分をモデル化することは、依然として有効です。

大規模な場合でも、オブジェクトを使用して設計する必要があります。オブジェクトの境界はカプセル化の境界です。これらのオブジェクト境界内で可変状態と実装の詳細を保持します。ケースクラスは優れたインターフェイスオブジェクトを作成するため、バニラコレクションやデータ構造も同様です。

実装を理解する

これらのデータ構造を他のオブジェクトではなくオブジェクトの境界を越えて渡すと、a)オブジェクトの内臓を内部に隠しやすくなり、b)オブジェクトの動作の機能的な実装が非常に理にかなっていることがわかります。

プログラムの大規模な構造を「小さな機能の膨大なプール」として扱いたくないでしょう。代わりに、システムの隔離された部分間の狭いインターフェイスに自然に引き寄せられます。とにかく、これらはオブジェクトによく似ているので、先に進んでオブジェクトとして実装してください!

表現と表記

したがって、この設計構造内で、頭から考えを引き出し、他の人と共有する必要があります。

システムの大規模な構造を記述するために、UMLが依然として有用であることをお勧めします。ただし、詳細度の低いレベルでは役に立ちません。

細部に至るまで、リテラシープログラミングテクニックを試してください。

私もminidocsを使うのが好きです。ミニドックは、システム動作の特定の側面を説明する1ページまたは2ページのドキュメントです。更新されるようにコードの近くに配置し、ジャストインタイムの学習を可能にするのに十分短い必要があります。適切なレベルの抽象化を実現するには、ある程度の練習が必要です。次のコード変更で無効になるほど具体的ではなく、有用であるように具体的にする必要があります。


9

純粋なScalaソリューションをどのように設計しますか?

この質問に対して間違った角度を取っていると思います。ソリューションの全体的な設計は、特定の言語に縛られるべきではありません。むしろ、目前の問題に対応する必要があります。Scalaの素晴らしい点は、設計を実装するときに邪魔にならないほど柔軟であることです。一方、Javaは、少し不格好な気分になるいくつかの設計上の決定(主に、すべてがクラスであるという考え方)を実施します

設計するときは、状態を明示的にモデル化してみてください。不変のデータと明示的な状態により、設計がはるかに簡単になります。ほとんどの場合、これは関数型プログラミングソリューションにうまく変換されますが、突然変異や命令型スタイルを使用する方が効率的または簡単である場合があります。Scalaは両方とも非常にうまく対応します。

Scalaがあなたの邪魔にならないように優れているもう1つの理由は、ニーズに合ったDSL作成できることです。特定の問題を「通常の」方法で解決する独自の小さな言語を作成し、それを単にScalaで実装できます。

要約すると、私の主なポイントは、「純粋なScalaソリューションの設計」を試みるべきではないということです。可能な限り最も自然で理解可能な方法でソリューションを設計する必要があります。Scalaは、これらのソリューションをさまざまな方法で実装するのに役立つ非常に柔軟なツールです。あなたが知っているすべてがハンマーであるとき、すべての問題は釘のように見え始めますので、あなたが利用できる様々なアプローチを探求してください。設計プロセスをステップX、Y、およびZに閉じようとしないでください。AからWまでの可能性を逃さないようにしてください。


4

OODは限られたものであり、時代遅れです。その主な利点は、非常に適切に指定され、儀式化されていることであり、それぞれのあらゆる些細なパターンとデザインのトリックに派手な名前が付けられています。システム設計に対するより現代的で合理的なアプローチに匹敵するシステムは見つかりません。

リストにできるのは、設計へのセマンティックアプローチ(サブセットは言語指向プログラミングと呼ばれ、Scalaコミュニティで頻繁に使用されます)とドメイン駆動設計です。後者は、より一般的なセマンティックデザインアプローチに関する単純化されたOOP化されたビューであり、OODが好きな場合にのみ楽しむことができます。

また、他の関数型プログラミングコミュニティ(HaskellやSchemeなど)から1つまたは2つのトリックを学ぶことをお勧めします。これらの設計ノウハウのすべてが既にScalaに移行されているわけではありません。


3

問題は、純粋なScalaソリューションをどのように設計するかということでした。

答えは、

  1. XYZを使用するのは....
  2. ABCを使用していますが、そのように....
  3. XYZの使用を開始しましたが、ABCの方が優れていることがわかりました...

そのようなツールセットまたはソリューションの成熟度、または一般に受け入れられている存在を示しているでしょう。

Scala固有の設計ツールセットを検討することが適切かどうかに関するコメントは別の問題です。これについての私の意見は、Scalaは命令型プログラミングと関数型プログラミングを組み合わせた方法で革命的だということです。Scalaは、開発の実践、概念、原則の驚くべき息吹をとらえているので、Scalaに最適なソリューションを見つける際に、おそらく他の多くの言語にも非常に役立つサブセットを見つけることができます。

フォールバック質問に対する答えを知っていると言っても安全ですか?

「...発明する時ですか?」

それはイエスですか?(「yes」はソリューションの手段を規定していません。既存のソリューションを拡張するか、ゼロから作成することで達成できます。既存の設計オプションに重大な欠点があることは認めています)

同意できない場合は、私の回答を投票してください。私は男のようにそれを取るでしょう。


革命的ですか?どうして?Lispは、何十年もの間、命令的アプローチと機能的アプローチの完璧な組み合わせでした。Scalaは、その型システムのために興味深いものです。
SKロジック

3
「革命的」が強力な強力な言葉である場合、おologiesびします。私はScalaが車輪を再発明したことを暗示しているわけではありません-しかし、それは地獄がゴムを再形成したように確かです。実際、Scalaは多くのプログラミング言語の優れた点をうまく組み合わせたものです。Lispからもかなり借りていると思います。私にとって、そして私は他の人を主張していませんが、Scala言語は、自然にかなりひどく来るような方法でコードについて考えているという点で革新的だと感じています。同じことをする設計/モデリング言語は、確かに無料です。それが私の唯一のポイントでした-Lispと他のすべての偉大な言語に対する攻撃はありません。
ジャック

2

私は言語を区別せず、Javaでも同じようにします。しかし、私は機能的(代数的なHaskellの1つまたはLispの1つ)ではなく、オブジェクト指向の学校から来ました。Haskellアプリの設計は、ScalaやClojureとはまったく異なります。また、Scala.jsアプリの設計は、ステートフルDOMにより異なるため、アプリのステートフルな部分を必須とするのは困難です。時間が経つにつれて、可能な限り状態と可変性を排除しようとしながら、オブジェクト指向の方法で行うことに慣れました。もし私がタイプレベルやスカラズのファンなら、私のアプリはおそらくかなり違って見えるでしょう。

  1. 技術スタックと、クライアント/サーバーの責任、分散性などの主要な設計決定を決定する-データの永続性が本当に必要なのでしょうか?アプリケーションに最適なものは何ですか?(確かにまだライブラリやフレームワークではありません)

  2. App.scalaキータイプ(特性とケースクラス)とロールを定義する単一のファイルから始めます-AFKである間に多くの熟考と思考を行います。1つのファイル内にあるので、簡単に操作できます。単純なアプリケーションであれば、プロトタイプでさえ実現する可能性があります。可能な限り最も正確で主に透明で賢明なプロトタイプを持つことほど重要なことはないので、私はこのフェーズに多くの時間を費やします。それはすべて、私たちのさらなる熟考をより正確にするのに役立ち、成功の確率を高めます。

  3. ソリューションの正しさを証明したら、明確なビジョンを持ち、潜在的な問題がすべて明らかになりました。どのようなサードパーティのライブラリまたは方法論を導入するかを考える時です。これらのステートフルなアクターを作成するつもりですか、本当にAkkaの回復力が必要ですか?これらのストリームにRxを使用しますか?UIに何を使用して、10個のインタラクティブな機能を備えた後でも気が狂わないようにしますか?

  4. App.scala新しい特性とクラスが出現して大きくなったため、ファイルを複数のファイルに分割します。彼らのインターフェースは彼らの役割を伝えるべきです。また、可能であれば、型クラスとアドホックポリモーフィズムを利用することを検討するときです。そのため、インターフェイスを呼び出す人は誰でも柔軟に対応できる必要があります。ポイントは、一般的な機能のみを実装し、詳細は呼び出し元に任せることです。実装しようとしているものがチューリング完全な場合もあるため、GitHubで機能要求を積み上げるのではなく、呼び出し元が独自に仕様を実装する方法を提供する必要があります。このようなものは後で追加するのが難しいです。それは最初から熟考しなければなりません。DSLの設計と同様に。

  5. アプリケーションが成長し、新しい機能、最適化、永続性、UI、リモート処理などに耐える準備ができている必要があるため、設計を熟考します。すべてが1つのファイルに収められていますが、変更は非常に簡単です。人間の脳は、10個以上のファイルに広がった後、それを失い始めます。そして、それは成長する腫瘍のようなものであり、それがオーバーエンジニアリングの始まりです。私のアプリケーションは、そのバックボーンのようなものを形成するいくつかの長い部分関数で終わることに気付きました。簡単に作業できます。アッカの俳優に感染したようです。

  6. コア機能だけでなく、最初の実際の機能が存在するので、テストの作成を開始します。何でそんなに遅いの?なぜなら、この時間中にあなたはおそらく大規模な書き直しを行い、それらのテストを維持する時間を無駄にしていたからです。大幅な再設計が行われないことが本当に確実でない限り、テストを作成しないでください。継続的なリファクタリングに簡単に耐えられる統合テストを好み、実際に開発するテストに時間を費やすことはありません。テストを維持するのにあまりにも多くの時間を費やしたことが何度かありました。潜在的なバグを修正することは、確かに悪いテストではなく、より良い結果をもたらすでしょう。悪いテストまたは最初の瞬間から書かれたテストは、大きな痛みを引き起こす可能性があります。私は確かにTDDのファンではないことに注意してください-私見それはでたらめです。

  7. リファクタリング、アプリケーション設計の可読性の維持、コンポーネントの役割の明確化。あなたが天才プログラマーでない限り、アプリケーションが成長するにつれて、そのようにとどまる方法はありませんし、この答えを読んだとしてもおそらくそうではありません:-)私もそうではありません。それ-問題を引き起こす可能性があります、それらを排除しようとします。また、しばらくの間あなたを悩ませていたコードの臭いを除去するようにしてください。この時点で、プロジェクトマネージャー(ある場合)が頭を振るでしょう。それが報われると彼に言ってください。

  8. 完了、アプリは適切に設計されていますか?それは依存します:あなたの頭の外でも実際に意味をなすコンポーネントが明確に定義された役割を持っていますか?それらのいくつかを取り、多くの努力なしでそれらをオープンソースにできますか?それらの間に懸念の明確な分離はありますか?他の場所でクラッシュすることを心配せずに新しい機能を追加できますか(あなたのしるしはあなたが何をしているかを正確に知っています)?一般的に言えば、問題に対する単純で実用的な解決策を備えた本として読みやすいものでなければなりません。私見は良いデザインの主要な兆候です。

全体として、それは単なる大変な作業であり、おそらくマネージャーからは得られないでしょう。ここで説明したすべての作業には、多くの時間、労力、コーヒー、紅茶、特にAFKの思考が必要です。与えれば与えるほど、デザインは良くなります。アプリケーションを設計するための一般的なレシピはありません。常識、プラグマティズム、KISS、ハードワーク、経験は優れたデザインを意味します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.