肥大化したGUIコードの記述を避けるにはどうすればよいでしょうか?


48

GUIコードを使用すると、コードが他の種類のコードよりも速く膨張する傾向があります。また、リファクタリングが難しいようです。一方、他の種類のコードではかなり簡単にリファクタリングできます-より大きなクラスをより小さな機能に分解できることがわかります-ほとんどのGUIフレームワークでは、多くの場合、ウィジェット/コントロール/クラスを必要とするフレームワークに縛られていますウィジェット/コントロール/その他にもっと多くのものを直接実装します。これは、(a)いくつかのベースウィジェット/コントロール/ものから継承するか、(b)保護されたメソッドにアクセスする必要があるためです。

また、通常、たとえば、フレームワークからの信号/イベント/何でもを介して多種多様な入力に応答して、ユーザーと対話するすべてのモードを実装する必要があります。1つのGUIウィジェット/コントロールで、次のようなさまざまな入出力を処理する必要がある場合があります。

  1. 右クリック/コンテキストメニュー
  2. コンテキストメニューからの選択に反応する
  3. GUIをペイントする特別な方法
  4. キーボード入力に反応する
  5. ボタン、チェックボックス、
  6. などなど

...その間、ビジネスロジックを表すGUIの下でクラスを管理します。

シンプルでわかりやすいGUIでは、ビジネスロジックを分離してMVCを使用する場合でも、コードを非常に迅速に成長させることができます。GUIコードは変更の大きな魅力です。

GUIコードを健全な方法で管理し、壊れたウィンドウにならないようにする方法はありますか?それとも、ランダムなイベントハンドラー/オーバーライドされたメソッドの塊が、GUIコードに対してできる最善の方法なのでしょうか。


4
「膨張」の正確な定義は何ですか?

回答:


36

GUIコードについて覚えておくべきことは、イベント駆動型であり、イベント駆動型コードは常にランダムに編成された大量のイベントハンドラーのように見えるということです。本当に厄介なのは、イベント駆動型でないコードをクラスに追加しようとするときです。確かに、イベントハンドラーをサポートするように見え、イベントハンドラーを小さく小さく保つことができますが、その余分なサポートコードはすべて、GUIソースが肥大化して面倒なように見えます。

では、これについて何ができますか?また、リファクタリングをより簡単にする方法はありますか?さて、最初にリファクタリングの定義を、時々行うことから、コーディング中に継続的に行うことに変更します。どうして?リファクタリングを使用して、コードをより簡単に変更できるようにしたいので、その逆ではありません。ここでセマンティクスを変更するように単純に求めるのではなく、コードを別の方法で見るために、少しメンタル体操を行うように求めています。

最もよく使用する3つのリファクタリング手法は、RenameExtract Method、およびExtract Classです。私が他のリファクタリングを一度も学んだことがない場合、これらの3つはまだコードをきれいで構造化された状態に保つことができ、あなたの質問の内容から、おそらく同じGUIコードを薄く清潔に保つため。

世界でGUIとビジネスロジックを可能な限り分離することができますが、GUIコードは、コードマイニングが途中で爆発したように見えます。私のアドバイスは、GUIを適切に管理するのに役立つ追加のクラスを1つまたは2つ用意しても害はないということです。MVCパターンを適用する場合、これは必ずしもViewクラスである必要はありません。中間クラスはビューに非常に似ているため、便宜上、それらをマージする必要があることがよくあります。これに関する私の見解は、すべての視覚的ロジックを管理するために追加のGUI固有のレイヤーを追加することは実際には害にはならないということです。

したがって、私のアドバイスは:

  • GUIをView(または中間層)にフックする方法を呼び出して定義する以外は、GUIのすぐ後ろで何もしません。
  • あなたがそうすることが理にかなっていない限り、すべてのビューに関連するものを単一のクラスに、またはGUIウィンドウごとに単一のクラスにすらしようとしないでください。別の方法は、GUIロジックを管理するために、管理が簡単でクラスを多数作成することです。
  • メソッドがコードの4〜5行より少し大きく見えるようになったら、これが必要かどうか、そしてメソッドを抽出できるかどうかを調べて、クラスを意味する場合でもメソッドを無駄にしないようにします。より多くの方法で。
  • クラスが非常に大きく見え始めている場合は、重複する機能をすべて削除してから、別のクラスまたは2つを抽出できるようにメソッドを論理的にグループ化できるかどうかを確認します。
  • コードを書くたびにリファクタリングを考えてください。動作するコード行を取得した場合、機能の重複を避けるためにリファクタリングできるか、または動作を変更せずに少しリーンにすることができるかどうかを確認してください。
  • 避けられないことを受け入れてください。特に、リファクタリングを怠ると、システムのある部分または別の部分が少し肥大化し始めます。十分にファクタリングされたコードベースを使用しても、さらに多くのことができるように感じることができます。これはソフトウェアを書くことの現実です。あなたは、もっと何かが「より良く」できたはずだと常に感じるので、プロの仕事と金メッキの間のバランスを取る必要があります。
  • コードをきれいにしようとすると、コードが肥大化することは少なくなります。

