<<

Experten-Dossier 2019

Über 80 Seiten mit praxisorientiertem Wissen für .NET-Entwickler rund um .NET Core, Azure DevOps, TypeScript, Cosmos DB, ML.NET, und Azure!

bastacon www.basta.net Inhalt

Agile & DevOps

Die DevOps-Challenge 4 DevOps-Fallstricke und wie man ihnen entkommen kann von Kevin Gerndt

Microservices & APIs

Warum einfach? Es geht auch komplex! 10 Entwicklung von Microservices mit Microsoft .NET von Dr. Felix Nendzig

Go Git! 16 Git erobert die Entwicklerwelt von Uwe Baumann

Des Kaisers neue Kleider 21 Aus VSTS wird Azure DevOps – mehr als nur ein neuer Name? von Nico Orschel und Thomas Rümmler

.NET Framework & #

R. I. P .NET „Core“ 29 .NET Framework, .NET Core und Mono sind tot – lang lebe .NET 5.0! von Dr. Holger Schwichtenberg

Machine Learning für die Zukunft 33 Hintergrund und Einstieg in ML mit .NET von Kevin Gerndt

Architektur

Kolumne: Stropek as a Service 40 Zehn Hausaufgaben für die Cloud-Architektur – Eine gute Softwarearchitektur setzt klare Ziele voraus von Rainer Stropek

Große Business-Apps mit Angular meistern 43 Nachhaltige Angular-Architekturen mit Nx und Strategic Design von Manfred Steyer Inhalt

Sicherheit

Du kommst hier nicht rein 48 API Authorization in ASP.NET Core 3.0 mit IdentityServer von Sebastian Gingter

Wasm – Ist das sicher oder kann das weg? 53 Neue Besen kehren gut, sagt man. Aber sind sie auch sicher? von Carsten Eilers

HTML5 & JavaScript

Das Beste aus zwei Welten 59 Mit ASP.NET Core und Angular eine Webanwendung erstellen von Fabian Gosebrink

Injections für echte TypeScript-Junkies 70 Dependency Injection in unter 200 Zeilen Code – ohne Leerzeilen von Thomas Mahringer

Olis bunte Welt der IT 76 Wenn’s etwas weniger sein darf: React und Redux kombiniert von Oliver Sturm

Data Access & Storage

Progressive Web Apps auf Knopfdruck? 66 Ohne Umwege zu offlinefähigen Webanwendungen mit Angular und @ angular/service-worker von Manfred Steyer

Ganz ir-relational 80 Cosmos DB in eigenen Projekten einsetzen: Grundlagen und Einsatzszenarien von Thorsten Kansy DOSSIER Agile & DevOps

DevOps-Fallstricke und wie man ihnen entkommen kann Die DevOps- Challenge

Noch vor einigen Jahren wurde die IT in Unternehmen als notwendiges Übel wahr- genommen. Doch in Zeiten von digitalen Geschäftsmodellen und Produkten haben Unternehmen den wahren Wert dieses Bereichs erkannt. Das birgt jedoch eine Menge neuer Herausforderungen, denn der Wettbewerbsdruck steigt stetig und die Entwicklungszyklen werden immer kürzer. DevOps scheint das Allheilmittel zu sein, der Weg dorthin ist aber steinig.

von Kevin Gerndt zur Vermittlung von Dienstleistungen. Doch sind es oftmals diese Unternehmen, die durch hohe zweistel- Das „Digital Mindset“ hat unlängst Einzug in große lige Wachstumszahlen brillieren und schnell einen deutsche Konzerne gehalten. Das zeigen diverse Studi- Milliardenwert auf die Börsenwaage bringen. Um ein en und dass die Notwendigkeit erkannt wurde, einen solches produktgetriebenes Wachstum zu erreichen, neuen Platz in der Führungsetage für den Chief Digital ist es erforderlich, extrem schnell und agil auf Ver- Officer (CDO) zu schaffen. Der CDO soll Unterneh- änderungen und Anforderungen reagieren zu können. men erfolgreich durch die digitale Transformation füh- In dieser Disziplin sind die oft „tankerähnlichen“, in ren. Denn der Wettbewerbsdruck wächst zunehmend Silos organisierten Großunternehmen ganz klar unter- und immer mehr Firmen setzen auf die Entwicklung legen. digitaler Produkte und Services. Wer nicht Opfer der Letztendlich ist jedoch alles eine Frage der Strategie Disruption werden möchte, muss sich diesem Trend und des Willens. Im Jahr 2018 hat Klaus Straub, CIO bei anschließen und der Konkurrenz immer einen Schritt BMW, angekündigt, das Unternehmen im Rahmen einer voraus sein. Interessanterweise beschränkt sich diese agilen Transformation ganz klar in Richtung Produkt­ Entwicklung nicht nur auf einzelne Branchen, sondern orientierung bzw. Agile Operating Model auszurichten. ist nahezu in allen Marktsegmenten erkennbar. Wer Unter dem Motto „100 % agil“ ist das erklärte Ziel, bis hätte vor fünfzehn Jahren schon gedacht, dass Unter- Ende 2019 nicht nur sämtliche laufende IT-Projekte des nehmen aus dem Bereich Automotive einmal Unsum- Unternehmens auf agil umzustellen, sondern auch die men in die Entwicklung und Bereitstellung digitaler IT-Organisation vollumfänglich nach agilen Prinzipien Services investieren würden? auszurichten. Ein zwingendes Erfordernis stellt die enge Ein gutes Beispiel hierfür ist der Car-Sharing-Dienst Zusammenarbeit zwischen Fachbereichen und der IT- DriveNow des Automobilherstellers BMW. Durch Abteilung dar. das Car-Sharing-Angebot verlängert sich einerseits Aber auch hinter den Mauern der IT ist ein enger die Wertschöpfungskette hin zum Kunden, auf der Schulterschluss gefragt. Gemeint ist damit natürlich anderen Seite lassen sich wertvolle Benutzerdaten DevOps – die Verschmelzung von Entwicklung und Be- sammeln. Wie lukrativ Servicemodelle sein können, trieb. Das Schaffen einer DevOps-Kultur ist jedoch viel zeigen Unternehmen wie myTaxi, HRS oder Uber. mehr als nur das Vorhaben, Abteilungen und Bereiche Diese Firmen sind weder im produzierenden Gewerbe zusammenzuführen. Es handelt sich vor allem um eine tätig, noch besitzen sie physische Güter. Sie fungieren Revolution im Kopf aller Beteiligten, einen Umdenkpro- lediglich als Serviceprovider und bieten die Plattform zess, der von höchster Ebene angeregt werden muss. Vor

www.basta.net 4 DOSSIER Agile & DevOps

allem ist es wichtig, die so häufig im Kopf existierenden reiche. Zögerliche Unternehmen riskieren mittel- und Silos abzureißen. Doch was genau bedeutet das? langfristig ihre Wettbewerbsfähigkeit. Im schlimmsten Stellt man sich einmal den klassischen Entwicklungs- Fall werden sie Opfer der Disruption und verschwin- prozess vor, läuft es meist so, dass die Fachabteilung den vom Markt. Doch auch Unternehmen, die sich un- mit einem Anforderungskatalog an den Entwicklungs- längst für eine DevOps-Strategie entschieden haben, bereich herantritt. Dieser entwickelt die , um kämpfen mit der Umsetzung. Unternehmen buhlen sie anschließend an den Betrieb zu übergeben. Das Be- mit allen Mitteln um die Gunst der wertvollen Ent- triebsteam wiederum stellt dann fest, dass die Software wicklerressourcen. Keine Entwickler zu finden, ist für so nicht den Betriebsanforderungen entspricht oder viel- moderne Unternehmen existenzgefährdender als der leicht auch einfach nur essenzielle Artefakte wie etwa fehlende Zugang zu frischem Kapital an den Finanz- das Betriebshandbuch fehlen. Indes ärgert sich der Fach- märkten. Umso wichtiger ist es, eine solide und nach- bereich über die mangelnde Kompetenz der IT und die haltige Basis für einen langfristigen Erfolg zu schaffen. Verzögerung bei der Inbetriebnahme. Ist die Software an Nachfolgend erläutere ich einige der Grundprinzipien den Betrieb übergeben, lehnt sich die Entwicklungsab- von DevOps. teilung oftmals entspannt zurück, denn ihre Bringschuld Kultur der Zusammenarbeit: Das A und O einer er- ist erfüllt. Kommt es im Betrieb einer Applikation zu folgreichen DevOps-Strategie ist das Erlangen einer Problemen, geht das Fingerzeigen erneut los. Der Betrieb Kultur der Zusammenarbeit. In einer traditionell aus- beschuldigt die Entwickler, die Entwickler den Betrieb. gerichteten IT verfolgen Entwicklung und Betrieb unter- In großen Unternehmen können diese Extra­runden schiedliche Ziele mit unterschiedlichen Prioritäten. Die schon einmal Wochen oder gar Monate an Verzug be- Entwicklung ist meist agiler und benötigt die Freiheit, deuten; ein Zeithorizont, der sich nicht mit einer agilen Änderungen vornehmen zu können, der Betrieb hinge- Strategie und der Verkürzung von Go-to-Market-Zyk- gen schwört auf Stabilität. Eine enge Zusammenarbeit len vereinbaren lässt. dieser Bereiche ist jedoch einer der wichtigsten Aspekte, In einem DevOps-Szenario übernimmt das Team, wenn es um DevOps geht. Das Schaffen eines Informa- bestehend aus Produktmanagern, Entwicklern und Be- tionsaustauschs in Echtzeit ermöglicht es den Teams, triebsleuten, gemeinsam die Verantwortung für einen einerseits schnelle Änderungen an einer Applikation erfolgreichen Ablauf und Betrieb. Alle verfolgen diesel- vornehmen zu können und andererseits eine stabile und ben Ziele und ziehen am gleichen Strang. Welche kriti- robuste Betriebsumgebung zu erhalten. Tools wie etwa schen Erfolgsfaktoren neben der Kultur noch existieren Slack, Yammer und Microsoft Teams können dazu und welche Tools und Plattformen bei der Einführung verhelfen, die Hürden einer klassisch formalen E-Mail- von DevOps hilfreich sein können, werden wir im Fol- Kommunikation abzubauen. genden betrachten. Einhalten von Architekturrichtlinien: Um die Be- treibbarkeit, Stabilität und Kompatibilität einer Soft- Die Säulen des Erfolgs ware zu sichern, ist es wichtig, Leitlinien zu definieren Auch wenn einige Unternehmen DevOps nur nutzen, und diesen zu folgen. Enthält eine Applikation bei- um kurzfristige Effizienzvorteile zu erhalten, wird spielsweise viele direkte Abhängigkeiten zu anderen diese Methodik doch mehr und mehr zu einem unver- Applikationen, Datenbanken oder anderen Systemen, zichtbaren Bestandteil für sämtliche Wirtschaftsbe- kann das schnell zu einem hohen Maß an Komplexität führen. Das kann sich wiederum negativ auf Testauf- wände, aber auch Key Performance Indicators (KPIs) wie die Deployment Success Rate auswirken. Probleme im Applikationsbetrieb müssen schnell identifiziert und DevOps für klassische behoben werden. Hierfür ist eine standardisierte Integ- Windows-Desktopanwendungen ration von Logging und Monitoring in die Applikation ebenfalls unabdingbar. Oftmals wird im Kontext dieser Thomas Schissler (agileMax) Design-for-DevOps-Best-Practices von zwölf Faktoren Der Begriff DevOps wird von vielen mit gesprochen, auf die im späteren Verlauf des Artikels hypermodernen Cloud- und Webtech- eingegangen wird. nologien in Verbindung gebracht. Die Infrastruktur und Plattform: Die Infrastruktur trägt Prinzipien von DevOps lassen sich aber einen maßgeblichen Teil zu einem stabilen Applikati- auch für klassische Desktopanwendun- gen und andere Legacy-Technologien anwenden. Die onsbetrieb bei und ist eine essenzielle Komponente in technischen Hürden sind oftmals gar nicht so groß, DevOps-Szenarien. Häufig kommen Plattformen wie aber natürlich sind ein paar Anpassungen dafür not- OpenShift, Clound Foundry oder Azure zum Einsatz, wendig. Im Vortrag zeigen wir an einem Beispiel, wie die einen sehr hohen Grad der Automation erlauben eine klassische WPF-Anwendung für DevOps fit ge- und als gemeinsame Basis für das DevOps-Team fun- macht werden kann und mit welchen Tools Continuous gieren. Die Entwickler können sich dadurch voll und Delivery und Monitoring möglich werden. ganz auf ihre Aufgabe – das Entwickeln – fokussieren. Die Betriebseinheit des Teams kann zum Beispiel die

www.basta.net 5 DOSSIER Agile & DevOps

Entwickler durch das Bereitstellen von Infrastruk- Erzeugen von Messbarkeit: Damit ein DevOps-Team turtemplates unterstützen. maximal erfolgreich wird und sich die Erfolge auch be- Dass jede Applikation auf einer einheitlichen Platt- legen lassen, spielt das Erzeugen von Messbarkeit eine form läuft, trägt zu einer allmählichen Effizienzstei- große Rolle. Dadurch, dass viele Prozesse zentral und gerung bei, da nicht bei jeder Inbetriebnahme einer automatisiert ablaufen, lassen sich jede Menge Daten Applikation erneut darüber diskutiert werden muss, wo erzeugen, die sich dann wiederum auswerten lassen und sich die Logs befinden, wie Loglevel zu konfigurieren aus denen Optimierungspotenziale abgeleitet werden sind oder wie ein Rollback auf eine frühere Applikati- können. Da eine Vielzahl von KPIs existiert, ist eine onsversion durchzuführen ist. projektindividuelle Festlegung durchaus sinnvoll, denn CI/CD Pipeline: Das Verwenden eines zentralen nicht jede KPI hat für jedes Projekt die gleiche Relevanz. Code-Repositorys ist für Entwickler ein alter Hut und Gute Beispiele für Metriken im Kontext von DevOps ein wesentlicher Bestandteil von DevOps. Alle Code- sind die Bereitstellungsfrequenz sowie die Bereitstel- änderungen werden regelmäßig in ein zentrales Re- lungszeit. Ein häufig definiertes Ziel ist es, möglichst vie- pository wie etwa Git zusammengeführt. Nach dem le, kleine Deployments durchzuführen. Dadurch sinken

Damit ein DevOps-Team maximal erfolgreich wird, und sich dieser Erfolg auch belegen lässt, spielt das Erzeugen von Messbarkeit eine große Rolle.

Check-in werden diese Änderungen automatisiert die Testaufwände für ein Release, und potenzielle Fehler erstellt und getestet. Die Hauptziele von Continuous lassen sich leicht eingrenzen. Integration bestehen darin, Bugs möglichst schnell zu In diesem Zusammenhang spielt natürlich auch die entdecken und zu beheben, die Qualität der Software für eine Bereitstellung benötigte Zeit eine große Rol- zu optimieren und den Zeitraum bis zum Go Live le: Je kürzer die für ein Release benötigte Zeit, desto auf ein Minimum zu reduzieren. Das übergeordnete schneller lassen sich im Fehlerfall Korrekturen auf dem Ziel ist, die Entwicklerproduktivität zu steigern und System einspielen. Die allgemeine Servicequalität kann „Stupid Work Tasks“ zu eliminieren bzw. zu auto- zum Beispiel durch die Verfügbarkeit der Systeme und matisieren. Das gelingt zum Beispiel durch Testauto- die Anzahl an Benutzertickets gemessen werden. Im Ide- matisierung; nach einem erfolgreichen Build-Prozess alfall werden Störungen und Probleme behoben, bevor lassen sich beispielsweise Unit-, Komponenten-, UI-, sie bis zum Benutzer vordringen, zum Beispiel durch ein Last- oder API-Tests durchführen. Die Ergebnisse intelligentes Application-Monitoring. Hierzu eignen fließen wiederum in Reports ein, mit denen sich der sich Tools wie Retrace, Grafana oder App Dynamics, Erfolg des Teams messen lässt. Anhand der Resultate die wiederum eine Vielzahl von Parametern wie etwa kann ebenfalls eine Entscheidungsgrundlage für z. B. Application-Performance, Bandbreiten oder Applikati- ein automatisiertes Deployment geschaffen werden. onsfehler überwachen. Neben den hier beispielhaft auf- Eine hundertprozentige Testautomatisierung ist je- geführten Metriken existiert natürlich noch eine ganze doch nicht realistisch. Die Kunst liegt darin, unter den Reihe weiterer KPIs. Testtasks diejenigen zu identifizieren, die sich leicht Um eine kontinuierliche Verbesserung der Werte zu automatisieren lassen und einen hohen Mehrwert für erreichen, ist es empfehlenswert, einen regelmäßigen das Team schaffen. Erfahrungsgemäß lassen sich ca. Austausch innerhalb des DevOps-Teams anzustreben. 40–60 Prozent aller Testaufgaben automatisieren. Die Das kann zum Beispiel in Form von Meetings erfolgen, Integration von Artefakten wie etwa Testautomatisie- bei denen die Beteiligten darüber sprechen, welche Fak- rung bildet den Continuous-Delivery-Teil einer CI/CD toren sich ihrer Meinung nach besonders negativ auf Pipeline ab. Gelegentlich wird in diesem Zusammen- einzelne KPIs oder den gesamten Service auswirken. hang auch von Continuous Deployment gesprochen. Diese Punkte lassen sich dann wiederum gezielt verbes- Diese zwei Varianten unterscheiden sich lediglich durch sern oder gar eliminieren. das Vorhandensein einer manuellen Genehmigung. Bei Continuous Delivery erfolgt das Deployment zunächst DevOps-kompatible Softwarearchitektur auf eine nicht produktive Test- oder Integrationsumge- Da es sich bei DevOps in erster Linie um eine Philoso- bung. Nach erfolgreichem Test und einer Freigabe wird phie handelt und nicht um eine Technologie, ergeben das Release dann in die Produktionsumgebung gestaget. sich vielleicht zunächst Fragen, inwieweit DevOps die Bei Continuous Deployment wird auf diesen zusätzli- zugrunde liegende Technologie beeinflusst oder sie gar chen Prüfschritt verzichtet und die Produktionsumge- voraussetzt. Das im Mittelpunkt stehende Ziel von Dev­ bung unmittelbar aktualisiert. Ops ist meist die Erreichung maximaler Effizienz und

www.basta.net 6 DOSSIER Agile & DevOps

größtmöglicher Ökonomie. Um diese Ziele zu erreichen, zentral aufgelöst werden. Auch Problemen, die durch bedarf es neben dem richtigen Mindset und einer Dev­ eine Diskrepanz in den Versionen entstehen, lässt sich Ops-kompatiblen Organisation auch der Wahl eines so vorbeugen. Das gleiche Paradigma gilt für Services fortschrittlichen Technologiestacks. Die Basis hierfür oder Ressourcen, die von einer Applikation verwendet bildet in der Regel eine DevOps-Plattform wie etwa werden. Dazu zählen zum Beispiel Datenbank- oder OpenShift, Cloud Foundry oder Azure DevOps. Diese SMTP-Dienste sowie APIs. Eine App muss stets so Plattformen bieten integrierte Funktionen wie ein Con- entwickelt werden, dass es für die Einbindung und tainermanagement, die notwendige Containerlaufzeit- Nutzung der Services und Ressourcen unerheblich ist, umgebung, Lastenausgleichsmodule, Integration von von welchem Anbieter sie zur Verfügung gestellt wer- Source-Code-Management und Build-Tools, CI/CD den. Im Rahmen eines Bereitstellungsprozesses ist es Pipelines sowie weitere nützliche Features. üblich, dass pro Umgebung eine eindeutige Konfigu- Mit der Festlegung auf eine DevOps-Plattform wird ration festgelegt wird. Diese Konfigurationsparameter also in gewisser Weise auch die Entscheidung für einen müssen sich zwingend von außerhalb der Applikation Basistechnologiestack gefällt, der in der Regel auch ein ändern lassen. Ein Hinterlegen dieser Konfiguration Containerkonzept mit sich bringt. Die aktuell wohl be- im Code durch Konstanten, zum Beispiel für System- kannteste Implementierung der Containertechnologie zugangsdaten oder Datenbankverbindungsfolgen, ist Docker, die aufgrund ihrer Einfachheit und Benut- stellt einen klaren Verstoß in einer 12-Faktor-Archi- zerfreundlichkeit den Begriff überhaupt erst populär tektur dar. gemacht hat. Die Idee hinter Containern ist eigentlich In einer 12-Faktor-App wird strikt zwischen Build-, recht einfach: Ein Container fasst eine einzelne An- Release- und Run-Phase unterschieden. Checkt der wendung mitsamt allen notwendigen Abhängigkeiten Entwickler neuen Code ins Repository ein, wird mit wie etwa Bibliotheken oder statischen Inhalten in einer der Build-Phase die Transformation des Codes in ein Image-Datei ohne Overhead zusammen. Im Gegensatz ausführbares Paket angestoßen. Im nächsten Schritt, zu einer virtuellen Maschine enthält ein Container der Releasephase, wird das Build-Ergebnis mit der zum aber kein komplettes Betriebssystem und benötigt da- Deployment passenden Konfiguration kombiniert. her auch weniger Ressourcen. Ein bedeutender Vorteil In der Run-Phase, der sogenannten Laufzeit, wird die der Docker-Container ist die gute Skalierbarkeit: Wer- Applikation dann ausgeführt. Aufgrund dieser strikten den aufgrund des Lastverhaltens zusätzliche Instanzen Trennung sind Codeänderungen zur Laufzeit nicht mög- einer Anwendung benötigt, lassen sich nach Belieben lich, weil es keinen Weg gibt, die Änderungen zurück neue Container auf Basis eines Images erzeugen. Nach in die Build-Phase zu übernehmen. Es empfiehlt sich, dem Stoppen sind die Container wieder vollständig jedes Release separat mit einem eindeutigen Identifier aus dem System verschwunden und alle Ressourcen und Erstelldatum und -uhrzeit abzulegen. Das ermög- werden freigegeben. Die Konfiguration ist so weit wie licht im Fehlerfall ein schnelles Rollback der Lösung. möglich bereits im Container-Image eingerichtet. Zu- Eine 12-Faktor-App sollte immer zustandslos sein. Alle sätzlich notwendige Anpassungen sollten skriptbasiert Daten werden in unterstützenden Diensten, in der Re- erfolgen. gel einer Datenbank, gespeichert. Der RAM oder das Um das volle Potenzial der Containertechnolo- lokale Dateisystem können als kurzzeitiger Cache für gie auszunutzen, müssen die darin ausgeführten eine Transaktion verwendet werden. Es darf aber nie- Applikationen verschiedene Architekturrichtlinien mals davon ausgegangen werden, dass Daten für einen berücksichtigen. In diesem Kontext wird häufig von längeren Zeitraum vorgehalten werden oder durch eine 12-Faktor-Applikationen gesprochen [1]. Hinter die- sem Konzept verbergen sich zwölf Punkte, die Ent- wicklern dabei helfen sollen, Applikationen so zu designen und zu entwickeln, dass sich diese als SaaS (Software as a Service) und letztendlich auch prob- Architektur, aber bitte agil! lemlos in Containern betreiben lassen. Ein wichtiges Urs Enzler (bbv Software Services AG) und zugleich selbstverständliches Kriterium der zwölf Architektur steht für Stabilität und weit- Faktoren ist, dass der Quellcode einer Applikation reichende Entscheidungen. Und das soll stets in einer Versionsverwaltung wie zum Beispiel Git in einem schnelllebigen, flexiblen agilen verwaltet wird. Dabei besteht immer eine eindeutige Projekt möglich sein? Ich zeige in dieser Korrelation zwischen einer Codebasis und einer App. Präsentation, wie sich Architektur mit Zwei Applikationen können sich nach diesem Kon- den User Stories zusammen evolutionär entwickeln zept also einen Quellcode teilen. Das Vorhalten des kann, wie Entscheidungen bis zum richtigen Zeit- Quellcodes ist ebenfalls ein wesentliches Erfordernis punkt vertagt werden können und welche agilen Architekturmuster es gibt. Ihr lernt, wie eine agile für den Aufbau einer CI/CD Pipeline. Applikationen Architektur schnelle Änderungen, einfache Archi- sollten keine direkten Abhängigkeiten untereinander tekturvalidierung und ein immer lauffähiges System aufweisen. Durch das Verwenden eines Package Ma- ermöglicht. nagers lässt sich sicherstellen, dass Abhängigkeiten

www.basta.net 7 DOSSIER Agile & DevOps

Azure DevOps Die Zeichen, die Microsoft aussendet, sind deutlich: Schon länger versucht der Konzern, ein Open-Source- freundlicheres Image aufzubauen. Ein großer Schritt in diese Richtung war der Beitritt Microsofts zum Open Innovation Network (OIN) und der damit verbunde- nen Bereitstellung von 60 000 eigenen Patenten. Ein weiterer bedeutender Schritt ist das Aufgeben der Mar- ke „Visual Studio“. Die Cloud-Dienste für Entwickler, ehemals Visual Studio Team Services (VSTS), laufen ab sofort unter dem Brand „Azure DevOps“. Auch das lokal installierbare Gegenstück zu den VSTS, das seit 2005 unter dem Namen „Team Foundation Server“ (TFS) auf dem Markt ist, erhält ab der Version 2019 einen Brand: „Azure DevOps Server 2019“. Dieses Rebranding soll vor allem dafür sorgen, die Assozia- tion in den Köpfen vieler Entwickler zwischen Visual Studio und den klassischerweise damit verbundenen Programmiersprachen C++, C#, F# etc. zu lösen. Ne- ben dem neuen Markennamen spendiert Microsoft natürlich auch noch ein paar neue Features wie etwa die „Azure Pipelines“. Hierbei handelt es sich um eine leistungsstarke CI/CD Pipeline Engine, die mit nahezu jeder gängigen Programmiersprache und einer Vielzahl von Projekttypen arbeitet. Natürlich gab es auch in der altbekannten Version bereits eine CI/CD Pipeline, doch vor dem Hintergrund immer größer werdenden Abb. 1: Azure DevOps Pipelines Leistungsdrucks stellt die CI/CD Pipeline eine Kompo- nente dar, die sicherlich noch viel Potenzial für Opti- andere Transaktion nutzbar sind. In einer skalierbaren mierung bietet. Azure Pipelines bieten die Möglichkeit, Umgebung ist es ebenso denkbar, dass ein künftiger verschiedenste Zielsysteme für Bereitstellungsszenarien Request von einer anderen Instanz als der ursprünglich zu adressieren. Dazu gehören neben den Azure-eigenen angefragten und somit in einem anderen Transaktions- Services, wie „Azure App Services“ oder „Azure Ku- Scope bearbeitet wird. Da diese Flexibilität ein we- bernetes Service“ (AKS), auch virtuelle Maschinen, sentlicher Teil der Grundidee ist, müssen Prozesse so klassische Container Registries oder Deployments zu ausgelegt werden, dass sie eine möglichst geringe Start- Amazon Web Services. Eine neue Pipeline kann einfach zeit haben. Im Idealfall ist ein Prozess innerhalb weniger über den Menüpunkt Pipelines auf der linken Seite Sekunden hochgefahren und einsatzfähig. Eine kurze der Azure-DevOps-Weboberfläche erstellt werden Start-up Time verleiht dem System noch mehr Agilität (Abb. 1). und Robustheit. Gleiches gilt natürlich für das Herun- Für das Erstellen einer Build Pipeline ist es zunächst terfahren eines Prozesses. erforderlich, eine Quelle auszuwählen, von der aus Um das Verhalten einer laufenden Applikation sicht- der abgerufen werden soll. Kompatible bar zu machen, ist Logging unabdingbar. Häufig wer- Quellcodeverwaltungssysteme sind zum Beispiel Git- den Logs gezielt an einem bestimmten Ort, wie dem Hub, Azure Repos Git, Subversion etc. Anschließend Dateisystem oder einer Datenbank, abgelegt. Dieses erfolgt die eigentliche Build-Konfiguration, die aber Verhalten wird oftmals durch die Applikation be- nicht jedes Mal aufs Neue manuell durchgeführt werden stimmt. Im Fall einer 12-Faktor-App ist es nicht mehr muss. Stattdessen kann der Benutzer aus einem Temp- Aufgabe der Applikation, sich um einen Ablageort zu latekatalog auswählen. So ist es mittels weniger Klicks kümmern. Stattdessen werden sämtliche Ereignisse un- beispielsweise möglich, eine Build Pipeline für eine gepuffert in den stdout-Stream geschrieben. Die wei- Azure-Web-App for ASP.NET zu konfigurieren. Sind tere Verarbeitung dieser Ereignisinformationen obliegt Container das präferierte Zielmodell, ist eine direkte dem Hostsystem. Es entscheidet alleinig, ob und wohin Containerisierung mit anschließender Bereitstellung in die Logs persistiert werden. Das Einhalten der hier auf- einer Container-Registry ebenfalls mit einem überschau- gezeigten Leitlinien trägt zu einer sauberen und ska- baren Aufwand realisierbar. Wer sich in der Welt von lierbaren Applikationsarchitektur bei. Auch wenn dies YAML, einem JSON-ähnlichen deklarativen Format, prinzipiell für jede Applikation gilt, sollte dem Thema wohlfühlt, ist eingeladen, die Build-Konfiguration auf im Kontext von DevOps eine besondere Bedeutung zu- Basis dieses Formats festzulegen. Das Erstellen einer Re- gemessen werden. lease-Pipeline fühlt sich ähnlich komfortabel an. End to

www.basta.net 8 DOSSIER Agile & DevOps

Abb. 2: Konfiguration einer Release-Pipeline end gedacht, dient die Release-Pipeline dazu, den Code „Agile Operating Model“ bis Ende 2019 angekündigt für die Benutzer auf einem System verfügbar zu machen. hat. Das Zauberwort für das Erreichen all dieser Ziele Ihre Konfiguration erfolgt mittels eines grafischen Edi- lautet DevOps. Hierzu gehört jedoch viel mehr als nur tors (Abb. 2). das Einführen neuer Technologien und Plattformen. Als Ausgangsbasis dient ein sogenanntes „Artifact“. Es gehört ebenfalls mehr dazu als nur das Vorhaben, Hierbei handelt es sich vereinfacht gesagt um den be- Abteilungen und Bereiche zusammenzuführen. Es han- reitstellbaren Teil einer Applikation, der in der Regel delt sich erst einmal um eine Revolution im Kopf aller durch die Build Pipeline erzeugt wird. Am Artefakt Beteiligten, einen Umdenkprozess, der von höchster selbst lässt sich wiederum das Verhalten über soge- Ebene angeregt werden muss. Dabei ist es vor allem nannte Trigger festlegen. Der Bereitstellungsprozess wichtig, die häufig im Kopf existierenden Silos abzu- wird somit zum Beispiel automatisch gestartet, sobald reißen. Auch wenn bei DevOps die Technik nicht im ein neuer Build zur Verfügung steht. Auch ein manu- Vordergrund steht, bedarf es natürlich entsprechender eller Eingriff mittels Pull Request lässt sich einstellen. Konzepte und einheitlicher Plattformen, um die größt- Über die Stages wird definiert, welche Umgebung zu mögliche Effizienz bei der Entwicklung zu erzielen. welchem Zeitpunkt mit welchen Voraussetzungen de- Finden all diese Punkte Berücksichtigung und gelingt ployt wird. Um den Konfigurationsprozess so einfach der Schulterschluss zwischen Entwicklung, Betrieb und wie möglich zu gestalten, existieren auch hierfür zahl- Fachbereichen, steht einer erfolgreichen DevOps-Or- reiche vorgefertigte Tem­plates für eine Bereitstellung ganisation nichts mehr im Weg. auf Azure, Kubernetes, IIS etc. Das Deployment einer Stage kann an verschiedene Pre- und Post-Conditions geknüpft werden. Hierbei kann es sich beispielsweise Kevin Gerndt arbeitet als Lead Consultant im Bereich um ein automatisch ausgelöstes Event oder eine benut- Microsoft .NET Client und Web Technologies und hat zergetriebene Aktion handeln. Gates ermöglichen eine während seiner beruflichen Laufbahn schon eine Viel- zahl an Projekten begleitet. Er gilt als Experte auf dem Integration von REST APIs, Azure Monitor Alerts oder Gebiet der modernen Web- und Softwarearchitektur Azure Functions. Sollte beim Deployment doch mal et- und ist darüber hinaus als freiberuflicher Autor tätig, sowie re- was schieflaufen, erlaubt die History eine transparente gelmäßig auf namhaften Konferenzen vertreten. Schwerpunkte Einsicht in Änderungen sowie ein kontrolliertes Zu- seiner Tätigkeit bilden die Analyse und Implementation von Ge- rückrollen des Release. schäftsprozessen sowie das Konzipieren und Entwickeln moder- ner Softwarelösungen. Fazit In Zeiten zunehmenden Wettbewerbsdrucks ist es wichtiger denn je, der Konkurrenz immer einen Schritt voraus zu sein. Dies trifft auf die Entwicklung phy- sischer Güter, aber vor allem immer stärker auf di- gitale Services und Produkte zu. Mit der klassischen Unternehmensorganisation fällt es jedoch vor allem großen Konzernen mit ihrer Silostruktur schwer, mit dem vorherrschenden Tempo mitzuhalten. Doch im- mer mehr Unternehmen passen sich an und vollziehen einen Strukturwandel oder gründen Start-ups aus, um der heutzutage geforderten Agilität gerecht zu werden. Links & Literatur Ein gutes Beispiel ist der Automobilkonzern BMW, dessen Vorstand einen radikalen Wandel in Richtung [1] https://12factor.net

www.basta.net 9 DOSSIER Microservices & APIs

Entwicklung von Microservices mit Microsoft .NET Warum einfach? Es geht auch komplex!

Wie zu erwarten zieht das heißdiskutierte Thema Microservices auch an Microsoft nicht vorüber. Grund genug, einmal näher zu betrachten, wie man als .NET-Entwickler bei der Entwicklung von Microservices mit Docker von technischer Seite unterstützt wird.

von Dr. Felix Nendzig Entwicklung kann in kleinen, unabhängigen Teams mit geringem Kommunikationsbedarf untereinander Mit „.NET Microservices: Architecture for Contain­ stattfinden. Um einen Vorteil gegenüber einer monoli- erized .NET Applications“ hat Microsoft nun ein mehr thischen Anwendung zu erreichen, sollten die Microser- als dreihundertseitiges E-Book veröffentlicht, in dem vices jeweils folgende Bedingungen erfüllen: das Unternehmen seine Sicht auf das Thema umfassend vorstellt und insbesondere die Benutzung von Docker • Ein Service erfüllt genau einen fachlichen Zweck und bei der Entwicklung von Anwendungen mit Microser- diesen vollständig vices-Architektur empfiehlt [1]. • Jeder Service umfasst sämtliche benötigte Schichten, In diesem Beitrag soll Microsofts Sicht auf das Thema Teams arbeiten unabhängig voneinander (vertikaler Microservices näher beleuchtet und mit Blick auf unsere Schnitt) eigene Erfahrung kommentiert werden. Weiterhin wer- • Asynchrone Kommunikation zwischen Services (kei- den wir darauf eingehen, wie Docker bei der Entwick- ne zentral steuernde Einheit) lung von Microservices genutzt werden kann. • Keine gemeinsamen Daten oder Code (shared Nothing) Was ist eine Microservices-Architektur? • Jeder Service ist unabhängig deploybar Das zentrale Erkennungsmerkmal einer Microservices- • Unabhängige Datenmodelle und minimale APIs zur Architektur ist, dass sich die gesamte Anwendung aus Gewährleistung eigenständiger Entwicklungszyklen einzelnen, voneinander unabhängigen Services zusam- mensetzt. Durch Dezentralisierung und Autonomiema- Der Name „Microservices“ impliziert, dass die ein- ximierung soll auch bei komplexen Anwendungen eine zelnen Services klein sein sollen. Diese Charakteri- gute Skalierbarkeit in der Entwicklung – gegenüber ei- sierung bezieht sich aber nicht auf die Lines of Code ner monolithischen Architektur – erreicht werden. Die oder die Anzahl der Klassen je Service. Stattdessen

www.basta.net 10 DOSSIER Microservices & APIs

