it-swarm.com.de

Wie kann man am besten vermeiden, aufgeblähten GUI-Code zu schreiben?

Wenn ich mit GUI-Code arbeite, neigt der Code dazu, schneller aufzublähen als andere Arten von Code. Es scheint auch schwieriger zu sein, umzugestalten. Während ich in anderen Arten von Code ziemlich einfach umgestalten kann - ich finde, ich kann eine größere Klasse in kleinere Funktionen zerlegen -, bin ich bei den meisten GUI-Frameworks häufig an ein Framework gebunden, für das mein Widget/Steuerelement/welche Klasse auch immer erforderlich ist Implementieren Sie viel mehr Dinge direkter im Widget/Steuerelement/was auch immer. Manchmal ist dies darauf zurückzuführen, dass entweder (a) von einem Basis-Widget/Steuerelement/Ding geerbt werden muss oder (b) Zugriff auf geschützte Methoden erforderlich ist.

Normalerweise muss ich zum Beispiel auch auf eine Vielzahl von Eingaben über Signale/Ereignisse/was auch immer aus dem Framework reagieren, um alle Arten der Interaktion mit dem Benutzer zu implementieren. Möglicherweise benötige ich in einem GUI-Widget/Steuerelement eine Vielzahl von Ein-/Ausgaben, die Folgendes umfassen können:

  1. ein Rechtsklick/Kontextmenü
  2. reagieren auf Auswahlen aus dem Kontextmenü - das können viele sein
  3. eine besondere Art, die GUI zu malen
  4. auf Tastatureingaben reagieren
  5. schaltflächen, Kontrollkästchen,
  6. etc etc.

... währenddessen die Klassen unter der GUI verwalten, die die Geschäftslogik darstellen.

Bei einer einfachen, unkomplizierten GUI kann der Code ziemlich schnell wachsen, selbst wenn die Geschäftslogik getrennt und MVC verwendet wird. Ich finde, dass GUI-Code ein großer Magnet für Änderungen ist.

Gibt es eine Möglichkeit, GUI-Code auf vernünftige Weise zu verwalten und zu vermeiden, dass er zu einem zerbrochenen Fenster wird? Oder ist eine Masse von zufälligen Ereignishandlern/überschriebenen Methoden wirklich das Beste, was wir für GUI-Code tun können?

48
Doug T.

Das Wichtigste an GUI-Code ist, dass er ereignisgesteuert ist und ereignisgesteuerter Code immer das Aussehen einer Masse zufällig organisierter Ereignishandler hat. Es wird wirklich chaotisch, wenn Sie versuchen, nicht ereignisgesteuerten Code in die Klasse zu integrieren. Sicher, es sieht so aus, als würde es die Event-Handler unterstützen, und Sie können Ihre Event-Handler nett und klein halten, aber all dieser zusätzliche Support-Code lässt Ihre GUI-Quelle aufgebläht und chaotisch erscheinen.

Was können Sie dagegen tun und wie können Sie die Umgestaltung vereinfachen? Nun, ich würde zuerst meine Definition von Refactoring von etwas ändern, das ich gelegentlich mache, zu etwas, das ich kontinuierlich mache, während ich codiere. Warum? Weil Sie Refactoring wünschen, damit Sie Ihren Code einfacher ändern können und nicht umgekehrt. Ich bitte Sie nicht nur, die Semantik hier zu ändern, sondern Sie, stattdessen ein wenig mentale Calisthenics zu machen, um Ihren Code anders zu sehen.

Die drei Refactoring-Techniken, die ich am häufigsten verwende, sind mbenennen, Extraktionsmethode und Extraktionsklasse. Wenn ich nie ein anderes Refactoring gelernt hätte, würden diese drei es mir trotzdem ermöglichen, meinen Code sauber und gut strukturiert zu halten, und nach dem Inhalt Ihrer Frage klingt es für mich so, als würden Sie wahrscheinlich fast ständig dieselben drei Refactorings verwenden um Ihren GUI-Code dünn und sauber zu halten.

Sie können die bestmögliche Trennung von GUI- und Geschäftslogik in der Welt erzielen, und dennoch kann der GUI-Code so aussehen, als ob eine Codemine in der Mitte explodiert wäre. Mein Rat ist, dass es nicht schadet, ein oder zwei zusätzliche Klassen zu haben, um Ihre GUI richtig zu verwalten, und dies müssen nicht unbedingt Ihre View Klassen sein, wenn Sie das MVC-Muster anwenden - Obwohl Sie häufig feststellen, dass die Zwischenklassen Ihrer Ansicht so ähnlich sind, dass Sie häufig den Drang verspüren, sie der Einfachheit halber zusammenzuführen. Ich gehe davon aus, dass es nicht wirklich schadet, eine zusätzliche GUI-spezifische Ebene hinzuzufügen, um die gesamte visuelle Logik zu verwalten. Sie möchten jedoch wahrscheinlich die Vorteile und Kosten abwägen.

