JavaScript-Code-Prüfliste: Alle Schritte inbegriffen

Wir alle sind bestrebt, hochwertige, leistungsfähige und sichere Software zu entwickeln. Ganz gleich, ob Sie sich auf eine wichtige Investitionsrunde vorbereiten oder Ihren Entwicklungszyklus beschleunigen wollen, eine robuste Codebasis ist ein absolutes Must-have. Aber wie können Sie sicherstellen, dass Ihr Team durchgehend außergewöhnlichen Code liefert? Die Antwort liegt in einer effektiven Codeüberprüfung.

In diesem Beitrag gehen wir auf die wichtigsten Aspekte der Entwicklung robuster JavaScript-Anwendungen und die besten Verfahren für die Codeüberprüfung ein. Wenn Sie unsere Checkliste für die JavaScript-Codeüberprüfung befolgen, können Sie den Zeitaufwand für Fehlerbehebungen verringern, die Effizienz Ihres Teams verbessern und letztendlich schneller bessere Produkte liefern. In diesem Artikel werden wir behandeln:

Konsistente Gestaltung und Formatierung des Codes

Indem Sie auf eine einheitliche Gestaltung und Formatierung des Codes achten, schaffen Sie eine solide Grundlage für eine gesunde Codebasis. Eine einheitliche Codebasis sieht nicht nur professionell aus, sondern erleichtert Ihrem Team auch die Zusammenarbeit, das Erkennen von Fehlern und das Einbinden neuer Entwickler. Die Einrichtung von Styleguides und Automatisierungstools ist zwar im Vorfeld mit etwas Aufwand verbunden, aber die verbesserte Effizienz und Codequalität sind es allemal wert.

Styleguide und Automatisierungswerkzeuge:

  • Wählen Sie einen etablierten Styleguide wie den von Airbnb, Google oder den JavaScript-Standard-Styleguide
  • Passen Sie ihn bei Bedarf an die spezifischen Anforderungen Ihres Projekts an
  • Halten Sie sich an den Style Guide, um sicherzustellen, dass jeder Code in Ihrem Projekt gleich aussieht und sich gleich anfühlt, unabhängig davon, wer ihn geschrieben hat
  • Um eine einheitliche Formatierung in Ihrer gesamten Codebasis zu gewährleisten, sollten Sie ein Code-Formatierungswerkzeug wie Prettier integrieren
  • Prettier kann Ihren Code automatisch so formatieren, dass er mit dem gewählten Styleguide übereinstimmt, und befreit Ihre Entwickler von der Last der manuellen Formatierung
// ESLint configuration with Airbnb style guide and Prettier
module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: [
    'airbnb-base',
    'prettier'
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  rules: {
    'no-console': 'warn',
    'import/prefer-default-export': 'off'
  }
};


// Code formatted with Prettier
// Before
function calculateTotal(price,quantity,tax)
{
    let total=price*quantity;
    total+=total*tax;
    return total;
}

// After
function calculateTotal(price, quantity, tax) {
  let total = price * quantity;
  total += total * tax;
  return total;
}

Klare Benennungskonventionen:

  • Verwenden Sie Namen, die eindeutig angeben, wofür die Variable oder Funktion steht. Verwenden Sie zum Beispiel getUserData() statt getData()
  • In JavaScript ist es üblich, für Variablen und Funktionen camelCase und für Klassen PascalCase zu verwenden
  • Halten Sie sich von Abkürzungen fern: Sie können zwar ein paar Anschläge sparen, aber Abkürzungen können verwirrend sein
  • Verwenden Sie in Ihrer gesamten Codebasis die gleichen Begriffe. Wenn Sie an einer Stelle fetch verwenden, sollten Sie nicht an einer anderen Stelle retrieve für dieselbe Aktion verwenden

Schlechte Praxis:

function calc(n) {
  // complex calculation
}
Gute Praxis:
function calculateTotalPrice(numberOfItems) {
  // complex calculation
}

Lesbarkeit und Wartbarkeit des Codes

Sauberer Code reduziert die kognitive Belastung der Entwickler, minimiert Fehler und beschleunigt die Entwicklungszyklen. Sauberer Code ist die Praxis, Code so zu schreiben, dass andere (und Ihr zukünftiges Ich) ihn leicht verstehen, pflegen und darauf aufbauen können.

Modulare Codestruktur:

  • Verwenden Sie aussagekräftige Datei- und Funktionsnamen, die ihren Zweck deutlich machen
  • Gruppieren Sie verwandte Funktionen in logischen Ordnern oder Modulen (z. B. utils, services, controllers)
  • Nutzen Sie objektorientierte oder funktionale Programmierung, je nach den Vorlieben Ihres Teams und den Anforderungen des Projekts

