So if your working on a physics engine and your optimizing collision detection, you think about the data in -> data out of the problem you are solving as the primary driver of how the code should be written.
You start with defining the data, and build from there.
Different types of applications all have different shapes of data so would have differently shaped optimal code. Eg) a physics engine would use some kind of spatial hash thing which can be optimized differently based on if stuff can be added/removed while it's running. A 3d renderer operates on big buffers of matrices and vertex data. A game is usually composed of some long lived things and a lot of short lived things.
The key message in Mike Acton's talk was:
"If you have different data, you have a different problem."
While ECS systems are not a panacea that solves all problems in a perfect data oriented way, they are generally more malleable than Object Oriented hierarchies. This means it's generally more feasible to write "near optimal" code in an ECS framework than in a mature Object Oriented code base.
But the key message isn't "use X framework", it's "start by defining the data".
Also: just having stuff in an array or vector invites you to the ABA problem. You need a generation counter in there too, or else the array indice may get reused if something is deleted and another thing is reinserted at the same index. But that's yet another boilerplate that would easily be overlooked if you had to do everything manually.
Also: you seem to be saying this with C++ in mind. Do you think that applies to bevy_ecs too?
Modern Bevy has relationships to make sure that if an entity has a component that refers to another, it doesn't become dangling. It works a bit like foreign keys in databases. I think this makes ecs much more usable
(as an aside, there is a whole host of analogies between ecs and relational databases. entity archetypes are tables, entities are rows, components are columns, and systems are queries). Nobody tells people to just write their database from scratch though)
Why? Flecs, for example, is pretty sick imo.
So while it's great to think about the data flow it's also important to think about the abstractions around it,.ie the (system) interfaces that let the system evolve without having to propagate changes everywhere while reaping the benefits of data orientation.
“Entity Component System”, for those like me who didn’t immediately think of it.
AI generated skill?
Try asking your LLM of choice this in an empty session with no other context:
You are working for Mike Acton. What principles do you follow when writing code?
Maybe he found that telling it that it works for him nudges it in a direction that is beneficial to get it to write code like he wants, alongside the specific rules and other instructions in the above linked document?
[1] https://www.manning.com/books/data-oriented-programming-in-j...
At work we are rewriting and reengineering system from scratch and its crazy because the limitations of the old system are now gone we get the most insane feature requests that are even accepted by the team lead et al. This makes such an approach impossible since DoD is exactly the opposite of flexible design in my opinion.
Im curious has anybody really followed this in a big long living commercial project?
E.g. if your job is writing game engines or middleware used by AAA games with fancy graphics to run on consumer hardware, getting the most efficient use out of the players' limited memory bandwidth may be very important.
For many (most?) arbitrary commercial software projects in other contexts, performance isn't high priority & memory bandwidth isn't a bottleneck. Performance just has to be 'good enough' & 'good enough' performance may be easily attained by writing typical OO code that uses cache & memory very inefficiently - so in those cases DoD is an engineering trade off that solves a problem that doesn't need to be solved & may create new problems if introduced.
And I say this as someone who basically sees programming as data and associated algorithms and always approaches problems by considering state or data first.
The connection is that ORMs convince you to have an object-oriented view of the world, which maps nicely to object classes. But highly normalised designs don't map as cleanly to classes and objects, so you need to approach with a different style of programming on the application side.
Instead of seeing a User instance, you start to see a more complex bundle of login methods, profile events, etc.
AI changes that. Especially because it appears that LLM's can't understand the OOP abstractions any better than your hardware can compute it.
That being said. OOP and DOD both have advantages and disadvantages. If you go back to what I said first it wasn't exactly a failing of the OOP paradigm. The biggest issue I have with OOP is actually that it's too easy to do things wrong with it. Which isn't helped by the multimillion dollar industry which thrives on teaching developers everything except core computer science. People know their DRY, SOLID, CLEAN, TDD, Agile and every design pattern in the world, but they don't know how the interface they've just implemented actually handles their data.
personally I've discovered it insufficient to "just" convert tables to lists, you also need to understand the rest of the array principles to then effectively manipulate your data, and just to be able to hold compute in your head. because I believe in this approach I spent time learning j and k, but the end result is that my solutions become too alien for the general practitioner. it becomes apl written in whatever host language.
this is something that is not addressed in a lot of DOD talks, what happens when you do the full realization of technique: bulk list primitives, bulk transforms, SIMD optimizations, list compression, etc. and it's also the reason people claim this only works in narrow scopes (like gamedev). in reality you can write all your code for lack of better term the apl way, you're just going to make it unreadable to non apl practitioners. I'm not quite sure how to reconcile this in general, short of forcing apl to be part of general CS curriculum.
array languages give you concepts for thinking about these problems where you can succinctly express that entire talk in a single sentence, something like "inverted tables improve cache locality and optimize for time and space, prefer them where it matters". yes, got it, also a well known conclusion in array world.
a table is a 2 dimensional data that stores your records row by row and the items of a column all have the same data type. the way an array of structs would. an inverted table is a list of original table's columns. like a struct of arrays.
so if you have a table,
x
┌────┬──────┬─┬─────────┐
│mob1│level1│0│0.0243902│
├────┼──────┼─┼─────────┤
│mob2│level2│1│0.0147059│
├────┼──────┼─┼─────────┤
│mob3│level2│0│0.0120482│
└────┴──────┴─┴─────────┘
there's an idiom for converting it to an inverted table ]y=:(<@(>"1)@|:)x
┌────┬──────┬─────┬─────────────────────────────┐
│mob1│level1│0 1 0│0.0243902 0.0147059 0.0120482│
│mob2│level2│ │ │
│mob3│level2│ │ │
└────┴──────┴─────┴─────────────────────────────┘
you can then splice it across variables, 'name level isactive v'=:y
isactive
0 1 0
so you have converted a table to lists.Data first is fine for simple systems, but lead to chaos for complex systems.
An example of failing to follow DoD is the N+1 query problem: a programmer builds an abstraction that operates on individual DB rows, but "where there's one, there's more than one": you will inevitably be running that code in a loop so that you can process multiple rows. If instead the programmer had abstracted over groups of rows, then per-item query overheads suddenly become per-batch overheads.
People posted a wide variety of specific ideas under my other comment: https://news.ycombinator.com/item?id=49061421
When you look at it from that angle, rather than as an optimization technique, it makes it clear there is actually an elegant programming model here.
Unfortunately game engine programmers tend to think databases are super uncool and not relevant. They could actually learn a lot.
"flecs" pulls in some concepts from the relational algebraic world in that it has some sense of joins, etc. but it's a bit ad hoc.
The ultimate "data oriented design" game engine could be a high speed, GPU/SIMD accelerated, in-memory Datalog engine. And then the game world expressed in Horn clauses and logic.
https://github.com/timbran-project/mica is some of my playing in this area.
Maybe hardware- and access-aware more generally.
One of Mike Acton's other talks has a "Is Data-Oriented Design even a thing?" section, which goes over what he means when he refers to DOD:
1. Indexes instead of pointers. This allows you to avoid alignment of 8 bytes in your structure for x86_64.
2. Storing booleans out-of-band. Booleans cause padding all the time.
3. Struct of Arrays. Based on your question I assume you're familiar with it.
4. Store sparse data in hash maps. I remember one time when it allowed to eliminate inheritance.
5. Encoding the data instead of OOP/polymorphism. I haven't got an occasion to use it. The idea is to add extra tags to avoid boolean properties.
- Andrew Kelley Practical Data Oriented Design (DoD) - https://youtu.be/IroPQ150F6c?si=F1Z0pLO2W5hbQgpM
- CppCon 2014: Mike Acton "Data-Oriented Design and C++" - https://youtu.be/rX0ItVEVjHc?si=jv4hhTSBh3XH--xQ
- Why You Shouldn’t Forget to Optimize the Data Layout - https://cedardb.com/blog/optimizing_data_layouts/
- Handles are the better pointers - https://floooh.github.io/2018/06/17/handles-vs-pointers.html
- Enum of Arrays - https://tigerbeetle.com/blog/2024-12-19-enum-of-arrays/
- Data oriented design book - https://www.dataorienteddesign.com/dodbook/
- Data-oriented design in practice - Stoyan Nikolov - https://youtu.be/_N5-JjogNXU?si=vhaxYcfE6tl11Sux
- Programming without Pointers - Andrew Kelley - https://www.hytradboi.com/2025/05c72e39-c07e-41bc-ac40-85e83...
- More Speed & Simplicity: Practical Data-Oriented Design in C++ - Vittorio Romeo - CppCon 2025 - https://youtu.be/SzjJfKHygaQ?si=jafavSl2YJWk4vIx
- Rust Handle - https://taintedcoders.com/rust/handles
There are also cases where the optimal data format isn't array oriented because the memory access patterns for the problem in question just require something else.
You also have to think of hot vs cold data, which has nothing to do with arrays.
Very often the answer is indeed arrays, but it can easily be something else, depending on the problem. Data driven design is not very complicated, it just means instead of thinking about abstraction you think about the shape the data needs to be in to accommodate the most common transformations you need to do with it.