Like any map, the inheritance pattern is bad, except when it works. It’s a strategic capability to be able to guess well which is which in given context.
My first foray into serious programming was by way of Django, which made a choice of representing content structure as classes in the codebase. It underwent the usual evolution of supporting inheritance, then mixins, etc. Today I’d probably have mixed feelings about conflating software architecture with subject domain so blatantly: of course it could never represent the fundamental truth. However, I also know that 1) fundamental truth is not losslessly representable anyway (the map cannot be the territory), 2) the only software that is perfectly isolated from imperfections of real world is software that is useless, and 3) Django was easy to understand, easy to build with, and effectively fit the purpose.
Any map (requirement, spec, abstraction, pattern) is both a blessing that allows software to be useful over longer time, and a curse that leads to its obsolescence. A good one is better at the former than the latter.
My first foray into serious programming was by way of Django, which made a choice of representing content structure as classes in the codebase. It underwent the usual evolution of supporting inheritance, then mixins, etc. Today I’d probably have mixed feelings about conflating software architecture with subject domain so blatantly: of course it could never represent the fundamental truth. However, I also know that 1) fundamental truth is not losslessly representable anyway (the map cannot be the territory), 2) the only software that is perfectly isolated from imperfections of real world is software that is useless, and 3) Django was easy to understand, easy to build with, and effectively fit the purpose.
Any map (requirement, spec, abstraction, pattern) is both a blessing that allows software to be useful over longer time, and a curse that leads to its obsolescence. A good one is better at the former than the latter.