Entwicklerrichtlinien/Styleguide
Diese Seite ist momentan eine Baustelle im Zustand: 1
-
0
-
1
-
2
-
3
-
4
Leben mit Debian: Die Entwickler Richtlinien
Alles was programmiert wird, soll sich an diese Richtlinien halten. Einige Dinge wie die Paketerstellung & -verwaltung, sowie die Konfiguration des Installers müssen sich auch an die "Debian Policy" halten.
Styleguide
Für das einheitliche Aussehen aller delixs-Werkzeuge, folgend "Admin-Interface" genannt, wird ein Styleguide erstellt.
Warum ein Styleguide?
Es handelt sich bei Quellcodes nach heute herrschender Meinung um technische Produkte und nicht um künstlerische Artefakte. Daher sind 'abgefahrene' und individuelle Formatierungen fehl am Platze. Es ist erwünscht, dass man bei den Quelltexten von mehreren Software-Entwicklern in einem Team nicht unterscheiden kann, wer welchen Code verfasst hat.
Es gibt eine weitere Argumentation, warum man soviel Wind um einen guten Stil macht. Das Boehm's Gesetz sagt, dass die Wartungskosten im Schnitt viermal größer sind als die Erstellungskosten. Das bedeutet, dass es sehr sinnvoll ist, den Code in Hinsicht Lesbarkeit zu optimieren.
Noch besser ist es, wenn in Hinsicht Verständlichkeit optimiert wird. Bitte immer vergegenwärtigen: einfach zu lesen und einfach zu verstehen ist nicht unbedingt das Gleiche.
Deshalb wurden für alle (Perl-)Scripte, die für dieses Projekt erstellt werden, die folgenden Festlegungen getroffen. Diese orientieren sich an der "Bibel für Perlprogrammierer", dem Buch "Perl Best Practices" von Damian Conway. Es geht hier nur darum, das der Quelltext auch von verschiedenen Programmierern wie "aus einen Guss" erscheint und damit hoffentlich gleich gut zu lesen ist. Es geht hier nicht darum, bestimmte Lösungen, auch wenn sie besser sind, zu propagieren oder/und durchzusetzen. Das Anliegen dieses Styleguides ist es nicht, Kenntnisse bzw. Tipps und Tricks zu vermitteln. Es wird deshalb auch nur ein ganz kleines Subset der Regeln dieses Buches hier herangezogen und auf Änderungen im Vergleich zu den dort angegebenen Regeln wird explizit hingewiesen. (Es ist damit kaum sinnvoll möglich, das bekannte Testmodul "Perl::Critic" einzusetzen.) In Hinblick auf die Kommentierung wird davon ausgegangen, dass eine typische Perldoc-Dokumentation erstellt wird, die aber debian-typisch als Man-Page bereitgestellt wird.
Codelayout
Klammerung
wir klammern generell im K&R-Stil:
my @names = ( 'schoffer', 'flesch', 'kirmse' )
oder
foreach my $zeile (@zeilen) { if ($zeile ne ) { print $zeile; } }
Schlüsselwörter
Schlüsselwörter bei Kontrollstrukturen sollen klar erkennbar sein und nicht fälschlich als Funktionsaufrufe interpretiert werden können. Zwischen Schlüsselwörtern und den Klammern schreiben Sie unbedingt Leerzeichen wie in den zwei gerade angegebenen Beispielen.
Im Gegensatz dazu: bei Unterroutinen und Variablennamen schreiben Sie die Klammern direkt hinter diese Bezeichner.
my $password = &get_password($datei);
oder
my $element = $hash[2]{$nummer};
Operatoren
Nutzen Sie (ein) Leerzeichen, um binäre Operatoren von den Operanden abzuheben.
my $tage = time / 3600 / 24;
Einrückung
Verwenden Sie 2 Leerzeichen für eine Einrückungsebene Anm.: Conway - 4 Leerzeichen
while ($zeile = <DATEI>) { if ($zeile ne ) { ($erstes_element) = split ',', $zeile; print $erstes_element, "\n"; } }
Blöcke
Geben Sie niemals 2 Anweisungen in der gleichen Zeile ein
if ($a > $b) { # tauschen von $a und $b $c = $b; $b = $a; $a = $c; }
Else-Konstrukte
"Herzen" Sie das else
nicht. Das bedeutet, das Folgendes NICHT in einer Zeile stehen soll:
} else {
sondern schreiben Sie es wie in dem folgenden Beispiel:
if ($a > $b) { print "$a ist größer als $b \n"; } else { print "$a ist nicht größer als $b \n"; }
Namenskonventionen
Namen für Variablen
folgende Bildungsvorschrift liefert verständliche Bezeichner:
variable -> [adjektiv_]* substantiv
Beispiele: $naechster_client, $letzter_zeitpunkt, $aktueller_aufruf
Ein besonderer Fall sind Hashs und Arrays für Lookup-Tabellen. Hier ist folgende Bildungsvorschrift zu empfehlen:
lookup_variable -> [adjektiv_]* nomen präposition
Beispiele: %titel_von, %ISBN_fuer
Das liest sich dann im Quelltext so:
foreach my $buch (@katalog) { print "Buch: $titel_von{$buch} - ISBN: $ISBN_fuer{$buch} \n"; }
Namen für Subroutinen und Methoden
Vorschlag für Bildungvorschrift
routine -> imperatives_verb [_adjektiv]? _nomen
Beispiele: &lies_datensatz, &generiere_profil, &schreibe_aktuellen_zaehler
Boolsche Variablen bzw. Routinen
Diese Variablen und Routinen sollten (als Sonderfall) nach ihren Test benannt werden.
Beispiele: &ist_gueltig, $hat_fehlerhaften_datensatz_gefunden
if (&ist_gueltig($naechster_datensatz)) { # ... } else { $hat_fehlerhaften_datensatz_gefunden = 1; }
Referenzvariablen
Um sofort erkennen zu können, dass eine skalare Variable eine Referenz ist, sollte das Kürzel _ref angehangen werden.
$opts_ref, $user_ref ...
sub demo { my $parameter_ref = shift; my %parameter = %{$parameter_ref}; # ... }
Hashs und Arrays
Benennen Sie (normalerweise) Hashs in der Einzahl und Arrays in der Mehrzahl. Bei Hash ist es häufig noch besser lesar, wenn dem singulären Nomen eine Präposition folgt.
Beispiele: %titel, %titel_von, %option, @ereignisse, @pcs ...
Unterstriche
Im Englischen werden Namen, die aus mehreren Wörtern bestehen, durch Bindestiche oder durch Leerzeichen "verbunden". z.B. "input stream", "double-click"
Da dies in Perl keine gültigen Bezeichner ergibt, ist nächstbeste Alternative der Unterstrich, wie sie in den vorangegangenen Beispielen verwendet wurden.
Die AlternativeMitEingestreutenGrossbuchstaben
ist nicht so gut lesbar.
Gross- bzw. Kleinschreibung
Verwenden Sie
- verwenden Sie nur Kleinbuchstaben für Variablen, Subroutinen und Methoden.
- verwenden Sie die gemischte Gross- und Kleinschreibweise für Namen von Paketen und Klassen (z.B. Delixs::LDAP)
- Verwenden Sie Grossbuchstaben für Filehandle und Konstanten (z.B. DATEI, MAX_ANZAHL, LEERZEICHEN)
Utility-Routinen
Stellen Sie Routinen, die nur für den internen Gebrauch bestimmt sind, einen Unterstrich voran
Beispiel: &_finde_groesste_uid
Da diese Hilfsfunktion nicht exportiert wird (besser: werden sollte), fällt der Bezeichner mit den Unterstrich am Anfang im Hauptprogramm doch hoffentlich auf. ;)
Konstanten
Verwenden Sie benannte Konstanten. Schreiben Sie diese mit Großbuchstaben.
use strict; use constant LEERSTRING => ; my $string = LEERSTRING;
HERE-Dokumente
Verwenden Sie HERE-dokumente, wenn Ihre Strings länger als 2 Zeilen sind. Verwenden Sie Quotingzeichen, wenn Sie Ihre HERE-Dokumente einleiten.
my $name =<< 'ENDE'; (c) Hans-Dietrich Kirmse <hd.kirmse@gmx.de>, 2008 Erasmus-Reinhold-Gymnasium Saalfeld, Thüringen ENDE
Kontrollstrukturen
If-Blöcke
Vermeiden Sie die Verwendung von Postfix-if. Die Lesbarkeit ist so viel besser! (Ausnahmen siehe "Perl Best Practices")
richtig:
if ($zensur == 1) { print "super \n"; }
falsch:
print "super \n" if $zensur == 1;
andere Postfix-Modifikationen
Verwenden Sie niemals Postfix-Varianten von unless, for, while oder until.
richtig:
my $a = 1; while ($a < 10) { print $a, "\n"; $a++; }
Iteratorvariablen
Verwenden Sie bei Schleifen benannte Iteratoren, nicht $_
Deklarieren Sie eine Iterator-Variable immer mit my
.
do/while-Schleifen
Verwenden Sie keine do ... while
-Schleife
Neben der Tatsache, dass die sich schlecht liest, ist es keine Schleife erster Klasse. Das bedeutet, in dieser Schleife können Sie nicht next, last oder redo verwenden. (jedenfalls verhalten die sich nicht so, wie Sie es erwarten!)
Kommentare
Subroutinen
Geben Sie vor jeder Subroutine mindestens den Zweck (Funktion) und den Aufruf an.
# Funktion: diese Subroutine bestimmt das Maximum zweier Zahlen # Aufruf: $groesste_zahl = &max(100, 75); sub max { my ($zahl1, $zahl2) = @_; if ($zahl1 > $zahl2) { return $zahl1; } else { return $zahl2; } }
Absätze
Verwenden Sie ganzzeilige Kommentare, um einen Abschnitt zu erklären. Geht ein Abschnitt nicht mit einem ganzzeiligen Kommentar zu erklären, dann ist das ein Hinweis darauf, dass in mehrere Abschnitte aufgetreilt werden sollte.
# Funktion: diese Subroutine bestimmt den größten gemeinsamen Teiler zweier Zahlen # Aufruf: $teiler = &ggt(100, 75); sub ggt { my ($zahl1, $zahl2) = @_; my $hilf; # wiederhole solange, bis die Differenz der beiden Zahlen 0 ist while ($zahl1 - $zahl2 == 0) { # die erste zahl muss die größere sein, sonst tauschen if ($zahl1 < $zahl2) { $hilf = $zahl1; $zahl1 = $zahl2; $zahl2 = $hilf; } # wir bilden die Differenz $differenz = $zahl1 - $zahl2; # wir streichen die größte Zahl $zahl1 = $zahl2; $zahl2 = $differenz; } return $zahl1 }
Erläuterungen zu einer Zeile
Kommentieren Sie alles, was Sie verwirrtt oder getäuscht hat. Erläutern sie alles, was Sie entweder im Handbuch nachschlagen müssen oder über das Sie mehr als 5 Sekunden bei lesen nachdenken mussten.
$zahl = oct $zahl; # aus 'octal' nicht nach 'octal'
Anm.: viele gehen davon aus, dass oct
eine zahl ins Oktalsystem wandelt. Es ist aber genau anders herum.
technische Dokumentation
Wenn man für das Verstehen des folgenden Codes das Konzept erklären will, dann ist es unschön, einen Block von viele Kommentarzeilen zu verwenden. Verwenden Sie stattdessen ein POD-Block für einen Formatierer, den es nicht gibt ;)
=for Konzept: den ggt mit Hilfe des EUKLIDschen Algorithmus zu bestimmen ist algorithmisch deutlich einfacher als über die Primfaktorzerlegung. Der Nachteil ist, dass er in der Schule häufig nicht erklärt wird. =cut
Beachten Sie, dass bei dieser Art der Formatierung nur ein Absatz in dem =for .. =cut-Block sein darf!
Qualitätssicherung
Wenn sie ihr Script bzw. ihre Lösung dem delixs-Projekt zur Verfügung stellen wollen, dann muss es wegen der langfristigen Sicherung des Supports bestimmten Ansprüchen genügen. Diese Qualitätsansprüche werden im Folgenden angegeben:
- Passworte, Hostnamen, IP-Adressen oder kurz: sämtliche variablen Daten sind nie im Script direkt anzugeben, sondern sollten immer aus der jeweiligen Datei (Beispiel: "ldap.secret") eingelesen werden.
- da jede Schule eine andere Suchbasis (hier LDAP-Base genannt) hat, sollte das Script diese aus der /etc/ldap.conf auslesen. Das kann so geschehen:
# wir holen uns die Such-Basis ($ldap_base) aus der ldap.conf open DATEI, '<', '/etc/ldap.conf' or die "konnte ldap.conf nicht oeffnen, $!\n"; while (my $zeile = <DATEI>) { if ($zeile =~ m/^\s*base\s+(\w.*\w)\s*$/) { $ldap_base = $1; last; } } close DATEI;
Kirmse 2008