Entwicklung & Code
JavaScript: Testing-Framework Vitest 4.0 bringt visuelles Regressionstesting
Vitest liegt in der neuen Hauptversion 4.0 vor. Updates gibt es unter anderem für den Browser Mode, den Umgang mit dem End-to-End-Testing-Framework Playright und das Debugging mit der Visual-Studio-Code-Erweiterung.
Weiterlesen nach der Anzeige
Bei Vitest handelt es sich um ein Testing-Framework auf Basis des Frontend-Build-Tools Vite.js, das einen Fokus auf Schnelligkeit legt. Beide sind quelloffen verfügbar, jedoch arbeitet das Vite-Team derzeit auch an dem kommerziellen Angebot Vite+, das eine einheitliche JavaScript-Toolchain darstellen soll.
(Bild: jaboy/123rf.com)

Call for Proposals für die enterJS 2026 am 16. und 17. Juni in Mannheim: Die Veranstalter suchen nach Vorträgen und Workshops rund um JavaScript und TypeScript, Frameworks, Tools und Bibliotheken, Security, UX und mehr. Vergünstigte Blind-Bird-Tickets sind bis zum Programmstart erhältlich.
Browser Mode stabil verfügbar
Der Browser Mode ist ein Feature der Vitest-API, das bislang als experimentell gekennzeichnet war und nun den stabilen Status erreicht hat. Damit lassen sich Tests nativ im Browser ausführen.
Um einen Provider festzulegen, ist nun die Installation eines separaten Pakets notwendig: @vitest/browser-playwright, @vitest/browser-webdriverio oder @vitest/browser-preview. Damit können Developer einfacher mit benutzerdefinierten Optionen arbeiten, und sie können auf die Kommentare ///
Visuelles Regressionstesten im Browser Mode
Der Browser Mode erhält darüber hinaus eine neue Funktion: Visual Regression Testing. Das bedeutet, Vitest erstellt Screenshots von UI-Komponenten und Seiten und vergleicht diese mit Referenzbildern, um unbeabsichtigte visuelle Änderungen festzustellen. Das Visual Regression Testing lässt sich durch die Assertion toMatchScreenshot ausführen, wie das Entwicklungsteam demonstriert:
Weiterlesen nach der Anzeige
import { expect, test } from 'vitest'
import { page } from 'vitest/browser'
test('hero section looks correct', async () => {
// ...the rest of the test
// capture and compare screenshot
await expect(page.getByTestId('hero')).toMatchScreenshot('hero-section')
})
Updates für die Anbindung an Playwright und VS Code
Vitest 4.0 bringt ein Update für die Verwendung mit dem End-to-End-Testing-Framework Playwright: Es kann nun Playwright Traces generieren, wenn die trace-Option in der test.browser-Konfiguration gesetzt ist, oder mithilfe der Option --browser.trace=on, in der sich auch off, on-first-retry, on-all-retries oder retain-on-failure festlegen lassen. Die erstellte Trace-Datei lässt sich mit dem Playwright Trace Viewer öffnen. In der Extension für Visual Studio Code gibt es ebenfalls eine Neuerung: Dort lässt sich nun der „Debug Test“-Button beim Ausführen von Browser-Tests nutzen.
Die komplette Liste der Änderungen führt das Vitest-Team im Changelog auf und geht in einem Blogeintrag detaillierter auf die wichtigsten Neuerungen ein. Da es einige Breaking Changes gibt, empfiehlt es Entwicklerinnen und Entwicklern, vor einem Upgrade die Migrationsanleitung zu beachten.
(mai)
Entwicklung & Code
UserDeleted, Diagnose Mord: Wenn Software wie ein Tatort klingt
Wenn ich Kunden zu Domain-Driven Design (DDD) und Event Sourcing berate, gibt es einen Moment, der regelmäßig eintritt. Das Team wirkt selbstbewusst, vielleicht sogar ein wenig stolz. Sie sagen mir:
Weiterlesen nach der Anzeige
„Eigentlich arbeiten wir schon mit Events.“
Und dann zeigen sie mir ihre Events:
UserCreatedOrderUpdatedInvoiceDeleted
Und innerlich zucke ich zusammen.

Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.
Denn das sind keine Events, sondern klassisches CRUD, nur eben mit Event-Syntax. Es hat die äußerliche Form von Events, aber keine innerliche Semantik. Und dieser Unterschied, so subtil er auch erscheinen mag, ist der Unterschied zwischen einem System, das die Sprache des Business spricht, und einem, das die Sprache von Datenbanken spricht.
Das Beispiel: Enterprise-Print-Management
Weiterlesen nach der Anzeige
Stellen wir uns einen Kunden vor, der sich mit Enterprise-Drucken beschäftigt. Die Software verwaltet Tausende von Druckern in großen Organisationen: in Krankenhäusern, Universitäten und Unternehmensbüros. Drucker müssen dem System hinzugefügt, für Wartungsarbeiten offline genommen, pausiert, fortgesetzt und schließlich entfernt werden, wenn sie außer Betrieb genommen werden.
Das Team hat etwas gebaut, das sie ein „Event-getriebenes System“ nennen. Und das sind ihre Events:
PrinterCreatedPrinterUpdatedPrinterDeleted
Das war’s. Drei Events. Kommt Ihnen das bekannt vor?
Das ist CRUD in Verkleidung. Die Namen haben sich von INSERT, UPDATE und DELETE zu Created, Updated und Deleted geändert, aber die semantische Armut ist dieselbe. Wenn man sich ein PrinterUpdated-Event ansieht, was weiß man dann? Irgendetwas hat sich geändert. Aber was genau hat sich geändert? Dazu muss man in den Payload schauen. Warum hat es sich geändert? Keine Ahnung. War es eine geplante Wartungsmaßnahme oder ein unerwarteter Ausfall? Das Event verrät es nicht.
Das Mordproblem
Und mich erinnert das immer an ein etwas düsteres Beispiel (und die Ironie ist hoffentlich offensichtlich): Betrachten wir UserDeleted (was mir in der Praxis auch regelmäßig begegnet).
Sprechen Sie das mal laut und bewusst aus: UserDeleted. Es klingt, als hätte man die Nutzerin oder den Nutzer erfolgreich ermordet:
„Der Nutzer wurde eliminiert.“
Wäre das ein Krimi, würden die Ermittlerinnen und Ermittler sich jetzt Notizen machen.
Aber was wahrscheinlich gemeint war: AccountClosed. Oder UserDeactivated. Oder SubscriptionCancelled. Jedes davon hat eine andere Bedeutung, andere geschäftliche Implikationen, andere nachgelagerte Effekte. Aber CRUD-Sprache presst all diesen Reichtum in ein einziges, leicht morbides Verb.
Das ist nicht nur unpräzise. Es ist aktiv irreführend. CRUD-Sprache verliert nicht nur Information. Sie kann Events wie einen Polizeibericht klingen lassen.
Es fehlt die Wartungsfrage
Zurück zu unseren Druckern. Eine Wartungstechnikerin ruft beim Helpdesk an:
„Dieser Drucker im dritten Stock funktioniert nicht. Was ist passiert?“
Der Support-Mitarbeiter schaut auf den aktuellen Zustand in der Datenbank:
{ "printerId": "printer-3f-01",
"status": "offline"
}
Das ist alles, was er sieht. Der Drucker ist offline. Aber warum? Wann ging er offline? Wurde er manuell für Wartungsarbeiten offline genommen, oder ist er unerwartet ausgefallen? Ist das schon einmal passiert? Wie oft?
Mit CRUD-Events muss der Mitarbeiter nun Logs durchforsten, Zeitstempel korrelieren, vielleicht die Technikerin später zurückrufen. Jede Minute, die mit Nachforschungen verbracht wird, bedeutet verlorenes Geld und wachsende Frustration.
Das sind die versteckten Kosten semantischer Armut: Nicht nur verlorene Information, sondern verlorene Zeit, verlorener Kontext, verlorenes Vertrauen in das System.
Die semantische Alternative
Wie würden echte Events aussehen? Events, die erfassen, was tatsächlich passiert ist? In der Sprache der Domäne?
PrinterAddedPrinterBecameOnlinePrinterPausedPrinterResumedPrinterWentOfflinePrinterRemoved
Beachten Sie die subtile, aber wichtige Verschiebung. Es heißt PrinterAdded, nicht PrinterCreated. Warum? Weil der Drucker in keinem sinnvollen Weg „erstellt“ wurde. Niemand hat einen Drucker hergestellt, indem eine Datenbankzeile eingefügt wurde. Der Drucker existierte bereits. Er war ein physisches Objekt, das in einem Karton lag, aus einer Fabrik geliefert. Was passiert ist: Er wurde dem System lediglich hinzugefügt.
Created ist CRUD-Sprache. Added ist Domänensprache. Der Unterschied zählt.
Genauso Removed statt Deleted: Der Drucker wurde nicht zerstört. Er steht wahrscheinlich irgendwo in einem Lagerraum und wartet darauf, neu zugewiesen zu werden. Er wurde aus der Verwaltung dieses Systems entfernt. Das ist passiert. Das sollte das Event sagen.
Die vollständige Historie
Spielen wir nun den Support-Anruf mit echten Events durch. Der Mitarbeiter ruft die Historie des Druckers auf:
2026-01-15 09:00 PrinterAdded
2026-01-15 09:05 PrinterBecameOnline
2026-01-16 14:30 PrinterPaused { "reason": "scheduled maintenance" }
2026-01-16 16:00 PrinterResumed
2026-01-17 11:45 PrinterWentOffline { "reason": "paper jam detected" }
2026-01-17 12:00 PrinterBecameOnline
2026-01-18 09:22 PrinterWentOffline { "reason": "connection lost" }
Jetzt kann er alles sehen:
- Der Drucker ging heute um 09:22 Uhr offline, weil die Verbindung verloren ging.
- Das ist das zweite unerwartete Offline-Event in zwei Tagen.
- Gestern war es ein Papierstau, heute ist es Konnektivität.
- Davor gab es eine geplante Wartungspause, die reibungslos verlief.
Die Technikerin muss in Konsequenz also nicht blind herumprobieren. Sie weiß, dass sie die Netzwerkverbindung prüfen muss, nicht das Papierfach. Sie kann ein Muster erkennen, weil das gleiche Problem in der Vergangenheit schon mit anderen Druckern aufgetreten ist: vielleicht versagt gerade die Netzwerkkarte dieses Druckers.
Das ist der Wert, den CRUD-Events nicht liefern können. Nicht nur „was ist der Zustand“, sondern „wie ist er dorthin gekommen“ und „was sagt uns dieses Muster“.
Events als natürliche Sprache
Das berührt etwas Grundlegenderes. In einem früheren Beitrag habe ich darüber geschrieben, wie niemand Geschichten mit CRUD erzählt. Man sagt nicht „Rotkäppchen wurde erstellt, dann aktualisiert, dann wurde die Großmutter gelöscht.“ Das ist absurd. Man erzählt die Geschichte durch Events: was passiert ist, in welcher Reihenfolge und warum es wichtig war.
Und in einem anderen Beitrag über DDD habe ich argumentiert, dass Domain-Driven Design unnötig kompliziert gemacht wurde. Die Essenz ist einfach: „Sprich die Sprache der Domäne!“ Aber wir haben diese Einfachheit unter Schichten von Patterns und Jargon begraben.
Hier ist der Zusammenhang: Wer gute Events formuliert, spricht automatisch die Sprache der Domäne. Man kann nicht PrinterPaused schreiben, ohne zu verstehen, dass Pausieren ein Konzept in dieser Domäne ist, unterschieden vom Offline-Gehen, unterschieden vom Entfernen. Der Akt des Benennens von Events zwingt dazu, Gespräche mit Domänenexpertinnen und -experten zu führen. „Wie nennen Sie es, wenn ein Drucker vorübergehend, aber absichtlich aufhört zu arbeiten?“ Diese Frage führt direkt ins Herz der Domäne.
Das ist DDD, ohne es DDD zu nennen. Keine Aggregates, keine Bounded-Contexts, keine einschüchternde Terminologie. Nur Events, die erfassen, was passiert, benannt so, wie das Business sie benennt.
Der Weg zu DDD führt durch Events
Das heißt mit anderen Worten: Event Sourcing ist ein Katalysator für Domain-Driven Design.
Kundinnen und Kunden DDD zu erklären ist schwer. Die Terminologie schüchtert ein. Die Konzepte sind abstrakt. Viele Entwicklerinnen und Entwickler (mich eingeschlossen) haben sich irgendwann „zu dumm“ für DDD gefühlt, erschlagen von der Theorie.
Aber Events zu erklären ist einfach. Jede und jeder versteht Events. „Was ist passiert?“ ist eine Frage, die Menschen stellen, seit es Sprache gibt. Und wenn man Teams dazu bringt, ihre Events präzise zu benennen, machen sie am Ende ganz natürlich DDD. Sie beginnen, die Sprache der Domäne zu sprechen. Sie beginnen, Gespräche mit Domänenexpertinnen und -experten zu führen. Sie beginnen, Systeme zu bauen, die die Realität widerspiegeln, statt Datenbanktabellen.
Wer also auf die eigenen Events schaut und überall Created, Updated und Deleted sieht, hat die Chance, nicht nur das Event-Modell zu verbessern, sondern ein Gespräch darüber zu beginnen, was im eigenen Business tatsächlich passiert. Wie nennt man es, wenn ein Drucker hinzugefügt wird? Wenn eine Nutzerin oder ein Nutzer geht? Wenn eine Bestellung storniert versus erstattet versus angefochten wird?
Die Antworten auf diese Fragen verraten mehr über die Domäne als jeder Musterkatalog es je könnte.
Wie es weitergehen kann
Wenn Ihnen das bekannt vorkommt, fangen Sie hier an: Schauen Sie sich Ihre Events an! Lesen Sie sie laut vor! Klingen sie wie Datenbankoperationen, oder klingen sie wie Dinge, die in Ihrem Business passieren?
Für einen tieferen Einblick in die Konzepte hinter DDD und Event-Sourcing erklären diese Einführungen in Domain-Driven Design und Event-Sourcing die Grundlagen.
Denn Events sollten eine Geschichte erzählen, keinen Polizeibericht.
(rme)
Entwicklung & Code
Hallo Developer, hallo heise, hallo C++
Willkommen bei der C++ Werkbank, meinem neuen C++ Blog hier bei heise Developer!
Weiterlesen nach der Anzeige
Ich bin Andreas Fertig. Seit vielen Jahren beschäftige ich mich mit der Programmiersprache C++. Mein Wissen teile ich im Rahmen von Trainings, Vorträgen und auch Artikeln wie in der iX oder meinem privaten Blog. Dort veröffentliche ich pro Monat einen Artikel zu C++ auf Englisch.

