(video)
ECS is better than OOP

OOP vs ECS, in Simple English

A plain explanation of what Casey Muratori is getting at in The Big OOPs, and how to actually use the idea to write better code. [page:1]

TL;DR

The simple idea is this: stop making one big object that contains everything about a thing, and instead keep each kind of data in its own place. Then write code that works over one kind of data at a time. [page:1]

In the talk, the key architectural shift is to organize code around systems like physics or combat instead of organizing everything around the entity itself. [page:1]

Very simple implementation

Imagine a game with a player and an enemy. Both have a position. Both may have health. Only the enemy has AI. [page:1]

In the usual object style, you might make a Player class and an Enemy class, and each object stores all its own data and functions. The talk argues this often puts the boundaries in the wrong place. [page:1]

In the ECS-style approach, you do this instead:

That means your code looks more like this:

entity 1 = player
entity 2 = enemy

positions[1] = {x: 10, y: 4}
positions[2] = {x: 20, y: 7}

health[1] = 100
health[2] = 50

ai[2] = "chase player"

Now your movement code does not ask “is this a Player or Enemy object?”. It just updates entries in positions. Your combat code just updates entries in health. Your AI code just works on entries in ai. [page:1]

So the real change is not “no objects ever.” The real change is: store data by kind, and write logic by job. That is the practical benefit Muratori points to when he says the boundaries should be around systems, not around domain-model objects. [page:1]

Why this is useful

This style helps because adding a new kind of thing becomes easier. If tomorrow you want a flying enemy with health and inventory, you do not need a new complicated inheritance tree; you just give that ID the data it needs in the right places. [page:1]

The talk’s example from Looking Glass describes this as using an ID and then asking each system what data exists for that ID, instead of stuffing everything into one hierarchy of entity classes. [page:1]

It also tends to make big features easier to write, because your physics code can focus on physics data, your combat code can focus on combat data, and your UI code can focus on UI-related data. That separation is the main implementation benefit. [page:1]

The longer explanation

Most people first learn to code by modeling the world as objects. You make a Player class, an Enemy class, maybe an Item class, and each one owns its own data and behavior. In the talk, Muratori argues this often becomes a trap when the class hierarchy is forced to mirror the real-world idea too literally. [page:1]

His criticism is specific: the mistake is drawing encapsulation boundaries around compile-time hierarchies that match the domain model. In simpler terms, that means you lock your code around categories like “player”, “enemy”, and “vehicle”, even when the real work in the program is actually movement, combat, inventory, rendering, or AI. [page:1]

The alternative he highlights is what Looking Glass used in Thief: start with an ID, then let systems own the relevant data for that ID. The entity is just the thing being referred to; the useful structure lives in the systems. [page:1]

What changes in practice

In OOP-heavy code, when you want to add a feature, you often ask: “Which class should this belong to?” In the ECS-style way, you ask: “What data exists, and what code should operate on that data?” [page:1]

That is a much better question for many real systems. If a stun effect applies to players, enemies, and bosses, it is awkward if those are all separate class branches. It is simpler if “stunnable” is just a piece of data that some IDs have. [page:1]

So instead of inheritance solving reuse, composition of data solves reuse. The talk repeatedly points to this as the more flexible direction, especially when code has to work across many kinds of entities. [page:1]

A practical mental model

If you know databases, think of ECS like this: entities are IDs, components are like tables keyed by ID, and systems are the code that queries and updates those tables. This matches the structure described in the talk’s discussion of Looking Glass and also appears in the audience discussion around the same idea. [page:1]

That mental model is useful because it stops you from over-romanticizing “objects.” A thing in your game or app does not need to be a giant self-contained creature in code. It can just be an ID with rows of data attached to it. [page:1]

How to code better tomorrow

You do not need to rewrite your whole programming style overnight. The easiest improvement is just this: when you are about to make a deep class hierarchy, stop and ask whether you actually have a “thing hierarchy” problem or a “shared data plus shared operations” problem. [page:1]

If many different kinds of things all need the same processing, that is usually a sign to move toward the ECS-style way of thinking. Put the shared data together, and write one piece of code that handles it in one place. [page:1]

In short: do not start with “what class is this?” Start with “what data exists?” and “what code needs to run over it?” That is the clearest coding lesson to take from this talk. [page:1]