3
+1好むと好まざるとにかかわらず、GUIは膨大な数の詳細な操作を処理し、コードを意味します。
パトリックヒューズ

開発者は、GUIのイベント駆動型コーディングの使用方法を学習する必要があります。
デヴィッド・ガオ

23

あなたが経験している問題の多くは、単純な原因に起因していると思います。ほとんどの開発者は、GUIコードを「実際の」コードのように扱いません。私はここに証拠も統計もありません、ただ私の直感です。

たぶん、彼らはそれが「単なるプレゼンテーション」であり、重要ではないと考えています。「そこにはビジネスロジックはありません」、彼らは言う、「なぜユニットテストを行うのですか?」オブジェクトの向きとクリーンなコードの記述に言及すると、彼らは笑います。彼らは物事を良くしようとさえしません。開始する構造はありません。一部のコードを平手打ちし、他の人が時間の経過とともに独自のタッチを追加するにつれてコードを腐らせます。美しい混乱、落書きコード。

GUIコードには独自の課題があるため、異なる方法で敬意を持って扱わなければなりません。愛とそれを書きたい開発者が必要です。それを薄く保ち、良い構造と正しいパターンを与えるもの。


2
GUIコードが非GUIコードとは異なる方法で扱われているという認識をほのめかした+1。「GUIの費用対効果が低く、しかも難しいので、GUIをテストする必要はありません」と言われた回数を数えていません。私は通常、「それは難しく、それを行うのを学ぶのが面倒です!」と訳しています。
-S.ロビンス

1
+1私が働いている場所では、GUIコードをレビューしないことがよくあります-「GUIであるため、スキップしてください」。そして、私は誰と同じように罪を犯しています。奇妙なことは、私の個人的なプロジェクトでは、すっきりとしたきれいなGUIコードを取得しようとすると、多くの時間を費やすことです。それは単なる文化的なものだと思います。
HappyCat

8

何らかの理由で、GUIコードは懸念の分離について開発者に盲点を作ります。すべてのチュートリアルがすべてを1つのクラスにまとめているからかもしれません。たぶんそれは、物理的な表現が物事を実際よりも密接に結びつけているように見えるからでしょう。多分それはクラスがゆっくりと構築され、人々がリファクタリングが必要だと認識しないからです。

理由が何であれ、解決策はクラスをはるかに小さくすることです。これを行うには、自分が入力しているものを別のクラスに入れることができるかどうかを常に自問自答します。別のクラスに入れることができ、そのクラスの合理的でシンプルな名前を考えることができるなら、私はそれをします。


6

モデルビューのプレゼンター/パッシブビューのパターンをご覧ください。レイライアンは、GWTのアーキテクチャのベストプラクティスについてGoogle IOで良い講演をしました。

http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html

アイデアを他のフレームワークや言語に抽象化するのは簡単です。(私の意見では)MVPの主な利点は単体テスト可能性です。そして、あなたは、あなたのコードが肥大化せず、スパゲッティではない場合にのみ得られます(あなたの質問から判断すると、これはあなたが望むものです)。プレゼンターと呼ばれるビューロジックレイヤーを導入することで機能します。実際のビューは、インターフェースを介してこれから分離されます(したがって、単体テストで簡単にモックできます)。これで、ビューロジックレイヤー(プレゼンター)が具体的なGUIフレームワークの内部から解放されるため、通常のコードのように整理でき、たとえばSwings継承階層に縛られることはありません。同じインターフェースに準拠している限り、異なるフレームワークでGUI実装を切り替えることができれば理想的です。


1
+1。MVPは、GUIロジックを個別のクラスに抽出する方法に厳密に焦点を合わせています。これは、多くの場合、人々がMVCについて話すときに理解するものとはかなり異なります。
Doc Brown

5

私の答えは、構造、シンプルさ、テスト、構文の4つの部分で構成されています。

最初の3つは本当に難しい!

構造とは、最小限のコードと最大限のフレームワーク、ライブラリなどの使用に多くの注意を払うことを意味します。

シンプルさとは、初期設計から実際の実装までをシンプルにすることです。ここでは、ナビゲーションをシンプルに保ち、シンプルなプラグインを使用して、レイアウトをかなり「プレーン」に保つことがすべて役立ちます。それらは、PC、iPad、モバイル、その他のデバイスで動作するページの利点をすぐに見ることができるクライアント/ユーザーに「販売」できます。

テストとは、頻繁にコードを「パッチ」するのではなく、より良いコードを最初に処理できるように設計できる場合に、クロスブラウザーの問題を事前にキャッチするブラウザーテストツール(webratとcapybaraが私のレールの仕事で頭に浮かぶ)を含むさまざまなブラウザのユーザーによって「発見」されるため、さまざまな開発者によって。

