Projekteinblick: CMS für Coaching App – Development & Deployment Workflow

Juli 20, 2023Einblick

Herzlich willkommen zurück zu unserer fortlaufenden Beitragsreihe, in der wir Sie hinter die Kulissen unserer Arbeit an einem Content Management System (CMS) für eine Coaching-App führen. Nachdem wir uns bisher mit den technischen Aspekten, der Architektur, der Benutzeroberfläche und der Nutzerinteraktion beschäftigt haben, werden wir uns heute dem Development & Deployment Workflow widmen.

Der Development & Deployment Workflow ist ein zentraler Bestandteil bei der Entwicklung einer solchen Anwendung. Er definiert, wie die Software entwickelt, getestet, ausgeliefert und aktualisiert wird. Ein guter Workflow gewährleistet, dass alle Entwicklungen reibungslos, effizient und qualitätsgesichert stattfinden und dass Updates problemlos an die Endnutzer ausgeliefert werden können.

Development Workflow

Aufgabenverteilung & Projektmanagement

Die Entwicklung des Projekts wurde in regelmäßigen 2 Wochen Sprints unterteilt. In dem regelmäßigen Meeting wurde der Ist-Stand mit dem Soll-Stand verglichen und die zu erledigenden Aufgaben definiert und zugeteilt. Für die Übersicht und damit keine Aufgaben untergehen, benutzen wir Asana. Dort können die Features angelegt und in Unteraufgaben aufgegliedert werden. Unter der Zuordnung zu Milestones und festsetzen einer Deadline, blieb so keine Aufgabe auf der Strecke.

Arbeiten mit Git

Gitlab wird verwendet, um gemeinsam am Code zu arbeiten und diesen zu versionieren. Um eine saubere Zusammenarbeit zu ermöglichen, wurde der folgende Arbeitsablauf vereinbart.

Der development Branch dient als Basis für das Projekt. Nichts darf direkt in diesen Feature Branch comittet oder bearbeitet werden. Für neue Funktionen oder Fehlerbehebungen muss ein separater Brach erstellt werden. Dort kann man gemeinsam an dem Feature arbeiten oder das Problem beheben. Zudem muss der Link des Branches in Asana dem entsprechenden Ticket hinterlegt werden.

Nachdem der Code fertiggestellt und getestet wurde, kann ein Merge Request gestellt werden, der von mindestens einem anderen Entwickler geprüft und genehmigt werden muss. Damit die Freigabe erteilt werden kann, muss auch geprüft werden, ob das Changelog entsprechend angepasst worden ist. Ist dies der Fall, wird der Feature Branch in den development Branch verschoben.

Wenn eine stabile Version fertiggestellt ist, kann ein Merge-Request für den main Branch erstellt werden. Hierfür muss die Software ausgiebig getestet und freigegeben werden. Jeder Merge in den mainBrancg entspricht einer neuen Programmversion, die entsprechend hochgezählt wird. Die Programmversion muss während des Merge-Prozesses als Gitlab-Tag angegeben werden.

Clean Code

Während der Entwicklung und bei den Merge Requests, muss der Code regelmäßig überprüft werden. Um gut strukturierten und verständlichen Code zu gewährleisten, werden die SOLID Prinzipien angewandt.

  • Single Responsibilty Principle
  • Open Closed Princple
  • Liskov’sches Substiotions Prinzip
  • Interface Segregation Principle
  • Dependency Inversion Principle

Vor allem die modulare Struktur der Komponenten muss gewahrt blieben. Auch das Auslagern sich wiederholender Logik und Funktionen, sowie das Benutzen von Interfaces, wird von jedem Entwickler gefordert.

Hier ein Diagramm der Interfaces, die geplant und genutzt wurden:

Single Responsibilty Principle

Jede Klasse sollte nur eine Aufgabe bearbeiten. Das stellt eine gute Codestruktur und eine geringere Fehleranfälligkeit sicher. Daher werden Funktionalitäten ausgelagert und in definierten Klassen abgebildet.

Beispielsweise ist der dbHandler.tsx nur für die Kommunikation mit der Datenbank zuständig. Andere Funktionalitäten wie die Authentifizierung, oder der Dateiupload wurden in anderen Klassen umgesetzt. (authHandler.tsx und storageHandler.tsx)

Open Closed Princple

Bei der Entwicklung muss das Open Closed Principle eingehalten werden. Das bedeutet, dass die Elemente – beispielswiese durch die Schnittstelle – erweitert, jedoch nicht verändert werden dürfen.

So wurde bei dem <Kapitel/>Komponent eine Schnittstelle gewählt ({ kapitelId, kapitel, addNewKurs, removeKurs, removeKapitel }), mit der gewisse Funktionalitäten erweitert werden können, jedoch der Komponent selbst nicht verändert werden kann. So können beispielsweise über den kapitel Wert verschiedene Inhalte angezeigt werden, ohne das <Kapitel/> Element selbst zu verändern.

Liskov’sches Substiotions Prinzip

Beim Liskov’sches Substiotions Prinzip muss eingehalten werden, dass Oberklassen die Funktionalität der Unterklassen erweitern, diese jedoch nicht von den Unterklassen eingeschränkt werden. Die Klassen/Typen werden unter /interfaces/index.tsdefiniert. Die Funktionalität darf hierbei nicht eingeschränkt werden.

Ein Beispiel, wie die Klassen aufeinander abgestimmt werden dürfen, wäre dieses:

export type Kurse = {
	name: string;
	image: string;
	data: KapitelType[];
};

export type KapitelType = {
	title: string;
	description: string;
	time: string;
	data: KursType[];
};
export type KursType = {
	kursId: number;
	title: string;
	description: string;
	type: string;
	image: string;
	status: string;
	url: string;
};

