Hermeneus Coding-Guidelines
Einführung
Zweck des Dokuments
Das Ziel dieses Dokuments ist die Etablierung eines konsistenten und wartbaren Codierungsstandards für das Hermeneus-Projekt, um die Zusammenarbeit zu erleichtern und eine hohe Softwarequalität sicherzustellen.
Allgemeine Projektprinzipien
Projektprinzipien
Orientierung an Standards
Die Hermeneus-Codebasis sollte sich an die allgemein anerkannten Best Practices und Standards der Laravel-Community halten (https://laravel.com/docs/11.x/contributions#coding-style). Zudem sollte bei der Konzeption eines neuen Features eruiert werden, ob es bereits ausgearbeitete Standards gibt, an die sich zu halten, künftig sinnvoll wäre.
Beispiele:
- Hermeneus-Texte sind im sog. TEI-Format enkodiert. Alle Textelemente sind, wo es möglich ist, nach den Regeln der TEI-Guidelines enkodiert (https://tei-c.org/release/doc/tei-p5-doc/en/html/index.html), um das Format innerhalb der Geisteswissenschaften einheitlich zu halten.
- Für die Enkodierung morphologischer Formen nutzt Hermeneus die sog. Perseus-Notation und erweitert diese um weitere Kategorien, wo es nötig ist. Künftige Abgleiche mit anderen APIs oder automatische Transformationen gestalten sich damit einfacher.
Kontinuierliche Verbesserung und Gradual Shift
Code sollte regelmäßig refaktoriert und optimiert werden, um mit aktuellen Best Practices Schritt zu halten. Sollten Standards geändert werden, wird der Code nicht rückwirkend angepasst, sondern nur bei neuen Features oder Refactorings. Dies gilt ebenso für die hier festgelegten Richtlinien.
Beispiele:
- Falls eine neue Komponentenbibliothek hinzugefügt wird, ist es nicht zwingend, alle bisherigen Komponenten zu erneuern. Dies geschieht dann im Falle eins Refactorings.
- Refactorings sollten so oft wie möglich stattfinden, auch wenn dadurch die Software instabiler werden könnte. Die Reduktion von Komplexität und damit einhergehender technischer Schuld verbessert die Wartbarkeit und ist eine Investition in die Zukunft.
Expressivität und Verständlichkeit
Der Code sollte sich möglichst an die natürliche Sprache anlehnen und selbsterklärend sein. Komplexe Programmlogik ist in expressiven Methoden- bzw. Variablennamen enkapsuliert.
Beispiele:
/**
* Policy-Methode, die festlegt, wann ein Nutzer Zugriff auf eine Ressource haben darf.
*/
public function view(User $user, Ressource $resource)
{
return $user->hasRole('editor') ||
$user->hasSubscription() ||
$resource->isPublished();
}Ein Methoden- oder Klassenname mit zu vielen Prä- oder Suffixen zeigt, dass in einer Methode/Klasse zu viele Vorgänge stattfinden (Single Responsibility-Prinzip). Es besteht Refaktorierungsbedarf.
/**
* :FIXME:.
*/
public function createLerneinheitAndSendUserMail($request)
{
//... Code
}Dateiorganisation
Verzeichnisstruktur im Core
Organisiere Dateien entsprechend der Standardstruktur von Laravel:
app/
Http/
Models/
Providers/
config/
database/
resources/Verzeichnisstruktur in Modulen
Bei Modulen wird die Hauptstruktur der Core-Struktur repliziert:
app/
modules/
Uebungen/
NameDesModuls/
app/
Http/
Models/
Providers/
resources/
...Dateinamenkonventionen
- Klassen-Dateien:
PascalCase, z. B.UserService.php. - Laravel-Klassen wie Controller, Middleware, Requests, Jobs, Observer etc. werden im
PascalCasebenannt und mit dem Suffix versehen, z. B.UserController.php,UserRequest.php,UserObserver.php. - Interfaces:
PascalCasemit dem SuffixInterface, z. B.LoggerInterface.php. - Traits:
camelCasemit der Formulierung als Methode, z. B.logsActivity.phpoderhasRoles.php. - Blade-Templates:
snake_case, z. B.user_profile.blade.php. - Blade-Templates als Partials: vorangestellte
__, z. B.__header.blade.php. - Vue-Komponenten:
- SFC:
PascalCase, z. B.Wörterbuch.vue. - Kindkomponenten:
PascalCase, mit entsprechendem Suffix z. B.WörterbuchEintrag.vue,WörterbuchEintragListe.vue.
- SFC:
Maximale Dateigröße
- Dateien sollten wenn möglich nicht mehr als 300 Zeilen umfassen. Falls notwendig, refaktorieren.
Code-Formatierung
Einrückung
Egal ob Tabs oder Leerzeichen, die Einrückung sollte konsistent sein. In Laravel wird eine Einrückung von 4 Leerzeichen verwendet.
Zeilenumbrüche und Klammern
Klassen und Funktionen
class User extends Authenticatable
{
public function profile()
{
return $this->hasOne(Profile::class);
}
protected function validateUser(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
]);
}
}Bedingungen und Schleifen
if ($user->isAdmin()) {
// Code hier
} elseif ($user->isManager()) {
// Code hier
} else {
// Code hier
}
foreach ($users as $user) {
// Code hier
}
while ($active) {
// Code hier
}Leerzeichen
Um Operatoren
// Richtig:
$a = $b + $c;
// Falsch:
$a=$b+$c;Nach Kommas
// Richtig:
array(1, 2, 3);
// Falsch:
array(1,2,3);Bei Funktionsaufrufen
// Richtig:
myFunction($arg1, $arg2);
// Falsch:
myFunction( $arg1 ,$arg2 );Mehrzeilige Methodenaufrufe
// Richtig:
$this->method()
->anotherMethod()
->thirdMethod();
$users = User::select('name', 'email')
->where('active', true)
->orderBy('name')
->get();
// Falsch:
$this->method()->anotherMethod()->thirdMethod();
$users = User::select('name', 'email')->where('active', true)->orderBy('name')->get();Array-Formatierung
// Einzeiliges Array
$names = ['John', 'Jane', 'Joe'];
// Mehrzeiliges Array
$config = [
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
];Type Hints und Return Types
public function calculateTotal(int $quantity, float $price): float
{
return $quantity * $price;
}
public function getUser(string $email): ?User
{
return $this->users->firstWhere('email', $email);
}Klammersetzung
- Verwende den "OTBS"-Stil für Klassen- und Funktionsdefinitionen:
class Example
{
public function showTestFunction() {
// code
}
}Laravel-Namenskonventionen
Die folgende Tabelle zeigt die wichtigsten Namenskonventionen in Laravel-Projekten:
| Typ | Regel | Richtig | Falsch |
|---|---|---|---|
| Controller | singular | ArticleController | ArticlesController |
| Route | plural | articles/1 | article/1 |
| Named route | snake_case mit dot notation | users.show_active | users.show-active, show-active-users |
| Model | singular | User | Users |
| hasOne/belongsTo Beziehung | singular | articleComment | articleComments, article_comment |
| Andere Beziehungen | plural | articleComments | articleComment, article_comments |
| Tabelle | plural | article_comments | article_comment, articleComments |
| Pivot-Tabelle | singular, Modelnamen alphabetisch | article_user | user_article, articles_users |
| Tabellenspalte | snake_case ohne Modelname | meta_title | MetaTitle, article_meta_title |
| Fremdschlüssel | singular Modelname mit _id Suffix | article_id | ArticleId, id, article_articles_id |
| Primärschlüssel | - | id | custom_id |
| Migration | - | 2017_01_01_000000_create_articles_table | 2017_01_01_000000_articles |
| Methode | camelCase | getAllUsers | get_all_users |
| Funktion | snake_case | abort_if | abortIf |
| Methode in Resource Controller | mehr Infos: [table] | store | saveArticle |
| Methode in Testklasse | camelCase | testGuestCannotSeeArticle | test_guest_cannot_see_article |
| Model-Property | snake_case | $model->model_property | $model->modelProperty |
| Variable | camelCase | $anyOtherVariable | $any_other_variable |
| Collection | beschreibend, plural | $activeUsers = User::active()->get() | $active, $data |
| Objekt | beschreibend, singular | $activeUser = User::active()->first() | $users, $obj |
| Config/Language Dateien | snake_case | articles_enabled | ArticlesEnabled, articles-enabled |
| View | kebab-case | show-filtered.blade.php | show_filtered.blade.php |
| Config | kebab-case | google-calendar.php | googleCalendar.php, google_calendar.php |
| Contract (Interface) | Adjektiv oder Nomen | Authenticatable | AuthenticationInterface, IAuthentication |
| Trait | Adjektiv | Notifiable | NotificationTrait |
Best Practices für Laravel-Entwicklung
Domain-Driven Design (DDD)
- Strukturiere den Code nach fachlichen Domänen statt technischen Schichten
- Gruppiere zusammengehörige Funktionalitäten in Module/Bounded Contexts
- Verwende eine ubiquitäre Sprache im Code und in der Dokumentation
Fat Models, Skinny Controllers
- Halte Controller schlank - sie sollten nur HTTP-Requests koordinieren
- Verlagere Business-Logik in die Models oder dedizierte Service-Klassen
- Verwende Eloquent-Relationships statt komplexer Queries in Controllern
Request-Validierung
- Nutze dedizierte Request-Klassen für komplexe Validierungslogik
- Zentralisiere Validierungsregeln in Request-Klassen statt in Controllern
- Verwende type-hinting und Docblocks für bessere IDE-Unterstützung
Service-Layer für Business-Logik
- Lagere komplexe Business-Logik in Service-Klassen aus
- Ein Service sollte eine spezifische Domänenfunktionalität kapseln
- Services können von mehreren Controllern wiederverwendbar genutzt werden
Eloquent Best Practices
- Nutze Eloquent ORM statt Query Builder wo möglich
- Verwende Eager Loading um N+1 Probleme zu vermeiden
- Definiere Relationships und Scopes im Model
- Schütze Models vor Mass Assignment durch
$fillableoder$guarded
Blade Template Best Practices
- Vermeide Datenbankabfragen in Blade Templates
- Nutze View Composer für wiederkehrende Template-Daten
- Verwende Blade Components für wiederverwendbare UI-Elemente
Clean Code Prinzipien
- Schreibe selbsterklärenden Code statt vieler Kommentare
- Halte Methoden kurz und fokussiert (Single Responsibility)
- Verwende aussagekräftige Namen für Variablen, Methoden und Klassen
Performance Best Practices
- Cache häufig genutzte Daten
- Nutze Eager Loading für Relationships
- Verwende Database Indexing für häufige Queries
- Implementiere Queue Jobs für zeitintensive Operationen