FreshRSS

🔒
✇ Developer-Blog - ÜberKreuz

LLMs erobern den Browser: Chrome experimentiert mit Built-in-AI-APIs

Von Christian Liebel — 06. Februar 2025 um 12:02
Kopf einer künstlichen Person mit verschiedenen Icons daneben, die mit dem Gesundheitsbereich zu tun haben.

Dank KI können Entwickler viele neue Anwendungsfälle umsetzen. Die Built-in-AI-APIs bringen KI-Modelle auf das eigene Gerät.

(Bild: Fabio Principe/ Shutterstock.com)

Chatbots und andere Use Cases rund um natürliche Sprache laufen dank der Built-in-AI-APIs direkt im Browser. Erste APIs können Developer in Chrome testen.

Generative KI legt den Grundstein für zahlreiche Anwendungsfälle, die vorher schwierig oder gar nicht umzusetzen waren. Sie legt den Fokus auf das Verarbeiten und Erzeugen von Inhalten wie Text, Bildern, Audio und Video mithilfe von Machine-Learning-Modellen: In der Trainingsphase werden sie mit erheblichen Datenmengen trainiert und können dann aus ihnen völlig unbekannten Situationen sinnvolle Zusammenhänge schließen, in denen regelbasierte Algorithmen an ihre Grenzen stoßen.

Large Language Models sind Tausendsassas

Large Language Models (LLMs) beschränken sich auf das Verarbeiten und Erzeugen von Text in natürlicher Sprache. Sie sind bereits zu einem wichtigen Baustein in der Softwarearchitektur geworden: LLMs können Inhalte übersetzen, Daten aus unstrukturiertem Text extrahieren, längere Textabschnitte präzise zusammenfassen, Code schreiben oder interaktive Dialoge mit dem Anwender führen.

Bislang führte der Weg zur Nutzung von LLMs praktisch immer in die Cloud. Gerätehersteller sind jedoch dazu übergegangen, LLMs mit ihren Geräten und Betriebssystemen auszuliefern: Die Funktionen von Apple Intelligence wie das Zusammenfassen mehrerer Benachrichtigungen werden durch ein lokales LLM ausgeführt [1]. Google liefert High-End-Smartphones mit seinem LLM Gemini Nano aus [2] und Microsoft bringt mit der Windows Copilot Runtime sein LLM Phi Silica auf Windows-Geräte [3].

Lokal ausgeführte LLMs schützen Privatsphäre

Lokal ausgeführte LLMs sind auch offline verfügbar, haben ein verlässliches Antwortverhalten unabhängig von der Netzwerkqualität und die Userdaten verlassen das Gerät nicht, was die Privatsphäre des Anwenders schützt. Da LLMs aber einen großen Speicherplatzbedarf haben, werden oftmals eher kleinere LLMs eingesetzt, die eine geringere Antwortqualität haben. Die Performance hängt zudem vom Endgerät ab.

Sechs Built-in-AI-APIs stehen zur Verfügung

Im Rahmen seiner Built-in-AI-Initiative [4] liefert Google KI-Modelle zu Testzwecken mit seinem Browser Google Chrome aus. Für die Installation werden Windows 10 oder 11, macOS ab Version 13 (Ventura), 6 GByte Video-RAM und mindestens 22 GByte freier Festplattenplatz auf dem Volume des Chrome-Profils vorausgesetzt, die heruntergeladenen KI-Modelle sind allerdings deutlich kleiner.

Nach dem initialen Download teilen sich sämtliche Webseiten den Zugriff auf diese Modelle über sechs Built-in-AI-APIs [5], die innerhalb der Web Machine Learning (WebML) Community Group [6] des W3C spezifiziert sind. Eine der APIs ist allgemein verwendbar, während der Rest aufgabenspezifisch ist:

  • Prompt API [7]: allgemein verwendbare Schnittstelle zur Ausführung von LLM-Konversationen, erlaubt neben der Implementierung von Chatbots auch Anwendungsfälle wie Ideenfindung, Sentiment-Analyse oder das Extrahieren und Klassifizieren von Daten.
  • Writing Assistance APIs [8]:
    • Summarizer API fasst Textabschnitte zusammen.
    • Writer API schreibt einen Text zu einem vorgegebenen Prompt.
    • Rewriter API schreibt einen Text nach bestimmten Wünschen um.
  • Translator and Language Detector APIs [9]:
    • Translator API übersetzt einen Text von einer Sprache in eine andere.
    • Language Detector API erkennt die Sprache, in der ein Text verfasst ist.

Während die Prompt API und Writing Assistance APIs derzeit auf das LLM Gemini Nano 2 mit 3,25 Milliarden Parametern zurückgreifen, werden für die Translation und Language Detection API intern andere Modelle genutzt.

Developer können erste APIs bereits testen

Das Chrome-Team stellt die APIs derzeit im Rahmen eines Origin Trial zur Verfügung. Dabei handelt es sich um eine Testphase für neue Webplattform-APIs. Entwickler müssen von Google ein Origin-Trial-Token beziehen [10] und mit ihrer Website ausliefern. Dann wird die Schnittstelle auf dieser Website aktiviert, auch wenn sie noch nicht allgemein verfügbar ist.

Auf diese Art können Interessierte die Translator API, Language Detector und Summarizer APIs bereits testen. Auch für die Prompt API gibt es eine Origin Trial, allerdings nur für Chrome-Erweiterungen.

Da sich die APIs noch alle im Spezifikationsprozess befinden und sich das KI-Feld stetig weiterbewegt, sind Änderungen an den Schnittstellen sehr wahrscheinlich. So soll etwa die Prompt API künftig multimodale Eingaben (neben Text auch Bilder oder Audiomitschnitte) verarbeiten können.

TypeScript-Pakete stehen zur einfachen Verwendung bereit

Mit dem Paket @types/dom-chromium-ai [11] stehen bereits TypeScript-Definitionen zur Verfügung, um die APIs bequem aus eigenem TypeScript-Code aufrufen zu können. Das Paket entspricht derzeit der in Chrome 128.0.6545.0 implementierten API. Änderungen werden mit neuen Chrome-Versionen nachgeliefert.

Das folgende Beispiel zeigt die Verwendung der Language Detector API in einer Webanwendung:

const languageDetector = await self.ai.languageDetector.create();
const review = "こんにちは!Hier esse ich einfach am liebsten Sushi."
               + "Immer super 美味しい!";
const result = await languageDetector.detect(review);
// result[0]: {confidence: 0.800081193447113, 
               detectedLanguage: 'de'}
// result[1]: {confidence: 0.0267348475754261, 
               detectedLanguage: 'ja'}

Fazit

Die Built-in-AI-APIs sind ein spannendes Experiment, das die Fähigkeiten generativer KI direkt auf das eigene Gerät bringt. Entwickler und Entwicklerinnen können im Rahmen des Early-Preview-Programms für Built-in AI [12] Feedback an das zuständige Chrome-Team richten.

Danke an Thomas Steiner für das Review dieses Blogposts.


URL dieses Artikels:
https://www.heise.de/-10256818

Links in diesem Artikel:
[1] https://www.heise.de/news/Statt-Cloud-Apples-LLM-angeblich-vollstaendig-on-device-9692827.html
[2] https://www.heise.de/news/Google-Gemini-zieht-in-Android-und-iOS-Geraete-ein-samt-Live-Funktion-9834081.html
[3] https://www.heise.de/news/Windows-Copilot-Runtime-Fundament-fuer-offene-KI-Entwicklung-mit-APIs-und-SLMs-9731468.html
[4] https://developer.chrome.com/docs/ai/built-in?hl=de
[5] https://developer.chrome.com/docs/ai/built-in-apis?hl=de
[6] https://webmachinelearning.github.io/incubations/
[7] https://github.com/webmachinelearning/prompt-api
[8] https://github.com/webmachinelearning/writing-assistance-apis
[9] https://github.com/webmachinelearning/translation-api
[10] https://developer.chrome.com/origintrials/
[11] https://www.npmjs.com/package/@types/dom-chromium-ai
[12] https://developer.chrome.com/docs/ai/built-in-apis?hl=de#participate_in_early_testing
[13] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Material UI & Co.: UI-Libraries können Ihr Projekt ruinieren

Von Golo Roden — 05. Februar 2025 um 12:02
Stilisierter Laptop und Handy

(Bild: Andrey Suslov/Shutterstock.com)

Viele Unternehmen setzen auf UI-Libraries – und kämpfen über kurz oder lang mit den damit verbundenen Nachteilen. Warum ist das so und wie macht man es besser?

Ich hätte nie gedacht, dass dieser Tag einmal kommt, aber er ist da: Wir arbeiten aktuell mit einer Behörde zusammen, und diese hat etwas geschafft, woran 99 Prozent aller Unternehmen scheitern. Sie haben eine ganz bestimmte Entscheidung strategisch richtig getroffen: Sie haben sich nämlich nicht einfach wahllos für eine UI-Library für ihre Entwicklung entschieden, sondern erst einmal ihre fachlichen Anforderungen durchdacht und darauf basierend dann technologische Entscheidungen getroffen.

Doch leider ist das die absolute Ausnahme. Denn in den meisten Fällen läuft es genau umgekehrt. Und da fangen die Probleme an. Und genau deshalb, weil das so verbreitet ist und weil man es so viel besser machen kann, als es die meisten Unternehmen da draußen tun, geht es heute um den Einsatz von UI-Libraries.

Zeit und Aufwand sparen

Ein typisches Szenario: Ein Unternehmen plant eine neue Software und hat bereits ein paar Ideen. Trotzdem ist es manchmal ganz gut, ein wenig Unterstützung zu haben, um von außen validieren zu lassen, dass man von vornherein in die richtige Richtung läuft. Genau dafür gibt es Beratungsunternehmen, wie ja nicht zuletzt auch wir eines sind. Da wir bei the native web [1] auf Web- und Cloud-Entwicklung spezialisiert sind, kommt natürlich auch immer wieder das Thema UI zur Sprache. Und da überlegen sich viele Unternehmen, dass sie für ihre UI doch auf eine Library setzen könnten, zum Beispiel Material UI, und sie glauben, damit wäre die Frage beantwortet, wie (also mit welcher Technologie) sie ihre UI bauen sollten.

Das scheint zunächst einmal sinnvoll zu sein: Immerhin sparen UI-Libraries in der Entwicklung einiges an Zeit und Aufwand. Zumindest scheint das auf den ersten Blick so. Und genau deshalb entscheiden sich Unternehmen auch so gerne dafür: Sie möchten die versprochenen Vorteile nutzen und ihre Entwicklung beschleunigen. Das – und das muss ich an dieser Stelle vielleicht noch einmal explizit betonen – ist ein völlig legitimer Wunsch und eine völlig legitime Überlegung.

Alles hat seinen Preis

Viele Unternehmen sehen aber nicht, dass dieser Ansatz seinen Preis hat. Konkret sind es vor allem drei Risiken, die man sich damit ungewollt einkauft:

  • Erstens bindet man sich an eine externe Lösung, deren Entwicklung man nicht steuern kann. Man ist, solange man ausschließlich auf das setzt, was serienmäßig vorgesehen ist, auf Gedeih und Verderb der UI-Library und den Entscheidungen des dahinterstehenden Entwicklungsteams ausgeliefert. Wenn diese sich morgen entscheiden, ein bestimmtes Control nicht mehr weiterzuentwickeln oder das Konzept hinter den Controls komplett zu ändern, dann ist das so. Und dann hat man bestenfalls noch die Option, das nächste Update nicht mitzugehen, aber das ist natürlich langfristig keine gute Option, weil man damit die Kompatibilität zu anderen Komponenten und Modulen gefährdet.
  • Das bringt mich zu Risiko Nummer zwei: Je größer eine externe Abhängigkeit wird (und wenn wir noch einmal an Material UI denken, dann ist das eine sehr große Abhängigkeit), desto größer ist die Gefahr, in eine technische Sackgasse zu geraten, aus der man nicht mehr ohne größeren Aufwand herauskommt. Denn man steht dann eventuell vor der Wahl, bei der alten Version zu bleiben oder für die neue Version die komplette UI einmal refaktorieren zu müssen. Und das ist meistens mit ziemlich hohem Aufwand verbunden, und den will, ganz plump gesagt, niemand haben. Also bleibt man häufig bei der alten Version. Und das ist ironischerweise gerade bei Material UI vielfach der Fall, weil es dort von Version vier auf Version fünf einen sehr großen Bruch gab und ich sehr viele Unternehmen kenne, die nun dauerhaft auf Version 4 hängengeblieben sind und damit langsam in die ersten Kompatibilitätsprobleme mit anderen Modulen geraten.
  • Tja, und Risiko Nummer drei sind die obligatorischen Anpassungsprobleme: UI-Libraries folgen natürlich ihren eigenen Designrichtlinien, und da stellt sich immer die Frage: Wie gut passen sie zur eigenen Corporate Identity beziehungsweise zum eigenen Corporate Design? Und meistens ist es so, dass dies nicht exakt übereinstimmt, sodass Anpassungen erforderlich sind, und dann stellt sich einfach nur die Frage: Wie leicht lassen sich diese Anpassungen umsetzen und, noch viel wichtiger: Lassen sie sich überhaupt durchführen, oder beginnt man dann plötzlich, gegen die Library oder das Framework zu arbeiten?

Und nur, damit es nicht missverstanden wird: Auch wenn ich hier schon ein paar Mal Material UI erwähnt habe, liegt das Problem nicht an Material UI! Material UI ist eine tolle UI-Library, solange Sie zufällig genau das Design wünschen, das Material UI vorgibt.

Fehlendes UI/UX-Know-How

Was wir regelmäßig erleben, ist, dass wir um eine Einschätzung gebeten werden, wie wir die Idee beurteilen, auf Material UI (oder eine andere UI-Library) zu setzen. Denn das wäre ja alles bereits vorhanden, wäre entsprechend günstig, und man käme damit sehr zügig voran, und so weiter. Viele Unternehmen sind dann überrascht, dass wir darauf vielleicht nicht ganz so begeistert reagieren.

Wir erklären dann oft, dass wir eher davon abraten würden, eine solche Library einzusetzen, einfach um zu vermeiden, dass man sich in eine große Abhängigkeit begibt, sich den Weg in die Zukunft verbaut und sich die Möglichkeit für individuelle Anpassungen nimmt. Das bedeutet, wir empfehlen in sehr vielen Fällen, die eigenen Controls zu entwickeln, und daraufhin kommt praktisch immer das Standard-Gegenargument, das sei ja so fürchterlich teuer: Denn man müsse ja auch Mobile berücksichtigen, und man müsse ja ebenfalls Accessibility berücksichtigen, und so weiter.

Aus eigener Erfahrung kann ich sagen, dass dies zum einen gar nicht so teuer ist, wie viele immer annehmen, und dass die größten Kosten in Bezug auf Mobile, Accessibility und so weiter nicht in der Implementierung, sondern in der Konzeption der Benutzerführung anfallen. Und diese Kosten entstehen ja ohnehin, ob nun mit oder ohne UI-Library. Nur glauben Unternehmen dies oft nicht, weil es für sie häufig nicht wirklich greifbar ist, da sie beispielsweise keine Erfahrung mit UX-Design haben. Sie wissen jedoch, dass Entwicklung teuer ist, also versuchen sie, an dieser Stelle Kosten zu sparen.

Ein Papagei, der nur "ja" sagen kann

Das Ganze endet dann meist damit, dass wider den Rat von außen doch eine UI-Library eingesetzt wird. Und ironisch wird es dann (und das habe ich tatsächlich schon einige Male erlebt), wenn schon nach wenigen Wochen die ersten Wünsche laut werden: Controls sollen bewusst anders aussehen, sich bewusst anders verhalten, das Ganze soll mit einem eigentlich nicht kompatiblen CSS-Framework kombiniert werden und so weiter.

Dann geschieht genau das Gegenteil von dem, was sich das Unternehmen ursprünglich erhofft hatte: Die Entwicklungskosten steigen massiv, alles dauert sehr lange, und es treten ständig merkwürdige Fehler in der UI auf, weil versucht wird, die vorgegebene Logik der Library zu umgehen. Am Ende kann das nur scheitern. Und Sie stehen dann als Berater daneben und denken sich:

"Tja, das ist genau das, was ich Euch vorhergesagt habe, aber Ihr wolltet ja keine Beratung, sondern einen Papagei, der nur "ja" sagen kann, Und eigentlich habt Ihr nur gehofft, jemanden zu finden, der Eure fragwürdige Idee von außen absegnet."

Beratung muss ehrlich sein und auch unangenehme Antworten liefern dürfen.

Ein Einzelfall?

All das ist leider kein Einzelfall – es kommt tatsächlich ständig vor. Wie schon erwähnt, ist das eigentliche Problem aber nicht die UI-Library an sich. Das Problem besteht vielmehr darin, dass Unternehmen sich für eine bestimmte Technologie entscheiden, bevor sie ihre Anforderungen wirklich verstanden haben. Da wird dann häufig mit Zeit und Kosten argumentiert, aber der springende Punkt ist: Wenn man noch gar nicht genau weiß, was man überhaupt will, kann man auch keine Technologie wählen, um das Ziel zu erreichen, denn man kennt dieses Ziel noch nicht.

Das ist, wie wenn Sie ein Fertighaus kaufen und dann die Wände herausreißen, weil Ihnen im Nachhinein auffällt, dass Sie eigentlich viel eher einen Loft-Charakter wollten. Man kann das natürlich trotzdem machen, aber es ist und bleibt doch eher eine schlechte Idee.

Das bedeutet, die richtige Reihenfolge sollte lauten:

  • Als Erstes sollten Sie sich überlegen, was Sie aus fachlicher Sicht überhaupt möchten. Wenn Sie das nicht wissen, ist die Wahrscheinlichkeit sehr hoch, dass Ihre Entwicklung komplett scheitert [3].
  • Das Zweite, was Sie sich fragen sollten, ist: Wie sind unsere Corporate Identity und unser Corporate Design, und wie sollen sich diese in einer UI widerspiegeln? Also: Wie soll sich die UI anfühlen und wie soll sie aussehen, damit sie zu Ihrem Unternehmen passt?
  • Drittens: Wie sieht auf dieser Grundlage Ihr UI-Konzept aus?
  • Und viertens: Erst wenn Sie das alles wissen, können Sie sich überlegen, welche Technologien Sie wählen, um Sie bei der Entwicklung zu unterstützen.

Von diesen vier Punkten konzentrieren sich die meisten Unternehmen jedoch auf den letzten, und insbesondere das Thema UI/UX-Konzept wird oft übergangen. Dabei ist das so ungemein wichtig. Mit anderen Worten: Bei sehr vielen Unternehmen kommt die Technik vor dem Konzept, und das führt über kurz oder lang zu absurden Workarounds.

Ein besserer Weg

Nun stellt sich die Frage: Wie kann man es besser angehen? Einen Punkt habe ich schon angesprochen: Es ist oft gar nicht so sinnvoll, auf eine UI-Library zu setzen, sondern man sollte viel häufiger eigene UI-Komponenten entwickeln. Das ist sehr viel weniger aufwendig als oft angenommen. Und der Vorteil ist: Man hat die volle Kontrolle, bleibt flexibel, bleibt unabhängig und vermeidet langfristig zahlreiche Probleme.

Noch wichtiger ist allerdings etwas anderes: Denn – und das habe ich oben ebenfalls erwähnt – grundsätzlich ist nichts falsch am Einsatz von UI-Libraries. Man muss sich nur im Vorfeld genau überlegen, ob das eine gute Idee ist. Passen sie wirklich zu 100 Prozent zu den Anforderungen? Oder gibt es doch Aspekte, die man gerne anders hätte, bei denen man bewusst vom getrampelten Pfad abweichen möchte, und macht man sich damit nicht auf lange Sicht das Leben schwerer, wenn man auf eine Standardlösung setzt?

Ich kann es nur wiederholen: Die initialen Kosten und der anfängliche Entwicklungsaufwand sind langfristig nahezu zu vernachlässigen. Denn allzu oft läuft es so ab:

"Ah, großartig, wir nehmen eine UI-Library, damit wir jetzt weniger Arbeit haben und schneller vorankommen!"

Ja, und drei Monate später sitzt man dann dort mit 10.000 Zeilen CSS-Hacks, aber Hauptsache, man hat anfangs zwei Tage Arbeit gespart …

Nicht zu den 99 % gehören

So, und da kann ich nur sagen: Begehen Sie nicht denselben Fehler! Setzen Sie sich vor einer Entscheidung für oder gegen eine Technologie intensiv mit Ihren Anforderungen auseinander und prüfen Sie dies im Hinblick auf Ihre Corporate Identity und Ihr Corporate Design. Nehmen Sie sich die Zeit, ein fundiertes UI-/UX-Konzept zu entwickeln, und beschäftigen Sie sich zumindest in einem Proof of Concept damit, wie komplex und aufwendig es tatsächlich wäre, eigene UI-Komponenten zu konzipieren und umzusetzen.

Und wie zu Beginn dieses Blogposts gesagt: Es gibt Unternehmen, die das von Anfang an richtig angehen, aber die sind leider selten. Sorgen Sie also dafür, dass Ihr Unternehmen zu diesem Kreis gehört!


URL dieses Artikels:
https://www.heise.de/-10266999

Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.youtube.com/watch?v=uRljbIxtauA
[4] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Kostenloser Vortrag zu den Neuerungen in .NET 9.0 und C# 13.0

Von Dr. Holger Schwichtenberg — 30. Januar 2025 um 10:41

