Angular Code Review Checkliste: Alle Schritte inbegriffen

Wir alle sind bestrebt, qualitativ hochwertige, wartbare und sichere Anwendungen zu entwickeln. Ganz gleich, ob Sie eine funktionsreiche Version vorbereiten oder Ihr Produkt für ein breiteres Publikum skalieren, gründliche Angular-Code-Reviews sind entscheidend. Und warum? Weil sie dabei helfen, verborgene Probleme aufzudecken, einen einheitlichen Code-Stil beizubehalten und Ihren Entwicklungsfluss auf Kurs zu halten.

Dieser Artikel befasst sich mit dem Thema:

Warum Code Review für Angular wichtig ist

Angular verfügt über eine modulare Struktur, die auf TypeScript basiert, wodurch viele der Probleme, die bei normalem JavaScript auftreten, bereits beseitigt sind. Aber auch mit dieser zusätzlichen Hilfe können Sie Code-Reviews nicht auslassen. Ein verirrtes “any”, eine übersehene Sicherheitslücke oder eine ungeschickte Architektur können große Probleme verursachen. Eine gründliche Überprüfung wird Ihnen helfen:

  • Halten Sie Ihren Code konsistent und übersichtlich
  • Erkennen Sie Leistungseinbußen, bevor sie Ihre Serverrechnung in die Höhe treiben
  • Verschärfung der Sicherheit, insbesondere bei nutzergenerierten Eingaben
  • Förderung eines vorhersehbaren Daten- und Logikflusses

Wenn Sie noch mehr Tipps suchen, warum Code-Reviews wichtig sind, sollten Sie sich unsere anderen Checklisten für Python, JavaScript und Sicherheit ansehen.

Klare Projektarchitektur

Ein gut strukturiertes Angular-Projekt führt zu weniger Merge-Konflikten und einem reibungsloseren Einstieg für neue Entwickler. Durch die Aufteilung von Funktionen in Module, die Entscheidung, welche davon nur langsam geladen werden, und die Beibehaltung logischer Dateinamen schaffen Sie die Voraussetzungen für einfache Wartung und Skalierbarkeit.

Funktionsmodule:

  • Gruppieren Sie verwandte Funktionen in speziellen Funktionsmodulen, um eine Aufblähung Ihres Hauptmoduls zu vermeiden und Ihren Code auffindbar zu halten.
  • Verwendung gemeinsamer Module für Richtlinien und Komponenten, die von mehreren Funktionen benötigt werden

Überwachen Sie Ihre Routing-Konfigurationen, um zu sehen, wo “Lazy Loading” die Leistung steigern kann.

// Naive routing: everything is loaded at once, which makes the final bundle bigger
const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent },
  { path: 'profile', component: ProfileComponent },
  // ...
];

// With lazy loading, only fetch modules on demand
const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module')
      .then(m => m.DashboardModule)
  },
  {
    path: 'profile',
    loadChildren: () => import('./profile/profile.module')
      .then(m => m.ProfileModule)
  }
];

Logische Ordnerorganisation:

  • Geben Sie jedem Ordner einen eindeutigen Zweck (Komponenten, Dienste, Leitungen usw.), um zu vermeiden, dass Dateien an beliebigen Orten vergraben werden.
  • Benennen Sie Ordner entsprechend ihrer Funktionalität (z. B. Benutzer, Produkte, Berichte) und nicht mit abstrakten Begriffen wie “Sonstiges” oder “Allgemein“.

Richtige Versionierung und CI/CD:

  • Markieren Sie Veröffentlichungen in Git und automatisieren Sie Ihre Build-Prüfungen. Dadurch wird sichergestellt, dass neuer Code korrekt zusammengeführt wird und dass alle architektonischen Änderungen frühzeitig getestet werden
  • Identifizieren Sie potenzielle Konflikte schnell mit einer einfachen CI-Pipeline, die ng build –prod zusammen mit Lint-Prüfungen ausführt

Konsistente Kodierungskonventionen

Styling-Regeln mögen zunächst kosmetisch erscheinen, aber ein konsistenter Stil steigert die Produktivität. Tools wie Angular ESLint und Prettier automatisieren den Großteil der Arbeit, während ein Standard-Namensschema Ihre App einheitlich hält.

