webfactory Neuigkeiten https://www.webfactory.de/assets-version-1536147931/bundles/webfactorywebsite/img/inside-logo.png Logo Webfactory http://www.webfactory.de Zend_Feed_Writer 2 (http://framework.zend.com) https://www.webfactory.de/blog/ © 2018 webfactory GmbH Warum wir ungerne an Ausschreibungen teilnehmen Das Wort „Ausschreibung“ ist mit der Webbranche in etwa so fest verbunden wie die Wörter  „Sprint“, „Serverausfall“ und „Kaffee“. Man munkelt, dass es dort draußen Agenturen gibt, in denen ganze Teams nichts anderes tun, als an einer Ausschreibung nach der nächsten teilzunehmen. Auf der anderen Seite der Macht – nämlich seitens der Auftraggeber – besteht oft sogar die rechtliche Verpflichtung, ein Projektvorhaben dem breiten Wettbewerb zur Verfügung zu stellen, insbesondere, wenn es sich dabei um Projekte der öffentlichen Hand handelt. Dass den Kunden also oft gar nichts anderes übrig bleibt als ihr Projekt auszuschreiben und dass sie sich dabei an gewisse Vorgaben halten müssen, ist uns somit natürlich bewusst. Dennoch sind wir in der webfactory bekennende Ausschreibungs-Skeptiker. Nur in Ausnahmefällen nehmen wir an einer teil, etwa dann, wenn das Vorhaben besonders gut zu unseren Anforderungen passt und ein Projekt uns sehr reizt. Warum das so ist, möchten wir in diesem Blogbeitrag erzählen.

1. Wir möchten mit potenziellen Kunden in den Dialog treten, statt anonyme Bewerbungen zu versenden

Wir haben das große Glück, dass die meisten unserer Kunden ihren Weg ganz ohne komplizierten Ausschreibungsprozess zu uns gefunden haben. Im Normalfall läuft das so ab: Ein*e Interessent*in meldet sich bei uns, man telefoniert ein paar Mal miteinander und steckt dabei ab, ob Projektwünsche und Expertise zusammenpassen und man sich vorstellen kann, miteinander zu arbeiten. Vielleicht trifft man sich dann noch einmal zu einem persönlichen Gespräch um weitere Details zu klären, zeigt das ein oder andere Vergleichsprojekt und brainstormt eventuell auch schon einmal los, in welche Richtung das Vorhaben gehen könnte. Das Angebot für das Projekt und die Auftragsbestätigung erfolgen dann oft ganz zwanglos via E-Mail. Der zentrale Aspekt, der hier betont werden soll, ist, dass diese gesamte Akquisephase in Form eines beidseitigen Austauschs stattfindet. Man spricht miteinander, kann sich erklären, eventuelle Missverständnisse schnell aus dem Weg räumen, alternative Vorschläge anbieten und letztlich auch schauen, ob man sich sympathisch ist. Bei einer Ausschreibung fällt genau dieser persönliche Aspekt in weiten Teilen weg. Stattdessen müssen hier seitenweise Unterlagen gelesen und Fragebögen ausgefüllt werden. Rückfragen sind nur eingeschränkt und oft nur über den schriftlichen Weg möglich. Das System kostet viel Zeit, Nerven und Ressourcen und ist unserer Ansicht nach dabei auch noch deutlich ineffizienter als die persönlichen Beratungsgespräche, die wir demgegenüber vorziehen. Gewisse Aspekte einer Ausschreibung nehmen dabei nahezu absurde Züge an: zum Beispiel, wenn man nach seitenlanger Lektüre der Projektanforderungen aufgefordert wird, diese in eigenen Worten wiederzugeben. Dahinter mag das Bedürfnis stehen, irgendwie zu verifizieren, ob die sich bewerbende Agentur das Projekt auch wirklich verstanden hat. Man kommt sich dabei allerdings ein bisschen vor wie bei einer Schulprüfung. Würde man einfach miteinander sprechen, wäre doch direkt klar, dass wir die Aufgabenstellung verstanden haben.

2. Wir finden Ausschreibungen zu teuer

Natürlich rechnen auch wir erste Beratungsgespräche, die wir mit potenziellen Neukunden führen, in der Regel nicht ab. Das Problem ist, dass die Akquisekosten bei einer Ausschreibung dieses normale Maß überschreiten. Ganze Berge an Unterlagen müssen gewälzt werden, darunter seitenlange Bedingungen und Verträge. Neben der Wiedergabe des Projektvorhabens in eigenen Worten müssen Mitarbeiterprofile versendet und eine meist festgelegte Anzahl an Referenzprojekten vorgestellt werden, der eigene Projektmanagementprozess muss erläutert und Standardfragen („Welche Gefahren sehen Sie in dem Projekt?“, „Wie gewährleisten Sie die Erreichbarkeit im Notfall?“) beantwortet werden. All dies kostet Zeit — und zwar so viel, dass gerne mal zwei Mitarbeiter einige Tage bis Wochen damit beschäftigt sind, die Unterlagen zusammenzustellen. Bei hohem Zeitdruck versteht sich, denn die Deadlines sind meist eng gesteckt. Das bedeutet für uns schon einmal, dass wir ziemlich spontan das stehen und liegen lassen müssen, was wir gerade eigentlich tun wollten – und das obwohl wir uns eigentlich gar nicht wohl dabei fühlen, die Projekte unser Bestandskunden nach hinten zu schieben, um uns um die Akquise neuer Kunden zu kümmern. Doch zurück zur Kostenfrage: Bei der letzten Ausschreibung, an der wir teilgenommen haben (und bei der wir als Zweitplatzierte ausgeschieden sind) haben wir ca. 15000 Euro in unsere Teilnahme gesteckt, wenn man den Verdienstausfall eins zu eins umrechnet. Betrachtet man hingegen die Akquisekosten unserer „normalen“ Kundenanfragen, so liegen diese i. d. R. deutlich unter diesem Wert. Bei einem unserer letzten Neukunden lagen die Akquisekosten beispielsweise bei ca. 3000 Euro (auch hier wieder der umgerechnete Verdienstausfall). Man kann hier anmerken, dass Ausschreibungen mit der Zeit insofern günstiger werden, als dass sich einige der erstellten Unterlagen (z. B. Mitarbeiterprofile) wiederverwenden lassen. Insgesamt bleibt aber bestehen, dass die Teilnahme an einer Ausschreibung deutlich zeitaufwändiger als eine ausschreibungsunabhängige Neukundengewinnung ist.

3. Wir glauben nicht, dass man auf Basis einer Ausschreibung ein seriöses Angebot abgeben kann

Wie soll das auch funktionieren, wenn man nicht miteinander sprechen kann? Wir haben in letzter Zeit einige gute Ausschreibungen mit wirklich detaillierten Anforderungen gesehen, aber auch hier ergeben sich einfach noch unglaublich viele Fragezeichen. Ohne zu wissen, welches Feature dem Kunden besonders am Herzen liegt, bei welchen Features die simpelste und preisgünstigste Lösung vollkommen ausreichend ist und vor allem auch ohne einen Einblick in die Datenstruktur zu bekommen, die später verwaltet werden soll, kann man ein Angebot eigentlich nur würfeln. 

4. Wir finden Geiz nicht geil

Die Unterlagen, die eine Agentur bei einem Ausschreibungswettbewerb einreicht, werden letzten Endes anhand eines Punkteschemas bewertet. Der Preis spielt bei der Bewertung natürlich eine ausschlaggebende Rolle. Wir glauben, dass jede teilnehmende Agentur in ihren Bewerbungsunterlagen versprechen wird, alle geforderten Features umzusetzen (sonst würde sie ja Punkte verlieren) und dann versucht, darunter einen möglichst kleinen Preis zu setzen. Wir denken aber, dass der Kunde letzten Endes nicht glücklich werden wird, wenn man jedes Feature mit der am billigsten denkbaren Variante kalkuliert. Wir als Agentur können es nicht mit unserem Gewissen vereinbaren, ein Angebot auf Basis von „möglichst schnell und möglichst billig“ zu erstellen. Wir schätzen die Gefahr, dass bei Ausschreibungen der Kampfpreis gewinnt, als relativ hoch ein. Und es gibt hier noch einen weiteren Aspekt, der es uns als Agentur sehr schwer macht, einen niedrigen Preis anzubieten: Da wir nicht jede Ausschreibung gewinnen können, müssten wir die angefallenen Kosten einer verlorenen Ausschreibung eigentlich auf den Angebotspreis der nächsten aufschlagen. Ein Kunde, der via Ausschreibung nach einer Agentur sucht, wählt das für uns teuerste System. Die angefallenen Kosten verlorener Ausschreibungen müssten wir also genau den Kunden in Rechnung stellen, die dieses System nutzen, um unsere eigene Wirtschaftlichkeit zu gewährleisten – wodurch die Angebote entsprechend teurer ausfallen müssten. 

5. Wir arbeiten nicht mit Festpreis

In der Branche ist hinlänglich bekannt, dass sich die Aufwände eines Projekts nur sehr grob abschätzen lassen und Anforderungen sich außerdem im Prozess stetig ändern (Stichwort: agil). Genau aus diesen Gründen arbeiten wir selbst bei unseren Schätzungen mit T-Shirt-Größen und weigern uns, wo es nur irgendwie geht, mit Festpreisen zu agieren. Die Erfahrung zeigt, dass Features immer mal wieder größer werden, als ursprünglich geschätzt, zum Beispiel weil sich die Anforderungen im laufenden Projekt ändern. Wenn wir einen Festpreis anbieten wollen, müssen wir eigentlich einen ordentlichen „Gefahren-Puffer“ einplanen. Und das umso mehr bei einer Ausschreibung, bei der sich die genauen Anforderungen im Vorfeld nur erahnen lassen (siehe Punkt 3). Ein Festpreis mit ordentlichem Puffer wiederum steht im direkten Widerspruch zur Nennung eines möglichst geringen Preises (siehe Punkt 4.)

6. Wir finden, dass Ausschreibungen Nebensächlichkeiten zu viel Gewicht einräumen

Bei unserer letzten Ausschreibung hat uns (unter anderem) der Teilaspekt „Wiederherstellungszeiten“ bei auftretenden Mängeln einen Punktabzug beschert. Dabei sind wir während unserer Geschäftszeiten von Montag bis Freitag telefonisch erreichbar, sichten laufend unseren zentralen E-Mail-Eingang und stehen bei Bedarf auch über unsere Geschäftszeiten hinaus über eine Notfallnummer zur Verfügung. Wenn wirklich einmal etwas brennt, haben wir noch immer sofort alles stehen und liegen gelassen und uns mit Hochdruck um das Problem gekümmert. Wie lange es im Einzelfall dauert, auf ein Problem zu reagieren und es zu lösen, lässt sich natürlich nur schwer vorhersagen und ist sicherlich anhängig vom Zeitpunkt der Kontaktaufnahme, davon wie kritisch eine schnelle Behebung auf Kundenseite ist und letztlich natürlich von der Komplexität des Problems. Somit ist es insgesamt gar nicht so leicht, sich hier auf bestimmte Werte festzulegen, die man kommunizieren kann. Letzten Endes hat jedenfalls eine andere Agentur im Punkt „Wiederherstellungszeiten“ durch ihre Angaben einen besseren Punktwert erzielt als wir. Unsere These: Um hier zu gewinnen, muss man nicht nur mit Kampfpreisen, sondern im Zweifelsfall eben auch mit Kampf-Reaktionszeiten bzw. -Wiederherstellungszeiten argumentieren. 

7. Wir wollen unsere Dienstleistungen nicht verschenken

Dass Ausschreibungen per se ein kostspieliges Unterfangen sind, haben wir bereits ausführlich dargestellt. Noch problematischer wird dies, wenn man für einen Ausschreibungswettbewerb einen Designvorschlag erstellt. Ein gutes Design braucht nun einmal seine Zeit, ein möglichst tiefgehendes Verständnis des Projekts und der Vorstellungen und Wünsche des Kunden. In der Realität zeigt sich: Selbst wenn eine Ausschreibung nicht explizit einen Designvorschlag einfordert, scheinen Agenturen, die „einfach mal eins mitschicken“, die Nase vorn zu haben gegenüber Agenturen, die darauf verzichten. Menschlich ist das sicherlich nachvollziehbar. Dennoch halten wir nichts davon, ein Design zu entwerfen, ohne dass wir dafür entlohnt werden. Immerhin gehört die Entwicklung eines Designs zu unseren Kerndienstleistungen und spielt damit auf einer ganz anderen Ebene, als das Erstellen von Mitarbeiterprofilen oder die Auflistung von Referenzprojekten. Wir finden: Gute Arbeit und Qualität darf auch ihren Preis haben.

