Node.js Projekt: Eine kurze Anleitung

Die meisten technischen Anleitungen erklären die Funktionalitäten (oder den „Werkzeugkasten“) einer Sprache. Dennoch wird die Wichtigkeit einer stabilen Projektstruktur beim Starten eines neuen Projekts oder neuen Jobs oft vernachlässigt. Natürlich ist das Erlernen der Grundlagen einer Programmiersprache der erste zentrale Meilenstein für jeden Programmierer. Es kann viel einfacher sein, ein erfahrener Entwickler zu werden, wenn […]

by Atanas Ivanov

Juli 26, 2022

7 min read

Node js project structure scaled 1 - Node.js Projekt: Eine kurze Anleitung

Die meisten technischen Anleitungen erklären die Funktionalitäten (oder den "Werkzeugkasten") einer Sprache. Dennoch wird die Wichtigkeit einer stabilen Projektstruktur beim Starten eines neuen Projekts oder neuen Jobs oft vernachlässigt. Natürlich ist das Erlernen der Grundlagen einer Programmiersprache der erste zentrale Meilenstein für jeden Programmierer. Es kann viel einfacher sein, ein erfahrener Entwickler zu werden, wenn man lernt, die eigenen Projekte korrekt aufzusetzen. Node.js zum Beispiel scheint einfach konfigurierbar und ein "Sandkasten"-Arbeitsplatz ist schnell eingerichtet. Es wird jedoch herausfordernder, wenn komplexe Backend-Projekte und APIs benötigt werden.

Heute fokussieren wir uns darauf, was ein exzellentes Node.js-Projekt ausmacht, basierend auf meiner Erfahrung als Software-Entwickler. Ich werde detailliert die wichtigtsten Komponenten beschreiben und Tipps geben, wie ein Projekt gut organisiert bleibt. Beachten Sie, dass diese Projektstruktur für Vanilla Javascript passend ist.

Zuerst die Ordner

Wenn wir von einer guten Projektstruktur sprechen, kommt als erstes die Frage eines jedes Entwicklers auf: “Wo soll ich diese Datei ablegen?”. Das Erstellen der Ordner, die den Quellcode enthalten, ist das erste, worüber man nachdenken sollte, wenn man ein Projekt beginnt. Um ihre Bedeutung hervorzuheben, werde ich von nun an die Order eines Node.js-Projekts als “Projekt-Komponenten” bezeichnen.

Bedenken Sie, dass wir mehrere Domains haben können, wenn wir ein komplexes Backend bauen. In diesem Fall hat Ihr Root-Projektordner vermutlich einen Paket-Einstiegspunkt. Dieser besteht aus eigenständigen Anwendungen (APIs), die miteinander kommunizieren. Jede Komponente, die unten aufgeführt ist, stellt eine Projektkomponentenstruktur dar, die idealerweise für alle Pakete in Ihrem Projekt angewendet wird.

1. Jede Komponente hat ihren Index

Nachdem Sie Ihre Projektkomponenten erstellt und angefangen haben, JavaScript-Code zu schreiben, werden Sie vermutlich mindestens zwei bis drei Dateien in jeder Komponente erstellt haben. Diese Dateien werden die Funktionalitäten beherbergen, die Sie in Ihrem Projekt benutzen - dies bedeutet, dass sie mehrmals importiert (required) werden. Typischerweise können wir jede JavaScript-Datei als ein Modul behandeln, indem wir die import/export-Syntax verwenden. Anstatt die Funktionalitäten jedes Moduls separat zu exportieren, können Sie einen einzelnen Export-Endpunkt der Komponente erstellen. Meistens ist dies die index.js-Datei. Schauen wir uns ein Beispiel an:

Hier sehen wir zwei Modelle (wir werden Modelle später erklären) - Kontakt und eine Gruppe. Es gibt außerdem eine index.js Datei, welche diese für andere Komponenten ohne weitere Konkretisierung exportiert.

Dies führt zu einer einfacheren Syntax beim Importieren, da Javascript die index.js-Datei automatisch erkennt. Daher müssen Sie ihren Namen nicht für jeden Import erwähnen.

Nachdem Sie wissen, wie man verschiedene Komponenten in der Projektstruktur importiert/exportiert, befassen wir uns mit den wichtigsten Komponenten, die Sie benötigen werden.

2. Node.js-Projektkomponenten

