Entwicklung & Code
Datenparallele Typen in C++26: Bedingte Ausführung von Operationen
Leider habe ich in meinem letzten Beitrag „Datenparallele Typen in C++26: ein Beispiel aus der Praxis“ vergessen, eine Funktion der neuen Bibliothek vorzustellen. Das hole ich in diesem Artikel nach.
Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tätig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und häufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschäftigt er sich intensiv mit seiner Leidenschaft C++.
Where-Ausdruck
Das neue Schlüsselwort where
erzeugt einen sogenannten Where-Ausdruck. Damit lassen sich die Elemente eines SIMD-Vektors bedingt ansprechen.
Folgendes Beispiel bringt dieses Verhalten auf den Punkt:
// where.cpp
#include
#include
#include
namespace stdx = std::experimental;
void println(std::string_view name, auto const& a)
{
std::cout << name << ": ";
for (std::size_t i{}; i != std::size(a); ++i)
std::cout << a[i] << ' ';
std::cout << '\n';
}
template
stdx::simd my_abs(stdx::simd x)
{
where(x < 0, x) = -x; // Set elements where x is negative to their absolute value
return x;
}
int main()
{
const stdx::native_simd a = 1;
println("a", a);
const stdx::native_simd b([](int i) { return i - 2; });
println("b", b);
const auto c = a + b;
println("c", c);
const auto d = my_abs(c);
println("d", d);
}
In der Funktion my_abs
kommt die where
-Funktion zum Einsatz: where(x < 0, x) = -x;
bewirkt, dass alle Elemente des SIMD-Vektors, die kleiner als Null sind, auf ihren absoluten Wert gesetzt werden.
Der Screenshot zeigt die Ausgabe des Beispielcodes.
In diesem Fall kommen SSE2-Befehle zum Einsatz. Der SIMD-Vektor ist 128 Bit groß.
Die where
-Expression kann mit einem bool
-Ausdruck oder einer simd_mask
parametrisiert werden.
Obiges Codebeispiel lässt sich auch mit einer simd_mask
implementieren. Folgender Code zeigt die Umsetzung:
// whereMask.cpp
#include
#include
#include
namespace stdx = std::experimental;
void println(std::string_view name, auto const& a)
{
std::cout << std::boolalpha << name << ": ";
for (std::size_t i{}; i != std::size(a); ++i)
std::cout << a[i] << ' ';
std::cout << '\n';
}
int main()
{
const stdx::native_simd a = 1;
println("a", a);
const stdx::native_simd b([](int i) { return i - 2; });
println("b", b);
const auto c = a + b;
println("c", c);
const stdx::native_simd_mask x = c < 0;
println("x", x);
auto d = c;
where(x, d) *= -1;
println("d", d);
}
Beginnen möchte ich meine Erläuterung mit den letzten fünf Zeilen der Main-Funktion. Zuerst erzeuge ich die simd_mask
x, indem das Prädikat c < 0
auf jedes Element des SIMD-Vektors c angewendet wird.
Die Maske x hat die gleiche Länge wie der SIMD- Vektor, besitzt aber nur Wahrheitswerte. Damit diese Wahrheitswerte als true
oder false
und nicht als 1 oder 0 dargestellt werden, habe ich der Funktion println
den Streammanipulator std::boolalpha
hinzugefügt.
Zusätzlich muss ich den SIMD-Vektor d mit c initialisieren, da c konstant ist. Nun lässt sich die Expression where(x, d) *= -1;
auf d anwenden. Dabei wird jedes Element des SIMD-Vektors negiert, wenn die Maske den Wert true
besitzt.
Der Screenshot zeigt die Ausgabe des Codes mit simd_mask.
Der Datentyp simd_mask
ist dem Datentyp simd
sehr ähnlich. Der wesentliche Unterschied besteht darin, dass simd
alle Standard-Ganzzahltypen, Zeichentypen und die Typen float und double annehmen kann. Im Gegensatz dazu unterstützt simd_mask
nur Wahrheitswerte.
Die Definition von simd_mask
sieht folgendermaßen aus:
template
class basic_simd_mask
Der Abi-Tag bestimmt die Anzahl der Elemente und deren Speicherplatz. Zur Vollständigkeit sind hier noch einmal die ABI-Tags:
scalar
: Speichern eines einzelnen Elementsfixed_size
: Speichern einer bestimmten Anzahl von Elementencompatible
: gewährleistet ABI-Kompatibilitätnative
: am effizientestenmax_fixed_size
: maximale Anzahl von Elementen, die von fixed_size garantiert unterstützt werden
Entsprechend zu simd
besitzt simd_mask
auch zwei Aliase:
template< size_t Bytes, int N >
using fixed_size_simd_mask = simd_mask>
template< size_t Bytes >
using native_simd_mask = simd_mask>
Wie geht‘s weiter?
In meinem vorerst letzten Artikel über data-parallel types möchte ich auf die besonderen Funktionen dafür eingehen.
(rme)
Entwicklung & Code
Flexibel und pflegeleicht: Testing ohne Mocks
Robuste, automatisierte Tests sind feste Bestandteile der agilen Softwareentwicklung. Da Anforderungen und Rahmenbedingungen sich stetig ändern, müssen Entwicklerinnen und Entwickler kontinuierlich in der Lage sein, ihre Architektur anzupassen. Ihr Code muss wachsen und sich weiterentwickeln können. Sie müssen laufend bestehende Features erweitern, anpassen, umsortieren, zusammenführen oder aufteilen. Dazu benötigen sie die Unterstützung einer schnellen, verlässlichen und robusten Testsuite, die bestehende Funktionen der Software nicht beeinträchtigt.
Martin Grandrath ist Software-Developer und entwickelt seit über 15 Jahren Applikationen mit Web-Technologien. Seine Schwerpunkte sind neben Frontend-Architektur vor allem Software-Craftsmanship und testgetriebene Entwicklung. Seit 2023 arbeitet er als Senior IT-Consultant bei codecentric.
Auf Mocks basierende Tests verursachen häufig zusätzlichen Pflegeaufwand beim Refaktorieren, also Änderungen an der Codestruktur, die die Arbeit mit dem Code insgesamt vereinfachen, das Verhalten des Systems aber nicht verändern. Die Art und Weise, wie Mocks in der Praxis meist zum Einsatz kommen, führt zu einer Kopplung von Tests und Implementierungsdetails. Änderungen an diesen Details erfordern Anpassungen der Tests, was zulasten der Entwicklungsgeschwindigkeit geht.
Dieser Artikel zeigt auf, welche Kompromisse mit auf Mocks basierenden Tests verbunden sind und stellt mit dem Nullable-Entwurfsmuster von James Shore eine Alternative vor.
Isolierte, interaktionsbasierte Tests
Mock-Objekte oder kurz Mocks (englisch für „Attrappe“) sind eine Unterkategorie der Test-Doubles, die in Unit Tests als Platzhalter für Produktionsobjekte dienen. Der Begriff Test-Double ist angelehnt an das Stunt-Double in Filmen. Weitere Arten von Test-Doubles sind Stubs, Spies oder Fakes.
Mocks zeichnen während eines Testlaufs auf, wie die Software mit ihnen interagiert: Welche ihrer Methoden ruft die Anwendung in welcher Reihenfolge und mit welchen Argumenten auf? Anschließend verifiziert der Unit-Test, ob die beobachteten Interaktionen mit den erwarteten übereinstimmen. Auf diese Weise werden die Interaktionen zwischen den Objekten zu einem integralen Bestandteil der Implementierung und der Tests. Diese Art von Tests wird als Interaction-based bezeichnet.
Gleichzeitig isolieren Mocks das zu testende Objekt von seinen Abhängigkeiten. Während des Tests wird also nur der Code eines einzelnen Objekts ausgeführt, während alle Interaktionspartner durch Mocks ersetzt werden. Tests, die Objekte in Isolation testen, nennt man solitary.
Auch wenn Solitary Interaction-based Tests ihre Vorzüge haben und sich im Laufe der Zeit zum Standard entwickelt haben, sind sie nicht frei von Nachteilen. Dass Tests an die Interaktionen zwischen Objekten gekoppelt sind, erschwert Refaktorierungen. Diese sind jedoch ein unverzichtbares Werkzeug, um die Qualität der Codebasis dauerhaft aufrechtzuerhalten.
Refaktorierungen, die die Interaktionen zwischen Objekten verändern, können zu False Positives führen: Tests schlagen fehl, obwohl das Programm als Ganzes keine Fehler enthält. Lediglich die Objektinteraktionen weichen von den Erwartungen der Tests ab. Eine Suite aus Interaction-based Tests macht die Codebasis dadurch insgesamt weniger flexibel, da die Tests die Implementierungsdetails fixieren.
Zudem kann es vorkommen, dass Solitary Tests Fehler nicht erkennen, wenn zwar alle Objekte in Isolation erwartungsgemäß arbeiten, es aber im Zusammenspiel der Objekte zu unerwünschtem Verhalten kommt. Um dem vorzubeugen, sind neben den Unit Tests zusätzliche Integrationstests erforderlich, die gezielt das Zusammenspiel mehrerer Objekte testen.
Eine Alternative stellen Sociable, State-based Tests dar.
Echte Abhängigkeiten und sichtbares Verhalten
In Sociable Tests interagiert das zu testende Objekt nicht mit Test-Doubles, sondern mit den echten Abhängigkeiten, die auch im Produktivbetrieb existieren. Fehler, die durch die Interaktion zwischen den Objekten entstehen, fallen im Test sofort auf. Separate Integrationstests sind nicht erforderlich.
State-based Tests verifizieren das sichtbare Verhalten von Objekten und ignorieren die darunter liegenden Interaktionen. Diese Tests reagieren daher sehr viel robuster gegenüber Refactorings, da sie sich nur für das Endergebnis interessieren und nicht für die Implementierungsdetails.
Der Elefant im Raum
Die echten Produktionsobjekte in den Tests zu verwenden, statt sie durch Mocks zu ersetzen, führt zunächst zu einem Problem: Der zu testende Code muss mit APIs, Datenbanken oder dem Dateisystem kommunizieren. Diese Nebenwirkungen (Side Effects) würden zu nicht deterministischen Tests führen, da sie vom globalen Zustand abhängig sind, unter anderem von Drittsystemen. So könnte etwa ein Test fehlschlagen, weil eine Fremd-API mit anderen Daten antwortet, als es der Test erwartet.
Ein weiteres Problem sind die Auswirkungen, die API-Aufrufe haben können. Dass jede Ausführung der Warenkorbtests eine Kreditkarte belastet, ist nicht wünschenswert. Darüber hinaus muss es möglich sein, zu testen, wie sich ein Programm verhält, wenn eine Dritt-API mit unterschiedlichen Formaten, mit Fehlern oder gar nicht antwortet. Und schließlich verlangsamt die API-Anbindung die Tests.
Integrationstests sind zwar für den Übergang des zu implementierenden Systems mit der Außenwelt notwendig, aber die Nebenwirkungen sind für die Tests innerhalb des Systems unerwünscht.
Entwicklung & Code
Mein Scrum ist kaputt #140: Shape Up statt Scrum – zur Produktentwicklung
ShapeUp ist ein willkommener Gegenentwurf zum klassischen Scrum und bringt frischen Wind in die agilen Diskussionen. Es ist ein Ansatz zur Produktentwicklung, den Basecamp, heute 37 Signals, entwickelt und den Ryan Singer im gleichnamigen Buch beschrieben hat.
Es versteht sich nicht als Framework wie Scrum, sondern als Set an Prinzipien und Praktiken, um fokussierter, selbstorganisierter und mit weniger Overhead zu arbeiten. Über dieses Thema sprechen Ina Einemann und Sebastian Bauer mit Klaus Breyer.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmung wird hier ein externer Inhalt geladen.
Weitere Hinweise
(Bild: Katsiaryna/stock.adobe.com)
Das Programm der zweitägigen Agile Leadership Conference 2025 steht fest: Der Leadership Day (27.11.25) behandelt das Führen von Teams und Organisationen, während sich der Self Leadership Day (3.12.25) mit Selbstführung und dem aktiven Selbst als Führungskraft beschäftigt.
(mdo)
Entwicklung & Code
software-architektur.tv: Webperformance mit Lucas Dohmen und Lisa Maria Schäfer
In dieser Folge des Videocasts software-architektur.tv sprechen Lucas Dohmen und Lisa Maria Schäfer über Webperformance. Sie klären, was sich dahinter verbirgt und warum das Thema wichtig ist – und zwar für alle, die Webseiten entwickeln. Des Weiteren stellen sie Tools zum Messen der Webperformance vor und geben Impulse, wie man seine Website schneller machen kann.
Lisa Maria Schäfer malt dieses Mal keine Sketchnotes, da sie vor der Kamera ist.
Livestream am Freitag, 5. September
Die Ausstrahlung findet am Freitag, 5. September 2025, live von 13 bis 14 Uhr statt. Die Folge steht im Anschluss als Aufzeichnung bereit. Während des Livestreams können Interessierte Fragen via Twitch-Chat, YouTube-Chat, Bluesky, Mastodon, Slack-Workspace oder anonym über das Formular auf der Videocast-Seite einbringen.
software-architektur.tv ist ein Videocast von Eberhard Wolff, Blogger sowie Podcaster auf iX und bekannter Softwarearchitekt, der als Head of Architecture bei SWAGLab arbeitet. Seit Juni 2020 sind über 250 Folgen entstanden, die unterschiedliche Bereiche der Softwarearchitektur beleuchten – mal mit Gästen, mal Wolff solo. Seit mittlerweile mehr als zwei Jahren bindet iX (heise Developer) die über YouTube gestreamten Episoden im Online-Channel ein, sodass Zuschauer dem Videocast aus den Heise Medien heraus folgen können.
Weitere Informationen zur Folge finden sich auf der Videocast-Seite.
(mdo)
-
Datenschutz & Sicherheitvor 3 Monaten
Geschichten aus dem DSC-Beirat: Einreisebeschränkungen und Zugriffsschranken
-
UX/UI & Webdesignvor 3 Wochen
Der ultimative Guide für eine unvergessliche Customer Experience
-
Apps & Mobile Entwicklungvor 3 Monaten
Metal Gear Solid Δ: Snake Eater: Ein Multiplayer-Modus für Fans von Versteckenspielen
-
Online Marketing & SEOvor 3 Monaten
TikTok trackt CO₂ von Ads – und Mitarbeitende intern mit Ratings
-
Social Mediavor 3 Wochen
Relatable, relevant, viral? Wer heute auf Social Media zum Vorbild wird – und warum das für Marken (k)eine gute Nachricht ist
-
UX/UI & Webdesignvor 1 Woche
Adobe Firefly Boards › PAGE online
-
Entwicklung & Codevor 2 Wochen
Posit stellt Positron vor: Neue IDE für Data Science mit Python und R
-
Entwicklung & Codevor 3 Tagen
EventSourcingDB 1.1 bietet flexiblere Konsistenzsteuerung und signierte Events