Programmierpraktikum NPDGL I

Tipps und Vorschläge zum Software entwickeln

Referenz zum Nachschlagen
Zusammengeh�rigkeiten von Tipps und Vorschläge zum Software entwickeln:

Dieser Abschnitt beschreibt Konzepte zum Entwickeln von C++-Programmen, sowie Tipps zum Code-Design, die das Entwickeln und vor allem das Finden von Fehlern vereinfachen.

Modularisieren und Schreiben von Tests

Es ist ein guter Programmierstil, sein Programm in möglichst kleine Module mit klar definierten Aufgaben zu zerlegen. Dies ermöglicht

Das Testen auf Korrektheit der Module ist besonders empfohlen für Programmteile mit hoher "logischer" Komplexität, d.h. z.B. vielen Vorzeichen oder komplexen If-Else-Abzweigungen.

Die Aufteilung in Module sollte auch in der Code-Strutktur abgebildet werden, weshalb ich euch den extensiven Gebrauch von Header Dateien nahelegen möchte.


Interfaces programmieren

Interfaces beschreiben die Funktionalität und die Datenstrukturen von Objekten, ohne diese selbst zu implementieren.

Um gute objekt-orientierte Software zu schreiben, ist es wichtig, die wichtigsten Interfaces in einem Projekt zu erkennen und zu definieren. Dies ermöglicht nämlich die Definition der Funktionalität der Software bzw. der Module einfach zu halten. (Beispiel: "Das erste Argument muss das Interface NumericalFluxIf erfüllen" ist einfacher als: "Das erste Argument muss ein Objekt sein, das eine apply-Methode hat, welche drei skalare Argumente hat, von denen das dritte das Resultat eines numerischen Flusses ist."

Ein weiterer Vorteil von Interfaces ist, dass der Compiler diese versteht und deswegen bei der Einhaltung der Definition helfen kann: Wenn ich ein Objekt von einem Interface ableite, und dieses Objekt nicht alle Funktionen oder Objekte des Interfaces erfüllt, so kann der Compiler den Programmierer darauf hinweisen.

Auf der C++-Seite finden sich noch weitere Details zur Implementierung von Interfaces in C++.

Siehe auch:
Modularisieren und Schreiben von Tests

Dokumentieren und Kommentieren von Code

Zur Definition von Interfaces und Modulen gehört nicht nur deren Syntax, also die Deklaration von Methoden, Methodenargumenten und Member-Variablen einer Klasse, sondern auch - und vor allem - die Semantik. Dazu ist es nötig seinen Code zu dokumentieren.

Das gängigste Tool zur Dokumentation von C++ Code ist doxygen, welches aus Kommentaren, die in den Code eingebaut werden können, Dokumentation erstellt, wie z.B. für die Klasse Grid. Mit diesem Tool wurden auch diese Seiten erstellt.

Eine gute Dokumentation sollte mindestens

Zudem ist es sehr sinnvoll, komplizierte Code-Stellen mit Kommentaren zu versehen, die zwar nicht in der Dokumentation auftauchen, aber dafür von Vorteil sind, wenn man erneut in den Quellcode schaut. Programmierern wird sehr schnell bewusst, wie viel Information das Kurzzeitgedächtnis bereits nach wenigen Stunden wieder verlässt.


Verifizierung von Implementierung numerischer Verfahren mittels EOC

Numerische Verfahren können sehr komplex werden, und es schwierig zu entscheiden, ob das Verfahren das Richtige tut. Ist für einen Spezialfall des Problems, das durch das numerische Verfahren gelöst weden soll, eine analytische Lösung bekannt, so kann das Verfahren mittels einer EOC Berechnung verifiziert werden.

Dazu geht man folgendermaßen vor:

  1. Diskretisierung auf einem Gitter mit einer sehr groben Gitterweite \( h_0 \).
  2. Berechne den Fehler zwischen der numerischen Lösung \( u_{h_0} \) und der Projektion der exakten Lösung \( u_{\text{exact}} \) in einer geeigneten Norm \( \| \cdot \| \):

    \[ e_0 := \left\| u_{h_0} - { \cal P }_h \left[ u_{\text{exact}} \right] \right\| \]

  3. Füre die EOC Schritte \(i = 1, \ldots, E \) aus:
    1. Diskretisierung auf einem verfeinerten Gitter mit Gitterweite \( h_i = \frac{h_{i-1}}{2} \).
    2. Berechne den Fehler zwischen der numerischen Lösung \( u_{h_i} \) und der exakten Lösung \( u_{exact} \):

      \[ e_i := \left\| u_{h_i} - { \cal P }_h \left[ u_{\text{exact}} \right] \right\| \]

    3. Berechne die experimentelle Konvergenzordnung (EOC = experimental order of convergence)

      \[ \mbox{eoc}_i := \log\left(\frac{e_{i-1}}{e_i}\right)/\log(2) \]

Wenn aus der Theorie eine Konvergenzordnung abgeleitet werden kann, dann sollte diese ungefährt mit der experimentellen \(\mbox{eoc}_E\) die heuristisch misst, wie schnell die diskrete Lösung gegen eine kontinuierliche Lösung konvergiert.

Globale Variablen vermeiden oder kapseln (Beispiel: TimeProvider)

Noch zu erledigen:
zu schreiben

�berpr�fen von Argumenttypen in Methoden und Funktionsaufrufen

Noch zu erledigen:
zu schreiben

Methoden und Variablen mit const - Qualifizierer versehen

Noch zu erledigen:
zu schreiben

Einr�cken von Code

Noch zu erledigen:
Schreibe wie automatisches Einrücken in Emacs konfiguriert werde kann.