20.8.08

Typische Probleme und Fehler während der SW-Entwicklung

  • Es wird zu früh mit dem Codieren begonnen.
  • Es wird zu spät mit dem Codieren begonnen.
  • Das Vorgehen ist schlecht geplant, ein Vorgehensmodell fehlt.
  • Das Vorgehensmodellist übertrieben genau, lähmend, bürokratisch und praxisfern.
  • Zwischen- und Endergebnisse werden nicht oder unzureichend verifiziert und validiert.
  • Die Anwendungsarchitektur wird nicht klar genug geplant oder entwickelt sich unkontrolliert.
  • Die Entwicklung wird von einem naiven Verständnis der Objektorientierung getrieben.
  • Die Entwicklung wird von einemfür die Praxis zu akademischen Verständnis der Objektorientierung getrieben.
  • Der Geist prozedular SW-Entwicklung tarnt sich nur mit Objektorientierung.
  • Analyse-, Design- und Realisierungsrichtlinien fehlen, werden nicht angewendet oder sind realitätsfern.
  • Die Dokumentation von Ergebnissen und Entwurfsentscheidungen führt ein scheintotes Randdasein.
  • Anforderungen werden nicht systematisch erhoben.
  • Die an der SW-Entwicklung beteiligten Personen (Entwickler, Anwender, Fachabteilung, Auftraggeber)
    kommunizieren kaum oder nicht direkt miteinander.
  • Aus Unsicherheit und Unerfahrenheit heraus wird naiv an vorgeblichen Heilslehren oder Heilsbringern
    festgehalten, z.B. Werkzeuge, Vorgehensmodelle, Berater.
  • Überambitionierte Lösungen (zu abstrakt, zu generisch oder zu kompliziert)

17.8.08

Die Prinzipien des objektorientierten Entwurfs

Prinzip 1: Prinzip einer einzigen Verantwortung (Single Responsibility Principle)

Jedes Modul soll genau eine Verantwortung übernehmen, und jede Verantwortung soll genau einem Modul zugeordnet werden. Die Verantwortung bezieht sich auf die Verpflichtung des Moduls, bestimmte Anforderungen umzusetzen. Als Konsequenz gibt es dann auch nur einen einzigen Grund, warum ein Modul angepasst werden muss: Die Anforderungen, für die es verantwortlich ist, haben sich geändert. Damit lässt sich das Prinzip auch alternativ so formulieren: Ein Modul sollte nur einen einzigen, klar definierten Grund haben, aus dem es geändert werden muss.

Jedes Modul dient also einem Zweck: Es erfüllt bestimmte Anforderungen, die an die Software gestellt werden.

Regel 1: Kohäsion maximieren (high cohesion) Ein Modul soll zusammenhängend (kohäsiv) sein. Alle Teile eines Moduls sollten mit anderen Teilen des Moduls zusammenhängen und voneinander abhängig sein. Haben Teile eines Moduls keinen Bezug zu anderen Teilen, können Sie davon ausgehen, dass Sie diese Teile als eigenständige Module implementieren können. Eine Zerlegung in Teilmodule bietet sich damit an.
Regel 2: Kopplung minimieren (low coupling) Wenn für die Umsetzung einer Aufgabe viele Module zusammenarbeiten müssen, bestehen Abhängigkeiten zwischen diesen Modulen. Man sagt auch, dass diese Module gekoppelt sind. Sie sollten die Kopplung zwischen Modulen möglichst gering halten. Dies können Sie oft erreichen, indem Sie die Verantwortung für die Koordination der Abhängigkeiten einem neuen Modul zuweisen.
image

Vorteile des Prinzips

  • Anforderungen ändern sich
  • Erhöhung der Wartbarkeit
  • Erhöhung der Chance auf Mehrfachverwendung

Prinzip 2: Trennung der Anliegen (Separation of Concerns)

Ein in einer Anwendung identifizierbares Anliegen soll durch ein Modul repräsentiert werden. Ein Anliegen soll nicht über mehrere Module verstreut sein.

Eine Aufgabe, die ein Programm umsetzen muss, betrifft häufig mehrere Anliegen, die getrennt betrachtet und als getrennte Anforderungen formuliert werden können.

Mit dem Begriff Anliegen bezeichnen wir dabei eine formulierbare Aufgabe eines Programms, die zusammenhängend und abgeschlossen ist.