Schlechte Praxis:

// Bad: A single function handling multiple responsibilities
function handleUserRequest(req, res) {
  // Validate request
  if (!req.userId) {
    res.status(400).send('User ID is required');
    return;
  }

  // Fetch user data
  database.query(`SELECT * FROM users WHERE id = ${req.userId}`, (err, user) => {
    if (err) throw err;

    // Process user data
    const processedData = processData(user);

    // Send response
    res.send(processedData);
  });
}
Gute Praxis:
// Good: Separate functions for each responsibility

function validateRequest(req) {
  if (!req.userId) {
    throw new Error('User ID is required');
  }
}

function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    database.query(`SELECT * FROM users WHERE id = ${userId}`, (err, user) => {
      if (err) reject(err);
      resolve(user);
    });
  });
}

function processUserData(user) {
  // Process and return user data
  return {
    id: user.id,
    name: user.name.toUpperCase(),
    // more processing...
  };
}

async function handleUserRequest(req, res) {
  try {
    validateRequest(req);
    const user = await fetchUserData(req.userId);
    const data = processUserData(user);
    res.send(data);
  } catch (error) {
    res.status(400).send(error.message);
  }
}

Tiefe Verschachtelung verhindern:

  • Verwenden Sie Kontrollflussbibliotheken: Bibliotheken wie async können helfen, asynchronen Code zu verwalten
  • Refaktorieren Sie komplexe Bedingungen: Zerlegen Sie komplexe if-Anweisungen in kleinere Funktionen oder verwenden Sie Guard-Klauseln
  • Verwenden Sie frühe Rückgaben: Beenden Sie eine Funktion frühzeitig, wenn bestimmte Bedingungen erfüllt sind, um zusätzliche Verschachtelungen zu vermeiden

Schlechte Praxis:

// Bad: Deeply nested if-statements reduce readability and increase complexity
if (user) {
  if (user.isActive) {
    if (user.hasPermission) {
      // Execute action
    } else {
      // No permission
    }
  } else {
    // User not active
  }
} else {
  // No user found
}
Gute Praxis:
// Good: Using early returns to simplify logic and improve readability
if (!user) {
  // No user found
  return;
}
if (!user.isActive) {
  // User not active
  return;
}
if (!user.hasPermission) {
  // No permission
  return;
}
// Execute action

Kommentare und Dokumentation:

  • Dokumentieren Sie Funktionen und Klassen: Verwenden Sie Kommentare, um den Zweck, die Parameter und die Rückgabewerte zu erklären
  • Erläutern Sie komplexe Logik: Wenn Sie lange darüber nachdenken mussten, kommentieren Sie es
  • Halten Sie Kommentare auf dem neuesten Stand: Überprüfen Sie Kommentare bei Codeüberprüfungen und Aktualisierungen
  • Vermeiden Sie das Auskommentieren von Code: Entfernen Sie ungenutzten Code, anstatt ihn auszukommentieren; die Versionskontrolle hält Ihnen den Rücken frei
/**
 * Calculates the final price by applying tax and discount.
 * @param {Object} params - Calculation parameters
 * @param {number} params.basePrice - Base price before calculations
 * @param {number} params.taxRate - Tax rate as a decimal (e.g., 0.2 for 20% tax)
 * @param {number} params.discount - Discount amount to apply
 * @returns {number} Final price after calculations
 * @throws {ValidationError} If any parameters are invalid
 */
function calculateFinalPrice({ basePrice, taxRate, discount }) {
  // Input validation
  if (!isValidPrice(basePrice)) {
    throw new ValidationError('Invalid base price');
  }

  // Calculate tax
  const taxAmount = basePrice * taxRate;

  // Apply discount
  const discountedPrice = basePrice + taxAmount - discount;

  // Ensure final price is not negative
  return Math.max(0, discountedPrice);
}

// Usage example
try {
  const finalPrice = calculateFinalPrice({
    basePrice: 100,
    taxRate: 0.2,
    discount: 25
  });
  console.log(`Final price: $${finalPrice}`);
} catch (error) {
  logger.error('Price calculation failed:', error);
}

Effiziente Fehlerbehandlung

Fehler sind bei der Softwareentwicklung unvermeidlich. Die Art und Weise, wie Sie mit diesen Fehlern umgehen, macht den Unterschied zwischen einer angenehmen Benutzererfahrung und einem frustrierenden Absturz aus. Mit einer effizienten Fehlerbehandlung stärken Sie proaktiv die Widerstandsfähigkeit Ihrer Anwendung. Dies hilft auch den Entwicklern beim Debuggen und Warten Ihres Codes.