Abb. 1: Illustration zweier Bounded Contexts (Quelle: [2]) bedeutet es, dass ein Service nur genau eine sinnvolle „2-Pizza-Regel“ liegt die maximale Teamgröße bei fünf Funktion im Sinne der fachlichen Logik erfüllen soll. bis neun Personen [4]. Diese Idee folgt dem Konzept des Bounded Context Eine verteilte Anwendung bringt allerdings auch aus dem Domain-driven Design [2]. Danach wird ein zusätzliche Schwierigkeiten mit sich, die bei falscher großer fachlicher Themenbereich in kleinere Bereiche, Vorgehensweise zu einer Verschlechterung gegen- die Bounded Contexts (Abb. 1), aufgeteilt, die jeweils über einem Monolith führen können: Es gibt keine ihre eigenen, eindeutigen Fachbegriffe benutzen (Ubi- zentrale Steuerung, sodass querschnittliche Aufgaben quitous Language). Ein Microservice überschreitet wie Service-übergreifendes Monitoring oder Logging keinesfalls die Grenzen eines Bounded Contexts. Er zusätzlichen Entwicklungsaufwand mit sich bringen. implementiert maximal den gesamten Bounded Con- Externe Tools wie der ELK-Stack [5], Zipkin [6], Jae- text, typischerweise aber nur einen Teilbereich. ger [7] und AppDynamics [8] können hier Abhilfe Man sollte die kleinsten Microservices implemen- schaffen. Die Durchführung von Service-übergreifen- tieren, die die oben genannten Bedingung erfüllen. den Integrationstests oder Refactorings wird schwie- Wird die optimale Größe unterschritten, wachsen riger. Transaktionen sind auf einzelne Microservices die Abhängigkeiten der Services untereinander. Das begrenzt. Das Prinzip des „shared Nothing“ erzwingt, verschlechtert die Performance der Anwendung zur dass jeder Service seine benötigten Daten replizieren Laufzeit und während der Entwicklung durch erhöh- oder über Schnittstellen von anderen Services abfragen ten Kommunikationsbedarf über Service- und Team- muss. Jedes Entwicklerteam hat zusätzlichen Aufwand grenzen hinweg. Der Schnitt der Microservices sollte durch erschwertes Debugging, eine eigene Fehlerbe- deren innere Kohäsion maximieren und die Abhän- handlung je Microservice, die Bereitstellung einer gigkeiten nach außen minimieren. Gemäß dem Gesetz Delivery Pipeline etc. Ein ungünstiger Service-Schnitt von Conway [3] sollten sich die Service-Grenzen hier- führt zu ständigen Schnittstellenanpassungen, gemein- bei an der Organisationsstruktur des Unternehmens samen Releases mehrerer Services oder der Auslastung orientieren. Es kann sich auch lohnen, dieses Prinzip mehrerer Services durch eine einzige Anfrage. umzukehren, und die Organisation so anzupassen, dass man den aus Softwaresicht sinnvollsten Service- Stateful oder stateless Microservices? Schnitt wählen kann. In einer verteilten Anwendung kann eine variierende An- Bei richtiger Umsetzung erhält man ein skalierba- zahl von Service-Instanzen simultan laufen. Der Orchest- res System lose gekoppelter Services, die unabhängig rator (mehr dazu etwas später) kann jederzeit Instanzen voneinander entwickelt und ausgeliefert werden kön- auf einen anderen Knoten schieben oder die Anzahl lau- nen. Releasezyklus, Entwicklungs- und Betriebsumge- fender Instanzen an die momentane Auslastung anpassen. bung können je Service passend gewählt werden. Der Man kann sich nicht darauf verlassen, dass eine spezielle Testaufwand je Service sinkt, da er nicht übermäßig Service-Instanz dauerhaft existiert. Das spricht gegen die komplex ist und nur über Schnittstellen kommuniziert. Implementierung von stateful Services, deren Zustand im Die Entwicklung in kleinen Teams erzeugt nur geringen Arbeitsspeicher gehalten und jederzeit repliziert werden organisatorischen Aufwand. Ausgehend von Amazons können muss. Für stateless Services stellt das kein Problem

www.basta.net 11 DOSSIER Microservices & APIs

Abb. 2: Möglichkeiten zur Strukturierung des GUI in einer Microservices-Architektur (Quelle: [10]) dar, da sie die Daten in eine externe Datenbank schrei- direkt auf aufrufende Services auswirken. Auf diese ben oder im Client oder einem Cachetool wie bspw. Redis Weise wird schnell die Performance der Gesamtan- ­cachen. Die externe Datenquelle wird je Service passend wendung beeinträchtigt. Das Problem potenziert sich zu dessen Anforderungen gewählt. noch, wenn mehrere synchrone Aufrufe in Reihe statt- Was ist aber mit Anwendungsfällen, in denen man finden. Bei asynchroner Kommunikation wirkt sich der Daten von verschiedenen Microservices sammeln oder Ausfall eines einzelnen Microservice dagegen nicht so anzeigen muss? Tritt ein solcher Fall auf, sollte man verheerend auf seine Nachbarn aus. Sie fördert zudem sich gut überlegen, ob der Service-Schnitt passend ge- die Autonomie der einzelnen Microservices. wählt wurde und ob nicht eine Verschmelzung von Da an der Verarbeitung eines Geschäftsprozesses im Microservices die beste Lösung darstellt. Lässt es sich Allgemeinen mehrere asynchron kommunizierende, un- jedoch nicht vermeiden, muss man bei der Implemen- abhängige Microservices beteiligt sind, ist es nicht mög- tierung besonders darauf achten, dass die Autonomie lich, stets Konsistenz im Sinne einer ACID-Transaktion der betroffen Microservices dadurch nicht einge- sicherzustellen. Latenzen, Teilausfälle und unterschied- schränkt wird. Zudem kann sich die Aggregation von liche Verarbeitungsdauern können zwischenzeitlich Daten verschiedener Services aufgrund erhöhter Kom- Service-übergreifende, inkonsistente Zustände erzeugen munikation negativ auf die Performance des Systems (Eventual Consistency), deren Behandlung zusätzlichen auswirken. Aufwand, z. B. in Form von Timeouts,­ Circuit Breakers Microsoft nennt als Alternative noch eine auf den An- und Bulkheads, erfordert [9]. wendungsfall zugeschnittene, denormalisierte Tabelle in einer separaten Datenbank, in die die Microservices Das GUI jeweils ihre Daten schreiben. Aus Konsistenzgründen Sollten Clients direkt mit den Microservices kommu- dürfen die abfragenden Services auf diese nur lesend zu- nizieren oder den Umweg über ein vorgeschaltetes greifen. Mit Blick auf die geforderte Autonomie ist diese API-Gateway nehmen? In der ersten Variante kann der Lösung allerdings kritisch zu sehen. Client über einen URL direkt den betreffenden Service (bzw. einen vorgeschalteten Load Balancer) anfragen. Inter-Service-Kommunikation Jeder Microservice besitzt sein eigenes GUI oder ist in Wie jede verteilte Anwendung muss auch eine Micro- einem Plug-in-Ansatz für einen Teil des GUI innerhalb services-Anwendung mit Teilausfällen des Systems eines allgemeinen Rahmens verantwortlich. umgehen können. Wie gut die Gesamtanwendung Für kleine Anwendungen mit geringem Aufwand in solche Ausfälle verkraftet, hängt maßgeblich von der der GUI-Entwicklung kann diese Variante ausreichen. Inter-Service-Kommunikation ab. Synchrone Kom- Man bekommt jedoch schnell Probleme, wenn die munikation, bei der der Aufrufer abwarten muss, bis Entwicklung der Benutzeroberfläche in mehreren Mi- eine Antwort zurückgeliefert wird, kann bei lesendem croservices gleichzeitig stattfindet und zudem noch für Zugriff gegebenenfalls eine Lösung für die Kommuni- verschiedene Endgeräte entwickelt werden muss. Sind kation zwischen Front- und Backend sein. Innerhalb zum Aufbau einer Oberfläche mehrere unabhängige des Backends ist sie allerdings zu vermeiden, da sich Abfragen nötig, erhöht das die Latenz. Ein besseres Er- Verzögerungen und Ausfälle des angefragten Service gebnis erhält man, wenn die Daten zuvor serverseitig

www.basta.net 12 DOSSIER Microservices & APIs

Ein Orchestrator ermöglicht eine einfache Steuerung der Anwendung inklusive Scheduling, Load Balancing und Gewährleistung von Verfügbarkeit und Robustheit. aggregiert werden. Auch querschnittliche Anforderun- Anwendungen, die in Docker-Containern laufen sollen. gen wie Sicherheit, Autorisierung, Logging und Caching Unterstützt wird die Entwicklung mit .NET Frame- möchte man nicht individuell für jeden Microservice, work, .NET Core und Mono in den Sprachen C#, F# sondern gerne zentral implementieren. und VB. Mit .NET Core entwickelte Microservices sind Schaltet man ein API-Gateway zwischen die Clients auf unterschiedlichen Plattformen lauffähig. Das mo- und die Microservices-Landschaft, kann es das Routing dulare .NET Core ist zudem sehr leichtgewichtig und sowie weitere querschnittliche Aufgaben übernehmen. damit besser geeignet, containerbasierte Anwendungen Der Aufbau einer Oberfläche erfordert keine mehrfa- mit möglichst kleinen Microservices zu entwickeln. Das chen Roundtrips und Sicherheitsthemen können zentral klassische .NET Framework ist vorzuziehen, wenn die implementiert und verwaltet werden. Die Weiterent- bereits bestehende Anwendung oder andere Abhängig- wicklung der Anwendung wird erleichtert, da die Cli- keiten das erfordern. Darunter würden zum Beispiel ents nicht mehr über die Existenz bzw. Aufteilung der dringend benötigte Pakete oder Technologien wie ASP. Microservices Bescheid wissen müssen. NET Web Forms oder WCF fallen, die nicht in .NET Man sollte jedoch nicht einfach ein einzelnes „monoli- Core verfügbar sind. Ab Visual Studio 2017 ist die Un- thisches“ Gateway implementieren, sondern muss auch terstützung für Docker bereits standardmäßig enthalten. hier sowohl die Separation nach Geschäftsprozessen als Für ältere Versionen können die Docker Tools nachins- auch nach Client-Apps einhalten (Abb. 2). Anderenfalls talliert werden [16]. erzeugt man ungewünschte Kopplungen zwischen den Beim Anlegen eines neuen Projekts mit Docker Sup- Microservices. port wird ein passendes Dockerfile erzeugt. Zusätzlich Im Falle eines Web-UI mit dem Browser als Inte­ muss man noch „Container Orchestrator Support“ grationskomponente, dürfte der direkte Ansatz am aktivieren, um für das Projekt ein Docker Compose einfachsten umzusetzen sein. Die Entwicklung nativer anzulegen bzw. zu aktualisieren. Es enthält mit der Apps für diverse Endgeräte erzwingt dagegen den API- Datei docker-compose.yml die Konfigurationsdaten Gateway-Ansatz, bei der die Microservices im Backend der Container und Deployment-Umgebung. So kann einer übergeordneten Präsentationsschicht arbeiten später für jeden Service ein separates Docker Image (Backend for Frontend). Dieses Muster ist auch dann erstellt werden. Der Entwicklungsworkflow in Visu- zu bevorzugen, wenn man besonders viel ausgeklügelte al Studio bleibt sonst größtenteils unverändert. Beim Logik in der Oberfläche unterbringen will. Zwar sind die Microservices ohne eigenes GUI nicht mehr unbe- dingt als vollständige Anwendungen zu betrachten, dennoch stellt das API-Gateway-Pattern keine Ver- letzung der Microservices-Philosophie dar. Die Unab- Microservices (Teil 1): Pragmati- hängigkeit der Services untereinander, einschließlich sche Architekturen mit .NET Core ihrer Datenhoheit, bleibt bei richtiger Umsetzung er- halten [11]. – Patterns & Code Christian Weyer (Thinktecture) Entwicklung mit Visual Studio und Docker Angetrieben von möglichen Nachtei- Microsoft empfiehlt, die Vorteile von Docker bei Ent- len einer monolithischen Architektur wicklung, Deployment und Betrieb von Anwendungen sollen Microservices und damit verbun- mit Microservices-Architektur zu nutzen. Für jeden Mi- dene Designpatterns und -ideen das croservice wird ein eigenes Docker Image erstellt, sodass scheinbare Allheilmittel sein. In diesem Vortrag erklärt Christian Weyer, was Microservices sind, was sie nicht zur Laufzeit schnell beliebig viele Instanzen in Form von sind, wann man sie einsetzt und vor allem: Wie man Docker-Containern erstellt werden können. Für diesen Microservices in der .NET-Core-Welt baut. Sehen Sie Ansatz mit allen damit verbundenen Fragestellungen Architekturansätze und Patterns in Aktion und erleben existiert eine umfangreiche Dokumentation [1], [12]- Sie Technologien wie Service Discovery, Web-APIs, [15]. Docker-Container passen gut in das Konzept der Push Messaging, Message Queuing und Co. im Microservices, da sie unabhängiges Deployment und praktischen Einsatz. Versuchen wir also gemeinsam, Skalieren unterstützen. langweilige Architekturthemen spannend zu machen – auf pragmatische Weise. Microsoft bietet in Visual Studio und Visual Studio Code integrierte Unterstützung für die Entwicklung von

www.basta.net 13 DOSSIER Sicherheit

Abb. 3: Containerclusters abstrahiert und so das Management Auswirkung einer Multicontaineranwendung ermöglicht. Er er- von Auto- nomie und laubt eine einfache Steuerung der Anwendung inklu- Komplexi- sive Scheduling, Load Balancing und Gewährleistung tät bei der von Verfügbarkeit und Robustheit. Plattformen, die Entwick- lung von als Orchestrator agieren können, sind beispielsweise Monolithen Azure Service Fabric, Kubernetes, Docker Swarm und und Micro- Mesosphere DC/OS [18]-[22]. services (Quel- le: [26]) Wann verwendet man Microservices? So lange die Prozesse eines Unternehmens oder eines Geschäftsbereichs durch eine Anwendung mit mo- nolithischer Architektur abgebildet werden können, besteht kein Handlungsbedarf. Auch wenn die Anwen- dung schnell auf schwankende Last reagieren können muss, ist es nicht unbedingt nötig, den Flaschenhals Starten der Anwendung werden die Docker Images im System als eigenen Service auszulagern. Nutzt man automatisch gebaut und direkt in Docker gestartet. Docker, kann man einfach den gesamten Monolith in Auch eine Multicontaineranwendung kann in Visual einem Container deployen und bei Bedarf zusätzliche Studio debuggt werden. In Microsofts Visual-Studio- Instanzen hochfahren. Wird das System aber zu kom- Dokumentation [17] wird erläutert, wie man eine plex und steigt der Organisationsaufwand, dann wird Containeranwendung direkt in die Azure Container es zunehmend schwerer, die Weiterentwickelung voran- Registry deployen kann. Das Deployen und Testen zutreiben, dabei das System wartbar zu halten und den sollte so früh wie möglich in Docker geschehen, da Qualitätsanforderungen gerecht zu werden. Dann lohnt so die Produktivumgebung exakt reproduziert werden sich der Übergang zu einer Microservices-Architektur, kann. um der Komplexität Herr zu werden. Um das System skalierbar zu machen, muss man Während komplizierte – aber nicht komplexe – eine Vielzahl Container gebündelt als Cluster mana- Fachlichkeit gut durch monolithische Systeme abge- gen und je nach Last die Anzahl der Service-Instan- bildet werden kann, lassen sich komplexe Systeme zen automatisch anpassen. Das wird erst durch einen aufgrund einer Vielzahl wechselwirkender Teilsys- Orchestrator ermöglicht, der die Komplexität eines teme nicht vollständig analysieren und nur teilweise steuern. Es ist daher nicht möglich, die optimale Ar- chitektur eines komplexen Systems vorab zu bestim- men. Diese muss viel mehr iterativ entwickelt werden, wobei praktische Erfahrungswerte einfließen können. Microservices (Teil 2): Serverless- Damit das möglichst unkompliziert vonstattengehen kann, sind z. B. kurze Releasezyklen, eine effektive Architekturen – Event-basiert mit Delivery Pipeline und geringer Kommunikationsbe- Azure Functions und Co. darf durch kleine Teams nötig, wie es eine Micro- Christian Weyer (Thinktecture) services-Architektur ermöglicht [23].Daraus folgt Wie bitte? Ohne Server? Ähm … Ja, allerdings auch, dass es gefährlich ist, Microservices in der Tat. Der Serverless-Ansatz auf der grünen Wiese zu entwickeln. Wählt man an verspricht mit niedrigen Hürden den kritischen Stellen den falschen Service-Schnitt, kann Einstieg in Microservices zu finden. In das folgenschwere Konsequenzen nach sich ziehen. Je diesem Vortrag zeigt Christian Weyer die Grundla- besser man die Geschäftsprozesse und das Verhalten gen von Serverless mit Azure und .NET Core anhand einer funktionierenden (aber schwer erweiterbaren) praktischer Anwendungsfälle. Auf Basis erprobter monolithischen Anwendung studieren kann, desto Designpatterns können Sie mit Azure Functions, Azure Service Bus und Co. in kurzer Zeit sowohl einfache besser kann man einschätzen, wo der optimale Schnitt als auch komplexe Services-Anwendungen designen zu setzen ist. Es ist allerdings anzumerken, dass diese und implementieren – lokal und in der Cloud. Einer Frage in der Literatur [24], [25] kontrovers diskutiert der Schlüssel ist hierbei das Denken in Events, über wird (Abb. 3) . die Daten übertragen, verarbeitet und weitergeleitet werden. Kommen Sie vorbei – eventuell lernen Sie die Fazit Basis für Ihr neues Businesssoftware-Backend kennen. Der Einsatz von Microservices zielt darauf ab, kom- plexe Anwendungen, die als Monolith nur schwer zu HINWEIS: Dieser 2. Teil setzt Grundwissen aus Teil 1 managen wären, durch Dezentralisierung und Auto- voraus! nomiemaximierung skalierbar, wartbar und leicht er- weiterbar zu machen. Jeder Microservice erfüllt dabei

www.basta.net 14 DOSSIER Microservices & APIs

genau eine Funktion im Sinne der fachlichen Logik. [7] https://www.jaegertracing.io Die wichtigsten Treiber in Richtung Microservices sind [8] https://www.appdynamics.com hohe Komplexität, hoher Innovationsbedarf sowie [9] https://www.informatik-aktuell.de/entwicklung/methoden/ Leidensdruck bei der Skalierung. Microservices erben microservices-sind-verteilte-systeme-asynchronitaet-und-eventual- allerdings alle Probleme, die aus verteilten Anwendun- consistency.html gen bekannt sind. Service-übergreifendes Monitoring [10] https://www.embarc.de/wp-content/uploads/2016/06/Architektur- und Logging aber auch Refactoring und Testen stellen Spicker3-Microservices.pdf eine Herausforderung dar. Zudem muss das System [11] https://www.informatik-aktuell.de/entwicklung/methoden/der- mit Eventual Consistency und Teilausfällen zurecht- fachliche-schnitt-von-microservices-was-ist-das-was.html kommen. [12] https://www.docker.com/community-edition Auf der technischen Seite bringt Docker bei Entwick- [13] https://docs.docker.com/docker-for-windows/ lung und Betrieb von Microservices viele Vorteile wie [14] de la Torre, Cesar; Microsoft: „Containerized Docker Application Lifecycle etwa schnelles Deployment und einfache Skalierbarkeit with Microsoft Platform and Tools“: https://azure.microsoft.com/de-de/ mit sich. Die nahtlose Integration in den Entwicklungs- resources/containerized-docker-application-lifecycle-with-microsoft- workflow stellt besonders für den .NET-Entwickler ei- platform-and-tools/ nen großen Vorteil dar. [15] Lasker, Steve: „.NET Docker Development with Visual Studio 2017“: https://www.youtube.com/watch?v=hFCwfHo_Kbc [16] https://docs.microsoft.com/aspnet/core/publishing/visual-studio- Dr. Felix Nendzig studierte Physik am KIT und der Uni- tools-for-docker/ versität Heidelberg, wo er auch promovierte. Der Wech- sel in die IT-Branche führte ihn zur Accso – Accelerated [17] https://docs.microsoft.com/en-us/azure/vs-azure-tools-docker- Solutions GmbH, wo er als erfahrener Senior Software hosting-web-apps-in-docker/ Engineer tätig ist. [18] https://azure.microsoft.com/documentation/articles/container-service- intro/ Links & Literatur [19] https://docs.docker.com/swarm/overview/ [20] https://docs.docker.com/engine/swarm/ [1] https://docs.microsoft.com/de-de/dotnet/standard/microservices- [21] https://docs.mesosphere.com/1.10/overview/ architecture/ [22] http://kubernetes.io [2] https://martinfowler.com/bliki/BoundedContext.html [23] https://www.informatik-aktuell.de/entwicklung/methoden/ [3] https://de.wikipedia.org/wiki/Gesetz_von_Conway microservices-nur-bei-ausreichender-komplexitaet.html [4] https://www.informatik-aktuell.de/entwicklung/methoden/wie-gross- [24] https://martinfowler.com/bliki/MonolithFirst.html darf-ein-microservice-sein-und-ist-das-ueberhaupt-wichtig.html [25] https://martinfowler.com/articles/dont-start-monolith.html [5] https://www.elastic.co/de/elk-stack [26] https://www.informatik-aktuell.de/entwicklung/methoden/wann-und- [6] https://zipkin.io fuer-wen-eignen-sich-microservices.html

www.basta.net 15 DOSSIER Microservices & APIs

Git erobert die Entwicklerwelt Go Git! Git ist „hip“ und gilt als Star unter den Versionskontrollsystemen. Der Grund dafür ist einfach: Git ist schnell, leistungsfähig und plattformunabhängig. Kein Wunder, dass im- mer mehr Teams, vor allem auch aus der Microsoft-Welt, den Umstieg planen. Doch um Git optimal zu nutzen, ist fundiertes Hintergrundwissen nötig – denn Git arbeitet von Grund auf anders als die bekannten „klassischen“ Systeme. Richtig eingesetzt macht Git aber ordentlich Spaß – durch mehr Performance, Produktivität und Flexibilität im Ent- wicklungsalltag.

von Uwe Baumann stands, zum Abrufen früherer Versionen sowie zum Verwalten von Varianten mittels Branching und Mer- Eigentlich – so schien es – war das Thema Versions- ging. kontrolle in der Microsoft-Welt abgehakt: Team Aber der Schein trügt: Git funktioniert intern kom- Foundation (TFVC) als ausgereif- plett anders, denn es ist als dezentrales System aus- tes, stabiles System war gesetzt – als Open-Source- gelegt. Das bedeutet: Während TFVC und Subversion Alternative stand bereit –, um den auf eine zentral verwaltete Datenbank setzen (Abb. 1), Rest des Kuchens stritten sich Systeme wie kommt Git auch gut ohne zentrale Datenbank aus. Je- und Rational ClearCase. Doch dann kam Git und er- der Nutzer hat vielmehr seine eigene Datenbank, unter oberte die Welt im Sturm: Nach der aktuellen Umfra- Git „Repository“ oder kurz „Repo“ genannt (Abb. 2). ge des Entwicklerportals Stack Overflow nutzen rund Unter Git arbeitet man die meiste Zeit mit dieser lo- 87 Prozent der Entwickler Git; Subversion und TFVC kalen Datenbank und kann dann die erzeugten Ände- landen mit 16,1 und 10,9 Prozent abgeschlagen auf rungen (Commits) mit den anderen Projektbeteiligten den Plätzen zwei und drei [1]. austauschen. Obwohl Git dies nicht erfordert, wird Was ist der Grund für den kometenhaften Aufstieg hier dann doch wieder auf die bewährte Architektur von Git? Was macht Git anders als die etablierten mit einem Zentralserver (Blessed Repository) zurück- Platzhirsche? Und was gibt es zu beachten, wenn man gegriffen. das eigene Team auf Git migrieren will? Die wichtigs- ten Antworten auf diese Fragen möchte ich Ihnen im Schnell, sicher, flexibel Folgenden liefern. Das lokale Arbeiten bringt einige Vorteile mit sich: Git reagiert generell extrem schnell auf Benutzereingaben – Zentral versus dezentral es müssen ja nicht für jede Aktion langsame Netzwerk- Wer sich ein Git Cheat Sheet (wie es diesem Heft bei- zugriffe durchgeführt werden. Diese gute Performance liegt) besorgt, könnte den Eindruck bekommen, dass ist in der täglichen Praxis deutlich spürbar. Git eigentlich nur eine Variante des bereits bekannten „Völlig losgelöst“ vom Server arbeiten zu kön- Musters darstellt: Befehle zum Sichern des Versions- nen, erhöht auch die Flexibilität bei der Arbeit mit

www.basta.net 16 DOSSIER Microservices & APIs

der Versionskontrolle. Kein Netzwerk? Kein Problem, auch wenn man an einem Ort am Sourcecode arbeitet, an dem keine Verbindung zum Server besteht. So ist es beispielsweise im Zug, in abgeschotteten Sicherheitsbereichen, bei Ausfall der DSL- Leitung und in ähnlichen Szenarien trotz- dem möglich, den vollen Funktionsumfang der Versionsverwaltung zu nutzen – ein Plus für Service-Ingenieure, Consultants und alle anderen örtlich mobilen Entwickler. Ein weiterer Bonus der dezentralen Aus- Abb. 1: Zentrale Versionskontrolle legung von Git: Änderungen am Repository sind zunächst einmal privat, bis sie auf den Server übertragen werden. So ist es unter Git üblich, bei der Arbeit eigene, private Bran- ches anzulegen, die vor der Übernahme in das zentrale Repository oft auch wieder ge- löscht werden. So lassen sich im Alltag leicht Experimente am Code vornehmen, die dann sehr einfach wieder zurückgerollt werden können – sozusagen ein „Undo auf Steroi- den“. Auch diese erhöhte Flexibilität bei der Codeerstellung ist ein Feature, das die meis- ten Git-Nutzer nicht mehr missen wollen. Abb. 2: Verteilte Versionskontrolle Nicht zuletzt bietet die dezentrale Datenspei- cherung auch noch einen weiteren Vorteil: Da die ein- zelnen lokalen Repos in der Praxis oft synchronisiert werden, hat jeder Entwickler sozusagen eine Sicherheits- kopie, was zu einer extrem hohen physischen Datensi- cherheit führt – und das ganz ohne explizite Back-ups auf einem Server.

Clevere Datenspeicherung Abb. 3: Versionsgeschichte als Abfolge von Commits, identifiziert Apropos Flexibilität: Um die dezentrale Datenspei- durch Hash-Werte cherung möglich zu machen, setzt Git auf ein flexibles grafenbasiertes Speichermodell. Die Versionsgeschichte fach nur markieren, dass eine technische Aktion wie wird durch eine einfach verkette Liste abgebildet, die ein (Zusammenführen von Branches) oder ein einzelnen Nodes repräsentieren die Commits (Ände- Revert (Rückgängigmachen von Änderungen) auf dem rungsdatensätze) mitsamt der Metadaten wie Name, Repo durchgeführt wurde. Datum und Eincheckkommentar. Branches und Label Dadurch ist es unter Git möglich, eine sehr saubere werden durch leichtgewichtige Pointer realisiert. Die In- und aufgeräumte Versionsgeschichte zu erstellen. Diese tegrität der Commits wird durch Hash-Werte sicherge- ist dann sehr gut les- und wartbar – im Gegensatz zur sellt, die über jedes berechnet werden und diese oft chaotischen Historie konventioneller Systeme. Vie- gleichzeitig eindeutig identifizieren (Abb. 3). le Git-Nutzer sehen die Versionsgeschichte deshalb als Dieses Speichermodell macht Git in jeder Hinsicht organisch entstandenes Changelog an, das die logisch- noch flexibler. Das Erstellen von Branches geht ex- semantische Projektgeschichte erzählt, und investieren trem schnell und einfach, da intern nur ein weiterer entsprechend viel Aufwand in dessen Pflege. Listen-Pointer eingefügt werden muss. Die interne Da- tenstruktur von Git ermöglicht die Manipulation der Power und Komplexität Versionsgeschichte auf jede erdenkliche Weise. Com- Doch um es mit den Worten von Spidermans Onkel zu mits können zusammengefasst, entfernt und verändert sagen: „With Great Pow­er Comes Great Responsibili- werden, durch spezielle Manipulationen am Datenmo- ty“ [8]. Das clevere Datenmodell bedeutet eben auch, dell können „technische“ Commits, wie sie bei anderen dass ein erhöhter Lernaufwand nötig ist, um mit Git Systemen beispielsweise beim Mergen zwangsläufig sicher und produktiv arbeiten zu können. Die vielen entstehen, komplett vermieden werden. Diese Commits Möglichkeiten möchten beherrscht werden, und das sind deshalb oft unerwünscht, weil sie keine inhaltliche geht nicht ohne ein intensives Studium der internen Weiterentwicklung des Codes darstellen, sondern ein- Funktionsweise von Git.

www.basta.net 17 DOSSIER Microservices & APIs

Viele Einsteiger stellen fest, dass der Einstig zwar sehr bungen verfügbar (Kasten: „Gute Git-Clients“). Git leichtfällt, es aber eine unsichtbare Barriere gibt, auf ist schnell, kompakt, einfach zu installieren und sofort die man dann trifft, wenn man fortgeschrittene Tech- einsetzbar. Sämtliche Operationen lassen sich über die niken anwenden will oder in ungewohnte Situationen Kommandozeile ausführen und es gibt zahlreiche freie gerät. Auch ist es bei Git durchaus möglich, Daten zu und kommerzielle grafische Git-Clients für Windows, „verlieren“. Meistens sind diese dann nicht wirklich Mac, Linux und Co. Egal ob Visual Studio, Visual gelöscht, aber bedingt durch den aktuellen Zustand Studio Code, Eclipse, Android Studio oder XCode – des Datenmodells gerade einfach nicht sichtbar. Git überall ist die integrierte Git-Unterstützung längst überrascht Anfänger oft mit nicht gerade intuitivem Standard. Ausgang von Operationen – etwa, wenn nach Anzeige All das macht Git auch in der aktuellen Cross-Platt- eines historischen Commits die neueren Commits ver- form-Entwicklungswelt zu einem idealen Tool. Unter schwunden zu sein scheinen. Ich habe einmal in einem Windows mit Xamarin entwickeln, auf einem Mac bau- Forum gelesen: „Git can smell your Fear!“ [9]. Zudem en und im Apple Store veröffentlichen? Kein Problem. ermöglicht Git es, bestimmte Operation „mit Gewalt“ Ein zentrales Repo für alle Skripte im Unternehmen, durchzuführen, die bei den Mitbewerbern schlicht egal ob Bash oder PowerShell? Kein Problem! Git stan- und ergreifend unmöglich sind – der Parameter –force dardisiert die Welt der Versionsverwaltung. macht’s möglich. Wer hier nicht genau versteht, was er oder sie tut, und einfach blind einem Rezept aus dem Internet folgt, läuft unter Umständen geradewegs ins Verderben. Also ist eine kurze, intensive Lernpha- se für jeden Ein- und Umsteiger Pflicht (Kasten: „Der 3-Schritte-Plan zum Umstieg“). Git in Visual Studio 2019: Grund- lagen für Entwickler Plattformübergreifend Thomas Claudius Huber (Trivadis Git hat seinen Ursprung in der Linux-Welt. Es wurde AG) als Ersatz für den bis dahin vom Linux-Kernel-Team genutzten BitKeeper (einem kommerziellen Pionier der Mit Visual Studio 2019 hat Microsoft ei- dezentralen Versionsverwaltung) entwickelt. Die Linux- nige Verbesserungen zum Arbeiten mit Gemeinde hatte sich mit dem Hersteller von BitKeeper Git eingeführt. Direkt vom neuen Start- fenster aus lassen sich Git Repositories aus GitHub, überworfen und brauchte eine Alternative. Der Legende Azure DevOps oder aus anderen Git-Diensten clonen nach schloss sich Linus Thorwalds im stillen Kämmer- und auschecken. Auch hat Microsoft mit der Pull chen ein und codierte die erste Version von Git in weni- Requests for Visual Studio Extension eine speziell für gen Tagen kurzerhand selbst [10]. Azure DevOps entwickelte Erweiterung eingeführt, Aufgrund der offensichtlichen Vorteile verbrei- die das Erstellen und Reviewen von Pull Requests tete sich das System sehr schnell. Überall auf der in Visual Studio erlaubt. Neben diesen Neuerungen lernen Sie in dieser Session die Grundlagen, um in Welt fanden sich Mitarbeiter für die Weiterentwick- Visual Studio 2019 effizient mit Git zu arbeiten. Dazu lung – und innerhalb weniger Jahr hatte sich Git zum gehören Commits, Branches, Tags und auch das De-facto-Standard entwickelt. Heute sind Git-Imple- Lösen von Merge-Konflikten. mentierungen und Clients für praktisch alle wichtigen Betriebssysteme und integrierten Entwicklungsumge-

Der 3-Schritte-Plan zum Umstieg Informieren und Lernen. Das beste Buch zu Git („Pro Git“) findet sich auf der offiziellen Git-Website [2] – auch als E-Book für alle gängigen Reader. Ein sehr gutes Tutorial bietet auch die Firma Atlassian auf ihrer Website [3] – und es gibt zahlreiche Videotutorials und Quickstarts. Wichtig: Nicht nur Befehle lernen, sondern sich intensiv mit der Funktionsweise von Git vertraut machen. Git ist anders! Üben. Es empfiehlt sich, zunächst mit der Kommandozeile und einem einfachen Projekt zu üben, bis man die grundlegenden Operationen sicher beherrscht. Eine große Hilfe hierbei ist das kleine Tools GitViz [4], das die inter- nen Vorgänge in einem Git-Repo visualisiert und so beim Verständnis hilft. Migrieren. Es ist möglich, Datenbanken von bestehenden Systemen wie Subversion und TFS nach Git zu migrieren – Git bietet direkten Support für den Import von SVN-Repos [5] und auch Team Foundation Server hat eine eingebaute Importfunktion (allerdings nur für maximal 30 Tage Versionsgeschichte) [6]. Open-Source-Projekte wie beispielsweise git-tf helfen weiter [7]. Viele Teams checken den Sourcecode aber einfach zu einem Stichtag aus dem bestehenden System aus und in Git wieder ein – so gibt es zwar einen Bruch in der Historie, aber dafür ist der Aufwand minimal. Das alte System kann dann zur Referenz in einen Read-only-Modus versetzt werden.

www.basta.net 18 DOSSIER Microservices & APIs

Grenzen und Fallstricke dass dies aufgrund der Größe des monolithischen Win- Wo Licht ist, ist auch Schatten. Erwähnt habe ich schon, dows-Sourcecodes mit 3,5 Millionen Files und 300 GB dass Git eine steile Lernkurve hat. Weitere Limitationen Repo-Größe praktisch unmöglich war. Operationen liegen genau in dem oben gelobten dezentralen Daten- dauerten teils Stunden – ein unhaltbarer Zustand. Mi- modell. Was, wenn mein Repository sehr groß ist und ich crosoft reagierte auf die Probleme mit der Entwicklung es nicht in kleinere, modularere Teile aufspalten kann? von Git Virtual File System – einer Erweiterung von Git, Schließlich muss das Repo auf jedem Entwicklerrechner die das System zumindest teilweise wieder in eine Client- repliziert werden und dort der entsprechende Speicher- Server-Software zurückverwandelt [11]. platz zur Verfügung stehen. Was das bedeutet, zeigt sich GitHub empfiehlt, ein einzelnes Repo unter 1 GB und an einem extremen Beispiel: Das Windows-Team bei Mi- einzelne Files unter 100 MB zu halten – klassische Ver- crosoft wollte auf Git umsteigen – und musste feststellen, sionskontrollsysteme ermöglichen hingegen riesige Peta-

Gute Git-Clients Atlassian Sourcetree: Kostenlos nach Registrierung, verfügbar für Windows und Mac; der Klassiker unter den gra- fischen Git-Clients. Bietet alle Grundoperationen in einer relativ modernen Oberfläche, enthält aber keinen Merge- Editor (Abb. 4). fournova Tower: 59–79 € pro User und Jahr; ursprünglich nur für Mac erhältlich, jetzt auch mit einer Windows- Version vertreten; sehr intuitiv mit guter Übersicht bei anspruchsvollen Operationen wie Merges (Abb. 5). Axosoft GitKraken: 49 $ pro User und Jahr; frei verfügbar für nichtkommerzielle Arbeit und Open Source; erhältlich für Windows, Mac und Linux (Abb. 6).

Abb. 4: Atlassian Sourcetree Abb. 5: fournova Tower

Abb. 6: Axosoft GitKraken

www.basta.net 19 DOSSIER Microservices & APIs

