So to avoid these ends, let's avoid these beginnings: avoid multi-threading. Use single-threaded programs, which are easier to design, write, and debug than their shared-memory counterparts. Instead, use multiple processes to extract concurrency from the hardware. Choose a communication medium that works just as well on a single machine as it does between machines, and make sure the individual processes comprising the system are blind to the difference. This way, deployment becomes flexible and scaling becomes simpler. Because communication between processes by necessity has to be explicitly designed and specified, modularity almost happens by itself.
"Use single-threaded programs, which are easier to design, write, and debug than their shared-memory counterparts."
Not really. Well, only true in simple cases. Let's say I have a 16-core box and I want to crunch some data using all the cores. What's easier, clojure with a single shared memory data structure that collects that stats, or a multi-process system where we not only have to manage multiple application processes, we also have to use something like redis to hold the shared state?
He's precisely considering your 16-core case. Now think about what happens when your dataset grows and you need more cores than you can reasonably fit in a single machine.
It's not when, it's if, and often you know it won't happen. Being a good engineer requires understanding when k use which model. acting as if there aren't a lot of cases where singel process, shred memory, concurrency is the only good choice for almost all cases is wrong
So to avoid these ends, let's avoid these beginnings: avoid multi-threading. Use single-threaded programs, which are easier to design, write, and debug than their shared-memory counterparts. Instead, use multiple processes to extract concurrency from the hardware. Choose a communication medium that works just as well on a single machine as it does between machines, and make sure the individual processes comprising the system are blind to the difference. This way, deployment becomes flexible and scaling becomes simpler. Because communication between processes by necessity has to be explicitly designed and specified, modularity almost happens by itself.