Das moderne Internet uns seine Probleme. Egal welche Technologie Sie verwenden. React. Angular. Vue. Das Framework ist ein anderes, doch die Probleme bleiben die gleichen. Hier starte ich eine Serie an Blogartikel zum Thema: Die Probleme des modernen Frontends. Wir beginnen mit:
Webapps sind zum Ersatz für viele Desktopanwendungen geworden. Fast alles, was früher als Programm auf ihrem PC installiert wurde, gibt es heute im Browser. Einiges davon nur noch im Browser. Daraus ergibt sich, dass Webapps immer größer und komplexer werden. Sie skalieren.
Mit einer wachsenden Webapp stellen sich fast immer die gleichen Probleme ein. Die Entwicklung wird langsamer. Neue Features werden immer schwerer zu implementieren. Ein riesiger Haufen Technical Debth türmt sich auf.
Rewrite? So weit wollen wir es hier gar nicht kommen lassen. Den Umgang mit einer legacy Codebase sehen wir uns in einem weiteren Artikel an.
Wir gehen nun auf Probleme ein, die sich bei wachsenden Webapps häufen und besprechen auch die Möglichkeiten diesen vorzubeugen.
Der Traum eines jeden Entwicklers. Die perfekte Komponente / Service / Library die sich beliebig oft wiederverwenden lässt und nur einmal existiert. Also kein duplicated Code.
Wir alle streben nach der einen eleganten Klasse, um alles abzudecken. Die Suche danach beginnt mit einer recht einfachen Implementierung. Simpel, effizient und elegant. Es dauert nicht lange bis der Code erweitert wird. Größer aber immer noch elegant.
Bisher hatte der Entwickler ein definiertes Problem und löst dieses mit genau diesem Code. Projekte bestehen aber nicht nur aus Entwicklern. Es gibt Einflüsse von außen. Projektleiter, CEO, Designer, Marketing. Der schlimmste aller Einflüsse: Kunden.
Auch die beste und genauste Anforderung ist nicht in Stein gemeißelt. Anforderungen ändern sich. Das ist einfach so und wir können nichts dagegen machen. Der Code des Entwicklers, diese eine elegante und effiziente Klasse entspricht nun nicht mehr ganz den Anforderungen, denn es kommen neue Features hinzu oder bestehende werden verändert.
Der Entwickler erweitert also seinen Code. Die Basis bleibt, doch nun gibt es einen Spezialfall. Wenn X eintritt, macht der Code ausnahmsweise Y. Das passiert noch ein paar mal und plötzlich gibt es mehrere Spezialfälle. Gleichzeitig ist die Klasse in vielen Teilen der Webapp in Verwendung.
Jetzt stehen wir vor einem Dilemma. Diese elegante, wiederverwendbare Klasse ist unwartbar geworden und skaliert nicht weiter. Der Entwickler überblickt kaum noch die Spezialfälle. Wenn an einer Seite etwas geändert wird, bricht an einer ganz anderen Stelle in der App plötzlich ein Mechanismus, den man gar nicht bedacht hatte.
Jetzt kommt der berühmt Rewrite der alles wieder elegant und einfach macht. Nur funktioniert das in den wenigsten Fällen. Außerdem bedeutet es zusätzlichen Aufwand, den niemand bestellt hat.
Wiederverwendbarer Code ist nur gut, wenn er klein und gut isoliert ist. Kleine UI Komponenten wie Buttons sind gut und einfach wiederverwendbar
Isolation ist das Stichwort. Lässt sich ein Stück Code gut isolieren, so kann es meist auch gut wiederverwendet werden. Hier kann man sich an der funktionalen Programmierung orientieren. Wiederverwendbarer Code sollte keine Sideeffects haben. Bei gleichem Input muss immer der gleiche Output kommen.
Sobald eine Komponente intern auf Daten zugreift, worauf der Verwender von außen keinen direkten Einfluss hat, entstehen Spezialfälle und die Komponente wird unwartbar.
Duplicated Code kann durchaus förderlich für die Skalierbarkeit sein. Die Zeiten von zu wenig Speicher sind längst vorbei. Wir können es uns leisten uns zu wiederholen.
Der riesige Vorteil von duplicated Code ist der Spillover. Die Implementierung auf Seite A ist völlig isoliert von er Implementierung auf Seite B. Ergeben sich nun Änderungen auf Seite A kann ich die Implementierung ohne Bedenken vornehmen. Ich weiß, dass diese Änderung nirgendwo anders greift als genau dort wo ich sie brauche.
Trauen Sie sich Code zu duplizieren, wenn er in sich nicht gut zu isolieren ist. Die Entscheidung fühlt sich oft wie Glücksspiel an, doch die Nachteile und aufzuwendende Zeit eines Rewrites sind weitaus größer als der Mehraufwand mehrere Implementierungen zu pflegen. Im Zweifelsfall duplizieren.
Styling von großen Webapps ist fast immer ein Problem. Es gibt theoretische Herangehensweisen, die fast nie zu 100% funktionieren.
Fertige Libraries wie Bootstrap erreichen meist nach der Prototyping bzw. MVP Phase ihre Grenzen. Man baut parallel zu Bootstrap eine eigene Library an Extensions, die dann einfach nur ein unwartbares Chaos wird.
Atomic CSS funktioniert zwar in der Theorie gut, wird aber meist schlecht umgesetzt. Ich kenne niemanden der es wirklich geschafft hat mit selbstgeschriebenen Atomic CSS eine ganze Seite zu stylen. Aus Atoms werden Molecules und Organisms und plötzlich sind wir wieder bei Spezialfällen die sich gegenseitig beeinflussen.
Ein Design System wird als heiliger Gral gesehen. Es gibt fix definierte Komponenten, die immer wieder verwendet werden. Diese Herangehensweise wäre eigentlich perfekt, erfordert aber unglaublich viel Disziplin von Designern, Entwicklern und Project Managern. Schlussendlich endet es wieder bei zusätzlichen Spezialfällen, die mit der Zeit unwartbar werden.
Meiner Meinung nach gibt es nur 3 Möglichkeiten um Styles wirklich skalierbar und wartbar zu machen.
BEM. Block Element Modifier. Ein wirklich überstrapazierter Begriff der eine Zeit lange auf jeder Stellenausschreibung stand und als Buz-Word genutzt wurde. BEM lässt viel Freiraum aber definiert zugleich Regeln im Naming die es einfacher machen Styles zu isolieren und Spillover zu vermeiden. BEM erzeugt viel duplicated Styles. Das ist aber gar nicht schlecht, denn nur so lassen sich Styles warten, ohne die Gefahr ständig an anderen Stellen der App etwas zu brechen.
Ein Utility Framework wie Tailwind CSS. Selbstgeschriebenes Atomic CSS ist der Horror, doch dieses fertige Framework bringt alles, was das Herz begehrt und lässt sich nach klaren Regeln erweitern. All die schlechten Erfahrungen mit Atomic CSS lassen sich hiermit entfernen. Die Wartung im HTML ist etwas aufwendiger, dafür lässt sich Spillover zu 100% vermeiden. Die Styles sind eng an das HTML gekoppelt und bilden somit eine übersichtliche Codebase.
Mein persönlicher Favorit: CSS Modules. Diese Technologie findet häufig bei Webapp mit React, Angular, … Einsatz. CSS Modules forcieren durch Technik die Isolation einzelner Stylesheets, somit gibt es garantiert kein Spillover. Dadurch können die Klassennamen im CSS kurz und prägnant für die jeweilige Komponente gewählt werden. Klassennamen können sich in mehreren Files wiederholen, das Postcss Module kümmert sich um die Isolierung. Das CSS bleibt einfach zu lesen und bietet einen einfachen Einstieg gegenüber dem Atomic CSS oder BEM Ansatz.
Die Struktur des Projekts hat keinen direkten Einfluss auf die Code-Qualität. Einige Frameworks und Best Practices geben die Struktur von Ordnern und Files klar vor. Ich habe für mich die perfekte Struktur gefunden, um den Überblick zu behalten.
Das wirkt sich nicht auf die Qualität des Codes, aber auf die Performance des Entwicklers aus. Wer schon mal Code gedebugged hat und dabei +3 Files gleichzeitig offen hatte weiß, dass das Wechseln in einen anderen Kontext immense geistige Anstrengung fordert.
Erwiesenermaßen kann ein Entwickler nicht mehr als 3 Files gleichzeitig im Kopf behalten. Noch schlimmer ist es, wenn diese Files an ganz unterschiedlichen Orten liegen und wir ständig in der Folder-Struktur scrollen und hin und her switchen müssen.
Der Großvater der Filestructur ist das klassische gruppieren anhand des Codes. Alles Models in einen Filter. Alle Services in einem Folder. Genau das führt dazu, dass Code, der eigentlich eng miteinander verbunden ist, oft weit voneinander getrennt im Filesystem liegt.
Für mich hat sich ergeben, dass die Gruppierung nach dem eigentlichen Einsatzgebiet viel einfacher zu verarbeiten ist. Code, der direkt abhängig ist, sollte auch im selben Folder liegt!
Dadurch verringert sich im Entwicklungsprozess die Anzahl der Kontext-Switches. Der Entwickler bleibt im selben Teilbereich und hat alles, was er braucht die ganze Zeit vor sich.
Der riesige Vorteil zeigt sich gerade in großen Anwendungen, wenn es eine Vielzahl an Seiten, Modulen, … gibt.
Das vermutlich größte Thema in der Frontend-Entwicklung der letzten Jahre verdient einen eigenen Artikel. Mehr dazu bald.
Anwendungen im Web werden von Jahr zu Jahr komplexer. Einerseits berechtigt, andererseits werden sie nur künstlich aufgeblasen. In dieser Reihe werde ich einige dieser Themen beleuchten. Kontaktieren Sie mich, wenn Ihr Unternehmen oder Ihr Team vor genau diesen Herausforderungen steht.
Das Entwickeln von Anwendungen hat sich stark verändert. Mit neuen Möglichkeiten ergeben sich auch neue Probleme. Gerade die Skalierung beschäftigt uns mehr denn je. Eine Webseite ist nicht mehr einfach nur eine Webseite, sondern eine global verwendete Webapp die in Laos die gleiche Performance wie in Berlin bringen soll.
Als Senior Frontend Entwickler in Niederösterreich entwickle ich aktiv an Startups, berate Dev-Teams und helfe ihnen als Freelancer.