-
-
Notifications
You must be signed in to change notification settings - Fork 96
Entwicklung: Programmierrichtlinien
Es wird der Google Java Style genutzt. Für Eclipse und co können entsprechende Einstellungen hier gefunden werden: GitHub - Google Styleguide
Warum der Google-Stil? Nun, er ist einer der wenigen Java-Styles, der nicht nur teilweise, sondern durchgängig (d.h. in ziemlich allen Belangen) definiert wurde. Daneben wurde er auf Lesbarkeit optimiert, und nicht auf althergebrachte Probleme. Tabs haben etwa den Vorteil, individuell einstellbar zu sein und brauchen weniger Platz. Das Problem bei Tabs entsteht aber letztlich bei der Ausrichtung (nicht Einrückung, sondern alles nach dem ersten Zeichen). Daneben ist das Argument, dass ein Tab nur ein Byte einnimmt, heutzutage nicht mehr sehr wesentlich.
Bleibt die Frage, warum mit zwei (2) Spaces eingerückt wird. Die Frage ist einfach zu beantworten: Wesentliche Elemente stehen untereinander.
if (condition) {
doThis();
} else {
doThat();
}
Es wird der Google Java Style genutzt. Das heißt im Wesentlichen:
- Klammern auf gleicher Ebene.
- Einrückung: Zwei Spaces. Keine Tabs.
- Konstanten (
static final
) an den Anfang, in Großbuchstaben. -
null
wird nicht genutzt. - Imports werden alphabetisch sortiert. Ausnahme sind die Projekteigenen Klassen -- die stehen am Anfang.
-
else
ist zu vermeiden. - Es sind nicht mehr als drei Einrückungsebenen zu nutzen (kein zu tiefes verschachteln von
if
/for
/while
etc.).
Folgende Änderungen sind vorzunehmen:
- Special Imports: Hier kommen die Projekteigenen Pakete hin.
- Zeilenlänge: Wird von 100 auf 140 Erweitert.
Zum Thema else: Oft kann man else
vermeiden, indem man etwa mit Preconditions
und/oder frühen if
-Abfragen auf negativ-Bedingungen aus der Methode herausspringt. Der eigentliche Code steht dann wieder auf der Haupt-Einrückungsebene.
Folgende leere Zeilen werden eingefügt:
- Vor einem
return
- Ausnahme: Es ist das einzige Statements eines Blockes (
{ return; }
).
- Ausnahme: Es ist das einzige Statements eines Blockes (
- Vor einem
if
und nach der schließenden Klammer}
. - Genauso bei
for
,catch
undwhile
. - Variablen oder ähnliche Statements können nach Bedarf durch Leerzeilen visuell gruppiert werden.
Alter Code wird im alten Stil belassen, um Pull-Requests und Commits auf das nötigste zu reduzieren.
- Neue Pakete werden unter
de.mediathekview
angelegt. -
msearch
-Pakete unterde.mediathekview.msearch
. -
mserver
-Pakete unterde.mediathekview.mserver
. - etc.
- Das ist für das Logging und für das Veröffentlichen nach Maven von Bedeutung.
- Statt
HTMLDriver
schreibt man nach Google-KonventionHtmlDriver
. StattZDFConnector
entsprechendZdfConnector
.
- Checked exceptions (
extends Exception
) werden nur mit Begründung genutzt. Ansonsten werden unchecked exceptions genutzt (extends RuntimeException
).
Checked Exceptions sollten da benutzt werden, wo man gut darauf reagieren KANN und wo es sinnvoll ist. Etwa, bei einer fehlenden Konfiguration (neue wird erstellt), ggf. HTTP-Timeouts (neuer Versuch, wobei bei Lambdas und
CompletableFuture
das wieder eine unchecked exception wäre).Bei anderen Dingen, die wir dann nicht mehr kontrollieren können, sollten Exceptions aber nicht die Methodensignatur "beschmutzen". Das führt zu unnützen
throws
-Ketten in der call-Hierarchie oder zu unsinnigen Catches (log.debug("Fehler bekannt, aber kann man eh nichts machen.", e);
). Und das sind, wenn man einen solchen Interceptor verwendet, erfahrungsgemäß die meisten Situationen.
- In einer Methode geworfene
RuntimeException
s werden nicht deklariert, nur dokumentiert per JavaDoc. - Die Exceptions
RuntimeException
,Error
undThrowable
werden nicht gefangen, da sonst auchOutOfMemory
etc. gefangen werden könnten. Legacy-Code ist gesondert zu kennzeichnen. - Wird die Exception gefangen und weitergeworfen, muss als Parameter der neuen Exception auch die alte Exception mitgegeben werden. Ein "vergessen" der History ist nicht erlaubt.
- Wird die Exception nicht weitergeworfen, so ist ein Logging erforderlich (s.u.).
- Literatur:
- http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/
- https://testing.googleblog.com/2009/09/checked-exceptions-i-love-you-but-you.html
Mit Java 8 sind Lambdas und co gekommen wodurch es möglich ist einige dinge zu verkürzen und zu beschleunigen. Diese Möglichkeit der funktionalen Entwicklung sollte auch für genau das genutzt werden. Beschleunigung und Verkürzung. Z.B. zum schnellen und kurzen sortieren einer Liste. Größere Aufgaben sollten nicht funktional umgesetzt werden da dies u.a. die Lesbarkeit drastisch verschlechter. Also kein aufruf von komplexen Methoden o.ä. innerhalb von Lambdas und co.
- Eine Methode gibt niemals
null
zurück. Ausnahmen sind alter Code. - Besondere Fälle müssen mit
@Nullable
annotiert werden. Javadoc ist dazu erforderlich. - Im Zweifel ist zu Prüfen, ob
Optional
oder eine eigene Klasse mit einem "leeren" Status besser geeignet ist. - Gibt eine Methode eine
Collection
zurück, darf ebenfalls niemalsnull
zurückgegeben werden. Bei keinen Ergebnissen gibt es eine leere Liste, bei Fehlern eine abgeleiteteRuntimeException
. - Parameter sollten nicht
null
able sein. Ausnahmen werden gekennzeichnet. - Jede Methode sollte etwa mit Google Guava o.ä. mittels
Preconditions.checkNotNull()
den Status einer Variable prüfen. - Optional ist nicht
Serializable
. Als Feld kann es also mitunter nicht genutzt werden. Stattdessen sollten dann ggf. eigene Klassen verwendet werden. - Literatur:
- https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
- https://dzone.com/articles/java-8-optional-avoid-null-and
- Lombok oder Immutables?
Die Kommentarsprache ist Deutsch|Englisch [TBD].
- An jeder public-Methode steht Javadoc.
- An
@Override
-Methoden steht kein Javadoc. Auch kein IDE-Generiertes@see
oderinheritdoc
, und erst recht keinnon-javadoc
. - Parameter werden beschrieben.
-
RuntimeException
s, die in genau dieser Methode geworfen werden, werden an Javadoc annotiert, aber nicht deklariert.
Es werden Findbugs, findbugs-contrib und Findbugs-Security genutzt. Es werden alle Analysen eingeschaltet, mit Ausnahmen von:
- CRLF Injection
- Es werden keine Controversial-Prüfungen eingeschaltet.
- Wird eine Exception nicht weitergeworfen, muss sie geloggt werden.
- Ist absolut ausgeschlossen, dass der Block nicht erreicht wird, loggt man im Level Trace.
- Der Logger wird immer so definiert:
private static final Logger LOG = LoggerFactory.getLogger(Class.class);
. - Das Logging-Framework ist Log4J
Für jeden gelösten Issue sollte ein JUnit-Test existieren.