Interface Segregation Principle

Um den Code strukturiert und möglichst modular zu halten, werden große Schnittstellen in kleinere modulare Schnittstellen aufgeteilt. Dies wurde beispielsweise bei den Kursen wie folgt umgesetzt: Auf der /kurseSeite sollen alle Kapitel und Kurse zu sehen sein. In der /pages/kurse/index.tsx wurde dafür die grobe Struktur definiert. Die gesammte Struktur mit Kapiteln und Kursen wurden jedoch in den <Kapitel/>Komponenten aufgeteilt, bei dem wiederum ein Teil der Logik in den <KursElement/>Komponenten abgekapselt wurde.

Dependency Inversion Principle

Um den Code so strukturiert wie möglich zu halten, wird das Dependency Inversion Principle angewand. Das bedeutet, dass definierte Interfaces statt einzelne Klassen / Objekte genutzt werden. Für oft genutzte, sich wiederholende, aber doch mit unterschiedlichen Inhalten gefüllten Objekten, haben wir Interfaces unter /interfaces/index.tsdefiniert.

Damit stellen wir die Struktur und Typisierung der Objekte sicher und können diese flexibel mit Inhalten füllen.

Hier ein Diagramm der Interfaces:

Test- & Qualitätskontrolle

Bevor ein Feature Branch in den developmentBranch gemerget werden kann, muss sichergestellt werden, dass keine Fehler oder Verstöße gegen die HCI-Richtlinien enthalten sind. Zu diesem Zweck wird der Code vor der Freigabe von einem anderen Entwickler/Designer geprüft.

Zusätzlich muss sichergestellt werden, dass genügend automatisierte Tests zur Verfügung stehen, um die entsprechenden Code-Passagen zu überprüfen. Je nach Gegebenheit sind Unit- oder E2E-Tests erforderlich. Das Gleiche gilt für die Freigabe in den mainbranch.

Deployment Workflow

Git Pipeline

Wir haben eine Git Pipeline aufgesetzt und diese in drei Bereiche aufgeteilt: Setup, Test und Build. Die genau Konfiguration finden Sie unter /.gitlab-ci.yml.

Setup

Im Setup-Abschnitt werden die Node Modules installiert, die für die nachfolgenden Schritte benötigt werden.

Test

Im Test-Abschnitt wird zunächst ein Type-Check durchgeführt und überprüft, ob alle von TypeScript definierten Bedingungen erfüllt sind. Ob Types und Interfaces definiert wurden, ob Imports stimmen und diese bei den Schnittpunkten und Aufrufen übereinstimmen.

Außerdem werden die Unit-Tests ausgeführt, die unter /__tests__ definiert werden. Hier werden die einzelnen Komponenten und Funktionen getestet.

Diese beiden Prozesse werden simultan ausgeführt, um ein effektives und schnellen Testprozess zu gewährleisten und direkt sämtliche Probleme erkennen zu können.

Die End-to-End Tests werden nur bei Bedarf ausgeführt, da diese deutlich mehr Zeit benötigen um durchzulaufen und jedes mal mehrere .mp4-Dateien generieren. Diese werden gespeichert und in Form von Artifacts zum Download bereitgestellt.

Fazit

Als Abschluss unserer tiefgreifenden Betrachtung des Development & Deployment Workflows unseres CMS für die Coaching-App, können wir festhalten, dass eine sorgfältige Planung, einheitliche Praktiken und die Nutzung effektiver Tools entscheidend für den Erfolg des Projekts waren. 

Die strikte Anwendung der SOLID-Prinzipien hat dabei geholfen, dass unser Code sauber, modular und erweiterbar bleibt, wobei der Einsatz von Asana und GitLab unsere Teamarbeit und Prozesskontrolle wesentlich verbessert hat. Wir haben das Projekt in sorgfältig geplante Sprints gegliedert, wobei jede Aufgabe klar definiert und zugeordnet wurde, um sicherzustellen, dass keine Aufgabe verloren ging.

Die Arbeit mit getrennten Branches und die strikte Durchsetzung von Code-Reviews vor dem Merging haben dazu beigetragen, dass die Code-Qualität auf einem hohen Niveau gehalten wurde. Die Nutzung von automatisierten Tests, sowohl Unit-Tests als auch E2E-Tests, war ebenfalls ein wichtiger Bestandteil unserer Qualitätskontrollpraktiken.

Die Aufteilung unserer Git-Pipeline in Setup, Test und Build hat es uns ermöglicht, einen reibungslosen und effektiven Deployment-Prozess zu gewährleisten. Dies hat nicht nur dazu beigetragen, dass unsere Anwendung schnell und effizient ausgeliefert wurde, sondern auch dazu, dass wir schnell auf eventuell auftretende Probleme reagieren und diese beheben konnten.

Im Großen und Ganzen zeigt dieses Projekt, wie wichtig ein gut definierter und durchgeführter Workflow ist, um ein erfolgreiches Softwareprojekt zu liefern. Es unterstreicht die Bedeutung einer guten Teamkommunikation, klarer Strukturen und Standards, sowie effektiver Prüf- und Qualitätskontrollverfahren. Es hat uns gezeigt, dass, wenn all diese Elemente gut durchgeführt werden, sie dazu beitragen können, ein robustes, qualitativ hochwertiges und erfolgreiches Produkt zu liefern.

Let’s talk business

Kontaktieren Sie uns und lassen Sie sich bei einem kostenlosen Erstgespräch von uns beraten. Wir freuen uns darauf, Sie kennenzulernen.

“Gemeinsam gestalten wir ihre digitale Identität”

Philipp Zimmermann

Philipp Zimmermann

Ihr Ansprechpartner

10 + 5 =