-
Notifications
You must be signed in to change notification settings - Fork 0
/
ansatz.tex
272 lines (202 loc) · 17.7 KB
/
ansatz.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
\section{Eigener Ansatz}
In diesem Teil der Arbeit wird eine Coding Convention erstellt. Sie soll dafür sorgen, dass ein Quelltext, der von mehreren Entwicklern geschrieben wird, eine Einheitliche Form annimmt. Zudem soll durch den Einsatz der Coding Convention die Lesbarkeit und Verständlichkeit des Quelltextes gefördert werden. Als Zielprogrammiersprache wird Java verwendet. In den hier erstellten Code Conventions wird kein Wert darauf gelegt, die einzig richtige Vorlage für guten Quelltext zu sein.
\subsection{Formatierung}
Zunächst einige allgemeine Festlegungen zur Formatierung des Quelltextes. Diese dienen dazu, ein einheitliches Textbild zu erhalten.
Der Zeichensatz der bei der Entwicklung verwendet werden muss ist UTF-8. Dieses wird von der Programmiersprache selbst vorgegeben. Durch die Verwendung, des UTF-8 Zeichensatzes, können die meisten länderspezifischen Umlaute und Sonderzeichen abgebildet werden. Des weiteren können so Umlautfehler vermieden werden.
Für die Einrückung werden vier Leerzeichen verwendet. Der Einsatz von Tabulatoren hätte den Vorteil, dass jeder Entwickler die Tiefe der Einrückung nach seinen Wünschen einstellen kann. Auf den Einsatz von Tabulatoren ist aber verzichtet worden, weil diese zu überlangen Zeilen führen können. Wenn ein Entwickler einen Quelltext schreibt und bei ihm ein Tabulator die Länge von zwei Leerzeichen hat, ist es für ihn möglich sehr viel längere Zeilen zu schreiben als ein Entwickler dessen Tabulatoren acht Leerzeichen lang sind ohne gegen die nächste Regel im bezug auf Zeilenlänge zu verstoßen.
Eine Zeile sollte nicht breiter als 120 Zeichen werden. Sollte eine Zeile länger werden kann diese an geeigneter Stelle umgebrochen werden. Die Fortsetzung wird doppelt, sprich acht Leerzeichen tief, eingerückt.
\subsubsection{Blöcke}
Der Inhalt von Blockklammern wird immer eingerückt. Die öffnende Blockklammer wird immer in derselben Zeile verwendet wie die dazugehörige Anweisung. Die schließende steht für sich alleine. Optionale Blockklammern bei Bedingungen und Schleifen sind immer zu setzen. Wenn es Sinnvoll ist, können Blockklammern zur Verdeutlichung des Quelltextes eingesetzt werden. In Listing \ref{own:blockopengl} ist ein Beispiel dazu zu sehen.
\begin{listing}[H]
\begin{minted}{java}
gl.PushMatrix();
{
gl.glTranslatef(width/2, height/2, 0);
gl.glRotatef(a, 0, 0, 0);
gl.glBegin(GL.GL_TRIANGLES);
gl.glColor4f(0.7, 0.1, 0.7, 0.8);
gl.glVertex3f(0, 0, 0);
gl.glVertex3f(0, 50, 0);
gl.glVertex3f(25, 0, 25);
gl.glEnd();
}
gl.PopMatrix();
\end{minted}
\caption{Einsatz von Blockklammern zur Verdeutlichung der Struktur am Beispiel von OpenGL}
\label{own:blockopengl}
\end{listing}
Die Transformationsoperationen nach dem \enquote{\texttt{gl.PushMatrix}} Aufruf gelten lediglich bis zum entsprechenden nächsten \enquote{\texttt{gl.PopMatrix}} Aufruf. Da die angewandten Rotationen und Translationen lediglich zwischen den aufrufen von Bedeutung sind kann es zur Lesbarkeit beitragen diese in einen extra Block zu schreiben.
\subsubsection{Zeilenumbrüche und Leerzeilen}
Als Zeilenumbruch wird der UNIX Zeilenumbruch verwendet. Dies bedeutet lediglich ein Zeilenvorschub(\textbackslash n), ohne Wagenrücklauf(\textbackslash r).
Dieser ist nach jeder öffnenden Blockklammer \enquote{\{} und jedem Semikolon zwingend. Durch diese Vorgabe wird sichergestellt, dass jede Anweisung in einer eigenen Zeile steht. Dies gilt genauso für Annotationen. Nach jeder Annotation muss ein Zeilenumbruch eingefügt werden. In \texttt{\enquote{ENUM}s} muss nach jedem Kommata ein Zeilenumbruch sein.
Leerzeilen sollen dazu verwendet werden eine sichtbare Trennung zwischen logischen Blöcken zu erzeugen. Die Trennung sollte jedoch maximal aus einer Leerzeile bestehen. Daraus ergeben sich u.a. Leerzeilen an folgenden Positionen:
\begin{itemize}
\item Nach der \texttt{package} Deklaration
\item Ggf. zwischen Importanweisungen von verschiedenen Quellen
\item Nach den Importen
\item Ggf. zwischen der Deklaration von Klassenvariablen
\item Zwischen der Deklaration von Klassenvariablen und Methoden
\item Zwischen den Methoden, inneren Klassen und inneren \enquote{\texttt{ENUM}s}
\end{itemize}
Diese sollen die Lesbarkeit des Quelltextes erhöhen. Der Quelltext wirkt dadurch weniger komprimiert. Zudem sollen die Leerzeilen logische zusammenhänge hervorheben.
\subsubsection{Leerzeichen}
Um eine bessere Lesbarkeit einzelner Zeilen zu erlangen werden an bestimmten Stellen Leerzeichen eingefügt. Dieses geschieht analog zu den Vorschlägen von Green und Ledgard\cite[S. 7]{Green}. Demnach wird nach jedem Komma ein Leerzeichen eingefügt. Zudem vor und nach nicht unären Operatoren. Der Memberoperator \enquote{.} bildet ist hiervon ausgenommen. Beispiele sind in Listing \ref{paper1:spaces}, auf Seite \pageref{paper1:spaces} zu sehen.
\subsection{Dateiaufbau}
Der Name, Speicherort und Teile der Struktur sind bereits durch die Spezifikation der Java Programmiersprache vorgegeben. Der Aufbau innerhalb der Datei ist wie in Listing \ref{own:struct} aufgebaut: Jede Datei beginnt mit der \texttt{package} Deklaration. Danach kommen die \texttt{Import} Anweisungen. Nun beginnt der Hauptteil der Datei, die Klasse, das Interface oder ein \texttt{ENUM}. Nach dieser darf es keine weiteren Elemente mehr geben. Auch wenn es die Java Spezifikation zuließe. Weitere Konstrukte müssen in eine separate Datei gelegt werden.
Die Reihenfolgen in einem Interface oder einem \texttt{Enum} sind trivial, da sie lediglich eine Art von Inhalt enthalten können. In Klassen kommen immer zuerst die Deklaration der Klassenvariablen, erst danach die Methoden und am Ende innere Klassen, Interfaces oder \texttt{Enums}.
Bei den Klassenvariablen kommen zuerst die Konstanten, gefolgt von den statischen Variablen und dann erst die Objektvariablen. Zwischen diesen Einheiten müssen Leerzeilen gesetzt sein.
Bei den Methoden kommen zuerst die Konstruktormethoden, gefolgt von statischen Methoden und am Ende die Objektmethoden. Die Reihenfolge der Methoden sollte so sein, dass im oberen Teil die Abstraktere und zum Ende hin immer speziellere Methoden stehen.
\begin{listing}[H]
\begin{minted}{java}
package my.package;
import java.packet.Klasse;
public class HelloWorldPrinter {
private static final String HELLO_TEXT = "hello";
private static String lastMessage = null;
private String name;
public HelloWorldPrinter(String name) {
this.name = name;
}
public static void sayHello(String name) {
HelloWorldPrinter printer = new HelloWorldPrinter(name);
printer.sayHello();
}
public void sayHello() {
System.out.Println(HELLO_TEXT + " " + name);
}
}
\end{minted}
\caption{Beispiel für die Struktur einer Quelltextdatei}
\label{own:struct}
\end{listing}
\subsection{Namensgebung}
Die Namen für Objekte unterstehen denselben Regeln wie sie auch Green und Ledgard aufgestellt haben. Sie sind in Abschnitt \ref{paper1:naming} auf Seite \pageref{paper1:naming} beschrieben. Mit Ausnahme der Regel, dass globale, häufig verwendete Objekte Namen haben dürfen die lediglich aus einem Zeichen bestehen. Jedes Element soll einen Namen haben, der die Aufgabe des Elementes möglichst genau beschreibt. Damit sind in zusammengesetzten Namen, Begriffe wie Info, Data, Object, etc. zu vermeiden. Diese bieten zum einen keine weitere Information, was die Bedeutung der Variable angeht und kann die Verständlichkeit negativ beeinflussen. In Listing \ref{own:namingmeta} sind zwei Variablendeklarationen zu sehen, anhand der Namen kann nicht unterschieden werden was der Unterschied zwischen diesen ist. Weiterhin soll bei zusammengesetzten Namen soll die \enquote{Camel Case} Schreibweise verwendet werden.
\begin{listing}[H]
\begin{minted}{java}
Map person = getPerson();
Map personData = getPersonData();
\end{minted}
\caption{Beispiel für schlechte Variablennamen.}
\label{own:namingmeta}
\end{listing}
Ein weiterer wichtiger Punkt ist, dass alle Namen aussprechbar sein müssen. Das hat den Effekt, dass sich diese besser merken lassen und die mündliche Diskussion über den Quelltext zwischen den Entwicklern vereinfacht. Die Entwickler müssen sich keine umständlichen Hilfsbezeichner ausdenken.
Weiterhin sollen die Namen suchbar sein. Diese Eigenschaft ist nicht für alle Namen notwendig, sollte aber für wichtige Elemente mit bedacht werden. Ein Negativbeispiel ist die Programmiersprache \enquote{Go}\footnote{s.a. http://golang.org/}. Wenn man versucht Informationen über die Programmiersprache mithilfe des Schlüsselwortes \enquote{Go} zu finden, wird man viele falsche Ergebnisse erhalten.
Namen sollten immer an die Problemdomäne angelehnt sein. Die Begriffswelt sollte sich im Quelltext wiederspiegeln. Damit können Sprachbarrieren zwischen Fachpersonal aus der Problemdomäne und den Entwicklern verringert werden.
\subsection{Kommentare}
Kommentare sollen zusätzliche Informationen zum Quelltext anbieten. Sie sollten dabei aber nicht zu geschwätzig sein. Genauso sollen sie keine unnötigen Informationen, wie eine Liste der Änderungen o.ä. enthalten. Ebensoweit sollen sie den geschriebenen Quelltext einfach wiederholen. Dies wäre zudem eine unnötige Redundanz.
In den Kommentaren darf die Lizenz der Software hinterlegt werden. Dies trägt zwar weder zur Lesbarkeit noch zur Verständlichkeit des Quelltextes bei, ist aber mitunter notwendiger Bestandteil und muss damit aufgeführt werden.
Wenn Kommentare verwendet werden sollte in ihnen, z.B. der Grund für eine Architekturentscheidung Dokumentiert sein. Der Entwickler kann so die Absicht die er verfolgt deutlich machen. Es können auch Warnungen sein. Es gibt Fälle, in denen der Aufruf einer Methode ungewollte Nebenwirkungen hat. Vor solchen, sofern sie nicht offensichtlich sind, muss gewarnt werden. Sogenannte \enquote{TODOs} sind ebenfalls erlaubt. Der Entwickler kann so unfertige stellen Kennzeichnen und beschreiben was noch zu erledigen ist.
Zuletzt noch die \enquote{JavaDoc} Kommentare. Sie dürfen verwendet werden. Aber auch hier gilt, diese mit Bedacht zu verwenden. Wenn die Bedeutung einer Variable oder einer Methode bereits aus ihrem Namen bzw. aus ihrer Signatur hervorgeht, kann dieser weggelassen werden. Genauso bei internen Operationen. Öffentliche Schnittstellen sollten hingegen mit \enquote{JavaDoc} Kommentaren versehen werden. Diese werden in der Regel von Entwicklern verwendet dich keinen tieferen Einblick in den Quelltext haben.
\subsection{Klassen}
Eine Klasse soll genau einem Zweck dienen. Dieser soll möglichst klar erkennbar sein und sich im Namen der Klasse wiederspiegeln. Ggf. soll der Zweck der Klasse im JavaDoc erläutert werden. Dies soll unter dem Einsatz des Single-Responsibility-Prinzips geschehen. Das Single-Responsibility-Prinzip sagt aus, dass eine Klasse genau einen Zweck haben soll. Daraus ergibt sich, dass es nur genau einen Grund geben darf die Klasse zu ändern. \cite[S. 176f.]{Martin}
Ein Hinweis auf das verletzen des Single-Responsibility-Prinzips ist es, wenn eine Klasse sehr lang wird. Sollte eine Klasse lang werden, muss darüber nachgedacht werden, ob diese möglicherweise mehrere Einsatzzwecken hat und aufgeteilt werden soll. Bei kleinen Klassen, mit lediglich einem Zweck, lässt sich dieser schnell erschließen, da sie aufgrund des geringeren Umfanges übersichtlicher ist.
\subsection{Methoden}
Bei Methoden wird das gleiche Ziel, wie auch bei Klassen verfolgt, sie sollen kurz und übersichtlich sein. Lange Methoden lassen sich in mehrere Kleinere zerlegen.
\begin{listing}[H]
\begin{minted}{java}
public Product getProductByName(String name) {
name = name.replace(" ", "+");
name = name.trim();
name = name.toLowercase();
for (Product product : products) {
if (!product.isActive()) {
continue;
}
if (!name.equals(product.getName())) {
continue;
}
return product;
}
throw new NoResultException();
}
\end{minted}
\caption{Lange Methode, die zwei Aufgaben erfüllt.}
\label{own:methodlong}
\end{listing}
Die Methode in Listing \ref{own:methodlong} sucht ein Produkt anhand seines Namens. Dies geschieht in zwei Schritten. Zunächst wird der Parameter \texttt{name} auf die Suche vorbereitet, danach wird dieser in allen aktiven Produkten gesucht. Diese zwei Schritte können in zwei extra Methoden ausgegliedert werden. Ein mögliches Ergebnis ist in Listing \ref{own:methodshort} zu sehen. Die Methode ist stark verkürzt und man kann sehr schnell sehen, was die Methode wie erledigt.
\begin{listing}[H]
\begin{minted}{java}
public Product getProductByName(String name) {
name = prepareProductName(name);
for (Product product : products) {
if (isProductNameMatching(product, name)) {
return product;
}
}
throw new NoResultException();
}
\end{minted}
\caption{Gekürzte Version des Listings \ref{own:methodlong}}
\label{own:methodshort}
\end{listing}
Ein weiterer wichtiger Aspekt an den Methoden ist die Parameteranzahl. Diese sollte möglichst gering sein und maximal 3 Parameter besitzen. Viele Parameter sind häufig ein Anzeichen dafür, dass eine Methode zu viele Aufgaben erledigt. Hier soll erwähnt sein, dass der Einsatz von Datenobjekten ausdrücklich erlaubt ist.
\enquote{Flag}-Parameter, die das Verhalten einer Methode beeinflussen sind nicht erlaubt. Sie schaden der Lesbarkeit des Quelltextes. In Listing \ref{own:flag} ist ein Methodenaufruf zu sehen. Dabei ist die Bedeutung des übergebenen Parameters nicht erkennbar. Besser ist es in einem solchen Fall zwei Methoden zu schreiben. Eine die das Verhalten mit gesetztem Flag, eine ohne abbildet. Der Name der Methode muss dieses Verhalten natürlich wiederspiegeln.
\begin{listing}[H]
\begin{minted}{java}
item.publish(true);
\end{minted}
\caption{Beispiel für einen \enquote{Flag}-Parameter}
\label{own:flag}
\end{listing}
Die verschachtelungstiefe kann ein weiterer Anhaltspunkt für zu komplexe, schwer zu lesende Methoden sein. Wenn eine Methode tief verschachtelt ist, zeugt dies von einer höheren Komplexität als flache Methoden, was sich u.a. in der zyklomatischen Komplexität wiederspiegelt\cite{McCabe}. Es gibt verschiedene Verfahren um die verschachtelungstiefe gering zu halten. Die offensichtlichste ist es, den Quelltext in verschiedene Methoden aufzuteilen. Eine andere Möglichkeit ist es in geeigneten Fällen, eine frühe Rückkehr aus der Methode zu verwenden. Listing \ref{own:lowindent} zeigt wie dies anhand von Validierungsoperationen. Sobald ein Fehler erkannt bemerkt wurde, wird die Methode sofort verlassen.
\begin{listing}[H]
\begin{minted}{java}
void print(String text) {
if (text == null) {
return;
}
if (text.isEmpty()) {
return;
}
System.out.Println(text);
}
\end{minted}
\caption{Beispiel für das frühzeitige verlassen einer Methode um eine niedrige Verschachtelungstiefe zu erhalten.}
\label{own:lowindent}
\end{listing}
\subsection{Fehlerbehandlung}
Bei der Fehlerbehandlung sind Exceptions zu verwenden. Die Rückgabe von Fehlercodes oder \texttt{NULL} werten ist verboten. Fehlercodes und \texttt{NULL} Werte bieten keinen Vorteil gegenüber von Exceptions, welche genau für den Ausnahmefall entworfen sind.
In Listing \ref{own:methodnull} ist der Aufruf ein Methodenaufruf zu sehen, der einen \texttt{NULL} wert zurückgibt, in Listing \ref{own:methodexception} anstelle von \texttt{NULL} eine Exception geworfen.
\begin{listing}[H]
\begin{minted}{java}
List<Product> products = getProducts();
if (products == null) {
// handle
}
\end{minted}
\caption{Methodenaufruf mit \texttt{NULL} Rückgabewert}
\label{own:methodnull}
\end{listing}
\begin{listing}[H]
\begin{minted}{java}
try {
List<Product> products = getProducts();
} catch (EmptyResultException exception) {
// handle
}
\end{minted}
\caption{Methodenaufruf mit Exception}
\label{own:methodexception}
\end{listing}
Die Methodenaufrufe ähneln einander zwar, aber im Listing \ref{own:methodexception} wird dem Leser erst deutlich gemacht was passiert. Am Namen der Exception ist klar zu erkennen welche Ausnahme an dieser Stelle behandelt wird, nämlich das es keine Produkte gibt. In Listing \ref{own:methodnull} ist nicht zu erkennen was schief gelaufen ist, sprich weshalb die Methode kein Ergebnis liefert.
\subsection{Magic-Strings and Numbers}
Magic –Strings sind feste Zeichenketten bzw. Zeichen, welche fest in den Quelltext eingebaut sind. Solche Werte werden häufig für bestimmte Zustände verwendet. Listing \ref{own:magicstrings} zeigt einige Beispiele.
\begin{listing}[H]
\begin{minted}{java}
search(searchString, 3);
call("GET", document);
respones(404);
\end{minted}
\caption{Beispiel für Magic-Strings}
\label{own:magicstrings}
\end{listing}
Die Bedeutung der festen Werte wird dem Leser nicht deutlich gemacht. Was bedeutet die \enquote{3} in der \texttt{search} Methode? Es ist nicht ersichtlich welchen Einfluss dieser Wert auf die Ausführung nimmt. Für solche Fälle müssen Konstanten mit entsprechenden Namen erzeugt werden. Dies bietet gleich zwei Vorteile. Erstens wird der konstante wert nur einmal im Quelltext verwendet, an der Stelle an der die Konstante deklariert wird, dadurch lassen sich spätere Änderungen leicht durchführen. Zweitens kann der Leser nun erkennen was an die Methoden übergeben wird und sich ihre Bedeutung erschließen. In Listing \ref{own:magicstringsconst} sind die werte durch Konstanten getauscht.
\begin{listing}[H]
\begin{minted}{java}
search(searchString, SearchParameter.TO_LOWER_CASE);
call(Http.GET, document);
respones(HttpCodes.PAGE_NOT_FOUND);
\end{minted}
\caption{Magic-Strings durch konstanten ersetzen}
\label{own:magicstringsconst}
\end{listing}