Software

Hands on Solid Web App

Unsere Erkenntnisse aus dem Experimentieren mit einer Solid Web App, um zu testen, ob und wie Benutzer die Kontrolle über ihre Daten zurückerlangen können, ohne die Vorteile zu verlieren.

April 2021
15
min Lesezeit
Stuart Heap
Fullstack-Entwickler
Diesen Beitrag teilen

Ein wichtiger Punkt, der bei den meisten Apps zu beachten ist, ist die Tatsache, dass einige große Technologieunternehmen als Gatekeeper fungieren und Nutzerdaten sammeln.

Hintergrundinformationen

Im Jahr 1989 erfand Sir Tim Berners Lee das World Wide Web. Ein Jahr später veröffentlichte er den ersten Browser.Damals diente es den Forschern am CERN und anderen Forschungseinrichtungen zum Austausch von Informationen. In den folgenden Jahren entwickelte es sich rasant und beherrscht heute die Weltwirtschaft. Aber das Web, das wir heute nutzen, ist nicht das, was Sir Berners Lee sich vorgestellt hatte. Zwar werden, wie ursprünglich beabsichtigt, Informationen in großem Umfang ausgetauscht, doch wird dies von einigen wenigen großen Technologieunternehmen kontrolliert, die als Torwächter fungieren. Sie machen Profit, indem sie die Daten der Nutzer verkaufen. Die Nutzer haben keine Kontrolle über ihre Daten, da sie nur begrenzt die Möglichkeit haben, sie abzurufen, zu löschen oder zu kontrollieren, wer auf sie zugreifen kann. Die Gesetzgebung, wie z. B. die GDPR in der EU, hat sich nur langsam angepasst und reicht oft nicht aus, um die grundlegenden Probleme zu lösen.

Heute steht Sir Berners Lee an der Spitze der Bemühungen, das Web in Richtung seiner ursprünglichen Vision zurückzubringen. Den Nutzern die Kontrolle zu geben, ohne die Leistung der Apps zu verlieren, die in den letzten Jahrzehnten entwickelt wurden, um unser Leben zu verbessern.


Wie man es repariert

Der wichtigste Schritt ist die Umkehrung der Idee, wo die Daten gespeichert werden. Derzeit haben die meisten Webdienste ihre eigenen Datenbanken, in denen alle relevanten Informationen über Sie gespeichert sind. Der Kerngedanke von Solid besteht darin, all diese Daten in einem einzigen "Pod" zu speichern, auf den alle Anwendungen zugreifen können (sofern sie eine entsprechende Genehmigung erhalten). Dieser Pod würde unter der direkten Kontrolle des Nutzers stehen, so dass er die Berechtigungen nach Belieben steuern kann. Wenn er mit den Richtlinien eines Unternehmens nicht einverstanden ist, kann er den Zugang sofort sperren, ohne dass das Unternehmen eingreifen muss. Zieht der Nutzer in ein neues Haus oder ändert er seine Telefonnummer, muss er dies nur an einem einzigen Ort ändern und muss sich nicht merken, welche der Dutzenden von Diensten aktualisiert werden müssen.

Da die Anwendungsdaten unter der Kontrolle des Nutzers und nicht der Anwendungen gespeichert werden, können auch andere Anwendungen mit demselben Datensatz arbeiten, so dass keine Anbieterbindung entsteht.

Ein zusätzlicher Vorteil ist, dass die meisten App-Backends dazu da sind, eine Schnittstelle zum Backend bereitzustellen und die Zugriffsrechte zu kontrollieren, was bei vielen Apps ganz ohne geht, da diese beiden Funktionen durch den Pod-Anbieter ersetzt werden.


Unsere Erfahrung mit der Entwicklung von Solid

Alle in unserer Discovery-Gruppe waren ziemlich technisch. Unsere Spezialisierungen sind gemischt, aber wir kennen uns alle recht gut mit der Webentwicklung aus. Aber die Arbeit mit verknüpften Daten - wie sie im Solid-Protokoll verwendet werden - war eine Hürde. Wir sind sehr vertraut mit relationalen Datenbanken (z. B. SQL) oder Dokumentendatenbanken (z. B. MongoDB) und all den Abstraktionsschichten, die über ihnen liegen, um die Arbeit mit ihnen zu erleichtern. Verknüpfte Daten sind noch nicht so ausgereift wie diese anderen Technologien, und die Werkzeuge sind noch nicht so ausgereift, wie wir es gewohnt sind. Daher kamen wir anfangs nur langsam voran.