Andreas Fertig ist erfahrener C++-Trainer und Berater, der weltweit Präsenz- sowie Remote-Kurse anbietet. Er engagiert sich im C++-Standardisierungskomitee und spricht regelmäßig auf internationalen Konferenzen. Mit C++ Insights ( hat er ein international anerkanntes Tool entwickelt, das C++-Programmierenden hilft, C++ noch besser zu verstehen.
Die Neuerung für (C++)2026 ist, dass ihr diese Artikel ab sofort auch hier bei heise Developer und auf Deutsch lesen könnt.
Mir ist bewusst, dass ich mit dem Blog in die Fußstapfen von Rainer Grimm trete, den ich sehr geschätzt habe und der leider viel zu früh von uns gegangen ist. Uns beiden lagen C++ und Wissen teilen sehr am Herzen. Mit meinem Blog möchte ich das Thema C++ hier bei heise Developer weiterführen.
Was erwartet dich?
Wie der Name des Blogs (der Titel „C++ Werkbank“ verzichtet bewusst auf den Bindestrich) verrät, werde ich mich mit C++-Themen beschäftigen, die dir helfen sollen, deine C++-Kenntnisse zu verbessern und mit einem neuen Werkstück aus jedem Post zu gehen.
Da ich mich viel im Umfeld eingebetteter Systeme bewege, haben meine Artikel häufig einen Fokus auf Effizienz und Performance. Auch Aspekte wie Softwaredesign werden gelegentlich ein Thema sein. Wie in meinen Trainings werde ich auch immer wieder auf Fallstricke wie undefiniertes Verhalten hinweisen. Mein Ziel ist es immer selbst robusten Code zu schreiben, der lange leben kann, und genau das vermittle ich auch in meinen Beiträgen.
Weiterlesen nach der Anzeige
Als Mitglied im C++-Standardisierungskomitee werde ich gelegentlich auch über Neuerungen für den nächsten C++-Standard berichten.
Mehr über mich
Gerne kannst du mich auch schon vor dem ersten C++-Beitrag kennenlernen. Eine Übersicht meiner Social Media findest du hier.
Du bist an einem C++-Training für deine Firma interessiert? Hier findest du meine Trainings, welche selbstverständlich auf die Anforderungen deiner Firma und deines Teams angepasst werden können.
Andreas
(rme)
Entwicklung & Code
programmier.bar: Entwicklung von Headless Apps mit Rust
In dieser Podcastfolge der programmier.bar blicken Joachim Böhmer und Dennis Becker gemeinsam mit Marcel Koch, Softwareberater, Coach und Rust-Autor, über den Tellerrand klassischer Cross-Platform-Frameworks. Im Mittelpunkt steht das Konzept sogenannter Headless Apps und die Frage, wie sich Anwendungslogik unabhängig von konkreten UI-Technologien umsetzen lässt.
Weiterlesen nach der Anzeige
Headless Apps mit Rust
Die drei diskutieren, wie sich die Business-Logik einer Anwendung vollständig in Rust kapseln lässt, um sie plattformübergreifend einzusetzen – unabhängig davon, ob die Benutzeroberfläche mit Flutter, SwiftUI oder Jetpack Compose umgesetzt wird. Auch der Einsatz im Web über WebAssembly (Wasm) sowie auf Mikrocontrollern ist Teil der Betrachtung. Es geht um die Trennung von Core-Logik und UI für die Reduktion technologischer Abhängigkeiten.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmung wird hier ein externer Inhalt geladen.
In dieser Folge gibt es außerdem einen Architektur-Deep-Dive zu Headless Apps sowie zur Rolle von Rust in diesem Kontext, insbesondere mit Blick auf Performance, Memory Safety und Portabilität. Zudem stellt Marcel Koch das Crux-Framework von Red Badger vor, das den Datenaustausch zwischen dem Rust-Core und den jeweiligen UI-Shells automatisiert. Abschließend diskutieren die drei, in welchen Fällen sich der Mehraufwand einer Headless-Architektur lohnt und wann klassische Lösungen wie Flutter oder Kotlin Multiplatform die sinnvollere Wahl sind.
Die aktuelle Ausgabe des Podcasts steht auch im Blog der programmier.bar bereit: „Headless Apps mit Marcel Koch“. Fragen und Anregungen gerne per Mail oder via Mastodon, Bluesky, LinkedIn oder Instagram.
Weiterlesen nach der Anzeige
(mdo)
-
Entwicklung & Codevor 2 MonatenKommandozeile adé: Praktische, grafische Git-Verwaltung für den Mac
-
UX/UI & Webdesignvor 3 MonatenArndt Benedikt rebranded GreatVita › PAGE online
-
Künstliche Intelligenzvor 3 WochenSchnelles Boot statt Bus und Bahn: Was sich von London und New York lernen lässt
-
Entwicklung & Codevor 1 MonatKommentar: Anthropic verschenkt MCP – mit fragwürdigen Hintertüren
-
Künstliche Intelligenzvor 3 MonatenGoogle „Broadwing“: 400-MW-Gaskraftwerk speichert CO₂ tief unter der Erde
-
Apps & Mobile Entwicklungvor 2 MonatenHuawei Mate 80 Pro Max: Tandem-OLED mit 8.000 cd/m² für das Flaggschiff-Smartphone
-
Social Mediavor 1 MonatDie meistgehörten Gastfolgen 2025 im Feed & Fudder Podcast – Social Media, Recruiting und Karriere-Insights
-
Apps & Mobile Entwicklungvor 2 MonatenFast 5 GB pro mm²: Sandisk und Kioxia kommen mit höchster Bitdichte zum ISSCC
