I agree with the idea that the abstractions provided are "inevitable." I disagree with the idea that the way we're using them is optimal.<p>I've just spent time in my code reducing polymorphic classes into simpler type identifier + record combinations. The rationale I am going by is that every class I introduce proliferates new symbols: the class definition, the instances, the methods, the values, the references to yet further symbols. Each time I introduce new symbols I bulk up the code and diffuse its meaning; the meaning of these symbols exists in the class, not at the call site. Thus, everything in a class definition is doing its job correctly as long as you want the class to be a true "black box" that hides behind the symbols it provides.<p>But in many situations, the algorithm is basically "business logic" and conveys the most meaning when inlined at the call site: "Given this type of data, do this. Otherwise, do that." This type of algorithm assumes a schema onto the data, which is usually our true intention; having determined the schema, we can cease further indirection and begin our actual computation. And in this code, ADTs become less important, because we've already used those to query for the data; when we have the queries abstracted, we can stop. We don't need to abstract the meaning any further. Relational database modelling is analogous; when the data is normalized, it's very indirect, yet also very simple. And this pattern can be followed from within a program as well.<p>Consider the "composable component-entity" model that has become somewhat of a cargo cult fad. These systems generally understand the entity as a record of "which components are used/where to find them/how they fit together". The implication is that a definite schema of "types of components and their properties" exists at or near the top level, and entities do not hide arbitrary blobs of data and functionality in deep recesses, as results when trying to build from class inheritance. Since the concept is poorly defined, actual implementations are all over the place, of course, but the general direction of it is towards flat/primitive/normalized.<p>The result I got from killing off some classes and inlining their functionality was that I found some lurking unused variables, clarified the top-level, improved the code's flexibility, and reduced total lines of code. So at least in this instance I seem to be on the right track.