Verwendung von Try-Catch-Blöcken:

  • Sparsam verwenden: Wickeln Sie nur Code ein, der Ausnahmen auslösen kann, nicht aber ganze Funktionen oder Module
  • Asynchroner Code: Denken Sie daran, dass try-catch keine Fehler in asynchronem Code abfängt (z. B. in setTimeout– oder Promise-Callbacks). Verwenden Sie .catch() für Promises oder behandeln Sie Fehler in asynchronen Funktionen
  • Unterdrücken Sie keine Fehler: Fangen Sie Fehler ab, um sie angemessen zu behandeln, nicht um sie zu verstecken

Schlechte Praxis:

// Bad: Not handling potential errors
function parseJSON(jsonString) {
  return JSON.parse(jsonString);
}

const data = parseJSON(userInput);
console.log(data.name);
Gute Praxis:
// Good: Handling errors with try-catch
function parseJSON(jsonString) {
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.error('Failed to parse JSON:', error);
    return null;
  }
}

const data = parseJSON(userInput);
if (data) {
  console.log(data.name);
} else {
  console.log('Invalid input provided.');
}

Benutzerdefinierte Fehlermeldungen:

  • Stellen Sie benutzerdefinierte Fehlermeldungen bereit, um die Fehlersuche zu erleichtern und die Benutzerfreundlichkeit zu verbessern
  • Deutliche Angabe der Art des Fehlers
class ValidationError extends Error {
  constructor(message, { cause, ...extra } = {}) {
    super(message);
    this.name = 'ValidationError';
    this.cause = cause;
    this.extra = extra;
  }
}

function calculateDiscount(price, discountPercentage) {
  if (price <= 0) {
    throw new ValidationError('Price must be a positive number', {
      cause: 'Invalid price',
      price,
    });
  }

  if (discountPercentage < 0 || discountPercentage > 1) {
    throw new ValidationError('Discount percentage must be between 0 and 1', {
      cause: 'Invalid discount percentage',
      discountPercentage,
    });
  }

  return price * (1 - discountPercentage);
}

try {
  const discountedPrice = calculateDiscount(-100, 0.2);
  console.log(`Discounted price: $${discountedPrice}`);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error(`${error.message} (${error.cause})`);
    console.error(error.extra);
  } else {
    console.error('An unexpected error occurred:', error);
  }
}

Protokollierung:

  • Protokollieren Sie in einem strukturierten Format (z. B. JSON), um die Analyse zu erleichtern
  • Achten Sie darauf, keine Passwörter, Token oder persönliche Benutzerinformationen zu protokollieren
  • Verwenden Sie geeignete Protokollierungsstufen: Fehler (für schwerwiegende Probleme, die sofortige Aufmerksamkeit erfordern), Warnung (für potenzielle Probleme oder wichtige Hinweise), Info (allgemeine betriebliche Einträge über die Vorgänge), Debug (detaillierte Informationen für die Fehlersuche)
  • Verwenden Sie Log-Management-Systeme wie ELK Stack (Elasticsearch, Logstash, Kibana) oder Cloud-Dienste, um Logs zu aggregieren und zu analysieren

Schlechte Praxis:

// Bad: Using console.log in production code
function fetchData(url) {
  fetch(url)
    .then((response) => response.json())
    .catch((error) => console.log('Error fetching data:', error));
}
Gute Praxis:
// Good: Using a logging library
const logger = require('your-preferred-logger');

function fetchData(url) {
  fetch(url)
    .then((response) => response.json())
    .catch((error) => {
      logger.error('Error fetching data:', {
        message: error.message,
        stack: error.stack,
        url,
      });
    });
}

Optimierung der Leistung

Die Nutzer erwarten, dass Anwendungen blitzschnell und reaktionsschnell sind. Sie werden sich also fragen, wie schnell eine Website im Jahr 2024 laden sollte? Laut Google ist alles, was über 2,5 Sekunden dauert, verbesserungswürdig, und alles, was unter 4 Sekunden liegt, gilt als schlechte Seitengeschwindigkeit. Leistungsoptimierung ist der Schlüssel zur Zufriedenheit und zum Engagement Ihrer Nutzer. Im Folgenden finden Sie einige bewährte Strategien zur Optimierung der Leistung Ihrer JavaScript-Anwendungen.

Effiziente Datenmanipulation:

  • Wählen Sie geeignete Datenstrukturen:
    • Arrays sind ideal für geordnete Sammlungen und wenn Sie Operationen wie Map, Filter oder Reduce durchführen müssen
    • Objekte (oder Maps) sind besser geeignet für Schlüssel-Wert-Paare mit kurzen Suchzeiten
    • Verwenden Sie Set für eindeutige Werte und schnelle Existenzprüfungen
    • Verwenden Sie Map für Schlüssel-Wert-Paare, bei denen die Schlüssel von beliebigem Typ sein können
  • Minimieren Sie die Datenverarbeitung: Verarbeiten Sie nur die Daten, die notwendig sind; verwenden Sie Pagination oder Lazy Loading für große Datenmengen
  • Vermeiden Sie unnötiges Tiefkopieren von Objekten: Tiefes Kopieren kann teuer sein; verwenden Sie wenn möglich flache Kopien oder unveränderliche Datenstrukturen
  • Verwenden Sie Web Worker: Verlagern Sie schwere Berechnungen auf Web-Worker, um ein Blockieren des Haupt-Threads zu vermeiden