Vereinheitlichte Lint- und Formatregeln:

  • Einigung auf einen Style Guide (z. B. Angular Style Guide), damit die Entwickler keine Zeit mit kosmetischen Änderungen verschwenden
  • Automatisieren Sie Korrekturen mit Prettier oder ESLint. Sie können sie sogar als Pre-Commit-Hook ausführen, um das Repo sauber zu halten. Sehen Sie sich dieses kurze Beispiel für die ESLint-Konfiguration an, die leicht mit Dutzenden von Plugins und benutzerdefinierten Regeln erweitert werden kann:
{
  "root": true,
  "overrides": [
    {
      "files": [
        "*.ts"
      ],
      "parserOptions": {
        "project": [
          "tsconfig.json",
          "e2e/tsconfig.json"
        ],
        "createDefaultProgram": true
      },
      // Can add ready-to-go config of Airbnb or others styleguides
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],
      "rules": {
        // ...
      }
  }]
}

Bedeutungsvolle Namen:

  • Verwenden Sie beschreibende Variablen- und Funktionsnamen und vermeiden Sie kurze Platzhalter wie val oder tmp.Angular bevorzugt Klarheit
  • Wenden Sie eine konsistente Namensgebung für Klassen, Dateien und Verzeichnisse an. Zum Beispiel signalisiert user-profile.component.ts oder auth.service.ts besser die Absicht als data.component.ts oder logic.service.ts

Lesbare Funktionen:

  • Halten Sie die Methoden kurz und zielgerichtet. Wenn Sie mehrere Aufgaben in einer Funktion bewältigen, unterteilen Sie sie in logische Teile
  • Das Gleiche gilt für ganze Klassen – wenn ein Dienst anfängt, auch als Hilfsbibliothek zu fungieren, ist es an der Zeit, ihn aufzuteilen

Strikte Typisierung und TypeScript-Verwendung

Eine der Stärken von Angular ist TypeScript, das Fehler frühzeitig erkennt und den Datenfluss explizit macht. Die übermäßige Verwendung von “any” hebt diese Vorteile auf und macht die Fehlersuche zu einem Ratespiel.

Nutzung von Schnittstellen:

  • Definieren Sie Datenstrukturen, damit Sie genau wissen, was in und aus Ihren Funktionen kommt
  • Wenn Sie Benutzerinformationen zurückgeben, erstellen Sie eine Benutzeroberfläche dafür

Hier ist ein kurzes Beispiel dafür, wie die Eingabe ohne richtige Definition schief geht:

// Bad practice: using `any` everywhere, there is spelling error, which is not catched
function submitForm(event: any): any {
  event.preventDefaulr(); // runtime error!
  // ...
  return fetch(`https://api.example.com/users/${id}`)
    .then(res => res.json());
}


// Good practice: using interfaces gives ability to avoid common errors and easily access properties
function submitForm(event: MouseEvent | Keyboard): any {
  event.preventDefault();
  const isShiftKeyPressed = event.shiftKey;
  // ...
  return fetch(`https://api.example.com/users/${id}`)
    .then(res => res.json());
}

Strenger Modus verwenden:

  • Aktivieren Sie “strict” in Ihrer tsconfig.json, um das Erkennen von subtilen Tippfehlern zu erleichtern. Dies ist einer der schnellsten Wege, um die Zuverlässigkeit Ihres Codes zu erhöhen

Generika, wo dies angebracht ist:

  • Verwenden Sie generische Klassen oder Methoden nur, wenn es notwendig ist; vermeiden Sie überkomplizierte einfache Typen
// Bad practice: Not constraining generics 
class BadDataService {
    process(data: T): T {
        return data; // No type safety or validation
    }
}

// Good practice: Using type inference and constraints
function transformAndValidate>(
    input: T,
    transform: (data: T) => R,
    validator: (data: R) => boolean
): R | null {
    const transformed = transform(input);
    return validator(transformed) ? transformed : null;
}

Schlanke Komponenten und Vorlagen

Die komponentenbasierte Struktur von Angular macht es einfach, Ihre Benutzeroberfläche aufzuteilen, aber große Komponenten können trotzdem schwerfällig werden. Verteilen Sie Geschäftslogik in Dienste und bereinigen Sie Vorlagen von schweren Schleifen oder Berechnungen.

Lifecycle Hooks richtig gemacht:

  • Implementieren Sie nur die Haken, die Sie wirklich benötigen. Ungenutzte Hooks sorgen für Unordnung und Verwirrung. Melden Sie sich zum Beispiel von Observables in ngOnDestroy() ab, wenn Sie manuell abonnieren
  • Vergessen Sie nicht, die richtige Schnittstelle in Komponente zu verwenden

