Programmierprinzipien: Unterschied zwischen den Versionen
Kowa (Diskussion | Beiträge) |
Kowa (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
(12 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 7: | Zeile 7: | ||
}} | }} | ||
'''Anmerkung''': In diesem Artikel haben die beiden | '''Anmerkung''': In diesem Artikel haben die beiden Folgerungspfeile „→“ und „⇒“ folgende Bedeutungen: | ||
:⇒: „hat zur Folge“ | :⇒: „hat zur Folge“ | ||
:→: „trägt bei zu“, „verbessert“, „erhöht“ | :→: „trägt bei zu“, „verbessert“, „erhöht“ | ||
Zeile 14: | Zeile 14: | ||
Um nützliche und dennoch preiswerte [[Programm]]e und [[Anwendung]]en erstellen zu können, sollte man eine Reihe von [[Programmierprinzipien]] beachten. | Um nützliche und dennoch preiswerte [[Programm]]e und [[Anwendung]]en erstellen zu können, sollte man eine Reihe von [[Programmierprinzipien]] beachten. | ||
Bevor die | Bevor die Programmierprinzipien näher beschrieben werden können, werden zunächst die Ziele genauer spezifiziert, die mit diesen Prinzipien erreicht werden sollen. | ||
==Ziele== | ==Ziele== | ||
Ziel eines jeden Softwareentwicklungs- | Ziel eines jeden Softwareentwicklungs-Vorhabens sollte die Erstellung von Software sein, die zwei Eigenschaften aufweist: | ||
; nützlich (useful): Die Software sollte für den Benutzer nützlich sein. | ; nützlich (useful): Die Software sollte für den Benutzer nützlich sein. | ||
Zeile 27: | Zeile 27: | ||
Um die beiden vorgenannten Ziele zu erreichen, sollte ein Softwarepaket folgende Eigenschaften haben: | Um die beiden vorgenannten Ziele zu erreichen, sollte ein Softwarepaket folgende Eigenschaften haben: | ||
; spezifiziert (specified): Um die Nützlichkeit und die Korrektheit des Softwarepakets beurteilen zu können, sollte eine Spezifikation vorliegen, die detailliert die Aufgaben und Eigenschaften des Paketes beschreibt. | ; spezifiziert (specified): Um die Nützlichkeit und die Korrektheit des Softwarepakets beurteilen zu können, bevor es eingesetzt wird, sollte eine Spezifikation vorliegen, die detailliert die Aufgaben und Eigenschaften des Paketes beschreibt. | ||
:⇒ Nützlichkeit (ist abschätzbar) | |||
⇒ Nützlichkeit (ist abschätzbar) | |||
; korrekt (correct): Die Implementierung des Paketes sollte korrekt sein, es sollte also die Spezifikation in allen Punkten erfüllen. | ; korrekt (correct): Die Implementierung des Paketes sollte korrekt sein, es sollte also die Spezifikation in allen Punkten erfüllen. | ||
:⇒ Nützlichkeit: Eine Software, die nicht korrekt arbeitet, nutzt dem Benutzer in den fehlerhaften Situationen nicht. | |||
⇒ Nützlichkeit: Eine Software, die nicht korrekt arbeitet, nutzt dem Benutzer in den fehlerhaften Situationen nicht. | :⇒ keine Kosten durch falsches oder unerwartetes Verhalten | ||
⇒ keine Kosten durch falsches oder unerwartetes Verhalten | |||
; robust (robust): Das Softwarepaket sollte auch in abnormalen (nicht-spezifizierten) Situationen stabil laufen. | ; robust (robust): Das Softwarepaket sollte auch in abnormalen (nicht-spezifizierten) Situationen stabil laufen. | ||
:⇒ keine Kosten durch Inkonsistenzen | |||
⇒ keine Kosten durch Inkonsistenzen | :⇒ geringe Kosten bei Bedienungsfehlern und Systemausfällen | ||
⇒ geringe Kosten bei Bedienungsfehlern und Systemausfällen | |||
; benutzbar (usable): Das Softwarepaket sollte einfach zu erlernen und zu benutzen sein. | ; benutzbar (usable): Das Softwarepaket sollte einfach zu erlernen und zu benutzen sein. | ||
:⇒ Nützlichkeit wird verbessert | |||
⇒ Nützlichkeit wird verbessert | :⇒ geringe Schulungskosten | ||
:⇒ fehlerhafte Nutzung kommt nur selten vor und hat daher nur selten Kosten zu Folge | |||
⇒ geringe Schulungskosten | :⇒ keine Kosten durch frustrierte Benutzer | ||
⇒ fehlerhafte Nutzung kommt nur selten vor und hat daher nur selten Kosten zu Folge | |||
⇒ keine Kosten durch | |||
;sicher (secure): Unautorisierter Zugriff auf Daten oder Programme sollte unmöglich sein. | ;sicher (secure): Unautorisierter Zugriff auf Daten oder Programme sollte unmöglich sein. | ||
:⇒ keine Kosten durch Sicherheitsmängel | |||
⇒ keine Kosten durch Sicherheitsmängel | |||
;effizient (efficient): Das Softwarepakt sollte eine möglichst gute Laufzeit- und Speichereffizienz aufweisen, d.h. die vorhandenen Ressourcen möglichst gut ausnutzen. | ;effizient (efficient): Das Softwarepakt sollte eine möglichst gute Laufzeit- und Speichereffizienz aufweisen, d.h. die vorhandenen Ressourcen möglichst gut ausnutzen. | ||
:⇒ geringe Personalkosten durch geringe Wartezeiten | |||
⇒ geringe Personalkosten durch geringe Wartezeiten | :⇒ geringe Kosten durch geringe Hardwareanforderungen | ||
⇒ geringe Kosten durch geringe Hardwareanforderungen | |||
; wartbar (maintainable): Das Softwarepaket sollte leicht an neue Gegebenheiten angepasst werden können. Fehler sollten leicht behoben werden können (da sie sich nie ganz vermeiden lassen). | ; wartbar (maintainable): Das Softwarepaket sollte leicht an neue Gegebenheiten angepasst werden können. Fehler sollten leicht behoben werden können (da sie sich nie ganz vermeiden lassen). | ||
:⇒ geringe Wartungskosten | |||
⇒ geringe Wartungskosten | ; wiederverwendbar (reusable): Erweiterungen der Spezifikation sollten wiederverwendet werden können. | ||
:⇒ geringe Wartungskosten und Erweiterungskosten | |||
:⇒ geringere Kosten bei Folgeprojekten | |||
Für die Eigenschaft „wartbar“ gibt es drei Spezialfälle, die hier gesondert genannt werden sollen: | Für die Eigenschaft „wartbar“ gibt es drei Spezialfälle, die hier gesondert genannt werden sollen: | ||
; kompatibel (compatible): Das Softwarepaket sollte | ; kompatibel (compatible): Das Softwarepaket sollte kompatibel zu bestehenden Systemen sein, es sollte also standardisierte Schnittstellen unterstützen. | ||
:⇒ geringe Intergrations- und Anpassungskosten | |||
⇒ geringe Intergrations- und Anpassungskosten | |||
; portabel (portable): Das Softwarepaket sollte einfach auf neue Systeme portiert werden können. | ; portabel (portable): Das Softwarepaket sollte einfach auf neue Systeme portiert werden können. | ||
:⇒ geringe Kosten bei Änderung der Ablaufumgebung | |||
⇒ geringe Kosten bei Änderung der Ablaufumgebung | |||
; erweiterbar (extensible): Erweiterungen der Spezifikation sollten schnell implementiert werden können. | ; erweiterbar (extensible): Erweiterungen der Spezifikation sollten schnell implementiert werden können. | ||
:⇒ geringe Wartungskosten | |||
⇒ geringe Wartungskosten | |||
==Programmierprinzipien== | ==Programmierprinzipien== | ||
Zeile 85: | Zeile 73: | ||
Um die vorgenannten Ziele zu erreichen, sollten folgende [[Programmierprinzipien]] beachtet werden: | Um die vorgenannten Ziele zu erreichen, sollten folgende [[Programmierprinzipien]] beachtet werden: | ||
===[[Verständlichkeit]], | ===[[Verständlichkeit]], Comprehensibility, Lesbarkeit, Readability=== | ||
;Schreibe lesbaren und verständlichen Code.: Der Programmcode sollte so einfach wie möglich gelesen und verstanden werden können. Das heißt, der Code sollte sauber | ;Schreibe lesbaren und verständlichen Code.: Der Programmcode sollte so einfach wie möglich gelesen und verstanden werden können. Das heißt, der Code sollte sauber formatiert werden, es sollten sprechende Bezeichner verwendet werden, es sollten sinnvolle Kommentare eingefügt werden etc. Ein erfahrender Programmierer sollte die Bedeutung der einzelnen Anweisungen, Operationen, Definitionen etc. problemlos erfassen können. | ||
:→ Überprüfbarkeit (durch Programmierer und nicht nur durch Compiler u.Ä.) (→ Korrektheit, Robustheit) | |||
→ Überprüfbarkeit (durch Programmierer und nicht nur durch Compiler u.Ä.) (→ Korrektheit, Robustheit) | :→ Wartbarkeit (da die Programme auch von anderen Programmierern verstanden werden) | ||
→ Wartbarkeit | |||
===[[Schreibbarkeit]], Writability=== | ===[[Schreibbarkeit]], Writability=== | ||
Zeile 102: | Zeile 86: | ||
* Fehler/Warnungen werden von der Programmierumgebung zeitnah gemeldet. | * Fehler/Warnungen werden von der Programmierumgebung zeitnah gemeldet. | ||
* Fehler werden vermieden (wenn beispielsweise Code-Fragmente automatisch generiert werden). | * Fehler werden vermieden (wenn beispielsweise Code-Fragmente automatisch generiert werden). | ||
:→ Korrektheit | |||
→ Korrektheit | :→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | ||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
===[[Stetigkeit]], Continuity=== | ===[[Stetigkeit]], Continuity=== | ||
;Schreibe stetigen Code.: Schreibe den Code so, dass kleine Änderungen an der Spezifikation auch nur kleine Änderungen am Code zur Folge haben. | ;Schreibe stetigen Code.: Schreibe den Code so, dass kleine Änderungen an der Spezifikation auch nur kleine Änderungen am Code zur Folge haben. | ||
:→ Wartbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden) | |||
→ Wartbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden) | :→ Wiederverwendbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden) | ||
→ Wiederverwendbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden) | |||
===[[Konfigurierbarkeit]], Customizability=== | ===[[Konfigurierbarkeit]], Customizability=== | ||
;Schreibe konfigurierbaren Code.: Konstante Werte sollten im Allgemeinen nicht direkt in den Code eingefügt werden, sondern als konstante Werte separat definiert werden (Ausnahme: triviale Konstanten, die sich sicher nie ändern werden, wie z.B. Vergleiche mit dem Wert <code>0</code>). Konstanten, die das Programmverhalten beeinflussen, sollten im Allgemeinen | ;Schreibe konfigurierbaren Code.: Konstante Werte sollten im Allgemeinen nicht direkt in den Code eingefügt werden, sondern als konstante Werte separat definiert werden (Ausnahme: triviale Konstanten, die sich sicher nie ändern werden, wie z.B. Vergleiche mit dem Wert <code>0</code>). Konstanten, die das Programmverhalten beeinflussen, sollten im Allgemeinen beim Programmstart aus einer Konfigurationsdatei ausgelesen werden. | ||
:→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | |||
→ Stetigkeit (→ Wartbarkeit | |||
===[[Don't repeat yourself]], DRY<ref>{{Quelle|Hund, Thomas (2003)}}</ref>=== | ===[[Don't repeat yourself]], DRY<ref>{{Quelle|Hund, Thomas (2003)}}</ref>=== | ||
;Wiederhole dich nicht.: Code sollte nicht dupliziert und anschließend nur marginal modifiziert werden. | ;Wiederhole dich nicht.: Code sollte nicht dupliziert und anschließend aber gar nicht oder nur marginal modifiziert werden. | ||
:→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | |||
→ Stetigkeit (→ Wartbarkeit | :→ Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit) | ||
:→ Robustheit (da keine inkonsistenten Änderungen an mehreren Stellen möglich sind) | |||
→ Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit | |||
→ Robustheit (da keine | |||
===[[Repeat yourself]], RY<ref>{{Quelle|Kowarschick (MMProg)}}</ref>=== | ===[[Repeat yourself]], RY<ref>{{Quelle|Kowarschick (MMProg)}}</ref>=== | ||
;Wiederhole dich.: In Benutzerschnittstellen sollten gleiche oder vergleichbare Aufgaben immer auf dieselbe Weise vom Benutzer durchgeführt werden können. Es sollten dieselben Bezeichner, dieselben bzw. gleichartige Bedienelemente, dasselbe Design etc. verwendet werden. | ;Wiederhole dich.: In Benutzerschnittstellen sollten gleiche oder vergleichbare Aufgaben immer auf dieselbe Weise vom Benutzer durchgeführt werden können. Es sollten dieselben Bezeichner, dieselben bzw. gleichartige Bedienelemente, dasselbe Design etc. verwendet werden. | ||
:→ Wiederverwendbarkeit (da gleichartige Elemente nicht mehrfach implementiert werden müssen; DRY) | |||
→ Wiederverwendbarkeit (da gleichartige Elemente nicht mehrfach implementiert werden müssen) | :→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | ||
:→ Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit) | |||
→ Stetigkeit (→ Wartbarkeit | |||
→ Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit | |||
===[[Gesetz von Demeter]]<ref>{{Quelle|Lieberherr, Holland (1989)}}</ref>, Law of Demeter, LoD=== | ===[[Gesetz von Demeter]]<ref>{{Quelle|Lieberherr, Holland (1989)}}</ref>, Law of Demeter, LoD=== | ||
Zeile 145: | Zeile 116: | ||
*Objekte, die mittels Parametern beim Methodenaufruf übergeben wurden | *Objekte, die mittels Parametern beim Methodenaufruf übergeben wurden | ||
*Objekte, die das aktuelle Objekt selbst erzeugt hat | *Objekte, die das aktuelle Objekt selbst erzeugt hat | ||
:→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | |||
→ Stetigkeit (→ Wartbarkeit | :→ Verständlichkeit (da die Anzahl der Kommunikationspartner geringer ist) (→ Korrektheit, Robustheit, Wartbarkeit) | ||
→ Verständlichkeit (da die Anzahl der Kommunikationspartner geringer ist) (→ Korrektheit, Robustheit, Wartbarkeit | |||
===[[Überprüfbarkeit]], Verifiability=== | ===[[Überprüfbarkeit]], Verifiability=== | ||
;Schreibe überprüfbaren Code.: Die Korrektheit eines Softwarepakets sollte plattformunabhängig sein und automatisch überprüft werden können. Viele Programmierparadigmen und auch Projekttechniken verlangen zu diesem Zweck, dass gleichzeitig mit der Software auch passende Softwaretests implementiert werden ([[Modultest]]s, [[Unittest]]s). Noch besser ist es, wenn die Semantik des | ;Schreibe überprüfbaren Code.: Die Korrektheit eines Softwarepakets sollte plattformunabhängig sein und automatisch überprüft werden können. Viele Programmierparadigmen und auch Projekttechniken verlangen zu diesem Zweck, dass gleichzeitig mit der Software auch passende Softwaretests implementiert werden ([[Modultest]]s, [[Unittest]]s). Noch besser ist es, wenn die Semantik des Programms formal spezifiziert und überprüft werden kann ([[Abstrakter Datentyp|Abstrakte Datentypen]], [[Integritätsbedingung]]en, ...) | ||
:→ Korrektheit (insbesondere, wenn die Erfüllung der Spezifikation [[Verifikation|verifiziert]], d.h. formal nachgewiesen wird) | |||
→ Korrektheit (insbesondere, wenn die Erfüllung der Spezifikation [[Verifikation|verifiziert]], d.h. formal | :→ Robustheit (wenn die Überprüfungen auch durchgeführt werden) | ||
:→ Portierbarkeit (wegen der Plattformunabhängigkeit) | |||
→ Robustheit (wenn die Überprüfungen auch durchgeführt werden) | |||
→ Portierbarkeit (wegen der Plattformunabhängigkeit) | |||
===Benutze [[Schnittstelle]]n, Make Use of Interfaces=== | ===Benutze [[Schnittstelle]]n, Make Use of Interfaces=== | ||
;Benutze Schnittstellen zur Kommunikation mit Objekten, Modulen etc.: Die Verwendung von Schnittstellen zum Zugriff auf und zur Modifikation von Daten/Informationen (an Stelle eines direkten Zugriffes) ermöglicht es, Code lokal zu ändern, ohne dass dies Auswirkungen auf andere Objekte, Module etc. hat (solange sich die Schnittstellen nicht ändern). | ;Benutze Schnittstellen zur Kommunikation mit Objekten, Modulen etc.: Die Verwendung von Schnittstellen zum Zugriff auf und zur Modifikation von Daten/Informationen (an Stelle eines direkten Zugriffes) ermöglicht es, Code lokal zu ändern, ohne dass dies Auswirkungen auf andere Objekte, Module etc. hat (solange sich die Schnittstellen nicht ändern). | ||
:→ Spezifikation | |||
→ Spezifikation | :→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | ||
:→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | :→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | ||
:→ Modularität | |||
→ Stetigkeit (→ Wartbarkeit | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Modularität | |||
===Benutze [[Integritätsbedingung]]en, Make Use of Integrity Constraints, Design by Contract<ref name="Meyer">{{Quelle|Meyer, B. (1997): Object-oriented Software Construction}}</ref>=== | ===Benutze [[Integritätsbedingung]]en, Make Use of Integrity Constraints, Design by Contract<ref name="Meyer">{{Quelle|Meyer, B. (1997): Object-oriented Software Construction}}</ref>=== | ||
;Benutze und beachte Integritätsbedingungen.: Wann immer möglich sollten Integritätsbedingungen – Vorbedingungen (pre conditions), Nachbedingungen (post conditions), Invarianten (invariants), Zusicherungen (Assertions), Typdefinitionen etc. – definiert und deren Einhaltung auch überprüft werden. | ;Benutze und beachte Integritätsbedingungen.: Wann immer möglich sollten Integritätsbedingungen – Vorbedingungen (pre conditions), Nachbedingungen (post conditions), Invarianten (invariants), Zusicherungen (Assertions), Typdefinitionen etc. – definiert und deren Einhaltung auch überprüft werden. | ||
:→ Spezifikation | |||
→ Spezifikation | :→ Korrektheit | ||
:→ Robustheit | |||
→ Korrektheit | :→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | ||
→ Robustheit | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
===[[Liskovsches Substitutionsprinzip]]<ref>{{Quelle|Liskov, Wing (1993)}}</ref>, LSP, Ersetzbarkeitsprinzip, Liskov substitution principle<ref>{{Quelle|Wikipedia (EN): Liskov substitution principle}}</ref>=== | ===[[Liskovsches Substitutionsprinzip]]<ref>{{Quelle|Liskov, Wing (1993)}}</ref>, LSP, Ersetzbarkeitsprinzip, Liskov substitution principle<ref>{{Quelle|Wikipedia (EN): Liskov substitution principle}}</ref>=== | ||
;Überschreibe Methoden nicht mit unerwartetem Code.: Eine Methode sollte nicht so überschrieben werden, dass sich ein Objekt einer [[Abgeleitete Klasse|abgeleiteten Klasse]] überraschend anders verhält, als man es aufgrund der Definition der Basisklasse erwarten würde. Mit anderen Worten: Methoden, die in abgeleiteten Klassen neu definiert werden, müssen alle [[Integritätsbedingung]]en (d.h. die Spezifikation) der Basisklasse beachten. Dieses Prinzip kann also ein Spezialfall des vorangehenden Prinzips angesehen werden. | ;Überschreibe Methoden nicht mit unerwartetem Code.: Eine Methode sollte nicht so überschrieben werden, dass sich ein Objekt einer [[Abgeleitete Klasse|abgeleiteten Klasse]] überraschend anders verhält, als man es aufgrund der Definition der Basisklasse erwarten würde. Mit anderen Worten: Methoden, die in abgeleiteten Klassen neu definiert werden, müssen alle [[Integritätsbedingung]]en (d.h. die Spezifikation) der Basisklasse beachten. Dieses Prinzip kann also ein Spezialfall des vorangehenden Prinzips angesehen werden. | ||
:→ Spezifikation | |||
→ Spezifikation | :→ Korrektheit | ||
:→ Robustheit | |||
→ Korrektheit | |||
→ Robustheit | |||
===Modularität, Modularity, Teile und herrsche, Divide et impera=== | ===Modularität, Modularity, Teile und herrsche, Divide et impera=== | ||
;Teile und herrsche: Ein komplexes Problem (Vorhaben, Projekt, ...) kann man nur dadurch in den Griff bekommen, dass man es solange in kleinere, möglichst unabhängige Teilprobleme (Teilvorhaben, Phasen, Vorgänge, ...) zerlegt, bis diese lösbar (= beherrschbar) sind. Ein Programm sollte daher '''modularisiert''', d.h. in einzelne '''Module''' unterteilt werden. | ;Teile und herrsche: Ein komplexes Problem (Vorhaben, Projekt, ...) kann man nur dadurch in den Griff bekommen, dass man es solange in kleinere, möglichst unabhängige Teilprobleme (Teilvorhaben, Phasen, Vorgänge, ...) zerlegt, bis diese lösbar (= beherrschbar) sind. Ein Programm sollte daher '''modularisiert''', d.h. in einzelne '''Module''' unterteilt werden. Jedes Modul sollte nur für eine Aufgabe zuständig sein und diese korrekt und robust erfüllen. | ||
====Fünf Anforderungen von Bertrand Meyer==== | ====Fünf Anforderungen von Bertrand Meyer==== | ||
Zeile 201: | Zeile 155: | ||
=====Modulare Zerlegbarkeit, modular decomposability===== | =====Modulare Zerlegbarkeit, modular decomposability===== | ||
;Zerlege ein Problem in unterschiedliche, seperat lösbare Teilprobleme. | ;Zerlege ein Problem in unterschiedliche, seperat lösbare Teilprobleme. | ||
:→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | :→ Wiederverwendbarkeit (wenn die Module weitgehend unabhängig voneinander sind) | ||
→ Wiederverwendbarkeit (wenn die Module weitgehend unabhängig voneinander sind) | |||
=====Modulare Zusammenfügbarkeit, modular composability===== | =====Modulare Zusammenfügbarkeit, modular composability===== | ||
;Module sollten in möglichst vielen (unterschiedlichen) Situationen/Anwendungen eingesetzt werden können. | ;Module sollten in möglichst vielen (unterschiedlichen) Situationen/Anwendungen eingesetzt werden können. | ||
:Das heißt, Module sollten auf unterschiedliche Art und Weise zu neuen Funktionseinheiten zusammengefügt werden können. | :Das heißt, Module sollten auf unterschiedliche Art und Weise zu neuen Funktionseinheiten zusammengefügt werden können. | ||
:→ Wartbarkeit | |||
→ Wiederverwendbarkeit | :→ Wiederverwendbarkeit | ||
:→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
=====Modulare Verständlichkeit, modular understandability===== | =====Modulare Verständlichkeit, modular understandability===== | ||
;Die Aufgaben eines Moduls sollten verstanden werden, ohne dass man viele andere Module kennen muss. | ;Die Aufgaben eines Moduls sollten verstanden werden, ohne dass man viele andere Module kennen muss. | ||
:→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
''Dies ist ein Spezialfall des Prinzips „[[#Verst.C3.A4ndlichkeit.2C_Comprehesibility.2C_Lesbarkeit.2C_Readability|Verständlichkeit]]“.'' | ''Dies ist ein Spezialfall des Prinzips „[[#Verst.C3.A4ndlichkeit.2C_Comprehesibility.2C_Lesbarkeit.2C_Readability|Verständlichkeit]]“.'' | ||
Zeile 230: | Zeile 174: | ||
;Kleine Änderungen an den Anforderungen sollten nur Änderungen an einer geringen Zahl von Modulen zur Folgen haben. | ;Kleine Änderungen an den Anforderungen sollten nur Änderungen an einer geringen Zahl von Modulen zur Folgen haben. | ||
:Im besten Fall ist nur ein einziges Modul betroffen. | :Im besten Fall ist nur ein einziges Modul betroffen. | ||
:→ Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit) | |||
→ Stetigkeit (→ Wartbarkeit | |||
''Dies ist ein Spezialfall des Prinzips „[[#Stetigkeit.2C_Continuity|Stetigkeit]]“.'' | ''Dies ist ein Spezialfall des Prinzips „[[#Stetigkeit.2C_Continuity|Stetigkeit]]“.'' | ||
Zeile 238: | Zeile 181: | ||
;Ein Modul sollte alle abnormalen Fälle selbst behandeln. | ;Ein Modul sollte alle abnormalen Fälle selbst behandeln. | ||
:Das heißt, es sollte sich nicht darauf verlassen, dass ein anderes Modul die Schnittstellen nur gemäß der Spezifikation verwendet. | :Das heißt, es sollte sich nicht darauf verlassen, dass ein anderes Modul die Schnittstellen nur gemäß der Spezifikation verwendet. | ||
:→ Korrektheit | |||
→ Korrektheit | :→ Robustheit | ||
:→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Robustheit | :→ Wartbarkeit | ||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Wartbarkeit | |||
====Sechs Prinzipien von Bertrand Meyer==== | ====Sechs Prinzipien von Bertrand Meyer==== | ||
Zeile 253: | Zeile 192: | ||
=====Syntaktische Einheiten, Syntactical Units===== | =====Syntaktische Einheiten, Syntactical Units===== | ||
;Module sind syntaktische Einheiten.: Module sollten unabhängig voneinander übersetzt und in Bibliotheken zur Verfügung gestellt werden können. | ;Module sind syntaktische Einheiten.: Module sollten unabhängig voneinander übersetzt und in Bibliotheken zur Verfügung gestellt werden können. | ||
:→ Wiederverwendbarkeit | |||
→ Wiederverwendbarkeit | :→ Korrektheit | ||
:→ Robustheit | |||
→ Korrektheit | :→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | ||
:→ Wartbarkeit | |||
→ Robustheit | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Wartbarkeit | |||
=====Wenige Schnittstellen, Few Interfaces===== | =====Wenige Schnittstellen, Few Interfaces===== | ||
; Module sollten wenige Schnittstellen haben.: Module sollten mit so wenig anderen Modulen kommunizieren wie möglich. | ; Module sollten wenige Schnittstellen haben.: Module sollten mit so wenig anderen Modulen kommunizieren wie möglich. | ||
:→ Wiederverwendbarkeit | |||
→ Wiederverwendbarkeit | :→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | ||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
=====Schlanke Interfaces, Small Interfaces===== | =====Schlanke Interfaces, Small Interfaces===== | ||
; Module sollten schlanke Schnittstellen haben.: Schnittstellen sollten nicht mit Funktionalität überfrachtet sein. Das heißt, zwei Module sollten über möglichst umfangarme Schnittstellen miteinander kommunizieren. | ; Module sollten schlanke Schnittstellen haben.: Schnittstellen sollten nicht mit Funktionalität überfrachtet sein. Das heißt, zwei Module sollten über möglichst umfangarme Schnittstellen miteinander kommunizieren. | ||
:→ Wartbarkeit | |||
→ Wartbarkeit | :→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | ||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
=====Explizite Schnittstellen, Explicit Interfaces===== | =====Explizite Schnittstellen, Explicit Interfaces===== | ||
; Module sollten über explizite Schnittstellen kommunizieren.: Ein Modul sollte nicht über globale Variablen oder andere implizite Kommunikationswege mit anderen Modulen kommunizieren, sondern über explizite Schnittstellen. | ; Module sollten über explizite Schnittstellen kommunizieren.: Ein Modul sollte nicht über globale Variablen oder andere implizite Kommunikationswege mit anderen Modulen kommunizieren, sondern über explizite Schnittstellen. | ||
:→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
=====(Daten-)[[Kapselung]], Geheimnisprinzip, Encapsulation, Information Hiding===== | =====(Daten-)[[Kapselung]], Geheimnisprinzip, Encapsulation, Information Hiding===== | ||
;Informationen sollten in Modulen gekapselt sein.: Jede Information, die nicht notwendig ist, um die Aufgaben bzw. die Funktionalität eines Moduls zu verstehen bzw. zu benutzen, sollte von außen nicht zugänglich sein. | ;Informationen sollten in Modulen gekapselt sein.: Jede Information, die nicht notwendig ist, um die Aufgaben bzw. die Funktionalität eines Moduls zu verstehen bzw. zu benutzen, sollte von außen nicht zugänglich sein. | ||
:→ Korrektheit | |||
→ Korrektheit | :→ Robustheit | ||
:→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Robustheit | :→ Wiederverwendbarkeit | ||
:→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Wiederverwendbarkeit | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
=====Offen-geschlossen-Prinzip, Open-Closed Principle===== | =====Offen-geschlossen-Prinzip, Open-Closed Principle===== | ||
; Module sollten sowohl offen, als auch geschlossen sein.: Module sollten sowohl offen für Veränderungen, als auch abgeschlossen gegenüber Veränderungen sein. Da heißt, ein funktionierendes Modul sollte möglichst nicht mehr verändert werden, aber andererseits sollte es problemlos möglich sein, ein Modul an neue Gegebenheiten anzupassen. In objektorientierten Sprachen wird dies vor allem durch [[Vererbung]], [[Überschreiben|Überschreiben von Methoden]] und die Verwendung von [[Abstrakte Klasse|Abstrakten Klassen]] (insbesondere [[Interface]]s) erreicht. | ; Module sollten sowohl offen, als auch geschlossen sein.: Module sollten sowohl offen für Veränderungen, als auch abgeschlossen gegenüber Veränderungen sein. Da heißt, ein funktionierendes Modul sollte möglichst nicht mehr verändert werden, aber andererseits sollte es problemlos möglich sein, ein Modul an neue Gegebenheiten anzupassen. In objektorientierten Sprachen wird dies vor allem durch [[Vererbung]], [[Überschreiben|Überschreiben von Methoden]] und die Verwendung von [[Abstrakte Klasse|Abstrakten Klassen]] (insbesondere [[Interface]]s) erreicht. | ||
:→ Wiederverwendbarkeit (wenn Module offen sind) | |||
→ Wiederverwendbarkeit (wenn Module offen sind) | :→ Erweiterbar (wenn Module offen sind) | ||
:→ Robustheit (wenn getestete Module geschlossen sind) | |||
→ Erweiterbar (wenn Module offen sind) | :→ Wartbarkeit (wenn funktionierende Module geschlossen sind; jede Änderung an einem Modul hat eventuell weitere Änderungen zu Folgen → dies soll nach Möglichkeit vermieden werden) | ||
→ Robustheit (wenn getestete Module geschlossen sind) | |||
→ Wartbarkeit (wenn | |||
====Weitere Modul-Prinzipien==== | ====Weitere Modul-Prinzipien==== | ||
Zeile 313: | Zeile 233: | ||
=====[[Entwurfsmuster|Verwende Design Patterns]]<ref>{{Quelle|Gamma et al. (1995)}}</ref>===== | =====[[Entwurfsmuster|Verwende Design Patterns]]<ref>{{Quelle|Gamma et al. (1995)}}</ref>===== | ||
;Verwende die in [[Entwurfsmuster]]n (design patterns) definierten Modul-„Schablonen“.:In der Programmierung gibt es viele Aufgaben, die immer wiederkehren, wie zum Beispiel das Durchlaufen einer Menge von Objekten. Für zahlreiche derartige Aufgaben gibt es praxiserprobte Modul-„Schablonen“. Diese beschreiben, welche Schnittstellen, Klassen, Objekte etc. benötigt werden, um die jeweilige Aufgabe zu lösen. | ;Verwende die in [[Entwurfsmuster]]n (design patterns) definierten Modul-„Schablonen“.:In der Programmierung gibt es viele Aufgaben, die immer wiederkehren, wie zum Beispiel das Durchlaufen einer Menge von Objekten. Für zahlreiche derartige Aufgaben gibt es praxiserprobte Modul-„Schablonen“. Diese beschreiben, welche Schnittstellen, Klassen, Objekte etc. benötigt werden, um die jeweilige Aufgabe zu lösen. | ||
:→ Wiederverwendbarkeit | |||
→ Wiederverwendbarkeit | :→ Korrektheit | ||
:→ Robustheit | |||
→ Korrektheit | :→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit) | ||
→ Robustheit | |||
→ Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit | |||
=====[[Separation of Concerns]]<ref>{{Quelle|Wikipedia (EN): Separation of concerns}}</ref>===== | =====[[Separation of Concerns]]<ref>{{Quelle|Wikipedia (EN): Separation of concerns}}</ref>===== | ||
Zeile 328: | Zeile 244: | ||
;Jede Aufgabe wird von genau einem Modul erfüllt und jedes Modul erfüllt genau eine Aufgabe.:Bei der [[objektorientierten Programmierung]] treibt man die Modularisierung manchmal sogar so weit, dass nicht nur für jede Aufgabe höchstens ein Objekt zuständig ist (Separations of Conerns), sondern dass umgekehrt auch jedes Objekt für genau eine Aufgabe zuständig ist (Single responsibility principle). | ;Jede Aufgabe wird von genau einem Modul erfüllt und jedes Modul erfüllt genau eine Aufgabe.:Bei der [[objektorientierten Programmierung]] treibt man die Modularisierung manchmal sogar so weit, dass nicht nur für jede Aufgabe höchstens ein Objekt zuständig ist (Separations of Conerns), sondern dass umgekehrt auch jedes Objekt für genau eine Aufgabe zuständig ist (Single responsibility principle). | ||
:Das heißt, für jedes Modul gibt es genau einen Grund, warum es geändert werden muss: Die eine Aufgabe, die es hat, ändert sich. | :Das heißt, für jedes Modul gibt es genau einen Grund, warum es geändert werden muss: Die eine Aufgabe, die es hat, ändert sich. | ||
:→ Robustheit | |||
→ Robustheit | |||
=====[[Interface-Segregation-Prinzip]]<ref>{{Quelle|Martin, R.C. (1996): The Interface Segregation Principle}}</ref>, Interface Segregation Principle===== | =====[[Interface-Segregation-Prinzip]]<ref>{{Quelle|Martin, R.C. (1996): The Interface Segregation Principle}}</ref>, Interface Segregation Principle===== | ||
;Zu große Interfaces sollten in mehrere Interfaces aufgeteilt werden.: Ein Modul, das ein Interface benutzt, sollte nur diejenigen Methoden präsentiert bekommen, die sie auch wirklich benötigt. Dieses Prinzip formuliert eine konkrete Möglichkeit, wie man die von Meyer geforderten schlanken Schnittstellen realisieren kann. | ;Zu große Interfaces sollten in mehrere Interfaces aufgeteilt werden.: Ein Modul, das ein Interface benutzt, sollte nur diejenigen Methoden präsentiert bekommen, die sie auch wirklich benötigt. Dieses Prinzip formuliert eine konkrete Möglichkeit, wie man die von Meyer geforderten schlanken Schnittstellen realisieren kann. | ||
:→ Wartbarkeit | |||
→ Wartbarkeit | :→ Wiederverwendbarkeit | ||
:→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
→ Wiederverwendbarkeit | |||
→ Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit) | |||
==Quellen== | ==Quellen== | ||
Zeile 353: | Zeile 265: | ||
#{{Vgl|Wikipedia (EN): DRY}} | #{{Vgl|Wikipedia (EN): DRY}} | ||
#[[WikipediaEn:Category:Programmingprinciples]] | #[[WikipediaEn:Category:Programmingprinciples]] | ||
#[[Wikipedia:Prinzipien | #[[Wikipedia:Prinzipien objektorientierten Designs]] | ||
#[[WikipediaEn:Code smell]] | #[[WikipediaEn:Code smell]] | ||
{{TBD|Principle of Least Surprise}} | {{TBD|Principle of Least Surprise}} | ||
[[Kategorie:Programmierprinzip]] | [[Kategorie:Programmierprinzip]] | ||
[[Kategorie:HowTo]] | [[Kategorie:HowTo]] | ||
[[en:Programing principles]] | [[en:Programing principles]] |
Aktuelle Version vom 6. April 2022, 16:29 Uhr
Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:
Korrektheit: 5 (vollständig überprüft) |
Umfang: 4 (unwichtige Fakten fehlen) |
Quellenangaben: 2 (wichtige Quellen fehlen) |
Quellenarten: 3 (gut) |
Konformität: 5 (ausgezeichnet) |
Anmerkung: In diesem Artikel haben die beiden Folgerungspfeile „→“ und „⇒“ folgende Bedeutungen:
- ⇒: „hat zur Folge“
- →: „trägt bei zu“, „verbessert“, „erhöht“
Zweck
Um nützliche und dennoch preiswerte Programme und Anwendungen erstellen zu können, sollte man eine Reihe von Programmierprinzipien beachten.
Bevor die Programmierprinzipien näher beschrieben werden können, werden zunächst die Ziele genauer spezifiziert, die mit diesen Prinzipien erreicht werden sollen.
Ziele
Ziel eines jeden Softwareentwicklungs-Vorhabens sollte die Erstellung von Software sein, die zwei Eigenschaften aufweist:
- nützlich (useful)
- Die Software sollte für den Benutzer nützlich sein.
- preiswert (inexpensive)
- Die Software sollte so geringe Kosten und Folgekosten verursachen wie möglich.
Software-Eigenschaften zur Erfüllung der beiden Ziele
Um die beiden vorgenannten Ziele zu erreichen, sollte ein Softwarepaket folgende Eigenschaften haben:
- spezifiziert (specified)
- Um die Nützlichkeit und die Korrektheit des Softwarepakets beurteilen zu können, bevor es eingesetzt wird, sollte eine Spezifikation vorliegen, die detailliert die Aufgaben und Eigenschaften des Paketes beschreibt.
- ⇒ Nützlichkeit (ist abschätzbar)
- korrekt (correct)
- Die Implementierung des Paketes sollte korrekt sein, es sollte also die Spezifikation in allen Punkten erfüllen.
- ⇒ Nützlichkeit: Eine Software, die nicht korrekt arbeitet, nutzt dem Benutzer in den fehlerhaften Situationen nicht.
- ⇒ keine Kosten durch falsches oder unerwartetes Verhalten
- robust (robust)
- Das Softwarepaket sollte auch in abnormalen (nicht-spezifizierten) Situationen stabil laufen.
- ⇒ keine Kosten durch Inkonsistenzen
- ⇒ geringe Kosten bei Bedienungsfehlern und Systemausfällen
- benutzbar (usable)
- Das Softwarepaket sollte einfach zu erlernen und zu benutzen sein.
- ⇒ Nützlichkeit wird verbessert
- ⇒ geringe Schulungskosten
- ⇒ fehlerhafte Nutzung kommt nur selten vor und hat daher nur selten Kosten zu Folge
- ⇒ keine Kosten durch frustrierte Benutzer
- sicher (secure)
- Unautorisierter Zugriff auf Daten oder Programme sollte unmöglich sein.
- ⇒ keine Kosten durch Sicherheitsmängel
- effizient (efficient)
- Das Softwarepakt sollte eine möglichst gute Laufzeit- und Speichereffizienz aufweisen, d.h. die vorhandenen Ressourcen möglichst gut ausnutzen.
- ⇒ geringe Personalkosten durch geringe Wartezeiten
- ⇒ geringe Kosten durch geringe Hardwareanforderungen
- wartbar (maintainable)
- Das Softwarepaket sollte leicht an neue Gegebenheiten angepasst werden können. Fehler sollten leicht behoben werden können (da sie sich nie ganz vermeiden lassen).
- ⇒ geringe Wartungskosten
- wiederverwendbar (reusable)
- Erweiterungen der Spezifikation sollten wiederverwendet werden können.
- ⇒ geringe Wartungskosten und Erweiterungskosten
- ⇒ geringere Kosten bei Folgeprojekten
Für die Eigenschaft „wartbar“ gibt es drei Spezialfälle, die hier gesondert genannt werden sollen:
- kompatibel (compatible)
- Das Softwarepaket sollte kompatibel zu bestehenden Systemen sein, es sollte also standardisierte Schnittstellen unterstützen.
- ⇒ geringe Intergrations- und Anpassungskosten
- portabel (portable)
- Das Softwarepaket sollte einfach auf neue Systeme portiert werden können.
- ⇒ geringe Kosten bei Änderung der Ablaufumgebung
- erweiterbar (extensible)
- Erweiterungen der Spezifikation sollten schnell implementiert werden können.
- ⇒ geringe Wartungskosten
Programmierprinzipien
Um die vorgenannten Ziele zu erreichen, sollten folgende Programmierprinzipien beachtet werden:
Verständlichkeit, Comprehensibility, Lesbarkeit, Readability
- Schreibe lesbaren und verständlichen Code.
- Der Programmcode sollte so einfach wie möglich gelesen und verstanden werden können. Das heißt, der Code sollte sauber formatiert werden, es sollten sprechende Bezeichner verwendet werden, es sollten sinnvolle Kommentare eingefügt werden etc. Ein erfahrender Programmierer sollte die Bedeutung der einzelnen Anweisungen, Operationen, Definitionen etc. problemlos erfassen können.
- → Überprüfbarkeit (durch Programmierer und nicht nur durch Compiler u.Ä.) (→ Korrektheit, Robustheit)
- → Wartbarkeit (da die Programme auch von anderen Programmierern verstanden werden)
Schreibbarkeit, Writability
- Verwende eine Programmiersprache und -umgebung, die dich beim Schreiben des Codes unterstützt.
- Der Programmcode sollte so einfach wie möglich geschrieben werden können. Zum einen sollte es die Programmiersprache ermöglichen, einfachen und eleganten Code zu schreiben. Und zum anderen sollten die Programmwerkzeuge einen bei der Erstellung des Codes möglichst gut unterstützen.
Vorteile:
- Code kann schneller erstellt werden.
- Code kann automatisch formatiert werden.
- Fehler/Warnungen werden von der Programmierumgebung zeitnah gemeldet.
- Fehler werden vermieden (wenn beispielsweise Code-Fragmente automatisch generiert werden).
- → Korrektheit
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
Stetigkeit, Continuity
- Schreibe stetigen Code.
- Schreibe den Code so, dass kleine Änderungen an der Spezifikation auch nur kleine Änderungen am Code zur Folge haben.
- → Wartbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden)
- → Wiederverwendbarkeit (der Code kann schnell an neue Gegebenheiten angepasst werden)
Konfigurierbarkeit, Customizability
- Schreibe konfigurierbaren Code.
- Konstante Werte sollten im Allgemeinen nicht direkt in den Code eingefügt werden, sondern als konstante Werte separat definiert werden (Ausnahme: triviale Konstanten, die sich sicher nie ändern werden, wie z.B. Vergleiche mit dem Wert
0
). Konstanten, die das Programmverhalten beeinflussen, sollten im Allgemeinen beim Programmstart aus einer Konfigurationsdatei ausgelesen werden. - → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
Don't repeat yourself, DRY[1]
- Wiederhole dich nicht.
- Code sollte nicht dupliziert und anschließend aber gar nicht oder nur marginal modifiziert werden.
- → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
- → Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit)
- → Robustheit (da keine inkonsistenten Änderungen an mehreren Stellen möglich sind)
Repeat yourself, RY[2]
- Wiederhole dich.
- In Benutzerschnittstellen sollten gleiche oder vergleichbare Aufgaben immer auf dieselbe Weise vom Benutzer durchgeführt werden können. Es sollten dieselben Bezeichner, dieselben bzw. gleichartige Bedienelemente, dasselbe Design etc. verwendet werden.
- → Wiederverwendbarkeit (da gleichartige Elemente nicht mehrfach implementiert werden müssen; DRY)
- → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
- → Verständlichkeit (da weniger Code existiert) (→ Korrektheit, Robustheit, Wartbarkeit)
Gesetz von Demeter[3], Law of Demeter, LoD
- „Sprich nur zu deinen nächsten Freunden.“
- Ein Objekt sollte nur Methoden von Objekten aufrufen, die es „persönlich“ kennt:
- Objekte, die in Zustandsvariablen gespeichert sind
- Objekte, die über direkte Beziehungen zugänglich sind
- Objekte, die mittels Parametern beim Methodenaufruf übergeben wurden
- Objekte, die das aktuelle Objekt selbst erzeugt hat
- → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
- → Verständlichkeit (da die Anzahl der Kommunikationspartner geringer ist) (→ Korrektheit, Robustheit, Wartbarkeit)
Überprüfbarkeit, Verifiability
- Schreibe überprüfbaren Code.
- Die Korrektheit eines Softwarepakets sollte plattformunabhängig sein und automatisch überprüft werden können. Viele Programmierparadigmen und auch Projekttechniken verlangen zu diesem Zweck, dass gleichzeitig mit der Software auch passende Softwaretests implementiert werden (Modultests, Unittests). Noch besser ist es, wenn die Semantik des Programms formal spezifiziert und überprüft werden kann (Abstrakte Datentypen, Integritätsbedingungen, ...)
- → Korrektheit (insbesondere, wenn die Erfüllung der Spezifikation verifiziert, d.h. formal nachgewiesen wird)
- → Robustheit (wenn die Überprüfungen auch durchgeführt werden)
- → Portierbarkeit (wegen der Plattformunabhängigkeit)
Benutze Schnittstellen, Make Use of Interfaces
- Benutze Schnittstellen zur Kommunikation mit Objekten, Modulen etc.
- Die Verwendung von Schnittstellen zum Zugriff auf und zur Modifikation von Daten/Informationen (an Stelle eines direkten Zugriffes) ermöglicht es, Code lokal zu ändern, ohne dass dies Auswirkungen auf andere Objekte, Module etc. hat (solange sich die Schnittstellen nicht ändern).
- → Spezifikation
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
- → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
- → Modularität
Benutze Integritätsbedingungen, Make Use of Integrity Constraints, Design by Contract[4]
- Benutze und beachte Integritätsbedingungen.
- Wann immer möglich sollten Integritätsbedingungen – Vorbedingungen (pre conditions), Nachbedingungen (post conditions), Invarianten (invariants), Zusicherungen (Assertions), Typdefinitionen etc. – definiert und deren Einhaltung auch überprüft werden.
- → Spezifikation
- → Korrektheit
- → Robustheit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
Liskovsches Substitutionsprinzip[5], LSP, Ersetzbarkeitsprinzip, Liskov substitution principle[6]
- Überschreibe Methoden nicht mit unerwartetem Code.
- Eine Methode sollte nicht so überschrieben werden, dass sich ein Objekt einer abgeleiteten Klasse überraschend anders verhält, als man es aufgrund der Definition der Basisklasse erwarten würde. Mit anderen Worten: Methoden, die in abgeleiteten Klassen neu definiert werden, müssen alle Integritätsbedingungen (d.h. die Spezifikation) der Basisklasse beachten. Dieses Prinzip kann also ein Spezialfall des vorangehenden Prinzips angesehen werden.
- → Spezifikation
- → Korrektheit
- → Robustheit
Modularität, Modularity, Teile und herrsche, Divide et impera
- Teile und herrsche
- Ein komplexes Problem (Vorhaben, Projekt, ...) kann man nur dadurch in den Griff bekommen, dass man es solange in kleinere, möglichst unabhängige Teilprobleme (Teilvorhaben, Phasen, Vorgänge, ...) zerlegt, bis diese lösbar (= beherrschbar) sind. Ein Programm sollte daher modularisiert, d.h. in einzelne Module unterteilt werden. Jedes Modul sollte nur für eine Aufgabe zuständig sein und diese korrekt und robust erfüllen.
Fünf Anforderungen von Bertrand Meyer
Bertrand Meyer war einer der ersten, der die Bedeutung der Modularität erkannt und beschrieben hat. Er hat insgesamt fünf Anforderungen formuliert, die bei der Definition von Modulen beachtet werden sollten:[4]
Modulare Zerlegbarkeit, modular decomposability
- Zerlege ein Problem in unterschiedliche, seperat lösbare Teilprobleme.
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
- → Wiederverwendbarkeit (wenn die Module weitgehend unabhängig voneinander sind)
Modulare Zusammenfügbarkeit, modular composability
- Module sollten in möglichst vielen (unterschiedlichen) Situationen/Anwendungen eingesetzt werden können.
- Das heißt, Module sollten auf unterschiedliche Art und Weise zu neuen Funktionseinheiten zusammengefügt werden können.
- → Wartbarkeit
- → Wiederverwendbarkeit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
Modulare Verständlichkeit, modular understandability
- Die Aufgaben eines Moduls sollten verstanden werden, ohne dass man viele andere Module kennen muss.
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
Dies ist ein Spezialfall des Prinzips „Verständlichkeit“.
Modulare Stetigkeit, modular continuity
- Kleine Änderungen an den Anforderungen sollten nur Änderungen an einer geringen Zahl von Modulen zur Folgen haben.
- Im besten Fall ist nur ein einziges Modul betroffen.
- → Stetigkeit (→ Wartbarkeit, Wiederverwendbarkeit)
Dies ist ein Spezialfall des Prinzips „Stetigkeit“.
Modulare Robustheit, modular protection
- Ein Modul sollte alle abnormalen Fälle selbst behandeln.
- Das heißt, es sollte sich nicht darauf verlassen, dass ein anderes Modul die Schnittstellen nur gemäß der Spezifikation verwendet.
- → Korrektheit
- → Robustheit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
- → Wartbarkeit
Sechs Prinzipien von Bertrand Meyer
Aus diesen Forderungen leitet Bertrand Meyer sechs Prinzipien ab, die bei der Entwicklung von Modulen beachtet werden sollten.
Syntaktische Einheiten, Syntactical Units
- Module sind syntaktische Einheiten.
- Module sollten unabhängig voneinander übersetzt und in Bibliotheken zur Verfügung gestellt werden können.
- → Wiederverwendbarkeit
- → Korrektheit
- → Robustheit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
- → Wartbarkeit
Wenige Schnittstellen, Few Interfaces
- Module sollten wenige Schnittstellen haben.
- Module sollten mit so wenig anderen Modulen kommunizieren wie möglich.
- → Wiederverwendbarkeit
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
Schlanke Interfaces, Small Interfaces
- Module sollten schlanke Schnittstellen haben.
- Schnittstellen sollten nicht mit Funktionalität überfrachtet sein. Das heißt, zwei Module sollten über möglichst umfangarme Schnittstellen miteinander kommunizieren.
- → Wartbarkeit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
Explizite Schnittstellen, Explicit Interfaces
- Module sollten über explizite Schnittstellen kommunizieren.
- Ein Modul sollte nicht über globale Variablen oder andere implizite Kommunikationswege mit anderen Modulen kommunizieren, sondern über explizite Schnittstellen.
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
(Daten-)Kapselung, Geheimnisprinzip, Encapsulation, Information Hiding
- Informationen sollten in Modulen gekapselt sein.
- Jede Information, die nicht notwendig ist, um die Aufgaben bzw. die Funktionalität eines Moduls zu verstehen bzw. zu benutzen, sollte von außen nicht zugänglich sein.
- → Korrektheit
- → Robustheit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
- → Wiederverwendbarkeit
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
Offen-geschlossen-Prinzip, Open-Closed Principle
- Module sollten sowohl offen, als auch geschlossen sein.
- Module sollten sowohl offen für Veränderungen, als auch abgeschlossen gegenüber Veränderungen sein. Da heißt, ein funktionierendes Modul sollte möglichst nicht mehr verändert werden, aber andererseits sollte es problemlos möglich sein, ein Modul an neue Gegebenheiten anzupassen. In objektorientierten Sprachen wird dies vor allem durch Vererbung, Überschreiben von Methoden und die Verwendung von Abstrakten Klassen (insbesondere Interfaces) erreicht.
- → Wiederverwendbarkeit (wenn Module offen sind)
- → Erweiterbar (wenn Module offen sind)
- → Robustheit (wenn getestete Module geschlossen sind)
- → Wartbarkeit (wenn funktionierende Module geschlossen sind; jede Änderung an einem Modul hat eventuell weitere Änderungen zu Folgen → dies soll nach Möglichkeit vermieden werden)
Weitere Modul-Prinzipien
Seit den wegweisenden Arbeiten von Bertrand Meyer aus den späten 80er-Jahren wurden weitere Prinzipien entwickelt, die die Definition von Modulen betreffen.
Verwende Design Patterns[7]
- Verwende die in Entwurfsmustern (design patterns) definierten Modul-„Schablonen“.
- In der Programmierung gibt es viele Aufgaben, die immer wiederkehren, wie zum Beispiel das Durchlaufen einer Menge von Objekten. Für zahlreiche derartige Aufgaben gibt es praxiserprobte Modul-„Schablonen“. Diese beschreiben, welche Schnittstellen, Klassen, Objekte etc. benötigt werden, um die jeweilige Aufgabe zu lösen.
- → Wiederverwendbarkeit
- → Korrektheit
- → Robustheit
- → Verständlichkeit (→ Korrektheit, Robustheit, Wartbarkeit)
Separation of Concerns[8]
- Jede Aufgabe wird von genau einem Modul erfüllt.
- Man also die „Verantwortlichkeiten“ unter den Modulen aufteilen, sonst gehen die Vorteile der Modularisierung zum Teil wieder verloren.
Single Responsibility Principle[9]
- Jede Aufgabe wird von genau einem Modul erfüllt und jedes Modul erfüllt genau eine Aufgabe.
- Bei der objektorientierten Programmierung treibt man die Modularisierung manchmal sogar so weit, dass nicht nur für jede Aufgabe höchstens ein Objekt zuständig ist (Separations of Conerns), sondern dass umgekehrt auch jedes Objekt für genau eine Aufgabe zuständig ist (Single responsibility principle).
- Das heißt, für jedes Modul gibt es genau einen Grund, warum es geändert werden muss: Die eine Aufgabe, die es hat, ändert sich.
- → Robustheit
Interface-Segregation-Prinzip[10], Interface Segregation Principle
- Zu große Interfaces sollten in mehrere Interfaces aufgeteilt werden.
- Ein Modul, das ein Interface benutzt, sollte nur diejenigen Methoden präsentiert bekommen, die sie auch wirklich benötigt. Dieses Prinzip formuliert eine konkrete Möglichkeit, wie man die von Meyer geforderten schlanken Schnittstellen realisieren kann.
- → Wartbarkeit
- → Wiederverwendbarkeit
- → Überprüfbarkeit (→ Korrektheit, Robustheit, Portierbarkeit)
Quellen
- ↑ Hunt, Thomas (2003): Andrew Hunt und David Thomas; Der Pragmatische Programmierer; Verlag: Fachbuchverlag Leipzig im Carl Hanser Verlag; ISBN: 3446223096, 978-3446223097; 2003; Quellengüte: 5 (Buch)
- ↑ Kowarschick (WebProg): Wolfgang Kowarschick; Vorlesung „Web-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2024; Quellengüte: 3 (Vorlesung)
- ↑ Lieberherr, Holland (1989): Karl J. Lieberherr und Ian M. Holland; Assuring Good Style for Object-Oriented Programs; in: IEEE Software; Band: 6; Nummer: 5; Seite(n): 36–48; Verlag: IEEE Computer Society Press; Adresse: Los Alamitos, CA, USA; 1989; Quellengüte: 5 (Artikel)
- ↑ 4,0 4,1 Meyer (1997): Bertrand Meyer; Object-oriented Software Construction; Auflage: 2; Verlag: Prentice Hall International; ISBN: 0136291554; 1997; Quellengüte: 5 (Buch)
- ↑
- ↑ WikipediaEN:Liskov substitution principle: Wikipedia-Autoren; Wikipedia, die freie Enzyklopädie – Liskov substitution principle; Organisation: Wikimedia Foundation Inc.; Adresse: San Francisco; http://en.wikipedia.org/w/index.php?title=Liskov_substitution_principle&oldid=499629316; 2012; Quellengüte: 5 (Web)
- ↑ Gamma et al. (1995): Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides; Design Patterns – Elements of Reusable Object-Oriented Software; Auflage: 1; Verlag: Addison-Wesley Longman; Adresse: Amsterdam; ISBN: 0201633612; 1995; Quellengüte: 5 (Buch)
- ↑ WikipediaEN:Separation_of_concerns: Wikipedia-Autoren; Wikipedia, die freie Enzyklopädie – Separation_of_concerns; Organisation: Wikimedia Foundation Inc.; Adresse: San Francisco; http://en.wikipedia.org/w/index.php?title=Separation_of_concerns&oldid=508337060; 2012; Quellengüte: 5 (Web)
- ↑ WikipediaEN:Single responsibility principle: Wikipedia-Autoren; Wikipedia, die freie Enzyklopädie – Single responsibility principle; Organisation: Wikimedia Foundation Inc.; Adresse: San Francisco; http://en.wikipedia.org/w/index.php?title=Single_responsibility_principle&oldid=507275547; 2012; Quellengüte: 5 (Web)
- ↑ Martin (1996): Robert C. Martin; The Interface Segregation Principle; in: C++ Report; Band: 8; Web-Link; 1996; Quellengüte: 5 (Artikel)
- Wintersteiger, Mathis (2011): Andreas Wintersteiger und Christoph Mathis; Clean Code – Prinzipien bei der Entwicklung von sauberem Code; in: Entwickler Magazin; Band: 2011; Nummer: 5; Seite(n): 13–20; Adresse: Frankfurt am Main; ISSN: 1619-7941; 2011; Quellengüte: 5 (Artikel)
- Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)
Siehe auch
- Softwaretechnik
- Wikipedia (EN): DRY (Web)
- WikipediaEn:Category:Programmingprinciples
- Wikipedia:Prinzipien objektorientierten Designs
- WikipediaEn:Code smell
TO BE DONE
- Principle of Least Surprise