byte-Versionsdatenbanken – schließlich können Nutzer über einen kollaborativen Prozess, in dem automati- hier auch nur wenige Files aus dem Zentralserver aus- sierte Tests und Builds ausgeführt werden können und checken, ohne gleich die ganze Datenbank kopieren zu das Team den Code in gemeinsamen Reviews bewerten müssen. und bearbeiten kann. Pull Requests sind kein Teil von Zugegeben, auch unter Git existieren teilweise Lö- Git, werden aber durch die Flexibilität der Git-Archi- sungen für dieses Problem – Stichworte sind hier Graf- tektur erst praktikabel. ting und Shallow Checkouts, Git Submodules und Subtrees. Diese Workarounds sind aber nur bis zu ei- Fazit: Widerstand ist zwecklos nem gewissen Grad praktikabel und performant. Wer Git ist ein schnelles, leistungsfähiges und revolutionäres also sehr große Repos hat, sollte sich den Umstieg auf System zur Versionskontrolle, das sich in der Softwar- Git gut überlegen und zunächst einmal Performance- eindustrie durchgesetzt hat. In Zukunft dürfte Git das tests durchführen. faktische Monopol für Versionsverwaltung besitzen. Ein weiteres Feature, das Git prinzipbedingt nicht Wer sich noch nicht mit Git beschäftigt hat, sollte das unterstützen kann, ist das exklusive Auschecken von schnell nachholen – es lohnt sich. Mit dem nötigen Re- Dateien (Check-out Locks), sodass diese nur von einer spekt vor der Mächtigkeit des Systems, ein bis zwei Ta- Person zu einem Zeitpunkt geändert werden können. gen Studium oder Seminar und ein bis zwei Wochen Zeit Gerade CAD- und Engineering-Systeme verlassen sich für die Umgewöhnung gelingt der Umstieg sicher und oft noch auf diese Funktionalität, die nur bei den klas- schnell. Go Git! sischen Versionskontrollsystemen zu haben ist.

Neue Workflkows Uwe Baumann ist ausgewiesener Experte für Microsoft Die neuen technischen Möglichkeiten von Git ebneten Visual Studio, ALM und .NET. Seit 1999 begleitet er die den Weg für neue Workflows in der Teamzusammen- verschiedenen Technologien zur Softwareentwicklung in der Microsoft-Welt. Als ALM Consultant und strate- arbeit. Kollaborationsplattformen wie GitHub und gischer Technologieberater bei der artiso solutions Azure DevOps (vormals Team Foundation Server) GmbH untertützt er mit seiner umfassenden Erfahrung Kunden bieten neue Wege, die Qualität und Transparenz von dabei, den Herausforderungen der modernen Softwareentwick- gemeinsam erstelltem Code zu steigern. Der Prozess lung zu begegnen. der Pull Requests, ebenfalls aus der Open-Source-Sze- ne übernommen, ist zum Quasistandard in modernen Softwareteams geworden. Dabei wird zunächst dezen- tral an Features und Bugfixes in eigenen, sogenannten Topic Branches gearbeitet – die Überführung in ge- schützte, qualitätsgesicherte Codelinien geschieht dann

Azure DevTest Labs: virtuelle Testumgebungen (VMs) dyna- misch in Minuten in der Cloud bereitstellen Links & Literatur Uwe Baumann (artiso solutions GmbH) Neno Loje (www.teamsystempro.de) [1] https://insights.stackoverflow.com/survey/2018/ [2] https://git-scm.com/book/en/v2 Heiße Testphase … Sie müssen Ihr Produkt unter verschiedenen Plattfor- [3] https://de.atlassian.com/git/tutorials men und Konfigurationen testen, aber [4] https://github.com/Readify/GitViz Ihr einsamer Testrechner bricht unter [5] https://git-scm.com/docs/git-svn der Last der virtuellen Maschinen schon fast zusammen. Ihre interne IT-Abteilung [6] https://docs.microsoft.com/en-us/azure/devops/repos/git/import- hat Hilfe in Aussicht gestellt – in zwei from-tfvc?view=vsts&tabs=new-nav Monaten! Was tun? Greifen Sie zur [7] https://blog.cellenza.com/devops/migrating-from-tfvc-to-git/ Cloud-Selbsthilfe. Mit Microsoft DevTest [8] https://quoteinvestigator.com/2015/07/23/great-power/ Labs können Sie Ihren Bedarf an Testinf- rastruktur schnell, sicher, flexibel und preiswert decken. [9] https://stevebennett.me/2012/02/24/10-things-i-hate-about-git/ Neno Loje und Uwe Baumann zeigen Ihnen, wie das [10] https://www.linuxjournal.com/content/git-origin-story/ geht. [11] https://blogs.msdn.microsoft.com/bharry/2017/05/24/the-largest- git-repo-on-the-planet/

www.basta.net 20 DOSSIER Microservices & APIs

Aus VSTS wird Azure DevOps – mehr als nur ein neuer Name? Des Kaisers neue Kleider

Das Jahr 2018 hat für Nutzer der Microsoft-ALM-/DevOps-Plattformen TFS und VSTS durch zwei große Ankündigungen mehrere gedankliche Neuausrichtungen bedeutet: Zum einen war da im Frühjahr die Absichtserklärung von Microsoft, GitHub für 7,5 Mio. US- Dollar zu kaufen, zum anderen die Umbenennung von VSTS und TFS zu Azure DevOps bzw. Azure DevOps Server in der Sommerphase.

von Nico Orschel und Thomas Rümmler Visual Studio als Entwicklungsumgebung nutzen, dass der TFS nur für .NET-Entwickler funktionieren würde. Im Folgenden wollen wir beide Themen aufgreifen und Betrachtet man die Entwicklung des TFS, erkennt man, zu Beginn das „Warum?“ etwas genauer anschauen; dass die ersten Versionen 2005 und 2008 tatsächlich sehr anschließend wird es um das „Wie manifestiert sich die stark an die .NET-Plattform gekoppelt waren. Mittlerwei- Umbenennung im Produkt?“ bzw. „Was gibt es für neue le hat sich das gesamte Umfeld allerdings massiv verändert Features?“ gehen. Einen weiteren inhaltlichen Schwer- und zu einer offenen Technologieplattform entwickelt. punkt wird die Betrachtung des Zusammentreffens von 2005 war Microsoft im Allgemeinen noch massiv gegen GitHub und Azure DevOps darstellen, bzw. die Erkennt- Open Source und zehn Jahre später ist das Unternehmen nis, dass Open Source mit Azure DevOps sich nicht aus- aus der Open-Source-Community nicht mehr wegzu- schließt, sondern Geld spart und die Produktivität fördert. denken. Auch das TFS-Entwicklungsteam hat hier eine gewisse Vorreiterrolle eingenommen. Beispiele sind die In- Raider heißt jetzt Twix aber sonst ändert sich nix? tegration von Git als zweites Versionskontrollsystem mit Das Umbenennen (oder neudeutsch Rebranding) von der Version TFS 2015 oder nativer Build-Agent-Support Microsoft-Produktnamen scheint für so manchen Nut- für Linux und Mac OS X. zer schon eine Tradition zu sein. Im TFS-Cloud-Umfeld Unabhängig von diesen Bemühungen ist aber leider haben wir mittlerweile auch schon die eine oder andere selbst im Jahr 2018 die Wahrnehmung von vielen Ent- Namensänderung durchlaufen: 2011 Team Foundation wicklern außerhalb der Microsoft-Technologiewelt, Service, 2013 Visual Studio Online (VSO) und 2015 Visu- dass TFS nur mit .NET sinnvoll zu verwenden ist, und al Studio Team Services (VSTS). Warum jetzt aber schon das ist schlichtweg falsch. Mit dem neuen Namen ver- wieder ein neuer Name? Im Microsoft-Universum gibt es sucht Microsoft jetzt eine Art Befreiungsschlag. Die Mar- eine überschaubare Anzahl an „starken“ Markennamen. ke Azure ist für Microsoft eine Art Leuchtturm. Azure Exemplarisch seien Visual Studio, Azure, Office 365 oder steht für Offenheit und Technologievielfalt. Das gleiche Xbox genannt. An diese Marken gliedern sich wiederum Gedankengut teilen auch TFS und VSTS, sodass jetzt die die eigentlichen Produkte an. TFS heißt beispielsweise neuen Namen Azure DevOps für den Cloud-Service und nicht nur Team Foundation Server, sondern formal gese- Azure DevOps Server für den On-Premises-Server sind. hen Visual Studio Team Foundation Server. Und genau Auf DevOps selbst muss an dieser Stelle nicht mehr ge- hier liegt aus Sicht von Microsoft das Problem. Mit dem nauer eingegangen werden, da man an diesem Thema Markennamen ist auch eine gewisse Erwartungshaltung gefühlt überhaupt nicht mehr vorbeikommt. Dev­Ops als des Nutzers verbunden. Bezogen auf den TFS suggeriert Philosophie wird dabei als der nächste Schritt nach Agile das Visual Studio im Namen gerade für viele, die nicht betrachtet.

www.basta.net 21 DOSSIER Microservices & APIs

Abb. 1: Aktivierung/Deaktivierung einzelner Azure DevOps Services

Hat jetzt Microsoft etwa nur die Beschilderung des sung sucht. Des Weiteren gibt es die Fälle, in denen bei- Produkts geändert oder habe ich als Nutzer auch etwas spielsweise eine Fachabteilung eine Möglichkeit für agiles davon? Der erste große Punkt, der bei diesem Release auf- Anforderungsmanagement sucht oder schlichtweg ihre fällt, ist, dass jetzt die Services der Plattform als Gesamt- Arbeit mit den Azure Boards organisieren möchte. In bei- einheit oder als getrennte einzelne Services nutzbar sind. den Szenarien ist es nun möglich, nur die benötigten Teile Die gesamte Plattform trägt dabei den Namen Azure zu verwenden (Abb. 1) und die anderen, nicht benötigten DevOps bzw. Azure DevOps Server. Im Gegensatz dazu Services einfach zu deaktivieren. Aus Sicht von Microsoft tragen die einzelnen Services die Namen Azure Boards wird dadurch eine größere und breitere Zielgruppe besser (Work-Item-Tracking, Backlogs, Enterprise-Portfolio- ansprechbar. Management), Azure Repos (Git Repositories, Team Foundation Server Version Control), Azure Pipelines Das neue UI (alles rund um CI/CD als Weiterentwicklung des TFS/ Neben der Umbenennung von VSTS in Azure DevOps VSTS-Build- und Release-Managements), Azure Artifacts wurde auch ebenfalls ein neues, durchgängigeres UI- (Package Management) und Azure Test Plans (Testma- Konzept für alle Benutzer etabliert. Mit dem neuen Lay- nagement und Ausführung). In Unternehmen, die eine out wurden dabei mehrere Ziele verfolgt: Unterstützung komplett neue Entwicklungslandschaft definieren, ist der des neuen Service-Konzepts und Verbesserung der Nut- Einsatz all dieser Teile die erste Wahl. Es gibt jedoch vie- zungsmöglichkeiten der Services für den Nutzer durch ein le Fälle, in denen nur ein Teil benötigt wird. Das kann konsistentes Design. Auch TFS/VSTS sind über die Jahre sein, weil es für andere Teile bereits gute Lösungen gibt, gewachsene Systeme, an denen viel verbessert und erwei- beispielsweise wenn ein Unternehmen eine gut ausgestat- tert wurde; dadurch finden sich ggf. Optionen nicht an tete Testmanagementumgebung hat, aber für die agile den Stellen, an denen ein Nutzer sie erwarten würde oder Planung und die CI/CD Pipeline eine durchgängige Lö- Navigationspfade sind unnötig lang.

www.basta.net 22 DOSSIER Microservices & APIs

Abb. 2: Azure- DevOps-UI- Konzept

Abb. 3: Teams in Azure Boards

Die neue UI aus Abbildung 2 folgt grob folgendem Azure Boards Schema: In der linken Leiste findet sich ein allgemeiner Der erste „neue alte“ Service sind die Azure Boards. Überblicksbereich mit allgemeinen, Service-übergrei- Unter ihm wurden alle Funktionalitäten bezüglich fenden Funktionen wie Wiki, Dashboards und Re- Work-Item-Tracking und der agilen Managementtools porting und natürlich auch die aktivierten Services (1). zusammengefasst. Beispiele für diesen Bereich sind das Links unten (6) finden sich immer kontextspezifische gesamte Thema Backlog-Portfolio-Management, Sprint- Einstellungen, wie z. B. der Link zu den Projekteinstel- lungen. Rechts oben finden sich das Nutzerprofil (3) mit sei- nen Einstellungen und die Preview-Flags zur Aktivie- rung von Previewfunktionen. Daneben ist dort immer der Link zum Azure DevOps Marketplace zu finden. Agiles Arbeiten mit Backlogs und Ebenfalls befindet sich neben dem Profillink (4) auch Boards in Azure DevOps/TFS eine Art Bereich mit den wichtigsten kontextsensitiven Neno Loje (www.teamsystempro.de) Funktionen bzw. eine Art Schnellstartbefehlsbereich. Neben Quellcodeverwaltung (Azure Re- Der flächenmäßig größte Bereich in der Mitte (5) pos) und Build-Automatisierung (Azure ist immer zur Darstellung der Service-spezifischen Pipelines) sind es vor allem die Work Informationen gedacht. In diesem Bereich stellen Items (Azure Boards), die von kleinen alle Services bzw. die Adminseiten ihre Informa- wie großen Teams verwendet werden, tionen dar. Es wird hier konsequent versucht, auf um sich und ihre Arbeit zu organisieren. das Öffnen von zusätzlichen Browsertabs – wie in In diesem Vortrag geht es um Tipps um Tricks zur der Vergangenheit oft üblich – zu verzichten. Mitt- Strukturierung, den Umgang mit Boards und Backlogs lerweile wird eher der Ansatz des kontextsensiti- und Strategien, wie agile Teams ihre Backlogs über- sichtlich halten und sich somit auf das Wesentliche ven Umschaltens präferiert. (2) zeigt in Form eines konzentrieren können. Bread-Crumbs-Links immer den aktuell aktiven Be- reich bzw. Service an.

www.basta.net 23 DOSSIER Microservices & APIs

Abb. 4: Git in Azure Repos

Abb. 5: TFVC in Azure Repos

Backlogs, Kanban Boards sowie die Verwaltung der Im Gegensatz zu GitHub adressiert die Git-Funkti- Sprintzyklen. onalität in Azure DevOps primär nichtöffentliche Git In diesen Bereich fällt auch eine weitere Änderung Repositories. Mit einer Lizenz habe ich hier als Nutzer durch das neue UI-Konzept auf (Abb. 3). In der Ver- theoretisch die Möglichkeit, unlimitiert private Git und gangenheit waren Teams immer direkt unter dem TFVC Repositories anzulegen. Das gilt faktisch sowohl Teamprojekt angeordnet, erst dann kamen die eigent- für die Anzahl als auch die Größe der jeweiligen Repo- lichen Services. Das ist jetzt nicht mehr der Fall, statt- sitories. Dass Azure DevOps praktisch auch Riesen- dessen sind die Teams jetzt unterhalb der Services zu Repositories handhaben kann, zeigt recht eindrucksvoll finden. Am Beispiel der Backlogs sieht man das recht die Office- und Windows-Entwicklung mit Repository- anschaulich. Klickt man beispielsweise auf Backlogs, Größen von mehr als 200 GB und über 20 Mio. Dateien. werden alle Team-Backlogs angezeigt. Früher war das genau andersrum, d. h., es wurde erst das Team ausge- Azure Pipelines wählt und alle Services haben teambezogenen Informa- Der Bereich mit den in der persönlichen Wahrnehmung tionen dargestellt. Die Änderung war wohl notwendig, meisten Änderungen in den letzten Monaten ist Azure um zum einen flexibler kontextbezogen navigieren zu Pipelines. Unter Azure Pipelines wurden die ursprüngli- können und zum anderen das neue Service-Modul be- chen Build- und Releasemanagementbereiche zusammen- züglich An- und Abwahl einzelner Services besser zu gefasst. Neben den fast schon üblichen Verbesserungen unterstützen. mit jedem Sprint, wie z. B. codebasierende YAML-Build- und -Release-Definitionen, bringt Microsoft mit der Um- Azure Repos benennung zwei weitere, sehr nützliche Verbesserungen Den zweiten „neuen alten“ Bereich bilden die Azure Re- mit: Das Kontingent der freien Minuten auf den Build und pos. Dieser Bereich umfasst die ursprünglichen Funkti- Release-Agents der CI/CD Pipeline für private Projekte onalitäten rund um das Thema Version Control (Abb. 4 wurde von 240 auf 1600 Minuten erhöht. Für Open-Sour- und 5). Beispiele hierfür sind die Themen Git, Pull Re- ce-Projekte stehen für Aufträge auf diesen Agenten sogar quests, Branch Policies aber auch das gute alte zentra- unlimitierte Minuten bereit. Die Open-Source-Projekte le Versionskontrollsystem TFVC (Team Foundation können dabei entweder unter Azure DevOps als Public Server Version Control). Der Name von TFVC wurde Project oder auf einem externen System wie z. B. GitHub, wider Erwarten nicht in Azure DevOps Version Con- GitLab, SVN, Sourceforge, usw. liegen. Microsoft hat trol umbenannt und wird es laut Microsoft auch nicht dabei für Open-Source-Projekte die sonst übliche Limi- werden. tierung von einer kostenlosen Pipeline auf zehn Pipelines

www.basta.net 24 DOSSIER Microservices & APIs

Abb. 6: Azure Pipelines mit GitHub verbinden erhöht. Zehn Pipelines ermöglichen exemplarisch das par- Plattformen verteilt werden. Aus Sichtweise der Autoren allele Kompilieren auf zehn verschiedenen Build-Agenten. ist das ein sehr spannendes Angebot für Open-Source-Pro- Wenn aber Windows nicht genug ist, dann können die jekte. Dieses Angebot an die Open-Source-Community zehn parallelen Builds natürlich auch mit von Microsoft sendet ebenfalls ein starkes Signal, dass Microsoft Open- vorkonfektionierten Hosted-Agent-Pools auf Windows, Source-Projekte sehr wichtig sind und diese nicht als Spie- Linux und Mac OS X genutzt werden. Das Betriebssystem lerei ansieht, sondern auch finanziell nicht nur für GitHub spielt dabei für Microsoft bezüglich des Sponsorings kei- tief in die Tasche greift. ne Rolle. Für ein Open-Source-Projekt bedeutet das, dass Nachfolgend möchten wir kurz auf den Workflow Microsoft für sie faktisch die kompletten CI/CD Pipelines zur Einbindung eines Open-Source-Projekts in Azure auf Windows, Linux und Mac OS X kostenlos bereitstellt. Pipelines eingehen. GitHub und Azure DevOps sind – Die zehn parallelen Builds können dabei beliebig über alle obwohl beides mittlerweile zu Microsoft gehört – un-

Abb. 7: YAML-basierte Azure-Pipeline-Definition anlegen

www.basta.net 25 DOSSIER Microservices & APIs

abhängige Plattformen. Die und passt es ggf. an seine Bedürfnisse an. Anschließend Integration von Azure De- muss er mit Save and run nur noch seine Pipeline an- vOps ist deshalb auf GitHubs stoßen. Will man auf seiner GitHub-Repo-Seite ebenfalls Seite auch nicht einfach in die die Build-Statusinformationen sehen, kann man das Build- eigentliche Plattform integ- Status-Badge in seine Repo-Markdown-Files integrieren. riert, sondern verwendet die gleichen externen Erweite- Azure Test Plans rungsmöglichkeiten wie alle Formale wie explorative Tests werden in Zukunft über anderen externen Partner Azure Test Plans verwaltet und ausgeführt. Hierbei hat auch: den GitHub Market- sich strukturell im Vergleich zur vorherigen Version place. Will ich auf GitHub von TFS bzw. VSTS nichts verändert. Für das formale Azure Pipelines nutzen, muss Testmanagement stehen immer noch sogenannte Test- ich nicht erst ein Azure-Kon- pläne und Testsuits zur Verfügung, die man ineinander to mit hinterlegter Kreditkar- verschachteln kann. Die eigentliche Testdefinition findet te anlegen, um den Service zu dann in den Testfall-Work-Items statt. nutzen, sondern kann Azure In der Navigation (Abb. 8) findet der Anwender zu- Pipelines direkt und kosten- nächst die Verwaltung der Testpläne. Die nächsten Abb. 8: Beispiel für Azure Test Plan los über den GitHub Market- Menüpunkte lassen die Definition von Parametern, also place beziehen (Abb. 6). Im Eingabewerten, die wiederverwendet werden, sowie Hintergrund wird dann die Anbindung provisioniert. Als Testkonfigurationen zu. Über den Menüpunkt Runs Ergebnis entstehen dann automatisch diverse GitHub gelangt man in eine Ansicht der letzten Testdurchläufe, Webhooks, die Azure DevOps über neue Aktivitäten unabhängig davon, ob sie vom einem Build-/Releasepro- auf GitHub informieren und eine abgespeckte Azure- zess oder Testplan erzeugt wurden. DevOps-Organisation mit nur einem aktivierten Service, Load test führt den Anwender zu dem Bereich der nämlich den Azure Pipelines, einrichten. Cloud-basierten Lasttests. Hier besteht die Möglichkeit, Nach der Anbindung von Azure Pipelines legt der Nut- die Anwendung durch die wiederholte und parallelisierte zer eine oder mehre YAML-basierte Build- und Release- Ausführung bestimmter Testschritte einer definierten (ggf. Pipelines an. In Abbildung 7 ist der Prozess dargestellt, hohen) Belastung auszusetzen. Interessant hierbei ist, dass der sich an Abbildung 6 anschließt. Als Nutzer kann man ganz verschiedene Arten der Testdefinition für die Last- natürlich den Prozess auch für weitere Build- und Re- tests unterstützt werden, wie in Abbildung 9 zu sehen ist. leasedefinitionen nach einem ähnlichen Schema mehrfach Microsoft befindet sich im Bereich des Testmanage- durchlaufen. Nach der Verbindung von GitHub mit Azure ments seit längerer Zeit auf dem Weg in Richtung eines Pipelines wählt der Nutzer das passende CI-/CD-Template­ vollständigen Testmanagements im Web. Dabei gibt es

Abb. 9: Unterstützte Lasttesttypen in Azure DevOps

Abb. 10: Test-Runners für die manuelle Test- ausführung in Azure DevOps

www.basta.net 26 DOSSIER Microservices & APIs

Abb. 11: Anlegen eines neuen Package Management Feeds in Azure DevOps

zwei wesentliche Knackpunkte, die im Web nicht so ein- und einen neuen Test-Runner bereitgestellt. Die zugrunde fach zu lösen sind: Das Verbinden auf virtuelle Umgebun- liegende Problematik ist, dass der Browser eine Weban- gen im Bereich der automatisierten Tests (früher bekannt wendung aus Sicherheitsgründen nicht so einfach auf sys- als Lab Management) sowie das Sammeln von systemna- temnahe Ressourcen zugreifen lässt. hen Diagnosedaten (z. B. Windows Eventlog, geöffnete Durch den neuen Azure Test Runnes ergibt sich das Prozesse einer Desktopanwendung, usw.) beim Testen ei- auch in Abbildung 10 dargestellte Bild an Test-Runnern, ner lokal installierten Anwendung (Desktopapplikation). das in der Zukunft sicherlich wieder etwas aufgeräumt Bei letzterem hat Microsoft nun einen Vorstoß gewagt wird:

• Web Test Runner: für formale Tests von Webanwen- dungen • Azure Test Runner: für formale Tests von Deskto- Umzug vom Azure DevOps Server/ panwendungen [1] TFS in die Cloud – wie geht das? • Test- und Feedback-Extension (für Chrome und Firefox): für exploratives Testen von Webanwen- Neno Loje (www.teamsystempro.de) dungen und das Testen auf Mobilgeräten mittels des Zeit und Geld (aber vor allem Zeit!) Diensts Perfecto Mobile [2] sparen, wer möchte das nicht? Insofern • Microsoft Test Manager 2017 Test Runner: für for- bietet es sich an, zu prüfen, ob man males Testen von Desktopapplikationen mit allen Dinge nicht auslagern kann, die andere Diagnoseadaptern besser oder günstiger tun können und die nicht Kernbestandteil der eigenen Aufgaben sind. Damit wären wir auch schon beim Thema: den Azure Da der neue Azure Test Runner auf Basis des plattform- DevOps Server/TFS zu Microsoft outsourcen. Seit übergreifenden Frameworks Electron implementiert ist einigen Jahren betreibt Microsoft den Azure DevOps und bereits beim Testen von Desktopapplikationen ein Server/TFS fix und fertig in der Cloud – unter dem Aktivitätslog erstellt wird, kann man davon ausgehen, Namen Azure DevOps Services – mit allem was dazu dass es sich hier um die potenzielle Ablösung des Mi- gehört: Versionsverwaltung mit TFVC und Git, Work crosoft Test Manager 2017 Test Runners (MTM) han- Items, Build und Release, Packages und Testplänen. delt. Noch immer steckt viel Funktionalität im MTM, Dies ist die gleiche Umgebung, die Microsoft für seine eigene Softwareentwicklung verwendet, z. B. für die die noch an keiner anderen Stelle abgebildet ist, aber Entwicklung von Windows, Visual Studio oder Azure. mit dem Azure-Test-Runner geht es einen weiteren gro- In diesem Vortrag geht es darum, wie der Weg vom ßen Schritt in Richtung der Ablösung dieser alten WPF- eigenen Azure DevOps Server/TFS zu Azure DevOps basierten Anwendung aus Visual-Studio-2010-Zeiten. Services aussieht und wo aktuell die Chancen und Li- mitationen von Azure DevOps Services liegen. Hinweis Azure Artifacts zu den Produktnamen: Der Azure DevOps Server ist Den Abschluss der Vorstellung der Azure DevOps Ser­ ab Version 2019 der neue Name für den Visual Studio Team Foundation Server (TFS). Azure DevOps Services vices bildet Azure Artifacts. Dieser neue Bereich fasst war zuvor als Visual Studio Team Services (VSTS) und alle Funktionalitäten rund um das Thema Package davor als Visual Studio Online (VSO) bekannt. Management zusammen (Abb. 11). Azure Artifacts un- terstützt dabei die Platzhirsche in diesem Bereich wie

www.basta.net 27 DOSSIER Microservices & APIs

NuGet für den .NET-Bereich aber auch npm für den tures bzw. Vergünstigungen, wie bei den inkludierten gesamten JavaScript-Bereich. Bei diesen Typen bleibt Ausführungszeiten der CI/CD Pipeline zu sehen ist. Zu es aber nicht, sondern Maven, Gradle, Python sowie die guter Letzt sei da noch die Open-Source-Community Universal Pack­ages sind ebenfalls mit an Board. zu nennen, die von einem Weltkonzern mit vielen Mög- In Anhängigkeit vom Package Type unterstützt das lichkeiten unterstützt wird. Package Management zum Zeitpunkt der Drucklegung In unseren industriellen Softwareentwicklungsprojek- nicht nur die einfache Ablage und Versionierung der ten nehmen wir diesen Wandel ebenfalls wahr. So ist Artefakte in Form von Feeds, sondern bringt auch er- der Einsatz von Azure-Cloud-Diensten eben auch bei weiterte Funktionalitäten wie z. B. Upstream-Support einem mittelständischen Maschinen- oder Anlagenbau- für NuGet und npm mit. Upstream-Support ermög- er kein Tabuthema mehr. Im Gegenteil, immer mehr licht das Zwischenspeichern von Packages in Azure unserer Projekte wickeln wir nicht mehr auf „alten“ DevOps, wenn der Entwickler das Paket das erste Mal TFS-Servern ab, sondern verwenden Azure DevOps abruft. Steht das Paket aus diversen Gründen nicht mit den hier aufgezeigten Möglichkeiten und betreiben mehr zur Verfügung, kann der Entwickler aber über Test- und häufig auch Produktionsumgebungen auf der Build Agents beispielsweise auf die zwischengespei- Microsoft-Azure-Plattform. cherte Version zurückgreifen. Auch dies ist ein Bereich, Microsofts Plan scheint also – zumindest in unserer in dem Microsoft sicherlich noch das ein oder andere Wahrnehmung – aufzugehen, und wir als Teil der Ent- Feature liefern wird. wicklercommunity freuen uns über die vielen neuen Zuvor relativ beiläufig erwähnt, ist auch das Univer- Möglichkeiten. sal Package für viele Entwickler sehr spannend. Das Feature selbst ist eine Weiterentwicklung einer zuvor nur Microsoft-intern entwickelten Technologie. Uni- Nico Orschel ist Principal Consultant, Autor und Refe- versal Packages ermöglichen das generische, versionier- rent im Bereich DevOps und ALM bei der AIT GmbH & te Speichern von Dateien im TFS [3]. Das Besondere Co. KG Stuttgart und wurde von Microsoft als Most Va- luable Professional (MVP) für Development Technolo- dabei ist die eingebaute Datenduplizierung bei Up- und gies ausgezeichnet. Er hilft Unternehmen, auf Basis von Download, sodass gleiche Daten nicht mehrfach ge- Team Foundation Server/Microsoft Visu- speichert oder abgerufen werden müssen. Durch diesen al Studio Team Services effizienter Software zu entwickeln und Ansatz sinkt das benötigte Speichervolumen für Build- zu testen und so ein höheres Qualitätsniveau bei kürzeren Re- Artefakte drastisch, während gleichzeitig die Perfor- leasezyklen zu erreichen mance steigt, da Teile der Daten oft schon auf lokalen [email protected] PCs vorliegen. Die Datenduplizierung selbst funktioniert momentan noch nur auf bestimmten Windows-Versionen; aber wenn Thomas Rümmler arbeitet als Managing Consultant sie unterstützt wird, dann werden die Inhalte bis auf die und Projektleiter bei AIT und ist von Microsoft als Most Blockebene genau mit dem jeweiligen Server abgeglichen. Valuable Professional (MVP) für Development Techno- logies ausgezeichnet worden. Sein Arbeitsschwerpunkt Hier kann man sicherlich auch davon ausgehen, dass es liegt auf Application-Lifecycle-Management und De- noch einige Neuerungen geben wird, weil wir uns noch vOps. Er hilft Unternehmen, ihren Entwicklungsprozess ganz- eher am Anfang des Featurelebenszyklus befinden. heitlich zu verbessern. Seine Erfahrung gibt er als Autor des TFS-Blogs und Sprecher im Microsoft-DevOps-Umfeld weiter. Fazit http://www.tfsblog.de/ [email protected] Für die alten Hasen unter den Lesern – gemeint sind die Entwickler mit einer langen TFS- bzw. VSTS-Historie – mag sich die neue Namensgebung komisch anfühlen. Insbesondere wenn Microsoft Azure in der eigenen Ent- wicklung nicht die Zielplattform ist. Dennoch ist nach- vollziehbar, wie sich Azure DevOps als starke Marke etablieren kann, die für Offenheit und eine Vielfalt an unterstützten Technologien steht. Diese Offenheit hat Microsoft durch den Zukauf von GitHub und die bei- behaltene strikte Trennung zwischen den kommerziellen Produkten und dem Support der Open-Source-Commu- nity noch untermauert. Das kostenfreie Bereitstellen einer Links & Literatur kompletten CI/CD Pipeline ist hier nur ein Beispiel. Unterm Strich ist die aktuelle Weiterentwicklung von [1] https://aka.ms/ATRDownload Microsofts Entwicklungsplattform also eine Win-win- [2] https://marketplace.visualstudio.com/items?itemName=ms.vss- Situation. Microsoft als Hersteller eröffnet sich Zugang exploratorytesting-web zu einer größeren Community und arbeitet weiter am [3] https://blogs.msdn.microsoft.com/devops/2018/07/09/universal- eigenen Image. Die Bestandskunden erhalten neue Fea- packages-bring-large-generic-artifact-management-to-vsts/

www.basta.net 28 DOSSIER .NET Framework & C#

.NET Framework, .NET Core und Mono sind tot – lang lebe .NET 5.0! R. I. P .NET „Core“ Vom 6. – 8. Mai 2019 hielt Microsoft seine jährliche Entwicklerkonferenz Build in Seattle ab und bot einen Ausblick auf die Pläne für die kommenden Jahre – vor allem im Bereich .NET wird sich mächtig was tun.

von Dr. Holger Schwichtenberg Nach derzeitigem Stand werden in .NET 5 zum Beispiel Windows Workflow Foundation (WF) und Windows- Für .NET-Entwickler gab es auf der Microsoft Build Communication-Foundation-(WCF-)Server sowie Win- 2019 wieder einmal einen ordentlichen Paukenschlag: dows Forms aus Mono fehlen. Im Rahmen von .NET 5 .NET 5.0 (kurz .NET 5) wird der gemeinsame Nach- wird aus Mono die statische Ahead-of-Time-(AOT-) folger der drei bisherigen .NET-Varianten (.NET Core, Kompilierung als Alternative zur bisherigen Just-in- .NET Framework und Mono) sein. Alle .NET-Anwen- Time-(JIT-)Kompilierung in .NET einfließen, sodass dungsarten von Desktop (WPF und Windows Forms) .NET-Entwickler zukünftig zwischen JIT und AOT über Webserver (ASP.NET) und Webbrowser (Blazor/ wählen können. AOT bietet .NET-Entwicklern kleinere WebAssembly) bis zu Apps (UWP, Xamarin) und Spie- Installationspakete und schnellere Anwendungsstarts, len (Unity) sollen damit zukünftig eine gemeinsame aber wegen der Vorkompilierung in Maschinencode .NET-Basis haben. eben keine plattformunabhängigen Installationspakete. .NET 5 soll im November 2020 erscheinen und im .NET 5 wird auch neue Funktionen beinhalten. Dazu Wesentlichen (aber nicht komplett) plattformneutral gehört eine Integration mit anderen Frameworks und sein (Abb. 2). Einige Anwendungsarten, die auf .NET 5 Programmiersprachen (Java, Objective-C und Swift) für basieren, werden nur auf bestimmten Plattformen lau- die App-Entwicklung auf iOS und Android. fen, z. B. UWP-Apps nur auf Windows 10, WPF- und Windows-Forms-Desktopanwendungen nur auf Win- Der Begriff „Core“ verschwindet wieder dows ab Version 7. .NET 5 darf nicht verwechselt wer- „.NET Core“ hatte Microsoft als Namen am 12.11.2014 den mit .NET Core 5 – dem Namen, den Microsoft für für das schon am 13. Mai 2014 verkündete „cloud-opti- .NET Core 1.0 geplant hatte, bevor man sich entschloss, mized .NET Framework“ alias „Project K“ eingeführt. die Versionszählung wieder von vorne zu beginnen. Version 1.0 erschien dann am 26. Juli 2016. Danach gab es die Versionen 1.1, 2.0, 2.1, 2.2. Version 3.0 von Nicht alle Features kommen in .NET 5 .NET Core soll im September 2019 erscheinen; auf der Technisch gesehen ist .NET 5 die Weiterführung von Build gab es die Preview-5-Version [1]; die Veröffent- .NET Core (mit den zugehörigen Werkzeugen und De- lichung des Release Candidate ist für Juli dieses Jahres ployment-Optionen), in das große Teile (aber nicht alles) geplant, dann soll es noch ein .NET Core 3.1 im No- von .NET Framework und Mono einfließen (Abb. 2). vember 2019 geben.

www.basta.net 29 DOSSIER .NET Framework & C#

Abb. 1: Abschied von Abb. 2: .NET 5 im Verhältnis zu .NET Core, .NET Framework und Mono .NET Core

Abb. 3: Zeitplan für die kommenden .NET-Versionen (Quelle: Microsoft)