(Bild: Pincasso/Shutterstock.com)

Der Vortrag in Dortmund behandelt die Neuerungen in der Syntax von C# 13.0, der .NET 9.0-Basisklassenbibliothek sowie den Anwendungsmodellen.

Ich möchte Sie kurz auf meinen nächsten ehrenamtlichen User-Group-Vortrag aufmerksam machen.

Am 5. Februar 2025 von 18 Uhr bis etwa 20:30 Uhr halte ich in Dortmund den Vortrag "Was bringen C# 13.0 und .NET 9.0?"

Die Veranstaltung der .NET User Group Dortmund ist kostenlos. Sie findet bei der Adesso AG am Adessoplatz 1, 44269 Dortmund in der ersten Etage statt.

Der Vortrag hat folgende Inhalte:

  • Neuerungen in der Sprachsyntax von C# 13.0
  • Neuerungen in der .NET 9.0-Basisklassenbibliothek
  • Ausgewählte Neuerungen in ASP.NET Core, Blazor, WPF und Windows Forms in .NET 9.0

Hier geht es zur Anmeldung:

Die Teilnahme ist kostenfrei. Eine Anmeldung ist jedoch zwingend erforderlich [1]. Die Teilnehmeranzahl ist durch die User Group auf 60 Personen begrenzt.

Denjenigen, die nicht persönlich zu dem Termin nach Dortmund kommen können oder mehr wissen wollen als ich an dem einen Abend vermitteln kann, empfehle ich alternativ meine vier Bücher zu .NET 9.0 zu lesen [2].Das geht besonders günstig im E-Book-Abo [3] (ab 99 Euro/Jahr). Hierin sind auch die laufenden Updates aller meiner .NET- und Web-Bücher enthalten.


URL dieses Artikels:
https://www.heise.de/-10261744

Links in diesem Artikel:
[1] https://www.it-visions.de/V11610
[2] https://www.it-visions.de/buecher/verlag.aspx
[3] https://www.it-visions.de/BuchAbo
[4] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Event Sourcing: Die bessere Art zu entwickeln?

Von Golo Roden — 29. Januar 2025 um 10:43
Blick auf einen Schreibtisch mit verschiedenen Dokumenten und bunten Klebezetteln.

(Bild: sabthai/Shutterstock.com)

Event Sourcing ist ein alternativer Ansatz für das Speichern und Verwalten von Daten. Wie funktioniert Event Sourcing und was sind die Vor- und Nachteile?

Kennen Sie das? Sie entwickeln eine Software (ganz gleich, ob für einen Kunden oder für die interne Fachabteilung), und kaum ist sie fertig, kommen schon die ersten Änderungs- und Anpassungswünsche: neue Funktionen, komplexere Analysen, mehr Reports und so weiter. Und oft fehlen entweder die richtigen Daten, oder die Code-Anpassungen sind aufwendiger und fehleranfälliger, als sie sein müssten. Und das führt zu Frust: bei Ihnen und auch bei Ihren Anwenderinnen und Anwendern.

Doch was wäre, wenn sich Software so entwickeln ließe, dass solche Änderungen und Erweiterungen deutlich einfacher und flexibler möglich sind? Genau darum geht es heute: Wir schauen uns an, warum viele Systeme für diese Herausforderungen nicht gemacht sind und wie wir das besser lösen können. Und wenn Sie bei der Softwareentwicklung flexibler und effizienter werden möchten, dann sind Sie hier genau richtig.

Wie wir mit Daten arbeiten

Was ist das Problem? Völlig gleich, mit welcher Architektur Sie arbeiten, ob Sie einen Monolithen entwickeln, ein Client-Server-System, eine Peer-to-Peer-Lösung, eine verteilte servicebasierte Anwendung oder etwas anderes – eines bleibt stets gleich, nämlich die Datenhaltung. Vielleicht würden Sie jetzt entgegnen, dass das nicht stimme, denn immerhin gäbe es nicht nur relationale Datenbanken, sondern auch NoSQL-Datenbanken oder File Storage und dieses und jenes, doch eines haben all diese Storage-Ansätze gemeinsam: Sie speichern stets den Status quo.

Wenn Sie etwa eine Software für eine Bibliothek schreiben, in der man Bücher ausleihen, verlängern und zurückgeben kann, dann ist es sehr wahrscheinlich, dass für jedes Buch ein Datensatz angelegt wird, wenn das Buch in den Bestand aufgenommen wird, und dass dieser Datensatz jedes Mal aktualisiert wird, wenn das Buch ausgeliehen, verlängert oder zurückgegeben wird, und schließlich gelöscht wird, wenn das Buch irgendwann so zerfleddert ist, dass es aus dem Bestand entfernt wird. Und das erscheint so logisch und naheliegend, dass man in der Regel gar nicht hinterfragt, ob das wirklich sinnvoll ist.

CRUD …

Doch warum wirkt das so logisch und naheliegend? Nun, ganz einfach: Weil wir das alle von klein auf so vermittelt bekommen haben – ganz gleich, ob Sie eine Ausbildung gemacht oder studiert haben, ob Sie an einer Fachhochschule oder an einer Universität waren, oder mit welcher Programmiersprache Sie aufgewachsen sind: Die Wahrscheinlichkeit, dass Sie das Speichern von Daten genau so gelernt haben, nämlich Datensätze anzulegen, bei Bedarf zu ändern und schließlich irgendwann zu löschen, ist nahezu immer gegeben.

Für diese Art, mit Daten umzugehen, gibt es sogar einen Fachbegriff, nämlich "CRUD": Das steht für "Create", "Read", "Update" und "Delete", also die vier Verben, mit denen wir in einer Datenbank auf Daten zugreifen können. Und das findet sich tatsächlich überall, egal, ob Sie eine relationale Datenbank wie beispielsweise PostgreSQL oder Microsoft SQL Server einsetzen oder ob Sie mit einer NoSQL-Datenbank wie etwa MongoDB oder Redis arbeiten. Und genau das meine ich: Die Art und Weise, in der wir Daten speichern und mit ihnen umgehen, ist konzeptionell stets dieselbe.

… und seine Probleme

Das wirkt zunächst auch gar nicht schlimm, denn es funktioniert offensichtlich seit vielen Jahrzehnten problemlos. Und Daten werden nun einmal angelegt, geändert und gelöscht. Das ist quasi ein universelles Prinzip. Aber: Wo Licht ist, ist immer auch Schatten. Und natürlich gibt es Aspekte, die mit diesem CRUD-Ansatz einfach nicht gut funktionieren. Ich bin mir sehr sicher, dass Sie selbst schon mindestens einmal ein solches Szenario erlebt haben, nämlich: Löschen ist meistens keine besonders gute Idee.

Denn wenn etwas gelöscht wird, ist es danach – Überraschung! – weg. Doch das ist oft unerwünscht, denn vielleicht hat sich die Anwenderin oder der Anwender nur verklickt und würde das Löschen gern rückgängig machen. Das Problem ist nur: Wenn die Daten bereits fort sind, lassen sie sich nicht wiederherstellen. Was tun? Nun, man löscht einfach nicht, sondern führt ein IsDeleted-Flag ein, macht also anstelle eines Delete ein Update und setzt dieses Flag auf true.

So kann man das Löschen zum einen rückgängig machen, und zum anderen lassen sich in der restlichen Anwendung derart markierte Datensätze einfach ignorieren – es wirkt also, als wären sie tatsächlich gelöscht. Das bedeutet, wir führen technisch ein Update durch, das aus fachlicher Sicht einem Delete entspricht.

Fachliches vs. technisches Denken

Wobei das in Wahrheit nicht ganz richtig ist, denn aus fachlicher Sicht geht es gar nicht um das "Delete" eines Buches, sondern darum, ein Buch aus dem Bestand zu entfernen. Delete ist in der Datenbanksprache lediglich das Wort, das diesem Vorgang inhaltlich am nächsten kommt, doch wenn beispielsweise jemand ein Buch stiehlt, dann muss es aus technischer Sicht ebenfalls gelöscht werden, was also auch ein Delete (oder genauer genommen ein Update) wäre – fachlich gesehen sind das jedoch zwei völlig unterschiedliche Vorgänge.

Das bedeutet, wir haben jetzt schon drei Ebenen: die fachliche, in der ein Buch aus dem Bestand entfernt wird, die technische, in der wir das IsDeleted-Flag aktualisieren, und eine dritte Ebene, die sich irgendwo dazwischen befindet und eigentlich die technische Intention ausdrückt, weil wir ursprünglich ein Delete durchführen wollten.

Und? Habe ich es bereits geschafft, Sie damit zu verwirren?

Missverständnisse

Wenn ja: Herzlichen Glückwunsch! Wenn Sie an dieser Stelle denken, dass dies für einen eigentlich trivialen Vorgang ganz schön kompliziert ist, sind Sie in guter Gesellschaft, denn vielen Entwicklerinnen und Entwicklern geht es genauso: Wir haben es geschafft, für ein banales Beispiel drei unterschiedliche sprachliche Ebenen zu erzeugen, sodass wir nun jedes Mal, wenn wir über solche Vorgänge sprechen, im schlimmsten Fall zweimal ersetzen müssen. Missverständnisse sind da natürlich vorprogrammiert.

Stellen Sie sich das nun in großem Maßstab vor, in einer wirklich großen und komplexen Anwendung. Dann kommt jemand aus der Fachabteilung und erklärt, dass ein bestimmter Vorgang erweitert werden müsse, und Sie überlegen angestrengt, was diese Person damit überhaupt meint, weil Ihnen die Fachsprache nicht geläufig ist und denken:

"Ah, bestimmt geht es um die Stelle, an der wir ein Delete ausführen!"

Anschließend sprechen Sie darüber mit jemandem, der die Datenbank verwaltet, und werden angesehen, als kämen Sie von einem anderen Stern, während Ihnen gesagt wird:

"Wir machen hier kein Delete, wir führen immer nur ein Update durch."

Viel Vergnügen dabei, das alles auseinanderzufieseln und zu klären, wo im Code nun was passiert, mit welcher Intention, wieso und warum, und wie und wo sich das letztlich auswirkt. Missverständnisse sind da geradezu vorprogrammiert, weil zwar alle irgendwie vom Gleichen reden, aber niemand das jeweilige Gegenüber wirklich versteht.

Fachabteilung vs. Entwicklungsabteilung

Und dann kommt die Fachabteilung und sagt:

"Ja, wir hätten da noch eine Idee. Wir möchten einen Report darüber, wie oft Bücher eigentlich verspätet zurückgegeben werden, nachdem sie bereits mindestens zwei Mal verlängert wurden."

Und Sie denken sich nur:

"Alles klar, ich melde mich dann morgen krank. Sollen sich doch andere um diesen Kram kümmern."

Denn es stellt sich heraus: Natürlich liegen Ihnen die Daten für diesen Report nicht vor, weil Sie ja nicht ahnen konnten, dass irgendwann einmal jemand danach fragen würde. Also, was tun Sie? Sie passen das Schema der Datenbank an (in der Hoffnung, dabei nichts kaputtzumachen), passen dann den vorhandenen Code an, um die neuen Veränderungen überhaupt zu erfassen (wieder in der Hoffnung, dabei nichts zu zerstören), und schreiben anschließend den Code für den neuen Report. Allerdings sind Sie damit noch nicht fertig, denn jetzt müssen Sie sechs Monate warten, bis Sie zumindest erste halbwegs belastbare Zahlen haben, mit denen Sie zur Fachabteilung gehen können – ein halbes Jahr später!

Softwareentwicklung dauert zu lange

Und wie reagieren diese Personen? Wenn Sie Glück haben, sind sie schlicht verärgert: Natürlich ist es toll, dass sie nun diesen Report bekommen, aber sie hätten ihn eben gerne schon vor einem halben Jahr gehabt, nicht erst jetzt. Doch immerhin haben Sie es überhaupt hinbekommen.

Wenn Sie Pech haben, bekommen Sie entweder zu hören, dass sie den Report gar nicht mehr benötigen (aber trotzdem danke für Ihre Mühe), oder man teilt Ihnen mit, dass Sie da leider etwas falsch verstanden haben. Dann war die ganze Arbeit umsonst, Sie können quasi noch mal von vorn anfangen, es dauert wieder ein halbes Jahr, und am Ende erfahren Sie vielleicht dann, dass nun niemand den Report mehr braucht.

Erinnern Sie sich noch, wie alles begann? Richtig: Sie haben das Datenbankschema angepasst. Neue Felder eingeführt, anschließend den Code geändert und so weiter. Setzen Sie das jetzt etwa alles wieder zurück? Ganz ehrlich: Sie wären die erste Person, die ich treffen würde, die das macht. Im Normalfall bleibt so etwas dann nämlich bestehen, auch wenn es niemand mehr benötigt. Weil, und das ist das Ärgerliche daran, Sie ja nie wissen, wer diese neuen Felder inzwischen vielleicht ebenfalls verwendet, und natürlich möchten Sie nicht nach einem vergeudeten Jahr auch noch diejenige oder derjenige sein, der anderen etwas kaputtmacht. Also lassen Sie lieber die Finger davon. Und so wächst und wächst das Datenschema, und nach fünf Jahren kennt sich kein Mensch mehr darin aus.

400 Spalten pro Tabelle

Das ist übrigens keine ausgedachte Situation, sondern genau das erlebe ich da draußen bei sehr vielen Unternehmen in der Praxis als Regelfall. Ich glaube, das Schlimmste in dieser Hinsicht war einmal eine Versicherung, die dem Ganzen vorbeugen wollte, indem sie jeder Tabelle von vornherein vierhundert Spalten verpasste – "Value1", "Value2", "Value3" und so weiter – sodass man zumindest nie das Schema anpassen musste: Man konnte sich einfach die nächste freie Spalte für die eigenen Zwecke reservieren.

Natürlich war das nirgends dokumentiert, und alle Informationen dazu wurden nur mündlich weitergegeben, nach dem Motto:

"Wenn in Spalte 312 ein Y steht, dann bedeutet Spalte 94 die Faxnummer. Wenn in Spalte 312 aber ein J steht, dann ist Spalte 94 das Geburtsdatum. Und wenn in Spalte 207 zusätzlich der Wert NULL steht, gilt das alles nicht mehr, aber wir wissen leider nicht, was dann gilt, weil der Typ, der das vor hundert Jahren mal gebaut hat, nicht mehr bei uns arbeitet."

Uff!

Die Wurzel allen Übels

Also stellt sich natürlich die Frage: Wie kann man es besser machen? Denn auf so eine Situation hat eigentlich niemand Lust. Und tatsächlich (auch wenn Sie das jetzt vielleicht überrascht) ist es eigentlich recht einfach. Der Fehler besteht nämlich darin, dass überhaupt erst der Status quo gespeichert wird. Denn wenn man das macht, muss man sich logischerweise festlegen, welche Felder man zum Status quo speichert und wann man diese Felder aktualisiert.

Das Problem dabei ist, dass man das im Vorfeld eigentlich gar nicht wissen kann. Denn Sie wissen nie, welche Fragen Ihnen morgen gestellt werden und welche Daten Sie dafür bräuchten, um diese Fragen sinnvoll beantworten zu können. Tja, und vielleicht fragen Sie sich jetzt, wie man das dann anders machen soll, schließlich kann niemand in die Zukunft blicken – und trotzdem lässt sich die Sache deutlich intelligenter angehen.

Ein anschauliches Beispiel

Dazu schauen wir uns an, wie ein Girokonto funktioniert. Ich wähle dieses Beispiel ganz bewusst, weil es jede und jeder von Ihnen aus eigener praktischer Erfahrung kennt.

Offensichtlich speichert die Bank nicht einfach nur zu Ihrer Kontonummer den Kontostand (also den Saldo), denn dann könnte sie Ihnen nicht erklären, wie dieser Kontostand überhaupt zustande gekommen ist. Man möchte das jedoch manchmal unbedingt wissen, wenn man sich fragt:

"Warum ist am Ende des Geldes noch so viel Monat übrig?"

Spaß beiseite: Den meisten Menschen ist es sehr wichtig, transparent nachvollziehen zu können, wofür sie Geld ausgegeben haben und wie sich der Kontostand zusammensetzt.

Warum Update und Delete keine guten Ideen sind

Und was macht die Bank dafür konkret? Zunächst einmal verzichtet sie auf das Delete, denn wir haben ja bereits festgestellt, dass es in den meisten Fällen keine gute Idee ist, Daten zu löschen, also streichen wir das einfach. Dann zeigt sich allerdings, dass auch ein Update genauso wenig geeignet ist, weil dabei ebenfalls Daten verloren gehen – nämlich die, die vorher da waren. Genau das ist der springende Punkt: Man überschreibt den bisherigen Status quo durch einen neuen Status quo. Und der alte ist anschließend weg.

Deshalb verzichtet die Bank folgerichtig auch aufs Update. Das ist übrigens in beiderlei Hinsicht hervorragend, denn so bleiben nur noch Create und Read übrig. Das bedeutet, dass eine Bank technisch gesehen einen einmal angelegten Datensatz nie wieder verändern oder gar löschen kann. Und genau das ist extrem wichtig für den Vertrauensaufbau: Stellen Sie sich einmal vor, eine Bank könnte bereits ausgeführte Buchungen nachträglich ändern! Sie würden wahrscheinlich niemals Ihr Geld dorthin bringen!

Ein alternativer Ansatz, Daten zu speichern

Nun stellt sich natürlich die Frage: Was lässt sich mit Create und Read schon Großartiges anfangen? Denn Daten müssen ja manchmal geändert werden. Und hier kommt der entscheidende Punkt: Wir speichern nicht mehr den Status quo, sondern stattdessen die einzelnen kleinen Veränderungen, die im Laufe der Zeit zum Status quo geführt haben. Genau das ist es, was Sie auf Ihrem Kontoauszug sehen: Die Bank erzeugt für jede Transaktion, die auf Ihrem Konto stattfindet, einen neuen, unveränderlichen Eintrag. Per Create.

Und diese immer länger werdende Liste können Sie sich anschließend per Read ausgeben lassen – das ist Ihr Kontoauszug. Wenn ich dann wissen möchte, wie Ihr aktueller Kontostand ist, kann ich hingehen und all Ihre Kontoauszüge seit der Eröffnung des Kontos nehmen und Transaktion für Transaktion durchrechnen, bis ich am Ende weiß, wie Ihr heutiger Saldo ausfällt.

Fehler kompensieren statt korrigieren

Und was passiert nun, wenn etwas schiefläuft? Dann kann man Daten doch gar nicht korrigieren, oder? Doch, kann man! Denn die Bank versucht gar nicht erst, eine fehlgeschlagene Transaktion zu ändern, sondern sie kompensiert diese einfach mit einer passenden Gegentransaktion. Wenn Sie also versuchen, 100 Euro auf ein Konto zu überweisen, das nicht existiert, streicht die Bank nicht Ihre fehlgeschlagene Überweisung aus der Historie, sondern Sie erhalten kurz darauf einfach eine Gutschrift über 100 Euro, sodass der Effekt ausgeglichen wird.

Das ändert natürlich nichts daran, dass die fehlgeschlagene Überweisung versucht wurde, aber genau so hat es sich ja auch wirklich zugetragen. Das bedeutet, die Historie wird nicht verfälscht, sondern nur die Effekte werden kompensiert.

Die Vergangenheit neu interpretieren

Dieses Modell hat einen enormen Vorteil: Aus Sicht des Datenmodells ist es sehr, sehr simpel. Aber weil Sie alle Rohdaten besitzen, können Sie sämtliche Fragen beantworten, von denen Sie bis vor Kurzem nicht einmal wussten, dass sie jemals gestellt werden würden. Und das können Sie nicht nur ad hoc tun, sondern Sie können es auch ad hoc über sämtliche Daten der Vergangenheit tun!

Also zum Beispiel: Wie viel Prozent Ihres Gehalts geben Sie für die Miete aus? Nun, wenn Sie mir Ihren Kontoauszug geben, kann ich das einfach ausrechnen, auch wenn es dafür kein eigenes Feld gibt. Sie möchten wissen, ob sich Lottospielen lohnt? Dann geben Sie mir bitte Ihren Kontoauszug, und ich rechne das für Sie gern aus. Sie möchten wissen, ob der durchschnittliche Kontostand des Jahres 2024 höher oder niedriger war als der von 2023 und falls ja, um wie viel? Nun, geben Sie mir Ihren Kontoauszug, und ich rechne Ihnen das gerne aus. Wie oft im Monat gehen Sie essen? Leben Sie eher sparsam oder eher verschwenderisch? Geben Sie direkt nach Geldeingang größere Beträge aus, oder warten Sie bis zum Monatsende, wenn Sie wissen, wie viel übrig ist? Haben Sie einen Zweitwohnsitz? Wie viel sind Ihre Ausgaben für Lebensmittel im Vergleich zu vor fünf Jahren gestiegen? Und so weiter und so fort …

Ich könnte diese Liste praktisch endlos erweitern. Und das Entscheidende ist: Ich kann Ihnen jede dieser Fragen beantworten, nur mithilfe der vorhandenen Transaktionen der vergangenen Jahre, ohne dass wir dazu das Datenmodell anpassen müssten. Ohne dass wir dafür den Code ändern müssen, der die Transaktionen ausführt. Ohne dass wir sechs Monate warten müssen. Ohne dieses, ohne jenes.

Den Ansatz verallgemeinern