Abschließend lässt sich sagen, dass wir uns natürlich darüber freuen, wenn wir auf eine Ausschreibung aufmerksam gemacht werden. Dennoch bleibt für uns als Fazit bestehen, dass wir auch zukünftig nur in seltenen Ausnahmefällen teilnehmen werden. Durch die anfallenden Kosten, den aus unserer Sicht ineffizienten Prozess und die mit einer Ausschreibung verbundenen Risiken für unsere Agentur werden wir vermutlich auch dann wieder Bauschmerzen dabei haben. 

]]>
Wed, 15 Aug 2018 13:06:19 +0200 https://www.webfactory.de/blog/warum-wir-ungerne-an-ausschreibungen-teilnehmen https://www.webfactory.de/blog/warum-wir-ungerne-an-ausschreibungen-teilnehmen webfactory GmbH webfactory GmbH 0
enterJS Darmstadt 2018 - Eine Zusammenfassung weiterer Talks Übersicht

Battle of the Frameworks

Lora Vardarova, Zalando GmbH

Von Angular, React und Vue hat jeder, der sich für Javascript interessiert, zumindest schon einmal gehört – doch gerade, wer am Anfang seiner Karriere als JavaScript-Entwickler steht, fragt sich vermutlich: für welches dieser Frameworks, die alle mehr oder minder den gleichen Zweck erfüllen, sollte man sich entscheiden? Welches Framework ist das beste?

Überblick

Der Vortrag beginnt nach einer kurzen Einführung mit einer Geschichtsstunde, die Aufschluss über die Entstehung der heutigen Framework-Landschaft bietet und unter anderem aufzeigt, warum Angular nicht Angular.js ist.

Beim Vergleich der Features stellt sich heraus, dass sich alle drei behandelten Frameworks sehr ähnlich sind, und über unterschiedliche Konzepte nahezu dieselben Features umsetzen.

Entscheidungsfindung

Die Erfahrungen bei Zalando haben in den letzten Jahren verschiedene Wege und Irrwege aufgetan, wie die Entscheidung für ein Framework angegangen werden kann.

Dabei hat sich unter anderem herausgestellt, dass die beliebte Methode, mit allen infragekommenden Frameworks eine To-Do-App zu implementieren, in der Regel für eine qualifizierte Entscheidung nicht ausreicht, da eine To-Do-App schlicht zu simpel ist um die Stärken und Schwächen des Frameworks zu erfahren. Stattdessen empfiehlt Vardarova die Implementiertung einer progressive Web App, die als Reader-Client für die Hackernews von YCombinator fungiert.

Außerdem zeige die Erfahrung, dass zu den wichtigsten Faktoren die Community und die Dokumentation zählen.

Projektleiter und Teams können sich am Bus-Faktor orientieren: Wenn der Hauptentwickler des Projekts vom Bus überfahren wird, wie schnell kann ein guter Ersatz gefunden werden?

Die Entscheidung, welches Framework eingesetzt wird, treffen die Zalando-Entwickler pro Projekt, denn jedes Projekt hat seine eigene Roadmap und eigene Bedürfnisse, die in der Entscheidung berücksichtigt werden sollten. Dennoch sei es wichtig, sich eine Deadline zu setzen, da sonst die „decision trap“ zuschlage und die Entscheidung wichtige Entwicklungszeit koste.

And the winner is...

Die Frage, welches Framework das beste ist, wird explizit nicht beantwortet, sondern durch eine andere Fragestellung ersetzt: Welches Framework ist das passendste für mein Projekt?

Mir als Neuling in der JavaScript-Welt, der sich noch nicht auf ein Framework festgelegt hat, hat dieser Vortrag aufgezeigt, dass ich das eventuell gar nicht muss. Es war beruhigend, festzustellen, dass man selbst nach Festlegung auf ein Framework keine technologischen Sensationen verpasst, da alle Frameworks alle populären Features auf verschiedene Weisen umsetzen.

JavaScript-Security: Webbrowser in Gefahr

Joshua Tiago, Cirosec

Cross-Site-Scripting(XSS)-Lücken sind die am weitesten verbreiteten, aber gleichzeitig auch die am trivialsten auszunutzenden Sicherheitslücken im Internet. Da das nicht die beste Kombination für ein sicheres Internet ist, leistet Tiago mit diesem Vortrag seinen Beitrag im Kampf gegen die Sicherheitslücke, über die jeder bereits alles zu wissen glaubt.

Cross-Site-Scripting

Nach einer Zusammenfassung über die Relevanz von Cross-Site-Scripting stellt frischt Tiago er noch einmal die Grundlagen auf:

Der Angreifer schleust fremden Code in eine Webanwendung (z. B. durch einen manipulierten Link zu einer Website, die URL-Variablen ungeprüft im Seitentext ausgibt oder einen javscripthaltigen Forenbeitrag), die dann in einem fremden Browser ausgeführt wird.

Die Voraussetzungen, eine XSS-Lücke auszunutzen, sind allgemein, dass eine Anwendung Eingaben entgegennimmt und später wieder ausgibt, und dabei weder bei der Eingabe, noch bei der Ausgabe Steuerzeichen filtert (keine Eingabefilterung und keine Ausgabekodierung). Die typischen Fälle von Ein- und Ausgaben sind dabei Suchfelder, Online-Formulare und Gästebücher bzw. Foren, aber auch auf weniger offensichtliche Ein-/Ausgabemöglichkeiten wie der Header der HTTP-Anfrage sowie der Inhalt hochgeladener Dateien müssen unbedingt beachtet werden, wenn eine Anfälligkeit für Cross-Site-Scripting vermieden werden soll.

Eingabefilterung und Ausgabekodierung illustriert der Vortrag an zahlreichen Beispielen: So codiert Wikipedia die Ausgabe von Sucheingaben, was die Interpretation von JavaScript-Code darin durch den Browser verhindert.

Persistentes und nicht-persistentes Cross-Site-Scripting

Bei nicht-persistenten XSS-Angriffen (reflected XSS) bringt der Anwender einen Nutzer dazu, die Webanwendung auf eine bestimmte Art und Weise zu benutzen, damit der Schadcode ausgeführt wird. Dafür lässt er den Nutzer beispielsweise einen bestimmten Link anklicken, der eine Eingabe mit Code enthält, die später in der Oberfläche der Anwendung ausgegeben wird. Diese Art von Angriff verändert die Webanwendung selbst nicht und funktioniert nur, wenn der Nutzer die Seite auf die vom Angreifer geplante Art nutzt. Der Nutzer schickt den Schadcode dabei selbst in seiner Anfrage mit.

Persistente XSS-Angriffe (stored XSS) hingegen betten sich im Backend der Anwendung ein und funktionieren auch bei ganz normalen Seitenaufrufen. Sie sind danach dauerhaft in der Anwendung enthalten und betreffen alle Seitenbesucher. Ermöglicht werden solche Angriffe z. B. durch Foren oder Gästebücher.

DOM-basiertes Coss-Site-Scripting