構文。 HTML、CSS、Javascriptなどにコードチェッカー/ IDE /エディタープラグインなどを使用すると、非常に役立ちます。そのため、HTML形式をチェックするツールが不可欠です。適切な形式のHTMLを使用することは、肥大化していないHTMLを作成するのに非常に役立ちます。これは、不良コードの可視性が高まるためです。


4

私が見つけた解決策は宣言型コードです。手続き型のコードを使用することは、スパゲッティGUIコードのレシピです。確かに、「ウィジェットをペイントする特別な方法」はおそらくコードのままです。しかし、これはクラスで分離されたコードです。イベントハンドラ、キーボードショートカット、ウィンドウサイズ-面倒なものはすべて宣言するのが最適です。


4

ここにはたくさんの素晴らしい答えがあります。

GUIコードの簡素化に役立った1つのことは、GUIに独自のデータモデルがあることを確認することです。

簡単な例を挙げると、4つのテキスト入力フィールドを持つGUIがある場合、これらの4つのテキスト入力フィールドの内容を保持する別のデータクラスがあります。より複雑なGUIでは、より多くのデータクラスが必要です。

モデルとしてGUIを設計-ビュー。GUIモデルは、アプリケーションモデルのアプリケーションコントローラー-ビュー-コントローラーによって制御されます。アプリケーションビューは、GUIコード自体ではなく、GUIモデルです。


2

ワープロ、グラフィックスエディタなどのアプリケーションには複雑なインターフェイスがあり、コードを単純にすることはできません。ただし、ビジネスアプリケーションの場合、GUIはそれほど複雑である必要はありませんが、多少複雑です。

GUIを簡素化するためのいくつかのキーは(ほとんどが.NETに適用されます):

  1. 可能な限りシンプルなデザインを目指してください。ビジネスから要求されていない場合、派手な行動は避けてください。

  2. 適切なコントロールプロバイダーを使用します。

  3. クライアントコード自体にカスタムコントロール機能を作成しないでください。代わりに、使用するフォーム/ページのコードではなく、コントロールに特定の動作を反映できるように、元のコントロールを拡張するユーザーコントロールを作成します。

  4. フレームワーク(自家栽培)を使用して、国際化、リソース管理、スタイルなどを処理し、すべてのUIでこのコードを繰り返さないようにします。

  5. ナビゲーション用のコンポーネント(またはフレームワーク)を使用します。

  6. エラー、警告、確認などの標準的なダイアログを作成します。


1

オブジェクト指向設計をコードに適用し、UI開発のために:

  1. プレゼンテーションとモデル分離するMV-whateverライブラリ/フレームワークを使用するか、独自に作成して、データモデルからビュー/コントローラーロジックを分離します。バックエンドとのすべての通信はモデル内で行われる必要があり、モデルの状態は常にバックエンドと同期する必要があります。
  2. 分離 オブジェクトAがオブジェクトBを知っている場合、AはBのメソッドを呼び出すことができますが、BはAを知らないはずです。代わりにAはBからのイベントをリッスンできます。循環依存がないことを確認します。アプリにコンポーネント間で多数のイベントがある場合は、EventBusを作成するか、Twitter Flightなどのイベント駆動型フレームワークを活用します。
  3. 部分レンダリングと完全レンダリングビューがテーブルまたはアイテムのリストである場合、コレクションに1つのアイテムを挿入/削除するための「追加」、「削除」などのメソッドを作成したくなるかもしれません。ソートとページネーションをサポートする必要がある場合、コードは簡単に肥大化する可能性があります。したがって、私のアドバイスは、部分的な変更がある場合でも、ビュー全体を単純に再レンダリングすることです。パフォーマンスはどうですか?コレクションが大きい場合は、とにかくページネーションを行う必要があります。Web開発者:イベントハンドラーが、変更されないビューのルート要素に委任されていることを確認してください。
  4. ビューモデルビューの状態を維持するのが複雑すぎる場合、たとえば、テーブルビューは行データ、列データ、並べ替え順序、現在チェックされている行(マルチチェックをサポートしている場合)などを追跡する必要があります。それらの状態のViewModelオブジェクトを作成します。UIで何かが変更された場合(たとえば、ユーザーが行をチェックした場合)、ViewオブジェクトはViewModelでセッターを呼び出す必要があります。また、UIを更新することにより、ViewModelのchangeイベントに応答する必要があります。通常、変更イベントがUIによってトリガーされる場合は、UIの更新を避ける必要があります。

ここに、私のポイントのいくつかを説明するのに役立つ、小さいが重要なアプリがあります。コードとビュー/モデルの相互作用図は、https//github.com/vanfrankie/pushpopboxにあります。


0

「データバインディング」の概念を見てみたいと思います。これは、モデル要素がUIのコンテンツと自動的に同期されるように、宣言的な方法で抽象モデル要素にUI要素を接続する方法です。このアプローチには多くの利点があります。たとえば、データを同期するためにイベントハンドラを自分で記述する必要がないなどです。

.NETEclipse / JFaceなど、多くのUIフレームワークのデータバインディングサポートがあります。

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