Michael Schröpl: Modular programmieren

Beitrag lesen

Hi Andreas,

Mir geht es jetzt nicht um spezielle Scripte, sondern nur
um die Technik im allgemeinen - wie macht man sowas am besten?

mein Zauberwort dafür lautet "dünne Kanten" zwischen den Code-Segmenten - also minimale Abhängigkeiten.

  • Überlege Dir, welche Informationen thematisch zusammen gehören.
  • Vermeide, daß ein Code-Abschnitt Wissen aus anderen als den ihm
      "zustehenden" Quellen bezieht.

Ich modelliere immer zuerst die Datentypen und danach erst die Code-Strukturen.
Dabei versuche ich, Wissen so gut wie möglich einer "zuständigen Instanz" zu geben, an welche sich alle "Bezieher" dieses Wissens zu wenden haben - ich entwerfe also im Prinzip APIs, aber auf einer von konkreten Sprachen noch völlig unabhängigen Ebene.
Im Prinzip versuche ich, ungefähr objektorientiert zu denken, ohne mich aber zum Sklaven einer konkreten Implementierung machen zu wollen.

Voraussetzung dafür ist eine hohe Disziplin.
Es ist verlockend, Informationen "durch die Hintertür" weiterzugeben - es spart oftmals Quelltext-Zeilen, wenn man globale Variablen verwendet, auf das Environment zugreift, das Windows-Clipboard oder die Registry oder gemeinsame Dateien nutzt. Alle diese Mechanismen unterlaufen jedoch das Prinzip der Informationstrennung - diese aber ist m. E. Voraussetzung dafür, ein Modul so stabil und zuverlässig schreiben zu können (weil ihm niemand mehr ins Handwerk pfuschen kann), daß es sinnvoll wiederverwertbar ist.
Dazu gehört natürlich auch, daß sich das Modul gegen Eingriffe von außen zur Wehr setzt - also aussschließlich über den "legalen" Zugriffsweg die geleisteten Dienste abzurufen erlaubt und Eingriffe an der "hohlen Gasse" vorbei unterbindet.

Das alles kostet etwas. Einerseits erlauben die mir bekannten Programmiersprachen nicht, Verstöße gegen "sauberen Programmierstil" automatisch zu unterbinden - vor allem C und Perl gehen gnadenlos den Weg "der Programmierer wird schon wissen, was er sich dabei gedacht hat".

Andererseits sind gerade bei kleinen Programmen die quickhacks mit globalen Variablen und ohne Funktionen oftmals wirklich schneller geschrieben als ein beliebig sauberer, strukturierter Entwurf. Ich denke, es gibt da keinen Königsweg. Das einzige, was hilft, ist Erfahrung - und ein Gefühl dafür, ob man eine konkrete Lösung irgendwann später nochmal brauchen wird.

Es ist auch irgendwie eine Frage der kritischen Masse - ich fange oft ein Skript in einer einzigen Datei an und zerlege diese erst dann in Module, wenn ich andernfalls den Überblick verliere.
Das läßt sich aber weder an der Zahl der Funktionen noch an der Zahl der Codezeilen festmachen - es ist eher eine Frage der Zahl der verschiedenen Aspekte der Aufgabenstellung, die das Programm zu erledigen hat, also der "intellektuellen Komplexität" des Programms. Und die kann wiederum sehr stark von der verwendeten Programmiersprache abhängen, weil die verschiedenen Sprachen unterschiedlich mächtige Elementarbefehle besitzen oder gar beliebig mächtige Funktionen in Form externer Bibliotheken zur Verfügung stellen können ... wenn ich dasselbe Problem in Perl und in Assembler zu lösen habe, muß ich bei Assembler viel gründlicher modularisieren.

Was ich selbst also anstrebe, ist
a) ein Bewußtsein dafür, wie es "richtig" geht und
b) ein Gefühl dafür, wo die kritische Masse erreicht ist,
   ab der sich "Pfuschen" nicht mehr lohnt.

Dabei ist die modulare Zerlegung etwas, das ich sehr viel später brauche als beispielsweise eine detaillierte Dokumentation des Qzelltextes - die brauche ich schon bei 20 Zeilen.
Das wiederum liegt an der Vielzahl von Sprachen, die ich verwenden muß. Für jemanden, der ausschließlich in seinern Leib- und Magensprache programmiert, mag ein 1000-Zeilen-Quelltext mit sprechenden Variablennamen noch selbsterklärend sein. Für mich ist er das definitiv nicht - vor allem deshalb nicht, weil er mir nicht erklärt, warum das Programm bestimmte Dinge _nicht_ tut - beispielsweise, weil es eine Entscheidung dagegen gibt, weil es im verlangten Kontext nicht funktioniert, weil Performance-Gründe dagegen sprechen usw.; das alles versuche ich durch Kommentare im Quelltext (oftmals einfach durch Auskommentieren des gesamten Code-Abschnitts mit entsprechender Begründung) zu beschreiben.

Was für modulare Programmierung ebenfalls notwendig ist, das ist Vertrauen in die Qualität der Implementierung. Du mußt wirklich das Selbstbewußtsein haben, ein Problem als "gelöst" zu klassifizieren - es kann sicherlich vorkommen, daß eine Bibliothek bugs hat, aber es sollte eben selten sein.
Also keine Schönwetterprogrammierung, sondern gnadenlos _alles_ abfragen - und auch die "this can't happen: ..."-Meldungen nach dem Abfragen irgendwelcher API-Returncodes, bei denen "eigentlich" nichts schiefgehen kann. Wer immer einen Returncode zurückliefert, hat sich dabei normalerweise etwas gedacht, und es steht einem "seriösen" Modul nicht zu, diese Entscheidung in Frage zu stellen. Den täte es das, wäre seine Qualität schlechter als diejenige der von _ihm_ verwendeten Module ...

Auch DEBUG-Code lasse ich mehr und mehr im Modul drin und mache ihn von Modul-globalen Konstanten abhängig (manchmal sogar von einem CGI-Parameter) - solange ich mir das in Sachen Performance leisten kann.

Das war jetzt alles ein bißchen über Dein Thema hinaus geschossen - aber ich finde es schwierig, die einzelnen Aspekte von "Programmierstil" voneinander zu trennen.
Modulare Programmierung alleine ist halt auch kein Allheilmittel - bloß eine gute Idee. Umsetzen mußt Du sie aber immer wieder auf's Neue.

Viele Grüße
      Michael