DOM-basiertes XSS ist eine Form des Cross-Site-Scriptings, bei welcher der Schadcode nicht über den Server übertragen wird, sondern der gesamte Angriff im Browser-DOM des Nutzers stattfindet. Dadurch können serverseitige Schutzmechanismen und Filter nicht schützen. Möglich wird DOM-basiertes XSS unter anderem durch Teile der URL, die nicht an den Server geschickt werden (alles nach einem #) und die Verwendung unsicherer JavaScript-Funktionen. Wenn Daten ungeprüft von Objekten wie

  • document.location

  • document.URL

  • document.referrer

übernommen werden, und von den Funktionen

  • document.write

  • document.writeln

verarbeitet werden, ist DOM-basiertes XSS möglich.

Das führt Tiago an einem Beispiel vor, in dem er einen Namen als URL-Parameter entgegennimmt und auf der Seite ausgibt. Ersetzt er den Namen in der URL durch JavaScript-Code, kann er die Seite dazu bringen, ein JavaScript-Alert-Fenster mit der Message „HACKED!!!“ auszugeben.

Um DOM-basiertes XSS zu verhindern, müssen Ausgaben also auch clientseitig codiert werden. Möglich ist das z. B. durch die Bibliothek OWASP ESAPI, die dafür zwei einfache Funktionen zur Verfügung stellt:

$ESAPI.encoder().encodeForHTML( myinput );

$ESAPI.encoder().encodeForJavaScript( myinput );

Neue Techniken, neue Angriffsmöglichkeiten

Die zahlreichen Techniken, die HTML5 mit sich brachte, machten nicht nur das Web schöner und flexibler, sondern auch die Angriffsmöglichkeiten. Diese Features ermöglichen unter anderem den Aufbau von Botnetzen, das persistieren von Schadcode auf dem Client und Angriffe auf die Privatsphäre der Nutzer.

Persistieren von Schadcode

Das Persistieren von Schadcode auf dem Client ist dabei mit allen vorgestellten XSS-Arten möglich (persistent, reflected und DOM-based XSS). Während der Schadcode beim persistent XSS ohnehin schon auf dem Server persistiert ist, kann er bei den anderen XSS-Arten im Application Cache bzw. im Local Storage des Nutzers gespeichert werden. Das macht die Erkennung durch den Server schwer bis unmöglich.

Um den persistenten Code loszuwerden, müssen Web-Cache und Web-Storage komplett gelöscht werden. Der Browser kann danach allerdings sofort wieder infiziert werden, wenn der Schadcode noch in einem anderen Tab oder Fenster läuft.

Der Aufbau von Botnetzen

JavaScript kann Requests aller Art senden, und wenn das JavaScript persistiert ist, lassen sich damit sehr leicht Botnetze aufbauen. Das liegt unter anderem daran, dass inzwischen einige Botnetzframeworks entstanden sind – vergleichbar mit den bekannten App-Frameworks fürs Frontend. Nur eben für Botnetze. Tiago stellt als Beispiel BeEF vor, das eine übersichtliche Weboberfläche zum Dirigieren verschiedenster Botnetz-Funktionen bietet.

SVG-Grafiken

SVG-Grafiken können ebenfalls JavaScript-Code enthalten. Wenn sie über den <svg>-Tag eingebunden sind, wird dieser einfach ausgeführt. Deswegen sollte man zum Einbinden von Grafiken immer den <img>-Tag benutzen – dieser führt keinen Code aus.

Schutzmaßnahmen

Als Schutzmaßnahme schlägt Tiago Content Security Policies vor. Diese können im Webserver konfiguriert werden.

Da XSS-Angriffe meistens über Inline-Skripte in den Ausgaben von Webanwendungen funktionieren, können Content Security Policies grundsätzlich jegliche inline-Skripte verbieten. Darüber hinaus ist es möglich, das Einbinden von Skripten, Grafiken und Videos nur aus bestimmten Quellen zu erlauben. Auch XMLHttpRequests und andere Requests können durch Content Security Policies eingeschränkt werden.

Level-2-Content-Securitiy-Policies können Skripte sogar mittels eines Hashs absichern, der verifiziert, dass das Skript echt ist. Alternativ zum Hash kann, sofern das Skript vom selben Server wie die Webapplikation ausgeliefert wird, ein vom Server generierter Zufalls-Wert, der sogenannte Nonce, das Skript absichern. Dieser wird vom Server sowohl im Skript, als auch im Script-Tag eingefügt und kann von einem Angreifer nicht vorhergesagt werden.

Content Security Policies werden von allen verbreiteten Browsern akzeptiert und sollten daher eingesetzt werden.

JavaScript-Security Top 3

Zum Abschluss stellt Tiago die drei wichtigsten Punkte dar, die JavaScript-Entwickler aus seiner Sicht zum Thema beachten sollten:

  1. Der Client/Browser ist immer als unsicher zu betrachten – es ist immer davon auszugehen, dass er bereits kompromittiert wurde, weswegen alle kritischen Funktionen serverseitig validiert werden müssen

  2. XSS ist mit allen Maßnahmen um jeden Preis zu verhindern: Eingaben müssen immer validiert, Ausgaben kodiert, Content Security Policy aktiviert werden

  3. JavaScript-Bibliotheken müssen immer aktuell gehalten werden

Wertvolles Wissen über Sicherheit – JavaScript-unabhängig

Das Thema XSS-Sicherheitslücken kommt immer wieder auf, ich kannte das Prinzip und wählte diesen Vortrag nur „zur Sicherheit“, um als angehender JavaScript-Entwickler alles richtig zu machen. Dass das Thema so groß ist, welche Techniken alles zweckentfremdet werden können und dass es gar Frameworks gibt, um über XSS Botnetze aufzubauen, hätte ich hingegen nicht gedacht, weswegen ich sehr dankbar bin, diesen Vortrag gehört haben zu können. Das Wissen über die unterschiedlichen Angriffsszenarien wird mir unter allen Programmiersprachen und auch in der Backend-Entwicklung zugute kommen und mir helfen, sicherere Anwendungen zu entwickeln – ich hoffe, den anderen Hörern des Vortrags und den Lesern dieses Blogbeitrags geht es genauso.

Vue.js on Steroids

Christian Hunger und David Müller, eXXcellent

Vue.js gehört zu den beliebtesten drei JavaScript-Fameworks, was sich unter anderem auch in der Anzahl an Vorträgen auf der enterJS zu dem Thema widerspiegelt. In der Praxis wird vue.js allerdings selten alleine eingesetzt – vue.js on Steroids bietet am Beispiel eines fiktiven Supplements-Stores für Web-Developer Überblick über ein vue.js-Ökosystem mit den „Steroids“ nuxt.js, Vuetify, Vue-rx, Vuex und Jest.

Die Entwicklertools

Als Entwicklertools werden das Vue.js-CLI und das Devtools-Plugin für Browser vorgestellt. Beide werden am Beispiel des Supplement-Stores vorgeführt.

So erstellen die Vortragenden das Projekt über das CLI mit dem Nuxt&Vuetify-Template. Ohne Template erstellt das CLI über den Befehl vue create app eine nackte vue-App, das Template hingegen erstellt eine wesentlich umfangreichere Ordnerstruktur, die für die Verwendung mit vuetify.js und nuxt.js ausgelegt ist.

Die Devtools erweitern die Chrome-Entwicklertools um einen Vue-Tab, der tiefe Eingriffe in den Status der vue-Anwendung erlaubt wie das zurücksetzen von Mutations. Mutations sind Commits von States, die den jeweiligen Status der Anwendung repräsentieren, ein System, das von Vuex bereitgestellt wird.

State-Managment mit Vuex

Das State-Managment-Framework Vuex wird auch gleich als nächstes Steroid vorsgetellt. Wer Redux kennt, wird sich hier gleich zuhause fühlen, denn Vuex implementiert genau wie dieses das Flux-Pattern.

Ein State-Managment-Framework bietet allen Komponenten die Möglichkeit, ihren State an einer zentralen Stelle, dem sogenannten Store, zu verändern, und stellt somit einen zentralen Punkt für den Zustand der gesamten Anwendung bereit.

Das verändern des States findet über sogenannte Actions statt. Diese definieren eine Veränderung, ohne diese aber durchzuführen. Dadurch können sie auch asynchrone Abläufe beschreiben. Die tatsächlichen Veränderungen am State hingegen werden über Mutations durchgeführt.

Um auf den Store zuzugreifen, stellt Vuex Getter bereit. Diese bereiten Daten z. B. für die GUI auf und bieten eine logische Sicht auf den Store. Im Zusammenspiel mit Computed Properties lassen sich Getter einfach in eine UI-Komponente einhängen.

Nuxt: Server-Side-Rendering und mehr

Nuxt.js ermöglicht Prerendering, Server Side Rendering und vereinfacht das Routing. Vuex wird durch Nuxt bereits mitgebracht. Nuxt lässt sich in drei Production Modes betreiben:

Single Page Application

Die Single Page Application ist eine ganz normale Single Page Application, die clientseitiges Routing umsetzt und Inhalte per API-Aufruf vom Server nachlädt.

SPA mit Server Side Rendering

Beim Server Side Rendering wird das JavaScript und die Dom-Manipulation bereits vom Server ausgeführt, damit das fertig gerenderte HTML an den Client verschickt werden kann. Auch der Vuex-Store wird bereits vom Server gefüllt und an den Client übertragen. Das Nachladen von Inhalten entfällt, dadurch kann die Seite schneller geladen werden und ist außerdem suchmaschinenfreundlicher (wichtig für SEO). Außerdem ist zumindest beim ersten Seitenaufruf kein JavaScript auf dem Client notwendig.

Prerendered SPA

Statische Seiten kann man sich auch prerendern lassen – wer bspw. einen Blog betreibt, muss die Inhalte nicht bei jedem Seitenaufruf vom Server rendern lassen, sondern kann mit nuxt generate statisches HTML für jede Route generieren. Daher wird dieser Modus im Vortrag auch „Server Side Rendering Light“ genannt.

Alle Dinge, die Nuxt kann, lassen sich auch mit reinem vue.js umsetzen – Nuxt vereinfacht die Dinge aber.

Vue-rx

Vue-rx ist eine Umsetzung von ReactiveX für vue. ReactiveX bietet verbesserte Promises, die komlexe asynchrone Abläufe modellieren können, und versucht dabei das beste aus dem Observer-Pattern, dem Iterator-Pattern und funktionalem Programmieren zu vereinen.

Wer komplexe DOM-Events, Websockets oder Animationen umsetzen will, und wem Promises nicht ausreichen, sollte sich auf jeden Fall einmal mit dem ReactiveX-Konzept befassen.

Schnell UIs zaubern mit Komponentenbibliotheken

Slider, Text-Inputs, Buttons – die meisten GUIs bestehen seit der ersten Smalltalk-Entwicklungsumgebung aus denselben Elementen. Nur dass diese heutzutage geräteübergreifend funktionieren und sowohl mit Maus- als auch Touch-Eingaben zurechtkommen müssen.

Um diese Standard-Komponenten nicht jedes Mal neu schreiben zu müssen, empfiehlt sich der Einsatz von Komponentenbibliotheken – diese bieten einem sämtliche GUI-Elemente, von Slideshows, Tabellen, Radiobuttons bishin zu ganzen Dialogen und Bestellabläufen als Komponenten an.

Wer vor hat, mit vue.js eine Webanwendung zu bauen, sollte sich auf jeden Fall die beiden vorgestellten Komponentenbibliotheken, Vuetify und Buefy, anschauen.

Jest

Unabhängig von Vue.js ist es immer wichtig, Tests zu schreiben – auch für Frontender. Daher wird als letztes Steroid mit Jest das führende JavaScript-Testing-Framework vorgestellt. Jest rühmt sich damit, weitestgehend ohne Konfiguration zu funktionieren. Über die expect-Funktion, die das zu erwartende Test-Ergebnis definieren lässt, kann man so ohne große Lernkurve alle möglichen Arten von Tests schreiben.

Viel zu lernen du noch hast

Dieser Vortrag hat mir wieder einmal gezeigt, wie viel größer als ich dachte die JavaScript-Welt doch ist, und welches Potential in JavaScript-Frameworks steckt. Die meisten der vorgestellten Steroide sind so oder in ähnlicher Form nicht nur für Vue.js verfügbar, von daher werde ich mich auch in der Entwicklung mit anderen Frameworks mit interessanten Konzepten wie State-Managment oder ReactiveX beschäftigen.

JavaScript-Essentials: Die Engine

Rainer Hahnekamp

JavaScript wird zur Laufzeit ausgeführt, und wie jede zur Laufzeit ausgeführte Sprache braucht sie eine Engine. Zu wissen, wie die Engine funktioniert, ist Macht, denn nur so kann man effektiv seinen Code optimieren. Mit viel Live-Coding zeigt Hahnekamp, wie man die Engine für seine Zwecke nutzt.

JavaScript, die lahme Ente

JavaScript eilt ein Ruf voraus. Dieser setzt die Programmiersprache nicht unbedingt mit schnellen Ausführungsgeschwindigkeiten in Verbindung. Inzwischen setzen aber ganze Industriezweige auf die Entwicklung mit JavaScript, mit Node.js gibt es sogar einen als schnell geltenden JavaScript-Server, JavaScript läuft auf embedded devices. Benchmarks zeigen, dass JavaScript die Konkurrenz unter Umständen abhängt. Doch die Erfahrungen jedes passionierten Internetnutzers können bezeugen, dass es noch heute langsamen JavaScript-Code gibt, und wie kann JavaScript überhaupt schnell sein, wenn es doch zur Laufzeit interpretiert wird?

Hahnekamp schreibt ein Programm, das für vier verschiedene Star-Wars-Charaktere Objekte erzeugt, in denen jeweils der Name gespeichert ist. Um die Geschwindigkeit zu messen, iteriert er mehrere zehntausend Mal über die Objekte. Es dauert etwas mehr als zwei Sekunden. Fügt er jedoch einem Objekt eine Eigenschaft hinzu, die die anderen nicht besitzen, dauert das Iterieren über sieben Sekunden – wenn noch mehr Eigenschaften, wie Beruf (nur für Han Solo), Nachname (bei Yoda nicht bekannt) hinzugefügt werden, steigt die Zeit auf knapp 10 Sekunden an.

Optimierte Ausführung mit aktuellen Engines

Um dieses Phänomen zu erklären, führt Hahnekamp in die Geschichte von JavaScript ein: Früher war JavaScript nämlich wirklich sehr lahm und nur für einfach Funktionen in Websites gedacht. Erst mit Googles V8-Engine im Jahr 2008 wurde das Ausführen von JavaScript so weit optimiert, dass damit komplexe Webanwendungen möglich waren.

Dafür werden Teile des Codes vor der Ausführung im Hintergrund vorkompiliert. Gleichzeitig wird der schwach typisierte JavaScript-Code vor der Ausführung intern hart typisiert. Dafür erkennt die Engine in jedem Objekt ein Object Shape und teilt ihm eine Hidden Class zu. Wenn also mehrere Objekte dieselben Properties in der selben Reihenfolge besitzen, erstellt die Engine dafür heimlich eine Hidden Class. Dadurch weiß sie bei Iterationen direkt, wo die Properties im Speicher liegen und muss nicht immer erst die Speicheradresse ausrechnen.

Zurück zum Live-Coding-Beispiel

Hahnekamp ergänzt seine Star-Wars-Charaktere um die fehlenden Properties der anderen, und füllt diese einfach mit null auf. Die Iterationen dauern trotz gestiegener Anzahl der Properties keine drei Sekunden. Wer also gut aufpasst, kann durch das entsprechende Setzen von Properties ordentlich die Performance optimieren. Die gleichen Regeln gelten auch für Sprachen wie TypeScript, wie Hahnekamp referiert, da TypeScript später auch von der selben Engine ausgeführt wird – in den meisten Fällen sollte die Optimierung hier aber ohnehin greifen, da TypeScript eine harte Typisierung erzwingt.

Smarte Engines erfordern smarte Coder

Ich persönlich bin kein Freund davon, wenn eine Programmiersprache so smart ist, dass der Programmierer mindestens genau so smart sein muss, um zu verstehen, was sein Code eigentlich genau macht. Da JavaScript im Web aber einfach alternativlos ist, bin ich sehr froh, nun zu wissen, wie heutige Engines Objektzugriffe optimieren, da Perfomance gerade im Web mit seinen unterschiedlichen Endgeräten von entscheidender Bedeutung ist. Vor allem bin ich auch glücklich über die ansprechende Gestaltung des Talks mit den anschaulichen Live-Coding-Beispielen.

Aurelia – mehr Standards, weniger Framework

Katharina Bähr, Zühlke GmbH

Während es in den meisten Talks nur um die drei großen Frameworks Angular, React und Vue.js kreisen, hat sich Katharina Bähr mit ihrem Entwickler-Team für das Aurelia-Framework entschieden, das sich durch Konformität mit den allgemeinen Standards von JavaScript und TypeScript auszeichnet.

Todo-App

Todo-Apps sind nach Cookie-Hinweisen vermutlich der zweithäufigste Verwendungszweck von JavaScript. Daher bietet sich das Schreiben einer Todo-App als Einstieg in ein Framework ziemlich gut an.

Bähr führt mit einer gut abgestimmten Mischung aus Live-Coding und vorbereiteten Git-Commits durch die Todo-App. Aurelia fällt dabei vor allem dadurch auf, dass man es nicht bemerkt – der entstehende TypeScript-Code enthält kaum Hinweise darauf, dass ein Framework genutzt wird. Lediglich die Klasse main.ts implementiert eine configure-Funktion, der ein Aurelia-Objekt injiziert wird.

Generell ist der Konfigurationsaufwand bei Aurelia aber sehr klein, weil das Framework konventionenbasiert funktioniert. Wenn man sich an das vorgegebene Namensschema hält (das bei Bedarf natürlich konfigurierbar ist), wirkt das Projekt wie reiner TypeScript-Code. Wenn man bereits selbiges oder ES Next beherrscht, sollte Aurelia einen sehr einfachen Einstieg ermöglichen, da nicht viel gelernt werden muss.

Alle Features vorhanden

Aurelia kann trotzdem so ziemlich alles, was die bekannteren Konkurrenten können – Bähr selbst entwickelte bei Zühlke zunächst mit Angular.js, vor Erscheinen von Angular2 entschied sich das dortige Entwicklerteam aber für den Umstieg auf Aurelia. Inzwischen entwickelt sie Web-Apps nahezu ausschließlich mit Aurelia und ist von dem Framework sichtlich begeistert.

Die Community sei zwar nicht so groß, aber mindestens genauso hilfreich wie bei Angular. Das Projekt sei gut dokumentiert, die Erweiterungen zwar nicht so zahlreich, aber dafür umso häufiger vom Aurelia-Team selbst, was sich in Qualität, Dokumentation und Support positiv niederschlage.

Aurelia wird nicht von einem großen Internet-Konzern wie Google oder Facebook entwickelt. Statt dessen verdient Bluespire, das Unternehmen, das Aurelia ins Leben gerufen hat, sein Geld mit Support-Leistungen rund um das Framework. Dadurch hängt laut Bähr das wirtschaftliche Interesse stärker von den Bedürfnissen aller Nutzer ab, während die Entwicklung der anderen Frameworks von der Bedeutung dieser für die Technik-Plattformen der entwickelnden Unternehmen abhinge.

Aurelia ist freundlich

Die vorgestellten Eigenschaften des Aurelia-Frameworks gefallen mir sehr. Das Prinzip Convention over Configuartion kenne ich durch meinen Backend-Hintergrund aus der Entwicklung mit dem PHP-Framework Symfony, wo es den Code stark vereinfacht und gut strukturiert. Vor allem das Einsteigen in ein neues, unbekanntes Projekt wird meiner Erfahrung nach durch gute Konventionen stark vereinfacht und löst viele Probleme beim Verständnis des Codes.

Bähr stellt Aurelia dabei so überzeugend und sympathisch dar, dass ich direkt am nächsten Tag anfing, meine erste Aurelia-App zu schreiben. Dabei musste ich kaum etwas über Aurelia lernen, für mich war das eher ein TypeScript-Tutorial.

Auch Symfony wird durch ein Unternehmen entwickelt, das wirtschaftlich vor allem von Support und Schulung rund um ebendieses abhängt. Bei Symfony hat dieser Umstand zu einer sehr entwicklerfreundlichen Frameworkentwicklung geführt, was es mir plausibel erscheinen lässt, dass sich Bluespire ähnlich gut um die Belange der Entwickler kümmert.

Ein gewisses Kümmern um die Entwickler zeigt sich auch in der Öffentlichkeitsarbeit von Bluespire: nach dem Vortrag erfuhr ich im Gespräch mit Bähr von einem Paket mit Aurelia-Stickern, die das Aurelia-Team ihr zuschickte, nachdem sie auf ihren Blog gestoßen sind, der sich u. a. mit der Aurelia-Entwicklung beschäftigt.

Ich werde mir Aurelia weiter anschauen, und kann jedem, der auf der Suche nach dem richtigen Framework für sich ist oder einfach ein neues Framework ausprobieren möchte empfehlen, das gleiche zu tun.

Die enterJS als Perspektivwandel

Für mich als Backend-Entwickler war JavaScript immer nur das Zeug, das die aus dem Backend kommenden Websites schick animiert und langsam macht. Meine Perspektive auf JavaScript und clientseitige Programmierung als solche hat sich durch die enterJS massiv verändert, nachdem ich sehen konnte, wie viel damit wie ansprechend und performant umgesetzt werden konnte. Ich bedanke mich bei allen Vortragenden, den Organisatoren und bei meinem Kollegen Konstantin Tieber, der mir den Anstoß gab, mit auf die enterJS zu kommen.

]]>
Sun, 08 Jul 2018 08:42:10 +0200 https://www.webfactory.de/blog/enterjs-2018-nochmehr-talks https://www.webfactory.de/blog/enterjs-2018-nochmehr-talks webfactory GmbH webfactory GmbH 0
Für zukünftige Azubis: meine Projektpräsentation als Fachinformatiker bei der IHK Abschlussprüfung Es ist übrigens immer gut, wenn ihr Köder in eurer Präsentation auslegt, auf welche die Prüfer dann im Fachgespräch eingehen. Ich war besonders überrascht, als mich einer der IHK-Prüfer sogar über Containervirtualisierung mit Docker befragt hat, was mein Vorurteil, dass in der IHK-Prüfung nur ältere Technologien thematisiert werden, widerlegt hat. So konnte ich mein breites Wissen aus dem Bonner Microservices Meetup aus dem Ärmel ziehen.

