diff --git a/header.tex b/header.tex index 6d15f95..b492b64 100644 --- a/header.tex +++ b/header.tex @@ -171,6 +171,7 @@ \newcommand{\enterm}[1]{``#1''} \newcommand{\determ}[1]{\textit{#1}} \newcommand{\codeterm}[1]{\textit{#1}} +\newcommand{\keycode}[1]{\texttt{#1}} \newcommand{\file}[1]{\texttt{#1}} %%%%% code/matlab commands: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/programmingstyle/code/calculate_sines.m b/programmingstyle/code/calculate_sines.m index 635764d..cd69b76 100644 --- a/programmingstyle/code/calculate_sines.m +++ b/programmingstyle/code/calculate_sines.m @@ -12,7 +12,7 @@ function sines = calculate_sines(x, amplitudes, frequencies) sines = zeros(length(x), length(amplitudes), length(frequencies)); for i = 1:length(amplitudes) - sines(:, i, :) = sines_with_frequencies(x, amplitudes(i), frequencies); + sines(:,i,:) = sines_with_frequencies(x, amplitudes(i), frequencies); end end @@ -27,4 +27,4 @@ end function sine = sinewave(x, amplitude, frequency) sine = sin(2 .* pi .* x *frequency) .* amplitude; -end \ No newline at end of file +end diff --git a/programmingstyle/lecture/programmingstyle.tex b/programmingstyle/lecture/programmingstyle.tex index e977ace..03be2a6 100644 --- a/programmingstyle/lecture/programmingstyle.tex +++ b/programmingstyle/lecture/programmingstyle.tex @@ -8,8 +8,8 @@ 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. +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} @@ -22,49 +22,48 @@ Guter Programmierstil greift auf unterschiedlichen Ebenen an: \item Auslagerung von Funktionalit\"at in eigene Funktionen. \end{enumerate} -\section{Struktur von Programmen, Organisation von m-Files im Dateisystem} +\section{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? +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 +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 +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\"ahlen -werden. In dem Beispiel in Abbildung \ref{fileorganizationfig} wird +werden. In dem Beispiel in \figref{fileorganizationfig} wird innerhalb dieses Ordners f\"ur jedes Projekt ein eigener Unterordner -erstellt in welchem widerum f\"ur jedes Problem, jede Analyse ein +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 +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 gitb es parallel zu den Projektordnern einen -``functions'' Ordner in dem Funktionen liegen, die in mehr als einem +\file{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 +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 -``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}). +\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} +\begin{figure}[tp] \includegraphics[width=0.75\textwidth]{program_organization} \titlecaption{\label{fileorganizationfig} M\"ogliche Oganisation von Programmcode im Dateisystem.}{ F\"ur jedes Projekt werden @@ -74,7 +73,7 @@ aktuellen Ordner nach passenden Dateien sucht (mehr Information in Box \end{figure} -\begin{ibox}[t]{\label{matlabpathbox}Der \matlab{} Suchpfad} +\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 @@ -109,14 +108,24 @@ aktuellen Ordner nach passenden Dateien sucht (mehr Information in Box \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. +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} + Die Namen von Funktionen und Skripte 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} \matlab{} macht keine weiteren Vorgaben, was die Namen angeht. Allerdings folgt die Benennung der vordefinierten Funktionen @@ -131,12 +140,12 @@ gewissen Mustern: Wertes in einen Text) benannt. \end{itemize} -Andere \"ubliche Muster sind der \emph{camelCase} bei dem die +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 +Namenskomponenten. Eine Funktion, die die Anzahl von +Aktionspotentialen bestimmt k\"onnte etwa \file{spikeCount.m} oder +\file{spike\_count.m} benannt werden. Leerzeichen, Sonderzeichen oder Anf\"ange mit Zahlen sind in Namen nicht erlaubt. @@ -146,15 +155,26 @@ 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. +f\"allt passende und nicht zu lange Namen zu finden, sollte einer gute +Namensgebung ernst genommen werden. -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}). +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} + 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} @@ -163,19 +183,21 @@ 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. +wurde. Mit der Tastenkombination \keycode{Ctrl-I} % XXX Oder wie war das? XXX +kann ein markierter +Bereich im \matlab{} Editor automatisch richtig einger\"uckt werden. -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. +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. +einmal aufger\"aumt und \"ubersichtlich. -\begin{lstlisting}[label=chaoticcode, caption={Random-walk Implementation unaufgr\"aumt.}] +\begin{lstlisting}[label=chaoticcode, caption={Un\"ubersichtliche Implementation des Random-walk.}] num_runs = 10; max_steps = 1000; @@ -198,7 +220,7 @@ end end \end{lstlisting} -\begin{lstlisting}[label=cleancode, caption={Random-walk Implementation etwas ordentlicher.}] +\begin{lstlisting}[label=cleancode, caption={\"Ubersichtliche Implementation des Random-walk.}] num_runs = 10; max_steps = 1000; positions = zeros(max_steps, num_runs); @@ -217,64 +239,89 @@ end \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. +Kommentarzeilen werden in \matlab{} mit dem Prozentzeichen \cide{\%} +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}). + +Zu viele 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} \begin{itemize} - \item Kommentare sind gut und wichtig aber: Sie m\"ussen richtig + \item Kommentare sollen die Absicht eines Programmabschnitts beschreiben. + \item Kommentare sind gut und wichtig --- sie m\"ussen aber 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! + \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} + 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 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. +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 m-Files, die -leicht un\"ubersichtlich sind. Man nennt sie -\codeterm{Spaghetticode}. Es ist h\"ochste Zeit \"uber Auslagerung in -Funktionen nachzudenken. +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} - Wann sollte man Programmteile in eigene Funktionen auslagern? + Wann sollten Programmteile in eigene Funktionen ausgelagert werden? \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. + \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} -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). +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 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} @@ -288,6 +335,7 @@ ist das anders. Diese werden innerhalb eines Funktionsk\"orpers ``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 @@ -302,7 +350,7 @@ 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. + ein \code{close all}, um alle Figures zu schlie{\ss}en, angebracht. Am Ende eines Skriptes sollte der \codeterm{Workspace} mithilfe von \code{clear} wieder von all den Variablen ges\"aubert werden, die @@ -319,9 +367,9 @@ 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 +werden. Wenn diese nich von globalem Interesse sind, kann mit \codeterm{lokalen} oder \codeterm{geschachtelten Funktionen} die -Lesbarkeit erh\"ohen. +\"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}