Zur Veranschaulichung sehen Sie hier dieselben Daten, die sowohl in JSON als auch in Turtle (einem in Solid verwendeten Format für verknüpfte Daten) angezeigt werden. Zunächst das altmodische JSON:



  “name”: “Stuart Heap”, 
  “email”: { 
    “work”: “fake.email@mail.com” 
  }, 
  “address”: { 
    “country”: “Germany”, 
    “locality”: “Munich”, 
    “postal-code”: “xxxxx”, 
    “region”: “Bavaria”, 
    “street-address”: “123 Fake Street” 
  }, 
  “organization-name”: “Motius GmbH”, 
  “role”: “Fullstack Developer” 
} 


Und nun die Schildkröte (einige Felder wurden zur einfacheren Darstellung entfernt):


  @prefix : <#>. 
  @prefix pro: <./>. 
  @prefix n: . 
  @Präfix n0: . 
  @präfix schem: .pro:card a n0:PersonalProfileDocument; n0:maker :me; n0:primaryTopic :me.:id1614167342660 a n:Work; n:value .:id1614174549144 
      n:country-name "Deutschland"; 
      n:Ortschaft "München"; 
      n:Postleitzahl "xxxxx"; 
      n:Region "Bayern"; 
      n:Straßenadresse "123 Fake Street".:me 
      a schem:Person, n0:Person; 
      n:fn "Stuart Heap"; 
      n:hasEmail :id1614167342660; 
      n:organisation-name "Motius GmbH"; 
      n:role "Fullstack-Entwickler". 


Lasse uns nun demonstrieren, wie man den Namen des Benutzers in jedem Beispiel erhalten würde.

Traditionell:


const getName = async () => { 
  const user = await getUser() 
  return user.name 
}


Solide:


const getName = async () => { 
  const dataset = await getSolidDataset(webId) 
  if (dataset) { 
    const Profil = getThing(Datensatz, webId) 
    if (Profil) { 
      return getStringNoLocale(profile, VCARD.fn) || 'Unknown' 
    } 
  } 
  return 'Unbekannt' 
} 


Die erhöhte Zeilenzahl ist eine Sache, aber nicht wirklich der springende Punkt. Es ist ziemlich klar, was user.name bedeutet. Der Entwickler weiß sofort, was los ist, und kann ohne nachzudenken weitermachen. Allerdings sagt getThing im Grunde nichts aus. Das Thing, das es zurückgibt, könnte jede beliebige Form von Daten darstellen. In unserem Fall, in dem wir die Daten selbst geschrieben haben, wird eine Person gespeichert sein, und diese Person hat einen VCARD.fn-Wert (formatierter Name), der als String gespeichert ist. Das ist jedoch nicht unbedingt der Fall. Bei einer traditionellen Architektur mit einer spezifischen Datenbank kann ich sicherstellen, dass jeder Benutzer einen Namen hat, und dieser Name ist ein String. Der Frontend-Code muss nicht vorsichtig sein (was nicht heißt, dass keine Ausnahmebehandlung erforderlich ist, aber wir wollen hier nicht vom Thema abschweifen). In Solid gehören die Daten dem Benutzer. Und wenn es eine Sache gibt, die im Leben eines Webentwicklers wahr ist, dann ist es die, dass Benutzer seltsame Dinge tun werden. Man kann nichts über die Daten annehmen, und deshalb muss man bei einer Solid-Anwendung viel mehr aufpassen.

Mit gut geschriebenen Vokabularen (im Wesentlichen Schemata für verknüpfte Daten) ist es vorstellbar, dass wir Werkzeuge haben, die einen Datensatz nehmen und ein leicht zu verwendendes JSON-Objekt oder zumindest ein ähnlich einfach zu verwendendes Format zurückgeben. In der kurzen Zeit, in der wir uns mit dieser Technologie beschäftigt haben, konnten wir jedoch keine derartigen Tools finden.

Dies ist vielleicht kein wirklich faires Beispiel. Es ignoriert die Tatsache, dass in den meisten traditionellen Anwendungen ein Backend involviert ist, das eine Schnittstelle zur Datenbank haben muss, um das JSON zu erzeugen. Man könnte argumentieren, dass wir lediglich einen Teil der Backend-Komplexität auf das Frontend verlagert haben, was im schlimmsten Fall ein Seitenschritt wäre. Viele moderne Datenbanken speichern jedoch bereits Daten in JSON (oder etwas sehr Ähnlichem) (z. B. MongoDB), und es gibt viele Tools, die diese Konvertierung abstrahieren und bei Vorliegen eines Schemas eine Schnittstelle zum Abrufen von JSON erzeugen (z. B. Prisma).

Wenn die Daten komplizierter werden, steigt auch hier die Komplexität. Und es wird noch schlimmer, wenn Daten in einen Pod geschrieben werden. Hier ist die Funktion aus meiner Bierrezept-App zum Speichern eines neuen Biers mit einem bestimmten Namen:



const addBeer = async (name: string) => { 
  if (beerDataset.value) { 
    const id = `#${uniqid()}` 
    const newBeer = createThing({ 
      url: storageLocation.value + BEER_STORAGE + id, 
    }) 
    const typedBeer = setUrl( 
      newBeer, 
      RDF.type, 
      BEER_RECIPE.BeerRecipe.value, 
    ) 
    const namedBeer = setStringNoLocale( 
      typedBeer, 
      BEER_RECIPE.name.value, 
      name, 
    ) 
    const ownedBeer = setUrl( 
      namedBeer, 
      BEER_RECIPE.writtenBy.value, 
      webId.value, 
    ) 
    beers.value.push(ownedBeer) 
    beerDataset.value = setThing(beerDataset.value, ownedBeer) 
    saveSolidDatasetAt( 
      storageLocation.value + BEER_STORAGE, 
      beerDataset.value, 
      { fetch: session.value.fetch }, 
    ) 
  } 
} 


Für einige Kontext - es ist ein Vue app, was bedeutet, dass es Daten auf der Komponente in refs gespeichert ist, daher alle .values Sie sehen, um verstreut.

Zuerst müssen wir ein Thing erstellen. Zu diesem Zeitpunkt ist es ein völlig abstraktes Ding, das einzige Unterscheidungsmerkmal ist, wo es sich befinden wird. Dann beginnen wir, ihm eine Eigenschaft nach der anderen zuzuweisen. Wir sagen, dass es vom Typ BeerRecipe ist (ein benutzerdefinierter Typ, der in meinem Pod veröffentlicht wurde), und geben ihm einen Namen, eine ID und einen Autor (jede Eigenschaft benötigt einen eigenen Funktionsaufruf). Dann setzen wir das Ding in den Datensatz und speichern es zurück im Pod.

Wenn wir ein herkömmliches Backend verwenden würden, das HTTP-Anfragen akzeptiert, könnte das Äquivalent etwa so aussehen:



fetch(‘/beers’, { 
  method: ‘POST’, 
  headers: { 
    ‘Content-Type’: ‘application/json’, 
  }, 
  body: { 
    name, 
    author: user.id, 
  }, 
}) 


Auch hier könnte das Argument angeführt werden, dass das traditionelle Beispiel die Komplexität des Backends verbirgt. Das ist richtig, aber wir überspringen auch das Schreiben des Vokabulars für die Bierrezeptdaten. Was nach meinem derzeitigen Verständnis eine viel schwierigere Aufgabe ist als die Bearbeitung der Anfrage im Backend und die Speicherung in SQL, selbst wenn ich auf alle Tools verzichten würde, die diesen Prozess erleichtern.

Die Quintessenz ist, dass die grundlegenden CRUD-Operationen mit den aktuellen Solid-Bibliotheken wesentlich mühsamer zu schreiben sind, als wir es gewohnt sind. Wenn wir Funktionen so schnell wie gewohnt und mit einem angenehmen Entwicklererlebnis erstellen wollen, müssen wir die Werkzeuge verbessern. Aber das ist wirklich keine Überraschung: Seit Jahrzehnten wird das Tooling für die Arbeit mit traditionellen Technologien iterativ entwickelt. Solid hat hier einen großen Nachholbedarf.


Wie könnte die Zukunft aussehen?

Solid ist eindeutig auf den Endnutzer ausgerichtet. Und die Vorteile für den Endnutzer sind notwendig und wertvoll. Auf der Seite der Entwickler gibt es offensichtliche Kompromisse, aber es ist eine Gemeinschaftsaufgabe, die Werkzeuge zu entwickeln, die die Arbeit mit dieser Technologie einfacher und zugänglicher machen. Wenn diese Werkzeuge vorhanden sind, wird die Arbeit mit Solid meiner Meinung nach einfacher sein als mit einem herkömmlichen Backend. Aber im Moment macht es die Dinge noch schwieriger.

Für die Unternehmen, die Apps entwickeln und hoffen, damit Geld zu verdienen (woher die meisten Apps letztlich kommen), gibt es meiner Meinung nach jedoch mehr Nachteile als Vorteile. Ich denke, dass dies die breite Akzeptanz dieser Technologie zu einem schwierigen Unterfangen machen wird. Die festgefahrene Position etablierter Unternehmen, die bereits einen Großteil der Daten ihrer Nutzer besitzen und diese als Geiseln halten, macht es schwierig, sie zu unterbieten - selbst wenn das Geschäft für den Nutzer besser ist. Für die Unternehmen gibt es wenig bis gar keinen Anreiz, den enormen wirtschaftlichen Nutzen aufzugeben, der ihnen aus dem uneingeschränkten Zugang zu den Nutzerdaten erwächst.

Wenn du diesen ausführlichen Artikel über Solid Web Apps interessant fandest, dann sehe dir den aufgezeichneten Clip der Live-Präsentation von unserer Discovery Conference an!  

Bereit durchzustarten?

Lass uns austauschen und gemeinsam ein Projekt beginnen.

Arbeiten in einem Technologieunternehmen | Motius