Bild von Die Zukunft der Web- und Mobile-Entwicklung

31. Okt 2024

Die Zukunft der Web- und Mobile-Entwicklung

Full-Stack und Cross-Platform im Fokus

Webframeworks sind immer noch "a dime a dozen", deshalb schauen wir uns in diesem Seminar die wichtigsten Single Page Application (SPA) Frameworks an und vergleichen sie. Wir finden heraus, was die jüngsten Entwicklungen in diesen Bereichen sind und welche Vor- und Nachteile die jeweiligen Frameworks mit sich bringen.

Auch wenn der Hype um Mobileapplikationen seit 2016 etwas abgeflacht ist, sind sie immer noch ein integraler Bestandteil unserer IT-Landschaft. Wir schauen uns deshalb die Gemeinsamkeiten zu Webapplikationen an und welche Möglichkeiten es gibt, um Synergien der beiden Technologien zu nutzen.

Das beste SPA Framework

 

https://npmtrends.com/@angular/core-vs-react-vs-vue

 

Wenn wir die Downloads der einzelnen Frameworks in NPM anschauen, sehen wir, dass React das mit Abstand beliebteste Framework zu sein scheint, gefolgt von Vue, welches Angular überholt hat.

Diese Zahlen dürfen aber nicht als absolut betrachtet werden, da zum Beispiel Angular sehr viel Anwendung in grossen Firmen findet, die initial einmal den Release in ihre eigene Repository ziehen, und jeder weitere Entwickler dann von dieser. Weswegen diese nicht in der Statistik auftauchen.

Eine etwas bessere Approximation ist es, Joblistings anzuschauen. Hier sehen wir, dass alle drei sehr beliebt sind und dass die Schweiz ein Spezialfall in Europa zu sein scheint mit einer sehr grossen Anzahl an Angular-Stellen.

 

https://www.devjobsscanner.com/blog/the-most-demanded-frontend-frameworks/

 

Ebenfalls wichtig zu beachten ist, dass keines am Sterben ist und alle immer noch stetig wachsen.

Wenn wir Vue, React und Angular auf die Hauptmerkmale herunterbrechen und vergleichen, stellen wir fest, dass:

  • Alle auf modernem JS basieren
  • Alle modernes Tooling mit NPM und Vite haben
  • Alle starke Separierung Front- und Backend praktizieren
  • Nicht "opinionated" bezüglich des Backends sind
  • Sehen den Browser als Applikationsplattform
  • Alle ausser Angular verwenden Vite

Wir könnten jetzt noch vergleichen, welches Framework die schnellste Renderzeit hat, aber in der Praxis spielt das für praktisch alle Anwendungen keine Rolle, da alle mehr als schnell genug sind.

 

Konvergenz der Frameworks

Mit diesen Erkenntnissen kann die These aufgestellt werden, dass alle aktuellen Frameworks zu konvergieren scheinen, da alle das gleiche Problem zu lösen versuchten und dieses gelöst zu sein scheint. Dies führt dazu, dass ein "idealer" Ansatz gefunden wird, den alle umsetzen.

Echte Innovation in diesem Bereich findet also nicht mehr statt. Klar gibt es noch einzelne "Innovationen" wie Signals, welche aber die User Experience nicht wirklich massgeblich verbessern, sondern einfach eine bessere Lösung für ein bereits ausreichend gelöstes Problem darstellen.

Indikativ dafür ist ebenfalls, dass obwohl immer mehr neue Frameworks erscheinen, diese keine nennenswerte Adaption in der Industrie finden. Weder der Leidensdruck noch die Verbesserungen scheinen ausreichend gross zu sein.

Die Entscheidung, welches nun das beste Framework ist, scheint also keine rein technische Entscheidung zu sein und von anderen Faktoren abhängig zu sein, wie etwa:

  • Womit hat das Team die meiste Erfahrung?
  • Welches ist am angenehmsten zu benutzen?
  • Wie gross ist die Community?
  • Was für Ressourcen sind verfügbar?
  • Wie einladend ist die Community?

Vite

Vite ist ein modernes Build-Tool und Entwicklungsserver. Es wurde von Evan You, dem Schöpfer von Vue.js, entwickelt, als er versuchte, den Entwicklungsprozess für Vue.js zu verbessern. Ihm ist dann aufgefallen, dass es mit wenigen kleinen Änderungen sehr generisch sein kann und für andere Frameworks ebenfalls verwendet werden kann. Dies hat er auch getan, und seitdem verwenden praktisch alle Frameworks Vite oder bieten die Möglichkeit an.

Angular bietet dies aber erst seit dem 23.10.2024 an, integriert das Build-Tooling jedoch noch nicht vollständig.

Anstelle das ganze JS gebündelt in einem grossen Script auszuliefern, setzt Vite auf einen unbundled workflow. Das heisst, es werden nur die nötigen Skripte geladen und ausgeliefert. Das Ganze wird in Echtzeit transformiert und granular ausgeliefert.

