Thoughts
The Pizza analogy describes, really, the problems with over-modularization (of the sort that is particularly tempting in OOP, but which is
by no means specific to it. You can imagine the same complexities with composing functions in a functional language). Imagine you've been tasked to build a dynamic menu / billing system / ordering system of some sort for a pizza restaurant. You create a Pizza class, which describes a Pizza that the customer might order. It has a size, a price, a list of toppings, methods to ensure that all of the ingredients are in stock, etc. When listing out the menu of available Pizzas, you notice that a huge portion of the menu entries share configuration code describing common dough and cheese options. You, taking the opportunity to DRY your code, create a subclass of Pizza called CheesePizza. This allows you to share the cheese methods and declarations between a large number of your Pizzas. But you can go a step further. A lot of Pizzas have Pepperoni; surely that's a subclass as well. So you can subclass PepperoniPizza from CheesePizza and subclass BBQPizza from Pizza and MeatLoversPizza from PepperoniPizza and so on for every pizza on the menu.
A customer then comes in and orders a pepperoni pizza without cheese (as they are lactose intolerant). This isn't a hardcoded class, but your ordering system supports modifications; you can create a PepperoniPizza without cheese. But should you? PepperoniPizza subclasses CheesePizza—the defining feature of which is that it has cheese. Do the methods in CheesePizza work if the pizza doesn't have cheese? Or will they crash your system?
What's interesting to me about the problem at this point is that it is totally artificial. It's very clear what the customer wants, and it's not fundamentally difficult to represent in computer memory. If you hadn't done any of your refactoring, it would be very clear how to express this request: a Pizza with pepperoni as its only topping.
The solution is to not try to encode data in your type system or class structure or methods or functions or code. If you keep data about the pizza toppings at runtime (or as close to it as possible—you can still hard-code the menu), then your code becomes easier to maintain, despite the fact that it is less modular and uglier. You have every method in the one Pizza class and no method is able to make any assumptions about the underlying data.
This is semantic programming. Let your code reflect the semantic complexity of the real-world problem that it is trying to solve. Iterate the options explicitly as data instead of encoding them implicitly as code. A pizza can have any toppings in the real world—it should be able to have any toppings in your code.
It's important in modern minimalist software that you avoid this temptation to "simplify the equation" and that you avoid ending up with the most concise, modular, code possible. Many long-lived projects with attentive maintainers fall into this trap. They've been refactored so many times to support the current "menu" that when a customer walks in with a request for a "cheese-free pizza" (or analogous request that the maintainer didn't predict) there's no way to express it and the customer leaves disappointed.