Damit soll dann die .NET-Core-Ära auch schon sen, die ausschließlich auf Windows laufen (z. B. für die wieder enden (Abb. 3). Es wird keine weiteren Versi- Registry-Programmierung). Dies wird verstärkt auch onen mehr mit „Core“ im Namen geben. Als Nächs- in .NET Core 3.0 gelten: Dort gibt es zwar dann die tes kommt .NET 5 (Abb. 3), denn Microsoft findet den GUI-Frameworks WPF und Windows Forms, aber sie Begriff inzwischen nicht mehr geeignet in der Kommu- sind weiterhin nicht plattformunabhängig, sondern an nikation, gerade für neu in die .NET-Welt eintretende Windows gebunden. Der Sinn von WPF und Windows Softwareentwickler. Forms liegt darin, dass Softwareentwickler bestehende Mit .NET Core Version 2.0 hatte Microsoft begon- .NET-Framework-basierte WPF- und Windows-Forms- nen, massiv Klassen aus dem .NET Framework nach Anwendungen auf .NET Core umziehen können. Auch .NET Core zu übernehmen. Man kehrte damit von in .NET 5 wird sich an dieser Plattformeinschränkung dem .NET-Core-1.x-Gedanken ab, das neue .NET erst einmal nichts ändern. Core klein und aufgeräumt zu halten. Stattdessen stand .NET Core 3.0 liefert darüber hinaus .NET Stan- nun auf der Agenda, möglichst kompatibel zum .NET dard 2.1, Unterstützung für gRPC und das neue Framework zu werden, damit bestehende klassische ASP. NET-SignalR-basierte Webanwendungsmodell .NET-Framework-Anwendungen auf .NET Core um- Server-side Blazor – nicht zu verwechseln mit dem ziehen können. In Version 2.1 führte Microsoft diese WebAssembly-basierten Client-side Blazor, das zwar Trendwende mit dem Windows Compatibility Pack nun eine offizielle Vorschau ist, für das es aber weiterhin (WCP) fort: Erstmals gab es in .NET Core nur Klas- keinen Veröffentlichungstermin gibt.

www.basta.net 30 DOSSIER .NET Framework & C#

.NET Framework 4.8 auf dem Abstellgleis und einem Erweiterungsmodell mit eigenem Markt- Softwareherstellern und Softwareentwicklern, die heu- platz spendieren. Das Windows Terminal wird für die te bestehende WPF- und Windows-Forms-Anwendun- klassische CMD, die PowerShell und das Shell für Win- gen besitzen oder neu planen, machte Microsoft auf der dows for Linux (WSL) zur Verfügung gestellt werden. Build-Konferenz klar, was sie schon am 4. 10. 2018 in Die erste Version soll es aber erst im Juni 2019 geben. einem Blogeintrag [2] angedeutet hatten: Die am 18. • Der neue Chromium-basierte Microsoft-Edge-Web­ April 2019 erschienene Version 4.8 ist die letzte Versi- browser erhält einen Kompatibilitätsmodus zum on des .NET Frameworks, die signifikante neue Funk- Internet Explorer 11 (IE Mode). Unternehmen, die tionen bieten wird. Alles, was danach noch an Updates auf Funktionen des Internet Explorers für alte Int- kommen wird, wird lediglich Sicherheitslücken und ranetanwendungen angewiesen sind (z. B. ActiveX), kritische Softwarefehler betreffen. Vielleicht wird das sollen damit auf Edge umsteigen können. ein oder andere Netzwerkprotokoll noch auf den neu- esten Stand gebracht, das wars dann aber. Werkzeuge

Deterministische Erscheinungstermine • Von Visual Studio 2019 gibt es eine dritte Vorschau- Microsoft will bei .NET 5 bei der in .NET Core eta- veröffentlichung auf Version 16.1 [4]. Die bisher blierten, agilen und transparenten Entwicklungswei- eigenständige IntelliCode-Erweiterung ist nun für die se eines Open-Source-Projekts auf GitHub bleiben. Sprachen C# und XAML enthalten. Auch die GitHub- Einen Unterschied soll es aber zu .NET Core geben: Erweiterungen gehören nun zum Standard. Ebenso Anstelle der bisherigen unregelmäßigen Erschei- soll die Performance für C++- und .NET-Entwickler in nungstermine soll es jedes Jahr im November eine einigen Punkten verbessert sein. In C# gibt es nun Intel- neue Hauptversion mit Breaking Changes geben, d. h. liSense auch für Typen, die noch nicht importiert sind. nach .NET 5 im November 2020 gibt es dann .NET 6 • Die Visual-Studio-Abonnementoptionen werden er- im November 2021, .NET 7 im darauffolgenden Jahr weitert um „Visual Studio Professional with GitHub usw. (Abb. 3). Enterprise“ und „Visual Studio Enterprise with Git- Zwischendurch sind Unterversionen mit neuen Fea- Hub Enterprise“ im Rahmen von Enterprise Agree­ tures, aber ohne Breaking Changes bei Bedarf angedacht. ments (EA) [5]. Jede zweite Version soll eine Long-Term-Support-(LTS-) • Entwickler können mit Visual Studio Online (VSO) Version mit drei Jahren Unterstützung durch Microsoft im Browser coden. Für diesen Onlineeditor verwen- sein [3]. .NET Core 3.0 wird genau wie .NET Core 2.0 keine LTS-Version sein; die auf .NET Core 2.1 folgende LTS-Version wird .NET Core 3.1 sein. Dann geht es in der LTS-Linie erst 2021 weiter. Weitere Neuigkeiten von der Microsoft Build: .NET Core 3.x und .NET 5.0: Die Windows Wiedergeburt der Desktops-Fron- tends und andere Neuigkeiten • Ein verbessertes Linux-Subsystem in Windows Dr. Holger Schwichtenberg (WSL) bietet schnellere Dateisystemoperationen (www.IT-Visions.de/5Minds IT-Solutions sowie die Unterstützung für Linux-basierte Docker- Bisher war .NET Core nur für Server-, Container. Web- und Konsolenentwickler interes- • Microsoft wird seinem Windows-Betriebssystem end- sant. Mit .NET Core 3.0 liefert Microsoft lich ein neues Kommandoeingabefenster (Windows nun auch WPF und sogar Windows Terminal) mit zeitgemäßer Zeichensatzunterstützung Forms für .NET Core, allerdings nur inklusive Emoticons, Registerkarten, Layoutthemen auf Windows. Mit dem App-Bundler von .NET Core 3.0 kann man eine Desktopanwendung zusammen mit .NET Core ausliefern, enorm verkleinern und zu einer EXE zusammenschnüren. Dann folgt .NET Core Build 2019 3.1 und danach .NET 5.0 als einheitliches .NET für alle Anwendungsarten. DOTNET-DOKTOR Holger Die Build-Konferenz fand vom 6. bis 8. Mai 2019 in Schwichtenberg thematisiert in diesem Vortrag die vier Seattle statt. Während die Veranstaltung früher im- großen Fragen: Was ist auf .NET Core 3.0 möglich? mer sehr schnell ausgebucht war, konnte Microsoft Welche Vorteile bietet .NET Core 3.0 für bestehende sie nun zum zweiten Mal in Folge nicht ganz füllen. und neue Desktopanwendungen? Mit welchem Auf- Einige Teilnehmer nennen als Grund dafür, dass wand kann ich bestehende Anwendung auf .NET Core Microsoft nicht mehr wie früher Hardwaregeschen- 3.0 umstellen? Was kommt dann mit .NET 5? Natürlich ke verteile. Die Aufzeichnungen der Vorträge kann werden auch andere Neuigkeiten rund um den C# 8.0, jedermann kostenfrei unter https://www.microsoft. .NET-Standard, ASP.NET Core, ASP.NET Blazor und com/en-us/build ansehen. Entity Framework Core nicht fehlen

www.basta.net 31 DOSSIER .NET Framework & C#

det Microsoft wieder den Namen VSO, den man YAML-basierten Pipeline-Definitionen nur für Build zwischen dem 14. 9. 2011 und dem 13. 12. 2013 als Pipelines nutzen. Nun gibt es dieses Feature auch für Name für die heutigen Azure DevOps Services ver- Release-Pipelines. Ein einziges YAML-Dokument wendete [6]. kann dabei sowohl die Build- als auch die Release- Pipeline enthalten. YAML-Pipeline-Definitionsdo- .NET kumente können im Quellcodeverwaltungssystem eingecheckt sein. Das gibt den Entwicklern die Mög- • Mit .NET Core 3.0 Preview 3 liefert Microsoft eine lichkeit, Pipeline-Definitionen auf einfache Weise erste Version des „Single-File Bundlers“ aus [7], die spezifisch für einzelne Branches zu erstellen. alle Dateien einer .NET-Core-Anwendungen in eine • Für das Deployment auf Azure Kubernetes Services selbstentpackende Executable verpackt. Eine echte .exe und Red Hat OpenShift gibt es nun Vorlagen in Azu- mit AOT-Compiler soll es erst in .NET 5.0 geben. re DevOps, sowohl für Cloud als auch On-Premises. • Die auf der Build 2018 angekündigten „XAML­- -Inseln“ werden in Windows 10 mit dem Update im Mai 2019 verfügbar sein. Damit können Steuerele- Dr. Holger Schwichtenberg (MVP) alias „der Dotnet- mente der Universal Windows Platform (UWP) in Doktor“, ist technischer Leiter des auf .NET und Web- WPF und Windows Forms eingebunden werden (na- techniken spezialisierten Beratungs- und Schulungsunternehmens www.IT-Visions.de. Er gehört türlich setzt dies Windows 10 voraus!) [8]. durch zahlreiche Fachbücher zu den bekanntesten Ex- • Mit MSIX Core können Entwickler das MSIX- perten für .NET und Visual Studio in Deutschland. Dr. Holger Installationsformat auch auf Windows-Versionen vor Schwichtenberg unterrichtet in Lehraufträgen an den Fach- Windows 10 verwenden. hochschulen Münster und Graz. Seit 1999 ist er Sprecher • Ergänzend zur Microsoft Authentication Library auf jeder BASTA!. (MSAL) for JavaScript [9] sowie Objective-C für [email protected] www.dotnet-doktor.de iOS [10] und Android [11] gibt es nun diese Hilfsbib- liothek für Azure Active Directory auch für .NET. • ML.NET, die auf der Build 2018 angekündigte Machine-Learning-Bibliothek für .NET, erreicht Version 1.0 [12]. • .NET-Programmierung ist nun auch dem Cluster- Computing-Framework Apache Spark möglich mit „.NET for Apache Spark“. • Xamarin Forms 4.0 gibt es als Public Preview, u. a. mit dem neuen CollectionView-Steuerelement, das ListView ersetzen soll, indem es schneller ist.

SQL Server Links & Literatur • Mit Azure SQL Database Edge [13] liefert Microsoft nun eine sowohl auf x64- als auch auf ARM-Syste- [1] https://dotnet.microsoft.com/download/dotnet-core/3.0 men installierbare SQL-Server-basierte Datenbank [2] https://msdn.microsoft.com/en-us/magazine/mt848631 mit niedrigen Systemanforderungen. Das API der Azure SQL Database Edge soll kompatibel zu SQL [3] https://dotnet.microsoft.com/platform/support/policy/dotnet-core Server und SQL Azure sein. [4] https://devblogs.microsoft.com/visualstudio/visual-studio-2019- version-16-1-preview-3/ DevOps [5] https://visualstudio.microsoft.com/subscriptions/visual-studio-github/ • Für Azure DevOps gibt es ein neues Preismodell. Es [6] https://devblogs.microsoft.com/visualstudio/intelligent-productivity- gibt keine Preiskategorien mehr: Wer mehr als fünf and-collaboration-from-anywhere/ Benutzer hat, zahlt 6 Dollar pro Benutzer. Für in der [7] https://github.com/dotnet/core-setup/pull/5286 Cloud gespeicherte Artefakte zahlt man zukünftig [8] https://docs.microsoft.com/de-de/windows/uwp/xaml-platform/xaml- zwischen 2 und 0.25 Dollar pro Gigabyte, wobei die host-controls ersten zwei Gigabyte frei sind. [9] https://github.com/AzureAD/microsoft-authentication-library-for-js • Durch die Azure-Active-Directory-(AAD-)Unter- [10] https://github.com/AzureAD/microsoft-authentication-library-for-objc stützung in GitHub können Entwickler nun Be- nutzergruppen zwischen dem AAD und GitHub [11] https://github.com/AzureAD/microsoft-authentication-library-for- synchronisieren [14]. Android • Auf der anderen Seite unterstützten die Webportale [12] https://github.com/dotnet/machinelearning/releases für Azure und Azure DevOps nun auch die Benutzer- [13] https://azure.microsoft.com/en-us/services/sql-database-edge/ anmeldung mit GitHub-Benutzerkonten. [14] https://github.blog/2019-05-06-team-synchronization-across-github- • Bisher konnten Azure-DevOps-Nutzer die neuen and-azure-active-directory/

www.basta.net 32 DOSSIER .NET Framework & C#

Hintergrund und Einstieg in ML mit .NET Machine Learning für die Zukunft Das Thema Machine Learning ist so präsent wie noch nie, obwohl es eigentlich alles andere als neu ist. Algorithmen haben in den letzten Jahren in immer mehr Bereiche unseres Le- bens Einzug gehalten und sind wohl dabei, die Gesellschaft nachhaltig zu verändern. Doch was verbirgt sich hinter den Buzzwords KI und Machine Learning und wie können Entwick- ler sich diese Technologien zu eigen machen? Mit diesen Fragen beschäftigt sich der nach- folgende Artikel und gibt anhand praxisnaher Beispiele Antworten.

von Kevin Gerndt ersetzt wurden, wird es diesmal auch Berufe wie etwa Buchhalter, Steuerprüfer und klassische Bürokräfte Die Machine-Learning-Technologie hat mittlerwei- treffen. le große Teile unseres Alltags erobert und ihr Sie- geszug scheint nicht mehr aufzuhalten zu sein. Ob Warum jetzt? Spracherkennung im Auto, persönlicher Assistent im Doch was hat eigentlich diesen regelrechten KI-Boom Smart­phone oder Fraud Detection beim Bezahlvor- der letzten Jahre ausgelöst, obwohl das Thema an sich gang – nahezu überall verbirgt sich Machine Learning doch schon über fünfzig Jahre alt ist? Im Wesentlichen beziehungsweise künstliche Intelligenz. Glaubt man stützt sich die überproportionale Entwicklung auf drei jedoch führenden Wissenschaftlern und Visionären, wichtige Säulen: Daten, Algorithmen und Rechenleis- handelt es sich hierbei erst um den Anfang. Unumstrit- tung. Aktuell erzeugen über drei Milliarden Webnutzer ten ist, dass Machine Learning unser Leben und die sowie die unzähligen, vernetzten Smart- und IOT-Gerä- Arbeitswelt, wie wir sie heute kennen, verändern wird. te jeden Tag etwa 2,5 Trillionen Bytes an Daten. Kon- Laut einer Studie des Instituts für Arbeitsmarkt- und kret bedeutet dies, dass 90 Prozent aller verfügbaren Berufsforschung (IAB) [1] sind Computer in der Lage, Daten in den letzten zwei Jahren entstanden sind. Ein mindestens 70 Prozent der Tätigkeit von acht Millio- autonom fahrendes Fahrzeug erzeugt pro Stunde eine nen Beschäftigten zu erledigen. Dadurch könnten bis gigantische Datenmenge von vier Terabytes. Ein selbst- zum Jahr 2025 bis zu 1,5 Millionen Arbeitsplätze in lernendes Computersystem benötigt eine enorm große Deutschland wegfallen. Doch diese Entwicklung macht Menge an Daten, die vor zehn Jahren einfach noch nicht den Menschen nicht komplett überflüssig, denn ohne zur Verfügung stand, zum Beispiel, wenn es um das Er- Menschen bringt Machine Learning keinen Mehrwert. kennen von Objekten wie etwa Personen, Autos oder Nicht außeracht zu lassen ist, dass die KI-Revolution Verkehrszeichen geht. Für die schnelle und zuverlässige auch jede Menge hochwertige Jobs und neue Berufs- Identifizierung von Objekten bedarf es wiederum effi- bilder, wie etwa Data Engineers, Data Scientists oder zienter Algorithmen. Auch in dieser Hinsicht hat die Data Strategen erschaffen wird. Berufe mit sich ständig Wissenschaft in den letzten Jahren enorme Fortschritte wiederholenden Arbeitsabläufen und Prozessen wer- vermelden können. Ein Schlagwort in diesem Zusam- den allerdings unweigerlich und zunehmend durch in- menhang ist Deep Learning. Neben großen Datenmen- telligente Algorithmen ersetzt. Anders als bei der ersten gen und effizienten Algorithmen wird noch eine dritte und zweiten Industriellen Revolution, bei der vorwie- Komponente benötigt: Rechenleistung. Das immense gend Jobs der Arbeiterklasse und in der Landwirtschaft Cloud-Wachstum der letzten Jahre hat dazu geführt,

www.basta.net 33 DOSSIER .NET Framework & C#

Abb. 1: Maschine-Learning-Übersicht dass schier unendliche Rechenpower durch Cloud- Dienste zur Verfügung gestellt und abgerufen werden kann. Cloud-Anbieter wie , Microsoft und Ama- zon ermöglichen es Firmen oder Privatleuten, gigan- tische Rechenleistung für einen benötigten Zeitraum abzurufen, ohne dass erst in das eigene Rechenzentrum investiert werden muss. Aber auch Hardwarehersteller wie etwa Nvidia oder Intel haben den Trend unlängst er- kannt und spezielle Hardware für die Verarbeitung von KI-Operationen entwickelt und optimiert. Die Basis für eine Welt voller Algorithmen und Automation scheint somit perfekt. Um jedoch moderne Applikationen und künstliche Intelligenz miteinander zu verknüpfen, be- darf es einer weiteren wichtigen Komponente: des Ent- wicklers. Im Folgenden gibt es deshalb einen Überblick über das Thema Machine Learning und es wird gezeigt, mit Hilfe welcher Werkzeuge sich künstliche Intelligenz Abb. 2: Klassische Programmierung vs. Maschine Learning in Softwarelösungen integrieren lässt.

Machine Learning, Deep Learning oder künstliche derlich. Am besten lässt sich das anhand des Beispiels Intelligenz? der Objekterkennung erklären. In der sogenannten Trai- Künstliche Intelligenz ist wohl jedem ein Begriff, schließ- ningsphase erhält eine Software eine gigantische Men- lich ist es ein beliebter Schwerpunkt unzähliger Kinofil- ge von Bildern mit zum Beispiel Verkehrssituationen. me wie etwa „Matrix“, „Terminator“ oder „I, Robot“. Die Software versucht nun, anhand eines Algorithmus Immer häufiger kann man aber auch in der Presse von ähnliche Objekte auf den Bildern zu identifizieren. Ein künstlicher Intelligenz, neuronalen Netzen, Deep Learn­ Stoppschild verfügt über charakteristische Merkmale ing oder Machine Learning lesen. Wer sich noch nicht wie etwa die Form, die Aufschrift und die Farbe. Der intensiver mit der Materie beschäftigt hat, mag die Be- Computer weiß natürlich nicht um die Bedeutung des zeichnungen womöglich für Synonyme halten. Um das Stoppschilds, aber er erkennt das Muster. Im nächsten Thema zu durchdringen, ist es zunächst erforderlich, die Schritt der Klassifizierung wird das Objekt mit einem Unterschiede und Zusammenhänge zu verstehen. Hier- sogenannten Label versehen. Somit ist nun bekannt, bei soll die in Abbildung 1 gezeigte Mindmap helfen. dass es sich um ein Stoppschild handelt. Mittels einer Machine Learning ist der Oberbegriff und letztendlich Programmierung könnte nun beispielsweise im Szena- nichts anderes als eine Sammlung mathematischer Me- rio des autonomen Fahrens das Fahrzeug angewiesen thoden. Darunter angeordnet sind verschiedene Diszip- werden zu stoppen, wenn ein Stoppschild erkannt wird. linen, die wiederum dazu dienen, spezifische Probleme An diesem Beispiel lässt sich der Unterschied zwischen zu lösen. Die hier dargestellte Mindmap zeigt nur einen klassischen Programmiermodellen und Machine Learn­ kleinen Ausschnitt des großen Ganzen. Zu jeder Prob- ing sehr gut veranschaulichen. Denn genauso gut wäre lemstellung gibt es eine Vielzahl verschiedener Algorith- es natürlich denkbar und möglich, eine Routine zu ent- men, die im Laufe der Jahre entwickelt wurden. Diese wickeln, die auf einem Bild speziell nach den charakte- Algorithmen sind der Schlüssel zu Machine Learning ristischen Merkmalen eines Stoppschilds sucht. Jedoch und künstlicher Intelligenz. Soll zum Beispiel ein einfa- wäre der Aufwand viel höher und der Algorithmus nicht ches Vorhersagemodell erstellt werden, eignet sich am in der Lage, durch eine größere Menge an Daten die Er- besten ein Regressionsverfahren, für das Erkennen von kennung zu verbessern (Abb. 2). Objekten hingegen ein Deep-Learning-Algorithmus. Doch wie ist ein Computer dazu in der Lage zu lernen? Supervised und Unsupervised Learning Damit eine Maschine in die Lage versetzt werden kann Im Bereich des Machine Learning werden im Wesent- zu lernen, sind in erster Linie große Datenmengen erfor- lichen zwei Kategorien des Lernens unterschieden:

www.basta.net 34 DOSSIER .NET Framework & C#

Supervised Learning (überwachtes Lernen) und Un- supervised Learning (unüberwachtes Lernen). Beim Supervised Learning, der gebräuchlicheren Variante, wird der Mensch dazu benötigt, dem Algorithmus Schlussfolgerungen beizubringen. Diese Art des Ler- nens kommt der menschlichen Art des Lernens sehr nahe. Soll ein Programm zum Beispiel das Erkennen von Katzen erlernen, wird in der Trainingsphase eine große Menge mit Labels versehener Katzenbilder ein- gelesen. Nach dem Lernprozess erfolgt die Prüfung auf Korrektheit in der Erkennung durch eine Testphase, bei der wiederum Bilder ohne Label verarbeitet wer- den. Die Erwartungshaltung ist, dass das Programm Katzen zu einem möglichst hohen Prozentsatz identi- fiziert. Auch wenn die Unterscheidung zwischen Hund und Katze für Menschen schon im frühen Kindesalter keine große Herausforderung darstellt, bedarf es beim Abb. 3: Clustering Anlernen eines Modells etwas mehr Geduld und mehr- facher Optimierungsvorgänge. Google schafft mittler- mehrere Millionen Wählerdaten mit einer Reihe ver- weile mit einem Identifizierungsalgorithmus immerhin schiedener Parameter wie etwa Einkommen, Alter, eine Trefferquote von 75 Prozent. Ein weiteres Anwen- Geschlecht und gewählter Partei. Ziel ist es, das wahr- dungsgebiet des überwachten Lernens sind Regressi- scheinliche Wahlverhalten eines Wählers nun anhand onsprobleme, auf die im weiteren Verlauf des Artikels von Einkommen, Alter und Geschlecht zu ermitteln. noch eingegangen wird. Mit Hilfe dieser statistischen Um dieses Ziel zu erreichen, werden mittels eines Al- Verfahren lässt sich zum Beispiel das Gehalt oder Ge- gorithmus zunächst Cluster oder Gruppierungen ge- wicht einer Person anhand von Abhängigkeitsdaten bildet (Abb. 3). vorhersagen. Um die Darstellung zu vereinfachen, ist diese auf Der häufigste Anwendungsfall für unbeaufsichtigtes zwei Dimensionen reduziert und gleicht einem Ideals- Lernen ist wohl das sogenannte Clustering. Es dient, zenario. Die Herausforderung des Clusterings wird wie der Begriff schon vermuten lässt, dem Bilden von jedoch an dem schwarzen Ausreißer erkennbar. Um Gruppierungen, um große Datenmengen zu visua- diese Problemstellung zu lösen, existiert eine Vielzahl lisieren. Am einfachsten kann Clustering mit einem an Algorithmen. Eines der einfachsten mathemati- Beispiel erklärt werden. Ein Algorithmus analysiert schen Verfahren ist der K-Means-Algorithmus. Bei diesem werden zunächst K Zufallspunkte generiert, um die wiederum die Daten gruppiert werden. Die An- zahl der Zufallspunkte K entspricht in diesem Fall der Anzahl von Parteien, was die Clusterbildung enorm vereinfacht. Daraus wiederum ergibt sich auch direkt ML und Unity – eine spielerische der erste Nachteil dieses Vorgehens, denn es wird im- Einführung in Reinforcement mer zwingend davon ausgegangen, dass ein unbekann- Learning ter Wähler einer der existierenden Parteien (Cluster) Dennis Deindörfer (MT AG) zugeordnet werden kann. Um eine Zuordnung zu er- reichen, wird für jeden Datenpunkt die euklidische Auf dem Weg hin zu selbstlernenden, Distanz zum sogenannten Centroid errechnet. Der autonomen Algorithmen, wie sie im Bereich der künstlichen Intelligenz Vorgang zur Berechnung der Clusterzentren und der verwendet werden müssen, werden Zuordnung der Datenpunkte wiederholt sich so lange, Lernverfahren benötigt, die auf eine bis sich die Zentren nicht mehr oder nur noch mini- sich verändernde Dynamik der Umgebung reagieren. mal ändern. Anhand der eingegebenen Daten konnten Hier setzen die Lernverfahren des Reinforcement in diesem Szenario drei Cluster ermittelt werden. Die Learnings an, die zukünftige Handlungen antizipieren Aufgabe besteht nun darin, den schwarzen Punkt ohne und diese in der Entscheidungsfindung berücksich- bekanntes Parteienmerkmal einem Cluster zuzuord- tigen. Im Rahmen des Talks wird die Funktionsweise von Reinforcement Learning anhand eines Spiels und nen. Auf den ersten Blick kann ausgeschlossen werden, unter Verwendung des Unity-ML-Agents-Toolkits dass der schwarze Punkt zum grünen Cluster gehört. veranschaulicht. Garantiert ohne langatmige Exkursi- Die eindeutige Zuordnung zwischen dem orangen und onen der zugrunde liegenden Mathematik, dafür aber blauen Cluster gestaltet sich für das menschliche Auge mit einsteigerfreundlichen Erläuterungen und vielen schon etwas schwieriger. Für den Algorithmus hinge- Visualisierungen. gen ist es nur die logische Zuordnung zum nächsten Clusterzentrum.

www.basta.net 35 DOSSIER .NET Framework & C#

dellieren. Die Vorgehensweise lässt sich zunächst am besten anhand eines verein- fachten Models mit zwei Variablen erklä- ren. Die Eingangsparameter werden auch als Features bezeichnet. Wird ein Modell durch das Entfernen von Features verein- facht, wird häufig von Featurereduktion gesprochen. Der Preis einer Wohnung soll aufgrund der Größe bestimmt werden. Zwischen diesen zwei Größen besteht eine Abb. 4: Visualisierung der Eingangsdaten Abb. 5: Line of Best Fit Korrelation: je größer die Wohnung, des- to höher der Preis. Jedoch ist eine Wohnung Regression mit ML.NET mit 200 Qua­dratmetern nicht genau doppelt so teuer wie Eine gute Einstiegsmöglichkeit, um mit der Entwick- eine Wohnung mit 100 Quadratmetern. Um nun ein Vor- lung eigener Modelle oder der Integration von Maschine hersagemodell basierend auf einer linearen Regression Learning in Software zu starten, bietet das Open-Sour ce- entwickeln zu können, wird zunächst ein Datensatz be- Machine-Learning-Framework ML.NET von Microsoft. stehend aus den Informationen Größe und Preis benötigt. Ein großer Vorteil ist die einfache Handhabung. Damit Um die Beziehung der zwei Variablen zueinander besser ist eine Verwendung der Bibliothek ohne fortgeschrittene zu verstehen, bietet es sich an, die Daten zunächst zu visu- Kenntnisse im Bereich des Maschine Learnings möglich. alisieren. Das kann zum Beispiel mittels eines Datenana- Die Bibliothek wurde ursprünglich von dem Microsoft- lysetools wie KNIME erfolgen. Aus dieser Darstellung Forschungsbereich Microsoft Research entwickelt und (Abb. 4) geht nun ganz klar hervor, dass die Daten zwar kommt in vielen Microsoft-Produkten wie etwa Bing linear sind, aber nicht der Funktion f(x)=x entsprechen. oder der Office-Produktpalette zum Einsatz. Mit der Um ein aussagekräftiges Modell entwickeln zu kön- ML.NET-Bibliothek lassen sich Aufgaben wie etwa Klas- nen, muss die Linie gefunden werden, die die Beziehung sifizierung, Sentimentanalysen oder auch das Entwickeln zwischen Wohnfläche und Preis am ehesten widerspie- von Vorhersagemodellen (Regression) einfach lösen. gelt. Hierfür kommen die beiden Verfahren lineare Re- Ein weiterer Vorteil besteht in der lokalen Verwendung. gression und Gradient Descent zum Einsatz. Vereinfacht Es ist also nicht erforderlich, einen Account bei einem gesagt wird zunächst ein Fehlerwert berechnet, der sich Cloud-Dienst wie Azure zu erstellen und für die benötig- aus der Summe der Abstände zwischen den einzelnen ten Ressourcen und Rechenleistung zu bezahlen. Auf der Datenpunkten und der festgelegten Linie errechnet. Um anderen Seite kann sich eine Trainingsphase aufgrund der den kleinsten Fehlerwert zu finden, kommt Gradient mangelnden Rechenleistung dadurch natürlich stark aus- Descent, ein Verfahren zur Optimierung einer Funkti- dehnen. Im Nachfolgenden wird anhand eines Beispiels on, zum Einsatz. Bei dieser Vorgehensweise wird bild- erklärt, wie sich ein Vorhersagemodell zur Bestimmung lich gesprochen die Linie solange verschoben, bis der von Wohnungspreisen anhand verschiedener Kriterien kleinstmögliche Fehlerwert erreicht ist. Bei jedem dieser wie etwa Größe, Anzahl der Bäder und Zimmer sowie Durchläufe wird mittels der Learning Rate bestimmt, das Vorhandensein eines Balkons mittels ML.NET ent- wie schnell sich der Algorithmus dem Ziel nähert. Ge- wickeln lässt. Um eine Lösung für dieses Problem erarbei- nau hier verbirgt sich auch die Krux, denn je niedriger ten zu können, ist es zunächst wichtig zu verstehen, um die Learning Rate, desto mehr Durchläufe werden be- was für eine Art Problem es sich handelt. Da in diesem nötigt und somit verlängert sich auch die Trainingspha- Fall anhand verschiedener Eingangsparameter (Fläche, se. Bei einer zu hoch angesetzten Learning Rate kann es Anzahl der Zimmer etc.) ein Preis ermittelt werden soll, wiederum passieren, dass die optimale Funktion nicht handelt es sich um ein sogenanntes Regressionsproblem. gefunden wird. Die Line of Best Fit für das hier skizzier- Für dessen Lösung wird auf die Regressionsanalyse, also te Beispiel ist in Abbildung 5 dargestellt. ein statistisches Verfahren zurückgegriffen, die das Ziel Mit Hilfe des trainierten Models lässt sich nun her- verfolgt, die Beziehung zwischen einer abhängigen und ausfinden, dass eine Wohnung mit 2 341 Square Feet einer oder mehreren unabhängigen Variablen zu mo- ca. 156 000 Pfund kostet. Allerdings ist der Wert nur

Price SqFt Bedrooms Bathrooms Offers Brick 114300 1790 2 2 2 False

114200 2030 4 2 3 False

114800 1740 3 2 1 False

… … … … … …

Tabelle 1: Analyse der Trainingsdaten

www.basta.net 36 DOSSIER .NET Framework & C#

wenig verlässlich, da einige zuvor entfernte Einflussfak- lesen der Trainingsdaten, die in Tabelle 1 exemplarisch toren, wie etwa ob die Wohnung einen Balkon hat, die dargestellt sind, zu ermöglichen, muss eine Modellklasse Anzahl der Zimmer usw., entfernt wurden. Ein wichti- auf Basis der vorliegenden Daten entwickelt werden. ges Kriterium für die Verlässlichkeit eines Modells ist Diese beinhaltet Eigenschaften für alle im Trainings- somit die Auswahl der richtigen Features. Zum Beispiel datenset enthaltenen Spalten und bildet diese in der vor- bestimmt das Vorhandensein eines Balkons den Preis liegenden Reihenfolge mittels des Column-Attributs ab mit hoher Wahrscheinlichkeit. Die Wandfarbe in der (Listing 1). Mit der zusätzlichen name-Eigenschaft und Wohnung hingegen spielt eine sehr geringe bis gar kei- der Bezeichnung Label wird das Feature markiert, das ne Rolle bei der Preisfindung. Wird diese jedoch in die die standardmäßig korrekten Werte für die Vorhersage Liste der Features mit aufgenommen, kann es passieren, enthält. dass der Algorithmus ungewünschte Korrelationen in Eine genaue Spezifikation dessen, was bestimmt wer- den Daten findet, die aber eigentlich gar keine Relevanz den soll, findet sich in der Klasse HousePricePrediction. haben. Bei diesem Effekt wird häufig von Overfitting ge- Für die Regressionsaufgabe enthält die Spalte Score sprochen. Mit zunehmender Anzahl von Features wird die vorhergesagten Bezeichnungswerte. Nachdem nun allerdings auch die Darstellung des Models immer kom- Klarheit über die Datenstruktur herrscht, ist es an der plizierter, weshalb sich ein solches Szenario am besten Zeit, das Model zu trainieren. Die Basis hierfür stellt die unter Zuhilfenahme einer Bibliothek wie ML.NET rea- LearningPipeline-Klasse der ML.NET-Bibliothek dar, lisieren lässt. Um mit der Entwicklung starten zu können, die sich im Namespace Microsoft.ML.Legacy befindet muss zunächst ein neues Projekt auf Basis des Visual-Stu- (Listing 2). Mittels der Learning-Pipeline wird zunächst dio-Templates Console App (.NET Core) angelegt wer- die Quelldatei für die Trainingsdaten festgelegt. Da der den. Anschließend ist es erforderlich, mittels des NuGet Algorithmus, der das Model trainiert, numerische Fea- Package­ Managers das Paket Microsoft.ML in der letz- ten vorliegenden Version zu installieren (Install-Package Microsoft.ML). Die Bibliothek unterstützt ausschließ- Listing 2 lich Programme auf 64-Bit-Architektur-Basis, weshalb es notwendig ist, die Zielplattform in den Projekteigen- public static async Task> schaften auf x64 festzulegen. Um ein strukturiertes Ein- Train() { string _datapath = Path.Combine( Environment.CurrentDirectory, "Data", "house-prices-train.csv"); Listing 1 public class House var pipeline = new LearningPipeline { { [Column("0", name: "Label")] new TextLoader(_datapath).CreateFrom public float Price; (useHeader: true, separator: ','), new CategoricalOneHotVectorizer( [Column("1")] "Brick"), public float SqFt; new ColumnConcatenator( "Features", [Column("2")] "SqFt", public float Bedrooms; "Bedrooms", "Bathrooms", [Column("3")] "Offers", public float Bathrooms; "Brick"), new Microsoft.ML.Legacy.Trainers.FastTreeTweedieRegressor() [Column("4")] }; public float Offers; PredictionModel model = [Column("5")] pipeline.Train(); public bool Brick; } string _modelpath = Path.Combine( Environment.CurrentDirectory, "Data", "Model.zip"); public class HousePricePrediction { await model.WriteAsync(_modelpath); [ColumnName("Score")] public float Price; return model; } }

www.basta.net 37 DOSSIER .NET Framework & C#

tures erfordert, muss das Boolean-Feld Brick mittels des sage nun funktioniert. Um das herauszufinden, wird CategoricalOneHotVectorizer zunächst transformiert ein Gegentest mit Testdaten durchgeführt. Für das Er- werden. Die Transformationsklasse ColumnConcatena- mitteln dieser Daten existieren verschiedene Herange- tor dient zur Vorbereitung der Daten und überführt die hensweisen. Im einfachsten Fall wird der vorliegende Werte aller angegebenen Spalten in das Feld Features. Datensatz nach dem 80/20-Prinzip aufgeteilt – 80 Pro- Für das Training des Models kommt ein sehr effizienter, zent Trainingsdaten und 20 Prozent Testdaten. Bei der entscheidungsbaumbasierter Algorithmus zum Einsatz, Extraktion der Evaluierungsdaten sollte darauf geachtet dessen Implementierung sich in der Klasse FastTree­ werden, sie nach dem Zufallsprinzip auszuwählen, um TweedieRegressor befindet. Alternativ ließe sich auch das Bilden falscher Korrelationen durch aufeinander- die Implementierung der Klasse FastTreeRegressor ver- folgende Datenreihen zu vermeiden. Um das Modell zu wenden. Während der Tests hat sich jedoch der Fast- verifizieren, wird zunächst die Testdatendatei mittels TreeTweedieRegressor als genauer in der Vorhersage der TextLoader-Klasse eingelesen (Listing 3). Den Rest erwiesen. Die Daten des trainierten Models werden ab- übernimmt die Evaluate-Methode des RegressionEvalu- schließend durch einen asynchronen Aufruf der Metho- ator-Objekts. Aus dem Ergebnis lassen sich verschiedene de WriteAsync in das Archiv Model.zip gespeichert. Metriken abrufen, mit der sich die Exaktheit bestimmen Nachdem jetzt ein trainiertes Model vorliegt, ist es lässt. Ein Indikator für die Exaktheit der Vorhersage natürlich interessant zu wissen, wie exakt die Vorher- ist der sogenannte Root Mean Squared Error (RMS).