Logik der Schablone begrenzen:

  • Eine Vorlage, die mit verschachtelten Schleifen und Bedingungen überfrachtet ist, ist schwer zu debuggen. Um dieses Problem zu lösen, verschieben Sie wiederholte Transformationen in eine Pipe oder Methode in der Komponentenklasse
  • Halten Sie Ihr HTML lesbar, indem Sie Angular-Direktiven wie ngIf und ngFor klug einsetzen.

Refactor Overgrown Components:

  • Wenn ein einzelnes Bauteil auf Hunderte von Zeilen angewachsen ist, ist es an der Zeit, es aufzuteilen
  • Um Ihre Hauptkomponente zu fokussieren, verlagern Sie die Datenverarbeitung in einen Dienst oder eine Unterkomponente

Effektive Dependency Injection

Dependency Injection ist ein Markenzeichen von Angular, aber es ist leicht zu missbrauchen. Zu viele Provider auf der Root-Ebene blähen Ihre App auf, und Singletons können versteckte Nebeneffekte verursachen, wenn sie sich unerwartet im Speicherzustand befinden.

Umfang der Dienstleistung:

  • Stellen Sie einen Dienst nur dann im Root-Bereich bereit, wenn Sie sicher sind, dass er in der gesamten Anwendung verwendet wird. Auch Singletons sind großartig für die Optimierung, da sie in die Baumstruktur einbezogen werden (vergessen Sie nicht, alle direkten Links zu Singleton zu entfernen)
  • Andernfalls deklarieren Sie ihn in einem bestimmten Modul, um die Reichweite zu begrenzen. Dieser Ansatz verhindert auch ungewollte Singletons, wenn Sie nur lokalisierte Dienstinstanzen benötigen

Vermeiden Sie Mülldeponien:

  • Halten Sie Dienste zweckmäßig – kombinieren Sie keine zufälligen Dienstprogramme oder unverbundene Logik in einem einzigen Dienst.
  • Organisieren Sie den Code nach Funktionen – Authentifizierung, Benutzerprofile, Analysen usw.

Staatliches Management:

  • Verwenden Sie einen Dienst zum Speichern des globalen Status nur nach sorgfältiger Überlegung
  • Führen Sie eine formale Zustandsverwaltungsbibliothek wie NgRx für größere Anwendungen ein; sie ist berechenbarer und testfreundlicher

Zustandsverwaltung und Datenfluss

Datenflussmuster können über Ihr Angular-Projekt entscheiden. Selbst wenn Ihre Anwendung jetzt noch klein ist, könnte eine inkonsistente Datenverarbeitung später zu einem umfangreichen Refactoring führen.

Vorhersehbare Muster:

  • Wählen Sie einen Ansatz für die Zustandsverwaltung – NgRx, verhaltensbezogene Muster oder einen einfacheren Store-Service-Ansatz – und bleiben Sie dabei
  • Wechseln Sie nicht mitten im Projekt das Muster, da dies zu Verwirrung führt.

Unveränderliche Updates:

  • Halten Sie Daten unveränderlich. Vermeiden Sie die Mutation von Arrays oder Objekten an Ort und Stelle, um seltsame Probleme mit der Änderungserkennung von Angular zu vermeiden.
  • Neue Objekte erstellen, statt bestehende zu verändern
// Bad practice
export class ListComponent {
  @Input() list: Todo[] = [];

  // Bad: Directly mutating input array
  toggleListCompletion(item: ListItem): void {
    todo.completed = !todo.completed; // Change detection might miss this!
  }
}


// Good practice
export class ListComponent {
  @Input() list: ListItem[] = [];
  @Output() listChange = new EventEmitter();

  // Good: Creating new array with modified item
  onToggleListItem(listItem: ListItem): void {
    const updatedList = this.list.map(item => 
      item.id === listItem.id 
        ? { ...item, completed: !item.completed }
        : item
    );
    this.listChange.emit(updatedList);
  }
}

Abonnements Housekeeping:

  • Verwenden Sie wann immer möglich asynchrone Pipes in Templates, damit Angular die Abonnement-Lebenszyklen für Sie übernimmt.
  • Wenn Sie manuell abonnieren, denken Sie daran, sich in ngOnDestroy() abzumelden

Optimierung der Leistung

Niemand mag eine träge App. Die in Angular integrierten Optimierungen helfen, aber Sie können noch mehr tun, um die Ladezeiten zu verkürzen und die Benutzeroberfläche reaktionsfähig zu halten.

