Disclaimer: This is a transcript from a 15mn recording which was supposed to be on critical thinking but immediately devolved into first principles thinking, stemming from a (very funny) screenshot sent to me in DMs

1. Critical thinking is a completely different thing – in the case of the example I used during the yap: it would be more akin of asking yourself “what are the the different ways I could implement the hit detection in this game?” and the process of uncovering and then fleshing these out.

2. This is very unpolished. I just cleaned up the “right?”, “ums”, and endless repetitions. It’s missing a lot of juicy details, like how under/over decomposition can be avoided, the kind of “pitstop” questions you can ask yourself, such as “is this component’s interface clear (eg clear inputs/outputs), can it be implemented independently of other components”, etc

Please take this for what it is: a transcript of a random 15mn rant full of “ummms” and wandering which I used to respond a DM.


Critical thinking is pretty important when it comes to designing and building systems, but also like the day-to-day of writing code. Here’s some of the things that you want to do, I guess.

Side-note: to improve critical thinking, you also kind of want to be thinking about thinking, uh for that, I recommend Dan B’s website. He’s a good buddy of mine. It’s a good website. Maybe just read that instead.

So, let’s see. let’s check my notes. All right.

I’ll start by talking about first principles thinking. You want to break down big problems and systems (I use systems and problems interchangeably throughout) into smaller, simpler parts – the basic, primitive components that compose the problems or systems in question.

So if you’re trying to build a Tetris clone, you don’t want to think about the whole thing at once. You can’t start that way, it’s too big and complex. You want to think about each of the things that composes what a Tetris clone are, for example:

  • how you going to represent the Tetris blocks?
  • How are you gonna handle them colliding with each other?
  • How are you gonna draw them on the screen? Even that is a big problem, you can break down into many other smaller problems.
  • How is the score gonna work?
  • And then you have the controls, right?  Like, how am I gonna listen to keyboard inputs and then you know, apply logic to do this, right? And then, if they press R, we have to rotate the piece, how am I gonna rotate the shape 90 degrees, etc…?

So you want to break these down into smaller problems, right? And then you want to keep breaking them down until you get two things:

  • you get something that feels actionable
  • and then something that’s also somewhat irreducible, right? Something that can’t really be broken down into anything simpler.

You don’t have to be absurd with it. , You don’t have to like keep breaking down into the absolute smallest things you can, otherwise you never get anywhere, but yeah.

So that’s the first step is that the decomposition of the problem into the smaller components that compose it, right? And what you’re trying to figure out is kind of like the atomic things that are inherent to what you’re trying to do, the things that are not going to go away, no matter the approach, right? And so, like, if you’re trying to build a Tetris clone, like some of the atomic truths of it are you’re gonna need the blocks and you’re gonna need them to appear from the top of the screen and you might need to preview the next five ones that are gonna appear because usually Tetris does that, and you’re gonna need to be able to rotate them and they’re gonna collide and when they make a line, then they’re gonna need to disappear, et cetera, et cetera.

Those are the things that you know are absolutely inherent to Tetris, and so, you know, they can be broken down, but they’re not ever going to move, right? Oh, they’re not going to disappear. So that’s one thing. then, once you’ve established this truths, you want to try to formalize and clarify them to some extent, right?

Oh, so this is kind of implicit in the part of the decomposition for many things, but sometimes they are like, you know, things you can spend a bit more time formalizing and making sure that they are clear. And have clear requirements or definitions. And part of the process of that is not just the practical act of decomposing the problem and establishing the definitions, it’s also for you to spend time in the domain or so that you’re familiar with the fundamentals of this domain, right? of what you’re trying to achieve. The more time you spend thinking about it, the bigger your capacity to be intuitive and apply critical thinking will be, right?

Then, from these components that you’ve broken the bigger problem into, you can start building solutions with them. For example, you can literally get a whiteboard, or open http://draw.google.com, put these components (or even smaller problems) in little rectangles and you can start composing things with them, relationships for example. You can also bunch up several of these components into a bigger rectangle, eg 4-5 things might actually compose “hit detection”

You also want to systematically avoid assumptions and conventional wisdom. You do that by focusing on the core of what you are trying to achieve, always going at it from first principles (so with the technique we’ve been discussing). This is something that’s a little harder at first, but yeah, you want to avoid, even remove assumptions. You want to kind of avoid falling into paths of thinking that feel natural, but are not necessary. Part really comes from decomposing the problem or the system into its fundamental blocks and understanding what you’re trying to do. Letting yourself kind of find your **own(( path to build it — because if you’ve broken down the problem well enough, your intuition will end up being very close to conventional wisdom (or better)

A thing you can always do (and most of the time, should) is set the negative space of the problem: set a boundary around the problem — everything that’s not in the problem space is something you don’t have to do. In the Tetris example, the negative space is quite large if you’re doing a basic Tetris clone. It also depends on what platform you want the game to be playable, but for example, fi you’re using a 2D game engine for JS, the rendering etc… is not part of your problem space. This is solved for you. So you obviously you don’t want to list them all out, but you, you know, there are things that could be in in you Tetris clone that won’t be, and they are important to list out because it narrows the problem space.

So yeah, you list down all these components that you’ve broken down from the main problem/system, you try to identify some relationships between them and group them, you ask a lot of “why’s” at every decision you take, so that you can figure out what is really what is necessary. And then, you now have at least a list of actionable. You have things you can build, because they are now much simpler. You can attack them one by one. You have a sense of the problem as a whole. Each of the smaller components, you can attempt to build differently, but at the end of the day, you KNOW you need that component for the problem to be solved / the system to exist.