Wenn ihr noch weitere Fragen zur Abschlussprüfung für den Beruf Fachinformatiker Anwendungsentwicklung habt, dann schreibt einfach eine Mail an info@webfactory.de oder tweetet an @xkons64 und ich werde meine Antworten gerne hier im Blog ergänzen.

Hier gibts meine Slides und mein Skript zum Download:

Slides

Skript

]]>
Thu, 05 Jul 2018 18:25:19 +0200 https://www.webfactory.de/blog/ihk-projektpraesentation-fachinformatiker-anwendungsentwicklung https://www.webfactory.de/blog/ihk-projektpraesentation-fachinformatiker-anwendungsentwicklung webfactory GmbH webfactory GmbH 0
enterJS Darmstadt 2018 - Eine Zusammenfassung ausgewählter Talks Übersicht

Micro Frontends: JavaScript Integration Patterns

von Nils Hartmann und Oliver Zeigermann

Nils und Oliver sind Serien-Speaker auf der enterJS. Sie beginnen den Talk mit der Behauptung, dass es genau drei Arten von Anwendungen gibt, die die bestmögliche Benutzererfahrung bieten:

Single-Page-Applications (SPA), mobile Apps und Desktop Apps. Auf die Frage, ob jemand aus dem Publikum nicht zustimmen würde, bleibt der Saal still.

Sie stellen drei Methoden/Architekturen für die Verbindung von Komponenten/Modulen im Frontend vor:

  1. HTML-Links

  2. Majestic Modular Monoliths

  3. Micro Components

Zu 1. HTML-Links

Die Benutzer navigieren über echte HTML-Links zwischen Seiten. Dabei ist jede Seite eine eigene SPA und sie teilen untereinander keinen State.

Diese Architektur ist besonders für Entwickler sehr bequem, da die Module der einzelnen Teams komplett unabhängig voneinander sind. Leider ist das auch der Katalysator für eine inkonsistente und schlechte Benutzererfahrung.

Als Beispiel für diese Architektur nannten Hartmann und Zeigermann Outlook Web. Hier ist der Mail Client in React implementiert und auf der linken Seite befindet sich eine Navigation, um beispielsweise von Mails zum Kalender zu wechseln. Klickt man auf den Kalender, so öffnet sich eine komplett andere Webanwendung, welche auch kein React einsetzen muss. Die Navigation, um zurück zu der React-basierten Mail Anwendung zu kommen, ist dort weiterhin vorhanden, allerdings ein bisschen anders positioniert, was für ein inkonsistente Benutzeroberfläche sorgt.

Zu 2. Majestic Modular Monoliths

Bei einem Majestic Modular Monolith befinden sich mehrere Module auf einer Seite.

Bei der Entwicklung wird empfohlen, dass es pro Modul nur ein Team geben darf. Die Module können entweder in einem großen Repository, vorzugsweise getrennt durch die Ordnerstruktur, oder auch in individuellen npm Paketen verteilt werden.

Für Module, die nicht in die offen zugängliche npm-Registry veröffentlicht werden sollen, gibt es inhouse Lösungen wie nexus. Ein statischer Build setzt schließlich alle Module zu einer Anwendung zusammen.

Um für schnellere erste Interaktion zu sorgen, soll Lazy-Loading verwendet werden.

Der Nachteil an dieser Architektur ist, dass die Entwickler-Teams ihr Frontend-Framework nicht flexibel wählen können, wie beispielsweise bei HTML-Links.

Der Vorteil daran ist, dass generische Präsentationskomponenten, wie Buttons oder Listen, über die Teams hinweg geteilt werden können, um konsistentes Design zu erzielen. Auf diese Weise wird die beste Benutzererfahrung in SPAs erreicht.

Majestic Modular Monoliths brauchen fast immer zentrales State-Management mit Tools wie Redux.

Diese Architektur könnte sich beispielsweise für Google Docs eignen. Wenn sich der Cursor im Text des Dokuments in einer gefetteten Zeichenkette befindet, so muss sich auch die „Werkzeugleistenkomponente“ aktualisieren und den Button für fette Schrift grau hinterlegen.

Zu 3. Micro Components

Im Gegensatz zu MMMs werden die einzelnen Module erst zur Laufzeit miteinander verbunden.

Die Kommunikation zwischen Modulen findet über einen EventBus (Vorschlag: PostalJS) oder geteilten State statt.

Man gewinnt wieder die Freiheit bezüglich der Wahl der Frontend-Frameworks, allerdings neigen diese SPAs aus genau diesem Grund dazu, recht groß zu werden, da mehrere Frameworks eingebunden gleichzeitig verwendet werden, weshalb sie eher für Desktop Apps oder Intranets verwendet werden sollten.

Die aktuell einzige Möglichkeit, um unterschiedliche Micro Components komplett ohne Interferenzen zu integrieren, sind iframes. Alternativen sind div-Tags mit script-Tags und web components, welche aber nicht ganz frei von Nebeneffekten sind.

Ein Beispiel für eine Micro Frontend Architektur ist Spotify.

Kommentar

Bisher bin ich bei meinen React Apps, in welchen oft viele Komponenten denselben zentralen State manipulieren, auch gut mit EventHandlern über Props zurechtgekommen und habe Redux lediglich zu Testzwecken ausprobiert. Nils und Oliver haben offensichtlich schon viele Begegnungen mit komplexen Frontends gehabt und für mich war dieser Talk sehr spannend.

No-Backend Peer to Peer Progressive Web Apps

von Felix Waterstraat und Sven Vowé (spreewunder GmbH)

Use-Cases

  • offline-first Apps

  • Apps, die zu vertrauliche Daten verarbeiten, um sie über einen Cloud Service kommunizieren zu lassen

Architektur

  • Datenbank lokal im Browser mit PouchDB oder Minimongo, welche als Wrapper für IndexedDB und localStorage agieren.

  • Datenbanksicherungen im Backend bei vorhandener Internetverbindung

  • Peer to Peer Synchronisierung mit WebRTC

  • RTCDataChannel zum teilen von Anwendungsdaten unter verschiedenen Browser-Instanzen

Das spreewunder Team kapselt diese Architektur in einem Framework, welches sie „Cloudless“ getauft haben. Es scheint allerdings nicht quelloffen zu sein.

Beispiel EKG-Messung

Das Team der spreewunder GmbH hat einen EKG-Rekorder, nach einem gescheiterten Versuch mit Web USB, über Web Bluetooth an eine No-Backend PWA angebunden und empfängt davon ca. 40000 Datenpunkte pro Sekunde, was mit einer HTTP-Schnittstelle, im Vergleich zu jungen Web-APIs, noch viel größere Herausforderungen mitgebracht hätte. Kleinere Schwierigkeiten mit der Datendurchsatzrate konnten dabei durch das Deaktivieren des Bluetooth Low Energy Modus (BLE) und Verwendung von Bluetooth 5 gelöst werden.

Mit Hilfe von Vega, einem Wrapper für D3.js, werden die Live-Daten in einem Diagramm visualisiert.

Kommentar

Dieser Vortrag hat mich definitiv beeindruckt und auch inspiriert, mich noch tiefer mit PWAs auseinanderzusetzen. Besonders die „persistente“ Speicherung in IndexedDB werde ich auf die Probe stellen, nachdem ich letztes Jahr schon meine alte Kalender Web-App mit der localForage-Library offline-fähig gemacht habe.

