Is this another ad for big design upfront, aka waterfall? It is a nice ideal, but when you get down into it, software really is evolved since requirements are constantly changing and your understanding becomes better.
> You get to build a bat by strapping wings onto a rat, and you know how to build wings because you already did it for birds.
Really you don't. The bat flies quite differently from the bird, with substantially different attributes. Strapping bird wings onto a rat often isn't going to work.
> This issue comes up enough in gaming that the no-hierarchy-lots-of-mixins approach has a name: the entity-component model.
This is actually much older than that (Common Lisp Flavors), and languages like Scala include mixin-like traits, not to mention the work of Bracha and Cook. Inheritance is still heavily involved in that though, it is not "mixins or inheritance" but "inheritance with mixins," it still very much is OOP, and you are still defining a DAG if not tree.
> Finally, how far would we really be willing to take biology's classification-by-implementation philosophy, even if classifying pieces of code were really our goal? We could end up with superclasses like UsesAStar and HashSet. Not really the point of all of this, right?
Why not? Why not classify all of our code at the finest grain we can? Of course, existing languages are poorly suited to that task, but we can always define new languages where this isn't a PITA. Or we could just use machine learning to figure out what the connections are automatically (this will happen eventually, just not for another 10 or 20 years I hope).