[chapter 4] translate code style chapter
This commit is contained in:
parent
104717cfe7
commit
4270b65442
@ -1,215 +1,208 @@
|
||||
\chapter{\tr{Programming style}{Programmierstil}}
|
||||
\chapter{\tr{Code 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}
|
||||
%\selectlanguage{ngerman}
|
||||
Cultivating a good code style not a matter of good taste but is
|
||||
a key ingredient for understandability, maintainability and in the end
|
||||
facilitates reproducibility of scientific results. Programs should be
|
||||
written and structured in a way that supports outsiders as well the
|
||||
author himself --- a few weeks or months after it was written --- to
|
||||
understand the programs' rationale. Clean code pays off for the
|
||||
original author as well as others that are supposed to use the code.
|
||||
|
||||
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:
|
||||
Clean code addresses several issues:
|
||||
\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.
|
||||
\item The programs' structure.
|
||||
\item Naming of scripts and functions.
|
||||
\item Naming of variables and constants.
|
||||
\item Application of indentation empty lines to define blocks.
|
||||
\item Use of comments and inline documentation.
|
||||
\item Delegation of repeated code to functions and dedicated
|
||||
subroutines.
|
||||
\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}).
|
||||
\section{Organization of programs on the file system}
|
||||
|
||||
While introducing scripts and functions we suggested a typical program
|
||||
layout (box\,\ref{whenscriptsbox}). The idea is to create a single
|
||||
entry point by having one script that controls the rest of program by
|
||||
managing data and results and calling functions that work on the data
|
||||
and produce the results. Applying this structure makes it easy to
|
||||
understand the flow of the program but two questions remain: (i) How
|
||||
to organize the files on the file system and (ii) how to name them
|
||||
that the controlling script is easily identified among the other
|
||||
\codeterm{m-files}.
|
||||
|
||||
Upon installation ``MATLAB'' creates a folder called \emph{MATLAB} in
|
||||
the user space (Windows: My files, Linux: Documents, MacOS:
|
||||
Documents). Since this folder is already appended to the Matlab search
|
||||
path (Box~\ref{matlabpathbox}), it is easiest to stick to it for the
|
||||
moment. Of course, any other location can specified as well. Generally
|
||||
it is of great advantage to store related scripts and functions within
|
||||
the same folder on the hard drive. An easy approach is to create a
|
||||
project-specific folder structure that contains sub-folders for each
|
||||
task (analysis) and to store all related \codeterm{m-files}
|
||||
(screenshot \ref{fileorganizationfig}). In these task-related folders
|
||||
one may consider to create a further sub-folder to store results
|
||||
(created figures, result data). On the project level a single script
|
||||
(analysis.m) controls the whole process. In parallel to the project
|
||||
folder we suggest to create an additional folder for functions that
|
||||
are or may be relevant across different projects.
|
||||
|
||||
Within such a structure it is quite likely that programs in different
|
||||
projects share the same name (e.g. a ``load\_data.m''
|
||||
function). Usually this will not lead to conflicts due to the way
|
||||
matlab searches for matching functions which always starts in the
|
||||
current folder (more information on the \matlab-path 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.}
|
||||
\titlecaption{\label{fileorganizationfig} Possible folder structure
|
||||
for maintaining program code on the file system.}{For each project
|
||||
one maintains an individual folder in which analyses or tasks may
|
||||
be structured in sub-folders. Within each analysis a ``main.m''
|
||||
script is the entry point for the analyses. On the project level
|
||||
there could be a single script that triggers and controls all
|
||||
analyses and tasks in the sub-folders. Functions that are of
|
||||
general interest across projects are best kept in a dedicated
|
||||
folder outside the project sub-structure.}
|
||||
\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.
|
||||
\begin{ibox}[tp]{\label{matlabpathbox}\matlab{} search path}
|
||||
The \codeterm{search path} defines where \matlab{} looks for scripts
|
||||
and functions. When calling a function from the command line
|
||||
\matlab{} needs to figure out which function is addressed and starts
|
||||
looking for it in the current path. If this fails it will crawl all
|
||||
locations listed in the search path (see figure). The
|
||||
\codeterm{search path} is basically a list of folders. \matlab{}
|
||||
will go through this list from front to end and the search will stop
|
||||
on the first match. This implies that the order in the search path
|
||||
may affect which version of functions that share the same name is
|
||||
used. Note: \matlab{} does not perform a recursive search. That is,
|
||||
a function that resides in a sub-folder that is not explicitly
|
||||
listed in the \codeterm{search path} will not be found.
|
||||
|
||||
\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.
|
||||
The search path can be managed from the command line by using the
|
||||
functions \code{addpath()} or \code{userpath()}. Alternatively, the
|
||||
\matlab{} UI offers a graphical tool for adding/removing paths, or
|
||||
changing the order of entries.
|
||||
|
||||
The current working directory can be changed via the UI or also the
|
||||
command line using the command \code{cd} (for change directory). The
|
||||
current path is shown in the current directory text field of the UI
|
||||
or can be requested using the command \code{pwd} (for present work
|
||||
directory). The function \code{which()} shows the full path of the
|
||||
actually used function. For example, finding out which \code{mean()}
|
||||
function is used gives a result similar to:
|
||||
\begin{lstlisting}[label=useofwhich, caption={Use of 'which'}]
|
||||
>> which('mean')
|
||||
/Applications/MATLAB2018b.app/toolbox/matlab/datafun/mean.m
|
||||
\end{lstlisting}
|
||||
\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.
|
||||
\section{Naming scripts and functions}
|
||||
\matlab{} will search the search path (Box \ref{matlabpathbox})
|
||||
exclusively by name. It is case-sensitive this implies that the files
|
||||
\file{test\_function.m} and \file{Test\_function.m} are two different
|
||||
things. It is self-evident that choosing such names is nonsensical
|
||||
because the name contains no cue about the difference between the two
|
||||
and it further tells close to nothing about the purpose. Finding good
|
||||
names is not trivial sometimes it is harder than the programming
|
||||
itself. Expressive names, however, pay off! Expressive means that the
|
||||
name provides information about the purpose.
|
||||
|
||||
\begin{important}[Naming scripts and functions]
|
||||
Function and script names should be expressive in the sense that the
|
||||
name provides information about the function's purpose
|
||||
(\file{estimate\_firingrate.m} tells much more than
|
||||
\file{exercise1.m}). Choosing a good name replaces large parts of
|
||||
the documentation.
|
||||
\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:
|
||||
\matlab{} has a few rules about names: Names must not start with a
|
||||
number, they must not contain blanks or other special characters like
|
||||
e.g. German Umlauts. Otherwise one is free to use whatever suits. The
|
||||
names of pre-defined functions shipped with \matlab{} follows several
|
||||
patterns:
|
||||
\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.
|
||||
\item Names are always lowercase.
|
||||
\item Names are often abbreviations (e.g. \code{xcorr()}
|
||||
stands for cross-correlation \code{repmat()} for ``repeat matrix'').
|
||||
\item Functions that convert between formats are named according to
|
||||
the pattern ``format2format'' (e.g. \code{num2str()} for ``number to string'' conversion).
|
||||
\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.
|
||||
There are other common patterns such as the \emph{camelCase} in which
|
||||
the first character of compound words is capitalized. Other
|
||||
conventions use the underscore to separate the individual words
|
||||
\emph{snake\_case}. A function that counts the number of action
|
||||
potentials could be named \file{spikeCount.m} or
|
||||
\file{spike\_count.m}.
|
||||
|
||||
|
||||
\section{Naming variables and constants}
|
||||
|
||||
\matlab{} applies the same rules for naming variables and constants as
|
||||
for the naming of scripts and functions. The dictum of good
|
||||
code style is: ``Program code must be readable.'' Expressive
|
||||
names are extraordinarily important in this respect. Even if it is
|
||||
tricky to find expressive names that are not overly long, naming
|
||||
should be taken seriously.
|
||||
|
||||
While the names of scripts and functions describe the purpose, names
|
||||
of variables describe the stored content. A variable storing the
|
||||
average number of actions potentials could be called
|
||||
\varcode{average\_spike\_count}. If this variable is meant to store
|
||||
multiple spike counts the plural form would be appropriate
|
||||
(\varcode{average\_spike\_counts}).
|
||||
|
||||
The control variables used in the head of a \code{for} loop are often
|
||||
simply named \varcode{i}, \varcode{j} or \varcode{k}. This kind-of
|
||||
clashes with the previously made statements but since it is a very
|
||||
common pattern the meaning of such variables in the context of the
|
||||
loop is quite obvious. This should, however, be the only exception to
|
||||
the general rule of expressive naming.
|
||||
|
||||
\begin{important}[Naming of variables]
|
||||
The names of variables should be expressive. That is, the name
|
||||
itself should tell about the content of the variable. The name
|
||||
\varcode{spike\_count} tells much more about the stored information
|
||||
than \varcode{x}. Choosing a good variable name replaces additional
|
||||
comments.
|
||||
\end{important}
|
||||
|
||||
|
||||
\section{Codestil}
|
||||
\section{Code style}
|
||||
Readability of program code depends strongly on whether or not a
|
||||
consistent code style is applied. A program that is only randomly
|
||||
indented or that contains lots of empty lines is very hard to read and
|
||||
to comprehend. Even though the \matlab{} language (as many others)
|
||||
does not enforce indentation, indentation is very powerful for
|
||||
defining coherent blocks. The \matlab{} editor supports this by an
|
||||
auto-indentation mechanism. A selected section of the code and be
|
||||
automatically indented by pressing the \keycode{Ctrl-I} combination.
|
||||
|
||||
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.
|
||||
Interspersing empty lines is very helpful to separate regions in the
|
||||
code that belong together. Too many empty lines, however lead to
|
||||
hard-to-read code because it might require more space than a granted
|
||||
by the screen and thus takes overview.
|
||||
|
||||
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.
|
||||
The following two listings show basically the same implementation of a
|
||||
random walk once in a rather chaotic version (listing
|
||||
\ref{chaoticcode}) then in cleaner way (listing \ref{cleancode})
|
||||
|
||||
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;
|
||||
\begin{lstlisting}[label=chaoticcode, caption={Chaotic implementation of the random-walk.}]
|
||||
num_runs = 10; max_steps = 1000;
|
||||
|
||||
positions = zeros(max_steps, num_runs);
|
||||
|
||||
@ -232,7 +225,7 @@ end
|
||||
|
||||
\pagebreak[4]
|
||||
|
||||
\begin{lstlisting}[label=cleancode, caption={\"Ubersichtliche Implementation des Random-walk.}]
|
||||
\begin{lstlisting}[label=cleancode, caption={Clean implementation of the random-walk.}]
|
||||
num_runs = 10;
|
||||
max_steps = 1000;
|
||||
positions = zeros(max_steps, num_runs);
|
||||
@ -249,33 +242,30 @@ for run = 1:num_runs
|
||||
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\\
|
||||
\section{Using comments}
|
||||
|
||||
It is common to provide extra information about the meaning of program
|
||||
code by adding comments to it. In \matlab{} comments are indicated by
|
||||
the percent character \code{\%}. Anything that is written in the
|
||||
respective line following the percent is ignored and considered a
|
||||
comment. When used sparsely comments can immensely important for
|
||||
understanding. Comments are short sentences that describe the meaning
|
||||
of the (following) lines in the program code. During the initial
|
||||
implementation of a function they can be used to guide the development
|
||||
but have the tendency to blow up the code and decrease readability. By
|
||||
choosing expressive variable and function names, most lines should be
|
||||
self-explanatory.
|
||||
|
||||
For example stating the obvious does not really help:\\
|
||||
\varcode{ x = x + 2; \% add two to x}\\
|
||||
ein v\"ollig unn\"otiger Kommentar.
|
||||
|
||||
\begin{important}[Verwendung von Kommentaren]
|
||||
\begin{important}[Using comments]
|
||||
\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!
|
||||
\item Comments describe the rationale of the respective code block.
|
||||
\item Comments are good and helpful --- they have to be true, however!
|
||||
\item A wrong comment is worse than a non-existent comment!
|
||||
\item Comments must be maintained just as the code. Otherwise they
|
||||
may become wrong and worse than meaningless!
|
||||
\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
|
||||
@ -284,153 +274,139 @@ ein v\"ollig unn\"otiger Kommentar.
|
||||
\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!
|
||||
\section{Documenting functions}
|
||||
All pre-defined \matlab{} functions begin with a comment block that
|
||||
describes the purpose of the function, the required and optional
|
||||
arguments, and the values returned by the function. Using the
|
||||
\code{help} command one can display these comments and learn how to
|
||||
use the function properly. Self-written functions can and should be
|
||||
documented in a similar way. Listing ~\ref{localfunctions} shows a
|
||||
well documented function.
|
||||
|
||||
\begin{important}[Documenting functions]
|
||||
Functions must be properly documented, otherwise a user (the author
|
||||
him- or herself) must read and understand the function code which is
|
||||
a waste of time!
|
||||
\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.
|
||||
\item Describe with a few sentences the purpose of the function.
|
||||
\item Note the function head to illustrate the order of the argments.
|
||||
\item For each argument state the purpose, the expected data type
|
||||
(number, vector, matrix, etc.) and, if applicable, the unit in
|
||||
which a provided number must be given (e.g. seconds if a time is
|
||||
expected).
|
||||
\item The same for all return values.
|
||||
\end{itemize}
|
||||
\end{important}
|
||||
|
||||
|
||||
\section{Auslagerung von Aufgaben in Funktionen}
|
||||
\section{Delegating tasks in functions}
|
||||
Comments and empty lines are used to organize code into logical blocks
|
||||
and to briefly explain what they do. Whenever one feels tempted to do
|
||||
this, one could also consider to delegate the respective task to a
|
||||
function. In most cases this is preferable.
|
||||
|
||||
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.
|
||||
Not delegating the tasks leads to very long \codeterm{m-files} which
|
||||
can be confusing. Sometimes such a code is called ``spaghetti
|
||||
code''. It is high time to think about delegation of tasks to
|
||||
functions.
|
||||
|
||||
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{important}[Delegating to functions]
|
||||
When should one consider delegating tasks to specific functions?
|
||||
\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.
|
||||
\item Whenever one needs more than two indentation levels to
|
||||
organize to code.
|
||||
\item Whenever the same lines of code are repeated more than once.
|
||||
\item Whenever one is tempted to use copy-and-paste.
|
||||
\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]
|
||||
\subsection{Local and nested functions}
|
||||
Generally, functions live in their own \codeterm{m-files} that have
|
||||
the same name as the function itself. Delegating tasks to functions
|
||||
thus leads to a large set of \codeterm{m-files} which increases
|
||||
complexity and may lead to confusion. If the delegated functionality
|
||||
is used in multiple instances, it is advisable to do so. On the other
|
||||
hand, when the delegated functionality is only used within the context
|
||||
of another function \matlab{} allows to define
|
||||
\codeterm[function!local]{local functions} and
|
||||
\codeterm[function!nested]{nested functions} within the same
|
||||
file. Listing \ref{localfunctions} shows an example of a local
|
||||
function definition.
|
||||
|
||||
\pagebreak[3] \lstinputlisting[label=localfunctions, caption={Example
|
||||
for local functions.}]{calculateSines.m}
|
||||
|
||||
Local function live in the same \codeterm{m-file} as the main function
|
||||
and are only available in this context. Each local function has its
|
||||
own \codeterm{scope}, that is, the local function can not access (read
|
||||
or write) variables of the calling function.
|
||||
|
||||
This is different in so called \codeterm[function!nested]{nested
|
||||
functions}. These are defined within the body of the parent function
|
||||
(between the keywords \code{function} and \code{end}) and have full
|
||||
access to all variables defined in the parent function. Working (in
|
||||
particular changing) the parent's variables is handy on the one side,
|
||||
but is also risky. One should take care when defining nested functions.
|
||||
|
||||
|
||||
\section{Specifics when using scripts}
|
||||
A similar problem as with nested function arises when using scripts
|
||||
(instead of functions). All variables that are defined within a script
|
||||
become available in the global \codeterm{Workspace}. There is the risk
|
||||
of name conflicts, that is, a called sub-script redefines or uses the
|
||||
same variable name and may \emph{silently} change its content. The
|
||||
user will not be notified by this change and the calling script may
|
||||
expect a completely different content. Bugs that are based on such
|
||||
mistakes are hard to find since the program itself looks perfectly
|
||||
fine.
|
||||
|
||||
To avoid such issues one should design scripts in a way that they
|
||||
perform their tasks independent from other scripts and functions.
|
||||
|
||||
A common use case for a script could be to control the analyses made
|
||||
on many datasets and to collect the results. A good script is still
|
||||
not too long and is thus easy to comprehend. Another advantage of
|
||||
small task-related scripts is that they can be directly executed by
|
||||
either calling them from the command line or pressing \keycode{F5} in
|
||||
the editor. Should it fail there will be a proper error message that
|
||||
provides important information to track and fix the bug.
|
||||
|
||||
\begin{important}[Structuring scripts]
|
||||
\begin{itemize}
|
||||
\item Skripte sollten genauso wie Funktionen spezifische Aufgaben
|
||||
l\"osen und nicht zu lang sein.
|
||||
\item Similar to functions script should solve one task and should
|
||||
not be too long.
|
||||
|
||||
\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.
|
||||
\item Scripts should work independently of existing variables in the
|
||||
global workspace.
|
||||
|
||||
\item It is advisable to start a script with deleting variables
|
||||
(\code{clear}) from the workspace and most of the times it is also
|
||||
good to close all open figures (\code{close all}).
|
||||
|
||||
\item Clean up the workspace at the end of a script. Delete
|
||||
(\code{clear}) all variables that are no longer needed.
|
||||
\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.
|
||||
\section{Summary}
|
||||
|
||||
Program code must be readable. Names of variables, functions and
|
||||
scripts should be expressive and describe their purpose (scripts and
|
||||
functions) or their content (variables). Cultivating a personalized
|
||||
code style is perfectly fine as long as it is consistent. Many
|
||||
programming languages or communities have their own traditions. It is
|
||||
advisable to adhere to these.
|
||||
|
||||
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.
|
||||
Repeated tasks should (to be read as must) be delegated to
|
||||
functions. In cases in which a function is only locally applied and
|
||||
not of more global interest across projects consider to define it as
|
||||
\codeterm[function!local]{local function} or
|
||||
\codeterm[function!nested]{nested function}. Taking care to increase
|
||||
readability and comprehensibility pays off, even to the author!
|
||||
|
||||
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}
|
||||
\footnote{Reading tip: 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}
|
||||
|
Reference in New Issue
Block a user