Ich finde es schade, dass Cloudless nicht quelloffen ist, da ich durch die Code-Beispiele zur Erstellung und Verwaltung von WebRTC-Verbindungen sehr neugierig geworden bin.

Common Ways We Break Accessibility and How to Avoid Them

von Laura Carvajal @lc512k

Die erste Frage, die wir uns bei Accessbility stellen sollten ist, ob unsere Seite auch ohne eine Maus bedienbar ist.

  • gibt es focus styles?

    • niemals outline: none

    • in CSS4 kommt focus-visible für tab-spezifische Focus-Styles

  • sind alle Elemente durch „Tabben“ erreichbar und in einer sinnvollen Reihenfolge?

    • <a> Tags ohne href-Attribut werden nicht angesteuert, benötigen tabindex=0

  • gibt es Inhalte, die von einem hover-Effekt abhängen?

Speziell für Screenreader ist es wichtig, dass alle <h> Tags auf einer Seite auch dessen Hierarchie widerspiegeln. Als Beispiel wird ein Video gezeigt, in dem ein blinder Mann im Rahmen eines Accessibility-Audits des Digital Accessibility Centers versucht, per Screenreader zu der Hardware-Support Seite auf der Amazon-Hilfeseite zu gelangen, wobei Elemente, die sonst <h2>-Elemente sein sollten, nämlich Unterkategorien für Hilfe (Bestellungen, Hardware, etc.), einfache Links waren. Aus diesem Grund, dauert es für den Besucher deutlich länger, zu der gewünschten Sektion zu navigieren.

H-Tags sollten auch nie zu Styling-Zwecken eingesetzt werden, sie dienen ausschließlich zur Repräsentation der Seitenstruktur!

Auf Seiten mit Video- oder Audioinhalten sind Untertitel einzubauen, welche keine Fehler enthalten und auch gut lesbar sind.

Kommentar

Ich freue mich immer auf Talks zu Accessibility, da ich bisher jedes Mal etwas neues gelernt und ein besseres Verständnis für die verschiedenen Herausforderungen von Menschen mit Behinderungen bei der Verwendung von Websites bekomme habe.

We need to talk about Preact

von Sara Vieira @NikkitaFtw

Preact ist eine JavaScript Library, die von Jason Miller begründet wurde, während er versuchte, die Innereien von Facebooks React zu verstehen. Heute steht eine große (19200 Sterne auf GitHub) und hilfsbereite Community dahinter und es wird von zahlreichen Firmen in Produktion eingesetzt (Uber, Lyft, Financial Times).

Sara nennt einige Punkte, in denen sich Preact von React unterscheidet:

  • 4KB Gzipped vs 32KB React

  • schneidet in Rendering-Benchmarks mehr als doppelt so schnell wie React ab

  • preact-router wird im Gegensatz zu React Router vom selben Team maintained wie die Haupt-Library

  • Standard-addEventListener für Event-Handling im Gegensatz zu Synthetic Events in React

Mit dem preact-compat Paket können außerdem React-Komponenten in Preact verwendet werden. Dazu gibt es im Repository auch eine Demo. Somit schließt man sich mit der Entscheidung für Preact nicht von der großen Auswahl an existierenden React-Komponenten aus.

In Zukunft bekommt Preact sogar asynchrones DOM-Diffing.

In einer Live-Demo baut Sara mit Hilfe der preact-cli eine Preact-App, die eine Liste der heutigen Spiele in der Fußball-WM Spiele inklusive einiger Details zeigt, welche sie sich von einer öffentlichen API holt.

Kommentar

Ich arbeite im Frontend aktuell hauptsächlich mit React und fühlte mich während der Preact-Demo auch direkt zu Hause. Der Sprung von React zu Preact scheint mir alles andere als dramatisch zu sein, allerdings bin ich dem preact-compat Paket gegenüber noch etwas skeptisch, da es sich einfach zu schön anhört.

In diesem Talk ist mir außerdem zum ersten Mal die neue <Fragment> Komponente aus React 16 begegnet. Endlich keine sinnlosen <div>s mehr!

TensorFlow.js

von Oliver Zeigermann @DJCordhose

Wer im Publikum macht Machine Learning? Drei Leute melden sich. Wer von euch kennt TensorFlow? Fast alle melden sich.

Oliver beantwortet für uns die Frage, warum man TensorFlow mit JavaScript verwenden wollen würde, wo doch Python viel schneller ist und es bereits viele Ressourcen dazu gibt:

  • Bildung

    • JavaScript kann man anfassen, man braucht nur einen Browser und Internet.

    • Konzepte sind einfacher zu begreifen, wenn man damit rumspielen kann.

  • Entwicklung

    • JavaScript ist eine weitverbreitete Sprache und dadurch spricht Google mit TensorFlow nun ein größeres Publikum an.

    • Kombination von Number-Crunching und interaktiven Visualisierungen.

  • Deployment

    • JavaScript ist womöglich die einzige Option für ML, weil der Browser alles ist, was du hast.

      • mobile Endgeräte

      • AI in Browser-Spielen

      • Unabhängigkeit von GPU-Hersteller

Um das beste aus beiden Welten zu bekommen, sprich die Schnelligkeit von Python und die Interaktivität von JavaScript, kann man erst in Python sein Keras oder TensorFlow Modell trainieren, um es dann mit dem tfjs-converter zu einem von TensorFlow.js lesbaren Format zu konvertieren und im Browser zu laden.

In Zukunft können wir dank WebGPU noch große Performance-Boosts für TensorFlow.js erwarten.

Kommentar

Auch wenn eine Vielzahl der Demos nicht so geklappt haben, wie erwartet, war es für mich dennoch ein sehr inspirierender Talk und ich hoffe ihr müsst nicht allzu lange warten, bis ich in diesem Blog eine Demo von einem Sprachmodell veröffentliche, das ich vor einem Jahr für den Bonn Data Science Meetup trainiert habe.

Cross-Plattform-Entwicklung mit React und React Native – Möglichkeiten und Stolpersteine

von Jasper Meyer @jasper__meyer

Jasper berichtet von seiner Erfahrung, eine existierende React App durch react-native zu erweitern. Mit Hilfe der react-native-cli ist das schon mit dem Ausführen von „react-native init“ getan, zumindest fast. Wer eine neue App mit React Native bauen möchte, verwendet besser „create-react-native-app“.

Es wird auf einige API-Unterschiede zwischen Web-React und React Native hingewiesen:

  • Styles

    • Web: CSS

    • Native: Stlye Objects

    • Eine Lösung für alle: cssinjs

  • Media Queries

    • Web: CSS

    • Native: Dimensions API

  • lokaler Key-Value-Store

    • Web: localStorage

    • Native: AsyncStorage

Wer React Native Komponenten auch direkt im Web verwenden möchte, für den gibt es react-native-web. Dazu noch ein Lesetipp von Jasper: Write once, run anywhere with Create React (Native) App and react-native-web

Wie darf man sich nun die Entwicklung von Komponenten in einer React Native App vorstellen?

Jasper beschreibt es mit dem bauen einer eigenen Komponenten-Library, um plattformspezifische Komponenten “automagisch” mit es6 imports zu bekommen.

Weiterer Lesetipp:

Warum AirBnb sich von React Native abwendet

Kommentar

In diesem Talk habe ich mich zum ersten Mal tiefer mit React Native befasst und habe bestimmt eine gewisse Sympathie dafür entwickelt. Am meisten stört mich wohl noch die 0 am Anfang der aktuellen react-native Version. Ich hoffe ja, dass ich in Zukunft mit Progressive Web Apps alle Plattformen glücklich machen kann. Dafür fehlt mir lediglich noch ein Pilotprojekt.

Unleash the Power of Higher-Order Components

von David Kopal @coding_lawyer

Eine kurze Definition von HOCs: Higher-Order Components sind Funktionen, die eine existierende Komponente entgegennehmen, diese manipulieren oder erweitern und eine neue Komponente zurückgeben.

David unterscheidet zwischen „smart components“, welche ausschließlich für Logik zuständig sind und „presentational components“, welche, wie es der Name schon sagt, meist nur noch aus der render Funktion bestehen. Diese „presentational components“ gilt es mit HOCs zu „dekorieren“.

Was macht eine wiederverwendbare Komponente aus? Sie ist nicht abhängig von einer spezifischen Property-Struktur.

Als erstes stellt David die sogenannte „Configured Higher-Order Component“ vor, welche dazu dient die Properties einer presentational component zu manipulieren.

HOCs können beliebig verkettet werden:

Die Recompose Library für React beinhaltet die meist verwendeten Higher-Order Components und eine compose() Funktion, welche eine beliebige Anzahl an HOCs entgegennimmt, um diese zu verketten.

Davids Vortrag war sehr Code-lastig und ich habe das Gefühl, dass ich dem Ausmaß der Wissensvermittlung, die ihm gelungen ist, in dieser Zusammenfassung nie gerecht werden kann.

Seine Code-Beispiele findet ihr unter https://github.com/codinglawyer/hocs-code

Kommentar

Higher-Order Components (HOC) ist ein weiteres Pattern, welches mir zum ersten Mal auf der enterJS begegnet ist. Der Speaker David Kopal, ursprünglich Anwalt, erklärt in einem sehr gut strukturierten Talk die Anwendung dieses Patterns, nachdem er es großflächig in einem komplexen React Frontend eingesetzt hat. Ich denke jedoch, dass HOCs ohne Code-Beispiele nicht so spannend sind und empfehle daher, sich Davids Beispiele und auch die offizielle React Dokumentation zu diesem Thema durchzulesen: https://reactjs.org/docs/higher-order-components.html

Einführung in D3.js – Mächtige Datenvisualisierung im Browser

von Mirco Zeiß @zemirco

D3.js ist eine JavaScript Bibliothek für Datenvisualisierungen im Web.

Über die „InputDomain“ kommen Daten in ein d3-Objekt rein und die „OutputRange“ projiziert die Daten.

In d3 gibt es drei Phasen:

  • Enter:      Neue Daten kommen hinzu

  • Update:  Bestehende Daten werden aktualisiert

  • Exit:        Bestehende Daten werden gelöscht

Der Punkt (0,0) ist in D3.js immer links oben und nicht links unten, wie wir es sonst vielleicht gewohnt sind.

Die API eines d3-Objekts lässt sich auf diese Methoden zusammenfassen:

  • constructor(config)

  • init()

  • render(data)

  • update(data)

  • resize(width)

React/Vue und D3.js sind ein Dream-Team! Lasse D3.js rechnen und nutze moderne Frontend Frameworks für dynamisches Re-Rendering.

Mirco hat ein Beispiel für eine Kombination aus React und D3.js auf GitHub veröffentlicht: https://github.com/zemirco/enterjs

Das dynamische Re-Rendering von Visualisierungen soll im „componentDidMount“ Lifecycle-Hook von React passieren, wobei die Reference der d3.js svg aktualisiert wird. Dabei ist es besonders wichtig, dass jeder Datenpunkt einen individuellen key hat.

Für Einsteiger/Neugierige

Es wird empfohlen, nicht direkt mit D3.js Wrappern einzusteigen, welche meist schwer erweiterbar sind, sondern lieber mit GitHub Gists bl.ocks.org einen interaktiven D3.js Playground zu verwenden, um mit reinem JavaScript und HTML neue Visualisierungen auszuprobieren.

Hier ein Beispiel: https://bl.ocks.org/zemirco/ef5dc3ae80b538e1034442c17c44237f

Wer heute ein Tutorial oder Buch zu D3.js bearbeiten möchte, sollte darauf achten, dass es mindestens mit Version 4 der Visualisierungs-Library arbeitet, da in dieser Version große Änderungen dazugekommen sind.

Leseempfehlung von Mirco: The Trouble with D3 plus die Diskussion auf Hacker News

Kommentar

Ich habe D3.js bisher nur indirekt über React Recharts verwendet und bin damit sehr schnell zu schönen Ergebnissen gekommen, die auch für professionelle Dashboards ausreichend waren und noch viel Spielraum bieten. Nach der inspirierenden Keynote von D3.js-Meisterin Shirley Wu war es umso spannender, einen Blick „unter die Haube“ zu werfen.

Epilog