Listing 3 Listing 5 private static void Evaluate(PredictionModel model) { { public override Task ProcessHttpRequestAsync string _testdatapath = Path.Combine( (HttpRequestMessage request, Environment.CurrentDirectory, "Data", "house-prices-test.csv"); CancellationToken cancellationToken) { var testData = new TextLoader(_testdatapath) request.Headers.Add("Ocp-Apim-Subscription-Key", "Your key"); .CreateFrom(useHeader: true, separator: ','); return base.ProcessHttpRequestAsync(request, cancellationToken); } var evaluator = new RegressionEvaluator(); } RegressionMetrics metrics = evaluator.Evaluate(model, testData); static void Main(string[] args) Console.WriteLine($"Rms = {metrics.Rms}"); { } ITextAnalyticsClient client = new TextAnalyticsClient(new ApiKeyServiceClientCredentials()) { Endpoint = https://westus.api.cognitive.microsoft.com Listing 4 }; public static async Task Main(string[] args) { SentimentBatchResult sentimentBatchResult = client. PredictionModel model = await Train(); SentimentAsync( new MultiLanguageBatchInput( Evaluate(model); new List() { HousePricePrediction prediction = model.Predict(new House new MultiLanguageInput("en", "0", "I had a wonderful trip to { Seattle and enjoyed seeing the Space Needle!."), SqFt = 1790, })).Result; Bedrooms = 2, Bathrooms = 2, foreach (var document in sentimentBatchResult.Documents) Offers = 2, { Brick = false Console.WriteLine($"Sentiment Score: {document.Score}"); }); }

Console.WriteLine("Predicted price: {0}.", prediction.Price); Console.ReadLine(); Console.Read(); } }

www.basta.net 38 DOSSIER .NET Framework & C#

Dieser beziffert die Differenz zwischen den Werten des ren. Das setzt natürlich ein Azure-Konto voraus, das Modes und den Werten, die auf Basis der Testdaten er- aber ebenfalls kostenlos eingerichtet werden kann. Der mittelt wurden. Je näher sich der RMS am Wert 0 be- TextAnalyticsClient bietet eine Vielzahl von Möglich- findet, desto besser ist die Leistung des Modells. Ein keiten zur Textanalyse, wie etwa die Bestimmung der Wert von 0 dürfte jedoch in einem Real-World-Szenario Sprache, das Extrahieren von Schlüsselbegriffen oder nicht zu erreichen sein. Mit einer Handvoll (optimier- eben die Bewertung der Textstimmung. Beim Instanzi- ter) Testdaten ergibt sich im hier gezeigten Beispiel eine ieren muss diesem neben dem Client-Credential-Provi- Abweichung von 343,64 – ein fast zu guter Wert. Mit der auch der Service-Endpunkt übergeben werden, der einer größeren Datenmenge, ausgewählt durch das oben ebenfalls dem Azure Portal zu entnehmen ist. Danach beschriebene Vorgehen, fällt der Wert jedoch auch be- ist der Client einsatzfähig und mittels des Methoden- deutend höher aus. aufrufs client.SentimentAsync(…)­ lässt sich eine erste Nachdem das Model nun trainiert und geprüft wurde, Sentimentation mit einem oder mehreren Texten aus- kommt der letzte Teil: die Datenvorhersage (Prediction). führen. Abschließend kann über das Ergebnis iteriert Der dafür notwendige Code ist in Listing 4 dargestellt. und das Stimmungsbild in der Konsole ausgegeben Da innerhalb der Main-Methode asynchrone Methoden- werden. aufrufe erfolgen, ist es notwendig, diese als async Task zu deklarieren. Damit das wiederum funktioniert, ist es Fazit erforderlich, in den erweiterten Build-Einstellungen des Maschine Learning ist schon jetzt nicht mehr aus unse- Projekts die Sprachversion auf C# 7.1 oder höher zu set- rem Alltag wegzudenken und wird immer schneller im- zen. Der Vorhersagecode ist relativ einfach zu verstehen. mer mehr Teile unseres Lebens erobern. Auch wenn das Der Predict-Methode wird ein Objekt vom Typ House Thema stark gehypt wird, steckt es in vielen Bereichen übergeben, welches mit Informationen zum Wohnob- immer noch in den Kinderschuhen. Ein Algorithmus, der jekt gefüllt ist, jedoch nicht den Preis enthält, da dieser Katzen auf einem Bild mit einer Wahrscheinlichkeit von über den Algorithmus ermittelt wird. Die Methode wie- 75 Prozent erkennt, ist beeindruckend, hat aber den- derum liefert ein HousePricePrediction-Objekt zurück, noch Optimierungspotential. Es ist ein bisschen wie mit über dessen Price-Eigenschaft der ermittelte Preis abge- den ersten Handys, diese stellten zwar eine Revolution rufen werden kann. dar, waren aber unhandlich und nicht wirklich prakti- kabel. Drei Jahrzehnte später trägt jeder einen leistungs- Azure Cognitive Services starken Minicomputer mit sich herum. Mit KI-Systemen Mit den Azure Cognitive Services bietet Microsoft eine ist die Wissenschaft jedoch schon jetzt an einem Punkt Reihe von APIs und SDKs an, die Entwicklern beim angekommen, an dem die Entwicklung überproportio- Erstellen intelligenter Anwendungen helfen, ohne dass nal voranschreiten wird. Auch die Integration von KI in diese spezielle KI- oder Data-Science-Kenntnisse besit- neue oder bestehende Softwarelösungen ist eine immer zen müssen. Dadurch lassen sich Anwendungen leicht häufiger aufkommende Anforderung. Als Entwickler mit kognitiven Fähigkeiten wie etwa Emotions- und Vi- muss man jedoch kein studierter Mathematiker sein, deoerkennung, Gesichtserkennung, Spracherkennung um solche Lösungen zu schaffen. Vielmehr kommt es, und Sprachverständnis ausstatten. Ein einfach zu ver- wie so häufig, darauf an, die richtigen Werkzeuge zu stehendes Beispiel stellt die Sentimentanalyse dar, bei kennen und diese optimal einzusetzen. Dank einfach zu der das Stimmungsbild eines angegebenen Textes be- verwendender Frameworks wie etwa ML.NET oder der stimmt wird. Mittels der Azure Cognitive Services lässt Cloud-Lösung Microsoft Azure Cognitive Services steht sich eine solche Anforderung mittels weniger Codezei- der Integration nichts mehr im Wege. len und ohne spezielle Vorkenntnisse realisieren. Wie auch beim vorangegangenen ML.NET-Beispiel dient eine .NET-Core-Konsolenapplikation als Projektbasis. Kevin Gerndt arbeitet als Lead Consultant im Bereich Die Cognitive Services lassen sich entweder direkt über Microsoft .NET Client und Web Technologies und hat das HTTP REST API ansprechen oder komfortabler während seiner beruflichen Laufbahn schon eine Viel- zahl an Projekten begleitet. Er gilt als Experte auf dem mit Hilfe des SDK. Hierzu ist es erforderlich, mittels Gebiet der modernen Web- und Softwarearchitektur des NuGet-Package-Manager-Kommandos Install- und ist darüber hinaus als freiberuflicher Autor tätig, sowie re- Pack­age Microsoft.Azure.CognitiveServices.Lan­guage. gelmäßig auf namhaften Konferenzen vertreten. Schwerpunkte TextAnalytics -Version 2.8.0-preview die aktuelle seiner Tätigkeit bilden die Analyse und Implementation von Ge- Preview zu installieren. Der für die Sentimentanalyse schäftsprozessen sowie das Konzipieren und Entwickeln moder- ner Softwarelösungen. notwendige Code ist in Listing 5 dargestellt. Zunächst wird ein neuer Client-Credential-Provider implemen- tiert, der von der Klasse ServiceClientCredentials abzu- leiten ist. Dieser dient lediglich dazu, den API Request durch Übermitteln des API Keys zu authentifizieren. Links & Literatur Der notwendige API Key lässt sich einfach über den Cognitive-Services-Bereich des Azure-Portals generie- [1] http://doku.iab.de/kurzber/2018/kb0418.pdf

www.basta.net 39 DOSSIER Architektur

Zehn Hausaufgaben für die Cloud-Architektur – Eine gute Softwarearchitektur setzt klare Ziele voraus Kolumne: Stropek as a Service

von Rainer Stropek 2. Scope Welchen Scope hat das Projekt, für das die Soft- Softwarearchitekturen für Cloud-Lösungen zu entwi- warearchitektur entwickelt werden soll? Was ist Teil der ckeln, ist seit Jahren fester Bestandteil meiner Arbeit. Aufgabenstellung für das vorliegende Projekt und was Ich werde von Firmen eingeladen, mit ihnen Architektu- wird im Moment bewusst ausgeklammert? Wie ist das ren für Cloud-basierende SaaS-Produkte zu entwickeln. aktuelle Projekt in eine längerfristige Produkt-Roadmap Dabei stelle ich oft fest, dass Teams wichtige Hausauf- eingegliedert? gaben vernachlässigen. Die Projektziele und -rahmen- bedingungen sind nicht klar formuliert. Man erwartet, 3. Innovation dass Cloud-Anbieter wie Microsoft oder Berater wie ich Damit der Fokus im Projekt richtig gesetzt werden kann, eine allgemeingültige Cloud-Architektur aus dem Ärmel muss klar sein, was das Innovative am zu entwickelnden zaubern, die unabhängig vom Geschäftsmodell und der SaaS-Produkt ist. Ich empfehle, die Innovation aus zwei fachlichen Domäne funktionieren. Diese Vorgehenswei- Perspektiven heraus zu beschreiben: se ist gefährlich. Sie führt zu unnötig komplexen oder Externe Perspektive: Was sind aus Kundensicht die unpassenden Architekturen. Es wäre, als würde man wichtigsten funktionalen und nichtfunktionalen Anfor- sein Haus planen, ohne vorher festgelegt zu haben, ob derungen, durch deren Lösung sich das SaaS-Angebot man einen Keller will oder wie viele Autos in der Garage von existierenden Produkten abheben wird? Ein Werk- Platz haben sollen. In dieser Ausgabe meiner Kolumne zeug, das ich persönlich in diesem Bereich gerne einset- möchte ich eine Liste von zehn Hausaufgaben zusam- ze, ist die Blue-Ocean-Strategie [3]. menfassen, die ich Teams vor einem Cloud-Architektur- Interne Perspektive: Welche internen Aspekte des Un- workshop mitgebe. Die Antworten sind die Basis, auf ternehmens werden sich durch das SaaS-Angebot funda- der eine solide Architekturentwicklung aufbauen kann. mental verändern? Betroffen sein könnten beispielsweise interne Geschäftsprozesse, die Aufbauorganisation oder 1. Vision die Unternehmensfinanzierung. Wie verändert das neue Beginnen Sie mit einer Zusammenfassung der zentralen SaaS-Angebot die Wertschöpfungskette der Firma? Ich Vision, die hinter der Cloud-basierenden SaaS-Lösung nutze bei dieser Frage gerne den Business Model Canvas steckt. Halten Sie sich dabei bewusst kurz. Idealerweise als Hilfsmittel [4]. gibt es für das Projekt bereits ein Visionsdokument [1], Hilfreich für die Qualität der Antwort auf diese Frage auf das Sie verweisen können. ist meiner Erfahrung nach eine Beschränkung auf jeweils Eine Vision, die nur in den Köpfen der Projektbetei- maximal fünf Schlüsselinnovationen. Dadurch ist man ligten existiert, ist zu wenig. Schreiben Sie sie nieder. Die gezwungen, sich auf das Wesentliche zu beschränken Vision in prägnante Worte oder Schaubilder zu fassen, und zu priorisieren. hilft, Inkonsistenzen und Unklarheiten aufzudecken. Beschreiben Sie die Einordnung des Projekts in die 4. Zielumgebung Gesamtstrategie Ihrer Organisation. Ein Werkzeug, das Ich habe in meinen Kolumnen schon oft darüber ge- ich in diesem Bereich gerne verwende, ist die Strategy schrieben, dass ein Produkt, das nur in der Cloud läuft, Map [2]. Sie erklärt die primären strategischen Ziele vielleicht sogar nur in einer bestimmten, per se nichts und ihre Zusammenhänge. Stellen Sie für das SaaS-Pro- Schlechtes ist. Man verliert vielleicht einige Kunden, die jekt dar, wie es die Zielerreichung unterstützt. auf jeden Fall eine On-Premises-Lösung suchen. Man

www.basta.net 40 DOSSIER Architektur

begibt sich auch in eine gewisse Abhängigkeit zum je- 6. Skalierung weiligen Cloud-Anbieter. Auf der anderen Seite profi- Legen Sie das Mengengerüst fest, an dem sich die Soft- tiert man aber von qualitativ hochwertigen, günstigen warearchitektur orientieren muss. Diese Frage ist spezi- PaaS- und Serverless-Diensten. ell für Start-ups schwierig zu beantworten, da sich der Die Architektur einer Cloud-Lösung wird massiv da- Markterfolg nur schwer prognostizieren lässt. Dieser von beeinflusst, ob man eine Cloud-native-Lösung ent- Aspekt beeinflusst die Architektur aber stark und daher wickeln will und auf welche Cloud-Zielumgebung man ist eine Festlegung wichtig. Hier einige Aspekte, die bei sich konzentriert. Daher müssen vor der Architekturent- der Beantwortung der Frage helfen können: wicklung insbesondere folgende Fragen geklärt werden: • Geben Sie Bandbreiten für die Anzahl an Kunden • Muss es möglich sein, die Software in Kunden- oder und Benutzer an. Es spricht nichts gegen mehrere Partnerrechenzentren (On Premises) zu installieren? Szenarien (z. B. optimistisch, realistisch, pessimis- Wenn ja, welche Anforderungen an das Zielrechen- tisch). Bei der Entwicklung der Architektur können zentrum sind realistisch? Vermeiden Sie bei der Varianten erarbeitet werden, die unterschiedlich gut Beantwortung dieser Frage technische Details (z. B. skalieren. Die endgültige Entscheidung kann dann „ein Kubernetes-Cluster wird vorausgesetzt“), da dies durch Gegenüberstellung der erwarteten Kosten je Architekturentscheidungen schon vorwegnehmen Architekturvariante und Eintrittswahrscheinlichkeit könnte. Beschreiben Sie stattdessen den beim Kunden des jeweiligen Szenarios getroffen werden. vorausgesetzten Reifegrad seiner IT-Infrastruktur • Strukturieren Sie das Mengengerüst nach Preisplänen (z. B. tiefgehende DevOps-Kenntnisse vs. kein eigenes (z. B. Kundenanzahl im Freemium-, Standard- und Team mit fundiertem IT-Wissen). Premiumplan). • Falls es eine Cloud-native-Lösung wird: Ist ein Fo- • Schätzen Sie den zeitlichen Verlauf des Mengenge- kus auf einen gewissen Cloud-Anbieter gewünscht? rüsts durch Schätzungen für Neukunden- und Ab- Erklären Sie die Gründe für die Fokussierung (z. B. wanderungsquoten (Churn Rate) ab. existierende strategische Partnerschaft). Beschreiben • Gehen Sie auf Besonderheiten im Nutzungsverhalten Sie allgemein den Unternehmensstandpunkt hinsicht- der Kunden ein (z. B. besonders hohe Last am Mo- lich Cloud Vendor Lock-in [5]. natsende, fast keine Nutzung an Wochenenden, rela- • Gibt es Einschränkungen (z. B. Region, ISO-Zer- tive stabile Nutzung tagsüber). tifizierungen, garantierte Verfügbarkeiten) für die • Schätzen Sie die Transaktionszahlen für die wichtigs- Cloud-Zielumgebung, die sich aus internen oder ex- ten Geschäftsprozesse ab. Konzentrieren Sie sich auf ternen Richtlinien (z. B. Konzernvorgaben, rechtliche die wichtigsten fünf, um sich nicht von Randthemen Bestimmungen) ergeben? ablenken zu lassen. • Wenn Sie das Mengengerüst nicht wirklich abschät- 5. Zielgruppe zen können, nennen Sie zumindest Ober- und Unter- Beschreiben Sie die Kundenzielgruppe für die SaaS-Lö- grenzen (z. B. sicher nicht mehr als … Transaktionen sung. Gehen Sie dabei insbesondere auf folgende Dinge pro Benutzer und Tag). ein:

• Beschreiben Sie die Kunden, die sie ansprechen wol- len, möglichst konkret. Meiner Erfahrung nach hilft es, wenn man konkrete Personas [6] für Kunden (bei Web-Apps und APIs in Azure: B2B-Projekten wären das Stakeholder, die den SaaS- Was gibt es Neues in Azure App Dienst nutzen oder über seine Nutzung entscheiden) entwickelt und beschreibt. Bei B2B-Lösungen gehen Service? Sie auf Merkmale typischer Kundengruppen ein (z. B. Rainer Stropek Branche, Größe, Region) und bringen konkrete Bei- (software architects/www.IT-Visions.de) spiele für potenzielle Kunden. Azure App Service ist einer der • Beschreiben Sie die wichtigsten Anwendungsfälle je Rockstars unter den Clouddiensten in Persona. Ich empfehle, dass Sie sich ein Limit von der Microsoft-Cloud. Das PaaS- und fünf Fällen setzen, damit Sie gezwungen sind, zu Serverless-Angebot bietet nahezu alles, was sich Webentwicklerteams wün- priorisieren. schen. Rainer Stropek startet seine Session mit einem • Fügen Sie quantitative Kundenmerkmale hinzu (z. B. kurzen Überblick darüber, was App Service alles bietet, Anzahl Benutzer pro Kunde, Anzahl Transaktionen damit auch Neueinsteiger wissen, warum so viele Ent- pro Kunde pro Zeiteinheit, Dauer der Nutzung der wicklerteams von dem Dienst begeistert sind. Darauf SaaS-Lösung je Benutzer pro Monat etc.). aufbauend zeigt Rainer an vielen praktischen Beispie- • Erwähnen Sie eventuell wichtige technische Ein- len, welche neuen Funktionen in den letzten Monaten schränkungen bei den Kunden (z. B. schlechte/keine zu App Service dazugekommen sind. Internetverbindung).

www.basta.net 41 DOSSIER Architektur

Beachten Sie, dass keine Aussage über das Mengenge- Manchmal ist es sogar leichter, Geld aufzutreiben als rüst keine Option ist. Irgendjemand muss eine Annahme Personal. Darauf muss in der Architekturentwicklung treffen. Eine bewusste unternehmerische Entscheidung Rücksicht genommen werden. Sind die Ressourcen ist besser als eine implizite Festlegung durch Annahmen, knapp, wird die Fertigungstiefe gering sein müssen und die das Umsetzungsteam trifft. man greift mehr auf vorhandene Services und Kompo- nenten zurück. Hat man ausreichend Leute, kann man 7. Daten es sich erlauben, mehr selbst herzustellen und dadurch Datenhaltung ist ein wichtiger Bestandteil einer Soft- auf individuelle Besonderheiten einzugehen oder Allein- warearchitektur. Während es vor einigen Jahren fast stellungsmerkmale zu entwickeln. immer auf eine relationale Datenbank hinauslief, gibt Beschreiben Sie quantitative (Anzahl) und qualitati- es heute in der Cloud eine Vielzahl an Speicherdiensten ve (vorhandenes Wissen) Aspekte des Personals, das für mit spezifischen Eigenschaften. Als Basis für die Wahl das Projekt zur Verfügung stehen wird. der richtigen Speichertechnologie sollten Sie insbesonde- re die folgenden Aspekte der Datenhaltung beschreiben: 10. Bestehende Komponenten Beschreiben Sie, welche bestehenden Komponenten • Mengengerüst für die wichtigsten Entitäten, geglie- (z. B. existierende Codebasis, vorhandene Services) in dert nach Kundentyp. der SaaS-Lösung weiterverwendet werden müssen. Ge- • Logisches Datenmodell aus fachlicher Sicht für die hen Sie auch auf Schnittstellen ein, die die SaaS-Lösung wichtigsten Entitäten. Vermeiden Sie dabei technische haben muss (z. B. System Context Diagram [8]). Ver- Details, da diese Architekturentscheidungen vorweg- meiden Sie, wie auch bei den zuvor genannten Punkten, nehmen würden. technische Details. Es geht darum, die großen Zusam- • Gehen Sie auf besondere nichtfunktionale Anforde- menhänge aufzuzeigen. Verweise auf externe Dokumen- rungen ein (z. B. garantierte maximale Zugriffszeit te, in denen Details zu den vorhandenen Komponenten bei gewissen Abfragen, Verfügbarkeitsgarantien, und notwendigen Schnittstellen zu finden sind, sind aber Datenwiederherstellung). keineswegs von Nachteil.

8. Geschäftsmodell Fazit Ich bin in früheren Ausgaben dieser Kolumne schon dar- Eine allgemeine Softwarearchitektur, die nicht für ein auf eingegangen, wie wichtig der Design-to-Cost-Ansatz spezifisches Problem entwickelt wird, ist selten beson- für Cloud-basierende SaaS-Lösungen ist. Ausgangsbasis ders nützlich. Je klarer die Vorstellungen über die zu dafür sind Preis- und Kostenvorgaben, die für das jewei- erreichenden Ziele sind, desto zielführender kann in der lige Projekt gelten. Wichtig sind insbesondere folgende Architekturentwicklung gearbeitet werden. Ich hoffe, Punkte: die oben genannten zehn Punkte helfen, Ihr nächstes SaaS-Projekt erfolgreich zu starten. • Beschreiben Sie das Preismodell (z. B. Preispläne, Mengenrabatte, Free- und Premium-Angebote). Rainer Stropek ist IT-Unternehmer, Softwareentwick- • Beschreiben Sie Zusatzprodukte und Dienstleistungen ler, Trainer, Autor und Vortragender im Microsoft-Um- rund um das SaaS-Angebot sowie deren Umsätze und feld. Er ist seit 2010 MVP für Microsoft Azure und entwickelt mit seinem Team die Zeiterfassung für die Kosten (z. B. kostenpflichtiger Support, Einführungs- Dienstleistungsprofis time cockpit. projekte, Self-Service-Portale). www.timecockpit.com • Legen Sie Kostengrenzen für Entwicklung und Be- trieb des SaaS-Produkts fest (TCO, nicht nur Infra- strukturkosten), die sich aus dem Projektbudget oder der Start-up-Finanzierung ergeben. • Wie beim Mengengerüst sollten Sie zumindest Ober- und Untergrenzen festlegen (z. B.: Wir werden nicht mehr verrechnen als …, der Standard-Preisplan wird mindestens … kosten). Links & Literatur

Ich habe in diesem Bereich gute Erfahrung damit gemacht, [1] https://en.wikipedia.org/wiki/Vision_document Customer-Lifetime-Value-(CLV-)Kalkulationen [7] für [2] https://en.wikipedia.org/wiki/Strategy_map verschiedene Szenarien durchzuführen. Sie machen mei- [3] https://en.wikipedia.org/wiki/Blue_Ocean_Strategy#Concept ner Erfahrung nach schnell klar, ob das Geschäftsmodell [4] https://en.wikipedia.org/wiki/Business_Model_Canvas im Hinblick auf Umsatz- und Kostenstruktur tragfähig ist. [5] https://en.wikipedia.org/wiki/Vendor_lock-in 9. Vorhandene Ressourcen [6] https://de.wikipedia.org/wiki/Persona_(Mensch-Computer-Interaktion) In der heutigen Zeit sind die vorhandenen personel- [7] https://en.wikipedia.org/wiki/Customer_lifetime_value len Ressourcen genauso wichtig wie die finanziellen. [8] https://en.wikipedia.org/wiki/System_context_diagram

www.basta.net 42 DOSSIER Architektur

Nachhaltige Angular-Architekturen mit Nx und Strategic Design Große Business- Apps mit Angular meistern Strategic Design bietet eine etablierte Methodik zum Schneiden großer Anwendungen in möglichst autarke Domänen. Nx erlaubt die Umsetzung dieser Domänen in einem Angular und stellt sicher, dass dabei möglichst wenig Abhängigkeiten entstehen.

von Manfred Steyer Nx [1] umsetzen lässt, einer populären und freien Erwei- terung für das Angular CLI. Angular bietet sich aufgrund seiner Struktur und des ge- botenen Leistungsumfangs für die Umsetzung von Fron- Domain-driven Design auf Metaebene tends großer Softwaresysteme an. Um solche Systeme DDD beschreibt einen Ansatz, der eine Brücke zwischen beherrschbar zu gestalten, gilt es, sie in kleine und wenig Anforderungen an komplexe Softwaresysteme auf der komplexe Module zu untergliedern; das ist soweit be- einen und einem dazu passenden Anwendungsdesign auf kannt. Die Frage, die sich hierbei jedoch immer wieder der anderen Seite schlägt. Es lässt sich in die Teildiszipli- aufdrängt, ist, nach welchen Kriterien der Modulschnitt nen Tactical Design und Strategic Design untergliedern. erfolgen soll. Außerdem gilt es festzulegen, wie diese Ersteres schlägt konkrete Denkweisen, Konzepte und Module zu implementieren sind, aber auch, wie sie un- Muster für ein objektorientiertes Design vor. Alternativ tereinander kommunizieren können. dazu existieren auch Ansätze, die die dahinterstehenden Dieser Artikel gibt eine Antwort auf beide Fragen: Um Ideen in die Welt der funktionalen Programmierung eine Vorgehensweise für den Modulschnitt aufzuzeigen, übertragen [2]. beleuchtet er zunächst Strategic Domain Design. Dabei Strategic Design beschäftigt sich hingegen mit der handelt es sich um eine Disziplin aus dem Umfeld von Untergliederung eines großen Systems in einzelne Do- Domain-driven Design (DDD). Danach werden wir be- mänen und deren Ausgestaltung. Egal, ob man die mei- trachten, wie sich eine damit gestaltete Architektur mit nungsstarke (engl. opinionated) Denkwelt von DDD

www.basta.net 43 DOSSIER Architektur

Abb. 2: Produkteigenschaften im Freigabeprozess

Abb. 1: Analyse von Abläufen zum Identifizieren von Domänen gut findet oder nicht: Einige Ideen von Strategic Design haben sich bewährt, um ein System in kleinere, mög- lichst autarke Teile zu untergliedern. Es sind genau diese Ideen, die dieser Artikel aufgreift und im Kontext von Angular darstellt. Ob die restlichen Aspekte von DDD auch Berücksichtigung finden, ist hingegen für den Ar- tikel unerheblich. Abb. 3: Context Mapping

Modularisierung mit Strategic Domain Design führt dazu, dass möglichst konkrete und somit auch Ein Ziel von Strategic Design ist es, möglichst autarke aussagekräftige Modelle entstehen. Gleichzeitig unter- (Sub-)Domänen zu identifizieren. Sie sind an einem spe- bindet dieser Ansatz, dass ein einziges Modell entsteht, zifischen Vokabular zu erkennen. Sowohl Domänen- das versucht, die gesamte Welt zu beschreiben. Solche experten als auch Entwickler müssen dieses Vokabular Modelle sind häufig unübersichtlich und mehrdeutig. rigoros verwenden. Das beugt Missverständnissen vor Außerdem weisen sie zu viele wechselseitige Abhängig- und führt dazu, dass die Anwendung den jeweiligen keiten auf, die eine Entkopplung sowie Untergliederung Fachbereich widerspiegelt. In diesem Sinn ist auch von unmöglich machen. einer allgegenwärtigen Sprache (engl. Ubiquitous Lan- Auf logischer Ebene können die einzelnen Sichten guage) die Rede. Ein weiteres Merkmal von Domänen auf das Produkt trotzdem miteinander in Verbindung ist, dass häufig eine oder wenige Gruppen von Domä- stehen. Wird das durch dieselbe ID auf beiden Seiten nenexperten primär damit interagieren. ausgedrückt, kommt man hier ohne technische Abhän- Um Domänen zu erkennen, lohnt sich ein Blick auf die gigkeiten aus. Abläufe im System. Ein E-Procurement-System, das sich Entsprechend ist jedes Modell nur innerhalb eines be- um die Beschaffung von Büromaterial kümmert, könn- stimmten Anwendungsbereichs gültig. Diesen Anwen- te bspw. die beiden in Abbildung 1 gezeigten Prozesse dungsbereich und den damit einhergehenden Rahmen unterstützen. bezeichnet DDD auch als den Bounded Context. Idea- Dabei fällt auf, dass sich die Prozessschritte Approve lerweise hat jede Domäne ihren eigenen Bounded Con- Order, Request Budget und Approve Budget vorrangig text. Wie der nächste Abschnitt jedoch zeigt, lässt sich um Organisationshierarchien und das verfügbare Bud- dieses Ziel gerade beim Einbinden von Drittsystemen get drehen. Außerdem sind hier primär Manager einge- nicht immer erreichen. bunden. Beim Prozessschritt geht es hingegen vor allem um Mitarbeiter und Produkte. Context Mapping Natürlich lässt sich argumentieren, dass Produkte Obwohl die einzelnen Domänen möglichst autark sind, bei einem E-Procurement-System omnipräsent sind. Bei müssen sie dennoch ab und an miteinander interagieren. einer genaueren Betrachtung stellt sich jedoch heraus, Im hier betrachteten Beispiel könnte eine weitere Domä- dass das Wort Produkt in einigen der hier gezeigten ne Ordering zum Versenden von Bestellungen sowohl Prozessschritte ganz unterschiedliche Dinge bezeich- auf die Domäne Catalog als auch auf ein angebundenes net. Während ein Produkt beim Auswählen im Katalog ERP-System zugreifen (Abb. 3). bspw. sehr detailreich ist, muss sich der Freigabeprozess Die Art und Weise, wie diese Domänen miteinander lediglich ein paar wenige Eckdaten merken (Abb. 2). interagieren, wird über eine Context Map festgelegt. Prin- Im Sinne der allgegenwärtigen Sprache, die innerhalb zipiell könnten sich ordering und booking die gemeinsam jeder Domäne vorherrscht, ist zwischen diesen beiden benötigten Modellelemente teilen. In diesem Fall ist je- Ausprägungen eines Produkts zu unterscheiden. Das doch darauf zu achten, dass eine Modifikation keine In-

www.basta.net 44 DOSSIER Architektur

konsistenzen auf der anderen Lösung in verschiedene Anwendungen und Libraries zu Seite mit sich bringt. Eine Do- untergliedern. Das ist natürlich nur einer von mehreren mäne könnte auch die andere möglichen Ansätzen. Als Alternative könnte man bspw. einfach verwenden. In diesem jede Domäne als komplett eigene Lösung umsetzen. Dies Fall stellt sich jedoch die Frage, entspräche dem Micro-App-Ansatz oder käme ihm zu- wem in diesem Zusammenspiel mindest sehr nahe. wie viel Macht zukommt. Kann Die Lösung untergliedert alle Anwendungen in einem der Konsument dem Anbieter Ordner apps und alle wiederverwendbaren Bibliothe- bestimmte Änderungen auf- ken finden sich nach Domänen geordnet im Ordner libs zwingen und auf Abwärtskom- (Abb. 4). patibilität pochen? Oder muss Da solch ein Workspace aus mehreren Anwendungen sich der Konsument mit dem und Bibliotheken besteht, die in einem gemeinsamen zufriedengeben, was er vom Quellcode-Repository verwaltet werden, ist auch von Abb. 4: Ordner der Um- Anbieter bekommt? einem Monorepo die Rede. Dieses Muster kommt unter setzung Im betrachteten Fall bietet anderem bei Google und Facebook sehr exzessiv zum catalog ein API an, um zu verhin- Einsatz und ist auch seit rund zwanzig Jahren der Stan- dern, dass sich Änderungen in der Domäne zwangswei- dardfall bei der Entwicklung von .NET-Lösungen in der se auf die Konsumenten auswirken. Da ordering wenig Microsoft-Welt. Einfluss auf das ERP-System hat, nutzt es einen Anti- Es erlaubt auf besonders einfache Weise das Teilen von Corruption-Layer (ACR) zum Zugriff. Ändert sich etwas Quellcode zwischen den Projektbeteiligten und beugt in im ERP-System, muss es somit nur genau diesen aktua- diesem Fall auch Versionskonflikten vor, indem es ledig- lisieren. Daneben definiert Strategic Design noch weitere lich einen zentralen node_modules-Ordner mit abhängi- Strategien für das Verhältnis zwischen Konsumenten und gen Bibliotheken gibt. Somit ist sichergestellt, dass z. B. Anbietern. jede Bibliothek dieselbe Angular-Version verwendet. Die nötigen Befehle zum Erzeugen solch eines Mono- Umsetzung mit Nx repos und zum Hinzufügen von Anwendungen und Bib- Für die Umsetzung der definierten Architektur kommt liotheken finden sich in der Dokumentation von Nx [1]. hier ein Workspace auf der Basis von Nx [1] zum Ein- satz. Dabei handelt es sich um eine Erweiterung für das Kategorisierung von Bibliotheken Angular CLI, das unter anderem dabei unterstützt, eine Den Vorschlägen der hinter diesem quelloffenen Pro- jekt stehenden Firma Nrwl folgend [3], unterteilt die betrachtete Lösung die einzelnen Bibliotheken in die fol- Listing 1 genden Kategorien:

"nx-enforce-module-boundaries": [ • feature: implementiert einen Use Case true, • data-access: implementiert Datenzugriffe, z. B. via { "allow": [], "depConstraints": [ { "sourceTag": "scope:app", "onlyDependOnLibsWithTags": ["type:shell"] }, { "sourceTag": "scope:catalog", "onlyDependOnLibsWithTags": Angular-Workshop: ["scope:catalog", "scope:shared"] }, { "sourceTag": "scope:shared", "onlyDependOnLibsWithTags": strukturierte Einführung ["scope:shared"] }, Manfred Steyer (SOFTWAREarchitekt.at) { "sourceTag": "scope:booking", "onlyDependOnLibsWithTags": Erfahren Sie in diesem Workshop, ["scope:booking", "scope:shared", "name:catalog-api"] }, welche Building-Blocks Angular für Ihre erfolgreichen Projekte bietet. Lernen { "sourceTag": "type:shell", "onlyDependOnLibsWithTags": Sie dabei, wie Sie aus .NET bekannte ["type:feature", "type:util"] }, Konzepte wie Komponenten, Datenbin- { "sourceTag": "type:feature", "onlyDependOnLibsWithTags": dung und Dependency Injection mit Angular umsetzen ["type:data-access", "type:util"] }, und wie Sie dank TypeScript Klassen sowie statische { "sourceTag": "type:api", "onlyDependOnLibsWithTags": Typisierung nutzen können. Ihr Workshoptrainer ["type:data-access", "type:util"] }, Manfred Steyer ist Entwickler und Berater mit Fokus { "sourceTag": "type:util", "onlyDependOnLibsWithTags": auf Angular-Entwicklung. Er berät Firmen im gesamten ["type:util"] } deutschen Sprachraum, ist Autor zahlreicher Bücher, ] Sprecher auf einschlägigen Fachkonferenzen und Google Developer Expert sowie Microsoft MVP. } ]

www.basta.net 45 DOSSIER Architektur

Abb. 5: Abhängigkeiten zwischen Bibliotheken

HTTP oder WebSockets DDD beinhalten. • ui: bietet Use-Case-agnostische und somit wiederver- Zur Wahrung der Übersicht werden die Kategorien wendbare Komponenten als Präfix für die einzelnen Bibliotheksordner verwen- • util: bietet Hilfsfunktionen det. Somit werden in einer sortierten Übersicht auch Bibliotheken derselben Kategorie nebeneinander prä- Der Autor erweitert diese Kategorien um die folgenden: sentiert. Jede Bibliothek hat außerdem ein öffentliches API (Lis- • shell: bietet bei einer Anwendung, die mehrere Domä- ting 1), über das es einzelne Bestandteile veröffentlicht: nen umsetzt, den Einsprungpunkt für eine Domäne • api: bietet Funktionalitäten für andere Domänen export * from ‘./lib/catalog-data-access.module’; • domain: Domänenlogik (hier nicht verwendet) export * from ‘./lib/catalog-repository.service’;