Das Ziel ist eine Paketstruktur (wenn Sie mehr als eins benötigten) ähnlich wie unten abgebildet. Wir werden alle Projektkomponenten und deren Zweck betrachten.

  • Config - dieser Ordner wird benutzt, um die Konfigurationsdateien zu verwalten. Der häufigste Anwendungsfall einer Konfigurationsdatei ist der Export von Umgebungsvariablen für andere Teile des Projekts oder Datenbank-Konfigurationen. Diese Datei ist notwendig, und wahrscheinlich werden Sie sie zu Beginn des Projekts erstellen und einrichten. Ohne sie werden Sie keinen geeigneten Ort haben, um zu Datenbanken zu verbinden oder Umgebungen aufzusetzen (z.B: Test, Produktion,...).

  • Controller - hier platzieren wir die Handler unserer Routen. Wie wir in dem Ordner routes/component des Node.js-Projekts sehen werden, erstellen wir einen Handler für jede einzelne Operation, wenn der Client unsere Routen für die verschiedenen CRUD-Operationen "pingt". In den Controllern nutzen wir die Logik der Services um die Antworten an den Client zu verarbeiten. Eine gute Namenskonvention ist die Entität, die mit dem Controller verknüpft ist, gefolgt von controller (statistics-controller.js, contact-controller.js).
  • Data/Enum - dies ist die Komponente, die für die Implementierung von Konstanten und Aufzählungswerten implementiert wird. Anstatt Strings für Daten zu verwenden, die von einer Drittanbieter-API empfangen werden, können Sie Konstanten im data/ Ordner anlegen, die Sie einfach wiederverwenden können.

  • Middleware - der Name sagt es bereits - Sie können eine separate Projekt-Komponente für Middleware, die Sie in den Routen verwenden, erstellen. Es empfiehlt sich, Unterordner anzulegen, die den Zweck der Middleware definieren. Zum Beispiel können Sie einen auth/ Unterordner für alle Authentifizierungsmiddlewares und einen store/ Unterordner für alle Middlewares bezüglich der Store-Entität usw. anlegen.
  • Models - jedes Modell ist ein Objekt, welches den Feldern in der Tabelle nach Name und Typ entspricht. Sie verändern keine Daten, sondern repräsentieren sie in ihrem Code. Abhängig vom ORM, dass Sie benutzen, werden models unterschiedlich aussehen. Sie können sie jedoch in unterschiedlichen js-Dateien speichern - user.js, group.js, usw.
  • Routes - alles, was mit dem Routing zu tun hat, gehört hier hin. Routen sind der wichtigste Teil der API. Eine gute Struktur hat Auswirkungen auf den Softwareentwicklungs-Lebenszyklus. Erinnern Sie sich an das zuvor erwähnte “Jede Datei hat ihren Index”? Hier können Sie es am Besten anwenden, indem Sie mehr Abstraktionen für Ihre Routen definieren, die in separaten Projektkomponenten definiert sind. Das macht es einfacher und nachvollziehbarer, welche Routen sich auf welchen Entitäten beziehen. Eine gute Namenskonvention ist der Name der Entität, die mit der Route verbunden ist, gefolgt von routes (contact-routes.js, group-routes.js).

Eine gut strukturierte index.js im routes/ Ordner

