|
|
|
@ -6,20 +6,19 @@
|
|
|
|
|
|
|
|
|
|
%\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
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Clean code addresses several issues:
|
|
|
|
|
\begin{enumerate}
|
|
|
|
|
\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 Application of indentation and empty lines to define blocks.
|
|
|
|
|
\item Use of comments and inline documentation.
|
|
|
|
|
\item Delegation of repeated code to functions and dedicated
|
|
|
|
|
subroutines.
|
|
|
|
@ -29,13 +28,12 @@ Clean code addresses several issues:
|
|
|
|
|
|
|
|
|
|
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}.
|
|
|
|
|
entry point by having one script that controls the rest of the program
|
|
|
|
|
by calling functions that work on the data and managing 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:
|
|
|
|
@ -110,24 +108,11 @@ Box~\ref{matlabpathbox}).
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
\end{ibox}
|
|
|
|
|
|
|
|
|
|
\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}
|
|
|
|
|
\section{Naming things}
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
\matlab{} has a few rules about names: Names must not start with a
|
|
|
|
|
number, they must not contain blanks or other special characters like
|
|
|
|
@ -144,26 +129,41 @@ patterns:
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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}.
|
|
|
|
|
|
|
|
|
|
The same naming rules apply for scripts and functions as well as
|
|
|
|
|
variables and constants.
|
|
|
|
|
|
|
|
|
|
\section{Naming variables and constants}
|
|
|
|
|
\subsection{Naming scripts and functions}
|
|
|
|
|
\matlab{} will search the search path (Box \ref{matlabpathbox})
|
|
|
|
|
exclusively by name. This search is case-sensitive which 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 tiny difference in the name contains no cue
|
|
|
|
|
about the difference between the two versions and the function names
|
|
|
|
|
themselves tell close to nothing about the purpose. Finding good names
|
|
|
|
|
is not trivial. Sometimes it is harder than the programming
|
|
|
|
|
itself. Choosing \emph{expressive names} that provide information about a
|
|
|
|
|
function's purpose, however, pays off!
|
|
|
|
|
|
|
|
|
|
\begin{important}[Naming scripts and functions]
|
|
|
|
|
Names of functions and scripts 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}
|
|
|
|
|
|
|
|
|
|
\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.
|
|
|
|
|
\subsection{Naming variables and constants}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
@ -190,7 +190,7 @@ 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.
|
|
|
|
|
automatically indented by pressing \keycode{Ctrl-I}.
|
|
|
|
|
|
|
|
|
|
Interspersing empty lines is very helpful to separate regions in the
|
|
|
|
|
code that belong together. Too many empty lines, however lead to
|
|
|
|
@ -198,8 +198,11 @@ hard-to-read code because it might require more space than a granted
|
|
|
|
|
by the screen and thus takes overview.
|
|
|
|
|
|
|
|
|
|
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})
|
|
|
|
|
random walk\footnote{A random walk is a simple simulation of Brownian
|
|
|
|
|
motion. In each simulation step an agent takes a step into a
|
|
|
|
|
randomly chosen direction.} once in a rather chaotic version
|
|
|
|
|
(listing \ref{chaoticcode}) then in cleaner way (listing
|
|
|
|
|
\ref{cleancode})
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[label=chaoticcode, caption={Chaotic implementation of the random-walk.}]
|
|
|
|
|
num_runs = 10; max_steps = 1000;
|
|
|
|
@ -245,25 +248,24 @@ end
|
|
|
|
|
\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}\\
|
|
|
|
|
code by adding comments. In \matlab{} comments are indicated by the
|
|
|
|
|
percent character \code{\%}. Anything that follows the percent
|
|
|
|
|
character in a line is ignored and considered a comment. When used
|
|
|
|
|
sparsely comments can be immensely helpful. 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 and should be
|
|
|
|
|
avoided:\\ \varcode{ x = x + 2; \% add two to x}\\
|
|
|
|
|
|
|
|
|
|
\begin{important}[Using comments]
|
|
|
|
|
\begin{itemize}
|
|
|
|
|
\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 are good and helpful --- they must be true, however!
|
|
|
|
|
\item A wrong comment is worse than a non-existent one!
|
|
|
|
|
\item Comments must be maintained just as the code. Otherwise they
|
|
|
|
|
may become wrong and worse than meaningless!
|
|
|
|
|
\end{itemize}
|
|
|
|
@ -303,7 +305,7 @@ well documented function.
|
|
|
|
|
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.
|
|
|
|
|
function. In most cases this is preferable.
|
|
|
|
|
|
|
|
|
|
Not delegating the tasks leads to very long \codeterm{m-files} which
|
|
|
|
|
can be confusing. Sometimes such a code is called ``spaghetti
|
|
|
|
@ -325,9 +327,9 @@ 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
|
|
|
|
|
is used in multiple instances, it is still 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
|
|
|
|
@ -336,17 +338,19 @@ 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.
|
|
|
|
|
\emph{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. Interaction
|
|
|
|
|
with the local function requires to pass all required arguments and to
|
|
|
|
|
take care of the return values of the 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.
|
|
|
|
|
\emp{Nested functions} are different in this respect. They 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}
|
|
|
|
@ -355,7 +359,7 @@ A similar problem as with nested function arises when using scripts
|
|
|
|
|
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
|
|
|
|
|
user will not be notified about 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.
|
|
|
|
@ -379,12 +383,15 @@ provides important information to track and fix the bug.
|
|
|
|
|
\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 Often 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}). Be
|
|
|
|
|
careful if a the respective script has been called by another one.
|
|
|
|
|
|
|
|
|
|
\item Clean up the workspace at the end of a script. Delete
|
|
|
|
|
(\code{clear}) all variables that are no longer needed.
|
|
|
|
|
|
|
|
|
|
\item Consider to write functions instead of scripts.
|
|
|
|
|
\end{itemize}
|
|
|
|
|
\end{important}
|
|
|
|
|
|
|
|
|
|