Falls die Geschäftslogik auch teilweise am Client statt- Alle anderen Bestandteile verbergen sie hingegen; diese findet, würden Domainbibliotheken z. B. im Sinne von lassen sich somit beliebig verändern. Functional Domain Modelling [2] neben Entitäten und Repositories zum Datenzugriff auch Services für Berech- Zugriffe auf Bibliotheken kontrollieren nungen sowie weitere Building-Blocks aus der Welt von Zur Verbesserung der Wartbarkeit gilt es, die Abhän-

Listing 2 "projects": { "catalog-feature-browse-products": { "ui": { "tags": ["scope:catalog", "type:feature"] "tags": ["scope:app"] }, }, "catalog-api": { "ui-e2e": { "tags": ["scope:catalog", "type:api", "name:catalog-api"] "tags": ["scope:e2e"] }, }, "catalog-data-access": { "catalog-shell": { "tags": ["scope:catalog", "type:data-access"] "tags": ["scope:catalog", "type:shell"] }, }, "shared-util-auth": { "catalog-feature-request-product": { "tags": ["scope:shared", "type:util"] "tags": ["scope:catalog", "type:feature"] } }, }

www.basta.net 46 DOSSIER Architektur

gigkeiten zwischen den einzelnen Bibliotheken zu mi- des Tippens an. In letzterem Fall ist ein entsprechendes nimieren. Das Erreichen dieses Ziels lässt sich mit Nx Plug-in zu installieren. zunächst mal auf grafische Weise prüfen (Abb. 5). Im hier betrachteten Fall wurden ein paar Regeln Fazit bei der Kommunikation zwischen Bibliotheken einge- Strategic Design bietet eine bewährte Vorgehensweise, halten und diese führen zu einer konsequenten Schich- um eine Anwendung in möglichst autarke Domänen zu tentrennung. Beispielweise darf jede Bibliothek nur unterteilen. Diese Domänen zeichnen sich durch ein ei- auf Bibliotheken derselben Domäne oder auf Biblio- genes Fachvokabular aus, das rigoros von allen Beteilig- theken aus dem Bereich shared zugreifen. Der Zugriff ten zu nutzen ist. auf APIs wie das catalog-api muss einzelnen Domänen Die CLI-Erweiterung Nx bietet eine sehr charmante explizit gewährt werden. Möglichkeit zur Umsetzung dieser Domänen mit unter- Auch aus der Kategorisierung der Bibliotheken er- schiedlichen, nach Domänen gruppierten Bibliotheken. geben sich Einschränkungen: Eine Shell greift nur auf Um den Zugriff durch andere Domänen zu beschränken Features zu und ein Feature wiederum nur auf Data- und zur Verminderung der Abhängigkeiten im Sinne ei- Access-Bibliotheken. Daneben darf aber jeder auf Utils ner Schichtentrennung, erlaubt es das Festlegen von Ein- zugreifen. Um solche Einschränkungen zu erzwingen, schränkungen für den Zugriff auf einzelne Bibliotheken. kommt Nx mit eigenen Linting Rules (Listing 1). Es lässt sich natürlich argumentieren, dass ein Angu- Entsprechend einem Vorschlag aus der Veröffentli- lar-Client nicht zwangsweise Domänenlogik beinhaltet. chung „Enterprise Angular Monorepo Patterns“ von Fakt ist aber, dass gerade bei Single-Page-Applikationen Nrwl [3] werden die Domänen hier mit dem Präfix immer mehr Logik auch am Client zu finden ist. Unab- scope und die Bibliotheksarten mit dem Präfix kind hängig davon haben sich gerade die Ideen von Strategic versehen. Präfixe dieser Art sollen lediglich die Lesbar- Design in diesem Umfeld als äußerst nützlich erwiesen, keit erhöhen und lassen sich frei vergeben. Außerdem um einen guten Schnitt zu erreichen. zeigt dieses Beispiel auch die Domäne Booking, die entsprechend des Context Mappings Zugriff auf das CatalogApi erhält. Manfred Steyer unterstützt als Trainer und Berater Soft- Die Zuordnung zwischen den Projekten und den hier wareteams im gesamten deutschen Sprachraum bei der gezeigten Bibliotheksarten sowie Domänen findet in der Entwicklung mit Angular. Er wurde als Google Developer Expert ausgezeichnet und schreibt für O’Reilly, das deut- Datei nx.json statt (Listing 2). sche Java Magazin und Heise Developer. In seinem ak- Alternativ dazu lassen sich diese Tags auch beim Ein- tuellen Buch zu Angular behandelt er die vielen Seiten des richten der Applikationen und Bibliotheken angeben. populären JavaScript Frameworks aus der Feder von Google. Um gegen diese Regeln zu prüfen, reicht ein Aufruf www.softwarearchitekt.at von ng lint auf der Kommandozeile. Entwicklungsumge- bungen wie WebStorm/IntelliJ oder Visual Studio Code zeigen solche Regelverletzungen auch schon während