Und das gilt nicht nur für Banken. Das funktioniert ebenfalls für unsere eingangs erwähnte Bibliothek: Statt für jedes Buch einen Datensatz zu führen, den wir immer wieder aktualisieren und am Ende trotzdem nichts Genaues wissen, legen wir einfach für jede Veränderung einen Datensatz an: Ein Buch wurde neu in den Bestand aufgenommen, ein Buch wurde ausgeliehen, ein Buch wurde verlängert, ein Buch wurde zurückgegeben, ein Buch wurde beschädigt und so weiter.

Auch daraus können Sie alle möglichen Fragen ableiten: Wie oft wird ein Buch pro Jahr ausgeliehen? Wie oft wird es verlängert? Welches sind die Top 10 der am häufigsten ausgeliehenen Bücher? Welcher Anteil der Bücher wird mehr als einmal von derselben Person ausgeliehen? Und so weiter. All das funktioniert in jeder Fachdomäne.

Der böse Wolf deleted das Rotkäppchen

Vielleicht ist es Ihnen bereits aufgefallen: Wir haben uns, ganz nebenbei, vom rein technischen Vokabular entfernt und reden nicht mehr von Create, Update und Delete, sondern plötzlich von der Fachlichkeit – Ausleihen, Verlängern, Zurückgeben und so weiter.

Das bedeutet, wenn jetzt jemand aus der Fachabteilung mit einem Wunsch hinsichtlich der Rückgabe von Büchern zu Ihnen kommt, wissen Sie sofort, worum es geht, weil Sie dasselbe Vokabular verwenden. Und wenn Sie nun sagen:

"Na gut, man müsste das ja nicht so machen, ich kann doch weiterhin mit Create, Read, Update und Delete arbeiten."

dann bekämen Sie sinngemäß einen Kontoauszug, auf dem steht:

  • Konto created
  • Konto geupdated
  • Konto geupdated
  • Konto geupdated
  • Konto geupdated

Da erkennt man, wie unglaublich dünn das übliche, verbreitete Vokabular in Anwendungen ist. Und man merkt, wie hilfreich und sinnvoll es sein kann, nicht immer nur dieselben vier technischen Verben zu verwenden, sondern endlich einmal semantisch gehaltvolle Begriffe aus der Fachlichkeit einzuführen. Das Ganze steht und fällt also damit, dass man inhaltlich sinnvolle Begriffe wählt. Und genau das ist in der Softwareentwicklung ohnehin von essenzieller Bedeutung: Dinge richtig zu benennen.

Wenn man das nicht macht, entsteht solcher Unsinn wie der böse Wolf, der das IsDeleted-Flag des Rotkäppchens aktualisiert, weil er es ja nicht löschen darf, sonst könnte der Jäger kein "Undelete" durchführen. Dabei geht es eigentlich doch um Gefressen- und Gerettet-Werden, aber hey – ein rein technisches Update und Delete sind so viel einfacher.

Übrigens: Ich habe mich schon häufiger über CRUD ausgelassen, und wenn Sie sich das CRUD-Märchen tatsächlich einmal in voller Länge ansehen wollen, empfehle ich Ihnen dieses Video [2].

Events als Quelle von allem

Jetzt wissen Sie, wie das System konzeptionell funktioniert. Was noch fehlt, ist ein Name für das Ganze. Die einzelnen Einträge in dieser immer weiter wachsenden Liste (übrigens nennt man sie eine "Append-Only-Liste", weil stets nur am Ende angehängt werden darf) stehen in der Vergangenheitsform, denn sie sind ja bereits geschehen: Ein Buch wurde ausgeliehen, ein Buch wurde verlängert, ein Buch wurde zurückgegeben und so weiter. Und weil das Ereignisse sind, die stattgefunden haben und nicht mehr rückgängig gemacht werden können (wie gesagt, man kann nur ihre Effekte kompensieren), spricht man hier von "Events".

Da diese Events sozusagen die Quelle für sämtliche Auswertungen, Abfragen, Analysen, Reports und Co. sind, sind sie die "Source" von allem, weshalb man bei diesem Datenhaltungskonzept von "Event Sourcing" spricht. Vielleicht haben Sie den Begriff schon einmal gehört und sich gefragt, was das eigentlich ist. Die kurze Antwort lautet: Das, was Ihr Girokonto macht, das ist Event Sourcing, beziehungsweise, das ist ein Beispiel dafür. Das heißt, Sie verwenden es tagtäglich, und zwar schon seit Jahren, nur kannten Sie vermutlich den Namen nicht.

Ein Audit-Log im Kernkonzept

Allerdings ist die historische Analysemöglichkeit von Daten nicht der einzige Vorteil, den Event Sourcing bietet. Sie erhalten, ohne dafür aktiv etwas machen zu müssen, quasi "kostenlos" ein Audit-Log: Sie können jederzeit nachvollziehen, welches Event (also welche fachlich relevante Aktion) wann und von wem und mit welchen Parametern ausgelöst wurde. Das ist natürlich generell schon sehr praktisch, aber besonders interessant wird es, wenn Sie Software für eine Branche entwickeln, in der das Führen eines Audit-Logs vorgeschrieben ist, etwa aus Sicherheitsgründen.

Wenn Sie dann sagen können, dass das Audit-Log nicht nachträglich angeflanscht wurde, sondern von Anfang an im Kernkonzept der Datenhaltung mitgedacht ist, verschafft es Ihnen einen deutlichen Wettbewerbsvorteil.

"Was-wäre-wenn"-Analysen

Sie interessieren sich für "Was-wäre-wenn"-Analysen? Kein Problem: Beim Abspielen der Events (was man übrigens "Replay" nennt) müssen Sie nicht zwangsläufig alle Events berücksichtigen. Sie können auch einige davon weglassen und sehen, wie sich dadurch das Ergebnis verändert. Oder Sie fügen bei einem Replay simulierte Events hinzu und beobachten, was im Laufe der Zeit geschehen wäre.

Das kann Ihnen helfen, weit bessere Einblicke zu gewinnen, Ihr (auch wenn sich das merkwürdig anhören mag) Business besser zu verstehen und auf dieser Grundlage möglicherweise bessere Entscheidungen zu treffen. Allein die Möglichkeit, die Vergangenheit auf unterschiedliche Weise zu interpretieren, ist so mächtig, dass Sie sich das, falls Sie es noch nie erlebt haben, kaum vorstellen können.

Event Sourcing für … Doom

Bevor ich es vergesse: Auch für Fehlersuche und Debugging ist Event Sourcing hervorragend geeignet. Mit Events können Sie problemlos nachvollziehen, wie ein System bei einem Kunden in diesen merkwürdigen Zustand geraten ist, in dem es sich gerade befindet.

Und das ist keineswegs eine neue Idee: Es gibt ein Interview mit John Carmack, dem ehemaligen leitenden Entwickler bei id Software, der maßgeblich an DOOM beteiligt war, und in diesem Interview erwähnt er, dass DOOM im Kern mit Event Sourcing arbeitet (auch wenn er es nicht so nennt, weil der Begriff damals noch nicht existierte, es aber de facto genau das ist).

Übrigens ist das zum Beispiel auch für Maschinensteuerung oder ganz allgemein IoT- und Industriebereiche interessant: Wie ist eine Maschine in den Zustand geraten, in dem sie sich befindet, und was können wir daraus lernen?

Flexible Lesemodelle erstellen

Und natürlich können Sie aus den Events jede beliebige andere Darstellung erzeugen, denn letztlich ist das nur eine Frage der Interpretation. Wenn Sie zum Beispiel häufig den aktuellen Kontostand benötigen, wäre es sehr ineffizient, jedes Mal ein komplettes Replay durchzuführen – stattdessen können Sie zusätzlich eine kleine Tabelle mit dem Kontostand pflegen, die Sie ganz klassisch nach CRUD aktualisieren, sobald ein Event auftritt, das Auswirkungen auf den Kontostand hat.

Theoretisch müssten Sie diese Tabelle nicht einmal auf der Festplatte sichern, denn falls das System abstürzt, könnten Sie sie jederzeit aus dem Replay neu aufbauen. Das bedeutet natürlich auch, dass Sie das gleiche Prinzip für jede beliebige andere Tabelle oder Darstellung anwenden können: Die Events bleiben stets Ihre Single Source of Truth, und was Sie daraus an speziell optimierten Lesemodellen ableiten, liegt ganz bei Ihnen.

Speicherplatz und Kosten

Es gilt natürlich: Wo Licht ist, ist stets auch Schatten. Ich möchte Event Sourcing nicht als eine Lösung darstellen, in der es nichts gibt, worüber man nachdenken sollte, und spreche deshalb kurz einige typische Einwände an. Erstens wird oft angeführt, dass eine Append-Only-Liste im Laufe der Zeit zunehmend mehr Speicher verbraucht. Das stimmt grundsätzlich, aber zum einen sollen Sie ja nicht jeden einzelnen Sensormesswert als Event erfassen, sondern nur geschäftsrelevante Fachereignisse. Davon haben Sie in der Regel nicht 100.000 pro Sekunde.

Zweitens sind Events meist deutlich kleiner, als man intuitiv annimmt, weil man nur die Deltas speichern muss.

Und drittens ist Speicherplatz heutzutage praktisch kein Kostenfaktor mehr. Letztlich ist das eine einfache Rechenaufgabe, und natürlich hängt die Antwort stark von der jeweiligen Fachdomäne ab, doch erfahrungsgemäß sind das oft weit weniger Daten als zunächst vermutet. Und außerdem könnte man alte Events irgendwann archivieren. Natürlich ließen sich dann deren Historien nicht mehr abrufen, aber das ginge bei einem klassischen Datenhaltungsmodell ebenfalls nicht.

Performance von Replays

Der zweite häufige Einwand lautet, dass Replays im Laufe der Zeit immer länger dauern: Das ist logisch, denn wenn das System rege genutzt wird, sammeln sich immer mehr Events an, und ein Replay benötigt dann naturgemäß mehr Zeit. Der springende Punkt ist jedoch, dass man dem mit sogenannten Snapshots hervorragend entgegenwirken kann: Ein Replay über die ersten 10.000 Events führt ja stets zum gleichen Ergebnis, gerade weil es kein Update und kein Delete gibt, das heißt, anstatt dieses Ergebnis immer wieder neu zu berechnen, lässt es sich in einem Cache als bereits vorgefertigter Wert hinterlegen.

Im Zweifelsfall müssen Sie dann lediglich ein Replay ab dem letzten Snapshot durchführen, was bei regelmäßig erzeugten Snapshots flott geht. Außerdem haben Sie es in der Hand, wie schnell das Ganze sein soll: Letztlich ist das nur eine Frage der Häufigkeit, mit der Sie Snapshots erzeugen.

DSGVO, Artikel 17

Der dritte Einwand betrifft häufig die DSGVO: Wie kann ein System, das darauf ausgelegt ist, Daten niemals zu ändern oder zu löschen, überhaupt mit der DSGVO vereinbar sein, insbesondere mit Artikel 17 zum Recht auf Vergessenwerden? Tatsächlich existieren dafür verschiedene Lösungswege, die unterschiedlich aufwendig zu implementieren sind, aber auch unterschiedlich hohen Anforderungen und Datenschutzklassen gerecht werden.

Was jeweils der richtige Ansatz ist, muss individuell für das jeweilige Projekt erarbeitet werden. Das lässt sich nicht pauschal beantworten, weil es beispielsweise einen Unterschied macht, ob Sie hochsensible medizinische Daten verarbeiten oder nur die Stammdaten des örtlichen Kanarienvogel-Züchtervereins. Das sind einfach verschiedene Welten.

Wo fängt man an?

Und vielleicht denken Sie jetzt:

"Klasse, das klingt alles sehr vielversprechend, besonders das mit den historischen Daten, dem Audit-Log, der stärkeren Fokussierung auf die Fachlichkeit, den vielfältigen Analysemöglichkeiten und Reports und so weiter – das möchte ich unbedingt einmal ausprobieren. Aber wo fange ich an?"

Dann ist mein allerwichtigster Rat: Beginnen Sie mit einem kleinen Projekt. Event Sourcing ist ein unglaublich mächtiges Werkzeug, das Ihnen völlig neue Türen öffnen kann, doch wie bei jedem mächtigen Werkzeug sollte man nicht gleich mit dem größten Projekt starten, das man hat. Suchen Sie sich also zuerst etwas wirklich Kleines heraus und beschäftigen Sie sich, bevor Sie mit einer Implementierung beginnen, zunächst einmal mit der Frage, welche Events überhaupt existieren. Denn das ist der Dreh- und Angelpunkt: Da Sie nichts mehr ändern oder löschen können, sollten Sie zumindest halbwegs sicherstellen, dass Sie in die richtige Richtung loslaufen.

Welches Tooling Sie dann später nutzen, welche Datenbank Sie verwenden und so weiter, ist im ersten Schritt völlig unerheblich. Natürlich wird das später eine sehr wichtige Frage sein, aber zuerst sollten Sie sich mit der Fachlichkeit befassen und erst dann mit den technischen Fragen, nicht umgekehrt. Nach einer Weile werden Sie dann irgendwann feststellen: Event Sourcing ist am Ende gar nicht so kompliziert, wie Sie vielleicht zunächst vermuten – es fehlt häufig einfach an Übung und Erfahrung, aber die sammelt man mit der Zeit.


URL dieses Artikels:
https://www.heise.de/-10258295

Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.youtube.com/watch?v=MoWynuslbBY
[3] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Neu in .NET 9.0 [6]: Neues Escape-Zeichen für Konsolenausgaben

Von Dr. Holger Schwichtenberg — 24. Januar 2025 um 12:42

(Bild: Valtenint Agapov / Shutterstock)

C# 13.0 bietet ein neues Escape-Zeichen \e für die Formatierung von ANSI/VT100 Terminal Control Escape Sequences.

Mit den uralten VT100/ANSI-Escape-Codes [1] kann man auch heute noch in Konsolenanwendungen zahlreiche Formatierungen auslösen, darunter 24-Bit-Farben, Fettschrift, Unterstreichen, Durchstreichen und Blinken. Die VT100/ANSI-Codes werden durch das Escape-Zeichen (ASCII-Zeichen 27, hexadezimal: 0x1b) eingeleitet.

Vor C# 13.0 konnte man dieses Escape-ASCII-Zeichen 27 in .NET-Konsolenanwendungen bei Console.WriteLine() nur umständlich ausdrücken über \u001b, \U0000001b oder \x1b, wobei Letzteres nicht empfohlen ist [2]: "Wenn Sie die Escapesequenz \x verwenden, weniger als vier Hexadezimalziffern angeben und es sich bei den Zeichen, die der Escapesequenz unmittelbar folgen, um gültige Hexadezimalziffern handelt (z. B. 0–9, A–F und a–f), werden diese als Teil der Escapesequenz interpretiert. \xA1 erzeugt beispielsweise "¡" (entspricht dem Codepunkt U+00A1). Wenn das nächste Zeichen jedoch "A" oder "a" ist, wird die Escapesequenz stattdessen als \xA1A interpretiert und der Codepunkt "ਚ" erzeugt (entspricht dem Codepunkt U+0A1A). ਚ ist ein Panjabi-Schriftzeichen. Panjabi ist eine in Pakistan und Indien gesprochene Sprache. In solchen Fällen können Fehlinterpretationen vermieden werden, indem Sie alle vier Hexadezimalziffern (z. B. \x00A1) angeben."

Typischerweise sahen Ausgaben mit VT100/ANSI-Escape-Codes vor C# 13.0 folgendermaßen aus:

Console.WriteLine("This is a regular text");
Console.WriteLine("\u001b[1mThis is a bold text\u001b[0m");
Console.WriteLine("\u001b[2mThis is a dimmed text\u001b[0m");
Console.WriteLine("\u001b[3mThis is an italic text\u001b[0m");
Console.WriteLine("\u001b[4mThis is an underlined text\u001b[0m");
Console.WriteLine("\u001b[5mThis is a blinking text\u001b[0m");
Console.WriteLine("\u001b[6mThis is a fast blinking text\u001b[0m");
Console.WriteLine("\u001b[7mThis is an inverted text\u001b[0m");
Console.WriteLine("\u001b[8mThis is a hidden text\u001b[0m");
Console.WriteLine("\u001b[9mThis is a crossed-out text\u001b[0m");
Console.WriteLine("\u001b[21mThis is a double-underlined text\u001b[0m");
Console.WriteLine("\u001b[38;2;255;0;0mThis is a red text\u001b[0m");
Console.WriteLine("\u001b[48;2;255;0;0mThis is a red background\u001b[0m");
Console.WriteLine("\u001b[38;2;0;0;255;48;2;255;255;0mThis is a blue text with a yellow background\u001b[0m");

Seit C# 13.0 gibt es nun \e als Kurzform für das Escape-Zeichen ASCII 27, sodass die Zeichenfolgen deutlich kompakter und übersichtlicher werden:

Console.WriteLine("This is a regular text");
Console.WriteLine("\e[1mThis is a bold text\e[0m");
Console.WriteLine("\e[2mThis is a dimmed text\e[0m");
Console.WriteLine("\e[3mThis is an italic text\e[0m");
Console.WriteLine("\e[4mThis is an underlined text\e[0m");
Console.WriteLine("\e[5mThis is a blinking text\e[0m");
Console.WriteLine("\e[6mThis is a fast blinking text\e[0m");
Console.WriteLine("\e[7mThis is an inverted text\e[0m");
Console.WriteLine("\e[8mThis is a hidden text\e[0m");
Console.WriteLine("\e[9mThis is a crossed-out text\e[0m");
Console.WriteLine("\e[21mThis is a double-underlined text\e[0m");
Console.WriteLine("\e[38;2;255;0;0mThis is a red text\e[0m");
Console.WriteLine("\e[48;2;255;0;0mThis is a red background\e[0m");
Console.WriteLine("\e[38;2;0;0;255;48;2;255;255;0mThis is a blue text with a yellow background\e[0m");

Die Ausgabe der beiden vorherigen Listings sieht gleich aus.

(Bild: Screenshot (Holger Schwichtenberg))


URL dieses Artikels:
https://www.heise.de/-10255344

Links in diesem Artikel:
[1] https://en.wikipedia.org/wiki/ANSI_escape_code
[2] https://learn.microsoft.com/de-de/dotnet/csharp/programming-guide/strings/
[3] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Wie niedlich: Du programmierst ernsthaft in dieser Programmiersprache?

Von Golo Roden — 22. Januar 2025 um 10:49

(Bild: Erstellt mit KI (Midjourney) durch iX-Redaktion)

Wer in Visual Basic programmiert, wird gerne belächelt, immerhin sei Basic eine "schlechte" Programmiersprache. Warum ist das eigentlich so und was ist da dran?

Vor ein paar Tagen habe ich einen Entwickler kennengelernt, und natürlich (wie das unter Entwicklern eben so ist) kam relativ schnell die Frage auf, mit welcher Programmiersprache man denn jeweils unterwegs sei. Ich habe dann ein bisschen erzählt, was wir bei the native web [1] so machen, womit wir uns beschäftigen und womit wir arbeiten.

Und natürlich habe ich ihn dann gefragt, wie das denn bei ihm sei. Da kam dann ein leicht verschämtes:

"Naja, ich arbeite nur mit Visual Basic."

Diese Antwort war ihm sichtlich unangenehm, und ich habe ihn dann gefragt, warum das so sei. Er erzählte mir, dass er schon oft die Erfahrung gemacht hätte, dass andere Entwicklerinnen und Entwickler ihn nach dieser Antwort nicht mehr so ganz ernst nehmen, sondern ihn eher belächeln würden. So nach dem Motto:

"Ach guck mal, wie niedlich, da arbeitet jemand tatsächlich noch mit Visual Basic!"

Zugegeben: Visual Basic hat keinen besonders guten Ruf. Eher im Gegenteil: Die Sprache gilt als veraltet, als minderwertig, kurzum als "schlecht". Doch da stellt sich natürlich die Frage: Was ist da dran? Ist Visual Basic wirklich so eine katastrophal schlechte Sprache? Um das beantworten zu können, muss man die Frage etwas allgemeiner stellen, nämlich: Was zeichnet eine gute oder eine schlechte Programmiersprache überhaupt aus?

Objektive Kriterien versus subjektive Meinung

Bevor wir loslegen, möchte ich noch ein paar Hinweise geben. Zuallererst: Auf diese Frage gibt es nicht die eine wissenschaftlich fundierte und absolut objektive Antwort. Schon die Definition von "gut" und "schlecht" ist eine Frage der Interpretation. Ich werde mir daher zwar große Mühe geben, das Ganze objektiv anzugehen, nicht emotional zu argumentieren und meine Behauptungen an Fakten festzumachen. Dennoch ist das, was hier steht, meine persönliche Sicht der Dinge. Bevor Du also in den Kommentaren mit Kritik um Dich wirfst, wäre es nett, wenn Du das berücksichtigen könntest.

Zweitens: Es geht mir in diesem Blogpost nicht speziell um Visual Basic. Vielmehr versuche ich, zu erklären, woran ich festmache, ob ich eine Sprache als gut oder schlecht empfinde. Dabei liefere ich die Kriterien, die ich für wichtig halte, und erkläre, aus welchen Gründen ich sie für wichtig erachte. Es ist völlig in Ordnung, wenn Du sagst, dass diese Kriterien für Dich nicht greifen oder Du sie anders bewertest. Denn immer da, wo es um Qualität geht, spielt auch das eigene Wertesystem eine Rolle. Und das sieht bei Dir sicher anders aus als bei mir, allein schon deshalb, weil wir unterschiedliche Erfahrungen gemacht haben.

