<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">\chapter{\tr{Programming style}{Programmierstil}}

Guter Programmierstil ist keine Frage des guten Geschmacks sondern des
Verst\"andnisses von Programmcode und ein Baustein in dem Bestreben
wissenschaftlichen Erkenntnisgewinn reproduzierbar zu
machen. 

Programme sollten so geschrieben und strukturiert sein, dass es sowohl
einem Au{\ss}enstehenden als auch einem selbst, nach ein paar Monaten,
leicht f\"allt den Programmablauf nachzuvollziehen und zu
verstehen. Saubere Programmierung zahlt sich aber in erster Linie
f\"ur den Verfasser eines Programmes aus.

Guter Programmierstil greift auf unterschiedlichen Ebenen an:
\begin{enumerate}
\item Die Struktur von Programmen.
\item Die Namensgebung von Skripten und Funktionen.  
\item Die Namensgebung f\"ur Variablen und Konstanten.
\item Die Verwendung von Einr\"uckungen und Leerzeilen um Bl\"ocke im
  Code hervorzuheben.
\item Verwendung von Kommentaren und Hilfetexten.
\item Auslagerung von Funktionalit\"at in eigene Funktionen.
\end{enumerate}

\section{Organisation von Programmdateien im Dateisystem}

In der Einf\"uhrung zu Funktionen und Skripten wurde schon einmal ein
typisches Programmlayout vorgestellt (\figref{programlayoutfig}). Hier
wurde vorgeschlagen ein Skript als Kontrollskript zu verwenden. Dieses
kontrolliert den weiteren Programmablauf, ruft Funktionen auf,
\"ubergibt Argumente und nimmt R\"uckgabewerte entgegen. Eine solche
Struktur macht es einfach den Ablauf zu verstehen. Es bleibt aber die
Frage, wie man das Kontrollskript unter den anderen \codeterm{m-files}
als solches erkennt. Um dieses zu erleichtern gilt es zwei Dinge zu
beachten: (i) Wie werden Programme im Dateisystem organisiert? (ii) Wie
werden Programme benannt?

Es hilft ungemein, wenn zusammengeh\"orige Skripte und Funktionen im
gleichen Ordner auf der Festplatte zu finden sind. Es bietet sich also
an, f\"ur jede Analyse einen eigenen Ordner anzulegen und in diesem
die zugeh\"origen \codeterm{m-files} abzulegen. Auf eine tiefere
Schachtelung in weitere Unterordner kann in der Regel verzichtet
werden. \matlab{} erzeugt einen ``MATLAB'' Ordner im eigenen
\file{Documents} (Linux) oder \file{Eigene Dokumente} (Windows)
Ordner. Es bietet sich an, diesen Ordner als Wurzelverzeichnis f\"ur
eigene Arbeiten zu verwenden. Nat\"urlich kann auch jeder andere Ort
gew\"ahlt werden. In dem Beispiel in \figref{fileorganizationfig} wird
innerhalb dieses Ordners f\"ur jedes Projekt ein eigener Unterordner
erstellt, in welchem wiederum f\"ur jedes Problem, jede Analyse ein
weiterer Unterodner erstellt wird. In diesen liegen sowohl die
ben\"otigten \codeterm{m-files} also auch die Resultate der Analyse
(Abbildungen, Daten-Dateien). Zu bemerken sind noch zwei weitere
Dinge. Im Projektordner existiert ein Skript (analysis.m), das dazu
gedacht ist, alle Analysen aufzurufen. Des Weiteren gibt es parallel
zu den Projektordnern einen \file{functions}-Ordner in dem Funktionen
liegen, die in mehr als einem Projekt oder einer Analyse gebraucht
werden.

Beim Betrachten dieses Layouts f\"allt auf, dass es sehr
wahrscheinlich ist, dass bestimmte Namen f\"ur Funktionen und Skripte
mehrfach verwendet werden. Es ist nicht verwunderlich, wenn eine
\file{load\_data.m} Funktion in jeder Analyse vorkommt. In der Regel
wird dies nicht zu Konflikten f\"uhren, da \matlab{} zuerst im
aktuellen Ordner nach passenden Dateien sucht (mehr Information zum
\matlab-Suchpfad in Box~\ref{matlabpathbox}).

\begin{figure}[tp]
  \includegraphics[width=0.75\textwidth]{program_organization}
  \titlecaption{\label{fileorganizationfig} M\"ogliche Organisation von
    Programmcode im Dateisystem.}{ F\"ur jedes Projekt werden
    Unterordner f\"ur die einzelnen Analysen angelegt. Auf Ebene des
    Projektes k\"onnte es ein Skript (hier ``analysis.m'') geben,
    welches alle Analysen in den Unterordnern anst\"o{\ss}t.}
\end{figure}


\begin{ibox}[tp]{\label{matlabpathbox}Der \matlab{} Suchpfad}
  Der Suchpfad definiert, wo \matlab{} nach Skripten und Funktionen
  sucht. Wird eine Funktion aufgerufen wird zun\"achst im aktuellen
  Arbeitsverzeichnis einem Treffer gesucht. Schl\"agt diese Suche
  fehl, so arbeitet sich \matlab{} durch den \codeterm{Suchpfad}
  (siehe Abbildung). Der \codeterm{Suchpfad} ist eine Liste von
  Ordnern in denen \matlab{} nach Funktionen und Skripten suchen
  soll. Die Suche nach der aufgerufenen Funktion wird dabei von oben
  nach unten durchgef\"uhrt. Das heisst, dass es, bei
  Namensgleichheit, eine Rolle spielen kann an welcher Stelle im
  Suchpfad der erste Treffer gefunden wird. Wichtig: \matlab{} sucht
  nicht rekursiv! Wenn die gew\"unschte Funktion in einem Unterordner
  des aktuellen Arbeitsverzeichnisses liegt, dieses aber nicht
  explizit im Suchpfad enthalten ist, so wird die Funktion nicht
  gefunden werden.

  \vspace{2ex}
  \includegraphics[width=0.75\textwidth]{search_path}
  \vspace{1.5ex}

  Der Suchpfad kann sowohl \"uber die in der Abbildung gezeigte GUI
  oder auch \"uber die Kommandozeile eingestellt werden. Die GUI
  erlaubt Ordner aus dem Suchpfad zu entfernen, neue
  Ordner (optional inklusive aller Unterordner) hinzuzuf\"ugen oder
  die Reihenfolge der Pfade zu ver\"andern.

  Zum Wechseln des aktuelle Arbeitsverzeichnis wechseln wird das
  Kommando \code{cd} verwendet. \code{which} zeigt an, in welchem Pfad
  eine bestimmte Funktion gefunden wurde. Das aktuelle
  Areitsverzeichnis wird durch den Aufruf \code{pwd} auf der
  Kommandozeile ausgegeben.
\end{ibox}

\section{Namensgebung von Funktionen und Skripten}

\matlab{} sucht Funktionen und Skripte ausschlie{\ss}lich anhand des
Namens. Dabei spielt die Gro{\ss}- und Kleinschreibung eine Rolle. Das
hei{\ss}t, dass die beiden Dateien \file{test\_funktion.m} und
\file{Test\_funktion.m} zwei unterschiedliche Funktionen benennen
k\"onnen. Diese Art der Variation des Namens ist nat\"urlich nicht
sinnvoll. Sie tr\"agt keine Information \"uber den Unterschied der
beiden Funktionen. Auch sagt der Name nahezu nichts \"uber den Zweck
der Funktion aus. 

Die Namensgebung f\"allt mitunter nicht leicht --- manchmal ist es
sogar der schwierigste Aspekt des Programmierens!  Ausdrucksstarke
Namen zu finden lohnt sich aber. Ausdrucksstark bedeutet, dass sich
aus dem Namen ein R\"uckschluss auf den Zweck ziehen lassen sollte.

\begin{important}[Benennung von Funktionen und Skripten]
  Die Namen von Funktionen und Skripten sollten m\"oglichst viel \"uber
  die Funktionsweise oder den Zweck aussagen (\file{firingrates.m}
  statt \file{uebung.m}). Gute Namen f\"ur Funktionen und Skripte sind
  die beste Dokumentation.
\end{important}

In Namen verbietet \matlab{} verbietet Leerzeichen, Sonderzeichen und
Umlaute. Namen d\"urfen auch nicht mit Zahlen anfangen. Es mach f\"ur
die Namensgebung selbst keine weiteren Vorgaben. Allerdings folgt die
Benennung der in \matlab{} vordefinierten Funktionen gewissen Mustern:
\begin{itemize}
\item Namen werden immer klein geschrieben.
\item Es werden gerne Abk\"urzungen eingesetzt (z.B. \code{xcorr}
  f\"ur die Kreuzkorrelation oder \code{repmat} f\"ur ``repeat matrix'')
\item Funktionen, die zwischen Formaten konvertieren sind immer nach
  dem Muster ``format2format'' (z.B. \code{num2str} f\"ur die
  Konvertierung ``number to string'', Umwandlung eines numerischen
  Wertes in einen Text) benannt.
\end{itemize}

Andere \"ubliche Muster sind der \emph{camelCase}, bei dem die
Anf\"ange zusammengesetzter Worte jeweils gro{\ss} geschrieben werden
oder auch die Verwendung von Unterstrichen zur Trennung von
Namenskomponenten. Eine Funktion, die die Anzahl von
Aktionspotentialen bestimmt k\"onnte etwa \file{spikeCount.m} oder
\file{spike\_count.m} benannt werden.


\section{Namensgebung von Variablen und Konstanten}

F\"ur die Bennennung von Variablen und Konstanten gelten die gleichen
Regeln wie f\"ur die Namen von Funktionen und Skripten. Die Maxime von
gutem Programmierstil ist: \emph{``Programmcode muss lesbar
  sein.''}. Dabei helfen gute Namen ungemein. Auch wenn es schwer
f\"allt passende und nicht zu lange Namen zu finden, sollte einer gute
Namensgebung ernst genommen werden.

W\"ahrend die Namen von Funktionen und Skripten ihren Zweck
beschreiben, sollten die Namen von Variablen ihren Inhalt
beschreiben. Eine Variable, die die mittlere Anzahl von
Aktionspotentialen speichert, k\"onnte also
\codeterm{average\_spike\_count} hei{\ss}en. Wenn die Variable nicht
nur einen sondern mehrere Werte aufnimmt, dann ist der Plural
angebracht (\codeterm{average\_spike\_counts}).

Die Laufvariablen von \code{for}-Schleifen werden oft nur \code{i},
\code{j} oder \code{k} benannt und sollten aber die einzige Ausnahme
bzgl. ausdrucksstarker Namensgebung bleiben.

\begin{important}[Benennung von Variablen]
  Die Namen von Variablen sollten m\"oglichst viel \"uber ihren Inhalt
  aussagen (\code{spike\_count} statt \code{x}). Gute Namen
  f\"ur Variablen sind die beste Dokumentation.
\end{important}


\section{Codestil}

Die Lesbarkeit von Programmen wird sehr durch den Codestil
beeinflusst. Ein Programm, in dem z.B. Schleifenk\"orper nicht (oder
zuf\"allig) einger\"uckt sind ist deutlich schwerer zu lesen und zu
verstehen, als eines, in dem eine konsistente Einr\"uckung vorgenommen
wurde. Mit der Tastenkombination \keycode{Ctrl-I} (\keycode{Strg-I}
auf der deutschen Tastatur) kann ein markierter Bereich im \matlab{}
Editor automatisch richtig einger\"uckt werden.

Sparsam und konsistent eingef\"ugte einzelne Leerzeilen sind
hervorragend geeignet, um logische Abschnitte eines Programm zu
trennen. Zu viele Leerzeilen haben den Nachteil, dass das Programm
nicht mehr auf eine Seite passt und dadurch leichter der \"Uberblick
verlorgen geht.

Die beiden folgenden Listings \ref{chaoticcode} und \ref{cleancode}
zeigen die Implementation des random-walk einmal eher chaotisch und
einmal aufger\"aumt und \"ubersichtlich.
 
\begin{lstlisting}[label=chaoticcode, caption={Un\"ubersichtliche Implementation des Random-walk.}]
num_runs = 10;
max_steps = 1000;

positions = zeros(max_steps, num_runs);

for run = 1:num_runs

    
for step = 2:max_steps

x = randn(1);
if x&lt;0
positions(step, run)= positions(step-1, run)+1;
    
       
elseif x&gt;0
 positions(step,run)=positions(step-1,run)-1;
 end
end
end
\end{lstlisting}

\clearpage

\begin{lstlisting}[label=cleancode, caption={\"Ubersichtliche Implementation des Random-walk.}]
num_runs = 10;
max_steps = 1000;
positions = zeros(max_steps, num_runs);

for run = 1:num_runs
    for step = 2:max_steps
        x = randn(1);
        if x &lt; 0
            positions(step, run) = positions(step-1, run) + 1;
        elseif x &gt; 0
            positions(step, run) = positions(step-1, run) - 1;
        end
    end
end
\end{lstlisting}

\section{Verwendung von Kommentaren}

Kommentarzeilen werden in \matlab{} mit dem Prozentzeichen \code{\%}
gekennzeichnet.  Gezielt und sparsam eingesetzte Kommentare sind f\"ur
das Verst\"andnis eines Programms sehr n\"utzlich.  Am wichtigsten
sind kurze Kommentare, die den Zweck und das Ziel eines Abschnitts im
Programm erl\"autern (z.B. \code{\% compute mean firing rate over all
  trials}).

Viele und h\"aufige Kommentare k\"onnen in der Entwicklungsphase eines
Programms sehr hilfreich sein, bl\"ahen aber den Code auf. Durch die
Verwendung guter Variablen- und Funktionsnamen sollten die meisten
Zeilen sowieso weitestgehend selbsterkl\"arend sein.

Die beste Dokumentation ist der Code selbst. Gut geschriebener Code
mit ausdrucksstarken Variablen- und Funktionsnamen ben\"otigt keine
Kommentare, um den Zweck einzelner Zeilen zu erkl\"aren. z.B. ist\\
\code{ x = x + 2;   \% add two to x}\\
ein v\"ollig unn\"otiger Kommentar.

\begin{important}[Verwendung von Kommentaren]
  \begin{itemize}
  \item Kommentare sollen die Absicht eines Programmabschnitts beschreiben.
  \item Kommentare sind gut und wichtig --- sie m\"ussen aber richtig
    sein!
  \item Ein falscher Kommentar ist schlimmer als gar kein Kommentar!
  \item Kommentare m\"ussen gepflegt werden, sonst sind sie wertlos!
  \end{itemize}
\end{important}

\section{Dokumentation von Funktionen}

Bei allen vordefinierten \matlab{} Funktionen findet sich am Anfang
eine Kommentarblock, der den Zweck der Funktion, die verschiedenen
M\"oglichkeiten des Funktionsaufrufs und die Argumente und
R\"uckgabewerte beschreibt. Auch in eingenen Funktionen sind diese
Kommentare sehr hilfreich. Siehe Listing~\ref{localfunctions} f\"ur
ein Beispiel einer gut Dokumentierten Funktion.

\begin{important}[Dokumentation von Funktionen]
  Funktionen m\"ussen unbedingt kommentiert werde!
  \begin{itemize}
  \item In wenigen Zeilen kurz den Zweck der Funktion beschreiben.
  \item F\"ur jedes Funktionsargument die Bedeutung, der erwartete
    Datentyp (Zahl, Vektor, Matrix, etc.), und eventuell die Einheit,
    in der die Zahlen erwartet werden (z.B. Sekunden).
  \item Ebenso m\"ussen die R\"uckgabewerte beschrieben werden.
  \end{itemize}
\end{important}


\section{Auslagerung von Aufgaben in Funktionen}

Kommentare oder Leerzeilen werden benutzt, um logische Abschnitte des
Codes abzutrennen und kurz zu erkl\"aren. Wenn eine
solche inhaltliche Trennung einzuf\"ugt wird, sollte man sich immer fragen,
ob dieser Teil des Programms nicht in eine eigene Funktion ausgelagert
werden sollte. Fast immer kann dies bejaht werden.

Abschnitte nicht auszulagern f\"uhrt zu sehr langen
\codeterm{m-Files}, die leicht un\"ubersichtlich werden. Diese Art von
Code wird \codeterm{Spaghetticode} genannt. Es ist h\"ochste Zeit
\"uber Auslagerung in Funktionen nachzudenken.

\begin{important}[Gliederung in Funktionen]
  Wann sollten Programmteile in eigene Funktionen ausgelagert werden?
  \begin{itemize}
  \item Wenn innerhalb einer Funktion oder eines Skripts mehr als zwei
    Einr\"uckungsebenen gebraucht werden.
  \item Wenn sich Strukturen im Code mehr als einmal wiederholten.
  \item Wenn man versucht ist, wiederholte Strukturen  mit Copy and Paste zu erzeugen.
  \end{itemize}
\end{important}

\subsection{Lokale Funktionen und geschachtelte Funktionen}

Das Auslagern von Funktionalit\"at in eigene Funktionen f\"uhrt
dazu, dass eine F\"ulle von Dateien erzeugt wird, die die
\"Ubersichtlichkeit nicht unbedingt erh\"oht. Wenn die auszulagernde
Funktionalit\"at an vielen Stellen ben\"otigt wird ist es
dennoch sinnvoll dies zu tun. Wenn nicht, dann bietet \matlab{} die
M\"oglichkeit sogenannte \codeterm{lokale Funktionen} oder auch
\codeterm{geschachtelte Funktionen} (\enterm{nested functions}) zu
erstellen. Listing \ref{localfunctions} zeigt ein Beispiel f\"ur eine
lokale Funktion.

\lstinputlisting[label=localfunctions, caption={\codeterm{Lokale Funktionen} erh\"ohen die Lesbarkeit sind aber nur innerhalb der definierenden Datei verf\"ugbar.}]{calculate_sines.m}

Lokale Funktionen existieren in der gleichen Datei und sind nur dort
verf\"ugbar. Jede Funktion hat ihren eigenen G\"ultigkeitsbereich, das
hei{\ss}t, dass Variablen aus den aufrufenden Funktionen nicht
sichtbar sind. Bei sogenannten \codeterm{geschachtelten Funktionen}
ist das anders. Diese werden innerhalb eines Funktionsk\"orpers
(zwischen den Schl\"usselworten \codeterm{function} und dem
\codeterm{end} definiert und k\"onnen auf alle Variablen der
``Mutterfunktion'' zugreifen und diese auch ver\"andern. Folglich
sollten sie nur mit Bedacht eingesetzt werden.


\section{Besonderheiten bei Skripten}

Ein \"ahnliches Problem wurde schon bei der Einf\"uhrung der Skripte
erw\"ahnt. Variablen, die in Skripten definiert werden sind global im
\codeterm{Workspace} verf\"ugbar. Es besteht die Gefahr von
Namenskollisionen. Problem dabei ist, dass der Nutzer gar nicht
mitbekommt, wenn eine Variable redefiniert oder neuen Inhalt
zugewiesen bekommt. Fehler, die auf derartigen Kollisionen beruhen
sind h\"aufig nur schwer zu finden, da das Programm f\"ur sich korrekt
aussieht.

Um dieses Problem zu vermeiden sollten Skripte genauso wie Funktionen
eine spezifische Aufgabe unabh\"angig vom Kontext erf\"ullen. Diese
Aufgabe ist dann nat\"urlich komplexer als die einer
Funktion. z.B. k\"onnte die Aufgabe eines Skriptes sein, die
Spiketrains aller aufgenommenen Zellen zu analysieren. Gute Skripte
sind trotzdem nicht \"uberm\"a{\ss}ig lang und deshalb leicht zu
verstehen.

Ein weiterer, sehr wichtiger Vorteil von zweckbestimmten Skripten ist,
dass sie immer als ganzes ausf\"uhrbar sind --- am einfachsten mit
\keycode{F5} aus dem \matlab-Editor heraus. Wenn ein Fehler auftritt
ist in der Fehlermeldung die Zeilennummer des fehlerhaften Codes
angegeben. Das ist eine sehr wichtige Information, um den Fehler
beheben zu k\"onnen.

\"Ubergeordnete Skripte k\"onnen dann einfach nacheinander
spezifischere Skripte aufrufen. Durch die Namen der aufgerufenen
Skripte ist dann klar, was passieren wird, und durch die
Unabh\"angigkeit der Skripte kommt es nicht zu Kollisionen.

\begin{important}[Struktur von Skripten]
  \begin{itemize}
  \item Skripte sollten genauso wie Funktionen spezifische Aufgaben
    l\"osen und nicht zu lang sein.

  \item Skripte sollten unabh\"angig von irgendwelchen Variablen im
    \codeterm{Workspace} f\"ur sich alleine geschlossen lauff\"ahig
    sein.
    
  \item Es empfiehlt sich zu Beginn eines Skriptes alle Variablen im
    \codeterm{Workspace} zu l\"oschen (\code{clear}). Meist ist auch
    ein \code{close all}, um alle Figures zu schlie{\ss}en,
    angebracht.

  \item Am Ende eines Skriptes sollte der \codeterm{Workspace}
    mithilfe von \code{clear} wieder von all den Variablen ges\"aubert
    werden, die nicht mehr ben\"otigt werden.
  \end{itemize}
\end{important}

\section{Fazit}

Programmcode soll lesbar sein. Namen von Variablen, Funktionen und
Skripten sollten ausdrucksstark sein und R\"uckschl\"usse auf den
Inhalt oder den Zweck erlauben. Einen pers\"onlichen Programmierstil
zu entwickeln ist v\"ollig in Ordnung solange er konsistent ist. In
machen Programmiersprachen gibt es Traditionen und \"Ubereink\"unfte,
diese sollten dann beachtet werden. 

Wiederholte Programmabschnitte sollten in Funktionen ausgelagert
werden. Wenn diese nicht von globalem Interesse sind, kann mit
\codeterm{lokalen} oder \codeterm{geschachtelten Funktionen} die
\"Ubersichtlichkeit erh\"oht werden. 

\noindent Es lohnt sich auf den eigenen Programmierstil zu achten!\footnote{Literatur zum Programmierstil: z.B. Robert C. Martin: \textit{Clean
  Code: A Handbook of Agile Software Craftmanship}, Prentice Hall}
</pre></body></html>