Nachhaltige Webarchi- tekturen mit Micro Apps und Angular Manfred Steyer (SOFTWAREarchi- tekt.at) Der Monolith hat ausgedient – kleine, wartbare Micro- services sind im Trend! Aber wie setzt man diese Idee in der Welt von Single Page Applications und Angular um? In dieser Session betrachten wir verschiedene Ansätze und bewerten ihre Vor- und Nachteile. Wir untersuchen verschiedene Realisierungsoptionen wie z. B. den Einsatz von Web Components und diskutie- ren Lösungen für Herausforderungen wie App-über- greifende Security, Routing, Kommunikation zwischen Links & Literatur Micro Apps und das Bereitstellen optimierter Bundles. Am Ende wissen Sie, ob sich Micro Apps für Ihr Vor- haben überhaupt lohnen und welche Ansätze sich für [1 https://nx.dev Ihren konkreten Fall anbieten. [2] https://pragprog.com/book/swdddf/domain-modeling-made-functional [3] https://go.nrwl.io/angular-enterprise-monorepo-patterns-new-book

www.basta.net 47 DOSSIER Sicherheit

API Authorization in ASP.NET Core 3.0 mit IdentityServer Du kommst hier nicht rein Manche Dinge sind, zumindest gefühlt, unnötig aufwändig, kompliziert oder beides. Aktuell ist die Absicherung eines ASP.NET Core Web API leider auch noch eins die- ser Themen. Noch – denn es ist Besserung in Sicht.

von Sebastian Gingter das Benutzersystem revolutioniert und heißt seitdem ASP.NET Identity. Seit damals hat sich im .NET-Umfeld Als Softwareentwickler, die die Plattform „Web“ bedie- viel getan: Wir bewegen uns auf .NET 4.8 zu und ha- nen, haben wir es in aller Regel mit einem von zwei Fäl- ben parallel das neue ASP.NET Core an der Hand, das len zu tun: Wir bauen entweder eine Webanwendung, uns ein viel moderneres Entwickeln für alle erdenklichen die für die gesamte Öffentlichkeit uneingeschränkt zur Plattformen ermöglicht. Verfügung steht, oder wir arbeiten an einer Anwendung, Umso erstaunlicher erscheint es, dass wir zwar mit die irgendeine Art von Zugangskontrolle in Form einer klassischen WebForms, ASP.NET MVC mit Razor Anmeldung eines Benutzers benötigt. Sei es ein einfacher Templates und auch den neuen Razor Pages das Identi- Blog mit Kommentarfunktion, ein Webshop, bei dem ty-System verwenden können, wir aber bis heute keine wir den Kunden kennen wollen, oder auch eine interne eingebaute Möglichkeit haben, es auch aus ASP.NET Businessanwendung, bei der wir den Benutzer zur Be- MVC Web API oder den API-Controllern in ASP.NET rechtigungssteuerung identifizieren müssen. MVC Core zu verwenden. Doch warum ist das so? Serverseitig gerenderte Webanwendungen basieren Von der Anmeldung an Webanwendungen … darauf, dass ein Webbrowser eine Webseite anfragt und Für serverseitig gerenderte Webapplikationen mit ASP. nach einer Benutzeraktion entweder eine weitere, andere NET (Core) MVC bringt uns das ASP.NET Framework Seite angefragt oder für die aktuelle Seite Formulardaten alles dafür Notwendige schon von Haus aus mit, und an den Server per POST gesendet werden. All das pas- zwar schon seit der allerersten Version: Bereits mit der siert immer aus dem Browser heraus. Wir können hier- einfachen Forms Authentication in ASP.NET 1.x und et- für also problemlos Cookies für die Anmeldung und die was später dann mit dem Membership Provider in ASP. Sessionverwaltung verwenden. ASP.NET Identity setzt NET 2.x waren die Mittel, um Benutzer zu verwalten, daher bei MVC (Core) und Razor Pages genau hierauf sie zu authentifizieren und dann zu autorisieren, direkt auf und realisiert die Authentication mit Cookies, die an Bord. Mit der Einführung von OWIN und damit ASP.NET Identity für uns ausstellt, und die der Browser Middlewares mit .NET 4.5.1 im Jahr 2013 wurde auch für uns handhabt.

www.basta.net 48 DOSSIER Sicherheit

… zur Authentifizierung bei API-Endpunkten Benutzer seines API problemlos gegen die Authorization- Bei API-Endpunkten sieht das anders aus: Diese müssen Server von Facebook oder authentifizieren lassen. nicht unbedingt von einem Browser angesprochen wer- Auch Google und Microsoft bieten OAuth-2.0-Authoriza- den, der sich vorher einen solchen Cookie geholt hat. tion-Server an, sodass man sich mit seiner Gmail-Adresse Es können natürlich moderne, rein browserseitige Web- oder seinem Microsoft-Account anmelden kann. Daneben anwendungen wie Single Page Applications (SPAs) sein, gibt es auch eher technische Anbieter wie GitHub, an die aber es können genauso gut mobile iOS- oder Android- man sein API hängen kann. Anwendungen, Windows-Dienste bzw. Linux Daemons Doch der Clientteil ist natürlich nur die halbe Mie- oder gar klassische Desktopanwendungen sein, die mit te: Bis heute muss man sich nach externen Lösungen unserem API arbeiten wollen und dazu einen authenti- umschauen, wenn man einen Authorization-Server mit fizierten Zugriff benötigen. Alle diese unterschiedlichen eigener Benutzerhaltung bereitstellen will oder muss. Szenarien haben dabei andere Anforderungen. Cookies Auch hier kann man sich natürlich einen Authorizati- würden hier nur bedingt helfen. Und da wir Authentifi- on-Server als Software as a Service anmieten, wie zum zierung ja auch nicht einfach nur machen, damit wir so Beispiel von Auth0 (Auth Zero) [1], aber wenn man in etwa wissen, wer da gerade mit unserem API spricht, eine anpassbarere Lösung benötigt oder seine Benut- sondern hier auch, je nach Anwendungsfall, Berechti- zerdaten nicht einem fremden Unternehmen überlas- gungen daran hängen und wir uns auf diese Information sen möchte, muss man aktuell leider noch selbst Hand verlassen können müssen, bewegen wir uns damit auto- anlegen. Im .NET-Umfeld hat sich hierfür das Open- matisch auch im Bereich Security, und damit haben diese Source-Projekt IdentityServer4 [2] von Dominick Baier unterschiedlichen Szenarien leider auch unterschiedliche und Brock Allen bewährt: Er wird vielfach für die Au- und vielfältige Angriffsmöglichkeiten. thentifizierung von eigenen Benutzern gegenüber einem Dankenswerterweise haben sich deswegen schon vor API eingesetzt. Jahren einige Leute bei der IETF (Internet Engineering Task Force) intensive Gedanken darüber gemacht und Eine unerfreulich große Menge an Arbeit – oder? uns OAuth als Standard vorgeschlagen, der 2006 ver- Doch auch wenn wir hier nun eine Open-Source-Lö- öffentlicht wurde. Dieser Standard hat sich dann auch sung für einen Authorization-Server an der Hand ha- durchgesetzt und wurde 2012 mit der neuen Versi- ben, die das OpenID-Connect-Protokoll und damit auch on OAuth 2.0 überarbeitet. Zwei Jahre später hat die O­Auth 2.0 beherrscht, so ist der IdentityServer dennoch OpenID Foundation dann auf OAuth 2.0 aufsetzend leider keine Komplettlösung, die man einfach installie- noch OpenID Connect als Protokoll bereitgestellt, das ren und sofort nutzen kann. Selbst wenn man „nur mal es erlaubt, mehr Informationen rund um die Identität schnell“ einen Authorization-Server zu Testzwecken des Benutzers zu erhalten. Also genau das, was wir als bereitstellen will, muss man erst einmal eine Konfigura- Entwickler für unser API benötigen. tion für seine Clientanwendung und das abzusichernde API bereitstellen. Dafür muss man sich dann allerdings OAuth 2.0 und OpenID Connect schon intensiver mit der Funktionsweise des IdentitySer- Zwischen Cookie- und OAuth-basierter Authentifizierung vers auseinandersetzen, damit man auch eine korrekte gibt es einige Unterschiede. Uns interessieren hierbei aber Konfiguration für seinen Anwendungszweck erstellen erst einmal nur die beiden auffälligsten: Erstens geschieht kann. Wenn man diese dann nicht hartcodieren möch- die Anmeldung bei OAuth meist nicht auf dem Webser- te, schreibt man extra Code, um die Konfiguration ent- ver, auf dem auch das API liegt. Stattdessen meldet sich weder aus Dateien oder aus einer Datenbank zu laden. der User bei einem sogenannten Authentication Server an, Für den zweiten Fall gibt es zwar schon eine Bibliothek der der Clientanwendung dann einen Token als Anmel- auf NuGet mit dem passenden Entity-Framework-(EF-) deinformation ausstellt. Diese Tokens können einfache, Datenmodell (das Paket IdentityServer4.EntityFrame- zufällige Strings sein, oder auch sogenannte JSON Web work), aber selbst dann müssen noch die dazu passen- Tokens (JWT), die Informationen in einer definierten den Migrationen erstellt und ausgeführt werden. Das JSON-Datenstruktur beinhalten. Unser API vertraut dem Gleiche gilt auch für die Testbenutzer: Entweder man Authentication-Server und akzeptiert die von ihm ausge- gibt sich mit den festen Testbenutzerkonten „Alice“ und stellten Tokens. Der zweite auffällige Unterschied besteht „Bob“ aus den Beispielen zufrieden, oder man muss wie- darin, dass diese Tokens über einen HTTP-Header von der Hand anlegen und das, was man schon für die Kon- der Clientanwendung an unser API übertragen werden, figurationsdaten gemacht hat, auch noch einmal für die und eben nicht mehr in einem Cookie. Benutzerdaten machen. Aber auch hier muss man sich Die eigenen Endpunkte mit OAuth 2.0 bzw. OpenID selbst um die notwendigen Migrationen und die Kon- Connect abzusichern, ist heutzutage der bevorzugte Weg figuration kümmern, wenn man den existieren Adapter für API-Entwickler, und auch in ASP.NET gibt es schon für ASP.NET Identity nutzt (das Paket IdentityServer4. seit gefühlten Ewigkeiten die Clientbibliotheken, um unse- AspNetIdentity). Damit die Benutzer dann auch irgend- re APIs über einen externen Authorization-Server mittels wo ihre Anmeldedaten eingeben können, benötigen wir Tokens abzusichern. Als externe Dienste dienen hier gerne noch die nötigen Eingabeformulare. Zwar bringt der die bekannteren sozialen Netzwerke, und so kann man die IdentityServer in seinen Beispielprojekten auch ein Boot-

www.basta.net 49 DOSSIER Sicherheit

strap-basiertes UI mit, aber auch das muss erst einmal in API Authorization kommt in ASP.NET Core 3.0 das eigene Projekt installiert und eingerichtet werden. Da ASP.NET Core 3.0 erst für die zweite Jahreshälfte Alles in allem ist das leider eine unerfreulich große 2019 angekündigt ist [4], müssen wir uns noch etwas Menge an Arbeit, die da vor uns liegt. Dazu kommt gedulden, bis das Feature wirklich bei uns ankommt. Je- noch der Lernaufwand über die OAuth-Konzepte und doch ist eine erste, beispielhafte Implementierung schon das Konfigurations-API des IdentityServers. Das ist un- heute im ASP.NET Core Repository auf GitHub ver- angemessen viel, insbesondere, wenn man doch eigent- fügbar [5]. An dieser Stelle ist anzumerken, dass es sich lich „nur mal schnell“ einen Authentication-Server für derzeit um einen Stand handelt, an dem noch entwickelt Testzwecke benötigt. Wenn man dann bedenkt, wie wird und der aktuell nur als Preview zur Verfügung einfach es im Gegenzug ist, eine Authentifizierung für steht. Wir dürfen bis zur Veröffentlichung also noch mit eine MVC- oder Razor-Pages-Anwendung zu realisie- Änderungen rechnen. Dennoch lohnt es sich, schon jetzt ren, erscheint das Thema API-Authentifizierung unge- einen genaueren Blick auf das zu werfen, was uns Mi- lenk, sehr kompliziert und über die Maßen aufwändig. crosoft hier an Automatismen liefern möchte. Das muss es aber nicht sein, und zum Glück ist das Die Integration verbindet ASP.NET Identity mit dem ASP.NET-Identity-Team bei Microsoft auch zu dieser IdentityServer ausschließlich mit .NET-(Core-)Hausmit- Ansicht gekommen: Es hat bereits damit begonnen, die teln, daher setzt das Identity-Team hier auf das Entity Situation zu verbessern. So hat Barry Dorrans, der bei Framework, um notwendige Daten in der Datenbank Microsoft im (ASP).NET-Team im Securitybereich ar- abzulegen. Im Code müssen wir daher zuerst in der beitet, angekündigt, dass es mit ASP.NET Core 3.0 ein Startup.cs unseres Projekts in der Methode Configu- eingebautes API-Authorization-Feature geben wird [3]. reServices() den entsprechenden Datenbankkontext Microsoft baut dafür keinen eigenen Authorization- konfigurieren und in die verfügbaren Services unseres Server, sondern setzt auch auf den IdentityServer4 auf. Projekts eintragen: Wie bereits erwähnt, muss dieser jedoch konfiguriert werden, und wenn man diese Konfiguration selbst er- services.AddDbContext(options => stellt, muss man die Konzepte von OAuth bzw. Ope- options.UseSqlite(Configuration.GetConnectionString(“DefaultConnecti nID Connect kennen und dazu wissen, wie sie auf die on”))); Einstellungen des IdentityServers zu übertragen sind. Damit wir uns nicht damit aufhalten müssen, versucht Der ApplicationDbContext, den uns Microsoft hier das ASP.NET-Identity-Team, uns möglichst viel Arbeit mitliefert, leitet von dem neuen ApiAuthorizationDb- und (Lern-)Aufwand abzunehmen. Context ab, der selbst wiederum vom IdentityDbCon- text ableitet, und uns damit auch sofort Zugriff auf die bereits bekannte ASP.NET-Identity-Datenstruktur gibt. Zusätzlich implementiert der ApiAuthorizationDbCon- text auch ein Interface des IdentityServers, über das die- ser seine Bewegungsdaten persistiert. Wir kommen also Advanced ASP.NET Core Web mit einem einzigen Datenbankkontext aus und müssen APIs: testen und dokumentieren – auch nur für diesen einen Kontext Migrationen verwal- aber richtig! ten. Im zweiten Schritt müssen wir das normale ASP. NET-Identity-System konfigurieren: Sebastian Gingter (Thinktecture AG)

Jeder baut Web-APIs, oder? Leider ist es services.AddDefaultIdentity() nicht damit getan, ein neues Projekt zu .AddEntityFrameworkStores(); erzeugen, ein paar Controller zu imple- mentieren und dann sein Web-API zu deployen. Zum einen sollte es vernünftig Hiermit tragen wir die Identity Services in die ­Dependency dokumentiert werden, damit die Entwickler, die mit un- Injection (DI) unseres Projekts ein und sagen ihnen, dass serem API arbeiten müssen, auch wissen, was es kann sie den oben bereitgestellten ApplicationDbContext für und wie es funktioniert. Zum anderen sollten wir selber die Persistenz unserer Benutzer nutzen sollen. Bis auf die auch sicherstellen, dass unser API das tut, was es soll. In Verwendung des erweiterten Identity-Kontexts sind dies dieser Session zeigt Ihnen Sebastian Gingter, wie man nur die Schritte, die man auch für die normale Konfigu- diese beiden Fliegen mit einer Klappe schlagen kann. ration von ASP.NET Identity vornehmen müsste. Im drit- Mit Hilfe von Open API/Swagger erzeugen wir erst eine umfassende, ständig aktuelle und lebendige Dokumen- ten Schritt fügen wir unserem Projekt den eigentlichen tation unseres APIs. Im zweiten Schritt generieren wir IdentityServer­ hinzu: aus dieser Dokumentation auch gleich Tests für das API- Test-Tool Postman, die wir dann mit etwas JavaScript services.AddIdentityServer() Testcode anreichern und diese sogar als automatisierte .AddApiAuthorization(); Integrationstests laufen lassen können. Web-APIs jen- seits von Hello World, mit viel Projekterfahrung. Dies führt zuerst die normale Eintragung aller Typen des IdentityServers in die DI durch. In der Methode

www.basta.net 50 DOSSIER Sicherheit

Add­ApiAuthorization() geschieht nun die eigentli- seinen eigenen URL konfiguriert wird, dieser hier aber che Integrationsmagie des ASP.NET-Identity-Teams. nicht angegeben wird. Daher werden hier Klassen, die Anstatt hier, wie es bei der normalen Nutzung des für das URL-Handling im IdentityServer verwendet IdentityServers der Fall wäre, die Konfiguration zu werden, ausgetauscht. Und zwar gegen Implementie- übergeben, wird sie im Hintergrund für uns und unser rungen, die die absoluten und relativen URLs zu dem API erstellt und vollautomatisch bereitgestellt. Wir ge- API und damit auch zum IdentityServer im gleichen hen hier später noch auf die Details ein, aber für jetzt Projekt, selbst automatisch ermitteln können. soll es genügen, dass durch die Angabe der Typen für Als Nächstes werden einige Standard-Identity- das Nutzerobjekt und den Datenbankkontext auch der Ressourcen registriert und danach das eigene API als IdentityServer so konfiguriert wird, dass er unseren sogenannte API-Ressource. Hier wird für das lokale Kontext sowohl für die Authentifizierung der Nutzer API in diesem Projekt eine Ressource angelegt, die ei- als auch für die Ablage seiner eigenen Daten verwen- nen Zugriff von allen Clients erlaubt, die später noch den soll. Hiermit wurde der IdentityServer konfigu- registriert werden. Diese werden dann im nächsten riert, und nun muss er noch als Middleware registriert Schritt generiert, wobei aktuell in der appsettings.json werden. Dazu müssen wir noch vor dem Aufruf von der Name der Clients und ein sogenanntes Profil konfi- UseMvc() in der Configure()-Methode unserer Startup- guriert werden müssen. In dem offiziellen Beispielpro- Klasse eintragen: jekt [6] wird hier folgende Konfiguration verwendet:

app.UseIdentityServer(); “IdentityServer”: { “Clients”: { Bis hierhin haben wir nun den IdentityServer konfigu- “ApiAuthSampleSPA”: { riert, und unser API-Projekt ist nun gleichzeitig auch “Profile”: “IdentityServerSPA” ein Authorization-Server im Sinne von OAuth 2.0. Un- } sere API-Endpunkte, also unsere Action-Methoden auf } unseren Controller-Klassen, können mit den Tokens, } die unser Server ausstellt, aber noch nichts anfangen. Hiermit wird lediglich gesagt, dass es einen Client na- Dafür fehlt noch der letzte Schritt, in dem wir unserem mens ApiAuthSampleSPA gibt, und dieser mit dem API sagen, dass es überhaupt Authentication beherr- Profil IdentityServerSPA generiert werden soll. Derzeit schen soll und unsere Tokens akzeptiert. Hierfür fügen existiert noch keine Dokumentation, welche Profile es wir noch folgende Zeilen in unsere ConfigureServices()- final geben wird und wie diese sich im Detail unterschei- Methode ein: den. Für das IdentityServerSPA-Profil wird derzeit ein Client generiert, der auf dem URL des aktuellen Servers services.AddAuthentication() ansprechbar ist. Der Name des Clients in der Konfigura- .AddIdentityServerJwt(); tion ist wichtig, denn die Anwendung, die das API ver- wenden will, muss ihre Autorisierungsanfragen an den Danach kann ASP.NET MVC die Tokens, die unser IdentityServer mit diesem Namen als ClientId stellen. frisch konfigurierter IdentityServer, der nun auch in un- Damit weiß der IdentityServer, welche Clientkonfigu- serem Projekt verfügbar ist, akzeptieren. Normalerweise ration er zu verwenden hat. Aktuell sieht das Feature müssten wir die Authentication explizit auf die passen- Profile für eine externe SPA vor, die nicht vom URL de Ressource eines spezifischen Authorization-Servers des API-Servers kommt, eben die verwendete Identity- konfigurieren, aber auch das wird uns netterweise vom Identity-Team in der AddIdentityServerJwt()-Methode abgenommen.

Hinter den Kulissen Das ASP.NET-Identity-Team hat sich wirklich viel Sicherheit in ASP.NET Core 2.2 Mühe gegeben, die Komplexität der IdentitySer- und 3.0 ver-Konfiguration hinter diesen zwei einfachen Ex- Dominick Baier tension-Methoden zu verstecken. Die erste für den (Unabhängiger Sicherheitsberater) IdentityServer relevante, also AddApiAuthorization(), nutzt zuerst die schon vom IdentityServer bereitgestell- ASP.NET Core ist in der aktuellen Version eine stabile und ausgereifte ten Funktionalitäten, die Benutzerhaltung von ASP. Plattform für Webanwendungen und NET Identity zu verwenden und die eigenen Daten, APIs. Dieser Vortrag gibt einen Über- zum Beispiel für ausgestellte Tokens, aus dem gleichen blick über die heutigen und zukünftigen Datenbankkontext zu verwenden. Danach werden ein Securityfeatures von ASP.NET Core. Dies soll Ihnen paar der vom IdentityServer in der DI registrierten die Evaluierung von ASP.NET Core aus Sicherheits- Klassen durch eigene Varianten ersetzt. Der Hinter- sicht erleichtern. grund ist, dass der IdentityServer normalerweise auf

www.basta.net 51 DOSSIER Sicherheit

Der Name des Clients in der Konfiguration ist wich- tig, denn die Anwendung, die das API verwenden will, muss ihre Autorisierungsanfragen­ an den Iden- tityServer mit diesem Namen als ClientId stellen.

ServerSPA, die vom gleichen URL kommt, und Nati- filen, und als Datenablage wird Entity Framework mit veApp für eine Mobile- oder eine Desktopanwendung. ASP.NET Identity für die Nutzerhaltung verwendet. Offenbar auch vorgesehen, aber aktuell (noch?) aus- Weichen die eigenen Anforderungen von diesem Sze- kommentiert, ist ein Profil für eine Server-rendered nario ab, wenn auch nur leicht, hilft uns diese neue, di- MVC-Webanwendung mit dem Namen WebApplica- rekt in ASP.NET Identity eingebaute Integration schon tion. nicht mehr weiter. In diesem Fall ist es leider notwen- Zuletzt werden noch die sogenannten Signing dig, den IdentityServer in seiner normalen Form zu ver- Credentials konfiguriert, also das kryptografische öf- wenden und all die genannten Schritte doch selbst zu fentliche und private Schlüsselpaar, mit dem der Iden- machen. Trotz allem: Es ist wunderbar, dass man bald tityServer die Tokens, die er ausstellt, auch signiert. in der Lage sein wird, so einfach zu starten, und die Zur Entwicklungszeit wird beim ersten Start ein neues Art, wie das Microsoft-Team die Konfiguration gelöst Paar automatisch generiert und dann verwendet, zur hat, kann einem dank ihrer Open-Source-Natur als In- Laufzeit in der Releasekonfiguration muss hier in der spiration dienen, wie man es dann später selbst elegant appsettings.json entweder ein x509-Zertifikat aus einer lösen könnte. Datei oder aus dem betriebssystemeigenen Zertifikats- speicher angegeben werden. Dort, wo die IdentityServer-JWT-Authentifizierung Moderne Softwarearchitektur sowie leichtgewichtige hinzugefügt wird, wird auch wieder auf die automatisch und performante Anwendungen, primär mit .NET Core generierten URL-Handler zurückgegriffen und der so- auf dem Server sind die Themen, die Sebastian Gingter als Software Architect und Consultant bei der Think- eben konfigurierte lokale IdentityServer als sogenannte tecture AG vorantreibt. Sein Wissen gibt er auch gerne Authority, also zulässige Quelle für Tokens, eingetra- in Artikeln und auf Konferenzen weiter. gen. Ab diesem Zeitpunkt kann der Standard-Authenti- cation-Handler für JW-Tokens, den es auch schon seit https://gingter.org @PhoenixHawk der ersten ASP.NET-Core-Version gibt, seine Aufgabe ganz regulär erledigen. Damit ist die Konfiguration des IdentityServers und unserer API-Authentifizierung abge- schlossen. Was noch fehlen würde, wäre die Clientsei- te, also die Single Page Application, die nun gegen den IdentityServer authentifiziert und dann mit dem für sie ausgestellten Token unser API aufruft. In dem Beispiel- projekt des ASP.NET-Teams ist dieser allerdings auch enthalten.

Fazit Wer schon einmal intensiver mit dem IdentityServer ge- arbeitet hat, wird zu schätzen wissen, welchen initialen Konfigurationsaufwand man sich mit diesen wenigen Zeilen sparen kann, wenn diese ApiAuthorization- Integration mit ASP.NET Core 3.0 veröffentlich wird. Links & Literatur Dieses neue Feature macht es erstaunlich einfach, einen IdentityServer für Entwicklungs- und Testzwecke auf- [1] https://auth0.com zusetzen, und zu einem wirklich schnellen Ergebnis zu [2] http://bit.ly/IdentitySrv kommen. Und genau hier hört die Genialität der Ein- [3] http://bit.ly/ApiAuthAnnouncement fachheit auch leider schon auf, denn diese Integration [4] http://bit.ly/NetCore3Announcement ist konzeptionell auf genau dieses Szenario beschränkt: Das API hostet und akzeptiert seinen eigenen Identity- [5] http://bit.ly/ApiAuthRepo Server, die Clients entsprechen den vorgegebenen Pro- [6] http://bit.ly/ApiAuthSample

www.basta.net 52 DOSSIER Sicherheit

Neue Besen kehren gut, sagt man. Aber sind sie auch sicher? Wasm – Ist das sicher oder kann das weg?

Schon wieder eine neue Technologie für aktive Inhalte – muss das denn wirklich sein? Als hätten wir mit Flash und Java nicht schon genug Ärger gehabt. Beides wurde wahrscheinlich öfter für Angriffe als für wirklich nützliche Anwendungen verwendet.

von Carsten Eilers WebAssembly ganz einfach ... Sehr vereinfacht gesagt ist WebAssembly ein Bytecode, Jedenfalls wenn man mal von Spielen und in der Web- der in einer Sandbox ausgeführt wird. Im Browser wer- steinzeit dem Wiedergeben von Videos durch Flash den WebAssembly-Module in der JavaScript VM aus- absieht. HTML5 und die dazugehörenden JavaScript geführt. Für den WebAssembly-Code gelten daher die APIs decken doch schon alle möglichen und unmögli- gleichen Sicherheitsbeschränkungen wie für JavaScript- chen Anwendungsfälle ab. Wieso also noch was Neues Code, insbesondere also die Same-Origin Policy. Hinzu erfinden? Vor allem, wo doch jede neue Funktionalität kommt die zusätzliche Einschränkung, dass WebAssem- immer auch die Angriffsfläche erhöht, die man doch bly-Code nicht direkt auf das DOM der Seite zugreifen eigentlich möglichst klein halten möchte. Die Antwort kann. Für Änderungen an der dargestellten Seite oder ist ganz einfach: Wieso nicht? Vielleicht ist das Neue ja das Abfragen von Informationen daraus müssen Java­ besser als alles Alte. Script-Funktionen verwendet werden. Auch können die Wichtig ist natürlich vor allem, dass es sicher ist. Nicht WebAssembly-Module nur dann auf die Hardware oder nur sicherer als Flash oder Java – das ist keine Kunst, das Dateisystem zugreifen, wenn der Benutzer das in der so chronisch unsicher wie die sind. Sondern wirklich Browserkonfiguration explizit erlaubt. sicher, von Anfang an und ohne Kompromisse. Wobei Java in der Theorie auch sicher sein sollte, nur bei der ... und etwas formaler Umsetzung, vor allem im Browser, hat es dann gewaltig Formal betrachtet ist WebAssembly die Spezifikation ei- gehakt. So sehr, dass Java im Browser inzwischen im ner Instruction Set Architecture und eines Dateiformats. Grunde tot ist. Die Instruction Set Architecture beschreibt einen (vir- Wie sieht es also mit der Sicherheit von WebAssem- tuellen) Rechner, und das Dateiformat legt den Aufbau bly (auch kurz „Wasm“ genannt) aus? Dazu schauen von WebAssembly-Modulen fest. Der Browser lädt den wir uns erst einmal an, was das überhaupt ist. Und WebAssembly-Binärcode in Form von Modulen und zwar nur im Kontext von Webanwendungen und der führt ihn aus. Ausführung im Webbrowser, denn das ist der primäre Das ähnelt den bekannten Java-Applets, die zu Java- Anwendungszweck. Dass WebAssembly auch in Nicht- Bytecode kompiliert und in der Java Virtual Machine Webumgebungen ausgeführt werden kann, ist laut den (VM) ausgeführt werden. Der Unterschied besteht da- WebAssembly-Entwicklern zwar wünschenswert, aber rin, dass Java Applets eine Erweiterung des Browsers kein zentrales Ziel der Entwicklung. sind, die in einem Plug-in ausgeführt werden, während

www.basta.net 53 DOSSIER Sicherheit

WebAssembly-Bytecode, wie schon erwähnt, im Ja- ggf. frei. Speicherlecks sind dadurch nur in den glei- vaScript-Interpreter der Browser ausgeführt wird. chen Grenzen wie bei normalen JavaScript-Program- Entwickelt werden können die WebAssembly-Pro- men möglich. gramme in etlichen Sprachen, angefangen bei C/C++ Da der komplette Heap des WebAssembly-Moduls über Rust und Go bis hin zu C#. Und falls sich irgend- im ArrayBuffer steckt, weiß die JavaScript-Umgebung, wer hinsetzt und einen Compiler dafür schreibt, könnte wie groß der Heap des Moduls ist und wo genau er im man auch z. B. Basic C64 verwenden. JavaScript Heap liegt. Dadurch kann sie bei jedem Spei- Aus Sicherheitssicht ist es aber egal, in welcher Sprache cherzugriff des WebAssembly-Codes zum einen exakt entwickelt wurde. Interessant sind dafür nur der Bytecode nachprüfen, ob sich der Zugriff innerhalb des Array- und dessen Ausführung. Und eigentlich sogar nur die Aus- Buffers bewegt, und zum anderen unerlaubte Zugriffe führung, denn der Bytecode stammt ja aus einer i. Allg. unterbinden. nicht vertrauenswürdigen Quelle, sodass man nicht weiß, Unerlaubte Speicherzugriffe in die JavaScript VM ob er harmlos ist oder bösartig, oder vielleicht auch harm- oder gar in den Adressraum des Browserprozesses wer- los aber kompromittiert. Sämtliche Schutzmaßnahmen den dadurch effektiv verhindert. Zwar verlangsamen müssen daher im Browser ergriffen werden. diese Prüfungen die Ausführung des Programms etwas, aber ohne sie wäre die Ausführung von WebAssembly- Die Schutzmaßnahmen Code viel zu gefährlich. Denn darin kann potenziell be- Einige der Sprachen, die nach WebAssembly kompiliert liebiger Schadcode stecken. werden können, erlauben den Zugriff auf beliebige Spei- cheradressen. Ein Angreifer könnte das nutzen, um im Schutz des Execution-Stacks Browser gespeicherte sicherheitsrelevante Informatio- Genauso gefährlich wie beliebige Zugriffe auf den Spei- nen wie z. B. Passwörter oder Authentifizierungstokens cher sind Zugriffe auf den Execution-Stack. Der enthält auszuspähen, sofern er deren Speicherort kennt. WebAs- außer den lokalen Variablen auch die Rücksprungad- sembly-Modulen werden daher separate Speicherberei- resse an die aufrufende Funktion. Gelingt es bösartigem che zugewiesen. Code, die Rücksprungadresse zu manipulieren, kann der Angreifer sie nutzen, um beliebigen Code auszufüh- Schutz des Speichers ren. WebAssembly verhindert einen Schreibzugriff auf Speicherzugriffe sind nur auf eine dedizierte Unter- den Execution-Stack, indem er außerhalb des Speichers menge des Heaps der JavaScript VM möglich. Dieser des WebAssembly-Moduls gespeichert wird. spezielle Heap wird durch einen JavaScript Array- Buffer realisiert. Dadurch gelten für den gesamten Vorsicht bei Sprüngen Speicher eines WebAssembly-Moduls die gleichen Auch Befehle, die an andere Stellen im Code springen, sind Beschränkungen wie für normale JavaScript-Objekte. generell gefährlich. WebAssembly springt nur bei Funk- Außerdem überwacht dadurch die Garbage Collection tionsaufrufen Speicheradressen an. Die werden teilweise die Speichernutzung des Moduls und gibt den Speicher erst dynamisch zur Laufzeit berechnet. Um Manipulatio- nen zu verhindern, kommen dabei Tabellen zum Einsatz. Statt die Zieladresse direkt im call-Befehl zu speichern, verwenden call-Befehle zwei Parameter: einen Index in einer Tabelle und eine Funktionssignatur. Der Index zeigt Web Application Security Trends: in eine Tabelle mit Funktions-Pointern. Die wird genau alte Technik, neue Gefahren wie der Execution-Stack außerhalb des WebAssembly- Moduls gespeichert, sodass ein Überschreiben durch das Christian Wenz (Arrabiata Solutions GmbH) WebAssembly-Modul nicht möglich ist. Angriffe wie etwa SQL Injection, Cross- Bevor die WebAssembly-Laufzeitumgebung einen Site Scripting (XSS) und Cross-Site call-Befehl ausführt, prüft sie, ob die an den call-Befehl Request Forgery (CSRF) sind teils zwei übergebene Funktionssignatur mit dem in der Tabelle am Dekaden alt, man sollte sie also kennen. Doch verschärfte Varianten bestehen- angegebenen Index gespeicherten Wert übereinstimmt. der Methoden sind bereits im Anmarsch: CSRF ohne Nur wenn die beiden Signaturen übereinstimmen, wird Nutzerinteraktion, längst vergessene XSS-Varianten, die Funktion an der in der Tabelle gespeicherten Adresse und JavaScript APIs aus dem letzten Jahrtausend. aufgerufen. Gibt es unter dem Index keinen Eintrag in Natürlich gibt es auch neuartigere Angriffe wie etwa der Tabelle oder stimmen die beiden Signaturen nicht unsichere JSON-Deserialisierung, überraschende XML- überein, wird die Ausführung des WebAssembly-Mo- Injektionen, XSS in SPA-Templates und vieles mehr. duls sofort gestoppt. Diese Session zeigt zahlreiche dieser Angriffe in Aktion und erläutert selbstverständlich Gegenmaßnahmen. Die beiden Parameter müssen nicht zwingend statisch Seien Sie bereit für ein paar überraschende Ansätze, gespeichert sein, sie können auch erst zur Laufzeit dyna- eine Menge Code und eine To-do-Liste, sobald Sie von misch generiert werden. Dadurch können z. B. Aufrufe der Konferenz nach Hause kommen. an virtuelle Methoden in C++ oder Traits-Implementie- rungen in Rust realisiert werden.

www.basta.net 54 DOSSIER Sicherheit

WebAssembly ist fast immer deterministisch Call-Stack gespeichert, die globalen Variablen befinden Abgesehen von wenigen Ausnahmen [1] erfolgt die sich im globalen Index Space und können von externen Ausführung der WebAssembly-Programme generell de- Modulen importiert werden. terministisch. Eine nichtdeterministische Ausführung Lokale Variablen mit unklarem statischem Gültigkeits- kann nur in wenigen, wohldefinierten Fällen auftreten, bereich werden beim Kompilieren in einem separaten Stack in denen die Implementierung eine aus einer limitierten im dem Programm zugänglichen linearen Speicher gespei- Menge möglicher Verhaltensweisen wählt. Außerdem chert. Dazu gehören z. B. Variablen, die vom address- sind die Effekte einer nichtdeterministischen Ausführung of-Operator verwendet werden oder die den Type struct immer nur lokal. haben und als „Returned by Value“ zurückgegeben wer- Ein nichtdeterministisches Verhalten tritt z. B. auf, den. Dieser Stack ist ein isolierter Speicherbereich mit fester wenn WebAssembly um neue Features erweitert wird Maximalgröße, der per Default mit null initialisiert wird. und die verschiedenen Implementierungen die Fea- tures unterschiedlich unterstützen. Zwar kann über Traps has_feature die Unterstützung abgefragt werden, Traps werden verwendet, um ggf. die Ausführung sofort trotzdem unterscheiden sich die Ausführungen auf den beenden zu können und unnormales Verhalten an die verschiedenen Implementierungen voneinander. Auch Laufzeitumgebung zu melden. Im Browser werden dazu wenn die umgebungsabhängigen Ressourcenlimits JavaScript Exceptions verwendet. erreicht werden, kann es zu einem nichtdeterminis- Traps können z. B. ausgelöst werden, wenn in irgend- tischen Verhalten kommen, z. B. wenn Speicherreser- einem Index Space ein ungültiger Index spezifiziert, ein vierungen fehlschlagen oder der Stack des Programms indirekter Funktionsaufruf mit falscher Signatur durchge- voll ist. führt oder im linearen Speicher auf verbotene Adressen zugegriffen wird. Sichere Entwicklung (fast) garantiert Das Design von WebAssembly unterstützt die Entwick- Speicherschutz lung sicherer Programme [2], indem auf gefährliche Im Vergleich zu normalen C/C++-Programmen verhin- Features verzichtet wurde, während gleichzeitig die dert WebAssembly verschiedene Klassen von Speicher- Kompatibilität zu in C/C++ geschriebenen Programmen fehlern. Z. B. sind die im Index-Space gespeicherten erhalten blieb. lokalen und globalen Variablen vor Pufferüberläufen si- cher, da sie eine feste Größe haben und über einen Index Funktionen adressiert werden. Die WebAssembly-Module müssen alle zugänglichen Im linearen Speicher abgelegte Daten können be- Funktionen und die zugehörigen Datentypen beim La- nachbarte Objekte überschreiben, da die Prüfung des den deklarieren. Und das auch dann, wenn dynamisch Gültigkeitsbereichs mit der Genauigkeit des linearen gelinkt wird. Dadurch ist es möglich, durch einen struk- Speicherbereichs erfolgt und nicht kontextsensitiv ist. turierten Kontrollfluss die Integrität des Kontrollflusses Das Vorhandensein von Kontrollflussintegrität und (Control-Flow Integrity, CFI) zu erzwingen. Da kom- geschützten Aufrufstacks verhindert jedoch das di- pilierter Code unveränderlich und während der Lauf- rekte Einschleusen von Code. Dadurch sind die sonst zeit nicht beobachtbar ist, kann der Kontrollfluss der üblichen Mitigations wie Data Execution Prevention WebAssembly-Programme nicht manipuliert werden, (DEP) und Stack Smashing Protection (SSP) in Web­ Hijacking-Angriffe sind also nicht möglich. Assembly-Programmen nicht nötig. Wie zuvor bereits erwähnt, müssen Funktionsaufru- Eine weitere übliche Klasse von Speicherfehlern fe den gültigen Index der gewünschten Funktion in der entsteht durch unsichere Pointer-Nutzung und undefi- Funktionstabelle (Function Index Space) oder Tabel- niertes Verhalten. Ein klassisches Beispiel dafür ist die lentabelle (Table Index Space) enthalten. Bei indirekten Dereferenzierung von Pointern in nicht reserviertem Funktionsaufrufen wird vor der Ausführung die Signa- Speicher oder die Freigabe noch genutzten Speichers. tur der Funktion geprüft. Der außerhalb des Modulspei- In WebAssembly enthalten Funktionsaufrufe und Va- chers abgelegte Stack ist vor Pufferüberlaufangriffen riablen mit festem statischem Gültigkeitsbereich keine sicher. Branches (br, br_if, br_table) müssen zu gültigen Pointer. Verweise auf ungültige Indexe in irgendeinem Zielen in der aufrufenden Funktion führen. Index Space lösen i. Allg. schon beim Laden einen Fehler aus, im schlimmsten Fall eine Trap zur Lauf- Variablen zeit. Bei Zugriffen auf den linearen Speicher werden C/C++-Variablen können in WebAssembly in Abhän- die Grenzen auf Regionsebene geprüft, ggf. wird zur gigkeit von ihrem Gültigkeitsbereich (Scope) auf zwei Laufzeit eine Trap ausgelöst. Diese Speicherbereiche unterschiedliche Primitive reduziert werden. Lokale Va- sind vom internen Speicher isoliert (s. o.) und werden riablen mit festem Gültigkeitsbereich und globale Varia- per Default auf null gesetzt, sofern sie nicht anderwei- blen werden als Werte mit festem Typ repräsentiert, auf tig initialisiert werden. die über einen Index zugegriffen wird. Die lokalen Va- Einige andere Klassen von Fehlern werden von riablen werden mit null initialisiert und im geschützten WebAssembly allerdings nicht verhindert. So kann

www.basta.net 55 DOSSIER Sicherheit

zwar nicht direkt Code eingeschleust werden, aber das keine zusätzliche Gefahr. Ob der Schädling nun in Java­ Hijack­ing des Kontrollflusses eines Moduls über Code Script, WebAssembly oder „the next big Thing“ imple- Reuse Attacks gegen indirekte Funktionsaufrufe ist mentiert ist, ist egal. Die einzigen, die darüber jammern, möglich. Konventionelle Angriffe über Return-oriented sind die Antivirushersteller, denn die müssen nun in einem Programming (ROP) zum Missbrauch kurzer Code- weiteren Datenformat nach Schadsoftware suchen. Und, sequenzen (Gadgets) sind allerdings nicht möglich, da so eine Unverschämtheit: Das ist auch noch ein Binärfor- die Kon­trollflussintegrität dafür sorgt, dass die Auf- mat, in dem sie nicht einfach nach Strings suchen können. rufziele zur Ladezeit deklarierte, gültige Funktionen sind. Ausbruch aus der Sandbox möglich Auch Race Conditions wie z. B. „Time of Check to Alex Plaskett, Fabian Beterke und Georgi Geshev von Time of Use“-(TOCTOU-)Schwachstellen und Seiten- den MWR Labs wollten mit einem Exploit für Web­ kanalangriffe sind möglich. Assembly in Safari 11.0.3 unter macOS 10.13.3 am Pwn2Own-Wettbewerb 2018 teilnehmen [6]. Daraus Kontrollflussintegrität wurde leider nichts, da die von ihnen entdeckte und Die Wirksamkeit der Kontrollflussintegrität kann an ih- für den Angriff ausgenutzte Schwachstelle (CVE-2018- rem Umfang gemessen werden. Generell muss der Kon- 4121) unabhängig von ihnen auch von Natalie Silvano- trollfluss an drei Stellen geschützt werden: vich von Project Zero entdeckt [7] und an die Entwickler gemeldet wurde. Da Apple die Schwachstelle 1. bei direkten Funktionsaufrufen, vor dem Wettbewerb kannte und dann auch geschlossen 2. bei indirekten Funktionsaufrufen und hatte, konnten Alex Plaskett, Fabian Beterke und Georgi 3. bei Rücksprüngen. Geshev ihren Exploit nicht mehr verwenden. Er ist hier aber relevant, denn er beweist, dass trotz Bei direkten Funktionsaufrufen wird der Kontrollfluss aller Schutzmaßnahmen ein Ausbruch aus der WebAs- in WebAssembly durch die Verwendung des Indexwerts sembly-Sandbox und die Kompromittierung des Sys- geschützt, bei Rücksprüngen durch den geschützten tems möglich sind. Wie genau, haben die drei in einem Call-Stack. Paper ausführlich beschrieben [6]. Und das ist nicht die Die Prüfung der Funktionssignaturen bei indirekten einzige Schwachstelle in den WebAssembly-Implemen- Funktionsaufrufen zur Laufzeit garantiert eine grobkör- tierungen [8]. nige, typbasierte Integritätssicherung. Der einzige noch mögliche Angriff bei indirekten Aufrufen ist, wie schon WebAssembly als Einfallstor für Spectre-Angriffe erwähnt, die Wiederverwendung von Code auf Funkti- Die Spectre-Varianten 1 und 2 lassen sich über den onsebene. Browser ausnutzen [9]; Auch über WebAssembly. Clang/LLVM enthält eine integrierte Implementie- Dazu müssen die C/C++ Exploits nur nach WebAssem- rung einer feineren Kontrollflussintegrität. Diese wurde bly kompiliert werden [10]. Das ist unschön, da gera- in Version 3.9+ mit dem neuen WebAssembly Backend de bekannt wurde, dass die ganzen softwarebasierten auf WebAssembly portiert. Damit ist u. a. ein besserer Schutzmaßnahmen gegen Spectre-Angriffe weitgehend Schutz vor Code-Reuse-Angriffen auf indirekte Funkti- nutzlos sind [11]. Von solchen Angriffen sind besonders onsaufrufe möglich [3]. Programme betroffen, die Daten aus nicht vertrauens- würdigen Quellen verarbeiten. Und bei mir und wahr- „Early Adopters“ – die Cyberkriminellen scheinlich auch bei den meisten von Ihnen dürfte das am Das sieht doch alles ganz gut bzw. sicher aus. Aber Sie ahnen es sicher schon: Es gibt da doch noch ein paar Haken – irgendwas ist ja immer. Im Fall von WebAssembly sind das z. B. Crypto Min­ er. Die Cyberkriminellen scheinen mit die ersten gewe- Add Security into your sen zu sein, die die Vorteile von WebAssembly erkannt Agile Process haben: Damit lassen sich Kryptowährungen im Browser deutlich schneller minen als mit JavaScript-Code [4]. Cecilia Wirén (Active Solution) Dementsprechend gibt es schon etliche entsprechende Security is often treated the same way Schädlinge, die über infizierte Websites oder bösartige we don’t like to do development, as wa- Werbung verbreitet werden. Das kann man natürlich terfall: in the beginning or just at the end nicht WebAssembly vorwerfen, der Vollständigkeit hal- as a last gateway/check. But of course that isn’t the best way to do it! How can ber soll es aber nicht unerwähnt bleiben. Crypto Miner you incorporate security thinking into you daily work im Browser gab es auch schon vor der Einführung von together with your customers? How can you make sure WebAssembly, nur waren die dann eben deutlich lang- you don’t add flaw frameworks or get notified when samer, da sie „nur“ in JavaScript implementiert waren. the security issue is detected? Let’s find a way to add a Generell kann fast jede JavaScript-basierte Schadsoft- security mindset into the develoment lifecycle! ware nach WebAssembly portiert werden [5], aber das ist

www.basta.net 56 DOSSIER Sicherheit

stärksten gefährdete Programm der Webbrowser sein – vorhandene Sicherheit durch unsichere WebAssembly- keine gute Kombination. Features unterminieren.

Was sagen die Sicherheitsforscher? WebAssembly = neue native Exploits im Browser WebAssembly ist noch ziemlich neu, aber die Sicherheits- Kritischer sehen das Justin Engler und Tyler Lukasie- forscher haben schon damit begonnen, es auf Schwach- wicz von der NCC Group WebAssembly, wie schon stellen abzuklopfen. Siehe die gefundenen Schwachstellen der Titel ihres Vortrags zeigt: „WebAssembly: A New und den für den Pwn2Own-Wettbewerb entwickelten World of Native Exploits on the Browser“ [13]. Die Exploit. Auch auf den Sicherheitskonferenzen gab es erste neuen „Nativen Exploits“ bestehen zum einen aus Vorträge, z. B. gleich zwei auf der Black Hat USA 2018. alten Exploits, die weiterhin funktionieren, und zum anderen aus neuen Exploits, die sich aus den Fea- Vorsicht Gefahrenstelle! tures von WebAssembly ergeben. Als Beispiele für Natalie Silvanovich von Googles Project Zero (die ja alte Exploits nennen sie Angriffe auf Formatstring- auch schon Schwachstellen in WebAssembly gefun- schwachstellen, Integer- und Pufferüberläufe. Einen den hat) hat „The Problems and Promise of WebAs- Pufferüberlauf demonstrieren sie mit einem kleinen sembly“ vorgestellt [12]. Dabei gibt es einen sowohl Beispiel. Weitere alte Exploits, die ihrer Ansicht negativen als auch positiven Aspekt: Für die meisten nach wahrscheinlich funktionieren, sind Angriffe Problemfelder konnte sie bereits tatsächliche Schwach- auf TOCTOU-Schwachstellen und Race Conditions stellen präsentieren, sie sind also keine theoretische, son- sowie Timing- und Seitenkanalangriffe. Und auch dern eine konkrete Gefahr. Das ist natürlich erst mal Heap-basierte Schreibzugriffe können für Angriffe schlecht. Andererseits aber zumindest bisher auch gut: missbraucht werden. Die Schwachstellen betreffen „nur“ Implementierungen Zum anderen gibt es neue Exploits. Da WebAssem- von WebAssembly, nicht die Spezifikation. Die ist also bly auf dem Umweg über JavaScript auf das DOM (noch) sicher. zugreifen kann, ist es möglich, über eine Pufferüber- Konkret hat Natalie Silvanovich folgende Probleme laufschwachstelle einen DOM-basierten XSS-Angriff angesprochen: durchzuführen. Was auf den ersten Blick widersinnig erscheint, da sich über einen Pufferüberlauf sicher inte- • Das Parsen des Binärformats sowie dessen Laden in ressantere Sachen anstellen lassen, sieht auf den zweiten das Modul (3 Schwachstellen) Blick doch schon etwas anders aus: Zum einen suchen • Die Speicherverwaltung (2 Schwachstellen) die Funktionen zur Abwehr von XSS-Angriffen kaum • Die Tabellen mit den Funktionen (2 Schwachstellen) im WebAssembly-Code danach, zum anderen kann über • Die Initialisierung von Speicher und Elementen einen XSS-Angriff JavaScript und damit WebAssembly (1 Fehler, bisher keine Schwachstelle) kontrolliert werden. Da lässt sich also durchaus Scha- • Der Export der WebAssembly-Funktionen (bisher den mit anrichten, vor allem wenn man bedenkt, dass keine Schwachstellen) WebAssembly meist für aufwendige Webanwendungen • Probleme zur Laufzeit (bisher keine Schwachstellen) verwendet wird. Ein weiterer neuer Exploit sind Angriffe auf „Funk- Dass es Schwachstellen gibt, ist natürlich immer schlecht, tions-Pointer-Überläufe“. Die sind möglich, da die aber ich denke, es hätte auch noch schlimmer kommen „Funktions-Pointer“ keine Pointer, sondern Indexe für können. Die Anzahl der Schwachstellen ist doch sehr die Funktionstabelle sind. Als Beispiele haben die beiden überschaubar. Außerdem sorgen die vorhandenen Si- wieder einen XSS-Angriff durchgeführt und außerdem cherheitsfeatures dafür, dass die Wahrscheinlichkeit für gezeigt, wie eine andere als die vorgesehene Funktion Schwachstellen sinkt; jedenfalls in den WebAssembly- aufgerufen werden kann. Was je nach Funktion genau- Programmen. Bei den Laufzeitumgebungen kommt es na- so gefährlich ist wie die Ausführung beliebigen einge- türlich darauf an, wie sicher die Browserhersteller etc. sie schleusten Codes. implementieren. Verschlimmert wird das Ganze dadurch, dass die Wie sich die Sicherheit von WebAssembly entwickelt, Angriffe auch mit Node funktionieren – und das führt hängt nach Ansicht von Natalie Silvanovich von den zu einer Remote Code Execution auf dem Server. zukünftigen Features ab. Und da sehe ich optimistisch Da sind noch einige Anpassungen und Erweiterungen in die Zukunft. Zum einen sind bereits weitere Sicher- bei den Schutzfunktionen nötig, aber die wurden zum heitsfeatures angekündigt, zum anderen haben die Web­ Teil auch schon angekündigt. Entwicklern empfehlen Assembly-Entwickler schon bewiesen, dass sie Wert die beiden Forscher Folgendes: auf Sicherheit legen. Daher gehe ich davon aus, dass die nicht plötzlich anfangen, unsichere Features in die • emscripten_run_script etc. zu vermeiden, Spezifikation aufzunehmen. Vor allem, da die Entwick- • den Optimizer zu verwenden, wodurch nicht genutz- lung von WebAssembly von den Browserherstellern aus- te, automatisch hinzugefügte Funktionen entfernt geht, und die haben ein großes Interesse daran, dass die und die Angriffsfläche für Angriffe auf den Kontroll- Browser sicher sind. Die werden kaum anfangen und die fluss reduziert werden,

www.basta.net 57 DOSSIER Sicherheit

• die Kontrollflussintegrität zu nutzen und vor allem Dipl.-Inform. Carsten Eilers ist freier Berater und Coach • ihre C-Fehler zu beheben. Wobei ich in so einem Fall für IT-Sicherheit und technischen Datenschutz sowie ja vorschlagen würde, die gar nicht erst zu machen. Autor einer Vielzahl von Artikeln für verschiedene Ma- gazine und Onlinemedien. Sicherheitstools www.ceilers-it.de, www.ceilers-news.de Es gibt auch schon erste Sicherheitstools für Web­ Assembly: Wasabi [14] (kurz für „WebAssembly ana- lysis using binary instrumentation“) ist ein am Software Links & Literatur Lab der TU Darmstadt entwickeltes Framework zur dynamischen Analyse von WebAssembly-Programmen. [1] WebAssembly Documentation: Nondeterminism in WebAssembly: Aron Szanto, Timothy Tamm und Artidoro Pagno- https://webassembly.org/docs/nondeterminism/ ni von der Harvard University haben eine JavaScript- [2] WebAssembly Documentation: Security: https://webassembly.org/ basierte VM für WebAssembly geschrieben, die Taint docs/security/ Tracking implementiert [15]. Damit ist es möglich, den [3] Foote, Jonathan; fastly: „Hijacking the control flow of a WebAssembly Fluss sensitiver Informationen zwischen den lokalen Va- program“: https://www.fastly.com/blog/hijacking-control-flow- riablen zu verfolgen und problematische Parameter zu webassembly erkennen. [4] Neumann, Robert; Toro, Abel; Forcepoint: „In-browser mining: Coinhive and WebAssembly“: https://www.forcepoint.com/blog/security-labs/ Fazit browser-mining-coinhive-and-webassembly Insgesamt sieht es mit der Sicherheit von WebAssem- [5] Lonkar, Aishwarya; Chandrayan, Siddhesh; Virus Bulletin: „The bly gut aus. Darum kann das Fazit auch kurz ausfallen: dark side of WebAssembly“: https://www.virusbulletin.com/ Es spricht nichts dagegen, WebAssembly zu nutzen. Als virusbulletin/2018/10/dark-side-webassembly/ Entwickler ebenso wie als Benutzer. [6] Plaskett, Alex; Beterke, Fabian; Geshev, Georgi; MWR Labs: „Apple Natürlich gibt es da noch einiges, was sich verbessern Safari - Wasm Section Exploit“: https://labs.mwrinfosecurity.com/ lässt, aber das gilt wohl für jede Software. Zumindest publications/apple-safari-wasm-section-exploit/ bisher wurden keine Schwachstellen in der Spezifika- [7] Silvanovich, Natalie; Google Project Zero: „Issue 1522: WebKit: tion gefunden (evtl. wurde auch nur nicht danach ge- WebAssembly parsing does not correctly check section order“: https:// sucht?), und die Anzahl der in den Implementierungen bugs.chromium.org/p/project-zero/issues/detail?id=1522&can=1&q= gefundenen Schwachstellen ist überschaubar. Und was &start=1300 Schwachstellen in den WebAssembly-Programmen be- [8] Silvanovich, Natalie; Google Project Zero: „The Problems and Promise of trifft: Interessiert sich wirklich irgendwer für die? Ich WebAssembly“: https://googleprojectzero.blogspot.com/2018/08/the- könnte mir vorstellen, dass die Cyberkriminellen sich problems-and-promise-of-webassembly.html darauf stürzen werden. Aber erst, wenn sie keine ande- [9] Eilers, Carsten; Windows Developer 3.19: „CPU-Schwachstellen im ren Schwachstellen mehr finden, die sie ausnutzen kön- Überblick - Sind Spectre und Meltdown nur die Spitze des Eisbergs?“ nen. Und bis dahin wird noch einige Zeit vergehen. [10] Jorgé; React, etc. Tech Stack: „Exploits in C/C++ to compiled JavaScript Und selbst wenn es irgendwann Angriffe auf / WebAssembly“: https://react-etc.net/entry/web-security-exploits-c- WebAssembly-Programme geben wird: Wie viel Scha- to-javascript-webassembly den können die Angreifer dann schon anrichten? Ist es [11] Mcilroy, Ross; Sevcik, Jaroslav; Tebbi, Tobias; Titzer, Ben L.; Verwaest, nicht eher wahrscheinlich, dass sie den Clientcode der Toon: „Spectre is here to stay: An analysis of side-channels and einen betroffenen Webanwendung zwar kompromit- speculative execution“: https://arxiv.org/abs/1902.05178 tieren können, dann aber in der Sandbox festsitzen? [12] Silvanovich, Natalie; Black Hat USA 2018: „The Problems and Und Angriffe auf den Clientcode der Webanwendung Promise of WebAssembly“: https://www.blackhat.com/us-18/ sind auch heute schon möglich, so extrem sicher sind briefings/schedule/index.html#the-problems-and-promise- die JavaScript-Clients nun auch nicht. Aber haben Sie of-webassembly-11219 ; Video: https://www.youtube.com/ schon von großflächigen Angriffen gehört? Oder auch watch?v=BHwqORo_83E nur einzelnen? „In the Wild“ ist es da doch ziemlich [13] Engler, Justin; Lukasiewicz, Tyler; Black Hat USA 2018: „WebAssembly: ruhig. Und ich glaube kaum, dass sich das mit WebAs- A New World of Native Exploits on the Browser“: https://www.blackhat. sembly ändert. com/us-18/briefings/schedule/index.html#webassembly-a-new-world- Außerdem ist das Zukunftsmusik und bis es soweit of-native-exploits-on-the-browser-10043 ist, werden die Sicherheitsfunktionen bestimmt sehr Video: https://www.youtube.com/watch?v=DFPD9yI-C70 viel ausgereifter sein. Und die Entwickler der WebAs- [14] Wasabi: http://wasabi.software-lab.org sembly-Programme können ja ihren Teil zur Sicherheit [15] Szanto, Aron; Tamm, Timothy; Pagnoni, Artidoro: „Taint Tracking for beitragen, die Schwachstellen in ihren Programmen kor- WebAssembly“: https://arxiv.org/abs/1807.08349 ; GitHub: https:// rigieren und keine neuen mehr entstehen lassen. github.com/aronszanto/wasm-taint-tracking

www.basta.net 58 DOSSIER HTML5 & JavaScript

Mit ASP.NET Core und Angular eine Webanwendung erstellen Das Beste aus zwei Welten

Moderne verteilte Systeme im Web bestehen heutzutage aus vielen verschiedenen Teilen, Systemen und Technologien. Frontend und Backend sind zwei sehr wichtige Elemente einer aktuellen Webapplikation. Für maximale Flexibilität kann man die- se Teile vollkommen trennen und eine im Browser laufende, eigene Applikation als Frontend mit einem REST-Service im Backend kommunizieren lassen.

von Fabian Gosebrink laufen lassen können. Beim Erstellen des Web-API wur- de gleich der dotnet restore-Command ausgeführt, mit Die Auswahl eines Frontend-Frameworks ist nicht dem alle unsere NuGet-Pakete heruntergeladen und für leicht, jedoch hat sich Angular in der letzten Zeit nicht unsere Anwendung bereitgestellt wurden. Hierbei wird nur durch ein gutes „Separation of Concerns“-Konzept ein neuer Webserver „Kestrel“ in einer Konsole gehos- und gute Synchronisierungsmechanismen von Model, tet, der unsere Applikation hochfährt und für Requests View, Architektur und hoher Performance hervorgeho- bereitstellt. Dabei stehen uns in der neuesten Version ein ben. Auch die Regelmäßigkeit, mit der neue Versionen HTTP- und ein HTTPS-Endpunkt zur Verfügung. dotnet erscheinen, das Angular CLI und nicht zuletzt der Inter- watch run bietet zudem einen Live-Reload-Server, sodass netgigant Google mit Long Term Support tragen dazu jedes Mal, wenn wir eine Datei in unserem Projekt än- bei, dass mehr und mehr Businessanwendungen im Web dern, das Backend neu gestartet wird und wir es nicht auf die Angular-Plattform setzen. manuell unterbrechen und wieder hochfahren müssen. Im Backend hat Microsoft mit ASP.NET Core spätes- tens seit Version 2.x den alten Mantel abgeworfen und Konfiguration und Start des Web-API kommt neu, schlank und vor allem schnell daher. Live- ASP.NET-Core-Applikationen sind grundsätzlich Kon- Reload, Middleware, die Geschwindigkeit und Cross- solenprogramme, die wir beispielsweise mit dem Befehl Plattform-Fähigkeit sind nur einige Gründe, warum man dotnet run von der Kommandozeile aus starten können. ASP.NET Core mehr als nur einen Blick widmen sollte. Somit ist der Startpunkt unseres Web-API eine einfache In diesem Artikel möchte ich die Bestandteile und auch Konsolenapplikation, die uns einen Webserver bereit- die Vorteile eines Frontends mit Angular sowie eines stellt, statt beispielsweise ein „Hello World“ auf der REST Backends mit ASP.NET Core darstellen und zeigen, Konsole auszugeben (Listing 1). wie man diese Teile einer Webapplikation programmieren Falls etwaige Konfigurationen für unsere Appli- kann. Als Beispiel programmieren wir einen Booktracker, kation vorgenommen werden sollen, können diese der eine Merkliste für Bücher enthält, die man als gele- Konfigurationsfiles hier eingelesen werden. Standard- sen markieren kann. Außerdem kann man neue Bücher mäßig werden die mitgenerierten appsettings.json und hinzufügen und bestehende bearbeiten. Den kompletten appsettings.*.json zur Konfiguration herbeigezogen und Quellcode gibt es natürlich wieder auf GitHub [1]. appliziert. Aber es werden auch weitere Konfigurations- formate wie *.xml oder sogar *.ini unterstützt. ASP. Das ASP.NET Core Backend NET Core erstellt also neben einem Webserver auch ein ASP.NET Core bietet ein Command Line Interface (CLI) Konfigurationsobjekt, das wir in der Startup.cs zur Ver- an, mit dem wir uns über Templates das Grundgerüst fügung gestellt bekommen und nutzen können. unseres Web-APIs erstellen lassen können [2]. Eine Kommandozeile im gewünschten Ordner und der Befehl Start-up und Dependency Injecton dotnet new webapi in der Konsole erzeugen hierbei ein Basierend auf der fertigen Konfiguration, die uns mit- neues Web-API für uns, das wir mit dotnet watch run gegeben wird, können wir nun unser Web-API konfi-

www.basta.net 59 DOSSIER HTML5 & JavaScript

gurieren. ASP.NET Core macht dabei Gebrauch vom zen. Auch MVC selbst wird hier mitsamt seinen Services internen Dependency-Injection-System. In der Datei in den Container gelegt. Startup.cs bekommen wir im Konstruktor der Klasse Die Methode Configure erstellt eine Pipeline für alle die Konfiguration übergeben (Listing 2). ASP.NET Core unsere Requests, bevor sie von unseren Controllern be- kommt also mit einem eigenen Dependency-Injection- arbeitet werden. Hierbei ist die Reihenfolge der hinzuge- System, auf das wir im weiteren Verlauf dieses Artikels fügten Middleware wichtig. Das heißt, jeder eingehende noch eingehen werden. Request durchläuft die Middleware, die wir in dieser Die Startup.cs-Datei stellt zwei weitere Methoden be- Methode angeben können. Ebenso die ausgehende Re- reit: ConfigureServices und Configure. Erstere füllt den sponse, diesmal wird die Middleware jedoch in umge- Dependency-Injection-Container, den wir von ASP. NET­ kehrter Reihenfolge abgearbeitet. Also können Features Core übergeben bekommen: wie Authentication etc. hier in die Pipeline für unsere Requests „eingehängt“ werden. Auch MVC selbst wird public void ConfigureServices(IServiceCollection services) { /*...*/ } als Middleware hinzugefügt. Die Services haben wir schon in der ConfigureServices-Methode angegeben, die Auf diesem Container können wir unsere abhängigen zugehörige Middleware nutzen wir mit app.UseMvc(). Services eintragen und später in unseren Klassen via De- Somit kann unser Web-API Requests in Controllern pendency Injection injiziert bekommen und somit nut- empfangen, Routing nutzen etc.

Verwenden des Dependency-Injection-Containers In unserer Beispielapplikation brauchen wir ein Repos­ Listing 1 itory, mit dem wir unsere Entities in der Datenbank ab- public class Program speichern können: { public static void Main(string[] args) public interface IBookRepository { ... } { public class BookRepository : IBookRepository CreateWebHostBuilder(args).Build().Run(); } Dieses Repository können wir nun in unserem Depen- dency-Injection-Container vor dem Interface registrie- public static IWebHostBuilder CreateWebHostBuilder(string[] args) => ren: WebHost.CreateDefaultBuilder(args) .UseStartup(); services.AddScoped(); } AddScoped sorgt hierbei dafür, dass die Instanz so lange gehalten wird, wie der Request bearbeitet wird, und dass mit jedem Request eine neue Instanz erstellt Listing 2 wird. Die weitere Methode AddSingleton() legt eine In- public class Startup stanz des Service beim Hochfahren der Applikation an, { AddTransient () würde eine Instanz pro Konstruktorin- public Startup(IConfiguration configuration) jection erstellen. { Definieren eines REST-Endpunkts mit Controllern Configuration = configuration; } Der eigentliche REST-Endpunkt wird in ASP.NET Core in Controllern abgebildet. Die HTTP-Verben wie GET, public IConfiguration Configuration { get; } POST, PUT, PATCH, DELETE etc. können in Control- // ... lern implementiert werden (Listing 3). } Das Route-Attribut über der Controllerklasse legt die Adresse des Endpunkts fest. Hierbei ist der Präfix her- kömmlicherweise api/, gefolgt von einem generischen [controller]. Das wird ersetzt durch den Namen der Klasse ohne das Suffix „Controller“. In diesem Fall also Listing 3 api/values. [Route("api/[controller]")] Mit dem ApiController-Attribut legen wir fest, dass es [ApiController] sich um einen HTTP-Endpunkt handelt, der HTTP-Ant- public class ValuesController : ControllerBase worten verschickt. Mit dem Ableiten von ControllerBase­ { verzichten wir auf alle View-Funktionalitäten, die wir // im Fall einer kompletten MVC-Applikation bräuchten, } da wir als Antwort keine komplett gerenderten Seiten, sondern JSON verschicken wollen.

www.basta.net 60 DOSSIER HTML5 & JavaScript

Innerhalb dieses Controllers können wir nun den Antwort alle Bücher als JSON serialisiert zurückge- REST-Endpunkt definieren, mit dem sich unsere Bücher ben (Kasten: „AddMvc()“). ASP.NET Core bietet hier- abspeichern und aktualisieren lassen. In unserem Bei- bei als Rückgabetyp einer Methode unter anderem das spiel erstellen wir uns einen BooksController, für den IActionResult-Interface oder eine gar generische Klasse wir den Endpunkt api/books definieren. Da das Reposi- ActionResult an, um HTTP-Antworten zu definieren. tory schon im Container registriert wurde, können wir Gleichzeitig bietet das Ableiten der Controllerklasse von es nun im Controller einfach injecten (Listing 4). ControllerBase einen weiteren Vorteil: Man kann kleine Um nun alle Bücher abrufen zu können, müssen wir Helfermethoden wie zum Beispiel Ok(...) oder BadRe- auf das HTTP-GET-Verb reagieren (Tabelle 1) und als quest(...) benutzen, die dem Entwickler helfen, die richti- ge HTTP-Antwort mit dem korrekten HTTP-Statuscode zurück zum Client zu schicken. Das ist bei entkoppelten Listing 4 Systemen und einer solchen Service-Architektur von ele- mentarer Wichtigkeit. [Route("api/[controller]")] Eine Methode, die auf ein HTTP-Verb reagieren soll, [ApiController] kann mit dem jeweiligen HTTP-Verb als Attribut ge- public class BooksController : ControllerBase kennzeichnet werden (Listing 5). { Diese Methode reagiert auf einen HTTP-GET-Aufruf private readonly IBookRepository _bookRepository; und gibt einen 200er-Statuscode zurück, der für Ok steht. Die Helfermethode Ok() mit den Daten, die als public BooksController(IBookRepository repository) Body mit der Response geschickt werden sollen, macht { uns diese HTTP-Konvention sehr einfach. _bookRepository = repository; Falls wir ein einzelnes Buch abfragen wollen, können } wir auch Parameter im Routing angeben und auslesen. } Hierfür geben wir das Routing-Attribut ebenfalls auf der Methode an und reichen es als Parameter in die Funktion selbst (Listing 6). Listing 5 Falls das Buch nicht gefunden wird, geben wir einen 404-Statuscode zurück, ansonsten unseren bekannten [HttpGet] Ok-Statuscode 200. Alle weiteren Endpunkte imple- public IActionResult GetAll() mentieren wir entsprechend. Ein Beispiel für einen kom- { pletten Endpunkt kann in Listing 7 gefunden werden. List items = _bookRepository.GetAll().ToList(); IEnumerable toReturn = items.Select(x => Hinzufügen von Cross-Origin Resource Sharing Mapper.Map(x)); (CORS) return Ok(toReturn); Damit unser API fähig ist, Aufrufe von anderen Do- } mains statt nur der eigenen zu empfangen, können wir CORS konfigurieren. Da die Konfiguration des APIs über die Startup.cs-Datei passiert, können wir auch hier Listing 6 die CORS-Policy eintragen, die für uns passend ist. Zuerst müssen wir CORS als Service hinzufügen und [HttpGet] if (item == null) können es gleichzeitig konfigurieren (Listing 8). [Route("{id:int}")] { Hierbei erstellen wir eine Regel, bei der wir nur An- public IActionResult return NotFound(); fragen von unserem Development-Client der Angular GetSingle(int id) } Application zulassen. Diese Regel nennen wir Allow­ { AngularDevClient und müssen diese nun noch in Book item = _bookRepository. return Ok(Mapper. unserer Pipeline – also in der Configure-Methode – ver- GetSingle(id); Map(item)); wenden (Listing 9). }

Methode Link GET api/books/ „AddMvc()“ GET api/books/{id} Mit dem Aufruf AddMvc() in der Startup-Klasse POST api/books/ haben wir bereits einen JSON-Serialisierer hinzuge- fügt, der uns die Daten automatisch von Objekten zu PUT api/books/{id} JSON und von JSON zu Objekten parst. ASP.NET DELETE api/books/{id} Core liefert diese Funktionalität also out of the box. Tabelle 1: REST-Endpunkt

www.basta.net 61 DOSSIER HTML5 & JavaScript

Listing 7 [Route("api/[controller]")] failed on save."); Book item = _bookRepository.GetSingle(id); [ApiController] } public class BooksController : ControllerBase if (item == null) { Book newItem = _bookRepository. { private readonly IBookRepository _ GetSingle(toAdd.Id); return NotFound(); bookRepository; } return CreatedAtRoute(nameof(GetSingle), public BooksController(IBookRepository new { id = newItem.Id }, _bookRepository.Delete(id); repository) Mapper.Map(newItem)); { } if (!_bookRepository.Save()) _bookRepository = repository; { } [HttpPatch("{id:int}", Name = throw new Exception("Deleting an item nameof(PartiallyUpdate))] failed on save."); [HttpGet(Name = nameof(GetAll))] public ActionResult PartiallyUpdate( } public IActionResult GetAll() int id, [FromBody] JsonPatchDocument { patchDoc) return NoContent(); List items = _bookRepository. { } GetAll().ToList(); if (patchDoc == null) IEnumerable toReturn = items. { [HttpPut] Select(x => Mapper.Map(x)); return BadRequest(); [Route("{id:int}", Name = nameof(Update))] return Ok(toReturn); } public ActionResult Update(int id, } [FromBody] BookUpdateDto updateDto) Book existingEntity = _bookRepository. { [HttpGet] GetSingle(id); if (updateDto == null) [Route("{id:int}", Name = nameof(GetSingle))] { public IActionResult GetSingle(int id) if (existingEntity == null) return BadRequest(); { { } Book item = _bookRepository.GetSingle(id); return NotFound(); } var item = _bookRepository.GetSingle(id); if (item == null) { BookUpdateDto bookUpdateDto = Mapper. if (item == null) return NotFound(); Map(existingEntity); { } patchDoc.ApplyTo(bookUpdateDto, return NotFound(); ModelState); } return Ok(Mapper.Map(item)); } TryValidateModel(bookUpdateDto); Mapper.Map(updateDto, item);

