Netidee Blog Bild
Ein Bisschen TDD
Wie test-driven development bei Delete Your Data zum Einsatz kommt (30.08.2020)
Förderjahr 2019 / Project Call #14 / ProjektID: 4612 / Projekt: Delete Your Data

Die Software-Struktur von DYD

In diesem Post soll es vor allem um Testen, und da speziell um test-driven-development gehen. Bevor das sinnvoll geht, ist aber ein Blick auf die Projekt-Struktur von Delete Your Data angebracht. Hier also die wichtigsten Ordner und Module:

delete-your-data/
├ server/         # DYD-Server
│ ├ models/       # Datenbank-Modelle
│ │ ├ index.js
│ │ ├ account.model.js
│ │ └ ...
│ ├ controller/   # Operationen, die in DYD durchgeführt werden können, z.B. CRUD, User anonymisieren
│ │ ├ index.js
│ │ ├ account.controller.js
│ │ └ ...
│ ├ index.js      # Einstiegspunkt für den Web-Server
│ ├ app.js        # Die Express-App mit Nuxt-Frontend und REST-API
│ └ api.js        # Routen für die REST-Schnittstelle
├ pages/          # Frontend der Admin-Oberfläche
│ ├ index.vue
│ ├ accounts.vue
│ └ ...
└ test/           # Tests der einzelnen Komponenten
  ├ controller/
  │ ├ account.spec.js
  │ └ ...
  └ api.spec.js

Der Großteil der Logik ist klarerweise serverseitig, und da gibt es erst mal die Datenbank-Modelle für Accounts, Plugins und Logeinträge. Letztere entsprechen Aktionen die ein User getätigt hat, etwa erstellte Blogposts oder ähnliches. Die Controller stellen für DYD wichtige Aktionen zur Verfügung. Neben CRUD sind das auch die komplexen Aktionen, die DYD tatsächlich ausmachen: Userdaten anonymisieren und löschen. Direkt im server-Ordner gibt es dann noch die Module, die die Gesamtstruktur des Webservers ausmachen: die Express-"App", welche die REST-Schnittstelle und das Frontend beherbergt, und den Webserver, der das ganze über HTTP zugreifbar macht. Das Frontend beschränkt sich auf die verschiedenen Verwaltungsseiten für Admins.

Und dann gibt es da natürlich die Tests.

Testen, Testen, Testen

Nuxt kommt praktischerweise vorkonfiguriert mit Jest, einem JavaScript Test-Framework, inklusive Messung der Code-Coverage. Nachdem unsere Test-Suite ausgeführt wurde kann man sich die Coverage anschauen, das sieht dann etwa so aus:

Die Code Coverage von sechs verschiedenen (Unter)ordnern. Man sieht, dass die ersten drei Zeilen (Frontend) nicht getestet wurden, die unteren drei Zeilen (Backend) schon. Die Statement-Coverage der Backend-Ordner liegt bei rund 94%, 99%, und 86%.
Code Coverage von DYD. Das Frontend wird nicht automatisch getestet, beim Server sind wir strikter

Wie man leicht sehen kann testen wir unser Frontend nicht automatisiert, was die Gesamt-Coverage stark nach unten auf 69,75% drückt. Dort wo es um die Datenverarbeitung geht, am Server, testen wir viel. Wo fallen wir unter die perfekten 100% Coverage? Schauen wir zum Beispiel in server/app.js rein:

Ein Ausschnitt der Coverage von app.js.
Zwei Befehle und der if-Branch wurden markiert: Tests benutzen den "test"-Modus, nicht "development" oder "production", der Code kann daher nie in einem Test erreicht werden.

Hier geht es um Code, der in der Testumgebung deaktiviert ist, hier gibt es also eigentlich kein Problem! Diese falsch-positiven Meldungen kann man noch unterdrücken, bisher haben wir das aber einfach noch nicht gemacht.

Der Kern von DYD, und Test-Driven Development

Die Idee bei TDD ist es, zuerst Tests zu schreiben und dann den Code, der diese Tests erfolgreich ablaufen lässt:

  • am Anfang steht ein Ziel, das mit dem Ist-Zustand noch nicht erreicht werden kann
  • wir formulieren Tests, der überprüft, dass das Ziel erreicht wurde
  • wir schreiben den Code, der das Ziel erreichen soll
  • wir überprüfen, dass die Tests erfolgreich durchgeführt werden.

Obwohl mit den Tests hier meistens automatisierte Testfunktionen gemeint sind, kann das jeglicher Prozess sein, der die Erreichung des Ziels ausreichend belegt. Ein nicht zu unterschätzender Nebeneffekt von TDD ist es, dass man schon vor dem eigentlichen Entwickeln eine Idee davon bekommt, wie der Code benutzt werden soll. Die Tests helfen also nicht nur, keine Fehler zu machen, sie sind auch ein Teil des Design-Prozesses!

