Aufbau großer Programme [Aufbau großer Programme] (Aufbau großer Programme), Lektion, Seite 722307
https://www.purl.org/stefan_ram/pub/aufbau_grosser_programme (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram

Aufbau großer Programme

Im Intensivkurs C  wurden bisher schon verschiedene Hinweise zum Aufbau von Programmen gegeben, insbesondere wurde die Verwendung abstrakter Datentypen empfohlen. Hier werden einige Punkte noch einmal kurz wiederholt und andere als Ergänzung genannt. Für dieses umfangreiche Thema muß aber sonst auf die Literatur verwiesen werden.

Ein Programm ist „groß“ im Sinne dieser Lektion, wenn es so groß ist, daß es ohne den Einsatz besonderer Strukturierungsmittel unübersichtlich oder unwartbar werden würde. Große Programme sind die wesentliche Herausforderung der angewandten Informatik.

Ein Problem der Lehre ist es, daß der Aufbau eines großen Programms von der Planung bis zur Auslieferung kaum realistisch in einem Kurs behandelt werden kann, so daß der Lernende damit oft erst nach seiner Ausbildung konfrontiert wird. So werden auch die folgende Ausführungen abstrakt bleiben müssen, ohne am Beispiel eines „großen Programms“ veranschaulicht werden zu können.

Programme werden mehr gewartet  als neu geschrieben. Niemand kann vor der Änderung eines großen Programms alle Programmteile kennenlernen (wenn man beim letzten angekommen wäre, hätte man den ersten schon wieder vergessen: Das gesamte Programm paßt einfach nicht mehr in einen Kopf). Daher ist es von entscheidender Wichtigkeit, bei einer Änderungsanforderung schnell ermitteln zu können, welcher Programmteil verändert werden muß, und diesen alsdann isoliert  ändern zu können, ohne  andere Programmteile dabei kennen zu müssen. Dafür ist hohe Kohäsion  und geringe Kopplung  wichtig: Jeder Programmteil muß bestimmte dokumentierte Zuständigkeiten haben, so daß man weiß, in welchem Programmteil eine bestimmte Änderung vorzunehmen ist, und mit anderen Programmteilen möglichst wenig gekoppelt sein, damit sie dort und nur dort vorgenommen zu werden braucht. Vergleichsweise zerlegt man auch Maschinen gerne in Teile mit bestimmten Aufgaben und Schnittstellen: Beim Auto etwa in einen Motor, ein Getriebe, eine Lichtmaschine und so weiter.

Die Qualität von Quelltext wird daher im wesentlichen durch seine Wartbarkeit und Lesbarkeit (Verständlichkeit) bestimmt.

Definition der Aufgabenstellung (Abgrenzung nach außen)

Bevor ein Programm geschrieben werden kann, sollten die Anforderungen natürlich erst einmal festgelegt sein. Hierfür empfiehlt sich die Schriftform, da bloße gedankliche oder mündliche Festlegungen später nicht mehr für Kontrollen verfügbar sind.

Aus einer oft ambitionierten Liste aller möglicher Anforderungen sollten nur die übernommen werden, die für den Anfang unbedingt notwendig  sind. Die anderen Anforderungen sind damit nicht ausgeschlossen, sondern nur auf eine spätere Überarbeitung verschoben.

Definition von Schnittstellen (Abgrenzung im Inneren)

Ein Programm wird grob in verschiedene Teile zerlegt, die einzelne Teilaufgaben übernehmen sollen. Zwischen solchen dieser Teile, welche während des Programmablaufs Informationen miteinander austauschen müssen, werden damit Schnittstellen  nötig.

Programmteile hinter Schnittstellen  (wie Module oder abstrakte Objekte) sollten bei späteren Überarbeitungen isoliert  verändert werden können. Das gesamte Programm sollte nach einer solchen Überarbeitung weiterhin korrekt arbeiten, wenn auch der geänderte Programmteil alle Anforderungen seiner Schnittstellen erfüllt. Daher ist die Änderung solcher Programmteile mit einem relativ geringen Aufwand möglich.

Die folgende Abbildung zeigt eine Situation, in der ein Programm Klient einer Schnittstelle ist. Diese Schnittstelle kann durch eine verkettete Liste oder durch eine Liste auf Basis einer Reihung realisiert werden. Wenn der Klient sich nur an die Schnittstelle bindet, kann die eine Implementation leicht gegen die andere ausgetauscht werden, falls sich ihre Wahl als ungünstig erweisen sollte (oder, um beide Möglichkeiten vergleichen zu können, um alsdann die bessere zu wählen). Andererseits bedeutet die Definition der Schnittstelle und die Anbindung an diese auch mehr Aufwand, so daß ein Programm nur dann durch Schnittstellen zerlegt werden sollte, wenn sich dieser Aufwand voraussichtlich auch lohnen wird.

Eine Liste als Schnittstelle und deren Implementationen (UML)
.-------------------.                   .--------------------------------------. 
| «program» | «uses» | «interface» | 
| client |- - - - - - - - - >| abstract list | 
| | |--------------------------------------| 
'-------------------' | + insertfirst( item ) | 
| + insertlast( item ) | 
| + remove( entry) | 
| + insertafter( entry, item ) | 
| ... | 
'--------------------------------------' 

/_\ 
«realizes» |  
 

- - - - - - - - - - - - - - - - - - - - -  
| | 
.-----------------------. .-----------------------. 
| «implementation» | | «implementation» | 
| linked list | | array list | 
'-----------------------' '-----------------------'