Fließendes Laden:

  • Laden Sie nicht alle Funktionen im Voraus: Dies verzögert die erste Erfahrung.
  • Laden Sie Ihre Module nach und nach, damit die Nutzer nur das abrufen, was sie brauchen. Verwenden Sie außerdem eine benutzerdefinierte Preload-Strategie, um das Benutzererlebnis noch weiter zu verbessern

Sehen Sie sich diesen Ausschnitt aus einer großen Anwendung an, die eine benutzerdefinierte Preload-Strategie implementiert hat, um die anfängliche Ladezeit mit der Navigationsgeschwindigkeit in Einklang zu bringen:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes, PreloadAllModules } from '@angular/router';

const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module')
      .then(m => m.DashboardModule),
    data: { expectedRole: 'manager' }
  },
  {
    path: 'settings',
    loadChildren: () => import('./settings/settings.module')
      .then(m => m.SettingsModule),
    data: { expectedRole: 'superuser' }
  },
  // ...
];

// Custom preloading strategy which checks user role 
import { Injectable } from '@angular/core';
import { PreloadStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
Import { RolesManagementService} from 'services/roles-management.service';

@Injectable({ providedIn: 'root' })
export class CustomPreloadStrategy implements PreloadStrategy{

  constructor(
    private rolesManager: RolesManagementService
  ) {}

  preload(route: Route, load: () => Observable): Observable {
    return this.rolesManager.hasRole(route.data.expectedRole).pipe(
        switchMap(hasRole => hasRole ? load() : of(null)),
      );
  }
}

OnPush-Erkennung:

  • Verwenden Sie ChangeDetectionStrategy.OnPush für Komponenten, die auf unveränderlichen Daten und Observablen beruhen, um unnötige Überprüfungen zu vermeiden, insbesondere bei großen komplexen Komponenten (Tabellen, Formulare) und Datenaktualisierungen in Echtzeit.
  • Erstellen Sie ein Profil Ihrer Anwendung, um zu überprüfen, ob OnPush wirklich die Anzahl der Wiederholungen reduziert, und heben Sie die Komponenten hervor, die am meisten von OnPush profitieren.

Abhängigkeiten trimmen:

  • Überprüfen Sie package.json regelmäßig, um große Bibliotheken zu identifizieren, die Sie nicht benötigen. Selbst eine einzige große Bibliothek kann die Größe Ihres Pakets in die Höhe treiben
  • Entfernen oder ersetzen Sie Abhängigkeiten, die nur selten verwendet werden (oder mit nativen Methoden repliziert werden können), um Ihren Build kleiner und effizienter zu halten

Sicherheitsprinzipien

Angular bietet integrierte Schutzmechanismen wie die DOM-Sanitization, aber Sie müssen Ihre App dennoch auf potenzielle Bedrohungen überprüfen. Das Ignorieren der Benutzereingabevalidierung oder das Protokollieren sensibler Informationen kann zu Datenschutzverletzungen führen.

Verhindern Sie XSS-Angriffe:

  • Verwenden Sie die Standard-Sanitization von Angular für URLs, HTML und Styles. Umgehen Sie diese nicht, wenn Sie nicht genau wissen, warum
  • Vermeiden Sie direkte innerHTML- oder bypassSecurityTrustHtml-Aufrufe, wenn Sie nicht absolut sicher sind, dass die Daten sicher sind.

Versteckte Berechtigungsnachweise:

  • Bewahren Sie niemals API-Schlüssel oder private Token in Ihrem Quellcode auf.
  • Überprüfen Sie Umgebungsdateien, Konsolenprotokolle und Debug-Anweisungen auf undichte Stellen.

Abhängigkeits-Scans:

  • Überwachen und aktualisieren Sie veraltete Pakete von Drittanbietern; sie können Ihre gesamte Anwendung gefährden
  • Tools wie npm audit oder SonarQube zeigen Schwachstellen auf, damit Sie sie frühzeitig beheben können
  • Integrieren Sie automatisierte Prüfungen in Ihre CI/CD-Pipeline und blockieren Sie Zusammenführungen, wenn kritische Schwachstellen auftreten.

Umfassende Prüfung

Eine robuste Testsuite fängt Regressionen ab, bevor sie die Produktion erreichen. Decken Sie Ihre Komponenten, Dienste und Routing-Logik ab und konzentrieren Sie sich zunächst auf kritische Pfade.

Einheitstests:

  • Verwendung von Angulars TestBed für Komponenten, mit Schwerpunkt auf deren Interaktion mit Diensten und Benutzereingaben
  • Testen Sie bei Diensten jede Methode gründlich, indem Sie Netzwerkaufrufe oder externe Abhängigkeiten simulieren, um die Logik zu isolieren.

Integration und E2E-Tests:

  • Verwendung von Frameworks wie Cypress oder Protractor (wobei der Wartungsmodus von Protractor zu beachten ist), um reale Benutzerströme zu simulieren und sicherzustellen, dass alles zusammen funktioniert
  • Schreiben Sie Tests für die wichtigsten User Journeys, z. B. für die Anmeldung, den Checkout und die Profilverwaltung, um Probleme aufzudecken, die in isolierten Unit-Tests möglicherweise nicht auftauchen.

Sinnvolle Abdeckung:

  • Ein Abdeckungsgrad ist nur eine Zahl. Sie müssen immer noch überprüfen, ob Ihre Tests tatsächlich das Verhalten überprüfen und nicht nur Codezeilen weitergeben
  • Setzen Sie auf Qualität statt Quantität. Es ist besser, weniger, dafür aber aussagekräftige Tests zu haben, die kritische Logik und Randfälle abdecken, als eine große Anzahl oberflächlicher Tests, die nur die Abdeckungsstatistiken aufblähen

Ihr Angular-Partner: Entwicklung & Audit Services

Wir nutzen Angular seit seinen Anfängen und liefern maßgeschneiderte Lösungen für technologieorientierte Unternehmen weltweit.

Im Fall unseres Kunden C!A haben wir Angular verwendet, um ein robustes Front-End für die Web-App Current zu entwickeln. Current ist ein System zur Erbringung öffentlicher Dienstleistungen, das von Regierungsbeamten in mehr als 10 US-Bundesstaaten und -Grafschaften genutzt wird, um landesweit Tausende von Serviceanfragen zu bearbeiten. Wenn Sie mehr erfahren möchten, werfen Sie einen Blick auf die Fallstudie.

Unsere Arbeit mit CDP Blitz bestand darin, komplexe Logik in schlanke Komponenten und Dienste umzuwandeln, die Stabilität zu erhöhen, die Seitenladezeiten zu verkürzen und versteckte Engpässe frühzeitig zu erkennen.

Bei PageFreezer, einer digitalen Archivierungs- und Compliance-Lösung, halfen wir bei der Integration einer erweiterten Verwaltung von Benutzerrechten, bei der Verfeinerung von Arbeitsabläufen für die Datenarchivierung und bei der Einführung systematischer Tests, um die Codequalität bei hoher Datenlast auf hohem Niveau zu halten. Weitere Einzelheiten finden Sie in der vollständigen Fallstudie.

Bei jedem Auftrag sind wir bestrebt, Angular-Anwendungen so zu optimieren, dass sie stabil, sicher und bereit für neue Funktionen bleiben. Wenn Sie neugierig sind, wie wir Front-End-Aufgaben in Angular, React oder Vue angehen, besuchen Sie unsere Webentwicklungsseite oder schauen Sie in unserem Blog vorbei, um mehr zu erfahren. Und wenn Sie daran denken, Ihre Angular-Codebasis zu aktualisieren oder etwas von Grund auf neu zu entwickeln, sind wir da, um Ihre Ideen in reale Lösungen zu verwandeln.

Wenn Sie diese Checkliste für die Angular-Codeüberprüfung befolgen, können Sie wartbare, leistungsstarke Anwendungen erstellen, die sich im Laufe der Zeit bewähren. Verfeinern Sie Ihre Prozesse, wenn sich Ihre Frameworks weiterentwickeln, und sprechen Sie uns an, wenn Sie die Grenzen Ihres Projekts noch weiter hinausschieben möchten. Wir arbeiten gerne mit Menschen zusammen, die wie wir Spaß daran haben, gute Ideen in großartige Software zu verwandeln.

Mitbringsel

Dies ist die Zusammenfassung unserer Angular Code Review Checkliste. Wenn Sie diese Punkte befolgen, werden Sie viele versteckte (und offensichtliche) Fallstricke auf Ihrer Reise vermeiden. Denken Sie daran, den Stil des Codes im Auge zu behalten, achten Sie auf Ihre Abhängigkeiten, und vergessen Sie nie die Sicherheit. Wenn Sie Probleme entdecken oder nicht weiterkommen, lassen Sie uns Kontakt aufnehmen. Wir helfen anderen Entwicklern gerne dabei, ihre Anwendungen zu verfeinern und zu verbessern.

Wir machen das schon seit 2005 und freuen uns darauf, Ihr Angular-Projekt wachsen zu sehen. Wenn Ihr Code klar ist, spüren Ihre Benutzer das. Lassen Sie uns das erreichen.