Schlechte Praxis:

// Bad: Using an array to check for the existence of a value
const items = ['apple', 'banana', 'orange'];

function hasItem(item) {
  return items.indexOf(item) !== -1;
}
Gute Praxis:
// Good: Using a Set for efficient existence checks
const itemsSet = new Set(['apple', 'banana', 'orange']);

function hasItem(item) {
  return itemsSet.has(item);
}

Asynchrone Programmierung:

  • Sofern die Kompatibilität mit älteren Umgebungen keine Rolle spielt, verwenden Sie async/await für einen saubereren Code
  • Verwenden Sie bei asynchronen Funktionen immer try/catch, um Fehler zu behandeln
  • Halten Sie sich an ein asynchrones Muster in einem bestimmten Codeblock, um die Konsistenz zu wahren

Schlechte Praxis:

// Bad Practice: Promise Hell, avoid this pattern at any cost
function getUserData(userId) {
  fetchUser(userId)
    .then(user => {
      fetchUserPosts(user.id)
        .then(posts => {
          fetchPostComments(posts[0].id)
            .then(comments => {
              console.log(comments);
            })
            .catch(err => console.error(err));
        })
        .catch(err => console.error(err));
    })
    .catch(err => console.error(err));
}
Gute Praxis:
// Good Practice: Promise Chaining
function getUserData(userId) {
  return fetchUser(userId)
    .then(user => fetchUserPosts(user.id))
    .then(posts => fetchPostComments(posts[0].id))
    .then(comments => comments)
    .catch(err => {
      logger.error('Failed to fetch user data:', err);
      throw err;
    });
}

// Better Practice: Async/Await with Error Handling
async function getUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchUserPosts(user.id);
    const comments = await fetchPostComments(posts[0].id);
    return comments;
  } catch (error) {
    logger.error('Failed to fetch user data:', error);
    throw error;
  }
}

// Best Practice: Parallel Operations with Error Handling
async function getUserProfile(userId) {
  try {
    const [user, posts, settings] = await Promise.all([
      fetchUser(userId),
      fetchUserPosts(userId),
      fetchUserSettings(userId)
    ]);
    
    return {
      ...user,
      posts,
      settings
    };
  } catch (error) {
    logger.error('Failed to fetch user profile:', error);
    throw error;
  }
}

Verhinderung von Speicherlecks:

  • Entfernen Sie unbenutzte Ereignis-Listener und Timer: Räumen Sie hinter sich auf, um unbeabsichtigte Speicherplatzverluste zu vermeiden
  • Vermeiden Sie unnötige globale Variablen: Beschränken Sie Variablen auf die Bereiche, in denen sie benötigt werden
  • Verwalten Sie Referenzen sorgfältig: Achten Sie darauf, wie Closures und Callbacks auf Variablen verweisen
  • Regelmäßige Tests und Profile: Verwenden Sie Tools, um Speicherlecks zu erkennen und zu beheben, bevor sie zu einem Problem werden

Schlechte Praxis:

// Bad: Not removing event listeners when elements are removed
function attachListener() {
  const button = document.getElementById('myButton');
  button.addEventListener('click', handleClick);
}

function handleClick() {
  // Handle click event
}

// Later, the button is removed from the DOM
document.getElementById('myButton').remove();
Gute Praxis:
// Good: Properly removing event listeners and managing references
function attachListener() {
  const button = document.getElementById('myButton');
  const handleClick = () => {
    // Handle click event
    console.log('Button clicked!');
  };

  button.addEventListener('click', handleClick);

  // Add a cleanup function to remove the listener when the button is removed
  const cleanup = () => {
    button.removeEventListener('click', handleClick);
    button.remove();
  };

  return cleanup;
}

// Example usage
const cleanupFunction = attachListener();

// Later, when the button is no longer needed
cleanupFunction();

Bewährte Sicherheitspraktiken

Benutzereingaben sind eine der größten Schwachstellen in jeder Anwendung. Ohne eine ordnungsgemäße Bereinigung wird Ihre Anwendung zu einer Spielwiese für Angreifer, die Schwachstellen durch Cross-Site Scripting (XSS) und Injektionsangriffe ausnutzen wollen. Die Sicherung von Daten während der Übertragung und Speicherung und die regelmäßige Überprüfung von Abhängigkeiten ist ein Muss.

