Einen Facebook oder Airbnb Klon bauen in weniger als einem Tag? Das wäre zu Gründungszeiten dieser milliardenschweren Plattformen nicht denkbar gewesen. Heute schon - dank No-Code Tools. Mit Bubble, Flutteflow, WeWeb und Co. kann heute jeder mit einem Computer und einer Internetverbindung eine eigene App entwickeln.
VisualMakers Community Projekte wie GuestGoods, CircleHand oder DreamyTales zeigen, dass es geht. Dabei machen es moderne Front-end Editoren und fertige Templates unfassbar einfach, eine schöne App Experience zu kreieren. Allerdings gehört zu einer App, die mehrere tausend User hosten soll, mehr als nur schöne Farben und ordentliche Tabellen.
Wenn auch nicht von Beginn an bemerkbar, ist die Performance - überwiegend in Ladezeiten ausgedrückt - etwas, was oft nicht mitbedacht wird, wenn man die ersten App-Entwürfe macht. Viele Citizen Developer lernen oft leider nicht (oder erst zu spät), wie man eine App auf ihre Performance optimiert. In diesem Blogpost gehen wir deshalb auf einige der Best-Practices ein, die dir helfen, die Ladezeit deiner App zu optimieren.
Die Inhalte in diesem Artikel beziehen sich dabei gar nicht explizit auf No-Code Development, sondern kommen aus der klassischen Entwicklung. Diese Liste ist mit Sicherheit auch nicht vollständig. Wir freuen uns also, wenn du eigene Tipps hast, die du mit uns teilen kannst. Komm’ dafür einfach in unsere Slack Community.
Zunächst geht es um das Front-end. Das betrifft alles was zu sehen ist, wie Bilder, Texte oder Tabellen, aber auch unsichtbare Front-end Elemente wie Container bzw. Div-Blöcke.
Reduziere die Anzahl der Elemente, die du auf einer Seite hast, auf das hinreichende Minimum. Denn je mehr Elemente geladen werden müssen, desto länger die Ladezeit und langsamer die App. Jedes Element benötigt Ladekapazität, aber auch nicht sichtbare Elemente wie Div-Blöcke können die Performance herunterziehen. Überlege also gut, ob du andere Elemente wie Texte oder Bilder zwingend in ihren eigenen Div-Blöcken oder Containern einschließen musst.
Wenn das Design deiner App ohnehin schon minimalistischer Natur ist, dann kommt dir das zugute. Wenn nicht, dann musst du das richtige Gleichgewicht finden zwischen Aussehen und Performance. Dabei solltest du Performance im Zweifel priorisieren. Frei nach dem Motto “Ist das Kunst, oder kann das weg?”
Am Ende willst du ja eine leistungsstarke App bauen, die schön aussieht, aber kein nutzloses Kunstwerk. Aussehen ist nicht alles!
Hier geht es nicht um PKWs, sondern die Auto-Einstellungen von Elementen, z.B. die automatische Höhe oder Breite eines Containers. Diese Einstellung kostet dich Performance, denn das zu berechnen braucht Kapazität. Diese Arbeit kannst du deinem Browser abnehmen, in dem du mit absoluten Dimensionen arbeitest, z.B. height: 150px statt height: auto. Ähnliches betrifft z.B. auch eine fixe Anzahl an Rows oder Columns in einer Tabelle. Fixe Zahlen werden weniger Kapazität brauchen, als eine relative Anzahl, die erst noch berechnet werden muss. Das ist natürlich nicht immer die beste Lösung. Wenn es aber eine funktionierende Möglichkeit ist, dann solltest du das bevorzugen. Immer in Hinsicht auf die Responsiveness der App, versteht sich.
Bleiben wir beim Design. Animationen sind ein wichtiger Teil des Look-and-Feel einer Website oder App. Manchmal haben diese den entscheidenden Coolness-Faktor. Aber wie du dir vielleicht schon denken kannst, hat diese Coolness ihren Preis: Abstriche in der Performance.
Auch hier gilt also: Was ist zwingend notwendig und was nur ein nice-to-have? Jeder Wobble-Effekt bei einem Button wird die Performance schmälern. Und seien wir mal ehrlich; niemand mag zittrige Buttons.
Wie du eben gelernt hast, ist Aussehen längst nicht alles. Auch auf die inneren Werte kommt es an. Und bei diesen inneren Werten kommt es ganz schön darauf an, ob es z.B. 3,5 Megabyte oder 40 Kilobyte sind (zur Erinnerung: 1000 Kilobyte sind 1 Megabyte).
Die Rede ist von Dateigrößen. Das betrifft alle Arten von Medien, die du hochlädst. Das sind meistens Bilder, Logos, Videos, GIFs oder herunterladbare Dateien, z.B. als PDF-Form.
Komprimiere diese Dateien immer, bevor du sie hochlädst. Dafür gibt es viele kostenlose Online Services wie z.B. compresspng.com. Für Bilder und Logos empfiehlt es sich außerdem, kleine Dateiformate wie SVG oder das von Google entwickelte WebP zu nutzen.
Es gibt Elemente, bei denen du die Sichtbarkeit von verschiedenen Faktoren abhängig machen möchtest. Doch um die Performance deiner App zu verbessern, solltest du eigentlich nicht in Sichtbarkeit, sondern in Präsenz denken. Damit gemeint ist, dass du gewisse Elemente, die eine bedingte Sichtbarkeit haben, nicht erst einmal lädst und auf nicht-sichtbar stellst, sondern gar nicht erst renderst.
Hast du z.B. verschiedene Ansichten eines Elements für verschiedene Nutzergruppen (Admin-Ansicht, Visitor-Ansicht o.ä.), könntest du umgehen, dass alle Ansichten geladen, aber unsichtbar sind, in dem du das Rendern an die Nutzer-Bedingung knüpfst. Dann lade gewisse Elemente gar nicht erst.
Das Gleiche gilt natürlich auch für Daten. Wenn du auf Daten zugreifen musst, stell sicher, dass du nur die Daten lädst, die du brauchst, anstatt alle Daten zu laden und dann zu filtern. Das hat nicht nur den Vorteil der verbesserten Performance, sondern auch den des Datenschutzes. Denn auch wenn bestimmte Daten im Frontend nicht zu sehen sind, kann man sie eventuell im Quellcode finden, wenn sie geladen worden sind und keine Sicherheitsvorkehrungen getroffen wurden.
Du kannst z.B. "Only when" Bedingungen nutzen, bevor du Daten aus dem Back-end abrufst. Die langsamere Alternative wäre, alle Daten abzurufen und sie dann zu filtern.
Wenn wir schon beim Thema sind.
Das Laden von Daten ist das, was oft die meiste Rechenleistung in Anspruch nimmt. Deshalb werden Verbesserungen, die beim Laden von Daten Anwendung finden, den größten Einfluss auf die Leistung deiner App haben. Einfach ausgedrückt, musst du sicherstellen, dass du nur die Daten lädst, die du zu jenem bestimmten Zeitpunkt auf der Seite benötigst.
Daten liegen im Back-end und deshalb kannst du vor allem dort leistungsrelevante Anpassungen machen, um die Performance deiner App zu steigern. Zum einen ist da der Faktor, welche Datenbank du wählst und wie du deine Datenbank strukturiert. Das ist aber ein Thema für sich.
Wenn das bereits erledigt ist, dann kannst du z.B. sicherstellen, dass du den API-Endpunkt optimierst, der die Daten aus deinem Back-end abruft. Dabei geht es vor allem darum, das Datenvolumen, das du ans Front-end sendest, auf das absolute Minimum zu reduzieren. Sende immer nur die Spalten oder Felder, die du für die jeweilige Operation benötigst.
Bei einem Tool wie Bubble, welches im Vergleich zu WeWeb nicht zwingend ein externes Back-end benötigt, kann das etwas anders aussehen. Dort brauchst du keine API, sondern kannst über den Editor direkt mit der Bubble-eigenen Datenbank kommunizieren. In diesem Fall ist aber relevant, wie du deine Befehle ausdrückst. Ob du z.B. “Do a search for” oder “List of” auswählst, macht einen Unterschied. Hier in Kurzfassung:
“List of” lohnt sich, bei kurzen Listen. Willst du beispielsweise die Lieblingsfarben von Usern anzeigen lassen, dann nimm “List of”. In diesem Fall könnte der Ausdruck lauten “Current User’s (list of) Lieblingsfarben”. Liste mit wenigen (1-30) Einträgen, lassen sich damit schneller laden.
“Do a search for” lohnt sich, bei langen Listen. Willst du beispielsweise die Kaufhistorie eines Users anzeigen, dann nimm’ “Do a search for”. Der Ausdrück könnte dann lauten: “Do a search for Käufe” + die Bedingung, dass der Käufer = Current User ist.
Join Operationen rufen Daten aus zwei oder mehr Tabellen ab, basierend auf einem gemeinsamen Feld. Das Resultat sind Ergebnistabellen, die Daten aus mehreren Tabellen kombinieren. Das zu tun, kostet Leistung. Es mag bei 3 Tabellen und 1.000 Datensätzen vielleicht noch nicht ins Gewicht fallen, doch wenn du skalieren möchtest, könnte das den entscheidenden Unterschied machen.
Also vermeide diese Leistungskiller, wo immer du kannst. Wenn du Informationen in einer einzelnen Tabelle darstellen oder benötigte Daten getrennt voneinander abrufen kannst, dann tu das. Nur in absolut notwendigen Fällen benutze join Operationen.
Wenn du z.B. in Bubble eine Repeating Group mit Daten füllst oder in WeWeb eine Collection anzeigen möchtest, dann werden die Daten per Default geladen, selbst du sie auf “display-none” stellst.
Für Seiten, bei denen die Leistung besonders kritisch ist, z.B. wo große Tabellen vorkommen, empfiehlt es sich deshalb, den Ladevorgang von Datensammlungen an Benutzerinteraktion zu knüpfen. Dann laden Daten nur bei Bedarf und nicht automatisch. Zum Beispiel lädt eine Tabelle erst, wenn der User dorthin scrollt oder auf einen “View Data” Button klickt. In WeWeb hat man hierfür die Option von Conditional Rendering.
Hast du mehrere Seiten in deiner App oder aber z.B. eine Tabelle, bei der man zwischen Seiten hin und her wechseln kann, stellt sich die Frage, wie du am besten die Daten dafür lädst. Hierbei gibt es folgende Optionen:
In diesem Fall werden alle Daten im Browser geladen und auf den entsprechenden Seiten dargestellt - selbst das, was du nicht siehst. Das bietet sich bei kleinen Datenmengen an. Wenn es sehr viele Daten sind, wird die Leistung massiv verlangsamt oder der Browser stürzt sogar ab.
Es kann von der UI/UX her ggf. dennoch Sinn ergeben, z.B. eine lange Tabelle zu erstellen, statt verschiedene Seiten zu nutzen. Das sollte aber immer in Abwägung zur Performance-Minderung getan werden.
Eine gute Möglichkeit, die Ladezeit zu vermindern, ist ein sog. Lazy Load. Bei einem Lazy Load werden nur die Daten geladen, die im Teil des Browsers sind, der für den User sichtbar ist. Scrollt er oder sie runter, werden mehr Daten geladen. Lazy Loads eignen sich vor allem für Bilder oder lade-intensive Tabellen, die nicht gleich zu sehen sind.
In diesem Fall werden alle notwendigen Daten in den Browser geladen, aber es wird nur das gerendert, was sichtbar sein soll. Das verlangsamt zwar das anfängliche Laden der Seite, wenn User aber auf eine andere Unterseite oder Tabellenseite wechseln, sind die Daten schnell sichtbar, da sie schon geladen wurden.
Hier werden immer nur die Daten geladen, die angezeigt werden sollen. Das beschleunigt das anfängliche Laden, verlangsamt aber das Laden zwischen Seiten. Dennoch ist das oft die beste Option, um die Wahrnehmung der Ladezeiten gering zu halten.
Skeleton Loaders sind visuelle Platzhalter, die User sehen, solange die eigentlichen Daten noch geladen werden. Das Ganze dient nicht dem Zweck der Performancesteigerung, sondern einer verbesserten User Experience.
Du kennst das vielleicht von der LinkedIn Mobile App. Öffnest du diese, wirst du zunächst nur graue “Hüllen” von dem sehen, was angezeigt wird, sobald die nötigen Daten dafür da sind.
Oft sind diese mit einem pulsierenden Effekt o.ä. dezent animiert. Das Skelett inklusive der Animation lässt den User wissen, dass sich etwas tut und macht, finden wir, einen besseren Eindruck als klassische Loading Icons.
In diesem Tweet erklärt Gregory John von Buildcamp, wie man Skeleton Loaders in die eigene Bubble App einbauen kann.
Wie oben erwähnt, ist diese Liste nicht vollständig und sicherlich auch nicht der 100% richtige Leitfaden für jede App. Deshalb ist unser letzter Tipp: teste es. Alles, was du dafür brauchst, sind zwei Versionen einer App oder Page, die du gegeneinander testen willst und eine gute alte Stoppuhr. Dann testest du diese über verschiedene Browser und Geräte hinweg. Entweder kommt daraus ein klarer Sieger hervor, oder du lernst etwas darüber, wie sich gewisse Anpassungen bei verschiedenen Interventionen (Browser, Geräte) verhalten.
Wir hoffen, diese Tipps helfen dir dabei, dein No-Code Sideproject zu einer leistungsfähigen App zu skalieren, die es mit Airbnb, Facebook und Co. aufnehmen kann - leistungsmäßig und ganz vielleicht sogar mal Revenue-mäßig!
Falls du also Fragen hast zu deinem Projekt, schreib uns gerne! Komm dafür in unsere Slack Community. Dort warten über 750 andere No-Code-Enthusiast:innen auf dich und deine Fragen.
Oder buch’ dir einen Call mit uns. Vielleicht können wir dir dabei helfen, dein nächstes Projekt umzusetzen und zu skalieren!