The Pragmatic Architect writes about The Neverending Abstraction. My knee-jerk reaction is that abstraction is perfectly valid when contained within the domain of the problem but, doesn't need to be expanded to deal with every possible case outside of that domain. In other words, don't over-engineer the solution.
Then I started thinking about the possible root-cause of this common behavior. Perhaps it's not the layers of abstraction that are the problem but, instead it's the depth of the taxonomy. What happens when a Vendor becomes a Customer? What happens when a key person at one customer, who has a deep history with your company, changes jobs? As much as we hate to admit it, very few of us practice true OO because we have had deep taxonomies and Nth normal form drilled into us since elementary school (kingdom, phylum, genus, species, etc.). The result of this is that we cast the majority of our objects solely as data containers, not interactive (behavior-based) information sources. This has two side-effects. The first steers us towards designing class hierarchies based on attributes, not behavior. The second is that our objects are too big. Let's look at the Customer object in The Neverending Abstraction.
This is a situation many of us have encountered, where the object is a Customer and it contains a field called name. Let's think about this a bit. How many different ways are you asked about information concerning your name? How many different ways do you ask your customers about information concerning their name?
- first name
- last name
- middle initial(s)
- middle name(s)
- christian name(s)
- full name
- first four letters of your surname
That's at least 14 methods, not including possible formats (last name first, etc.). Doesn't that constitute it's own object? When a Name needs to be applied to a company, it's easy to add common name, legal name, d.b.a, etc. Now, on to the Customer object. You are a customer of many companies or, are you? We tend to define ourselves by what we do. However, we do many things. Does that imply we have a clone for each major task we do? Of course not, we are a Person object that happens to be performing a specific Role. That should guide our thinking about OO abstractions.
The second possible root-cause is computer science education. Even when introductory courses are taught with an OO language, the first thing that we learn (in the case of Java) are the primitives and the second are control structures. We still haven't shed a half-century of procedural baggage. I can sum this up with one, very simple (American-centric) example. Hands up, how many people have used (in Java) an int for a zipcode? How would you address a package destined for Portland, Maine?
Try abstracting behavior, first. Then, worry about the attributes. Isn't the mantra, "Program to interfaces?"