Beseitigung von Benutzereingaben:

  • Verwenden Sie vertrauenswürdige Bibliotheken wie DOMPurify, um HTML zu bereinigen und XSS-Angriffe zu verhindern
  • Validierung von Eingaben auf der Server-Seite: Client-seitige Validierung kann umgangen werden; immer auf dem Server validieren
  • Eingabe zulassen: Nur erwartete Daten akzeptieren; akzeptable Muster definieren und alles andere zurückweisen
  • Angemessene Escape-Ausgabe: Verwenden Sie verschiedene Escape-Methoden für HTML, URLs, JavaScript und CSS
// Using 3rd-party library DOMPurify as it is more secure and robust than manually sanitizing the input using string manipulation or regular expressions
import DOMPurify from 'dompurify';

function sanitizeUserInput(unsafeInput) {
  // Sanitize HTML input to prevent XSS attacks
  const sanitizedInput = DOMPurify.sanitize(unsafeInput, {
    ALLOWED_TAGS: ['a', 'b', 'i', 'em', 'strong'],
    ALLOWED_ATTR: ['href'],
  });

  return sanitizedInput;
}

// Example usage
const userInput = '<a href="javascript:alert(\'XSS attack!\')">Click me</a>';
const cleanInput = sanitizeUserInput(userInput);

console.log(cleanInput); 
// Output: <a href="#">Click me</a>

HTTPS und sichere Cookies verwenden:

  • Setzen Sie sichere Cookie-Attribute: Secure Flag (stellt sicher, dass Cookies nur über HTTPS gesendet werden), HttpOnly Flag (verhindert, dass JavaScript auf Cookies zugreift und entschärft so XSS-Angriffe), SameSite Attribut (schützt vor CSRF-Angriffen)
  • Regelmäßige Aktualisierung der Zertifikate: Überwachen Sie die Gültigkeit von Zertifikaten und erneuern Sie sie, bevor sie ablaufen
  • Deaktivieren Sie schwache Protokolle und Chiffren: Verwenden Sie starke Verschlüsselungsstandards wie TLS 1.3+

Verwaltung von Abhängigkeiten:

  • Sperren von Abhängigkeitsversionen: Verwenden Sie package-lock.json oder yarn.lock, um konsistente Installationen in verschiedenen Umgebungen sicherzustellen
  • Regelmäßige Aktualisierung von Abhängigkeiten: Planen Sie Zeit ein, um Pakete zu aktualisieren und auf Kompatibilität zu testen
  • Verwenden Sie regelmäßig die Befehle npm audit oder yarn audit, um die Pakete auf Schwachstellen zu überprüfen
  • Entfernen Sie ungenutzte Abhängigkeiten: Eine schlanke Codebasis verringert die potenzielle Angriffsfläche und verbessert die Leistung
  • Bevorzugen Sie offizielle Quellen: Überprüfen Sie Paketnamen doppelt, um die Installation bösartiger Pakete mit ähnlichen Namen zu verhindern
  • Überprüfungen automatisieren: Integrieren Sie Tools, die Abhängigkeiten während des Build-Prozesses scannen

Umfassende Tests

Umfassende Tests erstrecken sich über mehrere Ebenen, vom Testen einzelner Code-Einheiten bis hin zur Überprüfung, ob ganze Systeme gut zusammenarbeiten. Laufende Tests stellen sicher, dass Sie eine solide Grundlage für das zukünftige Wachstum und den Erfolg Ihrer Anwendung schaffen. Unit-Tests, Integrationstests und eine hohe Testabdeckung können die Qualität Ihrer JavaScript-Anwendungen spürbar verbessern.

Unit-Tests:

  • Testen Sie eine einzelne Aufgabe: Jeder Test sollte sich auf einen Aspekt des Verhaltens der Funktion konzentrieren
  • Verwenden Sie beschreibende Testnamen: Geben Sie klar an, was der Test prüft
  • Externe Abhängigkeiten simulieren: Isolieren Sie die Codeeinheit, indem Sie APIs, Datenbanken oder andere Dienste nachbilden
  • Streben Sie deterministische Tests an: Tests sollten bei jedem Durchlauf die gleichen Ergebnisse liefern

Schlechte Praxis:

// Function to be tested
function add(a, b) {
  return a + b;
}

// Test suite
describe('add function', () => {
  it('should add two numbers', () => {
    assert.equal(add(2, 3), 5);
  });
});
Gute Praxis:
// Function to be tested
function add(a, b) {
  return a + b;
}