An dieser Stelle möchte ich mich bei den Organisatoren der enterJS bedanken, die ein wirklich qualitatives und vielfältiges Programm auf die Beine gestellt haben! Ich komme gerne wieder :-)

]]>
Tue, 26 Jun 2018 15:45:39 +0200 https://www.webfactory.de/blog/enterjs-2018-talks https://www.webfactory.de/blog/enterjs-2018-talks webfactory GmbH webfactory GmbH 0
Microservices aus einer monolithischen Webanwendung extrahieren Typischerweise ist die Unübersichtlichkeit des Monolithen ein großes Problem. Sein schierer Umfang, mangelhafte Dokumentation und die Abwesenheit seiner ursprünglichen Entwickler erschweren uns häufig das Verständnis seiner internen Komponenten und ihrer Abhängigkeiten. Vielleicht gibt es Indizien wie Namespaces - aber niemand kann garantieren, dass die Ordnungsprinzipien über alle Entwickler hinweg mit dem gleichen Elan befolgt wurden. Spätestens beim Einsatz schwarzer Magie hilft auch keine statische Code-Analyse mehr - und wir leben in ständiger Angst, dass eine Änderung unbeabsichtigte Nebeneffekte haben könnte.

Sobald wir den alten Code verstanden haben, jucken uns wahrscheinlich schon mehrere Refactorings in den Fingern. Hier schnell etwas gerade ziehen, jenes nebenher vereinfachen. Aber der Monolith ist komplex, und ehe wir uns versehen, grinst uns ein sehr, sehr zotteliges Yak an, das wir zumindest in dem Moment doch lieber nicht rasieren wollen.

Deshalb ist es wichtig, eine Strategie mit ganz vielen Reißleinen zu haben. Sobald wir bemerken, dass wir uns verrannt haben, müssen wir schnell wieder auf den letzten Commit fliehen, in Sicherheit durchatmen und dann noch einmal frisch anfangen können. Aber Moment mal - ist das nicht ein Standardproblem der Software-Entwicklung? Ja! Und es gibt auch eine Standardlösung: automatisierte Software-Tests.

Automatisierte Black-Box-Tests

Im besten Fall decken wir mit (z.B. in behat geschriebenen) Black-Box-Tests alle Funktionen des als Microservice zu extrahierenden Features ab. Wir klicken das Feature im Monolithen einmal komplett durch und halten unsere Beobachtungen als Test-Erwartungen fest. So können wir nicht nur später die Funktionalität absichern, sondern lernen auch nach und nach die Details des zu extrahierenden Features kennen.

Beispielsweise können wir HTTP-Status-Code und spezifische Seiteninhalte für die Feature-Startseite testen, für eine Login-Funktion, Erstellen-, Lesen-, Bearbeiten- und Löschen-Operationen, das Abschicken einer Suchmaske und die entsprechende Ergebnisliste. Bei diesem explorativen Ansatz sollten wir berücksichtigen, ob es verschiedene Benutzergruppen (z.B. Administratoren) und damit eingehende Rechte gibt und für jedes dieser Rechte den Zugriffsschutz testen.

Unit-Tests sind in diesem Kontext weniger relevant. Denn zu diesem Zeitpunkt wissen wir noch nicht genug über den Monolithen bzw. den zu extrahierenden Microservice, als dass wir zu jeder getesteten Unit sagen könnten: Dies ist ihr Kontext und daher ist sie ir/relevant für uns.

Tipp: Datenbank-Dumps mit Slimdump
Mit den Black-Box-Tests können wir schon einmal annähern, welche Tabellen der Microservice benötigt bzw. welche Datenzeilen wir für unsere Test-Fixtures benötigen. Später werden wir das noch weiter eingrenzen können, aber für den Moment wollen wir unser Wissen schon einmal festhalten. Dazu können wir beispielsweise in slimdump, einem Tool für hochgradig konfigurierbare MySQL-Dumps, eine Konfigurationsdatei anlegen, versionieren und mit unseren Kollegen teilen.
Neben der Tabellen- und Datenzeilenauswahl können wir beispielsweise konfigurieren, dass Benutzernamen und E-Mail-Adressen einer User-Tabelle nur anonymisiert gedumpt werden oder dass wir aus Performance-Gründen in jener Tabelle nur 10% der Datensätze und keine BLOBs dumpen wollen.

Grüne Wiese oder Klon?

Wie starten wir konkret mit dem Microservice? Bei Null auf der grünen Wiese oder als Klon des Monolithen, von dem wir dann alles wegschneiden, was nicht zum Microservice gehört? Für beide Varianten gibt es gute Gründe, aber für mich kocht die Entscheidung auf die Abwägung zwischen diesen drei wesentlichen Kriterien ein:

  1. Menge der Einschränkungen: Auf der grünen Wiese starten wir mit minimalen Einschränkungen, im Klon nehmen wir erstmal dessen komplette technische Welt mit.

  2. Nutzung alter Meta-Daten: Meiner Erfahrung nach ist insbesondere die Commit Message History oftmals die einzige Chance, eine Stelle mit besonders verrücktem Code zu verstehen. Insbesondere, wenn durch eine Ticket-Nummer der Kontext der letzten Code-Änderungen deutlich wird.

  3. Latenz bis zur Live-Schaltung des Microservices: Starten wir unseren Microservice auf der grünen Wiese, haben wir eine sehr hohe Latenz, bis er live geschaltet werden kann: er muss erstmal von Grund auf entwickelt werden.
    Wenn wir dagegen den Microservice als Klon des Monolithen erstellen und auf einem eigenen Host betreiben, kann der prinzipiell sofort live gehen. Wir richten einfach irgendeinen Proxy (z.B. Varnish oder mit Apache Rewrite-Rules) vor dem Original-Monolithen ein, der Requests an den Microservice an dessen Host und alle anderen Requests wie gehabt an den Monolithen-Host leitet. Vielleicht müssen wir uns noch um Details bzgl. Cookies, Sessions und URL-Rewriting kümmern - aber das ist offensichtlich immer noch erheblich weniger Latenz als die komplette Neuentwicklung auf der grünen Wiese.

In meiner Erfahrung überwiegen die Argumente für den Start mit dem Klon. Ich vermute, dieser Weg ist im Allgemeinen auch ökonomischer: denn so viel Spaß die grüne Wiese auch bereiten mag - sie scheint mir nur ein Euphemismus für einen teilweisen Rewrite zu sein, der Klon dagegen die Basis für ein Refactoring.

Wahrscheinlich gibt es auch Projekte mit besonderen Umständen, in denen die grüne Wiese die klar bessere Entscheidung ist - an solchen habe ich aber noch nicht gearbeitet. Daher behandelt der weitere Artikel den Klon-Weg.

Tipp: Lauffähigen Monolithen behalten
Falls wir den Monolithen bereits installiert haben, sollten wir den tunlichst bis zur Live-Schaltung des Microservices behalten. Denn wir werden im Laufe des Projekts anhand von Heuristiken Entscheidungen treffen, die sich erst Tage später als falsch herausstellen können. Vielleicht schneiden wir zu viel Code weg oder vereinfachen ihn zu stark und stellen erst im Nachhinein fest, dass uns ein Test fehlte, der genau das anzeigen würde.
In solchen Momenten ist es extrem praktisch, schnell in einer lauffähigen Version des Monolithen nachsehen zu können, wie eine bestimmte Verarbeitung konkret ablief.

Erkennung ungenutzter Ressourcen

Wenn wir unseren künftigen Microservice als Klon des Monolithen aufgesetzt haben - wie erkennen wir die ungenutzten Ressourcen, die wir wegschneiden müssen, damit nur der Microservice übrig bleibt? Allgemein gilt:

Ungenutzte Ressourcen = alle Ressourcen - genutzte Ressourcen

Alle Ressourcen einer Art stehen typischerweise bereits als Liste bereit (z.B. bei Dateien mit ls) und die genutzten Ressourcen ermitteln wir mithilfe unserer Black-Box-Tests. Dazu müssen wir nur eine passende Form des Coverage Loggings aktivieren, die Tests ausführen und dann die Coverage in ein aussagekräftiges Format bringen. Schließlich bilden wir deren Differenz und haben damit die ungenutzten Ressourcen.

Unsere Tests haben also eine Doppelrolle: Erstens sichern wir mit Ihnen die Korrektheit des Codes und zweitens verwenden wir ihre Coverage zur Ermittlung der ungenutzten Ressourcen.

Schauen wir uns mal im Detail an, wie die Ermittlung der genutzten Ressourcen bei verschiedene Ressourcen-Arten funktioniert.

Genutzte PHP-Dateien

Die meisten PHP-Frameworks verarbeiten Requests über einen einen FrontController. In einen solchen können wir uns leicht einhaken und z.B. xdebug die Code Coverage loggen und die Pfade der genutzten Dateien in einer Datei used-files.txt ausgeben lassen:

<?php
// Coverage sammeln lassen
xdebug_start_code_coverage();

// Original-FrontController
$app = new App();
$app->handle($_REQUEST);

// Pfade genutzter Dateien schreiben
$outFile = fopen('used-files.txt', 'a');
fwrite(
  $outFile,
  implode(PHP_EOL, array_keys(xdebug_get_code_coverage()))
);
fclose($outFile);

Wir könnten dafür beispielsweise auch sysdig einsetzen, ein Tool zur Überwachung und Analyse von system calls und Linux kernel events. Dessen großer Vorteil ist, dass wir damit nicht nur verwendete PHP-Dateien erfassen, sondern alle geöffneten Dateien - also z.B. auch Konfigurationsdateien und View-Templates. Größter Nachteil ist, dass der benötigte Umfang nur auf Linux verfügbar ist.

Genutzte Composer-Pakete

Wenn wir die used-files.txt aus dem vorigen Abschnitt auf die Dateien filtern, die in einem Unterverzeichnis von composers vendor-Verzeichnis liegen, können wir aus ihren Pfaden unmittelbar die genutzten Composer-Pakete ablesen.

Genutzte MySQL-Tabellen

Ein Coverage Logging ist leicht z.B. mit folgenden SQL-Statements zu aktivieren:

SET global general_log = 1;
SET global log_output = 'table';

Führen wir nun unsere Tests aus, werden die SQL-Queries in der Tabelle mysql.general_log geloggt (die wir deshalb vorher vermutlich TRUNCATEn möchten). Aus diesen können wir die Namen der genutzten Tabellen extrahieren. Das ist händisch allerdings schnell zu mühsam. Denn zum einen werden es typischerweise sehr viele Queries sein. Zum anderen müssten wir bei jedem Query genau hinschauen, an welchen Stellen Tabellennamen vorkommen können: kommagetrennt in der FROM-Klausel, in der JOIN-Klausel und in Sub-Queries.

Genutzte Frontend-Assets