Dies ermöglicht, dass der Testserver immer sehr schnell starten kann, egal wie gross das Projekt ist. In der Produktion wird jedoch noch immer ein gebündeltes JS ausgeliefert.

Feingranulare Reaktivität mit Signals

Signal ist ein Wrapper um einen State. Wann immer man mit diesem interagieren möchte, muss dies über die Wrappermethoden geschehen. Dies ermöglicht es, eine Änderung verlässlich zu erkennen und die Objekte, die im Observer-Pattern auf den State dieses Objekts zugreifen, über die Änderung benachrichtigt zu werden.

Dies ist ein Vorteil, da hier genau bekannt ist, welche Komponenten geupdated werden müssen und nicht ein ganzer Ast des DOMs neu gescannt werden muss, wie es aktuell in Angular und anderen Frameworks der Fall ist.

 

Ein Beispiel an React

# old
const counter = 0
counter++

# Signal
const counter = signal(0)
this.count.set(this.count() + 1)

Cross Platform (X-Platform) vs Native

Cross-Platform-Entwicklung (CP) ermöglicht es, eine Anwendung einmal zu entwickeln und auf mehreren Plattformen wie Web, Android und iOS zu veröffentlichen. Der Vorteil: weniger Entwicklungsaufwand, kürzere Zeit bis zur Marktreife und geringere Kosten.

Heute nutzen bereits viele Apps Cross-Platform-Technologien – ein Zeichen, dass die Vorteile überwiegen. Herausforderungen wie Performance-Unterschiede, plattformspezifische Einschränkungen und ein nicht ganz nativer Look-and-Feel sind bei modernen Frameworks wie Flutter und React Native meist nur noch geringfügig:

  • Performance: Nahezu native Geschwindigkeit in Bereichen wie Startzeiten und Animationen.
  • Limitierungen: Plattformspezifische Einschränkungen betreffen oft nur neueste APIs.
  • Nutzererlebnis: Moderne Frameworks bieten ein User Experience, das dem nativer Apps nahekommt.

Insgesamt zeigt sich, dass CP einen effizienten Weg darstellt, um Apps schnell und mit minimalem Mehraufwand auf mehreren Plattformen zu veröffentlichen.

Die grössten X-Platform-Frameworks sind Flutter und React Native, wobei wir uns hier Flutter etwas genauer anschauen.

Flutter & Mobile First Approach

Flutter ist ein von Google geschriebenes Framework, das bereits 2017 erschien. Es zeichnet sich durch folgende Punkte aus:

  • Hohe Performance dank AOT (Ahead of Time Compilation) und der Rendering Engine
  • Gutes UI/UX
  • Hohe Entwicklungseffizienz dank Hot Reloading, JIT und breitem Toolset

Seine Stärken leben sich vor allem auf Mobile-Plattformen aus. Toyota setzt Flutter bereits in ihren Autos ein.

Architektur

Flutter setzt auf einen modernen, deklarativen UI-Ansatz, der ohne HTML-Dateien und Stylesheets auskommt. Das gesamte User Interface wird direkt im Code definiert, was eine einheitliche Gestaltung und Kontrolle ermöglicht. Flutter ist ein Vorreiter dieses Ansatzes und bietet eine plattformübergreifende API für die meisten Funktionen. Plattform-spezifische Services können dennoch bei Bedarf über sogenannte Platform Channels eingebunden werden, um gezielt auf native Funktionen zuzugreifen.

Hier ein kleines Codebeispiel aus der Flutter-Dokumentation bezüglich Widgets mit dem Code-First-Ansatz:

Widget build(BuildContext context) {
    // Scaffold is a layout for
    // the major Material Components.

    return Scaffold(
      appBar: AppBar(
        leading: const IconButton(
          icon: Icon(Icons.menu),
          tooltip: 'Navigation menu',
          onPressed: null,
        ),

        title: const Text('Example title'),
        actions: const [
          IconButton(
            icon: Icon(Icons.search),
            tooltip: 'Search',
            onPressed: null,
          ),
        ],
      ),

      // body is the majority of the screen.
      body: const Center(
        child: Text('Hello, world!'),
      ),

      floatingActionButton: const FloatingActionButton(
        tooltip: 'Add', // used by assistive technologies
        onPressed: null,
        child: Icon(Icons.add),
      ),
    );
}

Hybrider Ansatz

Hybride Apps sind Browseranwendungen, verpackt in einem nativen Gewand. Flutter zum Beispiel ist ein Framework, um hybride Apps zu schreiben, denn es verwendet nicht-native UI-Elemente, sondern rendert “Kopien” von nativen Elementen auf seinem eigenen Canvas, im Gegensatz zu Kotlin Multiplatform, welches native Elemente erzeugt, z. B. einen Android-Button oder einen iOS-Button.