Drittens: Generell möchte ich darum bitten, in den Kommentaren nett zueinander zu sein und konstruktiv miteinander umzugehen. Auch wenn Dir die Sprache, die jemand anderes bevorzugt, nicht gefällt, macht das die entsprechende Person nicht zu einem schlechten Menschen. Es ist völlig in Ordnung, Technologien kritisch zu hinterfragen. Anderen Menschen sollten wir trotz Kritik respektvoll begegnen.

Geeignete und ungeeignete Sprachen

Damit kommen wir nun endlich zum eigentlichen Thema: Was macht eine Programmiersprache gut oder schlecht?

Eine häufig genannte Antwort lautet: Eine Sprache ist dann gut, wenn man mit ihr das jeweils gesteckte Ziel erreichen kann. Nach dem Motto: Wenn eine Sprache den Zweck erfüllt, dann kann sie nicht schlecht sein. Für mich persönlich ist das allerdings kein besonders überzeugendes Argument. Denn bloß, weil ein Werkzeug eine Aufgabe erfüllt, ist es noch lange kein gutes Werkzeug – es ist dann zunächst einmal nur ein für diese Aufgabe passendes oder geeignetes Werkzeug.

Ob es auch gut ist, steht auf einem anderen Blatt. Das merkt man spätestens dann, wenn es mehrere Werkzeuge für dieselbe Aufgabe gibt. Denn dann gibt es oft Unterschiede. Insofern gilt für mich, dass "gut" und "geeignet" zwei verschiedene Paar Schuhe sind. Umgekehrt ist eine Sprache nicht per se schlecht, nur weil sie für ein Problem ungeeignet ist. Sie ist dann einfach nur für dieses Problem ungeeignet. "Gut" oder "schlecht" sind für mich Begriffe, die sich auf eine qualitative Bewertung der Sprache an sich beziehen, unabhängig von ihrer Tauglichkeit für ein bestimmtes Problem.

Sprache vs Implementierung

Ein ähnlicher Punkt ist das Feature-Set einer konkreten Implementierung einer Sprache. Es hieß früher zum Beispiel oft, dass C# eine schlechte Sprache sei, weil sie nur unter Windows lauffähig war. Das ist falsch. Die Sprache an sich ist zunächst nur eine Syntax mit einer Semantik, wie man sich ausdrücken kann. Ob es dafür eine passende Laufzeitumgebung oder einen passenden Compiler für eine konkrete Plattform gibt, ist unabhängig von der Idee der Sprache. Heute ist es ja problemlos möglich, C# auch auf macOS oder Linux auszuführen. Insofern sind auch das keine Kriterien dafür, ob eine Sprache gut oder schlecht gestaltet wurde. Es sagt nur etwas über die Verfügbarkeit von Implementierungen aus.

Ein weiterer Punkt: Eine Sprache ist nicht dasselbe wie ihre Funktions- oder Klassenbibliothek. Auch das ist ein Implementierungsdetail. Es kann für ein und dieselbe Sprache unterschiedliche Umgebungen geben, die unterschiedlich viel an "Drumherum" zur Verfügung stellen. Das kennt man zum Beispiel aus .NET oder Java mit unterschiedlich umfangreichen Runtimes. Es geht mir also wirklich nur um das, was direkt zur Sprache an sich gehört.

Allein darüber könnte man nun lange diskutieren, ob diese Abgrenzung sinnvoll ist oder nicht. Für heute möchte ich sie so machen, weil es in meinen Augen die sinnvollste Definition ist, wenn man über das Design einer Sprache sprechen will.

Ausdrucksstärke

Damit ist umrissen, was ich überhaupt bewerten will. Jetzt ist die Frage, was geeignete Kriterien sind. Das wichtigste Kriterium für mich ist die Ausdrucksstärke einer Sprache. Eine Programmiersprache ist ein Werkzeug, um das umzusetzen, was eine Entwicklerin oder ein Entwickler im Sinn hat. Das sollte möglichst zielgerichtet und ohne unnötige Umstände möglich sein. Das macht das Schreiben und Lesen von Code einfacher. Je weniger eine Sprache mich zwingt, Konzepte umzuformulieren, desto einfacher und direkter lassen sich Ideen ausdrücken. Sprachen, die für jedes gedankliche Konzept ein entsprechendes Konzept in der Sprache bieten, empfinde ich als gelungen.

Ein Beispiel: In der Mathematik ist 1 die Fakultät von 1, und die Fakultät von n ist n * fac(n - 1). Hier handelt es sich also um eine rekursive Definition. Eine Sprache ist dann ausdrucksstark, wenn sie Rekursion unterstützt, weil ich die Fakultät dann genau so ausdrücken kann, wie sie in meinem Kopf definiert ist. Das klingt trivial, aber Rekursion gab es tatsächlich nicht schon immer in Programmiersprachen. Sie musste erst einmal eingeführt werden, und das war mit Lisp im Jahr 1958 [3]. Das im Jahr zuvor entstandene Fortran kannte keine Rekursion. Und genau das meine ich mit Konzepten: Eine gute Sprache holt mich auf der konzeptionellen Ebene dort ab, wo ich stehe, und bürdet mir keine unnötige Denkarbeit auf.

Minimalismus

Die Ausdrucksstärke ist aber nicht das einzige Kriterium. Das zweite wichtige Kriterium aus meiner Sicht ist Minimalismus: Für jedes Konzept sollte es nur genau einen einzigen Weg geben, um ans Ziel zu kommen. Ich will mich nicht zwischen mehreren gleichwertigen Wegen entscheiden müssen. Zu viele Alternativen führen nämlich zu Inkonsistenzen im Code und erhöhen die Komplexität. Ein Beispiel: JavaScript kennt zig Wege, eine Iteration auszudrücken – unter anderem sieben verschiedene Schleifentypen:

  • for als klassische Zählschleife
  • for ... in um über Objekte zu iterieren
  • for ... of eine Art foreach
  • for await ... of als asynchrone Variante davon
  • while als abweisende Schleife
  • do ... while als nicht abweisende Schleife
  • forEach als Schleifen-Funktion an Arrays

Ich bin mir sicher, dass ich die eine oder andere Variante vergessen habe, aber dass es überhaupt sieben verschiedene Schleifentypen in JavaScript gibt, die im Prinzip alle das Gleiche machen und sich lediglich in Details unterscheiden, das ist schon erschreckend. Vergleicht man das mit Go, dann kommt Go mit einer einzigen Schleife aus – nämlich der for-Schleife, die gegebenenfalls noch um das range-Schlüsselwort ergänzt wird. Das war's, und das führt zu viel weniger Diskussionen und Verwirrung.

Konsistenz & Co.

Das dritte Kriterium ist Konsistenz: Konzeptionell gleiche Dinge sollten syntaktisch gleich formuliert werden. Das senkt die kognitive Belastung und fördert die Lesbarkeit. In Go (nachdem ich die Sprache gerade positiv erwähnt habe, nenne ich nun auch ein Manko) stolpere ich regelmäßig darüber, dass Parameter einer Funktion per Komma separiert werden, Felder eines Struct jedoch nicht. Das ist unlogisch, weil man in beiden Fällen eine Auflistung von Namen und Typen vornimmt, und warum dieses – aus konzeptioneller Sicht – gleiche Muster mit unterschiedlichen Syntaxvarianten ausgeführt wird, erschließt sich mir nicht.

Viertens ist mir eine gewisse Explizitheit wichtig. Sprachen sollten dazu führen, dass man sich präzise ausdrücken muss. Ich bin ein großer Fan von expliziten Konvertierungen und kein Freund von impliziten. Explizitheit sorgt für mehr Klarheit und weniger Fehler. Je gefährlicher eine Aktion ist, desto expliziter sollte sie sein. Und hier kann man Go wieder als Positivbeispiel nennen: Der unsichere (weil direkte) Zugriff auf den Speicher erfolgt hier über das unsafe-Paket, das heißt, man muss explizit hinschreiben, dass es sich um unsicheren Code handelt.

Auf die Community hören?

Nun gehen da natürlich manchmal die Meinungen auseinander, was gut und was schlecht ist. Und da fragt man sich dann vielleicht, wie sehr Sprachdesigner auf die Community hören sollten. Meine klare Antwort ist: Eigentlich gar nicht. Denn es äußern sich oft nur wenige aus der Community, die dann aber sehr lautstark auftreten. Wirklich gutes Sprachdesign ist unglaublich schwer, und bloß weil es einige laute Schreihälse gibt, heißt das noch lange nicht, dass ihre Forderungen sinnvoll oder durchdacht seien. Tatsächlich denken viele Entwicklerinnen und Entwickler an der Stelle zu kurz und übersehen langfristige Konsequenzen, die eine Sprache aufweichen, verwässern und inkonsistent machen können.

Außerdem gilt: Wenn man zu einem neuen Feature erst einmal "ja" gesagt hat, kann man es nicht wieder entfernen, ohne einen Breaking-Change zu haben. Deshalb sollte man sich sehr genau im Vorfeld überlegen, welche Features wirklich in eine Sprache aufgenommen werden sollten. Mit anderen Worten: Weniger Optionen fördern die Standardisierung von Code und damit seine Lesbarkeit. Letztlich geht es um die richtige Balance zwischen Ausdrucksstärke, Minimalismus, Explizitheit und Konsistenz. Vielleicht auch noch um Fehlervermeidung.

Und eine Sprache, die das alles vereint, würde ich persönlich als gelungen bezeichnen.

Meine eigene Reise durch die Programmiersprachen

Wenn ich auf meine eigene Reise zurückblicke, sehe ich, wie sich die von mir genutzten Sprachen entwickelt haben. Meine erste große Sprache war Basic: Zunächst GW-Basic, später QuickBasic und schließlich Basic PDS, alles unter MS-DOS. Und Basic ist eigentlich das Gegenteil von dem, was ich beschrieben habe. Es ist nicht ausdrucksstark, nicht minimalistisch, nicht explizit. Es war bestenfalls halbwegs konsistent. Fehlervermeidend war es schon gar nicht, man denke nur an das unsägliche ON ERROR GOTO NEXT.

Danach habe ich zehn Jahre lang sehr intensiv mit C# gearbeitet. C# ist in fast allen Belangen besser als Basic: Es ist ausdrucksstärker, expliziter und weniger fehleranfällig. Nur minimalistisch ist es nicht, auch in C# gibt es zu viele Wege, dasselbe zu machen. Aber im Vergleich zu Basic war es trotzdem eine deutliche Verbesserung.

Dann kam JavaScript, mit dem ich wiederum zehn Jahre sehr viel gearbeitet habe. JavaScript kann tatsächlich minimalistisch genutzt werden, das macht es aber nicht zu einer minimalistischen Sprache. Tatsächlich gibt es auch in JavaScript sehr viele Schlüsselwörter und es ist weniger konsistent und gleichzeitig deutlich fehleranfälliger als C#. Unterm Strich sind die beiden Sprachen also durchaus unterschiedlich, aber ich würde sie letztlich als "gleichwertig" bezeichnen, nur eben als "anders".

Der aktuelle Kandidat: Go

Seit einigen Jahren arbeite ich nun hauptsächlich mit Go. Go ist eine viel kleinere Sprache als alle zuvor genannten: Es ist minimalistischer, konsistenter, weniger fehleranfällig und trotzdem ausdrucksstark. Ich fühle mich momentan mit Go sehr wohl, aber es wird wohl nicht die letzte Sprache sein, mit der ich mich jemals beschäftigen werde.

Wenn ich diese Reise von Basic über C# und JavaScript zu Go Revue passieren lasse, dann sehe ich, wie die von mir bevorzugten Sprachen immer mehr in die Richtung dessen gehen, was ich als gutes Sprachdesign empfinde. Das sagt allerdings absolut noch nichts über die Standardbibliothek, das Tooling oder ähnliches aus – es geht nur um die Sprache an sich.

Und: Was für mich funktioniert, muss nicht für jeden passen. Ich habe versucht, objektive Kriterien zu nennen, aber die Frage, ob eine Sprache gut oder schlecht ist, hängt immer vom eigenen Wertesystem ab. Selbst wenn Du die gleichen Kriterien anwendest wie ich, musst Du nicht zum gleichen Ergebnis kommen. Unterschiedliche Sprachen haben unterschiedliche Stärken und Schwächen.

Ich nehme aber an, dass niemand sagen würde, alle Sprachen seien gleich gut, denn sonst würden wir alle immer noch dieselbe Sprache nutzen, mit der wir irgendwann einmal angefangen haben. Die Tatsache, dass wir das nicht tun, zeigt, dass wir eine andere Sprache für gelungener hielten (oder dass wir uns in eine Nische weiterentwickelt haben, in der wir um eine bestimmte Sprache nicht herumkommen, unabhängig davon, ob wir sie gut oder schlecht finden).

Was bleibt

Was für mich bleibt, sind vor allem zwei Dinge: Erstens kann ich auf Basis meines persönlichen Wertesystems argumentativ erläutern, warum ich bestimmte Sprachen gegenüber anderen bevorzuge, und warum ich zum Beispiel Go für gelungener halte als C#. Zweitens ist mir bewusst, dass diese qualitative Einschätzung von jeder Entwicklerin und jedem Entwickler anders getroffen werden kann, da der eigene Hintergrund jeweils ein anderer ist – und das macht eine objektive Darstellung so schwierig.

Hinzu kommt noch, dass man eine Sprache letztlich nur nach diesen Kriterien auswählt, sondern eben auch nach Tauglichkeit für das vorliegende Problem, nach Tooling, nach Funktions- und Klassenbibliothek, und, und, und.

Und deshalb macht man es sich zu leicht, wenn man jemanden belächelt, weil sie oder er mit Visual Basic programmiert: Ja, auch in meinen Augen ist Visual Basic keine besonders gelungene Sprache. Trotzdem kann es sein, dass sie für den eingangs erwähnten Entwickler genau das Richtige ist, aus einer Vielzahl von Gründen. Und statt darüber zu urteilen, sollten wir vielleicht eher neugierig und überrascht nachfragen: Warum? Denn vielleicht können wir dabei etwas lernen.


URL dieses Artikels:
https://www.heise.de/-10248069

Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[3] https://www.youtube.com/watch?v=JxF5cv9LNIc
[4] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Weniger ist mehr: Was guten Code (und gute Architektur) kaputtmacht

Von Golo Roden — 16. Januar 2025 um 09:26
Skizze von einem Haus

(Bild: Erstellt mit KI (Midjourney) durch iX-Redaktion)

Je erfahrener ein Entwickler oder eine Architektin ist, desto besser die Ergebnisse – sollte man meinen. Doch tatsächlich ist häufig das Gegenteil der Fall.

Vielleicht kennen Sie die Situation: Sie öffnen ein Projekt, das jemand anderes entwickelt hat, und schon nach wenigen Minuten denken Sie sich:

"Das ist aber ganz schön kompliziert implementiert!"

Je mehr Code Sie lesen, desto stärker beschleicht Sie das Gefühl, dass vieles unnötig komplex ist. Häufig sind es Abstraktionsebenen, die Dinge verschleiern, die eigentlich pragmatisch und einfach hätten gelöst werden können. Solche Ansätze machen den Code schwer verständlich – und das gilt nicht nur für den Code, sondern auch für die Architektur eines Projekts. Vielleicht haben auch Sie schon einmal das Gefühl gehabt, dass weniger darauf geachtet wurde, guten Code zu schreiben, sondern dass jemand sich an einer übertriebenen Komplexität verkünstelt hat.

Genau darum geht es heute: Architektur sollte im Idealfall unsichtbar sein. Doch was bedeutet das genau? Und wie können Sie dieses Prinzip für sich nutzen?

Gute Architektur ist unsichtbar

Fangen wir mit der Frage an, was es bedeutet, dass eine gute Architektur unsichtbar ist. Ein Vergleich mit der Realität hilft, das zu verdeutlichen. Denken Sie an beeindruckende Bauwerke: vielleicht an eine moderne Villa, bei der jedes Detail passt und alle Entscheidungen nahtlos ineinanderfließen. Oder an ein historisches Bauwerk wie den Kölner Dom, das architektonisch ebenfalls fasziniert. Der entscheidende Punkt ist: Sie bewundern in beiden Fällen das Bauwerk als Ganzes. Sie wissen zwar, dass dahinter eine durchdachte Architektur steckt, diese drängt sich Ihnen aber nicht auf. Vielmehr wirkt alles wie ein schlüssiges Gesamtbild, bei dem man spürt, dass alle Details durchdacht sind. Das heißt, gute Architektur tritt in den Hintergrund und fordert nicht ständig Ihre Aufmerksamkeit.

Natürlich ließe sich alternativ auch ein Bauwerk schaffen, bei dem jede architektonische Entscheidung überdeutlich sichtbar wird. Das mag zwar schick aussehen, würde aber den Eindruck einer überambitionierten Studie vermitteln, die mehr Selbstzweck als Grundlage für ein großartiges Bauwerk ist. Und genau das meine ich, wenn ich sage: Gute Architektur ist unsichtbar. Sie schafft Strukturen, ohne sich in den Vordergrund zu drängen.

Architektur trifft Softwarearchitektur

Dieses Prinzip gilt nicht nur für Bauwerke, sondern auch für Software. Auch hier ist Architektur kein Selbstzweck. Sie sollte ein solides Fundament liefern, auf dem eine gut strukturierte, wartbare und langfristig nutzbare Software entstehen kann. Wenn eine Architektur diese Ziele erfüllt, ohne sich selbst zu wichtig zu nehmen, ist sie gelungen. Wenn sie diese Ziele hingegen verfehlt oder unnötig in den Vordergrund rückt, ist sie schlecht.

Bis hierhin klingt das alles vielleicht recht einleuchtend. Doch wenn es so einfach wäre, würden wir nicht so häufig auf Projekte stoßen, bei denen wir uns denken:

"Was ist das denn? Was hat sich da bloß jemand gedacht?"

Über die Jahre fällt dann ein Muster auf: Menschen, die gerade erst mit der Programmierung beginnen, entwickeln oft einfache und pragmatische Lösungen – allein schon deshalb, weil sie es nicht anders können. Mit wachsendem Wissen neigen Entwicklerinnen und Entwickler jedoch dazu, Probleme immer stärker zu abstrahieren. Das wird uns in der Ausbildung schließlich so beigebracht: Der Versand einer Word-Datei wird abstrahiert zu "Dateiversand", dieser wiederum zur Nachricht eines Senders an einen Empfänger – und am Ende reden wir nur noch abstrakt über "Messaging". Dabei wollte man ursprünglich einfach nur eine Word-Datei per E-Mail versenden.

YAGNI – You Ain't Gonna Need It

Das Problem dabei ist oft zu viel und vor allem zu frühe Abstraktion. Jede Abstraktion führt zu einer weiteren Indirektion, die den Code schwerer verständlich macht. Statt den eigentlichen Gedankengang der Entwicklerin oder des Entwicklers im Code nachvollziehen zu können, muss man diesen gedanklich zunächst auf eine andere Ebene übersetzen. Je mehr solche Ebenen es gibt, desto schwieriger wird es, den Code zu verstehen. Dabei wird Code jedoch nur einmal geschrieben, aber viele Male gelesen. Der Fokus sollte daher viel eher auf Lesbarkeit, Nachvollziehbarkeit und Verständlichkeit liegen, nicht auf möglichst vielen Abstraktionen. Das "You Ain’t Gonna Need It"-Prinzip (YAGNI) ist nicht ohne Grund ein Leitmotiv in der Softwareentwicklung: Keep it simple! Dieses Prinzip gilt für Code genauso wie für Architektur.

Ein zentraler Aspekt ist die klare Definition von Verantwortlichkeiten: Welche Funktion, Klasse oder welcher Service ist wofür zuständig? Die Prinzipien der niedrigen Kopplung und der hohen Kohäsion helfen hier: Einzelne Elemente sollten möglichst unabhängig voneinander existieren, während alles, was zu einer Aufgabe gehört, an einem Ort zusammengeführt wird. Wenn Sie also einen Fehler beheben müssen, sollte die Änderung an einer Stelle genügen, ohne andere Teile des Systems zu beeinflussen.

Ein Beispiel aus der Praxis

Ein Beispiel aus der Praxis verdeutlicht das: In einem Code-Review stieß ich auf eine unnötige Abstraktion in einer Go-Codebasis. Anstatt einen Pointer zu verwenden, um auszudrücken, dass ein Wert optional ist, hatte die Entwicklerin einen Maybe-Typ eingeführt – ein Konzept aus der funktionalen Programmierung. Dieser Typ war jedoch nur an einer einzigen Stelle im Code verwendet worden, was weder konsistent noch sinnvoll war. Ein einfacher Pointer hätte denselben Zweck erfüllt und wäre deutlich verständlicher und weniger fehleranfällig gewesen.

Das Problem unnötiger Abstraktion tritt nicht nur auf Code-, sondern auch auf Architekturebene auf. So wird manchmal ein Microservice eingeführt, nicht weil er notwendig ist, sondern um das Konzept eines Microservices umzusetzen. Das führt zu unnötiger Komplexität und verfehlt das eigentliche Ziel, die Struktur und Verständlichkeit der Software zu verbessern.

Lesbarkeit schlägt Schreibbarkeit

Warum verkünsteln sich erfahrene Entwicklerinnen und Entwickler so oft? Ein Grund ist der Wunsch nach Perfektion, ein anderer das Streben nach Anerkennung. Es ist wichtig, sich diesen Effekt bewusst zu machen und den eigenen Code und die eigene Architektur zu reflektieren. Code-Reviews und Pair-Programming können hier helfen, denn sie fördern pragmatische Ansätze und die Verständlichkeit für andere.

