Möchten Sie mehr darüber erfahren, wie wir Ihnen helfen können?
Zum Schluss kommt der spaßige Teil. Sobald wir die User Stories und Wireframes, den geschätzten Zeit- und Kostenrahmen, den Technologie-Stack und einen gründlichen Plan haben, können wir sie in die Tat umsetzen. Dies ist die Geschichte, wie MVPs codiert werden und die Best Practices, die es ermöglichen, dass dieser Code auch auf den Geräten aller anderen funktioniert.
Zur leichteren Lesbarkeit haben wir es in vier Stufen unterteilt:
Und natürlich ist ein Hauch von agilem Projektmanagement nötig, um 1 bis 4
zusammenzuhalten. Obwohl er nicht direkt an der Entwicklung beteiligt ist, ist der Projektmanager
dafür verantwortlich, die Arbeit durch den gesamten Prozess und bis zum Abschluss zu führen.
Für MVPs bedeutet dies, alle Schritte für eine erfolgreiche Markteinführung zu durchlaufen, mit
testbaren Meilensteinen und einem klaren Zeitplan, um die Time-to-Market zu verbessern. Sobald das
MVP zu wachsen beginnt, führen wir eine kontinuierliche Entwicklung durch, mit kleinen Iterationen
und regelmäßigen Deployments, um so viel Feedback wie möglich zu sammeln. Wenn Sie dachten, dass die
Softwareentwicklung nach dem Marktstart endet, liegen Sie falsch. Software-Entwicklung endet nie.
Niemals! :)
Wie Sie vielleicht aus den vorangegangenen Artikeln bemerkt haben, gibt es
eine Menge Dinge, die eingerichtet werden müssen, bevor die eigentliche Entwicklung beginnen kann.
Tatsächlich sind es so viele, dass es sich so anfühlt, als wäre der größte Teil der Arbeit schon
erledigt, bevor die eigentliche Arbeit beginnt. Aber glauben Sie uns, der größte Teil liegt noch im
Code. Deshalb muss alles optimal eingerichtet werden.
Zu Beginn eines Projekts/MVP verbringen Entwickler oft eine gewisse Zeit mit dem Einrichten. Das
kann alles bedeuten, von "Oh, ich richte gerade die Build-Automatisierung ein" bis zu "Bitte nicht
stören. Ich kümmere mich um das Abhängigkeitsmanagement und habe noch keinen Kaffee getrunken".
Während es tausende von Tools gibt, um "die Grundlagen" einzurichten, sind die zeitaufwändigsten
Teile immer die projektspezifischen. Das liegt daran, dass die Entwickler die richtige Umgebung, das
richtige Werkzeug, die richtigen Bibliotheken und die grundlegende Codestruktur für die aktuell
benötigten Funktionalitäten einrichten müssen, basierend auf einem bestimmten Technologie-Stack und
gemäß der vereinbarten technischen Lösung. Wir beziehen die Einrichtung immer in unsere technischen
Kostenvoranschläge ein (mehr zu Kostenvoranschlägen hier),
gerade weil der Zeitaufwand dafür von Projekt zu Projekt variiert.
Abgesehen von den spezifischen Anforderungen gehen wir bei der Einrichtung des Ökosystems für ein Web-Entwicklungsprojekt in der Regel nach einer der folgenden Varianten vor:
Entwickler schreiben Code. Der Code wird sicher gespeichert und mit Hilfe
eines Versionskontrollwerkzeugs, normalerweise Git, freigegeben. Stellen Sie sich Git als ein
wirklich fortschrittliches Google Docs vor, ein Tool, mit dem Sie zusammenarbeiten, eine Historie
der Änderungen verfolgen, Änderungen überprüfen oder zu einer früheren Version zurückkehren können.
Im Gegensatz zu Google Docs erlaubt Git jedoch die Koexistenz mehrerer Versionen der "Wahrheit". Im
Wesentlichen hat jeder Entwickler eine Kopie des Repositorys, im Gegensatz zu Google Docs, wo jeder
an einer zentralisierten Kopie arbeitet. In Git können Sie z. B. mehrere Versionen der Software
gleichzeitig in Produktion haben oder Fehlerbehebungen für eine frühere Version liefern.
Da jeder Entwickler seine Version der "Wahrheit" hat, muss es einen Weg geben, Konflikte zu
vermeiden. Es müssen einige Regeln aufgestellt werden, um die Arbeit mit so vielen Versionen weniger
verwirrend zu machen. Diese Regeln werden Gitflow genannt. Gitflow ist nur eine von mehreren
Möglichkeiten, den Arbeitsablauf des Verzweigens und Zusammenführens zu verwalten, aber es ist
wahrscheinlich die beliebteste.
Einfach ausgedrückt, ist Gitflow ein Satz von Regeln, die jedes
Teammitglied befolgt, wenn es ein Stück Code einreicht. Gitflow legt fest, was an einen bestimmten
Zweig übermittelt werden soll und wie ein Zweig noch weiter verzweigt oder in einen anderen Zweig
zusammengeführt werden soll. Dies ist wirklich nützlich, um die Versionskontrollpraktiken zwischen
den Teams zu standardisieren und um das Onboarding von Projekten zu beschleunigen. Im Grunde
genommen weiß man, wo sich alles befindet, ohne dass man auf die Projektspezifika eingehen
muss.
Das grundlegende Gitflow-Modell besteht aus zwei Hauptzweigen (Master und Develop) und drei
Arbeitszweigen (Feature, Release, Hotfixes). In einigen Versionen von Gitflow gibt es auch
Support-Zweige, die z. B. dazu dienen, Fehlerbehebungen für ältere Versionen der App anzubieten. Im
Gegensatz zu den Hauptzweigen haben die Arbeitszweige immer eine begrenzte Lebenszeit.
Wir verwenden spezifische Feature-Zweige für jede Aufgabe (mehr zu Aufgaben und Projektplanung hier). Alle Aufgaben werden in ihrem eigenen Feature-Zweig gelöst und wenn das erledigt ist, werden sie in Develop zusammengeführt. Auf diese Weise haben wir einen stabilen Develop-Zweig, der regelmäßige und kontinuierliche Releases unterstützt.
Damit Code tatsächlich in einem Versionskontrollsystem gespeichert werden kann,
muss er zunächst eingereicht und dann genehmigt werden. Man kann Code durch Pull-Requests
hinzufügen. Grundsätzlich bedeuten "Pull Requests", dass Sie den Betreuer des Repositorys bitten,
Ihren Code einzubringen. Pull-Requests enthalten einen oder mehrere Commits.
Eine Pull-Request ist immer mit einem Zweig verbunden. Mit anderen Worten, eine Pull-Request ist
eine Anfrage, einen Zweig in einen anderen zusammenzuführen und wird nach einem oder mehreren
Commits ausgegeben. Gute Commits folgen dem Single Responsibility Prinzip, was bedeutet, dass ein
Commit eine Sache im Code ändert und nur eine Sache. Sie können dieses Prinzip leicht in Ihrer
Commit-Nachricht testen. Wenn Sie das Wort "und" erreichen, hören Sie auf :)
Wir mögen es, Commit-Nachrichten auf Code-Ebene und auf den Punkt zu halten und
Pull-Request-Beschreibungen für ein übergeordnetes, architektonisches Verständnis der Änderung zu
verwenden. Eine High-Level-Zusammenfassung des Problems ist sehr nützlich für Leute, die durch die
Geschichte des Repositorys gehen, zusätzlich zu den einzelnen Code Änderungen. Das ist der Grund,
warum wir es vermeiden Commits beim Merge zu löschen, damit wir leicht in der Lage sind, die
historischen Änderungen zu verfolgen.
Nachdem ein Pull Request erstellt wurde, kommt ein Teammitglied, um die vorgeschlagenen Änderungen
zu überprüfen. Es gibt unzählige Artikel darüber, wie man gute Pull Requests einreicht, d.h. Pull
Requests, die Ihr Leben und das der Reviewer einfacher machen, aber was wir als besonders nützlich
empfunden haben, sind Pull Request Templates. Wir haben einen ganzen Artikel über das Thema
geschrieben und sogar einige der Pull Request Vorlagen, die wir für Frontend und Backend verwenden,
mit aufgenommen. Um es kurz zu machen, wir verwenden sie als Checklisten; die Person, die einen Pull
Request einreicht, kann die Checkliste durchgehen und sicherstellen, dass nichts wichtiges
ausgelassen wurde.
Der Reviewer kann dann die Pull-Review-Beschreibung lesen, auch die Checkliste durchgehen und sich einen Überblick über den Fortschritt verschaffen, der gemacht wurde. Einen Pull Request zu überprüfen ist genauso eine Kunst wie einen einzureichen. Feedback zu der Arbeit von jemand anderem zu geben, kann knifflig sein, aber wir versuchen immer diese drei einfachen Regeln zu befolgen, wenn wir Pull Requests überprüfen:
Stellen Sie sich vor, Sie wachen eines Tages auf und können Ihre eigene
Handschrift nicht verstehen. Nun stellen Sie sich vor, Sie hätten am Vortag etwas wirklich Wichtiges
aufgeschrieben. So würde es sich anfühlen, wenn Sie auf Ihren eigenen Code zurückblicken, ohne
Codierungsstandards. Multiplizieren Sie dies dutzendfach und Sie erhalten ein ganzes Team von
Entwicklern, die gemeinsam an der gleichen unverständlichen Codebasis arbeiten.
Coding-Standards sind langweilig. Tatsächlich sind sie so langweilig, dass die meisten von ihnen
automatisch von statischen Code-Analysatoren, auch bekannt als Linters, erzwungen werden. Aber sie
existieren aus mehreren Gründen. Einer davon ist die Vernunft, Ihre und die von allen anderen. Der
andere ist die Verringerung der Wartungskosten und der technischen Belastung. Die Wartung eines
Codes macht im Durchschnitt 60% seiner Lebenszeitkosten aus, was bedeutet, dass der Code von einem
Entwickler zahlreiche Male gelesen wird, nachdem er zum ersten Mal geschrieben wurde. Je einfacher
der Code also zu lesen ist, desto billiger ist er am Ende.
Wir setzen Codierungsstandards durch Linters und Code-Peer-Reviews durch. Wie bereits erwähnt, sind
Linters Werkzeuge, die Code gegen einen Satz von Regeln prüfen und Verstöße gegen diese Regeln als
Fehler markieren. Ein Linter kann auch so konfiguriert werden, dass er die Einhaltung eines
bestimmten Style-Guides überprüft, abhängig von der Sprache, in der der Code geschrieben wurde (z.B.
PSR-2 für PHP). Linters sind im Laufe der Zeit viel besser darin geworden, Inkonsistenzen oder sogar
unnötige Komplexität im Code zu erkennen, aber sie haben immer noch ihre Grenzen. Wir verwenden
Code-Peer-Reviews, um Probleme auszusortieren, die sonst von Linters unbemerkt bleiben würden, wie
z. B. fehlerhafte logische Strukturen.
Was passiert, wenn man nicht in Kodierungsstandards investiert? Es entsteht die
Hölle für Softwareentwickler. Sie haben PHP zusammen mit HTML, CSS und Javascript in einer Datei.
Kommentare variieren in ihrer Vagheit von "oopsie" bis "kleinere Änderung" oder "arbeite an Feature
x", gefolgt von 20 Commits hintereinander, ohne dass man sie auseinanderhalten kann. Die Namen von
Variablen, Klassen und Methoden sind inkonsistent und voller Tippfehler und ganze Codeabschnitte
sind auf seltsame Weise eingerückt.
Obwohl sie für Code-Interpreter syntaktisch nicht von Bedeutung sind, sind Kodierungsstandards für
Menschen von Bedeutung. Sie erleichtern das Lesen von Code, indem sie Regeln bezüglich der folgenden
Punkte durchsetzen:
Erinnern Sie sich, wie wir erwähnt haben, dass es eine gute Idee ist, den Code richtig zu
kommentieren? Raten Sie mal! Man kann auch Code-Dokumentation auf der Basis von Kommentaren
erzeugen. Wir empfehlen zwar nicht, dies zur einzigen Dokumentationsquelle zu machen, aber es gibt
einen bequemen Weg, um anzufangen. Technische Dokumentation ist in diesem Sinne ähnlich wie Pizza.
Selbst wenn sie schlecht oder zu wenig ist, ist sie immer noch besser als nichts.
Viele Sprachen haben die Möglichkeit, Kommentare in schön gerenderte Dokumente zu verwandeln, die
auf andere Teile der Dokumentation verweisen können. So etwas wie eine Wikipedia-Seite für den Code.
Wir verwenden Dokumentationskommentare (bekannt als Doc Blocks) insbesondere für die
API-Dokumentation. Je weiter entfernt vom Quellcode Ihre API-Dokumentation ist, desto
wahrscheinlicher ist es, dass sie mit der Zeit veraltet oder ungenau wird. Die beste Strategie ist
also, die Dokumentation direkt in den Code einzubetten und sie dann mit einem Tool zu extrahieren.
Wenn sich User Stories auf die Erfahrung des Endbenutzers mit der App konzentrieren, konzentrieren
sich die technischen Dokumente auf die Spezifikationen, die dies ermöglichen. Meistens werden
mehrere Funktionalitäten benötigt, um die in der User Story beschriebene Aktion zu liefern. Und in
fast allen Fällen fließen mehrere Entwicklungsentscheidungen in eine Funktionalität ein. Nehmen Sie
zum Beispiel die einfache Aktion des Einloggens. Welche Art der Anmeldung soll implementiert werden,
E-Mail und Passwort oder Social Login? Sollen die Eingabefelder Einschränkungen haben? Wie sollen
sie Fehler erkennen und behandeln, wie z.B. ungültige E-Mail-Adressen? Wie lange sollen die
Informationen für die "Remember Me"-Option gespeichert werden? Unterm Strich lassen sich technische
Dokumentationen nicht vom Entwicklungskontext trennen. Deshalb schreiben wir technische
Dokumentationen, während wir programmieren, und wir halten sie während des gesamten
Entwicklungsprozesses auf dem neuesten Stand.
Für Community-Projekte, wie APIs, Bibliotheken oder einige der Open-Source-Arbeiten, die wir gemacht
haben, ist die erste Interaktion, die jemand mit dem Projekt hat, normalerweise durch die
README-Datei. In solchen Fällen ist eine gut strukturierte, gut geschriebene README-Datei der erste
Schritt, um Ihr Produkt einem größeren Publikum vorzustellen. In der Tat nehmen einige diesen
"ersten Schritt" wörtlich und plädieren für eine README-getriebene Entwicklung. Im Folgenden finden
Sie eine einfache Vorlage für das Schreiben von leicht lesbaren und nützlichen README-Dokumenten.
Wie das Sprichwort sagt, ist der Zweck des Testens nicht, Dinge zu
zerstören, sondern die Illusion zu zerstreuen, dass Dinge funktionieren. Das kann von der
Sicherstellung, dass Ihre App nicht abstürzt, sobald jemand seinen Namen in ein Eingabefeld
schreibt, bis hin zu den obskursten Randfällen reichen.
Die Welt der Software-Qualitätssicherung ist riesig. Es gibt jedoch drei grundlegende Ebenen, auf
denen eine App von Entwicklern getestet wird, bevor sie ihre Arbeit jemand anderem zeigen, d. h.
bevor die App von Endbenutzern oder dem Kunden getestet wird, auch bekannt als User Acceptance
Testing (UAT).
Die folgenden Tests werden von Entwicklern geschrieben, um immer komplexere Teile des Codes zu
überprüfen. Sie sind in der Regel in der gleichen Sprache wie die App geschrieben und werden
zusammen mit dem Hauptcode der Software in einem Versionskontrollsystem gespeichert. Normalerweise
schreiben wir die Tests während des Programmierens und sie werden in der gleichen Weise wie unser
gesamter Code überprüft.
1. Unit Tests - sie sind die Bausteine des Software-Testens. Entwickler schreiben Unit-Tests,
um sicherzustellen, dass eine bestimmte Codeeinheit (z. B. Methode, Klasse, Funktion) über einen
Bereich von gültigen und ungültigen Eingaben hinweg wie erwartet funktioniert. Angenommen, Sie haben
eine Funktion 2VAL, die bei zwei Werten, x und y, immer x+y zurückgibt. Der Unit-Test würde die
Funktion mit zwei Eingabewerten ausführen und bestätigen, dass die Ausgabe x+y ist.
2. Feature Tests - sie decken die wichtigsten Funktionalitäten einer Komponente oder eines
Systems ab. Wie die Funktionen funktionieren sollen, kann in der Spezifikation der App oder in der
Produktdokumentation beschrieben werden und kann von sehr technisch (Geben Endpunkte das zurück, was
sie zurückgeben sollen?) bis hin zu selbsterklärend (Funktioniert Social Login?)
3. Integrationstests - Auf einer höheren Ebene als Funktionstests. Sie verifizieren, dass
verschiedene Komponenten Ihrer App, wie Module oder Dienste, gut zusammenarbeiten. Das kann zum
Beispiel das Testen der Interaktion mit der Datenbank sein oder das Sicherstellen, dass
Microservices gut zusammenspielen.
Nachdem sie vom Entwicklungsteam getestet wurden, durchlaufen Apps in der Regel eine Form von User
Experience Testing. Dies kommt so nah wie möglich an das heran, was passiert, wenn die App im Alltag
von normalen Benutzern verwendet wird, von etwas so Einfachem wie dem Absenden eines Formulars bis
hin zu komplexeren Szenarien. Der Zugriff auf die App erfolgt in einer Staging-Umgebung und wird in
der Regel mit Dummy-Daten bestückt. UAT ist Teil dieser Art von End-to-End-Tests und ist in der
Regel eine großartige Gelegenheit für Kunden, dem Entwicklungsteam Feedback zu geben und Funktionen
anhand von Geschäftsanforderungen zu validieren.
Das Testen von Software ist zeitaufwendig. Software von Hand zu testen ist noch schlimmer. Wenn es
doch nur eine Möglichkeit gäbe, Tests nicht nur zu automatisieren, sondern sie auch in Ihren
Entwicklungs-Workflow zu integrieren. Hier kommt CI/CD ins Spiel, kurz für Continuous
Integration/Continuous Delivery oder Deployment. Richtig, CD kann entweder für Delivery oder für
Deployment stehen (verwirrend, wissen wir), abhängig vom Grad der Automatisierung. Aber wir wollen
nicht zu weit vorpreschen. Auf diese Unterschiede werden wir im nächsten Abschnitt noch genauer
eingehen.
Für den Moment ist es wichtig zu wissen, dass CI/CD eine Reihe von Praktiken ist, die es
Entwicklungsteams ermöglichen sollen, Änderungen schneller und mit weniger Konflikten zu liefern,
sowohl auf menschlicher als auch auf Code-Ebene. Die primäre Idee ist es, Build, Test und Deployment
durch Skripte zu automatisieren, um: a.) Bugs, Merge-Konflikte, menschliches Versagen und alles, was
zwischen Ihnen und einem erfolgreichen Release steht, zu minimieren. b.) Code kontinuierlich zu
bauen, zu testen und zu deployen und einfach zurückzusetzen, wenn etwas schief läuft. Das bedeutet,
dass Releases weniger schwierig zu verwalten und weniger riskant sind und daher häufiger stattfinden
können.
Nehmen wir an, der Code ist in einem Git-Repository gespeichert. Die meisten Versionskontrollsysteme
haben heutzutage CI/CD-Tools integriert, wie GitLab CI/CD oder GitHub Actions. Diese Werkzeuge
sorgen dafür, dass Tests automatisch ausgeführt werden, sobald ein neues Stück Code übertragen wird.
Anders ausgedrückt: Man kann ein Stück Code nur dann committen, wenn jeder einzelne Test in der
Codebasis erfolgreich ist und es Tests gibt, die den gesamten neuen Code in der Codebasis abdecken.
Der Punkt hier ist ein doppelter. Erstens, um sicherzustellen, dass der neue Code der gerade
geschrieben wurde, nicht den alten Code kaputt macht. Stellen Sie sich das wie Ihr vergangenes Ich
vor, das Ihr zukünftiges Ich davor bewahrt, etwas Schreckliches zu tun. Zweitens, um automatisch
festzustellen, ob der neue Code Tests hat.
Genau wie beim Bestehen einer Prüfung muss der Code bestimmte Anforderungen erfüllen, um einen Test
zu bestehen. Bei automatisierten Tests werden diese Anforderungen in Skripten als Sequenzen von
Aktionen niedergeschrieben und was erwartet wird, wenn diese Aktionen ausgeführt werden. Um zu
überprüfen, wie viel des Codes tatsächlich durch Skripte abgedeckt ist, wird eine universelle Metrik
verwendet: die Testabdeckung. Diese Metrik berechnet, wie viel von dem Code läuft, wenn die Tests
ausgeführt werden. Die Teile, die nicht laufen (und solche Teile wird es immer geben), werden von
den vorhandenen Tests nicht abgedeckt.
Wenn CI/CD dafür verantwortlich ist, was automatisch gemacht werden kann, diktiert der Workflow zum
Verzweigen und Zusammenführen (erinnern Sie sich an Gitflow?) letztendlich, wie die Dinge
eingerichtet werden sollten. Ein grundlegendes CI/CD-Setup, das einer Gitflow-Logik folgt, könnte
etwa so aussehen:
CI/CD und Gitflow sind wichtige Bestandteile unseres Entwicklungsprozesses. Wir verwenden sie, um sicherzustellen, dass Tests vorhanden sind, Releases problemlos durchgeführt werden können und jeder dem gleichen Workflow folgt. Da es den Druck vom Tag der Veröffentlichung nimmt (keine Notwendigkeit, die Entwicklung für die Veröffentlichung zu unterbrechen, Probleme sind einfacher zu beheben, da sie in kleinen Chargen implementiert werden), ermöglicht es uns, häufiger zu veröffentlichen und viel schneller Feedback von unseren Kunden zu erhalten.
Mit CI/CD können Sie alles vom Bauen und Testen bis hin zum Deployment und
Release automatisieren. "Pipeline" ist ein anschaulicher Begriff, der meist mit CI/CD in Verbindung
gebracht wird. Er wird verwendet, um sowohl den Grad der Automatisierung eines Workflows als auch
die Abfolge der Schritte zu definieren, die ausgeführt werden müssen.
Wir betreiben eine CI/CD-Pipeline, um die wichtigsten Schritte im Bereitstellungsprozess zu automatisieren:
Wir automatisieren die Bereitstellung für Projekte, die häufige Releases und enge Feedback-Schleifen erfordern. Außerdem können wir so sicherstellen, dass alles in der Praxis wie erwartet funktioniert. Das Deployment in eine Produktionsumgebung erst dann durchzuführen, wenn die Entwicklung abgeschlossen ist, bedeutet, dass Sie keinerlei Garantien haben, dass eine bestimmte Version für die Endbenutzer funktioniert. Mit automatisierten Deployments können Sie Ihren Code in einer produktionsähnlichen Umgebung so viele Male wie nötig testen.
Wenn Sie ein Start-up sind, das einen technischen Partner für die Fahrt sucht, suchen Sie nicht weiter. Wir sind darauf spezialisiert, Start-ups bei der Validierung, Einführung und Skalierung ihres MVP zu unterstützen. Kontaktieren Sie uns jetzt, um Ihr Projekt auf den Weg zu bringen.