AVRO ist derzeit ein sehr populäres Serialisierungs-Framework. Dank Schemaregistry für Enterprise-Anforderungen bestens gerüstet. Es macht Sinn, die generierten Klassen im Code zu verwenden - allerdings ist der Code dann oft mit Zusatzcode zugepflastert, der mit der generierten Klasse interagiert, obwohl die Funktionalität eigentlich besser in die integrierte Klasse passen würde.
Ein kurzer Exkurs: Große Schemas verwalten Ein Finding war, dass komplexe Schemas in einer *.avsc File wenig Sinn machen. Die Herausforderung ist, dass beim ersten Vorkommnis ein record typ definiert wird und bei weiterer Verwendung nur mehr referenziert wird – das ist echt mühsam.
Microservices sind ein beliebtes Tool, um komplexe Domänen zu zerteilen. Doch am Ende des Tages macht die Entscheidung des übermäßigen Einsatzes – in manchen Fällen – dann mehr Kopfweh als Nutzen. Vor Kurzem ist mir dabei folgendes Beispiel im Zuge einer Diskussion in den Sinn gekommen:
Schauen wir uns einen Teil eines Webshops an:
Order Management mit der Aufgabe den Bestellvorgang abzuwickeln Pay Service mit der Aufgabe der Bezahlung Neben fachlichen Aspekten, die für das Schneiden wichtig sind, welche Eigenschaft sind noch wichtig? Stabile Interfaces. Schaut man sich diese an, so merkt man, dass diese relativ einfach sind und eigentlich über die Zeit hinweg stabil sein sollten: Pay Service: Input Parameter: Geldbetrag
Wann macht Table-Partioning Sinn? Vor kurzem hatte ich die Aufgabe, eine Liste aus Rechnungen filterbar zu machen – das schwierige dabei war, dass die Anzahl der Rechnungen nicht bekannt ist und diese auch noch hierarchisch waren (1 Rechnung hat 0..n Positionen – wobei die Positionen von unterschiedlichem Typ sein können). Ebenfalls war die Anforderung “über Jahre hinweg eine stabile Performance zu haben”.
Herausforderung 1: Die Pagination in der Übersichtsliste von Rechnungen ist auf der Rechnung – d.h. 10 Element auf der Seite entspricht 10 Rechnungen mit 0..n Positionen. Was bei großen Tabelle gut funktioniert, ist das Suchen nach gewissen Kriterien: e.g. gib mir alle Positionen mit der SomeValue = 123:
Wenn man im Projekt die Situation hat, dass man z.B. zwei unterschiedliche Personen hat, welche einerseits den OpenAPI Contract schreiben und anderseits implementieren, macht es Sinn, den Contract-First Approch zu verfolgen.
Bei .NET geht das nicht so out-of-the-box, wie z.B. bei Spring mit Maven.
Schritt 1: NSwag Studio laden
Das neueste NSwag Studio kann man von hier beziehen: https://github.com/RicoSuter/NSwag/releases. In NSwag kann man den OpenAPI Contract pasten und on-the-fly generieren lassen.
Ein gutes Beispiel bekommt man hier: https://editor-next.swagger.io/
Bei Domain-Driven-Design gibt es zwei Flughöhen:
Strategic: Hier befasst man sich mit dem „schneiden“ der Domänen Tactical: Hier geht es bis in die Implementierung Ich möchte meine Gedanken zu Tactical zu Blatt bringen.
Analyse von Aggregaten Aggregate umschließen jene Entitäten, welche eine atomare Einheit bilden sollen. Das hört sich auf den ersten Blick nutzlos an – aber in fast allen Applikationen muss man von parallelem arbeiten an einem Datensatz durch mehrere Personen ausgehen. Und hier ist das Thema Konsistenz dann ein großes Thema.
Welche Funktionalität ist in meiner Software? Diese Frage ist oft in agilen Projekten nicht einfach zu beantworten – zumindest seriös. Ist das Benutzerhandbuch die einzig valide Quelle? Folgende Vorgehensweise habe ich kennengelernt (es gibt auch viele andere):
1. User-Story Map Als erstes versucht man die User-Stories zu priorisieren. Da kann eine User-Story Map helfen, um eine gute End-to-End-Sicht zu bekommen. Wichtig ist nur zu verstehen: Man soll nicht versuchen, alles in eine User-Story Map zu pressen – man kann ohne weiteres mehrere haben.
Azure Subscription Die Reise beginnt in Azure. Man muss eine Subscription anlegen - dort werden die Zahlungsdaten hinterlegt. Wichtig ist, dass man ein Budget anlegt (Achtung: Es kann bis zu 24h dauern, bis man ein Budget bei einer neuer Subscription anlegen kann).
Repository Beginnen tut die Reise in Azure DevOps: Falls noch nicht passiert, muss man eine Organisation anlegen.
Genauere Infos gibt es in der Dokumentation.
Als nächstes muss man Azure DevOps und Azure verbinden. Dazu geht man in die Organization Settings. Die TenantId bekommt man aus Microsoft Entra.
SQL Server Als erstes möchte ich das ganze bei SQL Server ausprobieren. Dazu starten wir eine Instanz in Docker:
version: "3.8" services: sqldata: image: mcr.microsoft.com/mssql/server:2017-latest environment: - SA_PASSWORD=Pass@word - ACCEPT_EULA=Y ports: - "5434:1433" Danach erstellen wir eine Tabelle:
CREATE TABLE master.dbo.Persons ( PersonID int NOT NULL PRIMARY KEY IDENTITY, LastName varchar(255) NOT NULL ); Anschließend fügen wir einen Datenatz ein:
INSERT INTO master.dbo.Persons (LastName) OUTPUT INSERTED.PersonID VALUES('Mustermann'); Macht man nun in Transaktion 1:
Die meisten Anbieter haben inzwischen Lösungen für Cloud-Drives (OneDrive von Microsoft, Google Drive, Apple iCloud). Doch ab und zu schläft man besser, wenn man noch ein zusätzliches Backup hat.
Amazon Glacier Amazon Glacier ist kinderleicht zu bedienen und extrem kostengünstig. Das Anfordern des Inventars kann schon einige Stunden in Anspruch nehmen, aber ein Backup braucht man ja nicht jeden Tag. Wir reden hier von ca. 60cent pro Monat für 80GB. Man lädt die Inventar Metadaten lokal und synced dann. Storage Class ändern ist nicht erforderlich.
Vorweg: es war nicht unbedingt notwendig. Aber ich habe mir vor 3 Jahren einen ThinkPad T14 gekauft – leider mit AMD. Aktuell habe ich auch einen T15 mit Intel und einen HP mite Intel und Nvidia (beides Arbeitslaptops). AMD bedeutet: USB mit externen Monitoren – kann funktionieren – muss aber nicht. Bluetooth reagiert nicht mehr? Kann passieren. TouchPad spielt verrückt (hat wahrscheinlich nichts mit AMD zu tun) – passiert – wurde dann gewechselt. Und wenn man nach AMD googelt: Funktionierende Treiber schreiben, scheint nicht die Stärke von AMD zu sein. Intel und Nvidia funktionieren einfach zuverlässiger.