Architektur und Code sind Mittel zum Zweck, kein Selbstzweck. Sie sollten die fachlichen Anforderungen und die Bedürfnisse des Teams in den Mittelpunkt stellen. Lösungen sollten iterativ und pragmatisch entwickelt werden. Fragen Sie sich stets: Braucht das Team diese Abstraktion wirklich, oder verkompliziert sie die Dinge nur unnötig?


URL dieses Artikels:
https://www.heise.de/-10225156

Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Neu in .NET 9.0 [4]: Partielle Properties und partielle Indexer in C# 13.0

Von Dr. Holger Schwichtenberg — 13. Januar 2025 um 14:30

(Bild: Pincasso/Shutterstock)

C# 13.0 bietet neben partiellen Klassen und Methoden jetzt auch die lang erwartete Umsetzung für partielle Properties und Indexer.

Eine wichtige Neuerung in C# 13.0 sind partielle Properties und Indexer. Auf dieses Sprachfeature warten viele Entwicklerinnen und Entwickler bereits seit der Einführung der partiellen Methoden in C# 3.0. Das C#-Schlüsselwort partial gibt es sogar bereits seit C# 2.0 für Klassen.

Mit partiellen Klassen kann man den Programmcode einer einzigen Klasse auf mehrere Codedateien aufspalten – ohne dafür Vererbung zu nutzen. Das ist nicht nur sinnvoll für mehr Übersichtlichkeit bei umfangreichen Klassen, sondern wird vor allem verwendet, wenn ein Teil der Klasse automatisch generiert und der andere Teil der Klasse manuell geschrieben wird. Diese Vorgehensweise kommt in .NET zum Beispiel bei GUI-Bibliotheken wie ASP.NET Webforms und Blazor, beim Reverse Engineering von Datenbanken mit Entity Framework und Entity Framework Core sowie bei Source-Generatoren (z.B. für reguläre Ausdrücke und JSON-Serialisierung) zum Einsatz.

In C# 13.0 können Entwicklerinnen und Entwickler auch Property- und Indexer-Definition sowie deren Implementierung mit partial in zwei Dateien trennen. Dabei müssen beide Teile jeweils die gleiche Kombination von Getter und Setter mit den gleichen Sichtbarkeiten sowie dem gleichen Typ realisieren.

Ein konkretes Beispiel: Wenn in einem Teil der Klasse eine Property sowohl einen öffentlichen Getter als auch einen öffentlichen Setter besitzt, müssen diese auch im anderen Teil vorhanden und öffentlich sein. Aber während in einem Teil ein automatisches Property verwendet wird, kann im anderen Teil eine explizite Implementierung vorhanden sei.

Partielle Properties und partielle Indexer können genau wie partielle Klassen und partielle Methoden NICHT aus mehreren Projekten/Assemblies zusammengeführt werden. Alle Teile müssen in dem gleichen Projekt sein!

Die Neuerungen in Codebeispielen

Die folgenden Listings zeigen ein Beispiel einer aufgeteilten Klasse mit partieller Methode und partiellem Property sowie einem partieller Indexer.

Der erste Codeausschnitt zeigt den ersten Teil der partiellen Klasse nur mit Definitionen von Property ID, Indexer und Print():

using System.Text.Json.Serialization;
 
namespace NET9_Console.CS13;
 
/// <summary>
/// Erster Teil der partiellen Klasse nur mit Definitionen
/// </summary>
public partial class PersonWithAutoID
{
 // NEU: Partielles Property --> kein "Convert to Full Property"
 public partial int ID { get; set; }
 // NEU: Partieller Indexer
 public partial string this[int index] { get; }
 // "Normales Property"
 public string Name { get; set; }
 // Partielle Methode (gab es vorher schon)
 public partial void Print();
}

Im zweiten Teil der partiellen Klasse werden Getter und Setter für ID und den Indexer sowie die Methode Print() implementiert:

/// <summary>
/// Implementierung der Getter und Setter für ID, der Getter für den Indexer sowie die Methode Print()
/// </summary>
public partial class PersonWithAutoID
{
 int counter = 0;
 
 // Implementierung des Partial Property
 private int iD;
 
 public partial int ID
 {
  get
  {
   if (iD == 0) iD = ++counter;
   return iD;
  }
  set
  {
   if (ID > 0) throw new ApplicationException("ID ist bereits gesetzt");
   iD = value;
  }
 }
 
 // Implementierung des Partial Indexer
 public partial string this[int index]
 {
  get
  {
   return index switch
   {
    0 => ID.ToString(),
    1 => Name,
    _ => throw new IndexOutOfRangeException()
   };
  }
 }
 
 // Implementierung der Partial Method
 public partial void Print()
 {
  Console.WriteLine($"{this.ID}: {this.Name}");
 }
}

Folgender Code implementiert den Nutzer der zusammengesetzten Klasse PersonWithAutoID:

/// <summary>
/// Client-Klasse für die Demo
/// </summary>
public class CS13_PartialPropertyAndIndexerDemoClient
{
 public void Run()
 {
  CUI.Demo(nameof(CS13_PartialPropertyAndIndexerDemoClient));
  CS13.PersonWithAutoID p = new() { Name = "Holger Schwichtenberg" };
  p.Print(); // 1: Holger Schwichtenberg
  CUI.H2("Versuch, die ID neu zu setzen, führt zum Fehler:");
  try
  {
   p.ID = 42;
  }
  catch (Exception ex)
  {
   CUI.Error(ex); // System.ApplicationException: ID ist bereits gesetzt
  }
  CUI.Print($"Nutzung des Indexers: {p[0]}: {p[1]} ");
 }
}


URL dieses Artikels:
https://www.heise.de/-10237499

Links in diesem Artikel:
[1] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Neu in .NET 9.0 [3]: Features in der Programmiersprache C# 13.0

Von Dr. Holger Schwichtenberg — 03. Januar 2025 um 08:30

(Bild: Pincasso/Shutterstock)

Die Programmiersprache C# 13.0 ist zusammen mit Visual Studio 2022 Version 17.12 und .NET 9.0 am 12. November 2024 erschienen.

Das neue C# 13.0 unterstützt Microsoft offiziell erst ab .NET 9.0 ("C# 13.0 is supported only on .NET 9 and newer vesions.").

C# 13.0 in älteren .NET-Versionen

Man kann allerdings die meisten Sprachfeatures aus C# auch in älteren .NET-Versionen einschließlich .NET Framework, .NET Core und Xamarin nutzen. Dazu muss man die verwendete Compilerversion per Tag <LangVersion> in der Projektdatei (.csproj) auf "13.0" erhöhen.

<LangVersion>13.0</LangVersion>

Damit Sprachfeatures auch in Versionen vor .NET 9.0 funktionieren, dürfen sie keine Abhängigkeit von in .NET 9.0 eingeführten Basisbibliotheksklassen haben. Sofern man <LangVersion>latest</LangVersion> in der Projektdatei setzt, sind in älteren Versionen folgende neuen Sprachfeatures von C# 13.0 möglich:

  • Partielle Properties und partielle Indexer
  • Generische Mengen in Verbindung mit dem Schlüsselwort params
  • Neuerungen für ref struct, außer der Verwendung als Typargument
  • Escape-Zeichen \e

Zu beachten ist aber, dass es für den Einsatz der neuen Sprachfeatures in .NET-Versionen vor 9.0 keinen technischen Support von Microsoft gibt, man also bei Problemen nicht den Support-Vertrag nutzen kann, um Microsoft um Hilfe zu ersuchen. Dennoch ist der Einsatz höherer C#-Versionen in älteren .NET-Projekten in einigen Unternehmen gängige und problemlose Praxis.

Stabile neue Sprachfeatures in C# 13.0

In C# 13.0 sind folgende neue Sprachfeatures erschienen, die ich in den kommenden Wochen in dieser Blogserie besprechen werde:

  • Partielle Properties und partielle Indexer,
  • neues ESCAPE-Zeichen \e für ANSI/VT100 Terminal Control Escape Sequences,
  • Prioritäten für Methodenüberladungen,
  • Generische Mengentypen bei params,
  • Objekt-Initialisierung mit Index-Operator vom Ende,
  • Neue Klasse Threading.Lock für lock-Anweisungen und
  • Erweiterungen für ref structs (auf Stack).

Experimentelles Sprachfeature in C# 13.0

Ein weiteres Sprachfeature ist in C# 13.0 in experimenteller Form enthalten: halbautomatische Properties mit dem neuen Schlüsselwort field. Dieses Schlüsselwort ist nur verfügbar, wenn man in einer Projektdatei entweder <EnablePreviewFeatures>True</EnablePreviewFeatures> oder <LangVersion>preview</LangVersion> setzt.

Vertagte neue Sprachfeatures

Folgende Sprachfeatures waren für C# 13.0 geplant und zum Teil schon als Prototyp verfügbar, wurden aber dann auf C# 14.0 vertagt [1], das im November 2025 erscheinen soll :

  • Tupel-Dekonstruktion(int x, string y) = default statt (default, default)
  • Automatische Konvertierung zwischen Array, Span<T> und ReadOnlySpan<T>
  • Extensions: eine weiterentwickelte, generalisierte Form der Extension Methods, bei der man nicht nur Instanzmethoden, sondern Methoden und Properties sowohl auf Instanz- als auch Klassenebene ("static") ergänzen kann. Dazu will Microsoft das neue Schlüsselwort extensioneinführen.

Breaking Changes in C# 13.0

Es gibt einige wenige Breaking Changes [2] im Verhalten des Compilers in C# 13.0 gegenüber C# 12.0. Dabei handelt es sich jedoch um Sonderfälle von geringer Bedeutung, beispielsweise das Verbot der Annotation [InlineArray] auf record struct).


URL dieses Artikels:
https://www.heise.de/-10217343

Links in diesem Artikel:
[1] https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md
[2] https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%209
[3] mailto:rme@ix.de

Copyright © 2025 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Neu in .NET 9.0 [2]: Support für .NET 9.0

Von Dr. Holger Schwichtenberg — 27. Dezember 2024 um 08:30
Kalender, physisch – und mit Smartphone

(Bild: TippaPatt/Shutterstock)

.NET 9.0 ist eine Version mit Standard-Term-Support (STS) für 18 Monate. Für einige Bibliotheken ist der Support aber deutlich kürzer.

Während die vorherige, im November 2023 erschiene Version 8.0 noch 36 Monate Support erhalten hat und daher noch bis zum November 2026 mit Updates versorgt wird, bietet Microsoft Aktualisierungen und technische Hilfe für .NET 9.0 für die Dauer von 18 Monaten, also nur bis Mai 2026 an.

Microsoft unterscheidet bei den Support-Zyklen für das moderne .NET zwischen STS- und LTS-Releases.

(Bild: Microsoft)

Für einige von Microsoft veröffentlichte .NET-NuGet-Pakete, die nicht Teil des .NET-SDKs sind, gilt eine andere Support-Richtlinie.

Das betrifft folgende Paketfamilien:

  • Extensions.*, zum Beispiel Microsoft.Extensions.Http.Resilience und Microsoft.Extensions.Telemetry
  • AspNetCore.*, zum Beispiel Microsoft.AspNetCore.Testing und Microsoft.AspNetCore.Diagnostics.Middleware

Für diese Pakete gilt:

  • Es kann jeden Monat ein neues Minor Release geben (9.1, 9.2, 9.3, ...).
  • Es gibt immer nur Support für das aktuellste Release.
  • Die Regeln des Semantic Versioning befolgt Microsoft nicht streng.

Die Liste der betroffenen NuGet-Pakete findet man auf der Seite zu den Extensions [1].

Microsoft erläutert den abweichenden Support für die .NET Platform Extensions.

(Bild: Microsoft [2])


URL dieses Artikels:
https://www.heise.de/-10215755

Links in diesem Artikel:
[1] https://dotnet.microsoft.com/en-us/platform/support/policy/extensions
[2] https://dotnet.microsoft.com/en-us/platform/support/policy/extensions
[3] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ FreshRSS.org

FreshRSS 1.25.0

Von Alkarex — 23. Dezember 2024 um 12:19

In this release, the coding focus has been on moving to PHP 8.1+ and refactoring the integration of the SimplePie library (which was long due). At the same time, plenty of new features have been added. Enjoy! 🎄

Breaking changes 💥:

  • Require PHP 8.1+ (and improved support of PHP 8.4+)
  • Require PostgreSQL 10+ or MariaDB 10.0.5+ or MySQL 8+

A few highlights ✨:

  • Add support for regex search (regular expressions)
    • ⚠️ Advanced regex syntax for searches depends on the database used (SQLite, PostgreSQL, MariaDB, MySQL),
      but FreshRSS filter actions such as auto-mark-as-read and auto-favourite always use PHP PCRE2 syntax.
  • Allow dynamic search operator in user queries, like search:UserQueryA date:P1d
  • New feed mode HTML+XPath+JSON dot notation (JSON in HTML)
  • Better HTTP compliance with support for HTTP response headers Cache-Control: max-age and Expires
  • New unicity policies and heuristic for feeds with bad article IDs (reduce the problem of duplicated articles)
  • New option to automatically mark new articles as read if an identical title already exists in the same category
  • Add ability to remove content from articles with CSS selectors, also when not using full content
  • New condition option to selectively retrieve full content of articles
  • New UI feature to download a user’ SQLite database or a database SQLite export (to be produced by CLI)
  • Supported by Capy Reader (Android, open source)
  • Many bug fixes, UI improvements, and a lot more

This release has been made by @aledeg, @Alkarex, @Art4, @ColonelMoutarde, @Frenzie, @math-GH, @ramazansancar
and newcomers @DevGrohl, @UserRoot-Luca, @aarnej, @andrey-utkin, @bhj, @christophehenry, @davralin, @drego85, @ev-gor, @killerog, @kwarraich, @minna-xD, @mtalexan, @oshaposhnyk, @patHyatt

Full changelog:

  • Features
    • Add support for regex search (regular expressions) #6706, #6926
      • ⚠️ Advanced regex syntax for searches depends on the database used (SQLite, PostgreSQL, MariaDB, MySQL),
        but FreshRSS filter actions such as auto-mark-as-read and auto-favourite always use PHP PCRE2 syntax.
    • Allow dynamic search operator in user queries, like search:UserQueryA date:P1d #6851
    • New feed mode HTML+XPath+JSON dot notation (JSON in HTML) #6888
    • Better HTTP compliance with support for HTTP response headers Cache-Control: max-age and Expires #6812, FreshRSS/simplepie#26
    • Support custom HTTP request headers per feed (e.g. for Authorization) #6820
    • New unicity policies and heuristic for feeds with bad article IDs #4487, #6900
    • Fallback to GUID if article link is empty #7051
    • New option to automatically mark new articles as read if an identical title already exists in the same category #6922
    • New reading view option to display unread articles + favourites #7088
      • And corresponding new filter state &state=96 (no UI button yet)
    • Add ability to remove content from articles with CSS selectors, also when not using full content #6786, #6807
    • Update phpgt/cssxpath library with improved CSS selectors #6618
      • Support for :last-child, :first-of-type, :last-of-type, ^=, |=
    • New condition option to selectively retrieve full content of articles
      #33fd07f6f26310d4806077cc87bcdf9b8b940e35, #7082
    • Allow parentheses in quoted search #7055
    • New UI feature to download a user’ SQLite database or a database SQLite export (to be produced by CLI) #6931
    • New button to delete errored feeds from a category #7030
    • Better import of Inoreader user labels #6791
    • Rebuild feed favicon on cache clear #6961
    • New sharing with Bluesky #7116
    • New sharing with Telegram #6838
  • Bug fixing
    • Fix searches with a parenthesis before an operator like ("a b") or (!c) #6818
    • Fix auto-read tags #6790
    • Fix CSS selector for removing elements #7037, #7073,
      #7081, #7091, #7083
    • Fix redirection error after creating a new user #6995
    • Fix favicon error in case of wrong URL #6899
    • Use cURL to fetch extensions list (allows e.g. IPv6) #6767
    • Fix XML encoding in cURL options #6821
    • Fix initial UI scroll for some browsers #7059
    • Fix menu for article tags in some cases #6990
    • Fix share menu shortcut #6825
    • Fix HTML regex pattern during install for compatibility with v mode #7009
    • More robust creation of user data folder #7000
  • API
    • Fix API for categories and labels containing a + #7033
      • Compatibility with FocusReader
    • Supported by Capy Reader (Android, open source) capyreader#492
    • Improved UI for API #7048
    • Allow adding multiple feeds to a category via API #7017
    • API support edit multiple tags #7060
    • API return all categories also those without any feed #7020
  • Compatibility
  • Deployment
    • Docker: dev image freshrss/freshrss:oldest updated to Alpine 3.16 with PHP 8.1.22 and Apache 2.4.59 #6711
    • Docker alternative image updated to Alpine 3.21 with PHP 8.3.14 and Apache 2.4.62 #5383
    • Update Dockerfiles to newer key-value format #6819
    • Docker minor improvement of entrypoint #6827
  • SimplePie
  • Security
    • Apache protect more non-public folders and files #6881, #6893, #7008
    • Add privacy settings on extension list retrieval #4603, #7132
    • Fix login in unsafe mode when using a password with special XML characters #6797
    • Fix login in e.g. Brave browser by avoiding synchronous XHR #7023
    • Fix invalid login message #7066
    • Modernise windows.open noopener (to avoid flash of white page in dark mode) #7077, #7089
  • UI
    • Searchable My Labels field #6753
    • Add subscription management button to reading view #6946
    • New option for showing label menu in article row #6984
    • Move to next unread label on mark as read #6886
    • Improved article footer for small / mobile screens #7031
    • Improve Web accessibility: fix aria-hidden bug, and use HTML5 hidden #6910
    • Default styles for <pre> and <code> #6770
    • Refactor the sharing menu to use a <template> instead of duplicated HTML code #6751, #7113
    • Refactor the label menu to use a <template> #6864
    • Rework UI for authors #7054
      • Avoid Unicode escape of authors in HTML UI #7056
    • Improved subscription management page #6816
    • Improve user query management page #7062
    • Restore JavaScript form validation compatibility with Web browsers using older engines (SeaMonkey) #6777
    • Reorganise some options #6920
    • New shortcut ? to show shortcut page and help #6981
    • Use of consistent colours in statistics #7090
    • Various UI and style improvements #6959
  • Extensions
    • New extension hook simplepie_after_init #7007
  • I18n
  • Misc.
✇ Developer-Blog - Der Dotnet-Doktor ff.org

Neu in .NET 9.0 [1]: Start der neuen Blogserie

Von Holger Schwichtenberg — 20. Dezember 2024 um 08:56

(Bild: Pincasso/Shutterstock.com)

Auch für das aktuelle .NET-Release wird der Dotnet-Doktor-Blog die Neuerungen in einer Artikelserie detailliert beschreiben.

Mit diesem Beitrag beginne ich die neue Blogserie zu .NET 9.0. Wie im letzten Jahr zu .NET 8.0 [1] werde ich in zahlreichen kleineren Beiträgen die Neuerungen in .NET 9.0 vorstellen.

.NET 9.0 steht seit dem 12. November 2024 auf der Downloadseite [2] kostenfrei zur Verfügung. Für .NET 9.0 benötigen Entwicklerinnen und Entwickler die Entwicklungsumgebungen Visual Studio 2022 [3] mindestens in der Version 17.12.

Entwickelt wurde .NET 9.0 in den letzten 12 Monaten. Seitdem hat Microsoft sieben Preview-Versionen und zwei Release-Candidate-Versionen veröffentlicht, über ich für heise developer jeweils berichtete.

Offizieller Name

Wie schon bei .NET 6.0/C# 10.0 und .NET 7.0/C# 11.0 sowie .NET 8.0/C# 12.0 verwendet Microsoft an einigen Stellen eine Schreibweise ohne ".0" (.NET 9/C# 13) und an anderen mit ".0" (.NET 9.0/C# 13.0). Ich werde einheitlich die Schreibweise mit ".0" verwenden, wie es auf der Downloadseite [4] steht.

Die Downloadseite (Stand 11.12.2024) verwendet einheitlich die Schreibweise .NET 9.0

(Bild: Microsoft [5])

Inhalt der Blogserie

Meine Serie wird in den kommenden Wochen und Monaten über diese Aspekte von .NET 9.0 berichten:

  • Neue Sprachfeatures in der Programmiersprache C# 13.0
  • Neue Funktionen im Software Development Kit (SDK) in .NET 9.0
  • Neue und erweiterte Klassen in der .NET 9.0-Klassenbibliothek:

Ziele der Blogserie

Meine Beiträge erheben dabei nicht den Anspruch, die Dokumentation zu ersetzen oder zu überbieten. Leserinnen und Leser können meine Beiträge als Impulsgeber verstehen, sich zu entscheiden, ob eine Neuerung für ihre Anwendungsfälle Sinn ergibt und sie sich damit dann näher beschäftigen wollen.

Ich werde die Beiträge der Serie jeweils so weit im Voraus schreiben, dass eine wöchentliche Veröffentlichung gewährleistet ist. Aufgrund von redaktionellen Engpässen kann es dennoch vorkommen, dass einmal eine Woche kein Beitrag erscheint.


URL dieses Artikels:
https://www.heise.de/-10215673