Die Pfade zu genutzten Frontend-Assets wie Bildern, Schriftarten, Javascript- und CSS-Dateien finden wir als Hits in den Webserver-Access-Logs. Mit einem regulären Ausdruck (für das Apache Standard-Access-Log-Format z.B. #"(?:get|post) ([a-z0-9\_\-\.\/]*)#i) können wir sie herausfiltern. Doch dabei gibt es ein paar Probleme:

Assets-Download: Das Standard-behat-Setup verwendet Goutte als Webbrowser, der keine Bilder, kein Javascript und kein CSS runterlädt und ggf. ausführt. Das heißt, diese Hits fehlen im Logfile. Als Lösung können in behat aber auch andere Browser bzw. Browser-Treiber angebunden werden - mittels Selenium auch Firefox, Chrome oder sogar eine Armada von Browserstack.

Konkatenierungen: Jahrelang haben wir die Performance von Webanwendungen verbessert, indem wir Javascript und CSS in wenigen Dateien konkateniert haben, um so die Anzahl der TCP-Verbindungen an unseren Server zu senken. Dieser Ansatz hat sich mit HTTP/2 überholt, wird aber noch viel in Legacy-Monolithen zu finden sein. Dann ist eine Aussage wie “screen.css und app.js werden genutzt” nur wenig hilfreich.

Hier könnte es am Einfachsten sein, die Konkatenierung auszuschalten und die Quelldateien direkt im HTML einzubetten - wenn denn noch leicht herauszufinden ist, welche Datei auf welche Seite eingebunden gehört.

Falls nicht, könnte die Coverage auf Zeilenebene innerhalb der Dateien in Verbindung mit Sourcemaps ausgewertet werden. Die zeilenbasierte Coverage ist wiederum ein eigenes Problem.

Automatisierte Zeilen-Coverage in Javascript und CSS: Für Javascript gibt es eine Vielzahl von Coverage-Logging-Tools wie Istanbul, JSCover und Blanket.js (und bis dieser Artikel erscheint, gibt es vermutlich wieder drei neue). Diese können an JS-Testrunner wie Karma oder Jasmin angebunden werden. Zusammen mit den eigentlichen Javascript-Tests kommt hier möglicherweise einiges an Aufwand hinzu.

Bei CSS ist die Lage noch schwieriger, aber immerhin gerade in Bewegung: Beispielsweise hat Chrome seit der Version 59 ein eigenes Panel für die CSS Coverage. Die Ermittlung der Coverage funktioniert grob so, dass für alle Selektoren in den geladenen CSS-Dateien geprüft wird, ob sie im geladenen Dokument treffen. Falls ja, werden sie und die damit verbundenen Statements als benutzt markiert. Das ist zwar nicht perfekt, scheint aber eine brauchbare Heuristik zu sein. Leider sind weder Ein- noch Ausgabe für diesen Prozess leicht automatisierbar. Es bleibt zu hoffen, dass entsprechende Methoden mittelfristig in der puppeteer-API ergänzt werden.

Wer diesen Prozess unbedingt jetzt schon automatisieren will, kann sich z.B. mit dem Firefox Plugin “Dust-Me Selectors” notbehelfen. Dort können eine Sitemap eingegeben und die resultierende Coverage auf Datei- und Zeilenebene als JSON exportiert werden.

Automatisierung mit dem Zauberlehrling

Der Zauberlehrling ist ein Open Source-Tool, das bei der Extraktion von Microservices unterstützen soll. Insbesondere automatisiert es einige Schritte zur Erkennung ungenutzter Ressourcen:

bin/console show-unused-php-files --pathToInspect --pathToOutput --pathToBlacklist usedFiles

zeigt die ungenutzten PHP-Dateien an. Als Eingabe dient das weiter oben erstellte used-files.txt. Außerdem können der zu untersuchende Pfad auf dem Dateisystem, eine Ausgabe-Datei und eine Blacklist konfiguriert werden, um z.B. Temp-Verzeichnisse auszuschließen oder solche, von denen bekannt ist, dass sie nicht von den Black-Box-Tests abgedeckt werden (z.B. Pfade für Unit-Tests).

bin/console show-unused-composer-packages --vendorDir composerJson usedFiles

zeigt die vermeintlich ungenutzten Composer-Pakete. Die Qualität der Aussage korreliert unmittelbar mit dem Inhalt der usedFiles-Datei: Für den Zauberlehrling gilt ein Paket als genutzt, wenn mindestens eine Datei darin genutzt wird. Enthält die usedFiles-Datei beispielsweise nur mit xdebug ermittelte PHP-Dateien, werden Composer-Pakete, die ausschließlich aus View-Templates oder Konfiguration bestehen, niemals als genutzt erkannt und immer als vermeintlich ungenutzt ausgegeben werden. Mit sysdig erstellte usedFiles-Dateien sind daher hier vorteilhafter.

bin/console show-unused-mysql-tables

ermittelt mit einem SQL-Parser aus der MySQL-Log-Tabelle die genutzten Tabellen, bildet die Differenz zu allen und zeigt die vermeintlich ungenutzten Tabellen an.

bin/console show-unused-public-assets --regExpToFindFile --pathToOutput --pathToBlacklist pathToPublic pathToLogFile

zeigt die vermeintlich ungenutzten Frontend-Assets. Nimmt die Pfade des Public-Verzeichnisses und Access-Logs als Eingabe und kann mit dem regulären Ausdruck zur Erkennung der Dateipfade im Access-Log, der Ausgabe-Datei und einer Blacklist (wie bei den ungenutzten PHP-Dateien) konfiguriert werden.

Kurze Entwicklungs-Zyklen

Die Automatisierung durch den Zauberlehrling ermöglicht das Arbeiten in kurzen Entwicklungszyklen. Nach einem initialen Coverage-Durchlauf können diese wie folgt aussehen:

  1. Ungenutzte Ressource löschen
  2. Tests ausführen (der Geschwindigkeit halber ohne Coverage)
  3. ggf. gelöschte Ressource wiederherstellen, Code oder Tests fixen
  4. committen
  5. zurück zu 1. oder Abbruch.

Sind die erkannten ungenutzten Ressourcen gelöscht, sollte wieder ein Testlauf mit Code Coverage durchgeführt werden. Es lohnt sich auch ein Blick auf die Liste der genutzten Dateien - vielleicht sind hier noch niedrig hängende Früchte zu erkennen. Wenn beispielsweise in einem Composer-Paket nur noch wenige Dateien benötigt werden, können wir es vielleicht ganz überflüssig machen und als Abhängigkeit entfernen. Vielleicht finden wir auch im Kontext unseres Microservices überflüssige Abstraktionen, die wir jetzt vereinfachen können.

Und anschließend nicht vergessen: die Tests wieder ausführen :)

___

Dieser Artikel erschien zuerst im PHP Magazin 2.18. Er basiert auf einem ausführlicheren Vortrag auf der FrOSCon 2017, dessen Mitschnitt beim CCC und auf Youtube veröffentlicht ist.

]]>
Wed, 23 May 2018 11:02:42 +0200 https://www.webfactory.de/blog/microservices-aus-einer-monolithischen-webanwendung-extrahieren https://www.webfactory.de/blog/microservices-aus-einer-monolithischen-webanwendung-extrahieren webfactory GmbH webfactory GmbH 0
Girls'Day bei der webfactory Nachdem uns im März eine E-Mail von einer Mutter einer Bonner Schülerin erreicht hat, in der sie fragte, ob ihre Tochter im Rahmen des Girls'Day zu uns in die Firma kommen könnte, haben wir uns auf der offiziellen Seite als Botschafter für mehr Frauen in der IT-Branche angemeldet.

Ich habe bereits 2015 einen Girls'Day organisiert, als ich noch bei IBM gearbeitet habe und nahm mich daher ohne zu zögern dieser Aufgabe an. Damals war das Feedback sehr positiv, sodass ich die Agenda vollständig übernommen habe:

  1. Kennenlernrunde
  2. Vorstellung der Tätigkeiten in den verschiedenen Rollen bei der webfactory (Backend-Entwicklerin, Designerin, Projektmanagerin)
  3. Spielerisch Programmieren lernen mit der "hour of code" https://code.org/learn
  4. Gemeinsames Mittagessen
  5. Erarbeitung und Präsentation einer eigenen Projektidee

Mit der Unterstützung von meinen Kollegen Eva, Jano und Søren haben wir die Mädchen durch das Programm begleitet.

Mein persönlicher Höhepunkt waren die kreativen Projektideen und der feste Vorsatz von einem der zwei Projektteams, von denen sich zwei von vier Teammitgliederinnen zuvor noch nicht kannten, sich in der Freizeit zu treffen, um das Projekt weiterzuentwickeln.

Schließlich erhielt jede Teilnehmerin noch eine Liste von nützlichen Ressourcen, um mehr über Webentwicklung und Programmierung zu lernen:

Wir sind gespannt auf die nächsten Marktführer für Mode-Sale-Finder und community-driven Fitnessratgeber im Web.

Unser Angebot auf der Girls'Day Website: https://www.girls-day.de/aktool/ez/eventvcard.aspx?id=73844

]]>
Mon, 30 Apr 2018 11:05:45 +0200 https://www.webfactory.de/blog/girls-day-2018 https://www.webfactory.de/blog/girls-day-2018 webfactory GmbH webfactory GmbH 0
Advanced subsearches and transactions in Splunk: Tracing qmail deliveries The email in question was part of a larger mail processing job, and we're using qmail to process these mails. Yes, qmail – it works great when it comes to doing high-volume, outbound-only deliveries in short time. 

The problem challenge is that qmail has an interesting way of logging in the current log, which looks like this:

@400000005aa66b052a527324 new msg 33778541
@400000005aa66b052a527edc info msg 33778541: bytes 7703 from <sender@host.tld> qp 21534 uid 64011
@400000005aa66b052a840e5c starting delivery 7512293: msg 33778541 to remote recipient@host.tld
@400000005aa66b060a418aac delivery 7512293: success: 176.34.178.125_accepted_message./Remote_host_said:_250_OK_id=1evM4J-0005W8-QC/
@400000005aa66b060a419a4c end msg 33778541

I am not talking about the funny-looking tai64 timestamps, but rather the message and delivery ids. There are several problems with this:

  • The message id is based on the Linux filesystem inode id for the mail file sitting in the queue. While being unique at a given time, multiple different mails will use the same message id over time.
  • The delivery id is just a counter that increments with every message processed. It will start from scratch if you restart qmail, and so again, this id is not unique over a longer time.
  • While you get the information that a particular delivery has been started for a given message id, all further information regarding the progress of this delivery is logged only with the delivery id, but does not show the message id again. That's probably due to the way the qmail architecture uses different processes for isolated tasks.

In order to get a comprehensive Splunk report for a given email address and to make it run in acceptable time, I had to learn about Splunk subsearches and transaction grouping.

Use a subsearch to narrow down relevant events

First, lets start with a simple Splunk search for the recipient address.

index=mail sourcetype=qmail_current recipient@host.tld

In particular, this will find the starting delivery  events for this address, like the third log line shown above. Having done our homework, Splunk extractions are set up in a way that we get the qmail_msg and qmail_delivery fields for this event.

Now, in order to get a complete report including delivery progress, we need to consider all log events that include either the appropriate message id or delivery id. 

With a default Splunk subsearch, the outer search will get all events where every field returned from the subsearch matches.

This works because Splunk applies the format  command implicitly on subsearches. Try this:

index=mail sourcetype=qmail_current recipient@host.tld | fields qmail_msg qmail_delivery | format

This will return a single event with a field named search  and a value like

( ( qmail_delivery="8227046" AND qmail_msg="33565415" ) OR ( qmail_delivery="7947353" AND qmail_msg="33719121" ) OR ...)

Splunk will first execute the subsearch. Then, the value from this search  field is taken as a replacement for the subsearch part of the query. Finally, the resulting query is executed.

You can, in fact, put the format command in your subsearch yourself and use parameters to modify the resulting string. Let's do this and directly combine it with a subsearch:

index=mail sourcetype=qmail_current [
    search index=mail sourcetype=qmail_current recipient@host.tld 
    | fields qmail_msg qmail_delivery  | format  "" "" "OR" "" "OR" ""
]

This search fetches all log events that either have a message id or a delivery id for any message or delivery ids that appears in context with the recipient address.

Group events as transactions

You can then use the transaction command to group events. As you can see from the log excerpt above, qmail transactions start with new msg  and end with end msg . We need to pick the message id from the start event and also include all events that have this message id and occur before the end event.

Additionally, the delivery id makes up the transaction. The transaction command is smart enough to pick up any delivery id that appears together with the message id we're following, and it can use this delivery id to include further events, even if they lack the message id. The transaction documentation has an example for this.

Adding a maximum duration between single transaction events for added performance, this gives us

| transaction qmail_msg qmail_delivery
    startswith="new msg" endswith="end msg"
    maxpause=1h

Now the last step is to once again filter out transactions that do not contain our intended recipient. Those transactions may show up because, as I stated in the beginning, the ids used by qmail are not unique. So while the subsearch finds the right ids for our particular recipient, the outer search may produce too many intermediate results.

We remove those transactions by applying a final

| search recipient@host.tld 

The result

Putting it all together, we get

index=mail sourcetype=qmail_current [
    search index=mail sourcetype=qmail_current recipient@host.tld
    | fields qmail_msg qmail_delivery
    | format  "" "" "OR" "" "OR" ""  
]
    | transaction qmail_msg qmail_delivery
          startswith="new msg" endswith="end msg" maxpause=1h
    | search recipient@host.tld

Most Splunk queries like this seem to do magic. And once they work, you tend to forget how they work or why they probably produce correct results. In part, this is why I am writing this up as a note to my future self.

Also, because a query like this is hard to remember or to re-construct, I saved this search as a Splunk dashboard. That allows you to add a handy input box for the address et voilà, we have a simple-to-use interface for our next support call.

]]>
Fri, 16 Mar 2018 09:47:31 +0100 https://www.webfactory.de/blog/splunk-subsearch-transaction-qmail-deliveries https://www.webfactory.de/blog/splunk-subsearch-transaction-qmail-deliveries webfactory GmbH webfactory GmbH 0
Ein paar Worte zum Schluss Frohe Weihnachten

Danke!

