Arbeitsplatz Bild CADS GmbH

Data Oriented Design

Description

Florian Putz von CADS zeigt in seinem devjobs.at TechTalk, wie trotz großer Datenmengen mithilfe von Data Oriented Design doch schnelle Performance von Software erreicht werden kann.

Beim Videoaufruf stimmst Du der Datenübermittlung an YouTube und der Datenschutzerklärung zu.

Video Zusammenfassung

In "Data Oriented Design" zeigt Florian Putz (CADS GmbH), warum in 3D-Visualisierung, Simulation und anderen datenintensiven Anwendungen nicht nur Algorithmen, sondern vor allem das Data Layout die Performance treibt: Cache-Locality, kontinuierlicher Speicher und Struct-of-Arrays statt Array-of-Structs vermeiden Pointer-Chasing und ermöglichen SIMD-optimiertes Batching. Er kontrastiert OOP mit tiefen Abhängigkeiten und Shared Mutable State gegen einen Systems-Ansatz, der Daten zur Laufzeit queriert, nur zeitliche Abhängigkeiten modelliert, Daten partitioniert und so neben höherem Durchsatz auch lock-freies Multithreading über viele Kerne ermöglicht. Teilnehmende lernen, wann sich der anfängliche Mehraufwand lohnt (große Datenmengen, viele Kerne) und wie sie durch zugriffsorientiertes Datenlayout und entkoppelte Systeme schnellere, robustere und leichter änderbare Software bauen.

Data Oriented Design in der Praxis: Wie Speicherlayout und zeitliche Abhängigkeiten Performance und Architektur prägen – Recap von „Data Oriented Design“ mit Florian Putz (CADS GmbH)

Einordnung: Warum dieses Thema jetzt zählt

In seinem Talk „Data Oriented Design“ führte Florian Putz (Tech Lead und Team Lead bei CADS GmbH, Teil der KLS Martin Group) durch ein Thema, das im Engineering-Alltag oft verborgen bleibt, aber in Performance-kritischen Domänen den Unterschied macht: die Anordnung unserer Daten im Speicher. In der Medizintechnik – mit 3D‑Visualisierung, Simulationen und großen Datenmengen – ist ein responsives System keine Kür, sondern Pflicht. Genau hier setzt Data Oriented Design (DOD) an.

Wir von DevJobs.at haben zugehört und mitgeschrieben: Warum ist das Layout der Daten so bestimmend für die Geschwindigkeit? Weshalb sind viele Performance-Probleme in Wahrheit Speicherprobleme? Und wie führt der DOD‑Ansatz über reine Optimierung hinaus zu einer anderen, oft robusteren Softwarearchitektur – bis hin zu nebenläufigen Systemen ohne Locks?

Der Kernpunkt: Performance ist (meist) ein Speicherproblem

„CPUs sind unglaublich schnell, wenn es darum geht, irgendwas auszurechnen, aber sie sind unglaublich langsam, wenn es darum geht, Daten zu lesen aus dem RAM“, betont Florian Putz. Das ist keine Floskel, sondern eine praktische Beobachtung: Nicht die Rechenlogik, sondern der Weg zur und von der Datenquelle verlangsamt viele Hot Loops. Zwischen Cache-Ebenen und RAM potenzieren sich die Latenzen; je weiter die CPU „greifen“ muss, desto teurer wird jeder Zugriff.

  • L1, L2, L3, RAM: Jede Stufe entfernt sich weiter von der CPU. Die Kosten pro Zugriff steigen merklich.
  • Caches sind klein und wirksam – wenn relevante Daten lokal zusammenliegen. Sind sie verstreut, steigen Cache-Misses und der Prozessor verbringt Zeit mit Warten.
  • Ergebnis: Die „richtige“ Organisation der Daten im Speicher ist oft entscheidender als eine weitere Verfeinerung der Algorithmik.

Dieser Befund rahmt den gesamten Talk: Wer Performance will, muss über Datenzugriff und -anordnung reden, nicht nur über O(n) und Big‑O.

Objektorientierung vs. Datenorientierung: zwei Denkwelten

Florian Putz zeichnet einen klaren Kontrast. Objektorientierte Modelle sind stark im Modellieren von Beziehungen und Logik. Sie bilden Domänen ab, verankern Verantwortlichkeiten und erlauben polymorphe Strukturen. Aber: „Es entspricht halt meistens nicht dem, wie die CPU oder der Computer eigentlich arbeitet.“ Wenn bei jeder Iteration Methoden über verschachtelte Objekte aufgerufen werden, jagt die CPU Pointern hinterher, invalidiert Caches und verliert Taktzyklen.

  • Objektorientiert: Gute mentale Modelle, tiefe Hierarchien, Beziehungen als Erstbürger – aber oft schlechte Datenlokalität in Hot Paths.
  • Datenorientiert: Daten werden so gruppiert, wie auf sie zugegriffen wird. Was gemeinsam verarbeitet wird, liegt gemeinsam im Speicher – möglichst kontinuierlich (Continuous Memory).

Der Übergang ist konzeptionell groß: Statt Klassenlogik mit verteilter Zuständigkeit gibt es flache Datenstrukturen und Systeme, die zur Laufzeit genau jene Daten „abfragen“, die sie benötigen.

Warum Cache-Locality die Metrik ist, die zählt

Cache-Locality ist der rote Faden. Liegen benötigte Werte dicht beieinander, wirken Cache-Linien wie Beschleuniger. Liegen sie verstreut oder liegen zwischen den benötigten Werten große „Lücken“ (irrelevante Felder), „trasht“ der Code den Cache.

  • Pointer-Chasing vermeiden: Jeder Sprung über einen Pointer birgt das Risiko eines Cache-Miss. Viele kleine Sprünge summieren sich zu massiven Latenzen.
  • Kontinuierlicher Speicher: Arrays, die genau die Felder enthalten, auf die im nächsten Schritt zugegriffen wird, halten die CPU „gefüttert“.
  • SIMD und Pipelining: Wenn die Daten in der passenden Reihenfolge und Dichte vorliegen, kann der Compiler besser optimieren; Instruktionen können mehr „auf einen Schlag“ erledigen.

Das Geheimnis effizienter Schleifen ist also seltener der raffinierte Trick im Inneren der Schleife – und häufiger die Frage, ob die Schleife „die richtigen Bytes“ in der „richtigen Reihenfolge“ liest.

Array of Structs vs. Struct of Arrays: das grundlegende Layout

Im Talk kontrastiert Florian Putz die typischen Anordnungen, die in der Praxis direkt spürbare Folgen haben:

  • Array of Structs (AoS): Ein Array aus Objekten/Strukturen, die viele Felder enthalten. Bei der Bearbeitung eines Teilaspekts (zum Beispiel Positionen) werden jedes Mal auch andere, gerade irrelevante Felder in den Cache geholt.
  • Struct of Arrays (SoA): Ein „Struktur“-Gedanke, in der jedes Feld als eigenes Array vorliegt. Statt viele breitgefächerte Records zeilenweise zu lesen, liest man eine spaltenweise Anordnung – genau die Werte, die man für den aktuellen Schritt braucht.

Das Beispiel im Talk: Wenn wir nur die Positionen aktualisieren wollen, lädt AoS immer auch Geschwindigkeit, Lifetime und mehr mit in den Cache – verschwendete Bandbreite und Cache-Platz. SoA dagegen hält die Positionen eng nebeneinander; die Schleife liest fast ausschließlich Relevantes.

Praxiskonsequenzen:

  • Iterationen über große Mengen (Tausende bis Millionen Einträge) profitieren massiv, wenn irrelevante Felder nicht „mitschwingen“.
  • Die CPU kann Vorabrufe (Prefetching) und Vektorisierung besser nutzen, wenn die Daten gleichförmig und dicht gepackt sind.
  • Die Anzahl der Cache-Misses sinkt spürbar; die Schleifenlaufzeit wird stabiler und besser skalierend.

Über Performance hinaus: Wie DOD die Architektur verändert

Florian Putz betont, dass DOD mehr ist als ein Layout-Trick. Wer Daten flach und logisch getrennt organisiert, landet bei einer anderen Architektur:

  • Weniger Hierarchien, mehr „Systeme“: Statt tiefer Objektbäume mit Ownership-Ketten gibt es unabhängige Systeme, die sich Daten bedarfsorientiert „holen“ – ähnlich wie eine Datenbankabfrage.
  • Keine dauerhaften Abhängigkeiten: Systeme kennen einander nicht und halten keine langlebigen Referenzen. Abhängigkeiten entstehen nur temporär, wenn ein System Daten abfragt, und verflüchtigen sich danach sofort wieder.
  • Weniger geteilte Zustände: Shared Mutable State wird aktiv vermieden. Dadurch reduzieren sich Seiteneffekte und Überraschungen.

Das Resultat ist doppelt wertvoll: Zum einen sorgen wir für eine Software, die in Hot Loops schneller ist; zum anderen verringern wir Kopplung und Komplexität im Code.

Komplexität durch Beziehungen vs. DOD als Entflechter

Das Bild, das Putz vom „klassischen“ OOP-Ansatz zeichnet, ist vielen vertraut: über die Jahre zunehmend dichte Netze aus Zuständigkeiten, jeder kennt (oder referenziert) jeden, Lebensdauern werden undurchsichtig, Seiteneffekte mehren sich.

  • Versteckte Effekte: Methodenaufrufe, die nebenbei Zustand an anderer Stelle ändern, machen Bugs schwer reproduzierbar.
  • Schwierige Lebensdauern: Welche Objekte müssen wann noch leben? Wer hält noch eine Referenz? Solche Fragen kosten Zeit und Nerven.
  • Multithreading-Klippen: Shared State, Locks direkt in Objekten, Potenzial für Deadlocks und Contentions.

Dem setzt DOD die Idee entgegen, dass nur die zeitlichen Abhängigkeiten der Systems-„Pipeline“ modelliert werden. Statt „Klasse A kennt Klasse B“ fragen wir: „Wann werden welche Daten gelesen, wann geschrieben?“ Das macht Abfolgen explizit – ohne die Systeme logisch aneinanderzuketten.

Zeitliche Abhängigkeiten modellieren: die Pipeline als Ordnungsprinzip

Die zentrale Architekturbotschaft lautet: In DOD modellieren wir keine dauerhaften strukturellen Beziehungen, sondern zeitliche Reihenfolgen. Was muss vor was laufen, damit Daten zur richtigen Zeit an der richtigen Stelle liegen?

  • Implizite Kopplung wird durch explizite Reihenfolge ersetzt.
  • Systeme „konsumieren“ Daten und „produzieren“ neue; wenn ein System fertig ist, sind seine temporären Referenzen weg.
  • Die gesamte Abfolge macht den Datenfluss sichtbar – das, was bisher oft „versteckt“ in Objektbeziehungen steckte, wird zur expliziten Pipeline.

Diese Sichtweise erleichtert die Wartung: Wer auf die Timeline schaut, sieht, wo gelesen und wo geschrieben wird – und plant Änderungen entsprechend.

Nebenläufigkeit ohne Locks: Partitionieren statt blockieren

Einer der stärksten Teile des Talks sind die realen Erfahrungen: „Da kommt dann im Prinzip komplett Multithreaded Software raus, die wirklich alle 32 Kerne ... benutzt und in der ganzen Software gibt es keinen einzigen Mutex.“ Der Weg dorthin:

  • Daten partitionieren: Jeder Job/Systemschritt arbeitet auf einem disjunkten Datensegment.
  • Zeitliche Abhängigkeiten lösen: Durch die Pipeline-Logik wird klar, was gleichzeitig laufen darf und was sequenziell sein muss.
  • Keine geteilten Objekte: Ohne Shared Mutable State sinkt der Bedarf an Synchronisation dramatisch. Statt Locks: höchstens Warten auf Futures.

Das Ergebnis: Concurrency wird „zum Teil wirklich komplett trivial“. Nicht, weil Multithreading trivial wäre – sondern weil das Datenmodell Konflikte strukturell vermeidet.

Wo DOD glänzt – und wo nicht

Florian Putz macht deutlich: DOD ist kein Allheilmittel. Es entfaltet seine Stärken dort, wo Datenvolumen, Echtzeitanforderungen und Durchsatz zählen:

  • 3D-Engines und Rendering
  • Simulationen
  • Datenanalyse mit großen Datenmengen
  • Gaming

Hier ermöglicht DOD besseren Cache-Use, höheren CPU-Throughput und klare, robuste Nebenläufigkeit. Gleichzeitig gilt: „Nicht jedes System braucht das.“ In kleineren, nicht performancekritischen Anwendungen überwiegt möglicherweise der Mehraufwand im Design.

Kosten und Umstieg: Was das Team wissen sollte

Der Talk verschweigt die Einstiegshürden nicht:

  • Mehr Designaufwand am Anfang: Wer aus der objektorientierten Welt kommt, muss gedanklich umstellen. Lösungen sehen anfangs „komplett unintuitiv“ aus.
  • Debugging und Tooling verändern sich: Die Werkzeuge und Routinen, die sich an objektorientierten Strukturen orientieren, passen nicht 1:1.
  • Andere mentale Modelle: Statt „Objekte und ihre Beziehungen“ stehen „Daten und ihre Flüsse“ im Zentrum. Das betrifft Architekturgespräche, Reviews und Tests gleichermaßen.

Die Belohnung ist greifbar: „Besserer Cache-Use, besserer CPU-Use, größerer Throughput … Concurrency wird zum Teil wirklich trivial.“ Außerdem wird der logische Datenfluss so explizit, dass Änderungen leichter fallen.

Änderbarkeit als Feature: Systeme ein- und ausstecken

Ein besonders anschaulicher Vorteil: Systeme lassen sich isoliert entfernen, ohne die Gesamtheit zu zerbrechen. Putz nennt das Beispiel „Physics System“: Entfernt man es, funktioniert die Physik nicht – aber Rendering und andere Teile laufen weiter. Im OOP-Ansatz wäre das Entfernen einer Klasse oft bereits ein Kompilationsstopper, von Laufzeitfolgen ganz zu schweigen.

Diese Modularität entsteht nicht durch dynamische Magie, sondern durch die saubere Trennung von Daten und die zeitliche Modellierung der Verarbeitung.

Leitplanken für Teams: So denken wir DOD von Anfang an

Aus dem Talk lassen sich praktische Leitfragen ableiten, die wir bei neuen Projekten (oder Re-Designs) stellen können:

  1. Welche Daten bewegen wir wirklich pro Frame/Iteration? Was wird gelesen, was geschrieben?
  2. Welche Daten gehören „nebeneinander“, weil wir sie gemeinsam anfassen? Können wir sie in kontinuierlichen Speicher legen?
  3. Wo entstehen versteckte Abhängigkeiten? Können wir diese durch zeitliche Reihenfolgen ersetzen?
  4. Wie partitionieren wir die Daten, sodass Jobs unabhängig und ohne Locks laufen?
  5. Welche Systeme lassen sich klar umschreiben als „Nimmt Set A, berechnet B, schreibt C“ – ohne dauerhafte Referenzen?

Antworten auf diese Fragen zwingen Teams, Datenflüsse zu formalisieren – eine Art Architektur-„Inventur“, die in DOD essenziell ist.

Praxisbezug: Von der Schleife zur Pipeline

Der Weg in die Umsetzung verläuft typischerweise in zwei Schritten:

  • Lokal optimieren: Hot Loops identifizieren, die viel Zeit in Speicherzugriffen verlieren. Felder isolieren, SoA-Layouts einsetzen, Iterationsreihenfolgen anpassen.
  • Global ordnen: Systeme definieren, die ihre Eingabedaten abfragen, ohne dauerhafte Kopplung. Die Pipeline so anordnen, dass zeitliche Abhängigkeiten klar werden und Nebenläufigkeit möglich wird.

Der zweite Schritt ist der transformierende: Er ändert nicht nur die Geschwindigkeit, sondern die Art, wie Teams über Zuständigkeit, Verantwortlichkeit und Testbarkeit sprechen.

Missverständnisse vermeiden: Was DOD nicht ist

Aus der Argumentation im Talk lassen sich auch ein paar „Nicht-Ziele“ ableiten:

  • DOD ist kein Automatismus: Es ist ein Designansatz. Ohne bewusste Datenmodellierung bleiben die Vorteile aus.
  • DOD ist kein Dogma: „Ein Hammer ist ein Hammer und eine Schaufel ist eine Schaufel.“ Nicht jedes Problem verlangt denselben Ansatz.
  • DOD ist nicht nur Micro-Optimierung: Der Hauptgewinn liegt in Datenfluss, Cache-Locality und Architektur – nicht in einem zufälligen Trick in einer Engpass-Funktion.

Checkliste: Wann lohnt sich der Umstieg?

  • Hohe Datenraten pro Frame/Iteration (Tausende bis Millionen Einträge)
  • Spürbare Verzögerungen trotz „guter“ Algorithmik
  • Häufige Cache-Misses, Pointer-Chasing in Profilen
  • Schwierige Nebenläufigkeit mit vielen Locks und Contentions
  • Bedarf, Systeme zur Laufzeit zu- oder abzuschalten, ohne das Gesamtsystem aufzubrechen

Treffen mehrere Punkte zu, findet DOD wahrscheinlich eine natürliche Angriffsfläche.

Zitate und Leitsätze aus dem Talk

„CPUs sind schnell beim Rechnen und langsam beim Laden.“

„Ich ordne meine Daten so an, dass ich sie so gruppiere, wie sie dann darauf zugegriffen wird.“

„Dependencies zwischen den Systemen sind implizit … Es werden eigentlich nur zeitliche Abhängigkeiten modelliert.“

„Komplett Multithreaded, alle 32 Kerne – und kein einziger Mutex.“

Diese Sätze sind mehr als Merksätze. Sie dienen als Designkompass im Alltag.

Fazit: Weniger Magie, mehr Datenfluss – und robuste Performance

Der Talk „Data Oriented Design“ von Florian Putz (CADS GmbH) schärft eine einfache Einsicht: In datenintensiven Anwendungen gibt der Speicher den Takt vor. Wer Daten so organisiert, wie sie verarbeitet werden, gewinnt doppelt: in roher Geschwindigkeit und in architektonischer Klarheit. Systeme werden entkoppelt, Nebenläufigkeit wird planbar und oft lock‑frei, der Datenfluss ist sichtbar und änderbar.

Nicht jede Software braucht DOD – aber überall dort, wo es eng wird, lohnt der Blick auf Layout, Cache-Locality, zeitliche Abhängigkeiten und Partitionierung. Wer diesen Blick kultiviert, macht aus Performanceproblemen Architekturaufgaben – und löst sie an der Wurzel.

Wichtige Takeaways für Engineering-Teams

  • Speicherzugriffe dominieren häufig die Kosten. Optimiere das Layout vor der Logik.
  • SoA statt AoS, wo Schleifen nur Teilmengen der Felder berühren.
  • Systeme statt Hierarchien: Daten abfragen, nicht referenzieren.
  • Nur zeitliche Abhängigkeiten modellieren – keine dauerhafte Kopplung.
  • Daten partitionieren, damit Concurrency ohne Locks möglich wird.
  • DOD dort einsetzen, wo Datenmengen groß sind und Durchsatz zählt.

Wer diese Prinzipien beherrscht, macht den entscheidenden Schritt vom „schnellen“ Code zum „skalierenden“ System – genau der Sprung, den Florian Putz in seinem Talk adressiert.

Weitere Tech Talks

Weitere Tech Lead Stories

Weitere Dev Stories