Links in diesem Artikel:
[1] https://www.heise.de/blog/Neu-in-NET-8-0-1-Start-der-neuen-Blogserie-9574680.html
[2] https://dotnet.microsoft.com/en-us/download/dotnet/9.0
[3] https://visualstudio.microsoft.com/
[4] https://dotnet.microsoft.com/en-us/download/dotnet/9.0
[5] https://dotnet.microsoft.com/en-us/download/dotnet/9.0
[6] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Continuous Architecture

Führt KI zu mehr arbeitslosen Entwicklern oder zu mehr Softwareproduktion?

Von Eberhard Wolff — 12. Dezember 2024 um 16:28

(Bild: incrediblephoto / Shutterstock.com)

Künstliche Intelligenz könnte zu einem enormen Produktivitätssprung in der Softwareentwicklung führen. Welche Auswirkungen kann das haben?

Nehmen wir einmal an, dass wir es schaffen, die Produktivität in der Softwareentwicklung um eine Größenordnung – also um den Faktor zehn – zu verbessern. Um es ganz konkret zu machen, ein Gedankenexperiment: Eine Projektleiterin wacht morgens auf und weiß, dass in ihrem Projekt statt 100 Menschen nur 10 Menschen notwendig sind. Sie weiß auch, welche Menschen das sind. Das ist absolut sicher, so wie der Himmel blau ist.

Was wird die Projektleiterin nun tun?

Die erste Option wäre, das Projekt mit zehn Personen fortzusetzen und den restlichen 90 Personen andere Aufgaben zu geben oder sie gar zu entlassen. Diese Option umzusetzen ist schwierig, weil die Projektleiterin sich und anderen damit eingesteht, dass zu viele Menschen an dem Projekt gearbeitet haben. Außerdem ist das Management eines 100-Personen-Projekts prestigeträchtiger als die Leitung eines Projekts mit zehn Personen. Das Vorgehen birgt auch ein Risiko, weil man die Personen nicht so einfach wiederbekommt, wenn man doch eine sinnvolle Aufgabe für sie findet.

Eine andere Option ist, die zehn Personen an dem ursprünglichen Projekt arbeiten zu lassen und den anderen eine andere Aufgabe zu geben. Dazu könnte man den Scope des Projekts vergrößern. Das ist gegebenenfalls relativ einfach möglich, denn der Wunsch nach mehr Features ist eher die Regel. Oder man sucht für die Menschen ein anderes Projekt. Am Ende steht bei beiden Optionen mehr Wert für die Organisation und damit mehr Prestige für alle Beteiligten.

Vielleicht könnte man das Projekt auch durch die zusätzlichen Personen beschleunigen. Das erscheint aber schwierig, da mehr Menschen ein Projekt sogar verlangsamen können, weil Einarbeitung und mehr Kommunikation notwendig sind. Fred Brooks hat genau darauf in seinem Buch "The Mythical Man Month" hingewiesen.

Realistisch?

Aber ist ein solches Gedankenexperiment überhaupt realistisch? Auch hier hat Fred Brooks eine Antwort: In seinem Paper "No Silver Bullet" [1] stellt er die Behauptung auf, dass keine einzelne Maßnahme alleine die Produktivität in der Softwareentwicklung um eine Größenordnung verbessern kann. Das lässt aber Raum dafür, dass eine Kombination von Maßnahmen dieses Ziel erreichen kann. Und außerdem ist es – so wie dieser Blog-Post – auch eine Hypothese, die er nicht weiter belegt.

Ein Grund, warum das Szenario vielleicht doch realistisch ist: Wie schon erwähnt, bedeuten mehr Menschen in einem Projekt mehr Prestige und somit gibt es einen Drang dazu, Projekte möglichst mit vielen Menschen durchzuführen. Das Gesetz von Parkinson besagt nun, dass alle verfügbaren Menschen auch an dem Projekt mitarbeiten werden. Da Softwareentwicklung viel Kommunikation bedeutet, kann diese Vielzahl an Menschen zu erschwerter Kommunikation führen. Weil die Kommunikation sich auch in der Architektur niederschlägt, bricht dann auch die Architektur zusammen. Die Beziehung zwischen Kommunikation und Architektur geht auf Conway und sein Gesetz zurück. Er hat auch die These von aufgeblasenen Projekten mit schlechter Kommunikation und am Ende schlechter Architektur aufgestellt, die bereits Thema eines anderen Blog-Posts [2] war.

Dann kommt man aber mit einer sauberen Architektur, weniger Menschen und damit weniger Kommunikation und Kommunikationsproblemen vielleicht genauso schnell zum Ergebnis, sodass das Gedankenexperiment vielleicht doch nicht ganz unrealistisch ist.

Künstliche Intelligenz?

Motivator für das Gedankenexperiment ist aber eine andere Entwicklung: Es kann sein, dass wir durch künstliche Intelligenz bei der Produktion von Code deutlich effizienter werden, wie ein anderer Blog-Post [3] diskutiert hat. Dann ist die Frage, was bei einer Verbesserung von Produktivität um einen Faktor 10 passiert, sehr relevant.

Das Gedankenexperiment legt den Verdacht nahe, dass selbst bei einem solchen Fortschritt eher mehr Software produziert wird und in der Konsequenz Software auch für Bereiche genutzt wird, für die es sich im Moment noch nicht lohnt.

Tatsächlich gibt es in der Ökonomie für dieses Phänomen: Rebound-Effekt [4]. Wenn beispielsweise Autos effizienter werden, werden sie für mehr Fahrten genutzt, sodass am Ende nicht etwa der Verbrauch sinkt, sondern gegebenenfalls sogar steigt. Vielleicht führt KI zu einem ähnlichen Effekt: Softwareentwicklung wird damit zwar effizienter, aber Software wird dann auch für andere Einsatzzwecke genutzt, sodass am Ende der investierte Aufwand derselbe bleibt. Tatsächlich unterstützt Software immer mehr Bereiche und KI könnte diesen Trend dann noch verstärken.

Im Extremfall können Menschen Software entwickeln, denen das technische Skillset eigentlich fehlt. Auch dieses Versprechen gab es schon mehrfach, mit Technologien wie COBOL, aber auch Low- oder No-Code. Aber selbst wenn KI hier erfolgreich ist: Andere Branchen zeigen, welche Effekte solche Disruptionen haben. Mit Desktop-Publishing können im Vergleich mit den Achtzigerjahren nun viel mehr Menschen Druckerzeugnisse erstellen, aber die Qualität ist eher schlechter geworden und Profis haben immer noch ihr Betätigungsfeld.

Das mag nun so wirken, als sei die Zukunft der Softwarebranche auch gegen KI abgesichert. Aber natürlich ist die Zukunft schwer vorhersagbar. Man hätte auch argumentieren können, dass die aktuelle Krise am IT-Markt nur ein Vorbote von dem ist, was KI anrichten wird. Die Zukunft ist offen.

tl;dr

Selbst eine Verzehnfachung der Produktivität in der Softwareentwicklung, wie sie KI vielleicht hervorbringt, bedeutet nicht unbedingt, dass weniger Menschen in dem Bereich arbeiten werden, sondern vielleicht eher, dass Software für noch mehr Einsatzzwecke genutzt wird.


URL dieses Artikels:
https://www.heise.de/-10189960

Links in diesem Artikel:
[1] https://software-architektur.tv/2024/02/02/folge201.html
[2] https://www.heise.de/blog/Beten-wir-Komplexitaet-an-4170914.html
[3] https://www.heise.de/blog/KI-in-der-Softwareentwicklung-Ueberschaetzt-9336902.html
[4] https://de.wikipedia.org/wiki/Rebound-Effekt_(%C3%96konomie)
[5] https://genai.bettercode.eu/?wt_mc=intern.academy.dpunkt.konf_dpunkt_bcc_genai.empfehlung-ho.link.link
[6] https://genai.bettercode.eu/?wt_mc=intern.academy.dpunkt.konf_dpunkt_bcc_genai.empfehlung-ho.link.link#programm
[7] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Architektur ist überbewertet – und was wir daraus lernen können

Von Golo Roden — 11. Dezember 2024 um 11:30
Architekturskizze eines Hauses

(Bild: Erstellt mit KI (Midjourney) durch iX)

Architektur wirkt oft wie eine dunkle Magie, die nur in den elitären Kreisen der Wissenden diskutiert wird. Das ist nicht nur falsch, sondern auch gefährlich.

"Architektur ist überbewertet" wirkt auf den ersten Blick wie ein typischer Clickbait-Titel, aber ich will kurz erklären, was genau ich mit diesem Titel meine. Architektur hat ein Problem, über das meiner Meinung nach viel zu wenig gesprochen wird, das aber auf uns als Entwicklerinnen und Entwickler gravierende Auswirkungen hat.

Es geht um die ständige Idealisierung und die überhöhte Wahrnehmung von Architektur, von Architekten und all dem, was damit zusammenhängt und einhergeht, wie zum Beispiel einer ganzen Reihe von Prinzipien, Konzepten und nicht zuletzt auch von einigen Personen.

Das schreckt ab, denn auf dem Weg wird Architektur nicht mehr als das wahrgenommen, was sie eigentlich ist – nämlich als die Kunst, Software adäquat zu strukturieren –, sondern sie wird auf einmal als Selbstzweck wahrgenommen. Das jedoch ist nicht nur falsch, sondern auch gefährlich.

Eine emotionale und keine sachliche Diskussion

Architektur hat ein Problem: Sie wird idealisiert und überhöht. Wenn Sie nicht genau wissen, was ich damit meine, stellen Sie sich vor, wie über typische Prinzipien und Konzepte aus der Architektur gesprochen wird: Da geht es nicht um ein paar hilfreiche Leitplanken und nützliche Wegweiser, die Sie bei Ihren Bemühungen zu einer gut strukturierten Software unterstützen. Nein, da geht es zum Beispiel um Clean Code (und ja, mir ist bewusst, dass das Thema für viele nicht unter Architektur fällt, im Sinne einer besseren Strukturierung von Software gehört aber auch Clean Code dazu).

Allein durch die Namensgebung sprechen wir nicht mehr nur auf einer technischen Ebene, sondern es schwingt noch etwas ganz anderes mit, etwas Emotionalisiertes: Wenn Sie sich nicht an diese Regeln halten, dann schreiben Sie Code, der schmutzig, ungepflegt und minderwertig ist. Wollen Sie so etwas etwa wirklich? Wo die Frage nach gut strukturiertem Code explizit auf der emotionalen Ebene exkludiert, fällt eine rein sachliche Diskussion schwierig.

Ein weiteres Beispiel sind die SOLID-Prinzipien. Auch suggeriert allein der Name bereits ein stabiles Fundament, ein Fels in der Brandung. Und wehe, Sie setzen sie nicht ein: Dann stehen Sie da wie ein Grashalm, der beim leichtesten Windhauch umknickt. Wollen Sie das?

Bei diesen Beispielen kann man sich sehr gut den erhobenen Zeigefinger vorstellen: Passen Sie bloß auf, sonst enden Sie wie all die anderen vor Ihnen – als Versager.

Fanatischer Eifer und Personenkult

Tatsächlich ist es jedoch nicht die Namensgebung allein: Das ist nur das, was als Erstes auffällt. Es geht noch weiter: Versuchen Sie einmal, Clean Code zu kritisieren. Sofort kommen zahlreiche Befürworterinnen und Befürworter, die Clean Code mit Leidenschaft verteidigen und als das Nonplusultra darstellen. So nach dem Motto:

"Wie können Sie es wagen, Clean Code zu hinterfragen, zu kritisieren oder gar infrage zu stellen? Was bildet Sie sich ein, wer Sie sind? Und übrigens: Sie haben damit auch Uncle Bob beleidigt, also entschuldigen Sie sich gefälligst!"

Vielleicht finden Sie das jetzt übertrieben, und natürlich verhält sich nicht jede Anhängerin und jeder Anhänger von Clean Code, SOLID & Co. derart. Das Problem ist jedoch: Es lässt sich nicht leugnen, dass um diese Themen ein gewisser Kult betrieben wird, inklusive eines ausgeprägten Personenkults. Ich behaupte nicht, dass das nur Uncle Bob alias Robert C. Martin betrifft, aber bei ihm ist es besonders auffällig. Und so etwas ist immer problematisch, denn dann wird nicht mehr sachlich über die Inhalte diskutiert. Stattdessen werden diese mit unsachlichen Emotionen und persönlichen Befindlichkeiten aufgeladen und untrennbar verknüpft.

Architektur? Ein Thema für die Elite

Wenn sich das über Jahre und Jahrzehnte verfestigt, hat das natürlich Folgen. Architektur und lesbarer Code werden dann nicht mehr als etwas wahrgenommen, womit sich jede und jeder beschäftigen sollte, sondern als etwas für die Eliten. Genau so erlebe ich oft die Meinung von weniger erfahrenen Entwicklerinnen und Entwicklern: Sie sagen, sie hätten von Architektur keine Ahnung, aber eines Tages würden sie das gerne in ihrem Jobtitel stehen haben, "Distinguished Senior Solution Architect" oder etwas Ähnliches.

So entsteht eine mystische Aura um dieses Thema, als wäre es nur für sehr erfahrene Menschen zugänglich, die es geschafft haben, Teil dieses elitären Kreises zu werden. Was genau eine Architektin oder ein Architekt eigentlich macht, wird dabei oft nicht mehr klar. Es scheint nur eines sicher: Es handelt sich um eine intellektuell anspruchsvolle Aufgabe, der Normalsterbliche vermeintlich nicht gewachsen sind. Dementsprechend beschäftigt man sich nicht mit Architektur, überlässt es den Weisen, entwickelt sich nicht weiter und bleibt jahrelang in dem Traum gefangen, selbst irgendwann ein Teil dieses elitären Zirkels zu sein, ohne den Weg dorthin zu kennen.

Kein Selbstzweck

Das eigentliche Problem ist, dass Architektur oft als Selbstzweck betrachtet wird: Sie wird um ihrer selbst willen betrieben und nicht als praktisches Werkzeug, das einer größeren Aufgabe dient. Nein, die Architektur selbst wird zur höheren Aufgabe erhoben. Das ist jedoch Unsinn. Clean Code kann durchaus kritisiert werden, und Robert C. Martin ist kein Heiliger. Die SOLID-Prinzipien sind, wenn wir ehrlich sind, fünf relativ beliebig ausgewählte Prinzipien, die in der Objektorientierung mehr oder weniger sinnvoll und manchmal nützlich sind.

Warum es ausgerechnet diese fünf Prinzipien geworden sind und nicht irgendwelche anderen, bleibt Spekulation. Vermutlich hat sich jemand ein schickes Akronym ausgedacht (eben "SOLID") und dazu Prinzipien zusammengesucht, die ansatzweise sinnvoll erschienen. Wenn man sich diese Prinzipien genauer anschaut, sind die meisten davon weder besonders elegant formuliert (im Sinne von anschaulich und greifbar), noch sind sie besonders hilfreich im Alltag. Ich kann mich zumindest nicht erinnern, wann ich das letzte Mal dachte:

"Wie praktisch, dass ich das Liskovsche Substitutionsprinzip kenne, ohne das wäre diese Struktur deutlich schlechter."

Dennoch wird vermittelt, dass die SOLID-Prinzipien die fünf wichtigsten Prinzipien der objektorientierten Programmierung seien. Das sind sie jedoch nicht, da die meisten viel zu spezifisch sind.

Das heißt, sie sind keine absolute Wahrheit, die nicht hinterfragt werden dürfte. Sie sind nur Mittel zum Zweck. Architektur (und dazu zähle ich Clean Code und diese Prinzipien wie oben schon erwähnt) hat letztlich nämlich nur ein einziges konkretes Ziel: Sie soll helfen, eine gute Struktur für Code zu schaffen, sodass dieser langfristig verständlich, überschaubar, wartbar und erweiterbar bleibt.

Der eigentliche Sinn von Architektur

Wann hat Code diese Struktur? Eigentlich ist das ganz einfach: immer dann, wenn zwei Grundprinzipien erfüllt sind. Code ist gut strukturiert, wenn er zum einen eine geringe Kopplung und zum anderen eine hohe Kohäsion aufweist. In dem Video zu Kopplung und Kohäsion [2] erkläre ich die beiden Prinzipien im Detail.

Diese beiden Prinzipien – geringe Kopplung und hohe Kohäsion – sind der Leitstern, der uns überall im Code Orientierung gibt, egal ob bei Funktionen und Klassen im Kleinen oder im Großen bei den zahlreichen Microservices einer verteilten Anwendung. Diese Prinzipien machen eine gute Architektur aus. Darüber nachzudenken und daran zu arbeiten erfordert keinen Titel wie "Distinguished Senior Solution Architect". Auch Praktikantinnen und Praktikanten können sich damit beschäftigen. Vielleicht fehlt ihnen etwas Erfahrung, aber sie sind durchaus intellektuell in der Lage, darüber nachzudenken.

Die entscheidende Frage lautet: Wo sollte ich mich um was kümmern, wer ist wofür verantwortlich? Das ist letztlich alles.

Die Entscheidungen müssen ein höheres Ziel unterstützen: die Fachlichkeit. Denn genau darum geht es in der Softwareentwicklung. Wir entwickeln nicht deshalb Software, weil es Spaß macht (auch wenn es tatsächlich Spaß macht), sondern um ein tieferliegendes fachliches Problem zu lösen. Software ist kein Selbstzweck, sondern ein Werkzeug, um einen fachlichen Zweck zu erfüllen. Und Architektur muss sich daran messen lassen.

Es geht nicht darum, ob wir alle fünf SOLID-Prinzipien umgesetzt oder möglichst viele Design-Patterns verwendet haben. Was am Ende zählt, ist, dass die Architektur das fachliche Problem unterstützt und es uns erleichtert, die Software langfristig zu warten und weiterzuentwickeln. Apropos Design-Patterns: Auch diese halte ich für überbewertet [3].

Falsche, weil zu frühe Entscheidungen

Mit diesem Mindset trifft man jedoch oft auf Projekte, in denen die Architektur schon feststand, bevor die fachlichen Anforderungen bekannt waren. Das halte ich für eine schlechte Idee, genauso wie die Wahl von Technologien, bevor Architektur und Anforderungen klar sind. Was ich in Teams oft erlebe, sind Argumente wie:

"Wir sind aber nicht Netflix. Wir brauchen keine Microservices, kein CQRS, kein Event-Sourcing, keine komplexe Architektur."

Stattdessen setzt man auf eine einfache Drei-Schichten-Architektur mit einem Monolithen und Dependency Injection. Missverstehen Sie mich nicht: Es gibt Projekte, wo das angemessen ist. Viel zu oft werden solche Entscheidungen jedoch mit unpassenden Argumenten und aus den falschen Gründen getroffen. Bei Microservices etwa ist die Frage nicht:

"Sind Sie Netflix?"

Stattdessen geht es (eigentlich) um geringe Kopplung und hohe Kohäsion bei ausreichend komplexer Fachlichkeit. Diese Anforderungen kann auch ein Drei-Personen-Start-up haben. Das hängt nicht davon ab, ob man Netflix ist, sondern vom jeweiligen Business.

Nachteile von "einfacher" Architektur

Die klassische Drei-Schichten-Architektur im Monolithen hat einige gravierende Nachteile: Fachlicher und technischer Code sind oft nicht sauber getrennt, was Anpassungen erschwert. Beim Testen merkt man das besonders: Es ist kaum möglich, die Geschäftslogik zu testen, weil immer die Datenbank mit dranhängt. Statt die Architektur zu hinterfragen, setzen viele dann auf Mocking. Doch Mocking ist eine der schlechtesten Ideen im Testen, weil es grüne Tests liefert, ohne sicherzustellen, dass die Mocks die Realität abbilden. Mit anderen Worten: Mocking wird zum Workaround für schlechte Architekturentscheidungen.

Tatsache ist: Es gibt deutlich bessere Ansätze. Gerade bei komplexer Geschäftslogik bietet sich etwa eine hexagonale Architektur an, die die Fachlichkeit in den Mittelpunkt rückt – ohne Abhängigkeiten zu externen Ressourcen. Doch auch hier heißt es oft:

"Wir sind doch nicht Netflix."

Solche Aussagen basieren oft auf Angst vor Veränderung. Das Problem sind nicht sachliche Argumente, sondern emotionale Bedenken:

"Das haben wir noch nie gemacht, also bleibt alles beim Alten."

Oft bekommen dann Berater den Auftrag, die beruhigende Botschaft zu verbreiten, ein Monolith reiche aus, denn man sei nicht Netflix. Das wird dann nach und nach zum gefährlichen Mantra.

Jahre später stellt man dann fest, dass die Technologie veraltet ist, aber ein Wechsel kaum möglich ist, weil alles miteinander verwoben ist. Technologiewechsel werden so zu Alles-oder-Nichts-Entscheidungen. Dabei treten viele Probleme auf: schlechte Testbarkeit, keine Skalierbarkeit, fehlende APIs für externe Systeme oder unklare Verantwortlichkeiten bei Master-Data-Management. All das hätte man vermeiden können, wenn man früher über eine fachlich sinnvolle Architektur nachgedacht hätte.

Was bedeutet das alles?

Der Sinn einer Architektur liegt darin, eine tragfähige Struktur für die Software zu schaffen, die geringe Kopplung und hohe Kohäsion gewährleistet. Wie man das erreicht, ist zweitrangig. Wichtig ist, dass die Fachlichkeit unterstützt wird. Unsachliche Diskussionen über Werkzeuge wie Clean Code, SOLID oder Design-Patterns helfen dabei nicht. Stattdessen sollten wir mehr darüber sprechen, warum wir Software entwickeln und wie die Fachlichkeit unsere Entscheidungen beeinflusst. Wer sich weiterhin hinter emotionalen und unsachlichen Argumenten versteckt, wird langfristig viel Schaden anrichten.

