
A Thought Experiment: Using the ECS Pattern Outside of Game Engines - MichaelFBryan
http://adventures.michaelfbryan.com/posts/ecs-outside-of-games/
======
TeMPOraL
Which ECS? :).

Despite "clear" definition from Wikipedia, ECS as a pattern suffers from
multiple personality disorder. There are several different goals that all
share the same name, and different implementations pick a different goal set,
ending up looking not quite the same, and getting different kinds of benefits.

So outside games, if you pick "ECS as composition over inheritance", you get
something like here, or Clojure's "let's use maps for everything". If you go
for "ECS as a performance optimization" \- a frequently touted benefit -
you'll end up storing a lot of global arrays (perhaps arranged in structures),
each packing every instance of a component's property across all entities.

If you go for "ECS as a way to have data-driven entities modifiable on the
fly" or "ECS as a way to make game logic cleaner", then congratulations,
you've just reinvented a relational database! Since you're not developing a
game, you might as well store your data in SQLite and call it a day.

(In fact, I'm currently working on a roguelike game as a side project, whose
distinct feature is that it stores all its game data in an in-memory SQLite
database, precisely to experiment with a pure form of "ECS for game logic"
pattern.)

In the end, the author explored one way of doing ECS. There are plenty others,
worth their own thought experiments :).

~~~
codetrotter
> If you go for "ECS as a performance optimization" \- a frequently touted
> benefit - you'll end up storing a lot of global arrays (perhaps arranged in
> structures), each packing every instance of a component's property across
> all entities.

This is basically what I am doing in the backend I am writing for an app that
I am working on. (Also not a game btw.)

No database, no overhead :D

You really can fit a lot of data in memory, and I think a lot of people tend
to forget that.

I so so wish that I get to see the day when memristors become cheap and
abundant. It would be so pleasant to program for a system like that I think.
No persisting to disk or loading from disk, ever – imagine that!

~~~
BubRoss
New NVMe drives claim 5GB/s on PCIe 4, is memory mapping something like that
not good enough for you already?

~~~
fulafel
In these applications you primarily care about latency. Even these new SSD's
have latencies 3 orders of magniture higher than DRAM. The 20 usecs is access
time is about 100k executed instructions (scalar + single thread).

~~~
BubRoss
In what applications? The parent didn't even say what they were working on.
Everyone wants ideally wants a perfect memory technology with no latency,
large sizes and persistence, so I'm not sure what you are talking about
exactly. If something needs less latency, you cache it or load it into memory.
You seem to be saying that this current technology, that actually exists, is
not good enough for a mystery application because it isn't as good as
theoretical memresistors.

------
netgusto
I did this lightweight ECS for Go and TypeScript:

