Modeling Concretions into Generalities
In this topic, I will be describing somewhat philosophical in software architecting field. You might fall under false impression that I dislike software frameworks, but in reality I just like correctly built domain models. I can't stand incorrect software models, and if you know me, you know that I really mean it.
Before we go on, please have in mind that this topic applies to enterprise software development world.
Let's Solve Everybody's Problems
All starts from a very simple and innocent intention of software developers and architects: "let's solve everybody's problems". When I smell this intention, I become strict and start saying many "no"-s. I like people who want to solve the whole world's problems, but I don't like software that they create as a result.
When you start solving everybody's problems, you start creating many abstract classes, many interfaces, and many super-types for each family of classes. You try to find out how things work in general, not concretely in your problem domain. When you hear requirements, you try to ignore them and write a "smarter" solution that crosses boundaries of your domain. Right, why not create a model for medicine that also can be used in financial institutions?
Here's why: I guarantee you, financial institutions want something more or something less, but not what you think they want. Otherwise, there would already be a very famous software invention fitting all domains at the same time. I know the answer - there is such thing, and that's called database. But you are not writing a new database engine, are you?
I discourage you from using the generality-based approach that I described above. Instead, I encourage you to start from designing concrete classes and components, by limiting yourself to the domain's boundaries. Resort to generalities only for reasonable inheritance or interface segregations, that provide reusability and loose coupling. Forget about the whole world, - solve at least one problem rather well.
If you follow my recipe, you will end up writing software that is:
- Easy to understand - because everything follows domain-specific requirements.
- Easy to explain - because you don't have to go too far to explain the roots (generalities) of your classes and components.
- Easy to use - because the focus is on your architecture, but not on generalities that form yet another sort of architecture.
- Self explanatory - because it only does what it was asked to do, nothing more, nothing less.
Basically, you end up producing a software architecture the way I envision it to be.
Now, I am covering the dark side of the coin - what if you are too excited to solve the whole world's problems by falling in love with generalities.
You will definitely end up writing a framework. I would say, it's somewhat like a framework. To me, framework is an instrument that helps you solve the problem (first you have the problem, and then you find the instrument), rather than a tool that you want to use and thus are trying to solve the problem with that tool (first you have a tool which you find very attractive, and then you try to solve the problem because you already have this tool).
Your code is very flexible and exposes many functionalities that you deeply believe are very useful for the future requirements. However, you spent on it more time than you could. You increased the scope of the project, and scope of the knowledge curve that other developers need to consume. And about usefulness of your flexible code - I can bet that you cannot say exactly what will happen to you tomorrow, forget about usefulness of your code for your future requirements.
Every time a new developer joins your team, you will have to talk about things that are not related to your domain at all. Those things make you proud, but make many developers feel overwhelmed. Explaining thoughts to others becomes challenging if you have unrelated generalities, leave alone time spent on these explanations.
Generalities always look like boxes that have some sort of relation between each-other. If the generalities become complex, relations become complex too. This leaves generality-based model very close to relational database schema, because you have objects (tables) and relations between them (relational schema). Modern software models often tend to abstract database's relational nature from the entities, by introducing aggregates, aggregate roots and so on. Generalities bring us back to relational thinking, or wrong aggregate boundaries at best.
And finally, generalized frameworks make us concentrate more on them, instead of on our problem domains.
So, I encourage you to start from concretions when designing your domain models. Go to abstractions and generalities only when you know your problem domain very well, still limiting your thinking with domain's boundaries.
"We have met the enemy... and he is us" - Walt Kelly on Pogo papers.