Wir nutzen controllers/ in den separaten Routen um CRUD-Operationen zu definieren, wie das folgende Beispiel zeigt:

  • Services die Geschäftslogik Ihrer Anwendung ist hier abgelegt. Diese sind hauptsächlich Dateien, die Klassen oder eine riesige Funktion exportieren - abhängig von Ihren Node.js Projektanforderungen. Im Wesentlichen enthalten sie die komplexeren Funktionen Ihres Codes. In fast allen Fällen beziehen sich Services und Modelle aufeinander. Zum Beispiel werden Sie in den Services die Repräsentation der Datenbank-Tabellen verwenden, die aus den Modellen als Daten kommen. Dies sind die gleichen Daten, mit denen Sie Funktionen in der Anwendung implementieren.

    Die Service-Methoden werden in den zuvor genannten Controllern aufgerufen. Es empfiehlt sich, einen Basis- oder Unterordner zu erstellen, der die gemeinsame Logik von verschiedenen Services enthält. Auch wenn Sie eine Gruppe von Services haben (beispielsweise von einer Drittpartei-API) ist es sinnvoll, diese in einem Unterordner zu platzieren. Die beiden häufigsten Namenskonventionen von Services sind Camel Case oder das Platzieren von “.service” am Ende des Dateinamens (z.B. statistics.service.js oder statisticsService.js).

  • Utils- die sogenannten Utility oder “pure” Funktionen. Sie übergeben ihnen eine Eingabe, sie verarbeiten diese und geben eine Ausgabe zurück. Sie werden Utility genannt, weil Sie sie in verschiedenen Teilen Ihres Systems unabhängig von der vorhandenen Geschäftslogik verwenden können. Nennenswerte Beispiele sind Datumskonvertierungen oder die Verschlüsselung/Entschlüsselung.
  • Validators - Sie können Validatoren hauptsächlich dafür nutzen, Payloads und Konfigurationen zu validieren, was für APIs unerlässlich ist. Wenn Sie Daten vom Client empfangen, sollten Sie sicherstellen, dass diese gültig sind, sodass Ihre Services damit arbeiten können.
  • Tests - nachdem Sie die Schlüsselkomponenten in Ihrer Ordnerstruktur erstellt haben, ist es Zeit, Tests in Ihrem Projekt zu implementieren (Unit- und Integrationstests). Testen ist sehr wichtig für die Anwendungsentwicklung und ich garantiere, dass sich die Zeit und der Aufwand auszahlt.

Lassen Sie uns nun ein bisschen tiefer in die Struktur Ihrer Tests im Projekt eintauchen. In den meisten Fällen werden Sie es mit Unit- und Integrationstests zu tun haben. Da Integrationstests mehrere Komponenten des Systems abdecken anstelle einer einzelnen Einheit im Code, können Sie einen tests Ordner auf höchster Ordnerebene in Ihrem Quellcode anlegen, der die Tests für die restlichen Komponenten enthält. Wenn Sie zum Beispiel Tests für services haben, werden Sie einen Unterordner in tests -> services anlegen. Im Grunde wiederholen Sie die src Struktur in den Tests.

Eine gute Praxis für Unit-Tests ist es, den tests Ordner so tief wie möglich in der Projektstruktur zu platzieren. Angenommen, Sie möchten Unit-Tests für Ihr oben gezeigtes contact Modell schreiben. Dann erstellen Sie die Unit-Tests in src/models/tests/Contact.test.js.

3. Mehr als nur Ordner

  • Nutzen Sie einen Linter (eslint) - wenn Sie ein Entwicklungsteam haben, welches Code-Konventionen wie Styling oder Namensgebung folgt oder wenn Sie sauberen Code ohne Durcheinander schreiben wollen, empfiehlt sich ESLint (ein Werkzeug für statische Codeanalyse).

  • Umgebungsvariablen - speichern Sie diese Variablen in der sogenannten “.env” Datei. Wie der Name schon sagt, liefern diese Informationen über die Umgebung, in der das Projekt ausgeführt wird. Zum Beispiel können Sie die Zugangsdaten für eine Verbindung zu einer API ablegen, die nur für Sie gelten und die Sie nicht auf Github teilen möchten. Daher sind diese Dateien wichtig, da sie immer in .gitignore referenziert sind, sodass sie nicht remote geteilt werden.

  • Scripts - erstellen Sie einen scripts Ordner für einige Bash-Skripte, die Sie später einfach ausführen können.
  • .editorconfig Datei - diese Datei hilft Ihnen, die Editor/IDE-Erfahrung für alle Entwickler, die Zugriff auf Ihr Node.js-Projekt haben, zu vereinheitlichen. Hier können Sie Zeilenenden, Zeichensatz, Einzugsgröße und mehr angeben.

Zusammenfassung

Die Intention dieses Beitrags war es, einen generellen Überblick über eine typische, initiale Node.js-Projektstruktur zu geben. Währenddessen habe ich einige Best Practices wie Namenskonventionen und die Projektkomponentenstruktur erläutert. Hoffentlich können Sie nun zuversichtlich in Ihr nächstes JS-Projekt starten.

Sollten Sie noch zögern, Node.js als eine Backend-Laufzeitumgebung zu nutzen, empfehle ich diesen Beitrag. Er erläutert die Stärken von Node.js im Detail. Bleiben Sie gespannt auf Weiteres.

Kategorien

Middle Software Engineer at Dreamix