// Test suite
describe('add function', () => {
  it('should add two positive numbers', () => {
    assert.equal(add(2, 3), 5);
  });

  it('should add two negative numbers', () => {
    assert.equal(add(-2, -3), -5);
  });

  it('should handle a positive and a negative number', () => {
    assert.equal(add(2, -3), -1);
  });

  it('should handle zero as an argument', () => {
    assert.equal(add(2, 0), 2);
    assert.equal(add(0, 3), 3);
  });
});

Integration und End-to-End-Tests:

  • Pflegen Sie eine Testumgebung: Verwenden Sie eine separate Umgebung, die die Produktionseinstellungen widerspiegelt
  • Verwenden Sie Testdaten: Befüllen Sie Datenbanken mit bekannten Daten, um konsistente Ergebnisse zu erzielen
  • Automatisieren Sie Tests: Integrieren Sie Tests in Ihre CI/CD-Pipeline, um sie bei jedem Build oder Einsatz auszuführen
  • Priorisieren Sie kritische Pfade: Konzentrieren Sie sich auf die wichtigsten Benutzerabläufe und Integrationspunkte

Testabdeckung:

  • Streben Sie einen hohen Abdeckungsgrad an (z.B. 80-90%), aber seien Sie sich bewusst, dass eine 100%ige Abdeckung keine Garantie für fehlerfreien Code ist
  • Überprüfen Sie regelmäßig, welche Teile Ihres Codes nicht abgedeckt sind, und beurteilen Sie, ob sie getestet werden müssen
  • Schließen Sie Code, der automatisch generiert wird oder nicht kritisch ist (z. B. Konfigurationsdateien), aus den Abdeckungsberichten aus
  • Konzentrieren Sie sich auf aussagekräftige Tests, die das Verhalten validieren: Oberflächliche Tests zu schreiben, um den Abdeckungsgrad zu erhöhen, ist eine kontraproduktive Praxis

Richtige Verwendung der Versionskontrolle

Die Versionskontrolle ermöglicht es mehreren Entwicklern, an der gleichen Codebasis zu arbeiten, ohne sich gegenseitig auf die Füße zu treten. Die ordnungsgemäße Verwendung der Versionskontrolle verbessert die Zusammenarbeit, gewährleistet die Codequalität und unterstützt den agilen Entwicklungsprozess. Durch die Einführung effektiver Verzweigungsstrategien, das Verfassen aussagekräftiger Commit-Nachrichten und die Durchführung gründlicher Code-Reviews schaffen Sie die Voraussetzungen für den Erfolg Ihres Teams.

Verzweigungen:

  • Halten Sie Verzweigungen kurzlebig: Führen Sie Änderungen regelmäßig zusammen, um divergierende Codebasen zu vermeiden
  • Verwenden Sie aussagekräftige Zweignamen: Geben Sie den Typ und den Zweck an, z. B. feature/add-payment-method oder bugfix/fix-login-error
  • Regeln zum Schutz von Zweigen: Verhindern Sie direkte Übertragungen an Main oder Master und verlangen Sie PR-Reviews

Commit-Nachrichten:

  • Verwenden Sie die imperative Stimmung: Verwenden Sie Verben wie „Hinzufügen“, „Beheben“, „Aktualisieren“
  • Halten Sie die Betreffzeilen prägnant: Fassen Sie die Änderung in 50 Zeichen oder weniger zusammen
  • Geben Sie Kontext an: Helfen Sie anderen, die Gründe für die Änderungen zu verstehen
  • Trennen Sie die Änderungen angemessen voneinander: Eine logische Änderung pro Commit

Schlechte Praxis:

git commit -m "Fix stuff"
Gute Praxis:
git commit -m "Fix authentication error when user logs in with Google"

Pull Requests:

  • Wenn Sie einen PR eröffnen, geben Sie einen aussagekräftigen Titel und eine Beschreibung an
  • Erwähnen Sie etwaige Abhängigkeiten oder verwandte PRs
  • Weisen Sie ein bestimmtes Teammitglied als Reviewer zu
  • Verwenden Sie Merge-Strategien in angemessener Weise: Merge Commit (behält alle Commits und die Historie), Squash and Merge (fasst Commits zu einem zusammen, um die Historie aufzuräumen); Rebase and Merge (setzt Ihre Commits auf den Hauptzweig, um eine lineare Historie zu erhalten)

Verwaltung von Abhängigkeiten

Abhängigkeiten können die Stabilität, Leistung und Sicherheit Ihrer Anwendung erheblich beeinträchtigen. Effektives Abhängigkeitsmanagement ist ein Balanceakt zwischen der Nutzung von Drittanbietercode und der Beibehaltung der Kontrolle über die Integrität und Leistung Ihres Projekts. Hier sind einige Best Practices, die Ihnen helfen, die so genannte „Abhängigkeitshölle“ zu vermeiden.

