From 04f4d952308711b0aaf77ca13b00f7fca469c485 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Tue, 9 Oct 2018 18:02:28 +0200 Subject: [PATCH] [chapter 4] copy of german chapter --- .../lecture/programmingstyle_de.tex | 446 ++++++++++++++++++ 1 file changed, 446 insertions(+) create mode 100644 programmingstyle/lecture/programmingstyle_de.tex diff --git a/programmingstyle/lecture/programmingstyle_de.tex b/programmingstyle/lecture/programmingstyle_de.tex new file mode 100644 index 0000000..f74717b --- /dev/null +++ b/programmingstyle/lecture/programmingstyle_de.tex @@ -0,0 +1,446 @@ +\chapter{\tr{Programming style}{Programmierstil}} + +\shortquote{Any code of your own that you haven't looked at for six or + more months might as well have been written by someone + else.}{Eagleson's law} + +\selectlanguage{ngerman} + +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 +Wochen oder Monaten! --- leicht f\"allt den Programmablauf +nachzuvollziehen und zu verstehen. Saubere Programmierung zahlt sich +in erster Linie f\"ur einen selbst aus und macht es aber gleichzeitig +f\"ur andere Personen leichter, den Code nachzuvollziehen und zu +benutzen. + +Guter Programmierstil greift auf unterschiedlichen Ebenen an: +\begin{enumerate} +\item Die Dateistruktur 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 (box\,\ref{whenscriptsbox}). 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. + + \vspace{2ex} + \includegraphics[width=0.9\textwidth]{search_path} + \vspace{1.5ex} + + Der Suchpfad kann sowohl \"uber die Kommandozeile mit dem Kommandos + \code{addpath()} und \code{userpath()} als auch\"uber die in der + Abbildung gezeigte GUI angezeigt und 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 aktuellen Arbeitsverzeichnisses 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. 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 R\"uckschl\"usse 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 trotzdem nicht zu lange Namen zu finden, sollte +einer gute Namensgebung sehr 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 +\varcode{average\_spike\_count} hei{\ss}en. Wenn die Variable nicht +nur einen sondern mehrere Werte aufnimmt, dann ist der Plural +angebracht (\varcode{average\_spike\_counts}). + +Die Laufvariablen von \code{for}-Schleifen werden oft nur \varcode{i}, +\varcode{j} oder \varcode{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 (\varcode{spike\_count} statt \varcode{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<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} + +\pagebreak[4] + +\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 < 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} + +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. \varcode{\% 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\\ +\varcode{ 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} + \widequote{Good code is its own best documentation. As you're about to add + a comment, ask yourself, ``How can I improve the code so that this + comment isn't needed?'' Improve the code and then document it to + make it even clearer.}{Steve McConnell} +\end{important} + +\pagebreak[4] +\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. Mit dem \code{help}- Befehl wird dieser +Kommentarblock angezeigt. Auch in eigenen Funktionen sind +diese Kommentare sehr wichtig. 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 Den Funktionskopf nocheinmal hinschreiben, damit + klar ist, in welcher Reihenfolge Argumente \"ubergeben werden. + \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 sehr +sinnvoll dies zu tun. Wenn Funktionen nur von einzelnen anderen +Funktionen verwendet werden, dann bietet \matlab{} die M\"oglichkeit +sogenannte \codeterm[Funktion!lokale]{lokale Funktionen} oder auch +\codeterm[Funktion!geschachtelte]{geschachtelte Funktionen} +(\enterm{nested functions}) in einer einzelnen Datei zu +erstellen. Listing \ref{localfunctions} zeigt ein Beispiel f\"ur eine +lokale Funktion. + +\pagebreak[3] +\lstinputlisting[label=localfunctions, caption={Beispiel f\"ur den + Einsatz von lokalen Funktionen.}]{calculateSines.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[Funktion!geschachtelte]{geschachtelten +Funktionen} ist das anders. Diese werden innerhalb eines +Funktionsk\"orpers (zwischen den Schl\"usselworten \code{function} und +dem \code{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[Funktion!lokale]{lokalen} oder +\codeterm[Funktion!geschachtelte]{geschachtelten + Funktionen} die \"Ubersichtlichkeit erh\"oht werden. + +Es lohnt sich auf den eigenen Programmierstil zu +achten!\footnote{Buchtip: Robert C. Martin: \textit{Clean Code: A + Handbook of Agile Software Craftmanship}, Prentice Hall} + +\shortquote{Programs must be written for people to read, and only + incidentally for machines to execute.}{Abelson / Sussman} + +\shortquote{Any fool can write code that a computer can + understand. Good programmers write code that humans can + understand.}{Martin Fowler} + +\shortquote{First, solve the problem. Then, write the code.}{John + Johnson} + + +\selectlanguage{english}