Eine Frage zu Anti-Patterns

takidoso

Erfahrenes Mitglied
Hallo allesammt!
Heute komme ich mal nicht direkt einem algorithmischen Problem, sondern wollte mal so aus Eurer Praxis her fragen welchen Anti-Pattern Ihr begegnet seid?
Also mit Anti-Pattern seien Entwursmuster gemeint, die sich für die jeweilige Problematik für nicht so gut geeignet herausgestellt haben, auch wenn das gesammte Ding am Ende durchaus funktionsfähig gewesen sein mag. Mit "nicht so gut" meine ich alles, was mit einer mangelnden Erweiterbarkeit, Fehleranfälligkiet und, vielleicht mit allem zusammenhängend, einer mangelnden Verständlichkeit nicht zuletzt für Dritte, in Bezug auf die angewandte Design-Strategie in Verbindung steht.
Es können sowohl eigene Fehlentscheidungen, als auch Fehlentscheidungen innerhalb einer Gruppe, oder eines zu wartenden Systems von unbekannt, welches Ihr nicht selbst verbrochen habt, sein.
Ziel dieser vielleicht etwas arg entgegengesetzten Fragestellung, ist aus Design-Fehlern zu lernen, auch wenn man selbst nicht auf diese bisher gestoßen ist, um halt solche Späße nicht ungewollt zu wiederholen.

mit neugierigen Grüßen

Takidoso
 
Eine spezielle Antwort habe ich zwar nicht, jedoch eine Meinung dazu.

Anti-Patterns wird ich nicht alles nennen. Jedes Pattern hat seine Daseinsberechtigung, allerdings gibt es immer wieder Leute, die meinen alle Patterns in einem Projekt unterbringen zu müssen. Verständlichkeit und Performance ist dann meist eh "im Keller". Allein für spezielle Patterns müssen soviele Klassen erzeugt werden, die ein kleines Projekt ganz schön aufblähen, zumal auch das Erzeugen dieser verschiedenen Objekte verhältnismäßig viel Zeit beansprucht, ganz zu schweigen vom Arbeitsspeicherverbrauch.
Man sollte sich bei jedem Projekt seine Eckpunkte anschauen. Was will ich? Verständlichkeit, Anpaßbarkeit, Wiederverwendbarkeit, Performance, ect...
Je größer ein Projekt wird, desto wichtiger ist der Einsatz wiederverwendbarer Komponenten und Patterns. Spätestens bei Perfromanceproblemen wird man sicher auf das eine oder andere Pattern verzichten.

1. unperformant, aber wiederverwendbar (und etwas übertrieben...);) :

Code:
public class Alter {
private Integer alter;
public Alter(Integer alter) {
alter = alter;
}
public Integer getAlter() {
return alter;
}
}
public class Name {
private String name;
public Name(String name) {
name = name;
}
public String getName() {
return name;
}
}

Code:
public interface Person {
public int getAlter();
public String getName();
}
 
public class TOPerson implements Person {
private Name name;
private Alter alter;
public TOPerson(Name name, Alter alter) {
this.name = name;
this.alter = alter;
}
public int getAlter() {
return (alter != null && alter.getAlter() != null)? alter.getAlter().intValue(): 0;
}
public String getName() {
return (name != null)? name.getName(): "unbekannt";
}
}

Code:
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
list.add(new TOPerson(new Name("Heinz" + i), new Alter(new Integer(i + 5)));
}

Wieviele Objekt hier erzeugt werden, könnt ihr ja selbst ausrechnen...

2. wesentlich performanter:

Code:
Map map = new HashMap();
for (int i = 0; i < 10000; i++) {
map.put("Heinz" + i, new Integer(i + 5));
}
 