Verwendung von Sperrdateien:

  • Übertragen Sie Sperrdateien immer: Behalten Sie sie unter Versionskontrolle, um die Konsistenz zu wahren
  • Bearbeiten Sie Sperrdateien nicht manuell: Überlassen Sie sie dem Paketmanager, um Beschädigungen zu vermeiden
  • Aktualisieren Sie Lock-Dateien absichtlich: Führen Sie npm install oder yarn install aus, ohne die Versionen zu ändern, es sei denn, Sie beabsichtigen eine Aktualisierung
  • Umgang mit Lock-Dateien in Anwendungen: Übertragen Sie Sperrdateien, um die Konsistenz der Bereitstellung zu gewährleisten
  • Umgang mit Sperrdateien in Bibliotheken/Paketen: Ziehen Sie in Erwägung, Lock-Dateien nicht zu committen, um der Endanwendung die Kontrolle über die Abhängigkeitsversionen zu überlassen

Vermeiden der Abhängigkeitshölle:

  • Verstehen, wie die Operatoren Caret (^) und Tilde (~) Versionsbereiche beeinflussen
  • Caret (^1.2.3): Aktualisiert auf die neueste Minor-Version (aber nicht Major)
  • Tilde (~1.2.3): Aktualisiert auf die letzte Patch-Version (aber nicht Minor oder Major)
  • Prüfen Sie die Änderungsprotokolle vor der Aktualisierung: Prüfen Sie auf bahnbrechende Änderungen, insbesondere bei Aktualisierungen von Hauptversionen
  • Automatisieren Sie die Verwaltung von Abhängigkeiten: Verwenden Sie Tools wie Dependabot oder Renovate, um Aktualisierungen zu automatisieren und Pull-Requests für sie zu erstellen
  • Testen Sie nach Aktualisierungen gründlich: Führen Sie Ihre Testsuite durch, um Probleme zu erkennen, die durch aktualisierte Abhängigkeiten entstanden sind

Modulare Abhängigkeiten:

  • Importieren Sie nur die notwendigen Teile: Kleinere Pakete werden schneller geladen und verbessern die Benutzerfreundlichkeit
  • Verwenden Sie Bundler wie Webpack oder Rollup, die Tree-Shaking unterstützen, um ungenutzten Code zu eliminieren
  • Stellen Sie sicher, dass Sie ES6-Module (Import/Export) verwenden, die statisch analysierbar sind

Zusätzliche Überlegungen:

  • Dynamischer Import von Modulen bei Bedarf, um die anfänglichen Ladezeiten zu verbessern
  • Stellen Sie sicher, dass nicht mehrere Versionen der gleichen Bibliothek enthalten sind; verwenden Sie Tools wie npm dedupe oder yarn-deduplicate

Überlegungen zur Barrierefreiheit

Das Ziel der Barrierefreiheit ist es, Ihre Anwendung für möglichst viele Menschen nutzbar zu machen, auch für Menschen mit Behinderungen. Indem Sie bewährte Praktiken für die Barrierefreiheit einbeziehen, erfüllen Sie nicht nur die gesetzlichen Anforderungen in einigen Regionen, sondern bieten auch eine bessere Benutzererfahrung für alle.

Semantisches HTML:

  • Verwenden Sie <div> und <span> nicht übermäßig, wenn ein semantisches Element besser geeignet ist
  • Fügen Sie <div> nicht in <p> ein</li>
  • Sicherstellen, dass die Überschriftenebenen in der richtigen Reihenfolge verwendet werden (z. B. <h2> folgt auf <h1>)
  • Strenge Hierarchie von <h1> bis <h6> zur Definition von Überschriften und Unterüberschriften verwenden
  • Verwenden Sie <nav>, um Navigationslinks einzuschließen
  • Verwenden Sie <main>, um den Hauptinhalt der Seite zu umschließen
  • Verwenden Sie <section> und <article> für bestimmte Teile des Inhalts
  • Verwendung geeigneter Steuerelemente wie <label>, <input>, <select> und <textarea>

ARIA-Rollen und -Attribute:

  • Verwenden Sie die W3C WAI-ARIA-Spezifikation für die Umsetzung der besten Zugänglichkeitsempfehlungen
  • Verwenden Sie ARIA nur als letzten Ausweg: Bevorzugen Sie native HTML-Elemente, bevor Sie ARIA-Rollen hinzufügen
  • Stellen Sie eine angemessene Tastaturinteraktion sicher: Benutzerdefinierte Widgets sollten die Navigation und Aktivierung per Tastatur unterstützen
  • Halten Sie ARIA-Attribute auf dem neuesten Stand: ARIA-Status dynamisch aktualisieren, um Änderungen widerzuspiegeln
  • Definieren Sie die Art des Widgets und weisen Sie ihm die entsprechende Rolle zu, die seiner Position in der Rollenhierarchie entspricht (Rolle=„Schaltfläche“, Rolle=„Dialog“)
  • Beschreiben Sie den aktuellen Zustand von Elementen mit bestimmten Rollen (aria-checked, aria-expanded)
  • Zugängliche Namen bereitstellen (aria-label, aria-labelledby)