Dieser Ansatz gibt den Entwicklern viel Kontrolle über das Layout und ermöglicht ihnen, einen einheitlichen Look and Feel über mehrere Plattformen zu erzeugen. Ein weiterer Vorteil ist, dass, wenn die browserbasierte Nutzung im Fokus steht, die Webperformance sehr hoch ist. Ebenfalls lässt sich von bestehender Webentwicklungsexpertise im Team profitieren, da dies sehr gut im hybriden Ansatz angewendet werden kann. Mit Code Push werden sehr schnell Releases erzeugt, da diese oft nicht über Play- oder App-Store-Freigaben gehen müssen.

 

Back to the Server

Typischerweise sind SPAs client-seitiges Rendering, wozu haufenweise API-Calls notwendig sind, bevor etwas gerendert werden kann. Dies führt dazu, dass die erste Ausführung, der initiale Renderschritt, wenn die Webseite aufgerufen wird, länger dauert, als wenn sie serverseitig gerendert worden wäre.

Ein weiterer Nachteil ist, dass der Webcrawler beim initialen Besuch fast nichts im initialen HTML sieht und so der Inhalt nicht indexiert werden kann. (Yay, SEO is still alive)

Hieraus könnte geschlossen werden, dass man doch besser wieder auf serverseitiges Rendering (SSR) umstellen sollte, was auch die meisten Frameworks unterstützen. Hier wird mit dem initialen Call die Page serverseitig gerendert und ausgeliefert, der Client zeigt diese an und baut im Hintergrund die Seite komplett neu und tauscht das DOM dann aus. Nachteil ist hier, dass das Ganze doppelt gerendert wird und ein kurzes Flackern auftaucht.

Meta Frameworks

Meta-Frameworks sind Frameworks, die auf bestehenden Frameworks wie React aufbauen. Ein bekanntes Beispiel dafür ist Remix.

Durch Streaming Server Rendering wird HTML stückweise an den Client gesendet, ohne dass viele kleine Anfragen nötig sind. Bei der Island Architecture wird nur das notwendige JavaScript zur richtigen Zeit (zum Beispiel bei Mouse Hover) an den Client gesendet. So vermeiden wir, dass das gesamte DOM mehrmals gerendert werden muss, und bereits beim ersten Aufruf sind Informationen für Suchmaschinen vorhanden.

Fullstack Data Flow

Mit diesen Änderungen haben wir praktisch das gesamte Frontend-Framework auf unserem Server eingebunden. Es stellt sich die Frage, ob die traditionelle Trennung von Client und Server in diesem Kontext noch sinnvoll ist.

Ein alternativer Ansatz ist der von Remix als "Fullstack Data Flow" bezeichnete:

 

https://remix.run/docs/en/main/discussion/data-flow

 

Ein filebasiertes Routing besteht aus einem Routenmodul, das eine Loader-Komponente und eine Action-Funktion bereitstellt. Router-Dateien exportieren eine Loader-Funktion, die die Daten für die Komponente in dieser Route bereitstellt. Die Daten werden von der Komponente per useLoaderData geladen, gerendert und ausgeliefert. Die Action-Methode der Route wird ausgeführt, wenn das Formular übermittelt wird.

In diesem Ansatz wird die klassische API durch ein Routenmodul (Datei) ersetzt, und die einzelnen Calls werden in der Loader-Methode abgewickelt. Hier ein Codebeispiel:

import type { LoaderFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { json } from "@remix-run/node"; // or cloudflare/deno
import { useLoaderData, Form } from "@remix-run/react";

export async function loader({
  request,
}: LoaderFunctionArgs) {
  const user = await getUser(request);
  return json({
    displayName: user.displayName,
    email: user.email,
  });
}

export default function Component() {
  const user = useLoaderData<typeof loader>();
  return (
    <Form method="post" action="/account">
      <h1>Settings for {user.displayName}</h1>
      <input
        name="displayName"
        defaultValue={user.displayName}
      />
      <input name="email" defaultValue={user.email} />
      <button type="submit">Save</button>
    </Form>
  );
}

export async function action() {
  // ...
}

https://remix.run/docs/en/main/discussion/data-flow

React Server Components

React Server Components bieten eine ähnliche Lösung. Sie sind in der Lage, serverseitig zu rendern, jedoch mit der Besonderheit, dass sie den React Tree auf dem Server generieren und nur die Renderanweisungen an den Client senden.

Dies ermöglicht es, den Rendering-Prozess zu optimieren, indem Serverressourcen genutzt werden. Zudem wird paralleles Data Fetching ermöglicht, sodass bereits während des Streamings ein brauchbares Ergebnis an den Client gesendet werden kann.

Fazit

Es scheint, dass in naher Zukunft ein Trend zurück zum Server zu beobachten ist, insbesondere für Anwendungen, die keinen enormen Umfang oder hohe Skalierungsanforderungen haben. Bei diesen Anwendungen ist eine starke Trennung von Frontend und Backend mittels API eher eine "accidental complexity".


Schliessen
Stamp Icon-Print Icon-Clear
S
M
L
XL
XXL