Fragen Sie sich daher immer, ob Ihre Architektur das fachliche Problem löst oder eher behindert. Und wenn Letzteres der Fall ist, denken Sie über Alternativen nach – losgelöst von dem, was in Lehrbüchern steht oder als Standard gilt. Architektur ist mehr als das. Jede Entwicklerin und jeder Entwickler kann dazu beitragen, denn Programmieren bedeutet, Strukturen zu schaffen.


URL dieses Artikels:
https://www.heise.de/-10191624

Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] https://www.youtube.com/watch?v=kWP432pXP-U
[3] https://www.youtube.com/watch?v=oC-9HZ0r3e4
[4] https://shop.heise.de/ix-developer-praxis-softwarearchitektur-2024/print?wt_mc=intern.shop.shop.ix-dev-softwarearchitektur24.dos.textlink.textlink
[5] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - ÜberKreuz

Web Almanac 2024: HTTP Archive gibt Web-Jahrbuch heraus, Livestream am 10.12.

Von Christian Liebel — 05. Dezember 2024 um 16:07

Der 2024 Web Almanac ist seit wenigen Tagen verfügbar

(Bild: HTTP Archive, Apache 2.0)

98 Prozent aller Requests nutzen HTTPS, 25 Prozent der Websites setzen keinerlei Caching ein: Nach einer Pause in 2023 meldet sich der Web Almanac zurück.

Der Web Almanac 2024 [1] ist da! Das kostenlose Jahrbuch bietet tiefgehende Einblicke in die aktuellen Entwicklungen des World Wide Web. Das in diverse Sprachen übersetzte Nachschlagewerk identifiziert Trends, aber auch Herausforderungen und richtet sich an alle, die das moderne Web verstehen und mitgestalten möchten.

83 TByte Daten verarbeitet

78 führende Webexperten aus der ganzen Welt haben ehrenamtlich 21 Kapitel verfasst, die unterschiedliche Aspekte des Web beleuchten: Dazu gehören Markup [2], Performance [3], E-Commerce [4] oder Cookies [5]. Alle Kapitel haben ein Peer-Review durchlaufen und die Rohdaten sind jeweils am Ende eines Artikels verlinkt. Die Analysen basieren auf den umfangreichen Daten des HTTP Archive [6].

Das Jahrbuch erschien vergangenes Jahr nicht, da sich der Projektleiter in Elternzeit befand und keine halbherzige Durchführung wollte. Verglichen zur Ausgabe von 2022 [7] hat sich das Rohdatenmaterial verdoppelt: Über 17 Millionen Websites wurden analysiert und über 83 TByte Daten verarbeitet. Das Jahrbuch wurde auf Basis der Daten des Juli-Crawls geschrieben.

Interessante und kuriose Erkenntnisse

Auch die diesjährige Ausgabe fördert wieder viele interessante, aber auch einige kuriose Erkenntnisse zutage:

  • 98 Prozent aller Requests nutzen HTTPS, 4 Prozentpunkte mehr als 2022 (Quelle [8])
  • 92 Prozent aller Webseiten binden Drittanbieterseiten ein (Quelle [9])
  • Fünf der zehn der meistverwendeten Drittanbieter-Domains gehören zu Google (Quelle [10])
  • 70 Prozent aller Desktopseiten haben ein h1-Element (bei 6 Prozent davon ist es leer, Quelle [11])
  • 70 Prozent der Top-1.000-Websites nutzen ein CDN (Quelle [12])
  • 61 Prozent aller Cookies sind Third-Party-Cookies (Quelle [13])
  • 29 Prozent aller verwendeten Elemente sind divs (Quelle [14])
  • 25 Prozent aller Websites nutzen kein Caching (Quelle [15])
  • 14 Prozent der mobilen Websites setzen auf umweltfreundlicheres Hosting (Quelle [16])

Einladung zum Livestream am 10. Dezember

Um die Veröffentlichung des Web Almanac 2024 zu feiern, laden die Autoren zu einem Online-Event ein, das am 10. Dezember 2024 um 19 Uhr stattfindet. Interessierte können sich unter folgendem Link zuschalten: The Web Almanac Live Stream (YouTube) [17].


URL dieses Artikels:
https://www.heise.de/-10186758

Links in diesem Artikel:
[1] https://almanac.httparchive.org/en/2024/
[2] https://almanac.httparchive.org/en/2024/markup
[3] https://almanac.httparchive.org/en/2024/performance
[4] https://almanac.httparchive.org/en/2024/ecommerce
[5] https://almanac.httparchive.org/en/2024/cookies
[6] https://httparchive.org/
[7] https://www.heise.de/blog/HTTP-Archive-legt-Web-Jahrbuch-2022-vor-mit-einigen-kuriosen-Erkenntnissen-7286733.html
[8] https://almanac.httparchive.org/en/2024/security#fig-1
[9] https://almanac.httparchive.org/en/2024/third-parties#prevalence
[10] https://almanac.httparchive.org/en/2024/third-parties#fig-6
[11] https://almanac.httparchive.org/en/2024/seo#header-elements
[12] https://almanac.httparchive.org/en/2024/cdn#fig-3
[13] https://almanac.httparchive.org/en/2024/cookies#fig-2
[14] https://almanac.httparchive.org/en/2024/markup#fig-13
[15] https://almanac.httparchive.org/en/2024/sustainability#fig-28
[16] https://almanac.httparchive.org/en/2024/sustainability#how-many-of-the-sites-listed-in-the-http-archive-run-on-green-hosting
[17] https://www.youtube.com/live/cdYR0ZmplIM
[18] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Low-Code & Co.: Mehr Schaden als Nutzen?

Von Golo Roden — 04. Dezember 2024 um 09:36
Abstraktes Bild zu Netzwerken

(Bild: Sergey Nivens/Shutterstock.com)

Low-Code- und No-Code-Plattformen versprechen Fachabteilungen, geschäftsrelevante Software selbst entwickeln zu können. Doch ist das wahr?

Stellen Sie sich für einen kurzen Augenblick vor, Sie würden nicht in der Softwareentwicklung arbeiten, sondern wären vielleicht Domänenexpertin oder -experte für Versicherungs-Policen. Sie arbeiten bei einer Versicherung in der Fachabteilung. Programmierung und Softwareentwicklung sind so gar nicht Ihre Themen, aber Sie kennen sich dafür bestens mit all den inhaltlichen Aspekten wie Policen, Schäden, Haftung und Regress aus.

Nun benötigen Sie ein kleines Stück Software: Vielleicht ein einfaches Tool, um die Daten von Kundinnen und Kunden effizienter zu erfassen, oder einen Report, der Ihnen ermöglicht, Ihre Policen für das nächste Jahr besser zu optimieren. Was es konkret ist, spielt letztlich keine Rolle. Es geht um etwas Kleines und Einfaches, das Ihnen und Ihren Kolleginnen und Kollegen das Leben erleichtert und Ihr Business voranbringt.

Wie kommen Sie nun zu dieser Software? Klar, Sie könnten natürlich zur hausinternen IT-Abteilung gehen und nett fragen. Wenn Sie Glück haben, sagt Ihnen die freundliche Kollegin aus der IT, dass das kein Problem sei. Sie würde sich darum kümmern und Ihnen das nebenbei bauen. Natürlich stellt sich nachher heraus, dass sie leider nicht ganz so viel Zeit erübrigen kann wie gedacht, und sie wusste vielleicht auch nicht ganz so genau, was Sie eigentlich im Detail wollten.

Deshalb macht die Software am Ende nicht ganz das, was sie sollte. Aber hey, beschweren Sie sich nicht: Immerhin haben Sie überhaupt etwas bekommen! Es hätte nämlich auch schlimmer kommen können: Wären Sie statt an die freundliche und hilfsbereite Kollegin an ihren grummeligen Kollegen geraten, hätte er Ihnen wahrscheinlich sehr deutlich zu verstehen gegeben, dass für so einen Quatsch keine Zeit da sei, die IT ohnehin völlig überlastet sei und Sie ohne eine um 27 Ecken eingeholte Budgetfreigabe gar nicht erst wieder ankommen bräuchten.

Wie schön wäre es, wenn Sie die IT einfach gar nicht bräuchten, sondern sich das, was Sie benötigen, einfach selbst hätten zusammenbauen können – ganz ohne jegliche Programmierkenntnisse? Willkommen bei der Welt der Low-Code- und No-Code-Plattformen!

Das Versprechen hinter Low-Code

Das, was ich Ihnen gerade geschildert habe, beschreibt letztlich das Werbeversprechen von Low-Code- und No-Code-Umgebungen. Die Idee dahinter ist, dass viele Vorgänge in Fachanwendungen mehr oder weniger immer gleich ablaufen: Formulareingaben, Datenabrufe aus einem SharePoint, tabellarische oder grafische Visualisierungen – all das sind immer wiederkehrende Muster. Die Plattform stellt nun solche Aktivitäten als Bausteine zur Verfügung, und Sie können sich daraus Ihre eigene Anwendung zusammenbauen, ohne wissen zu müssen, wie die technischen Details funktionieren.

Ich selbst habe das vor einiger Zeit einmal ausprobiert, gemeinsam mit einem Freund, auf Basis der Microsoft Power Platform, genauer gesagt mit Power Automate. Es ging um einen simplen Anwendungsfall: Daten von einer HTTP-API abrufen und anzeigen. Nach drei bis vier Stunden hatten wir dann allerdings keine Lust mehr, weil wir immer wieder auf Probleme stießen. Entweder waren wir zu zweit zu unfähig (was ich bezweifle), oder unser Anwendungsfall lag geringfügig außerhalb der vorgesehenen Nutzungspfade. Schlussendlich zogen wir einen Kollegen hinzu – einen zertifizierten "Microsoft Power Platform Developer". Ein Entwickler also für eine Plattform, die Entwickler angeblich überflüssig machen soll – an Absurdität lässt sich das kaum überbieten!

Die Realität: Mehr Frust als Nutzen

Dieser Vorfall ist natürlich nicht repräsentativ für alle Low- und No-Code-Plattformen. Aber er zeigt ein grundlegendes Problem auf: Die Plattformen machen große Versprechungen, schüren hohe Erwartungen – und die Realität bleibt dahinter zurück: Fachabteilungen können nicht plötzlich auf magische Weise alles selbst lösen. Sie können nicht auf die IT-Abteilung und Entwickler verzichten. Und sie sparen am Ende oft weder Zeit noch Geld. Im ungünstigsten Fall passiert sogar genau das Gegenteil.

Woran liegt das? Programmieren bedeutet, eine Sprache zu beherrschen. Egal, ob Sie Französisch oder eine Programmiersprache lernen: Sie müssen Vokabeln und Grammatik lernen, lesen, schreiben, sprechen – und üben. Entwicklerinnen und Entwickler haben sich all dieses Wissen in jahrelanger, mühsamer Arbeit angeeignet. Und nun kommt eine Plattform daher, die behauptet:

"Das brauchen Sie alles nicht!"

Stattdessen bekommen Sie Bausteine, die Sie anordnen sollen. Aber diese Bausteine reichen oft nicht aus, um komplexe Anforderungen abzubilden. Die fachliche und technische Komplexität bleibt bestehen – sie wird nur unsichtbar. Und spätestens, wenn eine Anwendung nicht performant läuft, Race Conditions auftreten oder der Datenverkehr das Netzwerk lahmlegt, kommen Sie ohne grundlegende Programmierkenntnisse nicht weiter.

Langfristige Risiken

Hinzu kommt, dass viele Plattformen proprietär sind. Sobald Sie eine Anwendung auf Basis einer solchen Plattform entwickeln, schaffen Sie einen Vendor-Lock-in. Die IT wird sich hüten, solche Anwendungen zu supporten. Das erinnert nämlich zu sehr an Microsoft Access, das in vielen Unternehmen bis heute Probleme verursacht. Das Problem ist also nicht neu – nur die Technologien haben sich geändert.

Darüber hinaus wissen Fachabteilungen oft selbst nicht, wie ihre Prozesse im Detail aussehen oder was sie genau wollen. Deshalb gibt es Business-Analysten und Requirements Engineers, die diese Anforderungen gemeinsam mit den Fachabteilungen erarbeiten. Fachabteilungen haben das fachliche Know-how, aber sie sind meist nicht darauf vorbereitet, dieses Wissen zielführend und nachhaltig in digitale Prozesse umzusetzen.

Trotz aller Kritik haben Low-Code-Plattformen aber natürlich auch ihre Berechtigung. Sie können die Kommunikation zwischen Entwicklung und Fachabteilung erleichtern, indem die Fachabteilung beispielsweise eigenständig Prototypen erstellt. Für einfache Anforderungen – wie "Formular ausfüllen und Daten per E-Mail senden" – können sie zudem durchaus ausreichen. Bei komplexeren Aufgaben würde ich jedoch zur Vorsicht raten.

Ein Plädoyer für Zusammenarbeit

Was mich an dem ganzen Thema aber mit Abstand am meisten stört, ist das Narrativ von "Entwicklung gegen Fachabteilung". Es geht nicht um "wir gegen die", und dieses Narrativ war noch nie konstruktiv oder gar zielführend, sondern führt stets nur zu Zwist und Schuldzuweisungen. Am Ende des Tages sind wir doch eigentlich dann erfolgreich, wenn wir unsere unterschiedlichen Fähigkeiten und Kenntnisse konstruktiv zusammenbringen und gemeinsam und partnerschaftlich auf ein gemeinsames Ziel hinarbeiten: Es geht um Partnerschaft auf Augenhöhe. Und Low-Code-Plattformen sollten diese Partnerschaft unterstützen, nicht spalten – doch genau das ist es, was sie letztlich machen.

Langer Rede, kurzer Sinn: Gehen Sie kritisch mit solchen Plattformen um. Verstehen Sie deren Grenzen und setzen Sie auf eine solide Zusammenarbeit zwischen Entwicklung und Fachabteilung. Nur so profitieren letztlich alle Beteiligten – außer vielleicht der Hersteller der Plattform.


URL dieses Artikels:
https://www.heise.de/-10184237

Links in diesem Artikel:
[1] https://www.heise.de/Datenschutzerklaerung-der-Heise-Medien-GmbH-Co-KG-4860.html
[2] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - the next big thing

Schulungsangebote vor Ort und virtuell: tech:lounge Live! und tech:lounge 360°

Von Golo Roden — 27. November 2024 um 08:57
Junger motivierter Lehrer erstellt seinen Unterricht mit KI.

(Bild: fizkes/Shutterstock.com)

Im Sommer 2025 veranstaltet die the native web GmbH eine eintägige Konferenz zum Thema professionelle Web- und Cloud-Entwicklung.

Das Jahr 2024 ist noch nicht ganz vorüber, aber es neigt sich allmählich dem Ende entgegen. Für meine Kolleginnen und Kollegen der the native web GmbH [1] und mich bedeutet das, dass in diesem Jahr nur noch ein paar wenige Posts in diesem Blog und auch Videos auf YouTube vor uns liegen, bevor wir uns in den Weihnachtsurlaub verabschieden werden. Es bedeutet aber auch, dass wir bereits fleißig mit der Planung für das kommende Jahr beschäftigt sind.

Was Sie im nächsten Jahr genau erwartet, das verrate ich Ihnen heute noch nicht im Detail, aber ich möchte zumindest schon einmal ein paar Worte über das vergangene Jahr verlieren.

Danke für 2024!

Rückblickend war 2024 für uns ein großartiges Jahr. In den vergangenen elf Monaten haben wir sage und schreibe 26 Blogposts geschrieben, 47 Videos veröffentlicht, fünf Livestreams veranstaltet und 36 Webinare im Rahmen unserer tech:lounge Masterclass durchgeführt. Und ganz gleich, was wir gemacht haben – eine Sache war immer gleich: Ihr Feedback!

Sie haben uns in so vielen Kommentaren, E-Mails, Telefonaten, persönlichen Gesprächen, auf Discord und sogar per Post (!) geschrieben und gesagt, wie ungemein wichtig unsere Videos und Artikel für Sie sind: für lebenslanges Lernen, für kontinuierliche Weiterbildung, für den Alltag. Sie haben uns mitgeteilt, dass wir Sie mit unserem Content unterstützt haben, sich weiterzuentwickeln, endlich den neuen Job zu bekommen, anderen weiterzuhelfen und vieles mehr.

Das macht uns unglaublich stolz und wir sind sehr dankbar für dieses Feedback, denn es zeigt uns, dass das, was wir machen, nicht einfach nur das nächste x-beliebige Content-Schnippsel im Internet ist, sondern dass wir wirklich etwas zum Guten bewirken können und einen positiven Einfluss auf Ihr Leben haben. Das ist alles andere als selbstverständlich. Und darüber bin ich sehr froh.

Ankündigung #1: Die tech:lounge Live!

Lebenslanges Lernen ist gerade in der IT ein wichtiges Thema. Nur wer sich dauerhaft und kontinuierlich weiterbildet, wird auch nachhaltigen Erfolg in der Softwareentwicklung haben. Deshalb haben wir uns auch für das kommende Jahr einiges vorgenommen. Was das alles im Detail sein wird, möchte ich an dieser Stelle noch nicht verraten, aber zwei Neuigkeiten möchte ich doch schon mit Ihnen teilen.

Zum einen werden wir im Sommer 2025 zum ersten Mal seit der Pandemie wieder eine Vor-Ort-Veranstaltung durchführen: Wir werden eine kleine, schnuckelige, eintägige Konferenz rund um das Thema der professionellen Web- und Cloud-Entwicklung bei uns in Freiburg im Breisgau veranstalten. Vom Morgen bis in den späten Abend hinein wird es am 4. Juli 2025 um Themen wie Architektur, Algorithmen, Protokolle, Skalierbarkeit und Ausfallsicherheit gehen.

Da wir die Veranstaltung direkt neben unserem Büro abhalten, ist das auch die perfekte Gelegenheit, meine Kolleginnen und Kollegen (und natürlich auch mich) einmal persönlich kennenzulernen. Wie das bei Veranstaltungen in der Realität leider so ist, ist der Platz natürlich begrenzt, das heißt, die Teilnahme ist auf 150 Personen limitiert. Ein Ticket kostet 399 Euro (zuzüglich 19 % Umsatzsteuer), und Sie können es ab sofort auf unserer Website buchen [2], um bei der tech:lounge Live! vor Ort dabei sein zu können. Und natürlich würde ich mich sehr freuen, Sie dort begrüßen zu dürfen!

Ankündigung #2: Die tech:lounge 360°

Das ist jedoch noch nicht alles. Pünktlich zum Jahresende haben wir noch ein ganz besonderes Spezialangebot für Sie: Wir haben uns überlegt, dass wir auch im kommenden Jahr wieder Webinare anbieten werden, und zwar 24 Stück. Normalerweise kostet ein einzelnes Webinar 179 Euro, und ein Dreierpaket kostet 399 Euro. Bei 24 Webinaren wären das also insgesamt über 4.200 Euro.

Weil wir aber wissen, dass viele von Ihnen regelmäßig bei unserer tech:lounge Masterclass zu Gast sind, bieten wir Ihnen bis zum 31. Dezember dieses Jahres an, die Teilnahme an allen 24 Webinaren, die im kommenden Jahr stattfinden werden, für lediglich 999 Euro zuzüglich 19 % Umsatzsteuer zu buchen. Das sind über 75% Rabatt, und damit möchten wir Ihnen für Ihre Treue und auch für das Vertrauen danken, das Sie in den vergangenen Monaten und Jahren in uns gesetzt haben. Auch hier wissen wir, dass das alles andere als selbstverständlich ist.

Wir nennen dieses Angebot tech:lounge 360°, denn – und das ist anders als bisher – alle 24 Webinare folgen einem durchgängigen roten Faden. Das bedeutet, wir werden ab März bis einschließlich Dezember gemeinsam eine komplette Anwendung entwickeln. Dabei sind nicht nur alle möglichen Themen enthalten, wie zum Beispiel Konzeption, Modellierung, Architektur, Entwicklung, APIs, Services, Deployment, Operations, Data-Management, UIs und vieles mehr, sondern wir fügen das alles auch noch zu einem einzigen, großen, durchgängigen praktischen Beispiel zusammen.

So können Sie innerhalb eines Jahres praxisnah verfolgen, wie nach und nach eine moderne und skalierbare Web- und Cloud-Anwendung entsteht. All das in über 80 Stunden Training, verteilt auf 24 Termine, für gerade einmal 999 Euro. Auch das Ticket hierfür können Sie ab sofort auf unserer Website buchen [3]. Es lohnt sich jedoch, schnell zu sein: Das vergünstigte Angebot gilt nur bis zum 31. Dezember 2024, danach gelten die regulären Konditionen und Preise. Auch hier würde ich mich natürlich sehr freuen, Sie begrüßen zu dürfen!

PS: Einen letzten Livestream für dieses Jahr wird es in ungefähr zwei Wochen übrigens auch noch geben, nämlich am 12. Dezember, wie immer ab 18 Uhr auf unserem YouTube-Kanal [4].


URL dieses Artikels:
https://www.heise.de/-10159636

Links in diesem Artikel:
[1] https://www.thenativeweb.io/
[2] https://techlounge.io/
[3] https://techlounge.io/
[4] https://www.youtube.com/@thenativeweb
[5] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Pragmatische Architekt