Schlechte Praxis:

// Bad: Adding ARIA roles to non-semantic elements unnecessarily
<div role="button" onclick="toggleMenu()">Menu</div>
Gute Praxis:
// Good: Use a button and enhance with ARIA if needed 
<button aria-expanded="false" aria-controls="menu" onclick="toggleMenu(this)">Menu</button>
<ul id="menu" hidden>
  <!-- Menu items -->
</ul>

Keyboard Navigation:

  • Use standard controls: Native HTML elements like <button>, <a>, <input> are keyboard-friendly by default
  • Manage focus order: Arrange focusable elements in a logical order
  • Use tabindex=„0“ to make custom elements focusable, but use sparingly
  • Ensure that focused elements have a visible outline or highlight
  • For custom components, listen to keyboard events like keydown and respond appropriately
  • Test keyboard accessibility: Use the Tab key to move focus forward and Shift + Tab to move backward
  • Use accessibility testing tools like Axe or Lighthouse

Ihr JS-Partner: Entwicklung & Audit Services

Wir sind seit 2005 in der Webentwicklung tätig und arbeiten mit Startups und großen Unternehmen zusammen, um ihre Visionen zu verwirklichen. Von der Erstellung interaktiver Front-End-Anwendungen mit React und Vue.js bis hin zur Entwicklung skalierbarer Back-End-Dienste mit Node.js haben wir eine breite Palette von Herausforderungen bewältigt, die JavaScript-Projekte darstellen.

Unser Team aus erfahrenen Entwicklern, Designern und Projektmanagern kann Ihr Projekt stärken und Ihnen helfen, wichtige Aufgaben schneller zu erledigen, ohne sich überfordert zu fühlen. Hier erhalten Sie einen Einblick in die spezifischen Dienstleistungen, die wir anbieten, und wie unsere Kunden unser Fachwissen und unsere Ressourcen nutzen, um ihre Meilensteine zu erreichen:

  • Entwicklung von Grund auf. Wir sind darauf spezialisiert, kundenspezifische Softwarelösungen von Grund auf zu entwickeln. Sehen Sie, wie wir Kooky geholfen haben, eine webbasierte Plattform für die Nachverfolgung von wiederverwendbaren Kaffeebechern zu entwickeln und die Nummer 1 unter den Green-Tech-Startups in der Schweiz zu werden.
  • Code-Refactoring. Wir können Ihnen helfen, Ihre Anwendung zu refaktorisieren und sie auf den neuesten Stand zu bringen. Cakemail, ein E-Mail-Marketing-Startup mit Sitz in Montreal, beauftragte Redwerk mit dem Refactoring eines Abonnement-Formular-Moduls. Wir lieferten den überarbeiteten Code in weniger als 90 Tagen und ermöglichten es Cakemail, ein wichtiges Upgrade rechtzeitig zu starten.
  • Funktionalitäten erweitern. Erhöhen Sie die Attraktivität Ihres Produkts, indem Sie neue Funktionen hinzufügen. Orderstep, eine führende Vertriebs- und CRM-Plattform, nutzte unsere Expertise in der Front-End- und React-Entwicklung, um seine Lösung um ein Webshop-Modul für Premium-Benutzer zu erweitern und so den Umsatz des Unternehmens zu steigern.
  • Code-Überprüfung: Verschaffen Sie sich einen unvoreingenommenen Blick auf die Qualität Ihrer App mit einem umfassenden Code-Review durch Redwerk. Wir haben aus erster Hand erfahren, wie ein frisches Paar Augen versteckte Probleme oder Optimierungsmöglichkeiten aufdecken kann, die vielleicht übersehen werden, wenn Ihr Team mitten im Entwicklungsalltag steckt.

Dank unserer praktischen Erfahrung wissen wir um den Druck knapper Fristen und die Notwendigkeit schneller Iterationen ohne Kompromisse bei der Codequalität. Ganz gleich, ob Sie ein umfassendes Code-Audit, eine Anleitung zu Best Practices oder eine vollständige Entwicklung benötigen, wir haben ein Team von Technikexperten, das Sie unterstützt. Nehmen Sie Kontakt mit uns auf- wir würden uns gerne mit Ihnen unterhalten, Ihre geschäftlichen Anforderungen kennenlernen und Ihnen helfen, diese zu erfüllen.