From 108210210a364a3c3c180189183eb0d354aaacdb Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Sat, 14 Nov 2015 13:08:21 +0100 Subject: [PATCH] finished (?) chapter, add example code --- programmingstyle/code/calculate_sines.m | 30 ++++ programmingstyle/lecture/programmingstyle.tex | 151 +++++++++++++++--- 2 files changed, 155 insertions(+), 26 deletions(-) create mode 100644 programmingstyle/code/calculate_sines.m diff --git a/programmingstyle/code/calculate_sines.m b/programmingstyle/code/calculate_sines.m new file mode 100644 index 0000000..635764d --- /dev/null +++ b/programmingstyle/code/calculate_sines.m @@ -0,0 +1,30 @@ +function sines = calculate_sines(x, amplitudes, frequencies) + % Function calculates sinewaves with all combinations of + % given amplitudes and frequencies. + % Arguments: x, a vector of radiants for which the sine should be + % computed + % amplitudes, a vector of amplitudes + % frequencies, a vector of frequencies + % + % Returns: a 3-D Matrix of sinewaves, 2nd dimension represents + % the amplitudes, 3rd the frequencies. + + sines = zeros(length(x), length(amplitudes), length(frequencies)); + + for i = 1:length(amplitudes) + sines(:, i, :) = sines_with_frequencies(x, amplitudes(i), frequencies); + end +end + + +function sines = sines_with_frequencies(x, amplitude, frequencies) + sines = zeros(length(x), length(frequencies)); + for i = 1:length(frequencies) + sines(:,i) = sinewave(x, amplitude, frequencies(i)); + end +end + + +function sine = sinewave(x, amplitude, frequency) + sine = sin(2 .* pi .* x *frequency) .* amplitude; +end \ No newline at end of file diff --git a/programmingstyle/lecture/programmingstyle.tex b/programmingstyle/lecture/programmingstyle.tex index 5090943..e977ace 100644 --- a/programmingstyle/lecture/programmingstyle.tex +++ b/programmingstyle/lecture/programmingstyle.tex @@ -15,9 +15,11 @@ Guter Programmierstil greift auf unterschiedlichen Ebenen an: \begin{enumerate} \item Die Struktur von Programmen. \item Die Namensgebung von Skripten und Funktionen. -\item Die Namensgebung fuer Variablen und Konstanten. -\item Die Verwendung von Einr\"uckungen und Leerzeilen um Bl\"ocke im Code hervorzuheben. +\item Die Namensgebung f\"ur Variablen und Konstanten. +\item Die Verwendung von Einr\"uckungen und Leerzeilen um Bl\"ocke im + Code hervorzuheben. \item Verwendung von Kommentaren und Hilfetexten. +\item Auslagerung von Funktionalit\"at in eigene Funktionen. \end{enumerate} \section{Struktur von Programmen, Organisation von m-Files im Dateisystem} @@ -107,7 +109,7 @@ 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'' +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 @@ -163,14 +165,55 @@ zuf\"allig) einger\"uckt sind ist deutlich schwerer zu lesen und zu verstehen, als eines, in dem eine konsistente Einr\"uckung vorgenommen wurde. -Gerne werden Leerzeielen eingef\"ugt um Abschnitte im Programm zu +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 das das Programm nicht mehr auf eine Seite passt und man +f\"uhren dazu, dass das Programm nicht mehr auf eine Seite passt und man leicht den \"Uberblick verliert. - - \TODO chaotisches und aufger\"aumtes Listing +Die beiden folgenden Listings \ref{chaoticcode} und \ref{cleancode} +zeigen die Implementation des random-walk einmal eher chaotisch und +einmal aufger\"aumt. + +\begin{lstlisting}[label=chaoticcode, caption={Random-walk Implementation unaufgr\"aumt.}] +num_runs = 10; +max_steps = 1000; + +positions = zeros(max_steps, num_runs); + +for run = 1:num_runs + + +for step = 2:max_steps + +x = randn(1); +if x<0 +positions(step, run)= positions(step-1, run)+1; + + +elseif x>0 + positions(step,run)=positions(step-1,run)-1; + end +end +end +\end{lstlisting} + +\begin{lstlisting}[label=cleancode, caption={Random-walk Implementation etwas ordentlicher.}] +num_runs = 10; +max_steps = 1000; +positions = zeros(max_steps, num_runs); + +for run = 1:num_runs + for step = 2:max_steps + x = randn(1); + if x < 0 + positions(step, run) = positions(step-1, run) + 1; + elseif x > 0 + positions(step, run) = positions(step-1, run) - 1; + end + end +end +\end{lstlisting} \section{Verwendung von Kommentaren} @@ -190,8 +233,8 @@ Variablennamen sind viel Zeilen weitestgehend selbsterkl\"arend. \begin{itemize} \item Kommentare sind gut und wichtig aber: Sie m\"ussen richtig sein! - \item Ein Kommentar der l\"ugt, ist schlimmer als gar kein Kommentar! - \item Kommentare m\"ussen gepflegt werden sonst sind sie mehr als + \item Ein Kommentar, der l\"ugt, ist schlimmer als gar kein Kommentar! + \item Kommentare m\"ussen gepflegt werden, sonst sind sie mehr als wertlos! \end{itemize} \end{important} @@ -199,30 +242,86 @@ Variablennamen sind viel Zeilen weitestgehend selbsterkl\"arend. \section{Auslagerung von Aufgaben in Funktionen} -Spaghetticode - -inline functions +Kommentare oder Leerzeilen werden benutzt um Abschnitte des Codes +abzutrennen und nazudeuten, dass ab da etwas inhaltlich anderes +gemacht wird. Wenn man im Zuge ist, eine solche inhaltliche Trennung +einzuf\"ugen muss man sich immer fragen, ob dieser Teil des Programms +nicht in eine eigene Funktion ausgelagert werden sollte. Fast immer +kann man das bejahen. +Abschnitte nicht auszulagern f\"uhrt zu sehr langen m-Files, die +leicht un\"ubersichtlich sind. Man nennt sie +\codeterm{Spaghetticode}. Es ist h\"ochste Zeit \"uber Auslagerung in +Funktionen nachzudenken. -\section{Besonderheiten bei Skripten} +\begin{important} + Wann sollte man Programmteile in eigene Funktionen auslagern? + \begin{itemize} + \item Wenn man innerhalb einer Funktion, eines Skripts mehr als zwei + Einr\"uckungsebenen hat. + \item Wenn man wiederholte Strukturen im Code hat. + \item Wenn man versucht ist, diese mit Copy and Paste zu erzeugen. + \end{itemize} +\end{important} -Achtung, globaler G\"ultigkeitsbereich! +\subsection{Lokale Funktionen und geschachtelte Funktionen} + +Eine M\"oglichkeit Spaghetticode zu vermeiden ist das Auslagern von +Funktionalit\"at in eigene Funktionen. Dies f\"uhrt dazu, dass man +eine F\"ulle von Dateien erzeugt, die die \"Ubersichtlichkeit nicht +unbedingt erh\"ohen. Wenn die auszulagernde Funktionalit\"at an vielen +Stellen ben\"otigt werden k\"onnte ist es dennoch sinnvol dies zu +tun. Wenn nicht, dann bietet \matlab{} die M\"oglichkeit sogenannte +\codeterm{lokale Funktionen} oder auch \codeterm{geschachtelte + Funktionen} (\enterm{nested functions}) zu erstellen (Listing +\ref{localfunctions} zeigt ein Beispiel f\"ur eine lokale Funktion). + +\lstinputlisting[label=localfunctions, caption={\codeterm{Lokale Funktionen} erh\"ohen die Lesbarkeit sind aber nur innerhalb der definierenden Datei verf\"ugbar.}]{calculate_sines.m} + +Lokale Funktionen existieren in der gleichen Datei und sind nur dort +verf\"ugbar. Jede Funktion hat ihren eigenen G\"ultigkeitsbereich, das +hei{\ss}t, dass Variablen aus den aufrufenden Funktionen nicht +sichtbar sind. Bei sogenannten \codeterm{geschachtelten Funktionen} +ist das anders. Diese werden innerhalb eines Funktionsk\"orpers +(zwischen den Schl\"usselworten \codeterm{function} und dem +\codeterm{end} definiert und k\"onnen auf alle Variablen der +``Mutterfunktion'' zugreifen und diese auch ver\"andern. Folglich +sollten sie nur mit Bedacht eingesetzt werden. -Kollision von Variablennamen. +\section{Besonderheiten bei Skripten} -Best practice. +Ein \"ahnliches Problem wurde schon bei der Einf\"uhrung der Skripte +erw\"ahnt. Variablen, die in Skripten definiert werden sind global im +\codeterm{Workspace} verf\"ugbar. Es besteht die Gefahr von +Namenskollisionen. Problem dabei ist, dass der Nutzer gar nicht +mitbekommt, wenn eine Variable redefiniert oder neuen Inhalt +zugewiesen bekommt. Fehler, die auf derartigen Kollisionen beruhen +sind h\"aufig nur schwer zu finden, da das Programm f\"ur sich korrekt +aussieht. \begin{important} - 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. - - Es lohnt sich! + Es empfiehlt sich zu Beginn eines Skriptes alle Variablen im + \codeterm{Workspace} zu l\"oschen (\code{clear}). Meist ist auch + ein \code{close all} angebracht. + + Am Ende eines Skriptes sollte der \codeterm{Workspace} mithilfe von + \code{clear} wieder von all den Variablen ges\"aubert werden, die + nicht mehr ben\"otigt werden. \end{important} +\section{Fazit} + +Programmcode soll lesbar sein. Namen von Variablen, Funktionen und +Skripten sollten ausdrucksstark sein und R\"uckschl\"usse auf den +Inhalt oder den Zweck erlauben. Einen pers\"onlichen Programmierstil +zu entwickeln ist v\"ollig in Ordnung solange er konsistent ist. In +machen Programmiersprachen gibt es Traditionen und \"Ubereink\"unfte, +diese sollten dann beachtet werden. + +Wiederholte Programmabschnitte sollten in Funktionen ausgelagert +werden. Wenn diese nich von globalem Interesse sind, kann man auch mit +\codeterm{lokalen} oder \codeterm{geschachtelten Funktionen} die +Lesbarkeit erh\"ohen. -Literatur zum Programmierstil: z.B. Robert C. Martin: \textit{Clean - Code: A Handbook of Agile Software Craftmanship}, Prentice Hall +\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}