Künstliche Superintelligenz (ASI) und Allgemeine Künstliche Intelligenz (AGI)

Von Dr. Michael Stal — 20. November 2024 um 12:15

Vom gewöhnlichen LLM zur menschenähnlichen KI

(Bild: von DALL-E generiert)

Sind große Sprachmodelle tatsächlich kurz vor dem Erreichen eines menschlichen Niveaus, wie in einigen Publikationen und YouTube-Kanälen behauptet?

In derzeitigen Diskussionen über generative Künstliche Intelligenz werden häufig Begriffe wie Künstliche Superintelligenz (ASI – Artificial Super Intelligence) und Allgemeine Künstliche Intelligenz (AGI – Artificial General Intelligence) verwendet. Sie erwecken den Eindruck, dass wir mit den heutigen großen Sprachmodellen (LLMs) kurz vor der Erreichung von ASI oder AGI stehen. Laut IBM ist "künstliche Superintelligenz (ASI) ein hypothetisches, softwarebasiertes künstliches Intelligenzsystem (KI) mit einem intellektuellen Umfang jenseits menschlicher Intelligenz. Auf der grundlegendsten Ebene verfügt diese superintelligente KI über hochmoderne kognitive Funktionen und hochentwickelte Denkfähigkeiten, die fortschrittlicher sind als die eines jeden Menschen."

Motivation: Vision einer menschlichen KI

Ich vertrete jedoch eine andere Perspektive. Obwohl LLMs bedeutende Fortschritte in der Verarbeitung und Generierung natürlicher Sprache gemacht haben, sind sie im Wesentlichen ausgeklügelte statistische Modelle, die im Mustererkennen glänzen. Sie sind durch die begrenzte Menge an qualitativ hochwertigen verfügbaren Trainingsdaten eingeschränkt. Wenn wir die leicht zugänglichen Daten erschöpfen, wird es für Unternehmen wie OpenAI oder Anthropic zunehmend schwieriger, wie in der Vergangenheit erhebliche Fortschritte in Geschwindigkeit und Wissen ihrer Modelle zu erzielen.

Wie würde also eine wirklich menschenähnliche KI aussehen? Eine authentisch intelligente Maschine würde mehrere Schlüsselmerkmale aufweisen:

Proaktivität

Anstatt sich ausschließlich auf große Mengen an vorhandenen Daten zu verlassen, sollte eine KI die Fähigkeit haben, proaktiv neues Wissen und Erfahrungen durch selbstlernende Mechanismen zu suchen. Dies beinhaltet das Initiieren von Interaktionen mit anderen Maschinen und Menschen, um Informationen in Echtzeit zu erwerben. Eine wirklich intelligente Maschine würde nicht passiv statische Daten verarbeiten, sondern aktiv mit ihrer Umgebung interagieren, um ihr Verständnis zu erweitern.

  • Selbstlernende Fähigkeiten: Die KI sollte Algorithmen implementieren, die es ihr ermöglichen, dynamisch aus neuen Daten zu lernen, ohne explizite menschliche Programmierung für jede neue Situation.
  • Interaktives Engagement: Durch das Starten von Gesprächen oder Kollaborationen kann die KI verschiedene Perspektiven und Datenpunkte sammeln und so ihre Wissensbasis bereichern.

Autonomes Verhalten

Autonomie ist essenziell, damit eine KI wirklich ihre Umgebung erkunden und mit ihr interagieren kann. Eine intelligente Maschine sollte in der Lage sein, unabhängige Entscheidungen über ihre Handlungen und zukünftigen Richtungen zu treffen, ohne ständige menschliche Führung. Diese Autonomie ermöglicht es der KI, sich in komplexen, dynamischen Umgebungen zurechtzufinden und sich an neue Situationen und Herausforderungen anzupassen, wenn diese auftreten.

  • Entscheidungsfähigkeiten: Implementierung fortschrittlicher Algorithmen, die es der KI ermöglichen, Optionen abzuwägen und Entscheidungen basierend auf Zielen und gelernten Erfahrungen zu treffen.
  • Anpassungsfähigkeit an die Umwelt: Die KI sollte ihre Strategien als Reaktion auf Veränderungen anpassen, ähnlich wie Menschen es tun, wenn sie mit neuen Umständen konfrontiert werden.

Emotionale Intelligenz

Während Emotionen bei Menschen komplex und nicht vollständig verstanden sind, könnte die Einbeziehung von Elementen, die Emotionen wie Neugier und Zufriedenheit analog sind, die Fähigkeit einer KI verbessern, zu erkunden und zu lernen. Neugier treibt die Suche nach neuem Wissen an und veranlasst die KI, neuartige oder "interessante" Themen zu untersuchen.

  • Verstärkendes Lernen: Nutzung von Frameworks für verstärkendes Lernen kann emotionale Treiber simulieren, indem bestimmte Verhaltensweisen belohnt werden und die KI ermutigt wird, sie zu wiederholen.
  • Menschliche Interaktion: Damit eine KI effektiv mit Menschen interagieren kann, muss sie emotionale Hinweise verstehen und darauf reagieren können, was natürlicheres und bedeutungsvolleres Engagement ermöglicht.
  • Empathie und Verständnis: Entwicklung von Algorithmen, die es der KI ermöglichen, menschliche Emotionen zu erkennen und angemessen darauf zu reagieren, kann Zusammenarbeit und Vertrauen verbessern.

Sensoren und Aktoren

Die physische Interaktion mit der Umwelt ist entscheidend, damit eine KI erfahrungsbasiertes Wissen erlangen kann. Ausgestattet mit Sensoren und Aktoren kann eine KI ihre Umgebung wahrnehmen und Aktionen ausführen, die die Welt beeinflussen. Diese Verkörperung ermöglicht es der KI, aus direkter Erfahrung zu lernen und Informationen zu erwerben, die in bereits vorliegenden Datensätzen nicht vorhanden sind.

  • Verkörperte KI: Ob in einen Roboterkörper integriert oder mit entfernten Sensoren verbunden, erhält die KI eine physische Präsenz, die ihre Lernfähigkeiten verbessert.
  • Interaktion in der realen Welt: Durch Manipulation und Beobachtung kann die KI Hypothesen testen und die kausalen Beziehungen erlernen, die die physische Welt regieren.
  • Multimodales Lernen: Die Kombination von visuellen, auditiven, taktilen und anderen sensorischen Eingaben kann zu einem ganzheitlicheren Verständnis komplexer Umgebungen führen.

Denken, Meta-Denken und Reflexion

Fortgeschrittene kognitive Prozesse wie Denken und Selbstreflexion sind unerlässlich, damit eine KI aus ihren Erfahrungen, einschließlich Misserfolgen, lernen kann. Durch die Analyse vergangener Handlungen und Ergebnisse kann die KI ihr Verhalten anpassen, um die zukünftige Leistung zu verbessern.

  • Metakognitive Fähigkeiten: Die KI sollte in der Lage sein, über ihre eigenen Denkprozesse nachzudenken, was es ihr ermöglicht, ihre Lernstrategien zu optimieren.
  • Fehleranalyse: Die Identifizierung und das Verständnis von Fehlern ermöglichen es der KI, ihre Algorithmen zu verfeinern und Fehler nicht zu wiederholen.
  • Bewusstsein und Selbstwahrnehmung: Obwohl umstritten und herausfordernd, könnte die Entwicklung eines gewissen Grades an Selbstwahrnehmung der Schlüssel zur Erreichung echter AGI sein, indem die KI ihre eigenen Ziele setzen und ihre Existenz in einem breiteren Kontext verstehen kann.

Herausforderungen und der Weg in die Zukunft

Während aktuelle KI-Technologien beeindruckende Fortschritte gemacht haben, erfordert die Erreichung echter AGI oder ASI die Überwindung signifikanter Hürden:

  • Datenbeschränkungen: Da wir die Grenzen der verfügbaren Daten erreichen, werden neue Methoden der Wissensakquisition essenziell.
  • Ethische Überlegungen: Die Entwicklung von KI mit Autonomie und emotionalem Verständnis wirft wichtige ethische Fragen zu Kontrolle, Rechten und Sicherheit auf.
  • Technische Komplexität: Die Implementierung fortgeschrittener Denkprozesse und Selbstreflexion erfordert Durchbrüche in Rechenmodellen und Verarbeitungskapazitäten.
Fazit

Die Reise hin zu menschenähnlicher KI besteht nicht nur darin, Modelle zu skalieren oder Daten zu erhöhen, sondern erfordert ein grundlegendes Umdenken, wie KI-Systeme lernen, interagieren und denken. Indem wir uns auf Proaktivität, Autonomie, emotionale Intelligenz, physische Verkörperung und fortgeschrittene kognitive Prozesse konzentrieren, können wir der Entwicklung von KI näher kommen, die nicht nur menschliche Fähigkeiten nachahmt, sondern auch auf wirklich intelligente und autonome Weise mit der Welt interagiert.

Nur indem wir diese facettenreichen Herausforderungen angehen, können wir hoffen, das volle Potenzial der Künstlichen Intelligenz zu realisieren und den Weg für Maschinen zu ebnen, die wirklich denken, lernen und vielleicht eines Tages ein Bewusstsein ähnlich dem unseren besitzen.


URL dieses Artikels:
https://www.heise.de/-10039060

Links in diesem Artikel:
[1] mailto:map@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Neuigkeiten von der Insel

Java: Rekord beim bevorstehenden Release des OpenJDK 24

Von Falk Sippach — 20. November 2024 um 11:12

(Bild: Natalia Hanin / Shutterstock.com)

Das OpenJDK entwickelt sich rasant weiter. Die Anzahl der JEPs pro halbjährlichen Release steigt. Java gehört auch mit 30 Jahren noch nicht zum alten Eisen.

Für das OpenJDK 24 [1] sind aktuell (Stand: 20.11.2024) schon 24! (in Worten: vierundzwanzig) JEPs eingeplant. Das passt nicht nur zur nächsten Release-Nummer. Das ist auch ein neuer Rekord, seit die Entwicklung 2018 auf die halbjährlichen Release-Zyklen umgestellt wurde. Und die Zahl kann sogar noch weiter wachsen. Denn erst am 5. Dezember startet die Rampdown Phase One mit dem Feature Freeze für die nächste Version. Und weil es diesmal so viele JEPs (JDK Enhancement Proposals) sind, werden wir hier schon mal einen ersten Blick auf die aus Developer-Sicht interessantesten Punkte werfen, die aktuell eingeplant sind. Weitere Details können über die jeweiligen JEPs nachvollzogen werden.

In einem späteren Post schauen wir uns dann die restlichen Features an. Vielleicht kommen ja sogar noch welche hinzu. Wir dürfen also gespannt sein, was in den nächsten zwei Wochen passieren wird.

JEP 485 – Stream Gatherers

Nach zwei Previews erfolgt nun die Finalisierung. Die in Java 8 eingeführte Stream API unterstützt jetzt das Hinzufügen eigener Intermediate Operationen. Dadurch können Daten in Streams nun auf bessere, optimierte Art und Weise transformiert werden als mit den wenigen fest eingebauten Intermediate Operationen bisher. Somit können Stream Pipelines ab sofort flexibler und ausdrucksstärker implementiert werden. Das OpenJDK liefert auch gleich einige neue Operationen mit: fold, mapConcurrent, scan, windowFixed und windowSliding. In Zukunft können relativ einfach weitere folgen.

JEP 484 – Class-File API

Hier erfolgt nun ebenfalls nach zwei Previews die Finalisierung des neuen Standards zum Parsen, Generieren und Transformieren von Java-Bytecode (Class Files) basierend auf der Spezifikation der Java Virtual Machine. In Zukunft können alle JDK-Komponenten auf diese Standard-API migriert werden. Schlussendlich können die JDK-Entwickler dann die interne Kopie und damit die Abhängigkeit zur Drittanbieter-Bibliothek ASM entfernen.

JEP 488 – Primitive Types in Patterns, instanceof, and switch (Second Preview)

Es geht in diesem zweiten Preview um die Erweiterung des Pattern Matching, sodass primitive Datentypen wie int, byte und double in allen Pattern-Kontexten verwendet werden dürfen, also beim instanceof und im switch. Entwickler haben dadurch weniger Limitierungen und Sonderfälle und können primitive und Referenzdatentypen auch im Kontext von Type Patterns oder als Komponenten in Record Patterns austauschbar verwenden. Seit der ersten Preview gibt es keine Änderungen, die JDK-Entwickler wollen aber weiteres Feedback sammeln.

JEP 499 - Structured Concurrency (Fourth Preview)

Bei der Bearbeitung von mehreren parallelen Teilaufgaben erlaubt Structured Concurrency die Implementierung auf eine besonders les- und wartbare Art und Weise. Alternativ konnten Entwickler für diesen Zweck bisher die Parallel Streams, den ExecutorService oder reaktive Programmierung einsetzen. Alles sehr mächtige Ansätze, die aber gerade einfache Umsetzungen unnötig kompliziert und fehleranfällig machen. Structured Conncurrency behandelt Gruppen von zusammengehörigen Aufgaben als eine Arbeitseinheit, wodurch die Fehlerbehandlung sowie das Abbrechen der Aufgaben vereinfacht und die Zuverlässigkeit sowie die Beobachtbarkeit erhöht werden. Änderungen zur letzten Preview gibt es keine. Die Macher des OpenJDK wünschen sich vielmehr weitere Rückmeldungen aus der "realen" Welt.

JEP 487 – Scoped Values (Fourth Preview)

Einführung eines Gültigkeitsbereichs, sodass unveränderliche Daten sowohl in den Aufrufen innerhalb eines Threads als auch in Child-Threads geteilt und verwendet werden können. Scoped Values lassen sich einfacher nachvollziehen, verfolgen aber ähnliche Ziele wie ThreadLocal-Variablen. Sie haben auch einen geringeren Platz- und Zeitbedarf, insbesondere wenn sie zusammen mit virtuellen Threads (JEP 444 [2]) und Structured Concurrency (JEP 480 [3]) verwendet werden. Eine Änderung gibt es diesmal: Die Methoden callWhere() und runWhere() wurden aus der Klasse ScopedValue entfernt. Ihre Funktionalität kann aber noch über ein Objekt der Klasse Carrier aufgerufen werden, welches die Methode where() von ScopedValue zurückliefert. Dadurch wird die API vollständig fluent. Die Funktion call() liefert übrigens ein Ergebnis, während die Prozedur run() nichts zurückgibt.

JEP 489 – Vector API (Ninth Incubator)

Die Vector API ist der Dinosaurier unter den JEPs und nun schon das neunte Mal als Inkubator dabei. Seit Java 16 taucht sie regelmäßig in den Releases auf. Es geht dabei um die Unterstützung der modernen Möglichkeiten von SIMD-Rechnerarchitekturen mit Vektorprozessoren. Single Instruction Multiple Data (SIMD) lässt viele Prozessoren gleichzeitig unterschiedliche Daten verarbeiten. Durch die Parallelisierung auf Hardwareebene verringert sich beim SIMD-Prinzip der Aufwand für rechenintensive Schleifen. Der Grund für die lange Inkubationsphase hängt mit der Abstimmung mit dem Projekt Valhalla zusammen. Man wartet auf die Reformen am Typsystem (JEP 401: Value Classes and Objects [4]). Die Entwickler des JDK wollen vor der Finalisierung der Vector API die derzeitigen wertbasierten Klassen (Referenztypen) in Value Classes (ohne Objektidentität) umwandeln. Das kann noch etwas dauern, denn für das OpenJDK 24 sind die Value Types bisher noch nicht auf dem Plan. Aber immerhin hat Brian Goetz (Java Language Architekt bei Oracle) im Sommer 2024 angekündigt, dass sie beim Projekt Valhalla nach 10 Jahren den Durchbruch in der Implementierung geschafft haben. Hier könnte also mit dem OpenJDK 25 vielleicht schon die erste Preview auftauchen.

JEP 486 – Permanently Disable the Security Manager

Der Security Manager wurde häufig zur Absicherung von clientseitigem Java-Code (Rich-Clients, Applets), aber nur selten für die Server-Seite verwendet. Zudem ist seine Wartung teuer. Mit Java 17 (2021) wurde er als Deprecated for Removal markiert. Nun wird er intern ausgebaut. Er kann jetzt nicht mehr aktiviert werden und andere Klassen der Java-Plattform verweisen nicht mehr darauf. Diese Änderung wird aber vermutlich keine Auswirkungen auf die große Mehrheit der Anwendungen, Bibliotheken und Tools haben. In einer der zukünftigen Java-Versionen wird die Security Manager API endgültig entfernt.

JEP 492 – Flexible Constructor Bodies (Third Preview)

In Konstruktoren dürfen Anweisungen nun bereits vor einem expliziten Konstruktoraufruf (super() oder this()) erscheinen. Diese Anweisungen dürfen zwar nicht auf die zu konstruierende Instanz verweisen, können jedoch Parameter validieren bzw. transformieren oder auf Felder der Oberklasse zugreifen. Die Initialisierung von Feldern vor dem Aufruf eines anderen Konstruktors macht die Klasse zuverlässiger, wenn beispielsweise Methoden überschrieben werden.

JEP 494 – Module Import Declarations (Second Preview)

Dadurch lassen sich jetzt in Java alle exportierten Packages eines Moduls auf einmal importieren. Das vereinfacht die Wiederverwendung modularer Bibliotheken. Es ist übrigens nicht erforderlich, dass der importierende Code selbst in einem Modul enthalten ist. Bei dieser zweiten Preview gibt es zwei Erweiterungen. Einerseits wurden Beschränkungen bei den transitiven Abhängigkeiten vom Modul java.se (eine Art Aggregator-Modul ohne eigene Packages/Klassen) zu java.base aufgehoben. Dadurch kann man nun mit dem Import dieses einen Moduls die gesamte API von Java SE importieren. Außerdem ist es jetzt möglich, dass sogenannte Type-Import-on-Demand-Deklarationen (z. B. import java.util.*) vorherige Modul-Import-Deklarationen überdecken. Wenn beispielsweise die Module java.base und java.sql importiert werden, gäbe es eine Unklarheit beim Verwenden der Klasse Date. Die gibt es als java.util.Date und als java.sql.Date. Durch die on-demand-Deklaration import java.util.* wird in dem Fall java.util.Date verwendet.

JEP 495 – Simple Source Files and Instance Main Methods (Fourth Preview)

Das Ziel ist, Anfängern den Einstieg in Java zu erleichtern und erfahrenen Entwicklerinnen und Entwicklern die Möglichkeit zu geben, kleine Anwendungen einfach bauen und ausführen zu können. Anfänger wie auch Fortgeschrittene müssen sich somit nicht mit den für große Programme konzipierten Sprachfunktionen auseinandersetzen. In dieser vierten Preview soll weiter Feedback gesammelt werden. Unter Beibehaltung der bestehenden Java-Toolchain und nicht mit der Absicht, einen separaten Dialekt für Java einzuführen, lassen sich in simplen Java Source Files, die nur eine vereinfachte main-Methode (ohne Klassen-Deklaration) enthalten, einfache, skriptartige Programme erstellen. Dazu kommt die leichtere Verwendung von Standardein- und -ausgabe durch die neuen statischen Methoden print(), println() und readln() der Klasse java.io.IO. Diese wird zum Teil automatisch importiert, womit die Funktionen einsatzbereit sind.


URL dieses Artikels:
https://www.heise.de/-10051629

Links in diesem Artikel:
[1] https://openjdk.org/projects/jdk/24/
[2] https://openjdk.org/jeps/444
[3] https://openjdk.org/jeps/480
[4] https://openjdk.org/jeps/401
[5] mailto:rme@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

✇ Developer-Blog - Der Dotnet-Doktor ff.org

Fachbücher zu .NET 9.0, C# 13.0, Entity Framework Core 9.0 und Blazor 9.0

Von Dr. Holger Schwichtenberg — 13. November 2024 um 19:04

(Bild: jakkaje879/Shutterstock.com)

Die Bücher des Bloggers Dotnet-Doktor sind passend zum Release avon.NET 9.0 auf dem aktuellen Stand.

Pünktlich zum Release von .NET 9.0 [1] ist es mir auch dieses Jahr wieder gelungen, dass meine .NET-Bücher auf dem RTM-Stand (Release to Manufacturing) verfügbar sind:

Die Bücher gibt es in gedruckter Form (Print-on-Demand), im PDF-Format und als Kindle-E-Book.

Abbildung der Buchcover

(Bild: IT-Visions.de [6])


URL dieses Artikels:
https://www.heise.de/-10032056

Links in diesem Artikel:
[1] https://www.heise.de/news/Microsoft-NET-9-0-bringt-Breaking-Changes-und-neue-KI-Bibliothek-10031831.html
[2] https://it-visions.de/buch/N9U
[3] https://it-visions.de/buch/CSC13
[4] https://it-visions.de/buch/EFC13
[5] https://it-visions.de/buch/BLA90
[6] http://www.it-visions.de/NET9buecher
[7] https://net.bettercode.eu/?wt_mc=intern.academy.dpunkt.konf_dpunkt_bcc_net.empfehlung-ho.link.link
[8] https://net.bettercode.eu/index.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_bcc_net.empfehlung-ho.link.link#programm
[9] https://net.bettercode.eu/tickets.php?wt_mc=intern.academy.dpunkt.konf_dpunkt_bcc_net.empfehlung-ho.link.link
[10] mailto:mdo@ix.de

Copyright © 2024 Heise Medien

Adblock test (Why?)

❌