[HttpPost(Name = nameof(Add))] Mapper.Map(bookUpdateDto, existingEntity); _bookRepository.Update(id, item); public ActionResult Add([ Book updated = _bookRepository. FromBody] BookCreateDto bookCreateDto) Update(id, existingEntity); if (!_bookRepository.Save()) { { if (bookCreateDto == null) if (!_bookRepository.Save()) throw new Exception("Updating an item { { failed on save."); return BadRequest(); throw new Exception("Updating an item } } failed on save."); } return Ok(Mapper.Map(item)); Book toAdd = Mapper. } Map(bookCreateDto); return Ok(Mapper.Map(updated)); } } _bookRepository.Add(toAdd); [HttpDelete] if (!_bookRepository.Save()) [Route("{id:int}", Name = nameof(Remove))] { public IActionResult Remove(int id) throw new Exception("Creating an item {

www.basta.net 62 DOSSIER HTML5 & JavaScript

Mit dotnet add Back­end.csproj pa- ckage Swashbuckle. AspNetCore können wir das NuGet-Paket hinzufügen. Nach- dem es in die *.csproj eingefügt wurde, können wir es in der Startup.cs-Datei ver- wenden (Listing 10). Swagger generiert ein JSON-File als Be- schreibung unseres APIs, das wir mittels der SwaggerUi in ein leserlicheres User In- terface gießen lassen können. Nachdem Abb. 1: Von Swagger generiertes UI das API gestartet ist, können wir das Dokumentation mit Swagger UI via https://localhost:5001/swagger anzeigen lassen Nicht nur wenn ein API von anderen, eventuell projekt- (Abb. 1). fernen Entwicklern oder Teams verwendet werden soll, Um das Suffix swagger nach der Adresse des Servers bietet sich eine Dokumentation des APIs an. Auch für die zu sparen, können wir auch den RoutePrefix auf einen bessere eigene Übersicht ist eine gute Dokumentation sehr leeren String setzen: hilfreich. Damit wir keine endlosen Word-Dokumente ausfüllen, pflegen und aushändigen müssen, gibt es die Lö- app.UseSwaggerUI(c => sung, unser API elektronisch dokumentieren zu lassen und { die Dokumentation via Endpunkt zur Verfügung zu stel- c.SwaggerEndpoint(“/swagger/v1/swagger.json”, “Version 1”); len. Swagger [3] bietet eine solche Lösung an, die wir mit c.RoutePrefix = string.Empty; wenigen Handgriffen in unserem Web-API nutzen können. });

Listing 8 Listing 10 services.AddCors(options => public void ConfigureServices(IServiceCollection services) { { options.AddPolicy("AllowAngularDevClient", // ... builder => services.AddSwaggerGen(c => { { builder c.SwaggerDoc("v1", new Info { Title = "My first ASP.NET Core WebAPI", .WithOrigins("http://localhost:4200") Version = "v1" }); .AllowAnyHeader() }); .AllowAnyMethod(); // ... }); } }); public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env) { Listing 9 // ... app.UseSwagger(); public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, app.UseSwaggerUI(c => IHostingEnvironment env) { { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Version 1"); // ... }); app.UseCors("AllowAngularDevClient"); // ... // ... } }

www.basta.net 63 DOSSIER HTML5 & JavaScript

Jetzt ist die Swagger-Dokumentationsseite eben­falls un- Abb. 2: Aufteilung in ter der Serveradresse https://localhost:5001/ sichtbar, Module was das Anzeigen noch einmal etwas vereinfacht. Natürlich bietet ASP.NET Core noch viel mehr Mög- lichkeiten: WebSockets mit SignalR, Exception Hand- ling, Configuration, Queryparameter und Arbeiten mit unterschiedlichen Environments sind einige der Möglich- keiten, die den Rahmen dieses Artikels sprengen würden. Widmen wir uns nun der Clientseite mit Angular. Im nächsten Abschnitt wollen wir das erstellte ASP.NET- Core-Web-API benutzen, Bücher eintragen, als gelesen markieren und auch wieder löschen. den unter http://localhost:4200 zur Verfügung. Angular Erstellen einer Angular-Applikation baut auf dem Prinzip der Komponenten auf. Diese geben Um eine Angular-Applikation zu erstellen, benutzen wir uns die Möglichkeit, unsere Applikation in viele kleine das Angular CLI, das Command Line Interface von An- Teile zu unterteilen und diese einzeln zu implementieren. gular [4]. Mit ng new angular-booktracker können wir die Applikation erstmals erstellen lassen. Aufteilung der Applikation in Module Nachdem die Applikation mit ihren Dateien erstellt Um eine Architektur auf dem Client zu erstellen, bietet wurde, können wir sie mit npm start starten. Ein Web- Angular neben den Webkomponenten selbst eine weite- server zur Entwicklung steht uns nach ein paar Sekun- re Abstrahierungsstufe: das Aufteilen der Applikation in verschiedene Angular-Module. Ein Modul separiert unse- re Applikation in logische Bereiche und einzelne Features. Sie dienen als Container für Angular Components, Pipes, Directives etc., die von dem Modul benötigt werden. Durch die Aufteilung in Module wird die Applikation DevOps Live-Workshop: wartbarer, übersichtlicher und einfacher testbar (Abb. 2). Continuous Deployment und Für unseren Booktracker sehen wir drei Module vor: Continuous Delivery für ein BooksModule, ein CoreModule und ein SharedMo- .NET-Core- und Angular- dule. Das AppModule, das auch zum Starten unserer Anwendungen Applikation benutzt wird, ist natürlich ebenfalls dabei. Das BooksModule ist für das Buchfeature zuständig. Neno Loje (www.teamsystempro.de) Das CoreModule bietet einen Container für alle unsere Dr. Holger Schwichtenberg ( Services, das SharedModule wird in unserem Beispiel www.IT-Visions.de/5Minds IT-Solutions) zur Abstrahierung von Model-Klassen und den Angu- Alle reden von DevOps. Neno Loje lar-Material-Modulen benutzt, und das AppModule und Dr. Holger Schwichtenberg zeigen brauchen wir, um unsere Applikation zu starten; zudem Ihnen an diesem Workshoptag live, wie dient es als Einstiegsmodul. es geht. Das Fallbeispiel „MiracleList“ besteht aus einem .NET-Core-basierten Module bieten außerdem die Möglichkeit des Lazy Web-API-Backend (mit ASP.NET Loadings. Wir können also das erforderliche Feature- Core und Entity Framework Core) und modul erst dann laden, wenn der Benutzer es explizit einem Cross-Plattform-Client (HTML, JavaScript, Angular). Als Werkzeuge kommen Visual Studio, Visual Studio Code, Team Foundation Server bzw. Azure DevOps, Listing 11 XUnit, Postman und Selenium/Appium zum Einsatz. export const AppRoutes: Routes = [ Nach einem Streifzug durch den Programmcode bauen { path: '', redirectTo: 'books', pathMatch: 'full' }, die beiden Experten vor Ihren Augen den serverseiti- gen Build auf inklusive der Integration von Unit-Tests. { Nach dem erfolgreichen Bauen geht es dann in die // Falls dieser Pfad angewählt wird ... Release-Pipeline. Für die Integrationstests werden in path: 'books', der Staging-Umgebung eine Datenbank und ein Web- // ... lade dieses Modul nach server hochgezogen. Erst wenn sowohl die Tests von loadChildren: './books/books.module#BooksModule' Logik und Datenzugriff, als auch der HTTP-Web-API- }, Dienste sowie die Benutzeroberflächentests „grün“ { zeigen, legen wir das Release zur Veröffentlichung vor. path: '**', Wenn der Projektleiter zufrieden ist, geht am Ende der redirectTo: 'books' Auslieferungskette das Release mit einem Mausklick in } die Produktion. ];

www.basta.net 64 DOSSIER HTML5 & JavaScript

anwählt, oder wir laden es automatisch, nachdem alle URL, der im Service fix hinterlegt ist (Kasten „Konfigu- Module ohne Lazy Loading bereits geladen wurden. ration des URLs“). Der Rückgabetyp der Methode ist Mithilfe der Routen können wir das Lazy Loading im das Observable, also der Stream der Daten, die wir von app.routing.ts festlegen (Listing 11). dem REST Call erwarten. Von außen kann man sich auf die Antwort registrieren und, je nach Antwort, reagieren. Verwenden von Angular Material Die Book-Klasse ist eine reine DTO-Klasse, die wir ge- Um fertige UI-Controls wie eine Liste oder ein Menü mäß der zu erwartenden JSON-Antwort festlegen kön- benutzen zu können, greifen wir auf Angular Material nen. Durch die Angabe des Typs wird die JSON-Antwort zurück [5]. Alle benötigten Elemente werden bei Angu- automatisch in diese Klasse serialisiert (Listing 15). lar Material in einzelnen Modulen exportiert, die wir in Die weiteren Methoden auf dem Service sind genau einem material.module.ts zusammenfassen und unserer die, die wir am API implementiert haben und auch in Applikation mithilfe des SharedModule zur Verfügung unserer Applikation brauchen (Listing 16). stellen (Listing 12). Das SharedModule re-exportiert nun das Material- Anzeigen der Daten Module, um anderen Modulen, die das SharedModule Um die Daten anzuzeigen, erstellen wir Components, die importieren, ebenfalls Zugriff auf die Exports des Mate- ein HTML-Template haben. Wir geben den eben erstell- rialModule zu bieten (Listing 13). ten Service via Dependency Injection in die Components hinein und rufen die entsprechenden Methoden auf. Die Kommunikation mit dem API Man kann hierbei Komponenten in zwei verschiedene Bevor wir Daten anzeigen oder darstellen können, Arten aufteilen: Presentational Components und Con- müssen wir sie vom API abrufen, das wir soeben er- tainer Components [6]. Erstere fokussieren sich darauf, stellt haben. Dazu erstellen wir einen Service, der uns wie Daten dargestellt werden, aber kümmern sich nicht die Kommunikation mit dem API abstrahiert und mit- darum, wie Daten geladen werden oder woher sie kom- tels Methoden zur Verfügung stellt. Der HttpClient aus men. Container Components haben eine Abhängigkeit dem @angular/common/http-Modul sowie der Import zu einem Repository oder Daten-Service und empfangen des HttpClientModule aus Angular stellt uns genau die Events von Presentational Components. Presentatio- HTTP-Verben zur Verfügung, die wir brauchen (Lis- nal Components bekommen die Daten übergeben und ting 14). Die @Injectable({ provide- dIn: ‚root‘ })-Syntax fügt unse- ren Service in den Root Injector Listing 12 Listing 14 von Angular ein. Somit steht import { NgModule } from '@angular/core'; @Injectable({ providedIn: 'root' }) der Service in unserer Anwen- import { ... } from '@angular/material'; export class BookService { dung zur Verfügung. Durch die private url = `https://localhost:5001/api/books`; Syntax constructor(private re- const materialModules: any[] = [ constructor(private readonly http: HttpClient) {} adonly httpBase: ­HttpClient) // ... alle benötigten Material Modules // alle Methoden {} benutzen wir die Dependen- ]; } cy Injection von Angular auf der einen Seite, auf der ande- @NgModule({ ren Seite registrieren wir eine imports: materialModules, private Property in der Klasse exports: materialModules Listing 15 BookService namens „http“, }) export class Book { auf das wir von allen Metho- export class MaterialModule {} id: number; den aus zugreifen können. read: boolean; Um nun beispielsweise alle title: sting; Bücher abzufragen, schicken author: string; wir einen GET-Request an den description: string; URL https://localhost:5001/ Listing 13 genre: string; api/books: } import { NgModule } from '@angular/core'; getAllBooks() { import { MaterialModule } from './material.module'; return this.http.get(this.url); } @NgModule({ Konfiguration des URLs imports: [MaterialModule], Der URL kann durch verschiede- Wir rufen die GET-Methode exports: [MaterialModule] ne Möglichkeiten konfigurierbar auf, legen den generischen }) gemacht werden: Environments, Rückgabetyp auf Book[] fest export class SharedModule {} Config-Url-Requests etc. und verwenden als Ziel den

www.basta.net 65 DOSSIER HTML5 & JavaScript

kümmern sich um die Dar- mittels eines Events Bescheid, falls jemand ein Buch als stellung, während Container gelesen markiert hat. Components sich darum sor- Angular bietet uns hierfür die @Input()- und gen, wo die Daten herkom- @ Output()-Decorators an, mit denen wir eingehende men, und über Services mit Daten und ausgehende Events auf Properties der Com- beispielsweise einer REST- ponent-Klasse markieren können (Listing 17). Schnittstelle kommunizieren Um diese Properties mit Daten zu füllen bzw. sich auf können. Das macht Presen- Events der Component zu registrieren, verknüpfen wir tational Components extrem die Component im HTML mit der Parent Component: wiederverwendbar und die Sie verwendet die Child Component mittels ihres Selec- Stellen im Code, die den Sta- tors im HTML, bindet Daten an die Properties und re- tus einer Applikation mani- gistriert sich auf Events (Listing 18). pulieren, übersichtlicher. Wir binden also zwei Properties der Parent Compo- Abb. 3: Komponentenauftei- lung im Projekt So können wir auch die nent readBooks und unreadBooks an die Input-Property Komponenten in unserem der Child Component app-book-list, die wir hier sogar Projekt aufteilen (Abb. 3). wiederverwenden können.

List Component Übersichts-Component Die books-list.component.ts empfängt eine Collection In der Component-Klasse der Parent Component füllen von Büchern als Input und kümmert sich um die visuelle wir diese beiden Listen ab (Listing 19). Darstellung dieser Auflistung mit einer Liste aus Angu- Via Dependency Injection bekommen wir den BookSer- lar Material. Sie sagt der sie verwendenden Component vice in den Konstruktor übergeben und speichern ihn in ei- ner internen Variablen bookService. Danach speichern wir das Observable für alle Bücher, ungeachtet des read-Status, Listing 16 in einer Observable und erstellen zwei weitere Observab- les: unreadBooks$ und readBooks$ (Kasten „$-Suffix“). getAllBooks() { return this.http.get(this.url); Async Pipe } Damit wir uns nicht manuell via subscribe(...) an die getSingle(bookId: number) { Auflösung der Observable hängen müssen, können return this.http.get(`${this.url}/${bookId}`); wir sie an das Template binden und die Daten mit der } Async Pipe auflösen. Das bietet den Vorteil, dass un- ser Code in der Component leserlicher wird und wir update(updated: Book) { return this.http.put(`${this.url}/${updated.id}`, updated); } Listing 18 add(book: Book) { return this.http.post(this.url, book); } return this.http.delete(`${this.url}/${bookId}`); } Listing 17 @Component({ /*...*/ }) export class BookListComponent implements OnInit { „$“-Suffix @Input() Das $-Zeichen am Ende einer Variable (auch finni- books: Book[] = []; sche Notation genannt) macht es uns Entwicklern @Output() einfacher, zu erkennen, hinter welcher Variablen ein bookReadChanged = new EventEmitter(); bereits aufgelöster Wert liegt und welche Variable // ... einen Stream darstellt, dessen Wert irgendwann in } Zukunft aufgelöst wird.

www.basta.net 66 DOSSIER HTML5 & JavaScript

uns nicht um das unsubscribe kümmern müssen, falls Um die Daten der Observable im Template an eine die Component von Angular wieder zerstört wird. Die Variable binden zu können, bietet Angular uns eine Async Pipe macht das automatisch für uns [7]. *ngIf-as-Syntax an, die wir hier im Einsatz sehen:

Listing 19 export class BooksOverviewComponent implements OnInit { unreadBooks$: Observable; readBooks$: Observable; *ngIf=“unreadBooks$ | async as unreadBooks“ füllt uns den Inhalt der Observable an eine Variable unreadBooks, constructor(private readonly bookService: BookService) {} die wir im Scope des HTML-Elements verwenden. Jede Verwendung einer Async Pipe im Tem­plate gleicht ngOnInit() { also der Verwendung eines subscribe(...) im TypeScript- this.getAllBooks(); Code. Dadurch, dass wir zwei Async Pipes verwenden, } feuern wir die Observable zweimal, sodass eigentlich zwei Requests an unseren Server geschickt werden müssten. private getAllBooks() { Damit wir den Server und unser API nicht unnötig const allBooks$ = this.bookService.getAllBooks().pipe( belasten, können wir einen „Cache“ einbauen, den RxJs publishReplay(1), uns anbietet: refCount() ); const allBooks$ = this.bookService.getAllBooks().pipe( publishReplay(1), this.unreadBooks$ = allBooks$.pipe( refCount() map(books => books.filter(book => !book.read)) ); );

this.readBooks$ = allBooks$.pipe( publishReplay(1), refCount() speichert uns den letzten map(books => books.filter(book => book.read)) Call auf der Observable, ohne nochmal einen neuen ); Aufruf zum API zu starten. Die Alternative wäre ein ma- } nuelles subscribe(...), das Filtern des Ergebnisses mit der } filter(...)-Funktion und die Zuweisung in zwei Arrays

Listing 20 Mobile & Desktop: Cross-Platt- @NgModule({ form mit Electron und Cordova – declarations: [/*...*/], eine Einführung imports: [ Fabian Gosebrink // ... (Offering Solutions / Developer Academy) RouterModule.forRoot([ SPA Frameworks wie Angular ha- { path: '', redirectTo: 'books', pathMatch: 'full' }, ben sich als Frontend-Plattformen für { Businessapplikationen etabliert und path: 'books', schaffen die Möglichkeit, auch gro- loadChildren: './books/books.module#BooksModule', ße Anwendungsszenarien im Web }, abzubilden. Der Desktop und mobile Platformen sind { jedoch als Zielplatformen ebenfalls relevant und sollten path: '**', bei modernen Applikationen nicht fehlen. Mit Frame- redirectTo: 'books', works wie Cordova und Electron ist es ein Leichtes, die }, Webanwendung auch als App oder Desktopanwen- ], { useHash: true }), dung auszuliefern, ohne dabei auf native Funktionen ], zu verzichten. In diesem Talk zeigt Fabian Gosebrink am Beispiel einer Angular-App, wie aus der Codebasis providers: [], der Webanwendung eine Anwendung für den Desktop bootstrap: [...], und eine mobile Anwendung erstellt werden können. }) Alle Plattformen aus nur einer Codebase – eben mehr export class AppModule {} als „nur“ Web!

www.basta.net 67 DOSSIER HTML5 & JavaScript

auf der Component. Dieser Mehraufwand würde die Template der AppComponent können wir dies an die Async Pipe obsolet machen. Stelle schreiben, die dynamisch ersetzt werden soll:

Routing Um zwischen verschiedenen Templates von Compo- nents zu wechseln, arbeiten wir mit Routing auf der Clientseite. Um das Routing zu aktivieren, importie- ren wir das RoutingModule im AppModule und konfi- gurieren es mit der forRoot(...)-Methode (Listing 20). Somit können wir festlegen, bei welchem Begriff Basierend auf der Route wird an der Stelle von router- (path) zu welcher Komponente gesprungen werden outlet jetzt die jeweilige Komponente angezeigt. soll. Mit der Property loadChildren und der bereits gezeigten Syntax können wir das Lazy Loading dieses Forms Moduls aktivieren und die Routen des Child-Moduls Natürlich kann man Informationen mit Angular-Daten verwenden. Ebendiese können wir mit der Methode nicht nur anzeigen, sondern sie auch an den Server sen- forChild(...) konfigurieren, sie sollte zum Konfigureren den. Wir haben die entsprechende POST-Methode am in der Applikation nur einmal auf dem AppModule ver- Server und in unserem Service schon implementiert. wendet werden (Listing 21). Um dem Benutzer die Möglichkeit zu geben, neue Bü- Somit definiert das BooksModule seine eigenen cher zu erstellen oder zu bearbeiten, können wir Reac- Routen und wird komplett – also mit seinen Routen – tive Forms verwenden. Zuallererst importieren wir das geladen. Der Verweis im App Module ist quasi der Ein- ReactiveFormsModule und alles, was dieses Modul ex- stiegspunkt zum Modul. Routen des Root-Moduls und portiert, in unser Modul (Listing 22). des Child-Moduls werden einfach konkateniert. Mit Reactive Forms [8] erstellen wir die Form im Code Um die Templates der Komponenten darstellen zu der Component, binden die erstellte FormGroup an das können, benötigen wir einen auswechselbaren Teil, den Template und stellen die FormControls dar (Listing 23). Angular mit den Templates der Komponenten ersetzt. Wir können der Property form eine neue FormGroup Das RouterModul exportiert hierbei das router-out- zuweisen, die ein Objekt mit Properties bekommt, die let, das uns genau diese Funktionalität bereitstellt. Im die einzelnen FormControls id: new FormControl(‚‘) etc. darstellen. Als Parameter empfängt das FormControl- Objekt hier den Defaultwert. Man kann zusätzlich auch Validatoren oder Optionen mit angeben. In unserem Fall Listing 21 geben wir den Required Validator mit, der festlegt, dass @NgModule({ die Form diesen Wert benötigt, um valide zu sein. imports: [ Ist dieses Objekt abgefüllt, können wir es im Tem- RouterModule.forChild([ plate verwenden und unsere Form aufbauen (Lis- { path: '', redirectTo: 'overview', pathMatch: 'full' }, ting 24). { path: 'overview', component: BooksOverviewComponent }, { path: 'create', component: BookFormComponent }, { path: 'edit/:id', component: BookFormComponent }, Listing 23 { path: 'details/:id', component: BookDetailsComponent } ]) import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; ] }) @Component({ export class BooksModule {} /*...*/ }) export class BookFormComponent implements OnInit { form: FormGroup; Listing 22 import { ReactiveFormsModule } from '@angular/forms'; ngOnInit() { this.form = new FormGroup({ id: new FormControl(''), @NgModule({ title: new FormControl('', Validators.required), imports: [ author: new FormControl('', Validators.required), // ... description: new FormControl('', Validators.required), ReactiveFormsModule genre: new FormControl('') ] }); }) } export class BooksModule {} }

www.basta.net 68 DOSSIER HTML5 & JavaScript

Wir erstellen eine Form mit dem HTML-

-Tag Die Methode addGroup() auf der Component benutzt und binden sie an die Direktive formGroup, die vom erneut den zur Verfügung gestellten BooksService, um ReactiveFormsModule exportiert wird. Innerhalb dieses das Buch abzusenden. Der Property Value auf der Form HTML-Form-Tags stehen dann die Controls der Form stellt uns alle Form-Controls zur Verfügung, die wir so zur Verfügung, die wir an die entsprechenden HTML absenden, am Backend entgegennehmen und eintragen Controls binden können. können (Listing 25). Um die Form abzusenden, bietet uns Angular eine Damit der Benutzer weiß, dass das Hinzufügen erfolg- weitere Direktive ngSubmit an, die wir wie folgt ver- reich war, können wir noch eine Meldung anzeigen oder wenden können: anderweitig entsprechend reagieren.

Zusammenfassung Wir können mit einer serverseitigen Technologie wie Die Methode addBook() wird also mittels Event Bind­ ASP.NET Core moderne und flexible Backend-Appli- ing aufgerufen, wenn die Form abgeschickt wird. Der kationen bauen, die wir nicht nur von Angular aus nächste Schritt ist ein Button, mit dem wir die Form ab- konsumieren können. Tools wie das dotnet CLI, die schicken können: Dependency Injection, das automatische Neustarten des Servers, die Geschwindigkeit, und dass man zum Entwickeln nicht nur Visual Studio, sondern jeden beliebigen Editor benutzen kann, machen ASP.NET Core extrem flexibel und das Erstellen von Webappli-

kationen auch jenseits des Web-API sehr einfach. Die Trennung von Front- und Backend setzt dazu auf eine Angular bietet uns die Möglichkeit an, HTML Pro- sehr hohe Flexibilität und Entkopplung. perties zu binden, wie im Codebeispiel die disabled- Angular als moderne Webplattform – mit Tooling wie Property des Buttons. Wir können den Button inaktiv etwa dem Angular CLI und Features wie Dependency setzen, wenn die Form selbst invalid ist, also mindes- Injection, das Aufteilen in Module, Lazy Loading etc. – tens eine ihrer Controls nicht valide ist (form.invalid) ermöglicht es, auch große Applikationen im Web mit oder die Form noch nicht verändert wurde (form.pris- Struktur und Architektur in TypeScript umzusetzen. tine). Wer hätte vor ein paar Jahren gedacht, dass man solche Architekturen – auf dem Client und letztendlich mit Ja- vaScript – entwickeln kann? Listing 24

Fabian Gosebrink ist Google Developer Expert für An-
gular und Webtechnologien, Microsoft MVP und We- bentwickler im Bereich ASP.NET Core und Angular. Als Professional Software Engineer, Consultant und Trainer berät und unterstützt er Kunden bei der Umsetzung von Webapplikationen im Front- bzw. Backend bis hin zum mobilen Bereich.

Listing 25 export class BookFormComponent { Links & Literatur constructor( private readonly bookService: BookService, [1] https://github.com/FabianGosebrink/Angular-Booktracker private readonly notificationService: NotificationService [2] https://www.microsoft.com/net/download ) {} [3] https://swagger.io/solutions/api-documentation/ [4] http://cli.angular.io addBook() { [5] https://material.angular.io/ this.bookService .add(this.form.value) [6] https://blog.angular-university.io/angular-2-smart-components-vs- .subscribe(() => this.notificationService.show('Book added')); presentation-components-whats-the-difference-when-to-use-each-and- why/ } } [7] https://angular.io/guide/pipes#the-impure-asyncpipe [8] https://angular.io/guide/reactive-forms

www.basta.net 69 DOSSIER HTML5 & JavaScript

Dependency Injection in unter 200 Zeilen Code – ohne Leerzeilen Injections für echte TypeScript-Junkies Dependency Injection hat sich bei den meisten Softwareprojekten, Frameworks und Apps durchgesetzt. Dennoch ist es erstaunlich, wie viele Fragen man in diversen Foren im Kon- text von JavaScript Frameworks zu diesem Thema findet. Muss Dependency Injection kompliziert sein? Wir meinen nicht. Mit TypeScript MetaData und Decorators lässt sich eine sehr kompakte, aber wirkungsvolle Dependency Injection aufbauen.

von Thomas Mahringer Was hat das mit JavaScript zu tun? In der guten alten Zeit, in der Web-Apps serversei- Spätestens seit dem Java Spring Framework hat sich tig, z. B. über MVC-Frameworks, gerendert wurden, Inversion of Control oder Dependency Injection (DI) beschränkte sich JavaScript auf die dynamische Ma- als Designpattern etabliert. Die damals noch nicht nipulation des DOMs und evtl. auch noch auf Ajax- so verbreitete Idee war es, Methoden, Klassen und Datentransfer. jQuery, ähnliche Frameworks und ihr Module so zu entwerfen, dass sie durch ihre Schnitt- Programmiermodell saßen fest im Webstack-Sattel. Wie stellen wirklich vollständig beschrieben sind. Das be- Sie wissen, hat sich die Situation mit voll ausgewach- deutet, dass sie kein implizites oder globales Wissen senen JavaScript-Clientapplikationen stark verändert, mitbringen müssen, um korrekt zu funktionieren. Ein denn sie sind eigentlich Rich Clients (Single-Page-Ap- Gegenbeispiel dazu wären verschiedene Arten von Ser- plikationen), die mit Backends kommunizieren. Statt vice-Locator-Patterns oder, noch schlimmer, mehrere jQuery und Co. finden wir MVVC-Patterns und reakti- globale Objekte, die Services bereitstellen. Diese Mus- ve Programmierung. Frameworks wie React.js, Angular ter sind Antimuster, bei denen Methoden wissen, wo und Vue.js sind wohlbekannt, und mit Progressive Web sie nachsehen müssen, um benötigte Services zu bezie- Apps wird die Lücke zwischen echter App und Web- hen, z. B. für Datenzugriff, Authentifizierung usw. Der App nochmal deutlich verkleinert. Zugriff auf die Services erfolgt global, beispielsweise Wenn wir heute von JavaScript-Clients sprechen, mei- über static-Methoden wie ServiceLocator.getData- nen wir daher in der Regel ausgewachsene Softwaresys- Source(), DataAccess.getDataSource() oder Security. teme, bei denen wir den gleichen Herausforderungen getAuthenticationService(). Je mehr von diesen globa- gegenüberstehen wie bei traditionellen Rich Clients. len Abhängigkeiten umherschwirren, desto undurch- Daher wird es ganz selbstverständlich, dass wir zum De- schaubarer wird der Code, und er lässt sich vor allem signen unserer Softwarebausteine Designpatterns wie nicht mehr modular Unit-testen, da sämtliche globalen Dependency Injection verwenden. Objekte in den richtigen Testzustand versetzt werden müssen. Bei der DI oder Inversion of Control läuft es TypeScript Fanboy eben umgekehrt: Nicht die einzelnen Codefragmente Wie die regelmäßigen Leser vermutlich wissen, bin ich wissen, woher sie Services beziehen, sondern Letztere ein TypeScript-Fanboy. Bei den heutigen komplexen werden ihnen beim Aufruf einfach mitgegeben, z. B. (mobilen) Web-Apps wird eine statische Typisierung, als Konstruktorargumente. Damit sind jedes Code- die die Flexibilität von JS nicht einschränkt, zum ALM stück, jede Klasse und Methode wirklich eindeutig Lifesaver. Wenn man dann noch Frameworks wie bei- durch ihre Schnittstellen definiert. spielsweise React.js verwendet, die UI-Komponenten

www.basta.net 70 DOSSIER HTML5 & JavaScript

nach JavaScript/TypeScript transpilieren, hat man ein langersehntes Ziel der UI-Entwick- lung erreicht: UI-Komponenten sind statisch typisiert und werden vom Compiler über- prüft. Vorbei sind die Zeiten, in denen man erst während des Betriebs bemerkt, dass auf- grund von Typos im Data Binding Fehler zur Laufzeit auftreten. Hatten Sie auch schon mal das Property fristName als Data Binding in einer UI-Komponente?

TypeScript Decorators und Metadata Aber genug der Schwärmerei. TypeScript- Code lässt sich ähnlich wie in .NET mit At- Abb. 1: Vereinfachter Ablauf: Laden des Codes und Ausführen der App tributes oder wie in Java mit Annotations mit Metainformationen anreichern, die in Ty- das macht den Unterschied zwischen .NET Attributes peScript „Decorators“ heißen. Einen ersten Decorator und TypeScript Decorators aus: Decorators sind Funk- sehen wir hier: tionen, nicht nur Labels oder Tags. „Ja, und?“ kann man jetzt fragen. Und die Antwort @injectionTarget() lautet: „Man kann in Decorators alles tun – alles, was class TestClass { man in JS-Funktionen auch tun kann.“ Um es gleich konkreter zu machen, werfen wir einen Blick auf Lis- } ting 1, wo wir sehen, was der TS-Transpiler aus dem @ injectionTarget() macht. Die Klasse TestClass wird mit dem Decorator @injec- Es wird die Funktion __decorate aufgerufen, die als Pa- tionTarget() dekoriert. Daher wird dieser Decorator rameter unseren Decorator erhält. Ohne auf die Details Klassen-Decorator genannt. Wie wir sehen werden, gibt der __decorate-Funktion einzugehen, führt das dazu, dass es u. a. auch noch Parameter-Decorators. zur Ladezeit unserer Testklasse der Decorator mit der Unsere Testklasse erhält dadurch die Metainfor- Klasse als Parameter aufgerufen wird. Das ist auch schon mation, dass offensichtlich irgendetwas in diese Klas- die Hauptidee: Wir haben nun die Klasse in der Hand und se injiziert wird. Aber bei TypeScript bzw. JavaScript können sie manipulieren. Wir werden später noch auf die kommt ein entscheidender Vorteil einer interpretierten Codedetails des Decorators eingehen. Skriptsprache zum Tragen: Wenn eine Skriptdatei ge- laden wird (über

Web Analytics