Na, dann will ich mal.
Wir haben mal etwas übereifrig ein Singleton implementiert.
Es ging dabei um eine verteilte Simpulationsumgebung, bei welcher der gleiche Baustein, ein selbstorganisierendes Lagersystem, beliebig häufig vorkommen kann. Diverse andere größere Module, zum Beispiel ein Fahrsystem und ein Auftragsplaner, sollten unabhängig von dem Lager entworfen werden.
Da bei der Planung schon abzusehen war, dass die gesamte Anwendung ordentlich Ressourcen frißt, haben wir uns für eine verteilte Anwendung entschieden. Die Module sollten über RMI kommunizieren und einzeln gestartet werden.
So haben wir uns für diverse Singletons innerhalb der Module entschieden.
Als dann irgendein kluger Kopf in der Projektleitung entschieden hat, dass wir auch eine Stand-Alone-Version schreiben sollen, die bei Verzicht auf grafische Darstellung auch halbwegs performant läuft, hatten wir bei den Lägern ein Problem. Jedes Lager einzeln gestartet war mit den Singletons für Einlager-, Auslager- und Umlageraufträge bequem zu verwenden und auch erweiterbar. Als aber nun alle Läger in einer Anwendung gestartet wurden, hat es einiges an Arbeit gemacht, die Singletons für diesen Fall umzuschreiben.

Versteht das aber bitte nicht als Aufruf, keine Singletons zu verwenden. In der eigentlichen Planung waren sie einfach genial, insbesondere, weil sie sich selbst instanzieren, wenn sie gebraucht werden. Man sollte sich nur sehr genau überlegen, ob sie auf ewig und bei veränderten Anforderungen immer noch so einzigartig sind, wie in der ursprünglichen Planung.

Gruß hpvw
 
In Bezug auf Singletons sollte man sich überlegen, welche Komponenten wirklich nur einmal (bzw. in begrenzter Anzahl (Polytons - oder wie man die nennt...)) auftreten.

Meine Erfahrungswerte wären, Singletons für Einzelkomponeten zu verwenden (z.B. Dispatcher), Routinearbeiten per statischer Methoden (z.B. Transformationen), TransferObjects zum Datenaustausch, u.s.w. - im Klartext: jedes Pattern sinnvoll für den jeweiligen Anwendungsfall einsetzen und bei Performanceproblemen stets einfach denken, denn jedes zusätzliche Objekt frißt Zeit und Resourcen.

Patterns: http://www.patterndepot.com/put/8/DesignJava.PDF
 
Hallo!

Code:
denn jedes zusätzliche Objekt frißt Zeit und Resourcen.
Das kommt darauf an... Beispielsweise auf:
-Die groesse eines Objektes
-Etwaige damit verknuepfte native Systemressourcen
-Die Lebensdauer
-...

Allgemein kann man sagen das die modernen JVMs dafuer optimiert sind sehr viele kleine Objekte erzeugen zu koennen. Objekte die eine sehr kurze Lebensdauer aufweisen und noch in Eden/Nursury gc'ed werden bereiten der VM kaum Probleme. Objekte die jedoch langlebiger Natur sind und die old/tenured Generation gelangen brauchen weit mehr Zuwendung vom GC (und verbraten dort auch mehr Zeit, denn die Garbage Collection in der old/tenure generation ist um ein vielfaches aufwendiger als die Garbage Collection innerhalb von Eden/Nursery und den Survivor Spaces). Objekterzeugung selbst ist in Java nur dann teuer, wenn dahinter noch native Resourcen verknuepft sind oder das Objekt sehr "gross" ist.

Gruss Tom
 
Vor einigen Jahren war ich mal in einem Projekt, in dem es um eine aufwendigere GUI-Anwendung ging, die mit Internal-Frames arbeitete. Der, der die Gesamtkonzeption inne hatte, ersann sich da folgende Pattern für die Kommunikation der verschiedenen Fenster:

Jedes Fenster bekam einen sogenannten Controller, der Nachrichten entgegen nahm und weiter gab an den nächsten Controller in der Hierachie. Dabei gab es quasi eine richtung, Abwärts oder Aufwärts. Wenn z.B. der Anwender ein Menü-Item anklickte welches die oder nur eines der Fenster "berührte", wurde also eine Nachricht erzeugt, die von oberer Hierachie abwärts weitergeleitet wurde. Wenn der Anwender in einem inneren Fenster etwas tat, wurde eine Nachricht erzeugt die dann je nach Ziel mittels Controller nach oben oder unten weitergeleitet wurde. Dabei hatten alle Controller entsprechende Fallunterscheidungen zu bewerkstelligen, also wenn Nachricht für mich dann rufe entsprechende Funktion des Fensters auf, sonst leite entweder weiter hoch oder weiter runter. Das tolle an der Sache war, dass es tatsächlich funktionierte :p.
Im Grunde ist dieses Verfahren aus meiner Sicht so eine Art Daisy-Chain-Prinzip, welches gerne bei verkabelten Pereferiegeräten angewendet (wurde/wird), damit ein Computer eben nicht für n anschließbare Geräte n Ausgänge benötigt.
So nun aber zu den eigentlichen Problemen dieser Pattern...
  • Um neue Dinge zu progrmmieren, für die neue Nachrichten verwendet werden müssen, muss man erheblich mehr als nur eine Stelle ändern. Lustig wird es vor allem dann, wenn man bei irgendeinem Controler etwas falsches in der Fallunterscheidung (eigentlich großer verschachtelter if then else Konstrukt) programmiert hat, dann kann es durchaus vorkommen dass eine Nachricht fallen gelassen wird, und dann viel Spaß beim suchen wo in der Controller-Kette. (D.H ich hatte vorsorglich jeden Controller entsprechend seiner Nachrichten loggen lassen , dann wurde das Auffinden eines solchen Fehlers schon wesentlich leichter)
  • Es werden lauter Fallunterscheidungen gemacht, die noch dazu redundant sein können , abhängig von der Anzahl der Hierachiestufen. Auch wenn der kleine Performance Verlust einem Anwender nicht auffallen wird (lineare Suche, redundante abfragenkette ...) fand ich es weniger prickelnd (Ein weiser objektorientierter Spruch lautet: Hast du viele viele Fallunterscheidungen, dann hast Du möglicherweise irgendwas in Deinem Objektmodell unglücklich designed)
  • Das Framework war aus zumindest meiner Sicht unnötig umständlich und für dritte vermutlich nicht so leicht zugänglich.

In meinem sonstigen Java-Dasein, habe ich eigetnlich immer ganz gute Erfahrungen mit Listenern gemacht, sei es welche die vom Java-Framework herrrühren oder welche die man sich mal schnell selbst strickt. Es mag Entwickler geben, so auch der damaliger Designer, denen dieses Konzept innerhalb der Objekte zu chaotisch erscheint, dafür gibt es aber auch bessere Möglichkeiten als das oben beschriebene Daisy-Chain-Verfahren. Wenn man beispielsweise einen zentralen Nachrichten-Controller, Dispatcher oder Manager (oder wie auch imemr man es nennen mag) definiert (als Singleton), der die Nachrichten entgegen nimmt und sie mittels Map gleich direkt an das Ziel-Fenster, welches natürlich bei ihm angemeldet ist weiterleitet, hätte man nur eine Stelle neue Nachrichten-Typen neu einzurichten. Man könnte natürlich diese Idee noch weiter treiben, so dass beispielsweise alle dem Fenster zuzuordnenden Nachrichten im Fenster selbst definiert sein könnten, dann wäre eine Art Adaptivität auch noch drinn.
Naja wie gesagt, Daisy-Chain funktionierte zwar, aber ich bin glücklich den Kram nicht warten zu müssen.

in diesem Sinne

Takidoso
 
Strategische Anti-Pattern in der GUI-Entwicklung