TS: [https://github.com/netgusto/ecs-
typescript](https://github.com/netgusto/ecs-typescript)

Go: [https://github.com/bytearena/ecs](https://github.com/bytearena/ecs)

Very interesting programming concept indeed!

\---

Edit: These implementations support tagged queries, and indexed views for
faster iterations (ECS uses iterations a lot).

------
almindor
I've built the Texel ASCII Art Editor
([https://crates.io/crates/texel](https://crates.io/crates/texel)) using Specs
([https://crates.io/crates/specs](https://crates.io/crates/specs)) as my first
experience with ECS.

The original goal was an ASCII game but since I needed to create the resources
for it it morphed into Texel. I think the use of ECS here wasn't a bad
decision but Specs proved to be just too cumbersome and overoptimizing.

As others have mentioned ECS is a bit "loosly defined" and each implementation
seems to go over the line to add more specializing one way or the other. I
want to switch to something more simple and elegant like DCES
([https://crates.io/crates/dces](https://crates.io/crates/dces)) for my next
refactor.

I think for "runtime resource management" ECS is fine if you need a fairly
large, distinct pool of entities to handle. One of my main usage problems was
the re-use of same components in the same entity.

E.g. imagine having an entity with a global world position, but also an
internal position for something like "last cursor position". It's not possible
to just "add another Position component" to the same entity, for good internal
reasons, but still. It's pretty important people take these kind of
limitations into account before planning out their entity/component maps.

------
fulafel
In the Clojure world, this used to be a popular way to structure backend apps:
[https://github.com/stuartsierra/component](https://github.com/stuartsierra/component)

> Components provide some basic guidance for structuring a Clojure
> application, with boundaries between different parts of a system. Components
> offer some encapsulation, in the sense of grouping together related
> entities.

> Each component receives references only to the things it needs, avoiding
> unnecessary shared state. Instead of reaching through multiple levels of
> nested maps, a component can have everything it needs at most one map lookup
> away.

~~~
TeMPOraL
Used to be? What replaced it? I used it in my last Clojure project, and I'm
about to start expanding it further; should I replace it with something else?

~~~
heretoo
try integrant

[https://github.com/weavejester/integrant](https://github.com/weavejester/integrant)

You can move from using component's functions/macros to using a map and cross
references using reader literals.

Having used both, I find integrant to work better for me.

------
jrhurst
I find ECS a pretty intuitive concept, but it always ends up being a massive
yak shave to me

~~~
jayd16
Agreed. The vast majority of the benefit is simply from learning to use
composition over inheritance.

Most applications that aren't games don't need to support things like finding
all active objects of a type or maintain many discrete actors executing their
own run loops.

But Unity isn't dumping a lot of marketing into talking about the decorator
pattern so everyone is jumping right to ECS now.

------
shoo
See also: Richard Fabian's "Data-Oriented Design" book. The fourth chapter is
about component-based objects, and the preceding chapters about relational
databases and existential processing are relevant.

[http://www.dataorienteddesign.com/dodbook/](http://www.dataorienteddesign.com/dodbook/)

Prior HN discussion:
[https://news.ycombinator.com/item?id=20380397](https://news.ycombinator.com/item?id=20380397)

------
ncmncm
Who are these people who think that inheritance is the solution to every
architectural problem, or any?

I didn't think that Java coders were especially well represented in the gaming
world. It has been over 20 years since C++ programmers learned that
inheritance is just a way to dress up function pointers (not that that does no
good, but function pointers are pretty specialized machinery).

Seriously, you don't need to use a named style to write programs. Your
language offers lots of different facilities you can put together in any way
that is useful to achieve your aims. Functional, OO, ECS, MVC, procedural,
data-oriented, reactive, whatever -- it is all just code.

You have only three problems: code needs to be organized well enough that you
can understand it, code should run fast enough, and you should be able to
change one thing without rewriting everything else. Nothing else matters.

------
aliswe
I'm accidentally using this approach in my CMS for saving .NET Core classes
(with interfaces - and supports explicit interface implementations) into
document stores.

EDIT: Actually, now when I think about it, this approach sorta makes every
object (or Entity) into an independent, isolated database. Hm ...

------
5cott0
Apple provides an ECS in gameplaykit that can be used in iOS/UIKit apps, not
sure why anyone would want to though.

[https://developer.apple.com/documentation/gameplaykit](https://developer.apple.com/documentation/gameplaykit)

~~~
Razengan
> _not sure why anyone would want to though._

What do you mean by that?

GameplayKit has its limitations, but I've been building an entire engine
around it, and I like it so far, especially for the ability to stick with pure
Swift and native APIs:

[https://github.com/InvadingOctopus/octopuskit](https://github.com/InvadingOctopus/octopuskit)

~~~
5cott0
Not sure why anyone would want to use GameplayKit ECS as a replacement for
MVC/MVVM arch in a UIKit based app.

~~~
Razengan
Oh, I forgot what the topic was and assumed that comment was about GameplayKit
in games.

------
golergka
That's exactly the idea that I have been toying with recently: using ECS (and
even spec crate in particular) to implement an authoritative game server.
Haven't yet figured out how to make spec's and tokio's scheduling to play
along, though.

------
zubairq
How is an Entity Component System different from Objects and Controls in
something like Visual Basic for example?

~~~
adamnemecek
Ecs is more like a database.

~~~
TeMPOraL
ECS is all these things and none of these things. It's several separate
concepts under the same name; different applications/games pick different
pieces of it.

It's kind of meta, really; you can imagine ECS itself as an entity, and
different meanings of it as different components that could be included in it.

~~~
dyarosla
ECS is meta? Love the recursive definition ;)

------
JoshMcguigan
I look forward to seeing the ladder logic editor. I run PLCFiddle [0], which
is a purely React ladder logic editor.

[0]: [https://www.plcfiddle.com](https://www.plcfiddle.com)

------
spankalee
So many of these kinds of OOP modeling complaints and solved by mixins.

~~~
_carl_jung
I'd earnestly like to hear the responses to this from the down-voters. I had
the same thought and suspect there is a good reason not to use mixins.

One problem off the top of my head is run-time changing of components. An
entity that inherits from multiple mixins can't inherit from new mixins (or
lose existing ones) at runtime.

~~~
skybrian
Yes, ECS is usually about runtime changes in behavior. It also uses IDs rather
than hard references, like in a database. Deleting an object makes references
to it invalid, rather than references keeping objects alive like in a
functional or object-oriented object graph.

~~~
spankalee
But the complaints about OOP in the article are all about the difficulty in
modeling orthogonal traits in a single-inheritance hierarchy. That is
definitely addressed with mixins.

Nothing in the "Inheritance isn't Always the Best Tool for the Job" section
talks about runtime changes in behavior.

~~~
skybrian
It does touch on it towards the end:

> Most object-oriented languages are designed so that an object's underlying
> type will be the same for its entire lifetime. This makes things interesting
> when users want to scale a Circle without maintaining aspect ratio.

------
jayd16
Isn't this usually referred to as the decorator pattern when used this way
outside of a game loop?

~~~
akhosravian
Short answer is no. Decorator is an OOP design pattern, ECS is an
architectural pattern. In that sense it’s a more abstract concept. One could
say decorator is an OOP form of it, but I think the data oriented design crowd
would balk at doing so in a mainstream OOP language like Java or C#.

~~~
jayd16
I suppose you're right. ECS explicitly calls out a system that separate from
the components while most of the decorator examples run code in the
components. I've written decorators that are closer to ECS but I guess its
fair to say ECS implies a specific implementation.

------
adamnemecek
I've been playing around with ECS. It does seem to solve a lot of
architectural problems I had.

------
nabla9
I have been using this.

Common Lisp Object system perfect and natural for this kind of programming.

------
raverbashing
This sounds a lot like OOP purists finding out not everything can be solved by
inheritance so they rename something that existed already.

