"Is-a" and "part-of" are concepts from object oriented analysis, where you try to model "the real world" in terms of classes and objects. That is, by looking at the problem you are trying to solve, you could come to the conclusion that a customer "is-a" person, and that a street name is "part-of" an address.
In the early days of object orientation, it was assumed that you could simply transfer the relationships you found in that analysis directly into your design for good results.
There are (at least) three reasons why this doesn't generally work well, in my experience:
- when we analyze the "real world", we typically model the problem space. When we design software, we model the solution space. Although there are often similarities between the two, there is no direct mapping - in fact, finding a good model for the solution is the most creative (and important) act in developing software. Assuming that an "is-a" relationship in the problem space will directly translate into inheritance in our solution space needlessly restricts our creativity, and thereby leads to inferior solutions.
- for me, the primary goal of software design is to manage dependencies in the design, so that the resulting system is maintainable and extensible (because successful software is software that will need to be changed). As a consequence, there are forces working on our designs that don't exist in the "real world", and therefore considering just "real world" relationships won't help managing those forces. Just take the famous "a circle is an ellipse" example: while true in mathematics, depending on what you need a system to do, reflecting this relationship in your design can violate Liskov's Substitution Principle, and thereby lead to brittleness and unnecessary complexity. That is, a relationship that is absolutely natural in the problem space leads to problems when transferred as-is into the solution space. Another example: both a customer and an administrator are persons, but that commonality could be totally irrelevant to the solution of your problem, and then modeling it in your design would be a waste, at best.
- in the English language, there is no unambiguous rule about when to use which phrase, anyway. Yes, you could say a customer "is-a" person. You could as well say that personal information is "part-of" a customer. Or that a person "has-a" role of being a customer. It can even make sense to say that "a person is a customer". So you really can't use natural language semantics to decide which relationship to use in your code.
So, using those relationship names doesn't really take the burden off your shoulder to choose wisely which relationship makes the most sense in your specific case. And an experienced designer will - whether explicitly or by gut feel - choose the relationship that leads to the most SOLID design. and he knows how to refactor to a different relationship when his understanding of the forces in the code changes.
Great thoughts. Especially the distinction between problem and solution space creates a valuable new perspective.
ReplyDeleteI have a small concern about your second point: I believe, that often the real world parts that change can be distinguished from those that are more stable. This aspect can help to find the right solution abstractions.