posrod nas

Analysis of "Casey Muratori – The Big OOPs: Anatomy of a Thirty-five-year Mistake"

The talk was amazing but I think a lot of people who speak negatively about it right now are either frustrated that the topic was OOP again or that they got an history lesson instead of a guide on how to apply X to their codebase. One of my friends is not a fan of Casey and from his point of view, the talk was irrelevant to him because there aren’t directly any actionable actions.

From my point of view, this is exactly what an history class is for, it’s not made to tell you how you should think and how you should do things but it’s there to make you reflect on decisions made in the past, what mistakes and what good moves were made, etc. Once you have that information, it’s up to you to use critical thinking and make your own opinions based on historical facts, and that’s what we have here. While very opinionated, I think Casey did a good post-mortem on OOP’s design.

Many historical facts point out that OOP’s base design happened in the context of small teams (1-5 people) trying to do code reuse in simulation software (e.g. Car -> Truck to avoid rewriting the common code), and over the time, different language designer ended up selecting a subset of what was originally thought of based on the personal preferences and we lost those possible features (e.g. consider/inspect for discriminated unions). Furthermore, what made language designers prefer those features was (Casey’s opinion) a misunderstanding of what made Ross’s Plex and Sutherland’s Sketchpad so powerful.

When you look back, you can see that the Plex’s original design had BOTH function pointers (virtual functions) and tags (discriminated unions). It didn’t only choose one option since at the end of the day, both options are valuable (and Casey agrees on that). You don’t have to only do X or only do Y, when used at the right time both these tools can be useful. Sutherland’s Sketchpad used that idea and that’s what allowed him to be so efficient in his code and build something amazing in 1960. The omniscience present in his code (allowed by the Plex) is what made it possible for him to go so far.

Another takeaway from those two engineers is that they were not modelling the problem based on real life, they had to model the problem based on how the computer actually worked. Casey actually brought that one up, for example how people started to realize that you don’t have to “erase” the line once you’ve drawn it, and it doesn’t have to be permanent like in real life. This was hinting at retained mode vs immediate mode design, and how computer software architecture doesn’t map well to real life.

When designing software, we can often take “shortcuts” that real life can’t, such has deleting everything all at once (hello arenas and goodbye lifetime management!). We shouldn’t just try to map everything one to one because doing things this way will stop you from taking advantage of what computers actually enables you to do.

After hearing about Sketchpad’s omniscient design, you should be able to see how encapsulation can hinder this. While I’m pretty sure that Sutherland’s didn’t have encapsulation in mind designing this, it doesn’t stop us from mixing both ideas. This is actually something that I think Casey is for (contrary to popular beliefs based on his opinions on OOP).

If you link this back to Looking Glass’ architecture from the start of the talk (and the end of the Q&A), you can see how you would do encapsulation while allowing an omniscient design. Instead of encapsulating on an object level, you should encapsulate on a module/system level. Inside a system, there should be no encapsulation so that your Plexes (or Structs/Classes) can be omniscient to themselves and other data inside a same system. Encapsulation shouldn’t be a hard stop either, it’s more of an interface to a system, a recommendation, but if a system really needs to get additional information they should be able to go in another system and get it.

What was great about Sketchpad isn’t that its systems were omniscient to the whole program, but it’s that the program was omniscient to its systems and its systems were omniscient to their respective data. It was easy to calculate and apply constraints in the “drawing system” since it had all the information it could ever ask to do so, but that same system doesn’t need to be omniscient to the “rendering system” for example.

Another thing that the Plex allowed was to keep systems bundled together. Not every system needs to be made into its own system (e.g. an health point system and a shield point system), at the end of the day the best omniscient system is the one that contains all of them. Keeping multiple systems at the same place is even more powerful than constantly trying to split everything. Following Looking Glass’ history, you can also see that the reason they split something into a system is that it was getting too big and hard to manage. Before you get to this point, there is no issue with keeping everything together.

Now I’m not a fan of rule of thumbs, but if you really want something actionable to design your systems once they get out of hand and you need to split, it would be to think “how much information does my system needs to know to operate”, and you should draw the system’s boundaries where that information ends. When looking at your system’s boundaries, you should be able to see how it’s omniscient to all the data it might need. By doing this, we are no longer basing our boundaries on real life representation, but instead we are shaping them based on our software requirements.

Why do most people in this “school of thought” dislike rule of thumbs is because they shouldn’t be blindly followed. When you look at ECS, you can see how many are trying to generalize this approach and apply it blindly to every use case, when in fact this often ends up in development hell (despite OOP often being the one being “bashed”, turns out everything is bad!). This is the reason we don’t like naming things or calling it “ECS”. General purpose solutions rarely end well, whether it’s a coding paradigm, a design pattern or a game engine, these tools are not tailor made to their problem, they try to generalize an approach to solve X but as a result, they make solving X a lot more tedious and often forcing developers to work around the tools they were originally using instead of with them, adding a ton of friction in development.

While many directly assume that Casey is “bashing” OOP again, his main message was that the roots of OOP were originally designed to solve a few specific problems:

When looking at the history, we can see that back then people didn’t have general rules to follow nor were they trying to create them. They just had a specific problem they had to solve and created a tool to solve it. The issue came when people tried to generalize these approaches into a general purpose tool (OOP) and today, people are applying them to every problem even though their problems are not what these tools were originally intended for.

Casey gave a lot of pointers to what makes a good software architecture through his talk but the main takeaway is that every problem requires its own solution, and as software developers and engineers we can’t just blindly apply generic solutions to them, we have to think critically.