Weil es so schön ist, fangen wir doch gleich einmal mit dem Dank an: Liebe Kunden, die Zusammenarbeit mit euch ist das Kernstück unserer Arbeit. Wie könnten wir also nicht mit euch beginnen? Wir danken euch dafür, dass ihr uns – viele von euch schon seit so vielen Jahren – euer Vertrauen schenkt. Jeder einzelne von euch liegt uns wirklich sehr am Herzen und wir sind nach wie vor fest davon überzeugt, die besten Kunden der Welt zu haben! Auch 2017 haben wir wieder einige spannende Aufgaben gemeinsam mit euch gestemmt. An großen Projekten hervorzuheben ist sicherlich der schrittweise Launch der Staatsoper Berlin von Juni bis Oktober. Das Projekt hat uns trotz – oder vielleicht gerade wegen – seiner Komplexität und seines Umfangs sehr viel Spaß gemacht. Wir freuen uns ganz besonders darüber, dass das gute Feedback des Staatsoper-Teams uns direkt ein Folgeprojekt für das Staatstheater Darmstadt in die Firma gespült hat. Neben den Webprojekten aus dem künstlerischen Feld begleitet uns außerdem fast schon das ganze Jahr die Überarbeitung der Website des Gemeinsamen Bundesausschuss, die wir 2018 fertigstellen werden. Auch Jugend für Europa hat uns dieses Jahr wieder einige Projekte beschert: Besonders spannend ist dabei gerade die Umsetzung der Website für das neue Förderprogramm des Europäischen Solidaritätskorps, das 2018 an den Start geht. 

Danke sagen möchten wir außerdem auch all unseren externen Kooperationspartnern und Helferlein, die uns auch in diesem Jahr wieder an vielen Fronten unterstützt haben: Lieben Dank an Benjamin O’Daniel für die Unterstützung bei unserer Mitarbeitersuche und für all den wertvollen Input. Danke an Ruth und ihr Team von kaffeetante.net für die tolle Kooperation bei unserem FrOSCon-Kaffeestand. Danke an die Odenthal-Illustratoren für unsere schönen, neuen Team-Avatare und danke auch an unsere gute Bürofee Jutta für all die Blumen, Kürbisse, Kerzen und Schokoladen, mit denen du uns dieses Jahr eine Freude gemacht hast. 

Webfactory 2017 intern

Für unseren kleinen webfactory Mikrokosmos war das Jahr unseres 20. Geburtstags relativ turbulent. Besonders beeinflusst hat uns sicherlich der Verlust von gleich drei Kolleg*innen in der ersten Jahreshälfte. Auch viele unserer Kunden haben dies leider durch einige Projektverzögerungen zu spüren bekommen. An dieser Stelle danken wir euch hier noch einmal ganz herzlich für eure Geduld. Auf der anderen Seite freuen wir uns sehr darüber, drei neue Kolleg*innen dazugewonnen zu haben, die uns maßgeblich im Frontend, in der Konzeption und Projektorganisation unterstützen. Damit sind wir aber noch lange nicht am Ende, denn im Backend suchen wir immer noch dringend nach Verstärkung. Im vergangenen Jahr haben wir im Hinblick auf die Mitarbeitersuche erstmals in der Firmengeschichte einen eigenen, kleinen Konferenzstand auf der FrOSCon12 betreut und im nächsten Jahr legen wir direkt noch einen drauf: Ab Januar könnt ihr an ausgewählten Bushaltestellen im Bonner Stadtgebiet unsere knallorangene Stellenanzeige bewundern. 

Eine weitere große Veränderung dieses Jahr betrifft die Art und Weise, wie wir unsere Aufgaben organisieren. Seit einigen Monaten sind wir damit beschäftigt, dafür ein sogenanntes Kanban-System in unsere Projektabläufe zu integrieren (dazu sicherlich zu einem späteren Zeitpunkt einmal mehr). Auch wenn wir noch nicht am Ende angelangt sind, so haben wir doch das Gefühl, schon einiges in eine sehr positive Richtung bewirkt zu haben. Insgesamt erhoffen wir uns von der Umstellung eine Intensivierung unseres Arbeitsfokus, einen schnelleren Durchlauf der einzelnen Aufgaben und eine Verbesserung in der Vorhersagbarkeit von Projektlaufzeiten. 

Bei aller Ernsthaftigkeit darf aber auch der Spaß nicht zu kurz kommen, dieses Jahr zum Beispiel in Form eines Paintball-Teamevents. Und auch, wenn es vielleicht nur eine Kleinigkeit ist, freuen wir uns darüber, dass wir uns nach wie vor jeden Mittag zu einem gemeinsamen und vor allem selbst zubereiteten Essen zusammenfinden. Wir glauben, dass wir nur dann zur Höchstform auflaufen, wenn wir zufrieden mit dem sind, was wir tun und wenn wir nicht nur auf Effizienz und Output blicken, sondern ebenso auf soziale Faktoren achtgeben. Somit versuchen wir in unserer Firma einen Ort zu schaffen, an dem alle offen und ehrlich miteinander reden können und auch den Bedürfnissen einzelner Raum gegeben wird. 2017 konnten wir wieder einen stattlichen Jahresbonus an all unsere Mitarbeiter ausschütten und dem Team mit der Zahlung eines 13. Gehalts eine Freude machen. Zum Jahresende haben sich auch auf der sozialen Ebene noch einige Neuerungen ergeben: Seit kurzem bieten wir allen Mitarbeitern die Möglichkeit, jeden Morgen vor Arbeitsbeginn an einer fünfminütigen Meditationsübung teilzunehmen. 2018 wollen wir außerdem ausprobieren, wie sich das Leben mit einem Bürohund anfühlt. 

Zu guter Letzt bleibt nur noch zu sagen: Wir freuen uns auf 2018 und sind gespannt, was das neue Jahr zu bieten hat!

Wir wünschen euch allen fröhliche Weihnachten und einen guten Start in das neue Jahr.

Herzliche Grüße
eure webfactory 

]]>
Tue, 19 Dec 2017 13:55:47 +0100 https://www.webfactory.de/blog/ein-paar-worte-zum-schluss-2017 https://www.webfactory.de/blog/ein-paar-worte-zum-schluss-2017 webfactory GmbH webfactory GmbH 0
UXBN@webfactory zu Performance und UX-Test-Methodenmix Nachdem die Teilnehmer gemütlich eingetroffen und mit Getränk und Snacks in der Hand in eine erste Networking-Runde gestartet waren, machte unser Kollege Søren mit seinem Vortrag zu Performance als neuer UX-Grundanforderung den Anfang.

Nach einer kurzen Einordnung, warum Performance (im Sinne von schnellen Ladezeiten und zügig verfügbarer Interaktivität auf Webseiten oder in Apps) ein wichtiges Thema ist, führte Søren die Anwesenden durch eine Reihe von Erkenntnissen der Neurowissenschaften zu Zeit, Zeitwahrnehmung und vor allem der "Psychologie des Wartens". Wichtigstes Take-away: es gibt einen erheblichen Unterschied zwischen objektiv messbarer Zeit und dem, was das menschliche Hirn daraus macht. 

Neben der Unterstützung von Entwicklern bei der Reduktion der objektiven Ladezeiten können sich UX-Spezialisten genau diesen Unterschied mit schlauen Tricks zu Nutze machen, um einen wichtigen Beitrag zur Optimierung der vom Nutzer empfundenen ("perceived") Performance zu leisten. Søren stellte dazu sieben Maßnahmen anhand von praktischen Beispielen vor.

Nach kurzer und diskussionsreicher Pause ging es weiter mit Bastian Weber, der extra aus dem fernen Dresden angereist war, um uns Lehren aus der täglichen Arbeit mit A/B-Tests bei der m-pathy GmbH näherzubringen.

Bastian stellte vor allem heraus, dass A/B-Tests nur eine von vielen Methoden sind, sich einer optimalen User Experience anzunähern. Insbesondere gab er zu bedenken, dass ein A/B-Test nicht notwendigerweise ein korrektes Gesamtbild zeigen muss: In einem Beispiel wären A/B-Tests zur Verbesserung der Absprungraten auf einer bestimmten Seite (hier: Liste von Suchergebnissen) nicht sinnvoll gewesen, da das Problem der Nutzer tatsächlich auf der vorherigen Seite (hier: dem Suchformular) lag.

Neben der Empfehlung, immer lieber auf einen guten Methodenmix zu setzen, als sich auf eine "Lieblingsmethode" zu beschränken, gab Bastian noch ein paar Tipps, wie man zu guten Test-Hypothesen kommt – und wie nicht. 

Nach den beiden Vorträgen ließen wir den Abend bei entspannt-angeregten Gesprächen und netzwerkeliger Atmosphäre langsam ausklingen und freuen uns auf neue UX Themen im nächsten Jahr – sehr gerne auch wieder bei uns im wfLab!

---

* Der Vortrag von Jörg Niesenhaus über Erfahrungen aus 5 Jahren Arbeit mit Gamification musste krankheitsbedingt leider kurzfristig ausfallen, wird aber im Januar beim nächsten UXBN Termin bei Aktion Mensch nachgeholt.
 

]]>
Tue, 12 Dec 2017 13:40:39 +0100 https://www.webfactory.de/blog/uxbn-bei-webfactory-performance-methodenmix https://www.webfactory.de/blog/uxbn-bei-webfactory-performance-methodenmix webfactory GmbH webfactory GmbH 0
Erasmus+ Social Inclusion Days: Dinner in the Dark bei der webfactory Die 21 Teilnehmerplätze für Erasmusstudierende in Bonn waren innerhalb von zwei Stunden nach Beginn der Anmeldung vergeben und wir freuten uns über das große Interesse.

Es galt ein Menü, Tische, Sitzplätze, Geschirr, Besteck und Augendbinden zu organisieren. 

Trotz des engen Zeitplans ist am Freitagabend alles bereit und das dreiköpfige Koch-Team bezieht um 17:30 Uhr die webfactory Küche, wo sie für den Rest des Abends kulinarische Genüsse zaubern. Ab 18 Uhr wird das webfactory Lab umgebaut und Augenbinden werden vorbereitet, bis kurz vor 19 Uhr schon die ersten Gäste eintreffen. Jeder Gast bekommt die Augen verbunden und wird daraufhin zu einem zufällig zugewiesenen Platz an der großen Tafel geführt. 

Als wir den ersten Gang, Feldsalat mit Feta, Granatapfel und Walnüssen, servieren, sind neue Bekanntschaften geschlossen und von oberflächlichen Gesprächen ist keine Spur. Oft wird eine leere Gabel zum Mund geführt, weswegen manche auf manuellere Methoden umsteigen. Für die Organisatoren bieten sich recht amüsante Szenen, zum Beispiel als wir den Teller einer Teilnehmerin entfernen, sodass sie mit Gabel und Löffel den Tisch nach ihrem Salat absucht.

Vor dem Hauptgang servieren wir den Gästen erst noch ein paar Gegenstände, die sie in Teams abtasten, um zu erkennen, worum es sich handelt.

Als Hauptspeise gibt es Nudeln mit Kirschtomaten und Weißweinsauce, welche eine willkommene Abwechslung von den schwer zu befördernden Salatblättern bieten.

Im Anschluss verwöhnt uns das Koch-Team mit einem Bratapfel-Schichtdessert, dessen Keksboden für besondere Verwirrung bei der Identifizierung sorgte.

Bei einem „Dinner in the Dark“ hat man nicht nur ein erhöhtes Geschmacksempfinden, sondern bekommt auch einen Eindruck davon, wie es ist, blind zu sein. Nachdem unsere Gäste die Augenbinden abnehmen dürfen, sagt mir eine Teilnehmerin, dass sie sich zu Hause unbedingt informieren müsse, wie blinde Menschen mit den Herausforderungen zurechtkommen, mit denen Sie sich in den vergangenen zwei Stunden zum ersten Mal konfrontiert sah.

Zum Abschluss zeigen wir zur Belustigung noch die Fotos und Videos des Abends auf der Leinwand.

Unsere Gäste und das ESN Bonn bedanken sich herzlich für die großzügige zur-Verfügung-Stellung der webfactory Räumlichkeiten!

]]>
Mon, 04 Dec 2017 16:24:41 +0100 https://www.webfactory.de/blog/erasmus-social-inclusion-days-dinner-in-the-dark https://www.webfactory.de/blog/erasmus-social-inclusion-days-dinner-in-the-dark webfactory GmbH webfactory GmbH 0