Mein Rat ist daher:

  • Tun Sie nichts direkt hinter Ihrer GUI, außer aufzurufen und zu definieren, wie sich die GUI in die Ansicht (oder eine Zwischenebene) einfügt.
  • Versuchen Sie nicht, alle mit der Ansicht verbundenen Dinge in eine einzelne Klasse - oder sogar eine einzelne Klasse pro GUI-Fenster - zu unterteilen, es sei denn, dies ist für Sie sinnvoll. Ihre Alternative besteht darin, viele kleine und einfach zu verwaltende Klassen zu erstellen, um Ihre GUI-Logik zu verwalten.
  • Wenn Ihre Methoden etwas größer als 4 bis 5 Codezeilen aussehen, prüfen Sie, ob dies erforderlich ist und ob es möglich ist, eine oder zwei Methoden zu extrahieren, damit Sie Ihre Methoden schlank halten können, auch wenn dies eine Klasse bedeutet mit vielen weiteren Methoden.
  • Wenn Ihre Klassen sehr groß aussehen, entfernen Sie zunächst ALLE duplizierten Funktionen und prüfen Sie dann, ob Sie Ihre Methoden logisch gruppieren können, sodass Sie eine oder zwei weitere Klassen extrahieren können.
  • Denken Sie an Refactoring jedes Mal, wenn Sie eine Codezeile schreiben. Wenn Sie eine Codezeile zum Laufen bringen, prüfen Sie, ob Sie sie umgestalten können, um doppelte Funktionen zu vermeiden oder um sie ein wenig schlanker zu gestalten, ohne das Verhalten zu ändern.
  • Akzeptieren Sie das Unvermeidliche, dass Sie immer das Gefühl haben, dass sich der eine oder andere Teil Ihres Systems etwas aufgebläht anfühlt, insbesondere wenn Sie das Refactoring vernachlässigen. Selbst mit einer gut faktorisierten Codebasis können Sie immer noch das Gefühl haben, dass es mehr gibt, was Sie könnten tun. Dies ist die Realität beim Schreiben von Software, bei der Sie immer das Gefühl haben, dass etwas "besseres" hätte getan werden können. Sie müssen also ein Gleichgewicht zwischen professioneller Arbeit und Vergoldung finden.
  • Akzeptieren Sie, dass Ihr Code umso weniger aufgebläht erscheint, je sauberer Sie versuchen, Ihren Code beizubehalten.
36
S.Robins

Ich denke, viele der Probleme, die Sie haben, lassen sich auf eine einfache Ursache zurückführen. Die meisten Entwickler behandeln GUI-Code nicht wie 'echten' Code. Ich habe hier keine Beweise oder Statistiken, nur mein Bauchgefühl.

Vielleicht denken sie, es ist ' nur Präsentation ' und nicht wichtig. ' Es gibt dort keine Geschäftslogik ', sagen sie, ' warum Unit Test es '? Sie lachen, wenn Sie die Objektorientierung erwähnen und sauberen Code schreiben. Sie versuchen nicht einmal, die Dinge besser zu machen. Es gibt zunächst keine Struktur, sie schlagen nur einen Code und lassen ihn verrotten, während andere im Laufe der Zeit ihre eigene Note hinzufügen. Ein wunderschönes Durcheinander, Graffiti-Code.

GUI-Code hat seine einzigartigen Herausforderungen, daher muss er anders und mit Respekt behandelt werden. Es braucht Liebe und Entwickler, die wollen, um es zu schreiben. Diejenigen, die es dünn halten und ihm eine gute Struktur und korrekte Muster verleihen.

23
c_maker

Aus irgendeinem Grund schafft GUI-Code bei Entwicklern einen blinden Fleck in Bezug auf die Trennung von Bedenken. Vielleicht liegt es daran, dass alle Tutorials alles in einer Klasse zusammenfassen. Vielleicht liegt es daran, dass die physische Repräsentation die Dinge enger miteinander verbunden erscheinen lässt als sie sind. Vielleicht liegt es daran, dass der Unterricht langsam aufgebaut wird, sodass die Leute nicht erkennen, dass sie umgestaltet werden müssen, wie der sprichwörtliche Frosch, der durch langsames Erhöhen der Hitze gekocht wird.

Was auch immer der Grund sein mag, die Lösung besteht darin, Ihre Klassen viel kleiner zu machen. Dazu frage ich mich ständig, ob es möglich ist, das, was ich schreibe, in eine separate Klasse einzuteilen. Wenn es möglich ist, in eine andere Klasse einzusteigen, und ich mir einen vernünftigen und einfachen Namen für diese Klasse vorstellen kann, dann mache ich es.

8
Karl Bielefeldt

Vielleicht möchten Sie einen Blick auf das Muster Model View Presenter/Passive View werfen. Ray Ryan hielt einen guten Vortrag auf einem Google IO über die besten Architekturpraktiken für GWT).

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

Es ist einfach, die Ideen auf andere Frameworks und Sprachen zu abstrahieren. Der Hauptvorteil von MVP (meiner Meinung nach) ist die Unit-Testbarkeit. Und das bekommen Sie nur, wenn Ihr Code nicht aufgebläht und nicht spaghetti ist (nach Ihrer Frage zu urteilen, ist dies das, was Sie wollen). Es funktioniert durch Einführung einer Ansichtslogikebene, die als Präsentator bezeichnet wird. Die tatsächliche Ansicht ist über eine Schnittstelle davon entkoppelt (und kann daher in Unit-Tests leicht verspottet werden). Da Ihre Ansichtslogikebene (der Präsentator) von den Interna des konkreten GUI-Frameworks befreit ist, können Sie sie wie normalen Code organisieren und sind nicht an z. Schwingt die Vererbungshierarchie. Im Idealfall können Sie GUI-Implementierungen in verschiedenen Frameworks wechseln, sofern diese mit derselben Schnittstelle übereinstimmen.

6
scarfridge

Meine Antwort besteht aus vier Teilen: Struktur, Einfachheit, Test und Syntax.

Die ersten drei sind wirklich schwer zu machen!

Struktur bedeutet, der Verwendung der geringsten Menge an Code und der maximalen Menge an Frameworks, Bibliotheken usw. viel Aufmerksamkeit zu widmen.

Einfachheit bedeutet, die Dinge vom ersten Entwurf bis zur tatsächlichen Implementierung einfach zu halten. Hier hilft es, die Navigation einfach zu halten, einfache Plugins zu verwenden und das Layout ziemlich einfach zu halten. Sie können jetzt an Kunden/Benutzer "verkauft" werden, die schnell die Vorteile von Seiten erkennen können, die auf PCs, iPads, Mobilgeräten und anderen Geräten funktionieren.

Testen bedeutet, dass Browser-Test-Tools (Webrat und Capybara) in meine Rails Arbeit) einbezogen werden, die browserübergreifende Probleme im Vorfeld auffangen, wenn besserer Code entwickelt werden kann Behandeln Sie sie am Anfang im Gegensatz zum häufigen "Patchen" von Code durch verschiedene Entwickler, da sie von Benutzern verschiedener Browser "entdeckt" werden.

Syntax. Es ist sehr hilfreich, eine Codeüberprüfung/IDE/editor-plugin usw. für HTML, CSS, Javascript usw. zu verwenden. Der Vorteil, den Browser haben Wenn Sie in der Lage sind, schlecht geformtes HTML zu verarbeiten, wirkt dies gegen Sie, wenn verschiedene Browser unterschiedliche Funktionen ausführen. Daher ist ein Tool zur Überprüfung Ihres HTML-Formats von entscheidender Bedeutung .

5
Michael Durrant

Hier gibt es viele gute Antworten.

Eine Sache, die mir geholfen hat, den GUI-Code zu vereinfachen, ist sicherzustellen, dass die GUI über ein eigenes Datenmodell verfügt.

Um ein einfaches Beispiel zu nennen: Wenn ich eine GUI mit 4 Texteingabefeldern habe, habe ich eine separate Datenklasse, die den Inhalt dieser 4 Texteingabefelder enthält. Kompliziertere GUIs erfordern mehr Datenklassen.

Ich entwerfe eine GUI als Modellansicht. Das GUI-Modell wird vom Anwendungscontroller des Anwendungsmodell-Ansichts-Controllers gesteuert. Die Anwendungsansicht ist das GUI-Modell und nicht der GUI-Code selbst.

4

Die Lösung, die ich gefunden habe, ist deklarativer Code. Die Verwendung von nur prozeduralem Code ist ein Rezept für Spaghetti-GUI-Code. Sicher, eine "besondere Art, das Widget zu malen" wird wahrscheinlich Code bleiben. Dies ist jedoch Code, der in einer Klasse isoliert ist. Event-Handler, Tastaturkürzel, Fenstergrößen - all diese unordentlichen Dinge lassen sich am besten deklarieren.

4
MSalters

Anwendungen wie Textverarbeitung, Grafikeditoren usw. haben komplexe Schnittstellen und ihr Code kann nicht einfach sein. Für Geschäftsanwendungen muss die GUI jedoch nicht so komplex sein, sondern so, wie sie immer noch ist.

Einige der Schlüssel zur Vereinfachung der Benutzeroberfläche sind (die meisten gelten für .NET):

  1. Streben Sie nach einem einfacheren Design, wann immer dies möglich ist. Vermeiden Sie ausgefallene Verhaltensweisen, wenn dies nicht vom Unternehmen verlangt wird.

  2. Verwenden Sie einen guten Steuerungsanbieter.

  3. Erstellen Sie keine benutzerdefinierten Steuerungsfunktionen im Client-Code. Erstellen Sie stattdessen Benutzersteuerelemente, die das ursprüngliche Steuerelement so erweitern, dass Sie Ihr spezifisches Verhalten in den Steuerelementen und nicht im Code des verwendeten Formulars/der verwendeten Seite widerspiegeln können.

  4. Verwenden Sie ein Framework (auch ein selbst entwickeltes Framework), um Internationalisierung, Ressourcenverwaltung, Stile usw. zu verwalten, damit Sie diesen Code nicht in jeder Benutzeroberfläche wiederholen.

  5. Verwenden Sie eine Komponente (oder ein Framework) für die Navigation.

  6. Erstellen Sie Standarddialoge für Fehler, Warnungen, Bestätigungen usw.

2
NoChance

Wenden Sie objektorientiertes Design auf Ihren Code und für die UI-Entwicklung an:

  1. Separate Präsentation und Modell Verwenden Sie eine MV-beliebige Bibliothek/ein beliebiges MV-Framework oder schreiben Sie eine eigene, um die Ansichts-/Controller-Logik vom Datenmodell zu trennen. Die gesamte Kommunikation mit dem Backend sollte innerhalb des Modells erfolgen, und der Modellstatus sollte immer mit dem Backend synchron sein.
  2. Entkopplung Wenn Objekt A über Objekt B Bescheid weiß, kann A Methoden für B aufrufen, B sollte jedoch nichts über A wissen. Stattdessen kann A Ereignisse von abhören B. Es stellt sicher, dass keine zirkuläre Abhängigkeit besteht. Wenn Ihre App viele Ereignisse zwischen Komponenten enthält, erstellen Sie einen EventBus oder nutzen Sie ein ereignisgesteuertes Framework wie Twitter Flight.
  3. Teilweise oder vollständige Wiedergabe Wenn Ihre Ansicht eine Tabelle oder Liste von Elementen ist, könnten Sie versucht sein, Methoden wie "Hinzufügen", "Entfernen" zum Einfügen zu erstellen/lösche ein Element in/aus der Sammlung. Ihr Code kann leicht aufblähen, wenn Sie das Sortieren und Paginieren unterstützen müssen. Mein Rat lautet also: Rendern Sie einfach die gesamte Ansicht neu, auch wenn sich dies teilweise ändert. Was ist mit Leistung? Nun, wenn Ihre Sammlung groß ist, sollten Sie trotzdem eine Paginierung durchführen. Webentwickler: Stellen Sie sicher, dass Ihre Ereignishandler an das Stammelement der Ansicht delegiert sind, das sich nicht ändert.
  4. Ansichtsmodell Wenn der Status Ihrer Ansicht zu kompliziert wird, um beispielsweise verwaltet zu werden, muss eine Tabellenansicht die Zeilendaten, Spaltendaten und die Sortierreihenfolge verfolgen , aktuell überprüfte Zeilen (wenn es Multi-Check unterstützt) usw., sollten Sie wahrscheinlich ein ViewModel-Objekt für diese Status erstellen. Ihr View-Objekt sollte Setter im ViewModel aufrufen, wenn sich auf der Benutzeroberfläche etwas ändert (z. B.: Benutzer überprüft eine Zeile). und es sollte auf das Änderungsereignis von ViewModel reagieren, indem es die Benutzeroberfläche aktualisiert. Normalerweise sollten Sie die Aktualisierung der Benutzeroberfläche vermeiden, wenn das Änderungsereignis von der Benutzeroberfläche ausgelöst wird.

Hier ist eine kleine, aber nicht triviale App, um einige meiner Punkte zu veranschaulichen. Das Interaktionsdiagramm für Code und Ansicht/Modell finden Sie hier: https://github.com/vanfrankie/pushpopbox

1
frank

Sie möchten einen Blick auf das Konzept von "Datenbindung" werfen. Auf diese Weise werden UI-Elemente deklarativ mit abstrakten Modellelementen verbunden, sodass die Modellelemente automatisch mit dem Inhalt der UI synchronisiert werden. Dieser Ansatz bietet viele Vorteile, z. B. dass Sie keine Ereignishandler selbst schreiben müssen, um Daten zu synchronisieren.

Es gibt Datenbindungsunterstützung für viele UI-Frameworks, zum Beispiel . NET und Eclipse/JFace .

0
JesperE