Prinzip 3: Wiederholungen vermeiden (Don't repeat yourself)

Eine identifizierbare Funktionalität eines Softwaresystems sollte innerhalb dieses Systems nur einmal umgesetzt sein.

Es handelt sich hier allerdings um ein Prinzip, dem wir in der Praxis nicht immer folgen können. Oft entstehen in einem Softwaresystem an verschiedenen Stellen ähnliche Funktionalitäten, deren Ähnlichkeit aber nicht von vornherein klar ist. Deshalb sind Redundanzen im Code als ein Zwischenzustand etwas Normales. Allerdings gibt uns das Prinzip Wiederholungen vermeiden vor, dass wir diese Redundanzen aufspüren und beseitigen, indem wir Module, die gleiche oder ähnliche Aufgaben erledigen, zusammenführen.


Prinzip 4: Offen für Erweiterung, geschlossen für Änderung (Open-Closed-Principle)

Ein Modul soll für Erweiterungen offen sein.

Das bedeutet, dass sich durch die Verwendung des Moduls zusammen mit Erweiterungsmodulen die ursprüngliche Funktionalität des Moduls anpassen lässt. Dabei enthalten die Erweiterungsmodule nur die Abweichungen der gewünschten von der ursprünglichen Funktionalität.

Ein Modul soll für Änderungen geschlossen sein.

Das bedeutet, dass keine Änderungen des Moduls nötig sind, um es erweitern zu können. Das Modul soll also definierte Erweiterungspunkte bieten, an die sich die Erweiterungsmodule anknüpfen lassen.

Wir müssen hier allerdings einschränken: Ein nichttriviales Modul wird nie in Bezug auf seine gesamte Funktionalität offen für Erweiterungen sein. Auch bei einer Spiegelreflexkamera ist es nicht möglich, den Bildsensor auszuwechseln.

Am einfachsten lässt sich diese Frage beantworten, wenn das Modul nur innerhalb einer Anwendung verwendet oder nur von einem Team entwickelt wird. In diesem Fall können Sie einfach abwarten, bis der Bedarf für eine Erweiterung entsteht. Wenn der Bedarf da ist, sehen Sie bereits, welche Funktionalität allen Verwendungsvarianten gemeinsam ist und in welchen Varianten sie erweitert werden muss. Erst dann müssen Sie das Modul anpassen und es um die benötigten Erweiterungspunkte bereichern.

Zu viele nicht genutzte Erweiterungspunkte machen Module unnötig komplex, zu wenige machen sie zu unflexibel. Die Bestimmung der notwendigen und sinnvollen Erweiterungspunkte ist deshalb oft nur auf der Grundlage von Erfahrung und Kenntnis des Anwendungskontexts möglich.


Prinzip 5: Trennung der Schnittstelle von der Implementierung(program to interfaces)

Jede Abhängigkeit zwischen zwei Modulen sollte explizit formuliert und dokumentiert sein. Ein Modul sollte immer von einer klar definierten Schnittstelle des anderen Moduls abhängig sein und nicht von der Art der Implementierung der Schnittstelle. Die Schnittstelle eines Moduls sollte getrennt von der Implementierung betrachtet werden können.

Schnittstelle ist Spezifikation

In der obigen Definition dürfen Sie unter dem Begriff Schnittstelle nicht nur bereitgestellte Funktionen und deren Parameter verstehen. Der Begriff Schnittstelle bezieht sich vielmehr auf die komplette Spezifikation, die festlegt, welche Funktionalität ein Modul anbietet.

Durch das Befolgen des Prinzips der Trennung der Schnittstelle von der Implementierung wird es möglich, Module auszutauschen, welche die Schnittstelle implementieren. Das Prinzip ist auch unter der Formulierung Programmiere gegen Schnittstellen, nicht gegen Implementierungen bekannt.


Prinzip 6: Umkehr der Abhängigkeiten (Dependency Inversion Principle)

Unser Entwurf soll sich auf Abstraktionen stützen. Er soll sich nicht auf Spezialisierungen stützen.

Ein Entwurf, der grundsätzlich von Modulen ausgeht, die andere Module verwenden (Top-down-Entwurf), ist nicht ideal, weil dadurch unnötige Abhängigkeiten entstehen können. Um die Abhängigkeiten zwischen Modulen gering zu halten, sollten Sie Abstraktionen verwenden.

Abstraktion

Eine Abstraktion beschreibt das in einem gewählten Kontext Wesentliche eines Gegenstand oder eines Begriffs. Durch eine Abstraktion werden die Details ausgeblendet, die für eine bestimmte Betrachtungsweise nicht relevant sind. Abstraktionen ermöglichen es, unterschiedliche Elemente zusammenzufassen, die unter einem bestimmten Gesichtspunkt gleich sind.

Umkehrung des Kontrollflusses (engl. Inversion of Control)

Als die Umkehrung des Kontrollflusses wird ein Vorgehen bezeichnet, bei dem ein spezifisches Modul von einem mehrfach verwendbaren Modul aufgerufen wird. Die Umkehrung des Kontrollflusses wird auch Hollywood-Prinzip genannt: »Don’t call us, we’ll call you«.

Die Umkehrung des Kontrollflusses wird eingesetzt, wenn die Behandlung von Ereignissen in einem mehrfach verwendbaren Modul bereitgestellt werden soll. Das mehrfach verwendbare Modul übernimmt die Aufgabe, die anwendungsspezifischen Module aufzurufen, wenn bestimmte Ereignisse stattfinden. Die spezifischen Module rufen also die mehrfach verwendbaren Module nicht auf, sie werden stattdessen von ihnen aufgerufen.


Prinzip 7: Mach es testbar

Unit-Tests

Ein Unit-Test ist ein Stück eines Testprogramms, das die Umsetzung einer Anforderung an eine Softwarekomponente überprüft. Die Unit-Tests können automatisiert beim Bauen von Software laufen und so helfen, Fehler schnell zu erkennen.

Idealerweise werden für jede angeforderte Funktionalität einer Komponente entsprechende Unit-Tests programmiert.


(Quelle: Bernhard Lahres, Gregor Rayman, Praxisbuch Objektorientierung ISBN: 3-89842-624-6)

16.8.08

Modifizierer in C#

Zugriffsmodifizierer für Klassenmember


ModifiziererBeschreibung
publicUneingeschränkt zugänglich.
protected
internal
Zugänglich für die eigene Klasse, von dieser abgeleitete Klassen und das eigene Programm (Kompilierungsgemeinschaft).
internalZugänglich für das eigene Programm.
protectedZugänglich für die eigene und abgeleitete Klassen.
privateZugänglich für die eigene Klasse. Dies ist der Standardzugriff für Member, die ohne Modifizierer deklariert wurden.

Spezielle Klassen


ModifiziererBeschreibung
staticEine als static deklarierte Klasse darf nur statische Member enthalten. Statische Klassen können weder instanziiert noch vererbt werden.
abstractDie Klasse kann nur als Basisklasse für die Definition weiterer Klassen verwendet werden. Eine Instanziierung der Klasse ist nicht möglich.
sealedDie Klasse kann nicht als Basisklasse für die Definition weiterer Klassen verwendet werden.

Feldmodifizierer



ModifiziererBeschreibung
staticStatische Felder, auch Klassenvariablen genannt, existieren nur einmal. Methoden der Klasse können direkt auf die statischen Felder ihrer Klasse zugreifen. Ansonsten erfolgt der Zugriff über den Klassennamen.
readonlyDeklariert ein Feld als konstant. Einem solchen Feld können Sie nur im Zuge der Deklaration oder innerhalb eines Konstruktors einen Wert zuweisen. Später kann der Wert nur noch abgefragt werden. Dieser Modifizierer kann nicht in Kombination mit volatile oder static vergeben werden. (readonly-Felder sind automatisch static.)
volatileSchützt ein Feld vor ungewünschten Optimierungen durch den Compiler, die zu Fehlern führen können, wenn mehrere Threads unsynchronisiert auf das Feld zugreifen. Dieser Modifizierer kann nicht in Kombination mit readonly vergeben werden.
newZeigt an, dass ein geerbtes Feld bewusst verborgen wird.

Methodenmodifizierer



ModifiziererBeschreibung
staticStatische Methode, die nicht über Objekte der Klasse, sondern über die Klasse angesprochen wird.
externZeigt an, dass die Methode in einer anderen Assembly implementiert wird. Mit extern deklarierte Methoden werden ohne Anweisungsblock definiert. Die Verbindung zur Implementierung wird meist über ein DllImport-Attribut hergestellt.
Die folgenden Modifizierer regeln die Vererbung von Methoden
virtualVirtuelle Methode. Virtuelle Methoden können in abgeleiteten Klassen überschrieben werden (also unter Beibehaltung der Signatur mit neuem Anweisungsblock verbunden werden).
overrideZeigt an, dass hier nicht eine neue Methode eingeführt, sondern eine geerbte Methode überschrieben wird.
newZeigt an, dass diese Methode eine geerbte Methode gleicher Signatur verdeckt.
abstractFührt eine virtuelle Methode ein, ohne jedoch für diese eine Implementierung vorzugeben. Die Methode muss(!) also in abgeleiteten Klassen überschrieben werden, wenn von diesen Klassen Objekte erzeugt werden sollen.
sealedZeigt an, dass diese Methode in abgeleiteten Klassen nicht weiter überschrieben werden kann. Darf nur in Kombination mit override verwendet werden, d. h. die Methode muss selbst eine geerbte Methode überschreiben.

(Quelle: Dirk Louis, Shinja Strasser: Microsoft Visual C# 2008 – Das Entwicklerbuch
Microsoft Press Deutschland, ISBN:978-3-86645-507-8)

Nvidia's GauGan App

NVIDIA's GauGAN AI Machine Learning Tool creates photorealistic images from Simple Hand Doodling http://nvidia-research-mingyuliu.com/...