Beim Erstellen von Softwaresystemen ist es entscheidend, die Komplexität der Codebasis zu verwalten.
In Kapitel 11 von Clean Code geht es um den Entwurf modularer Systeme, die einfacher zu warten und im Laufe der Zeit anzupassen sind.
Wir können JavaScript-Beispiele verwenden, um diese Konzepte zu veranschaulichen.
Wenn Systeme wachsen, werden sie natürlich auch komplexer. Diese Komplexität kann Folgendes erschweren:
Ein gut konzipiertes System sollte leicht zu modifizieren, testbar und skalierbar sein. Das Geheimnis, dies zu erreichen, liegt in der Modularität und der sorgfältigen Trennung der Belange.
Im Mittelpunkt des sauberen Systemdesigns steht das Prinzip der Modularität. Sie machen das System besser verwaltbar, indem Sie ein großes System in kleinere, unabhängige Module mit jeweils klarer Verantwortung aufteilen.
Jedes Modul sollte eine bestimmte Funktionalität kapseln, wodurch das Gesamtsystem leichter zu verstehen und zu ändern ist.
Beispiel: Organisation eines Warenkorbsystems
Stellen wir uns ein Warenkorbsystem in JavaScript vor. Anstatt die gesamte Logik in einer einzigen Datei zusammenzufassen, können Sie das System in mehrere Module aufteilen:
// cart.js export class Cart { constructor() { this.items = []; } addItem(item) { this.items.push(item); } getTotal() { return this.items.reduce((total, item) => total + item.price, 0); } } // item.js export class Item { constructor(name, price) { this.name = name; this.price = price; } } // order.js import { Cart } from './cart.js'; import { Item } from './item.js'; const cart = new Cart(); cart.addItem(new Item('Laptop', 1000)); cart.addItem(new Item('Mouse', 25)); console.log(`Total: $${cart.getTotal()}`);
Hier sind die Verantwortlichkeiten aufgeteilt: Cart verwaltet die Artikel, Item stellt ein Produkt dar und order.js orchestriert die Interaktionen.
Diese Trennung stellt sicher, dass jedes Modul in sich geschlossen ist und einfacher unabhängig getestet und geändert werden kann.
Eines der Ziele der Modularität ist die Kapselung – das Verbergen der internen Abläufe eines Moduls vor dem Rest des Systems.
Externer Code sollte nur über seine klar definierte Schnittstelle mit einem Modul interagieren.
Dies erleichtert die Änderung der internen Implementierung des Moduls, ohne dass sich dies auf andere Teile des Systems auswirkt.
Beispiel: Kapselung der Einkaufswagenlogik
Angenommen, wir möchten ändern, wie wir den Gesamtbetrag im Warenkorb berechnen. Vielleicht müssen wir jetzt die Umsatzsteuer berücksichtigen. Wir können diese Logik in der Cart-Klasse einkapseln:
// cart.js export class Cart { constructor(taxRate) { this.items = []; this.taxRate = taxRate; } addItem(item) { this.items.push(item); } getTotal() { const total = this.items.reduce((sum, item) => sum + item.price, 0); return total + total * this.taxRate; } } // Now, the rest of the system does not need to know about tax calculations.
Andere Teile des Systems (wie order.js) sind von Änderungen in der Berechnung der Gesamtsumme nicht betroffen. Dadurch wird Ihr System flexibler und einfacher zu warten.
Ein häufiges Problem in großen Systemen besteht darin, dass verschiedene Teile des Systems miteinander verwickelt sind.
Wenn ein Modul zu viele Verantwortlichkeiten übernimmt, wird es schwieriger, es in verschiedenen Kontexten zu ändern oder wiederzuverwenden.
Das Prinzip der Trennung von Belangen stellt sicher, dass jedes Modul eine bestimmte Verantwortung hat.
Beispiel: Separate Abwicklung der Zahlung
Im Warenkorb-Beispiel sollte die Zahlungsabwicklung in einem separaten Modul abgewickelt werden:
// payment.js export class Payment { static process(cart) { const total = cart.getTotal(); console.log(`Processing payment of $${total}`); // Payment logic goes here } } // order.js import { Cart } from './cart.js'; import { Payment } from './payment.js'; const cart = new Cart(0.07); // 7% tax rate cart.addItem(new Item('Laptop', 1000)); cart.addItem(new Item('Mouse', 25)); Payment.process(cart);
Jetzt ist die Zahlungslogik von der Warenkorbverwaltung getrennt. Dies macht es einfach, den Zahlungsprozess später zu ändern (z. B. die Integration mit einem anderen Zahlungsanbieter), ohne dass sich dies auf den Rest des Systems auswirkt.
Einer der größten Vorteile der Modularität besteht darin, dass Sie jedes Modul unabhängig testen können.
Im obigen Beispiel könnten Sie Unit-Tests für die Cart-Klasse schreiben, ohne sich Gedanken darüber machen zu müssen, wie Zahlungen verarbeitet werden.
Beispiel: Unit-Test des Warenkorbs
// cart.test.js import { Cart } from './cart.js'; import { Item } from './item.js'; test('calculates total with tax', () => { const cart = new Cart(0.05); // 5% tax cart.addItem(new Item('Book', 20)); expect(cart.getTotal()).toBe(21); });
Mit einer klaren Trennung der Belange kann jedes Modul isoliert getestet werden, was das Debuggen erleichtert und die Entwicklung beschleunigt.
Wenn Module zu stark voneinander abhängig sind, können Änderungen in einem Teil des Systems unerwartete Folgen an anderer Stelle haben.
Um dies zu minimieren, achten Sie auf eine lockere Kopplung zwischen den Modulen.
Dadurch kann sich jedes Modul unabhängig weiterentwickeln.
Beispiel: Abhängigkeiten einfügen
Anstatt Abhängigkeiten innerhalb eines Moduls fest zu codieren, übergeben Sie sie als Argumente:
// cart.js export class Cart { constructor(taxRateCalculator) { this.items = []; this.taxRateCalculator = taxRateCalculator; } addItem(item) { this.items.push(item); } getTotal() { const total = this.items.reduce((sum, item) => sum + item.price, 0); return total + this.taxRateCalculator(total); } }
Dieser Ansatz macht die Cart-Klasse flexibler und einfacher mit verschiedenen Steuerberechnungen zu testen.
Viel Spaß beim Programmieren! ?
Das obige ist der detaillierte Inhalt vonClean Code verstehen: Systeme ⚡️. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!