All der bisher genannte Code war von der Struktur her relativ einfach: Modelle schauen nunmal so aus wie sie das tun, bei CRUD-Befehlen gibt es auch nicht sonderlich viel Spielraum wie diese aussehen sollen. Die weiteren Schritte bieten mehr Designmöglichkeiten, und da ist es praktisch, sich mit TDD zuerst in ein Benutzer-Mindset zu begeben. "Benutzer" ist in dem Fall etwas irreführend, denn die Nutzer von DYD sind immer noch Entwickler bzw. Betreiber von Internet-Plattformen. Was sollen diese mit DYD tun?

  • Den DYD Service betreiben, damit er der Plattform zur Verfügung steht,
  • Plugins erstellen, mit denen DYD auf ihren Service zugreifen kann (einige werden wir selbst implementieren),
  • unsere REST-APIs in ihrer Plattform aufrufen, um personenbezogene Daten in DYD zu indizieren, und
  • über unsere APIs personenbezogene Daten aus der Plattform entfernen.

Um all das sinnvoll testen zu können haben wir also eine einfache Webapplikation erstellt in der es Accounts gibt, die wiederum Einträge erstellen können - in einer echten Anwendung könnten das zum Beispiel Blogger und ihre Blogposts sein. Wir formulieren also das Ziel:

  • Die "Dummy"-Plattform und DYD sollen beide in Betrieb genommen werden,
  • Ein Plugin für die Plattform soll erstellt und in DYD registriert werden,
  • Die Plattform soll DYD melden, wenn Accounts oder Einträge angelegt werden, und
  • Über die DYD-APIs sollen die Daten bestimmter Benutzer aus der Plattform gelöscht werden können.

Damit nimmt das ganze Gestalt an. Die weiteren Schritte, Tests zu schreiben und die neuen Features zu implementieren, sind die Arbeit der vergangenen Monate. Ohne sich in Details zu verfangen bietet ein aktualisierter Projektbaum einen guten Überblick was sich getan hat:

delete-your-data/
├ server/         # DYD-Server
│ ├ models/       # Datenbank-Modelle
│ │ ├ index.js
│ │ ├ account.model.js
│ │ └ ...
│ ├ controller/   # Operationen, die in DYD durchgeführt werden können, z.B. CRUD, User anonymisieren
│ │ ├ index.js
│ │ ├ account.controller.js  # unterstützt jetzt auch das Anonymisieren/Löschen von Accounts
│ │ └ ...
│ ├ index.js      # Einstiegspunkt für den Web-Server
│ ├ app.js        # Die Express-App mit Nuxt-Frontend und REST-API; hier wird momentan immer das Dummy-Plugin registriert
│ └ api.js        # Routen für die REST-Schnittstelle; erweitert um Anonymisieren/Löschen
├ pages/          # Frontend der Admin-Oberfläche
│ ├ index.vue
│ ├ accounts.vue
│ └ ...
├ dummyService/   # Die "Dummy"-Plattform, rein für Testzwecke
│ └ ...
├ dydPlugins/     # Plugins, die mit DYD ausgeliefert werden
│ └ dummy/
│   └ index.js    # Implementierung des Dummy-Plugins
└ test/           # Tests der einzelnen Komponenten
  ├ controller/
  │ ├ account.spec.js
  │ └ ...
  ├ api.spec.js
  └ dummy.spec.js # testet die Kombination aus DYD und der Dummy-Plattform

Wie ein DYD-Plugin aussieht kann man sich also jetzt hier anschauen; außer der Validierung verschiedener Daten gibt es vor allem zwei Methoden, die Logeinträge und Accounts (beides im DYD-Sinn, nicht im Dummy-Sinn) anonymisieren/löschen können. Die Tests liegen hier; wie man sieht indiziert die Dummy-Plattform noch nicht selbstständig die Accounts und Einträge, es ist also noch nicht alles fertig, aber die grundlegende Funktionalität ist damit gegeben.

Wir nähern uns mit großen Schritten einem verwendbaren Produkt, mit dem das Recht auf Löschung mit geringem Aufwand zu einer Plattform hinzugefügt werden kann!

Tags:

DSGVO Datenschutz Industry meets Makers PRIA
CAPTCHA
Diese Frage dient der Überprüfung, ob Sie ein menschlicher Besucher sind und um automatisierten SPAM zu verhindern.
    Datenschutzinformation
    Der datenschutzrechtliche Verantwortliche (Internet Privatstiftung Austria - Internet Foundation Austria, Österreich) würde gerne mit folgenden Diensten Ihre personenbezogenen Daten verarbeiten. Dies ist für die Nutzung der Website nicht notwendig, ermöglicht aber eine noch engere Interaktion mit Ihnen. Falls gewünscht, treffen Sie bitte eine Auswahl: