\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 auch f\"ur den Sch\"opfer 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{Struktur von Programmen, Organisation von m-Files im Dateisystem} In der Einf\"uhrung zu Funktionen und Skripten wurde schon einmal ein typisches Programmlayout vorgestellt (Abbildung \ref{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: 1. Wie werden Programme im Dateisystem organisiert? 2. 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 eingenen ``Documents'' (Linux) oder ``Eigene Dokumente'' (Windows) Ordner. Es bietet sich an diesen als Wurzelverzeichnis f\"ur eigene Arbeiten zu verwenden. Nat\"urlich kann auch jeder andere Ort gew\"ahlen werden. In dem Beispiel in Abbildung \ref{fileorganizationfig} wird innerhalb dieses Ordners f\"ur jedes Projekt ein eigener Unterordner erstellt in welchem widerum f\"ur jedes Problem, jede Analyse ein weitere Unterodner erstellt wird. In diesen liegen sowohl die ben\"otigten m-files also auch die Resultate der Analyse (Abbildungen, Dateien). Zu bemerken sind noch zwei weitere Dinge. Im Projektordner existiert ein Skript (analysis.m), das dazu gedacht ist, alle Analysen aufzurufen. Des Weiteren gitb es parallel zu den Projektordnern einen ``functions'' Ordner in dem Funktionen liegen, die in mehr als einem Projekt oder einer Analyse gebraucht werden. Wenn man sich dieses Layout anschaut 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 ``load\_data.m'' Funktion in jeder Analyse vorkommt. In der Regel wird dies nicht zu Konflikten f\"uhren, da \matlab{} zuforderst im aktuellen Ordner nach passenden Dateien sucht (mehr Information in Box \ref{matlabpathbox}). \begin{figure} \includegraphics[width=0.75\textwidth]{program_organization} \titlecaption{\label{fileorganizationfig} M\"ogliche Oganisation 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}[t]{\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. \includegraphics[width=0.75\textwidth]{search_path} Man kann den Suchpfad sowohl \"uber die in der Abbildung gezeigte GUI oder auch \"uber die Kommandozeile editieren. In der GUI hat man die M\"oglichkeit Ordner aus dem Suchpfad zu entfernen, neue Ordner (optional inklusive aller Unterordner) hinzuzuf\"ugen oder die Reihenfolge zu ver\"andern. Will man das aktuelle Arbeitsverzeichis wechseln benutzt man das Kommando \code{cd}, um herauszufinden, in welchem Pfad eine bestimmte Funktion gefunden wurde, benutzt man das Kommando \code{which}. Der 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 der Namen. Dabei spielt die Gro{\ss}- und Kleinschreibung eine Rolle. Das hei{\ss}t, dass die Namen ``test\_funktion.m'' und ``Test\_funktion.m'' zwei unterschiedliche Funktionen benennen k\"onnen. Diese Art 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, es lohnt sich aber ausdruckstarke Namen zu finden. Ausdrucksstark bedeutet, dass sich aus dem Namen ein R\"uckschluss auf den Zweck ziehen lassen sollte. \matlab{} macht keine weiteren Vorgaben, was die Namen angeht. Allerdings folgt die Benennung der 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 Aktionspotentiale berechnet k\"onnte etwa \codeterm{spikeCount.m} oder auch \codeterm{spike\_count.m} benannt werden. Leerzeichen, Sonderzeichen oder Anf\"ange mit Zahlen sind in Namen nicht erlaubt. \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 Namen zu finden, die nicht zu lang werden sollte man sich auch da M\"uhe geben. Bei den Funktionen und Skripten fragt man danach, welchen Zweck sie erf\"ullen, bei Variablen fragt man nach dem Inhalt. Eine Varaible die die mittlere Anzahl Aktionspotentiale 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}). \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. Gerne werden Leerzeilen eingef\"ugt um Abschnitte im Programm zu trennen. Das ist v\"ollig ok, wenn es konsistent und sparsam benutzt wird. Hier sollte eine Leerzeile ausreichen. Zu gro{\ss}e Abst\"ande f\"uhren dazu, dass das Programm nicht mehr auf eine Seite passt und man leicht den \"Uberblick verliert. Die beiden folgenden Listings \ref{chaoticcode} und \ref{cleancode} zeigen die Implementation des random-walk einmal eher chaotisch und einmal aufger\"aumt. \begin{lstlisting}[label=chaoticcode, caption={Random-walk Implementation unaufgr\"aumt.}] 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<0 positions(step, run)= positions(step-1, run)+1; elseif x>0 positions(step,run)=positions(step-1,run)-1; end end end \end{lstlisting} \begin{lstlisting}[label=cleancode, caption={Random-walk Implementation etwas ordentlicher.}] 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 < 0 positions(step, run) = positions(step-1, run) + 1; elseif x > 0 positions(step, run) = positions(step-1, run) - 1; end end end \end{lstlisting} \section{Verwendung von Kommentaren} Kommentare k\"onnen ebenfalls sehr zum Verst\"andnis beitragen. 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, vor allem wenn auch andere Personen sie benutzen sollen, sind diese Kommentare hilfreich. H\"aufig werden kurze Kommentare eingesetzt um Abschnitte im Programm zu trennen. Hierbei sollte man auch sparsam sein. Jede Zeile zu erkl\"aren kann in der Entwicklungsphase eines Programms sehr hilfreich sein, bl\"aht aber den Code auf und bei der Verwendung guter Variablennamen sind viel Zeilen weitestgehend selbsterkl\"arend. \begin{important} \begin{itemize} \item Kommentare sind gut und wichtig aber: Sie m\"ussen richtig sein! \item Ein Kommentar, der l\"ugt, ist schlimmer als gar kein Kommentar! \item Kommentare m\"ussen gepflegt werden, sonst sind sie mehr als wertlos! \end{itemize} \end{important} \section{Auslagerung von Aufgaben in Funktionen} Kommentare oder Leerzeilen werden benutzt um Abschnitte des Codes abzutrennen und nazudeuten, dass ab da etwas inhaltlich anderes gemacht wird. Wenn man im Zuge ist, eine solche inhaltliche Trennung einzuf\"ugen muss man sich immer fragen, ob dieser Teil des Programms nicht in eine eigene Funktion ausgelagert werden sollte. Fast immer kann man das bejahen. Abschnitte nicht auszulagern f\"uhrt zu sehr langen m-Files, die leicht un\"ubersichtlich sind. Man nennt sie \codeterm{Spaghetticode}. Es ist h\"ochste Zeit \"uber Auslagerung in Funktionen nachzudenken. \begin{important} Wann sollte man Programmteile in eigene Funktionen auslagern? \begin{itemize} \item Wenn man innerhalb einer Funktion, eines Skripts mehr als zwei Einr\"uckungsebenen hat. \item Wenn man wiederholte Strukturen im Code hat. \item Wenn man versucht ist, diese mit Copy and Paste zu erzeugen. \end{itemize} \end{important} \subsection{Lokale Funktionen und geschachtelte Funktionen} Eine M\"oglichkeit Spaghetticode zu vermeiden ist das Auslagern von Funktionalit\"at in eigene Funktionen. Dies f\"uhrt dazu, dass man eine F\"ulle von Dateien erzeugt, die die \"Ubersichtlichkeit nicht unbedingt erh\"ohen. Wenn die auszulagernde Funktionalit\"at an vielen Stellen ben\"otigt werden k\"onnte ist es dennoch sinnvol 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. \begin{important} Es empfiehlt sich zu Beginn eines Skriptes alle Variablen im \codeterm{Workspace} zu l\"oschen (\code{clear}). Meist ist auch ein \code{close all} angebracht. 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{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 nich von globalem Interesse sind, kann man auch mit \codeterm{lokalen} oder \codeterm{geschachtelten Funktionen} die Lesbarkeit erh\"ohen. \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}