Files
michaelschiemer/backups/docs-backup-20250731125004/standards/CODING-GUIDELINES.md
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

5.9 KiB

Coding Guidelines

Allgemeine Prinzipien

Diese Guidelines definieren die Standards für die Entwicklung und Wartung des Projekts. Sie sorgen für Konsistenz, Lesbarkeit und Wartbarkeit des Codes.

PHP-Version

  • PHP 8.4: Die Codebase nutzt stets die neueste stabile PHP-Version (aktuell PHP 8.4)
  • Alle neuen PHP-Sprachfeatures sollten, wo sinnvoll, genutzt werden

Abhängigkeiten

  • Externe Abhängigkeiten vermeiden: Das Projekt soll möglichst ohne externe Bibliotheken auskommen
  • Eigene Implementierungen bevorzugen: Anstatt externe Pakete einzubinden, sollten eigene Lösungen entwickelt werden
  • Erlaubte Abhängigkeiten: Nur die bereits in composer.json definierten Pakete dürfen verwendet werden
  • Neue Abhängigkeiten: Müssen explizit genehmigt werden und sollten nur in Ausnahmefällen hinzugefügt werden

Klassenstruktur

Klassen

  • Alle Klassen müssen final sein, es sei denn, es gibt einen zwingenden Grund für Vererbung
  • Keine abstrakten Klassen - bevorzuge Interfaces und Kompositionen
  • Klassen sollten readonly sein, wann immer möglich
  • Interfaces verwenden, um Verträge zwischen Komponenten zu definieren
// Gut
final readonly class AnalyticsManager
{
    // ...
}

// Vermeiden
abstract class BaseManager
{
    // ...
}

Properties

  • Properties sollten readonly sein, wann immer möglich
  • Private Visibility für alle Properties, es sei denn, es gibt einen zwingenden Grund
  • Typisierung ist obligatorisch für alle Properties
// Gut
private readonly StorageInterface $storage;

// Vermeiden
public array $config;

Methoden und Funktionen

  • Typisierung ist obligatorisch für alle Parameter und Rückgabewerte
  • Methoden sollten klein und fokussiert sein (Single Responsibility)
  • Verwende named arguments für bessere Lesbarkeit
// Gut
public function track(string $event, array $properties = [], ?string $userId = null): void
{
    // ...
}

// Vermeiden
public function process($data)
{
    // ...
}

Dependency Injection

  • Constructor Injection für alle Abhängigkeiten
  • Keine Service Locator oder globale Zustände
  • Verwende das #[Initializer]-Attribut für Service-Registrierung
// Gut
public function __construct(
    private readonly Configuration $config,
    private readonly StorageInterface $storage
) {}

// Vermeiden
public function __construct()
{
    $this->config = Container::get(Configuration::class);
}

Moderne PHP-Features

Nullable Types und Union Types

public function findUser(?int $id): ?User
public function process(int|string $identifier): void

Match Expression statt Switch

// Gut
return match($storageType) {
    'file' => new FileStorage($path),
    'redis' => new RedisStorage($connection),
    default => throw new \InvalidArgumentException("Nicht unterstützter Storage-Typ: {$storageType}")
};

// Vermeiden
switch ($storageType) {
    case 'file':
        return new FileStorage($path);
    // ...
}

Named Arguments

$this->createUser(
    email: 'user@example.com',
    role: 'admin',
    sendWelcomeEmail: true
);

Constructor Property Promotion

public function __construct(
    private readonly Configuration $config,
    private readonly PathProvider $pathProvider
) {}

Fehlerbehandlung

  • Spezifische Exceptions werfen
  • Typed Exceptions verwenden
  • Early Return Pattern bevorzugen
// Gut
if (!$this->isValid()) {
    throw new ValidationException('Ungültige Daten');
}

// Vermeiden
if ($this->isValid()) {
    // Lange Verarbeitung...
} else {
    throw new Exception('Fehler');
}

Testing

  • Tests mit Pest-Framework schreiben
  • Für jede öffentliche Methode sollte mindestens ein Test existieren
  • Mocking nur für externe Abhängigkeiten verwenden
test('track method records events correctly', function () {
    $analytics = new Analytics($manager, $dispatcher);
    $analytics->track('test_event', ['key' => 'value']);

    expect($manager->getEvents())->toHaveCount(1);
});

Dokumentation

  • PHPDoc für alle öffentlichen Methoden und Klassen
  • Typen in PHPDoc sollten den tatsächlichen Typen entsprechen
  • Klare, beschreibende Kommentare für komplexe Logik
/**
 * Zeichnet ein Event auf und wendet Middleware an
 *
 * @param string $event Event-Name
 * @param array $properties Event-Eigenschaften
 * @param string|null $userId Benutzer-ID (optional)
 */
public function track(string $event, array $properties = [], ?string $userId = null): void

Namenskonventionen

  • Klassen: PascalCase (AnalyticsManager)
  • Methoden/Funktionen: camelCase (getEventStats())
  • Variablen: camelCase ($eventData)
  • Konstanten: SNAKE_CASE (MAX_BATCH_SIZE)
  • Dateien: Klassenname.php (AnalyticsManager.php)

Architektur

  • Dependency Inversion Principle befolgen
  • Interfaces für alle externen Abhängigkeiten
  • Vermeide zirkuläre Abhängigkeiten zwischen Modulen
  • Services sollten eine klare, fokussierte Verantwortung haben

Performance

  • Lazy Loading für ressourcenintensive Operationen
  • Caching wo sinnvoll
  • Datenstrukturen sorgfältig auswählen

Security

  • Alle Benutzereingaben validieren und bereinigen
  • Prepared Statements für Datenbankabfragen
  • Vermeidung von eval() und ähnlichen unsicheren Funktionen
  • Sensible Daten niemals in Logs schreiben

Best Practices

  • Immutability: Bevorzuge unveränderliche Objekte
  • Pure Functions: Bevorzuge reine Funktionen ohne Seiteneffekte
  • Enums: Verwende Enums statt String-Konstanten für feste Optionssätze
  • DTOs: Verwende Data Transfer Objects für Datentransport
  • Value Objects: Verwende Value Objects für semantisch reiche Datentypen

Refactoring

  • Code, der diese Guidelines nicht erfüllt, sollte beim Bearbeiten aktualisiert werden
  • Tests müssen vor und nach dem Refactoring bestehen
  • Große Refactorings sollten in kleinen, separaten Commits erfolgen