Connect with us

Entwicklung & Code

Software Testing: Fußballanalyse trifft Softwaretest


Für diese Episode seines Podcasts Software Testing hat sich Richard Seidl gleich zwei Gäste eingeladen: Sven Braxein und Athanasios Kallinikidis. Gemeinsam sprechen sie über Process Mining im Test, Regressionstests und die Frage, wie echte Nutzungsdaten Prioritäten setzen. Auslöser ist ein Großprojekt mit Systemablösung und dem Vorwurf zu geringer Abdeckung.

Weiterlesen nach der Anzeige

Athanasios Kallinikidis ist 28 Jahre alt und im Kreis Esslingen bei Stuttgart geboren und aufgewachsen. An der Technischen Universität München absolvierte er den Bachelor und Master in Management & Technology mit Schwerpunkt Informatik. Ein Praktikum bei Celonis entfachte seine Leidenschaft für Process Mining und legte den Grundstein für seinen Karrierefokus. Heute treibt er bei Mercedes‑Benz Leasing Deutschland als Product Owner im Platform Team Business‑IT die Weiterentwicklung der Process‑Mining‑Plattform voran. Athanasios ist leidenschaftlicher Fußballfan und hat das Coaching als zweite Berufung entdeckt. Als Werkstudent arbeitete er in der Spielanalyse des FC Bayern München II in der 3. Liga. Die dort erlernten Analysekompetenzen überträgt er aktuell auf die Arbeit mit seiner Kreisliga‑Herrenmannschaft.

Sven Braxein ist Gründer und Geschäftsführer der 2008 gegründeten TestGilde GmbH. Er arbeitet seit 30 Jahren in der Beratung von IT-Projekten mit Fokus auf Software-Qualitätssicherung und -Test. Sein Schwerpunkt liegt im Testmanagement für Großprojekte sowie in der Konzeption und Umsetzung unternehmensweiter Testmanagementstrukturen. Wenn es das Thema Qualität und Test noch nicht gäbe, für ihn müsste es erfunden werden.

Bei diesem Podcast dreht sich alles um Softwarequalität: Ob Testautomatisierung, Qualität in agilen Projekten, Testdaten oder Testteams – Richard Seidl und seine Gäste schauen sich Dinge an, die mehr Qualität in die Softwareentwicklung bringen.

Die aktuelle Ausgabe ist auch auf Richard Seidls Blog verfügbar: „Fußballanalyse trifft Softwaretest – Sven Braxein und Athanasios Kallinikidis“ und steht auf YouTube bereit.

Weiterlesen nach der Anzeige


(mdo)



Source link

Entwicklung & Code

Programmiersprache C++: Was reinterpret_cast nicht tut


Im heutigen Beitrag werde ich eine der größten Fallstricke von C++ erläutern: reinterpret_cast. Ein anderer Titel für diesen Beitrag könnte lauten: „Das ist nicht der Cast, den du suchst!“

Weiterlesen nach der Anzeige


Portrait von Andreas Fertig

Portrait von Andreas Fertig

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.

Meine Motivation für diesen Blogbeitrag stammt aus mehreren Schulungen und einigen Vorträgen, die ich gehalten habe. Seit C++23 gibt es in der Standardbibliothek eine neue Funktion: std::start_lifetime_as. Wenn ich Kurse mit Schwerpunkt auf eingebetteten Umgebungen unterrichte oder Vorträge mit diesem Schwerpunkt halte, habe ich begonnen, std::start_lifetime_as in das Material aufzunehmen. Mit einem interessanten Ergebnis.

Das Feedback, das ich bekomme, lautet in etwa:

  • Warum benötige ich std::start_lifetime_as, ich habe doch schon reinterpret_cast?
  • Warum kann ich reinterpret_cast nicht verwenden?

Wer noch nie von start_lifetime_as gehört hat, findet weitere Informationen in meinem englischen Artikel „The correct way to do type punning in C++ – The second act“. Ich verwende folgendes Beispiel daraus:


struct ConfigValues {
  uint32_t                  chksum;
  std::array values;
};

bool ProcessData(std::span bytes)
{
  if(bytes.size() < sizeof(ConfigValues)) { return false; }

  // #A
  ConfigValues* cfgValues = reinterpret_cast(bytes.data());

  return HandleConfigValues(cfgValues);
}


Die Idee hier ist, eine Reihe von rohen Bytes in eine bekannte Struktur umzuwandeln – hier mit dem Namen ConfigValues. Zusammen mit start_lifetime_as gerate ich immer öfter in Gespräche, in denen mir Leute sagen, dass der Name reinterpret impliziert, dass solcher Code wie erwartet funktionieren sollte. Die Erwartung ist, dass solcher Code frei von undefiniertem Verhalten ist und tatsächlich einen Zeiger auf ein ConfigValues-Objekt zurückgibt.

Weiterlesen nach der Anzeige

Zwar kann ich einer solchen Erwartung aufgrund des Wortlauts des Standards und des C++-Objektmodells nicht widersprechen, doch eine solche Erwartung führt zu undefiniertem Verhalten. In einer typsicheren Sprache kann ein Objekt nicht in ein anderes, nicht verwandtes Objekt konvertiert werden.

Der wichtigste Wortlaut ist [expr.reinterpret.cast § 7], der besagt:

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast(static_cast(v)). [Note 5: Converting a pointer of type “pointer to T1” that points to an object of type T1 to the type “pointer to T2” (where T2 is an object type and the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. — end note]

Zunächst einmal handelt dieser ganze Absatz von Zeigern auf Objekte und nicht von Objekten selbst. Es heißt, dass du ein ConfigValues in einen void* oder einen beliebigen anderen Datentyp konvertieren kannst, der ein Objekttyp ist. Ein Objekttyp ist alles außer einem Funktionstyp, einem Referenztyp und void.

Weiter unten in der Anmerkung bestätigt der Standard ausdrücklich, dass du einen Rundlauf durchführen kannst. Zum Beispiel:


ConfigValues  cfg{};
ConfigValues* val{&cfg};
void*         typeErased         = reinterpret_cast(val);
ConfigValues* roundTripBackToVal = reinterpret_cast(typeErased);


Dies ermöglicht Konstrukte, die sogenannte Typlöschung (Type Erasure) nutzen, wie std::any. Du kannst einen Alias eines anderen Zeigertyps erhalten.

In diesem Absatz ist von einer Konvertierung des Objekts selbst keine Rede. Nur den Zeiger kann man konvertieren.

Im Sinne des C++-Objektmodells muss eine Anwendung ein gültiges Objekt erstellen (und später zerstören). Aber alles, was jemals erstellt wurde, ist ein ConfigValues-Objekt. reinterpret_cast ist ein Werkzeug, das es ermöglicht, einen Zeiger eines anderen Typs zu speichern. Sobald du ihn verwenden möchtest, musst du den Zeiger wieder in seinen ursprünglichen Typ zurückkonvertieren.

Nehmen wir einmal an, reinterpret_cast würde so funktionieren, wie manche Leute es erwarten:


struct Apple {
  int x;
};

struct Orange {
  int y;
};

Apple*  grannySmith{new Apple{4}};
Orange* bali{reinterpret_cast(grannySmith)};  // #A

int y = bali->y;
int x = grannySmith->x;


Nach den Regeln von C++ muss ein Objekt erstellt und zerstört werden. Wenn #A ein Objekt erstellen würde, müsste es das grannySmith-Objekt zerstören. Was überraschend wäre. Dann hättest du keine Möglichkeit, eine Typlöschung wie std::any zu implementieren, da das Speichern eines gelöschten Typs void* das ursprüngliche Objekt aus Sicht der abstrakten Maschinerie von C++ zerstören würde. Das würde dem Compiler ermöglichen, verschiedene andere Optimierungen vorzunehmen, die das Programm zum Absturz bringen würden.

Mit reinterpret_cast hast du eine Möglichkeit, ein Objekt A als einen anderen Typ B zu aliasieren, jedoch ohne das Recht, jemals über diesen Zeiger auf ein B-Objekt zuzugreifen. Andererseits erstellt start_lifetime_as implizit ein B-Objekt am Zielort des Zeigers A, während gleichzeitig die Lebensdauer von A beendet wird.

Meist will man in diesen Situationen ein Objekt eines anderen Typs zum Leben erwecken. Und genau dafür ist std::start_lifetime_as gedacht.

Wenn du std::start_lifetime_as auf einen Zeiger anwendest, versteht die abstrakte Maschine, dass du ein neues Objekt dieses Typs erstellst. Im Gegensatz zu einem Aufruf von new oder einem Stack-Objekt wird kein Konstruktor ausgeführt. Alles geschieht nur innerhalb des C++-Objektmodells.

Es gibt noch eine weitere Funktion von std::start_lifetime_as: Wenn es die Lebensdauer eines neuen Objekts startet, wird die Lebensdauer der Quelle automatisch beendet, wiederum ohne einen tatsächlichen Destruktor aufzurufen. Das ist hier entscheidend.

Wenn ich std::start_lifetime_as auf mein vorheriges Beispiel anwende, sieht die korrekte Implementierung wie folgt aus:


struct Apple {
  int x;
};

struct Orange {
  int y;
};

Apple*  grannySmith{new Apple{4}};
Orange* bali{std::start_lifetime_as(grannySmith)};  // #A

int y = bali->y;

grannySmith = std::start_lifetime_as(bali);  // #B
int x       = grannySmith->x;


Der Code in #B startet die Lebensdauer des Zeigers erneut als Apple-Objekt.

Mit reinterpret_cast erhältst du nur eine Zeigerkonvertierung. Du darfst diesen neuen Zeiger nicht verwenden, um auf ein Objekt des Typs zuzugreifen.

Wenn du die Lebensdauer eines Objekts starten möchtest, um auf Daten als neuen Typ zuzugreifen, benötigst du std::start_lifetime_as.


(rme)



Source link

Weiterlesen

Entwicklung & Code

Self-Hosted Backend: Appwrite 1.9 bringt MongoDB


Appwrite 1.9.0 ist da und unterstützt nun MongoDB, feinere Sicherheitsmechanismen und gezieltere Realtime-Funktionen. Hinzu kommen ein ausgebauter Compute-Bereich und zahlreiche Performance-Verbesserungen.

Weiterlesen nach der Anzeige

Bei Appwrite handelt es sich um eine quelloffene Backend-as-a-Service-Plattform (BaaS), die Authentifizierung, Datenbank, Storage, Serverless Functions und Realtime-Kommunikation in einem Paket für den Eigenbetrieb bündelt. Damit richtet sie sich an Teams, die mehr Kontrolle über ihre Backend-Infrastruktur behalten wollen, als es klassische Cloud-BaaS-Dienste erlauben.

Die zentrale Neuerung: Appwrite unterstützt jetzt MongoDB als Datenbank-Backend. Damit steht neben dem bisherigen TablesDB-Modell erstmals eine dokumentenorientierte Alternative bereit. Entwickler können so dynamische Datenstrukturen abbilden – etwa Event- oder Log-Daten mit variierenden Feldern –, ohne vorher ein Schema anzupassen.

Ferner ergänzt Version 1.9.0 neue String-Typen wie mediumtext und longtext, unterstützt 64-Bit-Integer und zeigt den Speicherverbrauch einzelner Collections an. Dokumentlisten lassen sich zudem mit konfigurierbarer TTL cachen, was bei häufig abgefragten Datenbeständen die Datenbanklast senkt.

Administratoren erhalten mehrere neue Schnittstellen: Eine Webhooks-API verwaltet Ereignisbenachrichtigungen zentral. Eine Schedules-API gibt Einblick in geplante Aufgaben und stellt Steuerungsfunktionen bereit. Neu ist auch eine Nutzer-Impersonation (User Impersonation). Damit kann sich ein Admin als ein bestimmter Nutzer anmelden, um Fehler direkt aus dessen Perspektive nachzuvollziehen. Projektvariablen lassen sich jetzt gezielt als öffentlich markieren, etwa um Konfigurationswerte ans Frontend durchzureichen.

Die Realtime-Schnittstelle arbeitet nun gezielter. Clients definieren Subscriptions mit Query-Filtern und empfangen nur noch passende Ereignisse statt sämtlicher Änderungen in einer Collection. Ein Client könnte so ausschließlich Updates für eine bestimmte Nutzer-ID abonnieren. Appwrite liefert außerdem Metriken zu Verbindungen, Nachrichtenaufkommen und Bandbreite.

Weiterlesen nach der Anzeige

API-Keys lassen sich ab Version 1.9.0 ressourcenbezogen einschränken. Ein Key kann etwa Lesezugriff auf den Storage erhalten, ohne gleichzeitig die Benutzerverwaltung freizuschalten. JWT-Laufzeiten sind individuell konfigurierbar. Verbesserungen bei CORS, OAuth und Multi-Domain-Support erleichtern Setups mit mehreren Frontends.

Im Serverless-Bereich trennt Appwrite jetzt Build- und Runtime-Ressourcen. Wer rechenintensive Builds mit einer schlanken Runtime kombinieren muss, kann beides unabhängig dimensionieren. Eigene Startkommandos, automatisches Aufräumen alter Deployments und verwaister Ausführungen sowie saubere Worker-Shutdowns sollen den Betrieb stabiler machen.

Dateien lassen sich jetzt einzeln mit Verschlüsselungs- und Komprimierungsparametern versehen. Listenabfragen geben den gesamten Speicherverbrauch zurück. Neue Migrationstools übertragen Sites und Messaging-Ressourcen zwischen Appwrite-Instanzen. Hinzu kommen ein offizielles Rust-SDK, ein Plugin für die KI-gestützte IDE Cursor sowie ein Agent Skills SDK, das die Integration von KI-Agenten erleichtern soll.

Unter der Haube haben die Entwickler die Architektur auf die modulare Utopia-Plattform umgestellt. Der bisherige Proxy-Container entfällt, Traefik wird direkt angesprochen. Sparse Updates senden nur noch geänderte Attribute, Shared-Memory-Caching via Swoole Tables ersetzt den bisherigen Pro-Worker-Cache und vorverarbeitete Queries beschleunigen häufig genutzte Pfade. Swoole ist eine PHP-Erweiterung für asynchrone Programmierung, die hier für effizientes Shared-Memory-Caching genutzt wird. Diverse Memory Leaks in der Webhook-, Statistik- und Event-Verarbeitung haben die Entwickler behoben.

Appwrite 1.9.0 setzt ein Upgrade von Version 1.8.1 voraus und erfordert eine Datenbankmigration. Diese lässt sich über den neuen Web-Installer, das CLI-Flag --migrate oder manuell per docker compose exec appwrite migrate anstoßen.

Alle Informationen zu Appwrite 1.9.0 finden sich in den Release Notes auf GitHub.


(fo)



Source link

Weiterlesen

Entwicklung & Code

Software Testing: Als Software-Tester von der Stiftung Warentest lernen


In dieser Episode spricht Richard Seidl mit Johannes Stiller von Stiftung Warentest über die Testmethoden und Entscheidungsprozesse bei Produktprüfungen. Es geht darum, wie die Stiftung ihre Prüfprogramme entwickelt, welche Kriterien für verschiedene Produkte gelten und wie Teams aus Wissenschaftlern und Marktanalysten zusammenarbeiten. Besonders spannend: die Parallelen zum Softwaretesting, etwa Objektivität, Transparenz und die Perspektive des Nutzers. Wie funktioniert die Auswahl der getesteten Produkte und wie werden subjektive Eindrücke bei Zahnbürsten oder Laptops möglichst vergleichbar gemacht?

Weiterlesen nach der Anzeige

Johannes Stiller schloss 2016 seine Promotion im Bereich der nuklearen Kern- und Teilchenphysik in Heidelberg ab. Während dieser Zeit arbeitete er intensiv vor Ort am CERN am ALICE-Experiment. Aufgrund seiner Expertise in Tracking-Algorithmen wechselte er anschließend in die Softwareentwicklung der Automobilindustrie. Ein wesentlicher Meilenstein war seine maßgebliche Beteiligung an den Sicherheitsbremssystemen für das autonome Parkshuttle-System Parkshuttle Rivium. Nach seinem Umzug nach Berlin widmete er sich im VW-Konzern der Serienentwicklung von Fahrassistenzsystemen wie dem Emergency Assist und dem Travel Assist, inklusive der ASPICE-konformen Entwicklung, Prüfung und Freigabe. Seit August 2025 bekleidet Johannes Stiller eine leitende Funktion bei der Stiftung Warentest, wobei ihn besonders die Möglichkeit motiviert, vielseitige Themen auf wissenschaftlich fundierter Basis zu bearbeiten.

Bei diesem Format dreht sich alles um Softwarequalität: Ob Testautomatisierung, Qualität in agilen Projekten, Testdaten oder Testteams – Richard Seidl und seine Gäste schauen sich Dinge an, die mehr Qualität in die Softwareentwicklung bringen.

Die aktuelle Ausgabe ist auch auf Richard Seidls Blog verfügbar: „So testet Stiftung Warentest – Johannes Stiller“.


(mai)



Source link

Weiterlesen

Beliebt