Seit einiger Zeit habe ich mit einem System zu tun, welches ich fachlich gar nicht weiter umreißen möchte.
Es besteht wie viele Systeme auch aus umfangreicher Server- und Client-Software.
Diese Anwendung ist für Multiprozssorarbeit konzipiert und man hat, was ich ganz pfiffig finde, viele Möglichkeiten in Parameterdateien unter anderem auch Tuning durchzuführen, in dem man z.B. bestimmt wie viele Javamaschienen für einen bestimmten Prozesstyp gleichzeitig laufen sollen. Die Parameterdateien sind dabei hierachisch in Ordnern abgelegt und damit je nach Hierachie Mandantenfähig. Kurz gesagt, es ähneld sehr dem Package-Konzept von Java.
Nun aber das was sehr bedauerlich ist...
Die Client-Software ist im wesentlichen ein Engine, der mittels spezieller Parameterdateien zur Laufzeit Masken erzeugt. Klingt zunächst nicht schlimm, aber irgendwie kann ich zumindest seit Einzug der Objektorientierung und gerade bei Benutzung von Java den Sinn nicht ganz nachvollziehen.
Früher waren GUIs zu entwickeln wirklich kein sonderlich leichtes Brot, zumal man bei ähnlichen Maksen ohne Vererbungsmöglichkeit halt entsprechend viel mit Copy and Paste gearbeitet hat. Also waren Maskengeneratoren, die Metainformationen für GUI-Engines generierten eine übliche Praxis.
Aber bei Objektorientierung dann mit manuell zu entwickelnden Parameterdateien Masken zu zaubern, halte ich für fehlgeleiteten Ehrgeiz, zumal in diesem Fall sämmliche Elemente mit absoluten physichen X/Y-Koordinaten zu positionieren und dimensionieren sind :suspekt:
Man hat sich quasi eine 'neue Sprache' in Form von Parameterdaeien einfallen lassen, die auf jedenfall nicht die Möglichkeiten bietet, wie eine gewöhnliche Java-GUI Programmeirung (in diesem Fall Swing), wobei es in diesem Sektor eine Menge Source-Code-Generatoren gibt, die durchaus gute Ergebnisse erzielen. Ganz abgesehen in diesem Fall vom Verzicht auf Layout-Managern, verzichtet man hier auf sämmtliche objektorientierte Ansätze vor allem die Vererbung, so dass ähnliche Masken nicht von einander abgeleitet werden, sonden mit der Uralt-Techniken "Copy&Paste und bastle so lange rum bis gewünschtes Ergebnis erzielt" erstellt werden, die schon zu rein prozeduralen Zeiten als unglücklich angesehen wurden. Damit trägt man dazu bei das die GUI-Entwicklung bis zu einem bestimmten Grad nicht beschleunigt werden kann, was man bei geschickter Verbung und echter Wiederverwendung vermag. Ein weiterer Nachteil ist, dass Entwickler für ein solches proprietäres Maskensystem speziell ausgebildet werden müssen.

Fazit: Parameterdateien zum Konfigurieren und Tunen sind gut. Sie aber für GUI-Entwicklung quasi als Programmiersprachenersatz zu verwenden halte ich für zeitverschwendendes Unglück.
 
Zuletzt bearbeitet:
Ich habe mal wieder eine interessante offenbar ungünstige Technik wahrgenommen, diesmal direkt bei mir.
Das Programm war ein 4-Personen Schachspiel via Internet, jedoch glaube ich trifft das auf sicher andere Programmtypen auch gut zu, die über Internet kommuniziern sollen.
Um es mir einfacher zu machen dachte ich, wäre die schon in Java eingebaute Möglichkeit Objekte zu serialisien zu nutzen und ganze Objekte (inklisive dem Schachbrett) zu verschicken.
Im Laufe der Kommunikationsprogrammeirung stellte ich vermehrt fest dass ich an meinen Ursprungsklassen so einiges als transient deklarieren musste da nicht alles Inhaltsgemäß sinnvoll war. Der aber wirklich größere Nachteil war die Performance. Sicher liegt das auch daran, dass sehr viele Objekte mit serialisert werden, an die man im ersten Moment nicht denkt.
Ich denke bei einer neuen Gelegenheit werde ich Serialisierungen nicht mehr ganzer Objekte vornehmen sondern wirklich nu rnoch die reinen Daten die benötigt werden auf die Reise, beispielsweise in Stringform, schicken. Und entsprechende Serialisierungen bzw Deserialisierungen weitestgehend selbst in die Hand nehmen oder vielleicht auch mich anderer kompakterer Techniken wie z.B. YAML anvertrauen.
 
Zuletzt bearbeitet:
Meine Top3:

* klassische Singletons
* Dependencies selbst besorgen (lookups oder Erzeugung mit new)
* instanceof (in 90% der Fälle)

REINHAUN!
 
Meine Top3:

* klassische Singletons
* Dependencies selbst besorgen (lookups oder Erzeugung mit new)
* instanceof (in 90% der Fälle)

REINHAUN!

Hi Oliver,
das sind interessante Stichwörter, wobei ich mir noch nicht ganz im Klaren bin, welche Nachteile aus ihnen erwachsen, und was man anstelle davon tun kann.
Könntest Du da noch dazu erläutern?

mit wissberierigen Grüßen

Takidoso
 

Neue Beiträge

Zurück