But to begin with, we're not classifying things; we're building them. Software is designed; you don't (or at least shouldn't), construct your programming abstractions by progressively mutating the different parts of your code. Nature had to reimplement flying for the bat, but you don't have to! 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. But the hierarchy system doesn't let you do that; you'll have to do what nature did and completely reimplement flying for the Rodent subclass of Mammal, since Bird is nowhere near it in your hierarchy diagram. That's the essence of the author's point, as I read it.
I suspect Raganwald would probably go a lot further than an OOP+mixin approach (and there is no shortage of good alternatives), but the simplest way around this kind of thing is something like this piece of Ruby:
class Bat
include Flying
include Rodent
include Echolocation
end
You get the idea, and it's pretty easy to port to JS. It also lets you build the griffin and the centaur, because the software doesn't have to follow nature's rules about how to derive one thing for another. Constraining your code's structure to evolution's is-a model is a straight jacket.So that's implementation, but what about interface? We actually do care about outward behavior, and making our interfaces reflect that is important. Morphological classification may not tell you much about how a bat works inside and what other species a bat is evolutionarily close to, but it remains the case that if you want to know what a bat does, flying is a big part of that. What if I want to know whether a given animal can get over my fence? How do I ask if a creature can fly? I don't care at all that bats are closely related to mice because they're acting nothing like mice when zooming over my fence. Do I really add canFly() to some Animal superclass and have flying creatures override it? How many features will I detect that way? But with our mixins, we can just ask if it includes Flying, because the structure of our code captures that. Codifying the structure of your interface into the structure of your classes is part of the point of OOP, but it turns out that interfaces don't fit a simple inheritance mold. So you need more powerful tools to describe that structure.
This issue comes up enough in gaming that the no-hierarchy-lots-of-mixins approach has a name: the entity-component model. I bring this up not because I think the point applies differently to games but because it's a domain where you might actually build a bat.
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?
Long story short: I agree with the article and think the biology doesn't contradict it, but think we should probably stop using evolution as a conceptual model for how we organize our code.