11 März 2025 (updated: 11 März 2025)
Chapters
Die großen Unternehmen liegen nicht falsch, wenn sie Monorepos für ihre Projekte verwenden. Monorepos zusammen mit einer generischen Vorlage können die Einrichtung Ihres Projekts schneller (und günstiger) machen. Wir teilen unseren Ansatz.
Mit dem ständigen Wachstum der Komplexität in Anwendungen kommt ein Problem - wie kann man all die Anforderungen aufrechterhalten und die Kosten eines Projekts reduzieren, das von Anfang an so viele Abhängigkeiten benötigt? In diesem Artikel werden wir eine Möglichkeit vorstellen, um Tage an Teamarbeit beim Start eines neuen Projekts zu sparen.
Es gibt keinen einfachen Weg, dies zu tun, aber mit jahrelanger Erfahrung und der Suche nach den besten Praktiken von Unternehmen wie Google haben wir bei EL Passion eine Lösung entwickelt, die die benötigte Zeit zur Einrichtung eines neuen Projekts drastisch reduziert.
In diesem Artikel werden wir die Konzepte eines Vorlageprojekts, Monorepos und unseren eigenen Ansatz zu diesem Thema behandeln.
Es gibt ein häufiges Missverständnis, dass das Halten aller Codes in einem Repository alle Nachteile von Monolith-Anwendungen mit sich bringt - es ist nicht skalierbar, es zwingt uns, Apps gemeinsam zu veröffentlichen… Wenn ja, dann warum verwenden Unternehmen wie Google oder Facebook Monorepos? Die Wahrheit ist tatsächlich das Gegenteil. Der Grund, warum der Ansatz eines Repositorys pro Projekt so beliebt ist, liegt in der Autonomie - Teams können isoliert arbeiten und Entscheidungen separat treffen. Das Ding ist - mit den richtigen Werkzeugen können Monorepos alle Vorteile von separaten Repositories und sogar noch mehr haben.
Hier sind einige der Funktionen, die Monorepo bietet:
Die Verwendung von Monorepos allein kann die Entwicklungskosten senken, aber wir sind einen Schritt weiter gegangen und haben die Vorteile von Monorepos genutzt, um eine generische Vorlage für unsere kommenden Projekte zu erstellen.
Die Entwicklung der meisten Apps beginnt ziemlich ähnlich. Es besteht immer die Notwendigkeit, die Architektur und die grundlegende Konfiguration der App einzurichten. Sogar spezifischere Module wie die Autorisierung haben oft eine gemeinsame Logik.
Mit all dem im Hinterkopf kommt die Idee, eine Art Vorlage zu erstellen, die zwischen verschiedenen Projekten wiederverwendet werden kann, was Tage oder Wochen an Arbeit des gesamten Teams spart.
Um zu beweisen, dass es einen signifikanten Zeitunterschied zwischen der Erstellung eines neuen Projekts und der Verwendung eines generischen gibt, beschloss ich, mir 2 Tage Zeit zu geben, um ein Backend-NestJS-Projekt von Grund auf neu einzurichten.
Zunächst nutzte ich die NestJS CLI und generierte ein Starterprojekt, das einige grundlegende Konfigurationen enthält. Dann, obwohl ich täglich mit NestJS arbeite, brauchte ich einige Stunden, um die Datenbankverbindung und die einfache Validierung von Umgebungsvariablen einzurichten. Nach ein paar weiteren Stunden gelang es mir, grundlegende Tests durchzuführen und eine Github Actions CI-Pipeline zu erstellen, um sie automatisch auszuführen.
Es dauerte eine Weile, bis ich die Fehler, die ich gemacht hatte, erkannte, also musste ich sie beheben. Und hier war ich, nach fast 2 Tagen, die ich damit kämpfte, eine grundlegende App-Einrichtung zu machen. Warum war das so?
Die Einrichtung Ihres Projekts erfolgt normalerweise nur einmal alle paar Monate oder sogar seltener. Egal, wie viele Jahre Erfahrung oder Wissen man hat, es ist unmöglich, sich an alle kleinen Details zu erinnern, die notwendig sind, um eine funktionale kommerzielle Anwendung zu erstellen.
Selbst wenn ich mich irgendwie an alles erinnerte, was getan werden musste, hätte es ewig gedauert, um den Stand zu erreichen, an dem es all die Funktionen und Hilfsmittel hat, die wir bei EL Passion in unserem Flounder-Projekt entwickelt haben.
Wie ich bereits erwähnt habe, ist die Einrichtung der meisten Projekte ähnlich - aber nicht ganz gleich. Nehmen wir an, wir haben unser Starter-Monorepo-Projekt abgeschlossen… aber haben wir das wirklich? Auch wenn wir eine Architektur und grundlegende Funktionen vorbereitet haben, ist es tatsächlich nicht anpassbar. Wir wollen nicht jedes Mal, wenn wir ein neues Projekt starten, durch alle Dateien suchen und die Werte von Namen, Pfaden usw. ändern.
Um das zu lösen, haben wir eine Lösung entwickelt, die das Projekt in eine generische Vorlage umwandelt, indem sie jeden projektspezifischen Wert durch Variablen ersetzt, sodass es dann leicht für alle verschiedenen Projekte angepasst werden kann.
Sie fragen sich vielleicht, warum wir nicht von Anfang an mit den Variablen beginnen. Da das Flounder-Projekt ständig aktualisiert wird, müssen wir sicherstellen, dass es voll funktionsfähig ist, damit die Entwickler es wie ein normales Projekt ausführen und entwickeln können.
Um die Dinge zu automatisieren, haben wir eine CI-Pipeline erstellt, die zuerst unser Skript ausführt und dann die Vorlage im Github-Paket-Registry veröffentlicht, sodass sie über die Befehlszeile ausgeführt werden kann, wobei alle Variablen durch projektspezifische Werte ersetzt oder sogar Ressourcen übersprungen werden, die wir für das spezifische Projekt nicht benötigen.
Wir werden ein voll funktionsfähiges Vorlagenprojekt erstellen, das alle oben genannten Funktionen enthält. Lassen Sie uns beginnen, indem wir einen leeren Nx Monorepo-Arbeitsbereich über das Terminal erstellen.
npx create-nx-workspace@latest
Sie sollten ein neu erstelltes Projekt sehen. Jetzt möchten wir das NestJS-Preset als Entwicklungsabhängigkeit in unserem Projekt installieren.
yarn add –dev @nrwl/nest
Sobald es installiert ist, können wir eine neue Anwendung generieren.
nx generate @nrwl/nest:app backend
Wir werden auch eine Node-App als Bibliothek erstellen.
yarn add –dev @nrwl/node
nx generate @nrwl/node:lib utils
Nx hat die gesamte Konfiguration für uns generiert. Wir können jetzt ganz einfach alles aus der Utils-Bibliothek in jedes andere Projekt importieren. Unten sehen Sie, wie ich die Beispielmethode aus Utils in den App-Service der NestJS-Anwendung importiert habe.
Wie Sie sehen können, funktioniert unsere App einwandfrei und ist bereit für die Entwicklung. Nx hat alles für uns erledigt und wir können alle Vorteile von Monorepos nutzen.
Projekt ausführen
Der nächste Schritt besteht darin, die App generisch zu machen, damit sie als Ausgangspunkt für jedes andere Projekt verwendet werden kann. Lassen Sie uns einen „template-setup“-Ordner im Hauptverzeichnis unseres Projekts und eine „revert-to-template.js“-Datei darin erstellen. Wir werden auch eine „config.js“-Datei erstellen, in der wir einige Hilfswerte speichern. Die Struktur sollte folgendermaßen aussehen:
Die Ordnerstruktur des Projekts
Was wir jetzt tun möchten, ist, die Projektdateien zu kopieren und die Werte, die anpassbar sein sollen, durch EJS-Variablen zu ersetzen. Wir müssen auch ein „_“-Präfix zu allen Dateien hinzufügen, die Variablen enthalten, damit sie als EJS-Dateien ausgewertet werden können.
Wenn Sie jetzt „node revert-to-template.js“ ausführen, sollten Sie einen neu erstellten Ordner mit ersetzten Dateinamen und unserer Variablen in package.json sehen. Wir werden diesen Befehl jedoch nicht manuell ausführen, er sollte im Github Actions-Workflow behandelt werden, aber das werden wir später behandeln.
Mit der vorbereiteten Vorlage werden wir einen Code schreiben, der sie nutzen und ein Projekt generieren kann. Lassen Sie uns mit der Erstellung einer einfachen package.json-Datei mit zwei Paketen und einer „bin“-Eigenschaft beginnen, damit wir sie als ausführbare Datei ausführen können. Stellen Sie sicher, dass Sie Ihren GitHub-Profil- oder Organisationsnamen in der „name“-Eigenschaft einfügen, da dieser später im CI-Workflow verwendet wird, um den Code zu veröffentlichen.
Schließlich werden wir das „commander“-Paket verwenden, um unser CLI-Programm zu erstellen. Es wird die vom Benutzer bereitgestellten Parameter übernehmen und ein neues Projekt mit dem „scaffe“-Paket generieren.
Wir können jetzt den Ablauf testen, indem wir die Dateien manuell ausführen. Zuerst führen Sie „node revert-to-template.js“ wie zuvor aus. Wechseln Sie nun in das neu generierte Template, installieren Sie die Pakete („yarn install“) und geben Sie „node index.js ~/path-to-project -p ProjectName“ ein. Sie sollten ein Projekt mit dem ersetzten Wert der „name“-Eigenschaft in der package.json-Datei sehen.
Das Letzte, was wir tun müssen, ist, eine CI-Pipeline zu erstellen, die unsere Vorlage auf npm veröffentlicht.
Wenn Sie nicht vertraut sind, was in diesem Snippet vor sich geht, empfehle ich Ihnen, mehr über die Github Actions-Dokumentation zu lesen. Im Wesentlichen habe ich eine „setup-node“-Aktion verwendet, die eine „.nprmc“-Datei erstellt (mehr dazu hier: Veröffentlichen von Node.js-Paketen), unser revert-to-template-Skript ausgeführt und es mit dem automatisch generierten GITHUB_TOKEN-Geheimnis veröffentlicht. Zusätzlich habe ich eine Aktion verwendet, um die Version der package.json automatisch zu erhöhen, damit es keine Konflikte gibt.
Jetzt, wenn wir unseren Code in das Repository pushen, sollten wir einen laufenden Workflow sehen und dann unser veröffentlichtes Paket.
Zusammenfassungsansicht des Github Actions-Workflows
Lassen Sie uns versuchen, es zu installieren und zu sehen, ob alles funktioniert! Denken Sie daran, sich im Registry anzumelden, wenn Sie private Pakete installieren.
Einrichtung und Generierung eines neuen Template-Projekts
Und das war's! Sie sollten ein voll funktionsfähiges generiertes Projekt mit dem ersetzten Wert des Namens in package.json sehen.
Ein Zeichen für einen guten Softwareentwicklungsprozess ist das ständige Streben, Dinge flexibler und skalierbarer zu gestalten, was sich direkt in Kosten- und Zeitersparnissen niederschlägt. Ein Beispiel dafür ist unser generisches Template-Projekt.
Das Beispiel aus diesem Artikel zeigte nur eine einfach generierte Anwendung mit einer Variablen, dem App-Namen. In unserer internen Lösung bei EL Passion haben wir mehrere Anwendungen (Frontend und Backend) mit wiederverwendbaren Modulen und sogar einer Terraform-Konfiguration für die AWS-Infrastruktur vorbereitet, was mehreren Entwicklern Tage an Arbeit erspart.
Bleiben Sie dran für weitere Inhalte!
11 März 2025 • Patrycja Paterska
11 März 2025 • Patrycja Paterska