Bei der Änderung einer Schnittstelle  sind hingegen normalerweise gleich mehrere  (normalerweise mindestens zwei) Programmteile betroffen. Daher ist eine spätere Änderung von Schnittstellen oft relativ aufwendig, in manchen Fällen sogar so aufwendig, daß einmal getroffene Festlegungen von Schnittstellen später praktisch gar nicht mehr verändert werden können.

Da Schnittstellen später oft kaum noch geändert werden können, gehören sie zu den folgenschweren Festlegungen bei der Planung eines Programmes. Hier hilft meist eine gute Ausbildung und Erfahrung. Natürlich ist es kaum möglich, bei der Festlegung von Schnittstellen immer das Optimum zu treffen, aber selbst wenn dies deutlich verfehlt wird, ist ein Programm, das durch Schnittstellen untergliedert ist immer noch besser als ein „monolithisches“ Programm ohne Schnittstellen.

Manifestation von Schnittstellen Schnittstellen können einerseits durch bestimmte Aufrufe samt ihrer Dokumentation gegeben sein (Schnittstelle einer Funktion, Methode, Routine, …). Es ist aber auch möglich, daß die Zusammenfassung mehrerer solcher Aufrufe als Schnittstelle angesehen wird (Schnittstelle eines Moduls, abstrakten Objekts, Exemplars einer Klasse, …).

Anregungen zur Festlegung von Schnittstellen

Anzahl von Schnittstellen Jede Schnittstelle hat jedoch nicht nur einen Nutzen, sondern auch einen Preis, da Programmteile Aufwand treiben müssen, um sich an Schnittstellen anzupassen und die Schnittstellen gefunden, dokumentiert und erlernt werden müssen. Dieser Aufwand lohnt sich erst bei Programmen ab einer gewissen Größe. Schnittstellen werden also verwendet, um Programm in Einheiten handhabbarer Größe zu zerlegen. Eine noch feinere Zerlegung dieser Einheiten hätte aber keinen Vorteil.

Vorhersehbare Änderungen Es empfiehlt sich all das hinter einer Schnittstelle zu verstecken, von dem man schon absehen kann, daß es sich möglicherweise später ändern  soll. Beispielsweise sind Bildschirme und Tastaturen selten direkt mit der Hauptplatine eines Rechners verlötet, sondern über einen Steckkontakt angeschlossen, weil es vorhersehbar ist, daß eines dieser Teile einmal ausgetauscht werden können soll, ohne daß deswegen die anderen Teile auch ausgetauscht werden müssen sollen. Entsprechend faßt man alle Dinge zu einem Programmteil zusammen, die sich voraussichtlich gemeinsam miteinander ändern (so daß eine Änderung an dem einen auch eine Änderung an dem anderen nötig macht).

Literatur zur Architektur und Wartung von Software

Die folgenden Bücher werden in verschiedenen Quellen immer wieder als Empfehlung genannt.

[MCCONNELL 2004]
Steve McConnell : Code Complete. Second Edition, Microsoft Press, 2004-06.
[HUNT]
Andrew Hunt : The Pragmatic Programmer.
[Brooks]
Frederick Brooks : The Mythical Man-Month.
[Feathers]
Michael Feathers : Working Effectively with Legacy Code.
[Liskov 1974] (Schon zuvor genannt)
Barbara Liskov, Stephen Zilles : Programming with abstract data types. In: ACM SIGPLAN Notices. (1974), Volume 9, Issue 4:50-59.
http://www.cs.iastate.edu/courses/archive/f06/cs362/papers/p50-liskov.pdf
[Meyer 1974] (Schon zuvor genannt)
Bertrand Meyer : Applying "Design by Contract". In: Computer (IEEE). (1992), Volume 25, Issue 10:50-51.
http://www.cs.iastate.edu/courses/archive/f06/cs362/papers/meyer92.pdf
Einige Web-Quellen zur Architektur von Software:
http://www.cs.cmu.edu/afs/cs/project/vit/ftp/pdf/intro_softarch.pdf
http://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf
http://www.laputan.org/mud/

Jack W. Reeves: Code as Design

Die folgende Empfehlung beziehen sich zwar teilweise auf „Objektorientierte Programmierung“ (OOP), können aber sinngemäß oft auch auf die C -Programmierung angewendet werden, wobei OOP-Objekte in C  teilweise durch abstrakte Objekte oder Module realisiert werden können.

[Gamma 1994]
Gamma, Helm, Johnson & Vlissides : Design Patterns. Addison-Wesley, 1994.
[Fowler 1999]
Fowler, Martin : Refactoring. Addison-Wesley, 1999.
[Larman 2005]
Craig Larman : Applying UML and Patterns. Prentice Hall PTR, 2005.
Einige Web-Quellen zur Architektur objektorientierter Software:
http://butunclebob.com/ArticleS
http://www.objectmentor.com/resources/articles/ocp.pdf

Einige Empfehlungen und Vorgehensweisen

Einige Web-Quellen dazu:

An Object-Oriented Design Taxonomy, http://www.jonathanholloway.co.uk/thesis/MPhilThesis.pdf

http://en.wikipedia.org/wiki/List_of_software_development_philosophies

http://foundationsof.com/FoundationsOfProgramming.pdf

Techniken des Autors

Für die folgenden Techniken/Empfehlungen ist dem Autor dieses Textes kein allgemeiner Namen bekannt, sie erscheinen ihm allerdings als nützlich.

void * mymalloc( size_t const size  ){ return malloc( size  ); }
void myfree( void * const block ){ free( block ); }
int warning( char const * const text ){ fprintf( stderr, "%s\n", text ); }
int error( char const * const text ){ fprintf( stderr, "%s\n", text ); }

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722307 stefan_ram:722307 Aufbau großer Programme Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722307, slrprddef722307, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten.
https://www.purl.org/stefan_ram/pub/aufbau_grosser_programme