As developers, we like to code. We want to write code. It's what we do. So, naturally, when a project begins what we want to do is dive in and start writing code. From a proper planning perspective, this is generally frowned upon. And for good reason. When you're just starting to plan and haven't flushed out the details and don't have a firm grasp on the actual requirements (not just the documented requirements that some business user wrote down) is precisely when you shouldn't be etching into stone the logic to be used in the software.
But this reality can easily be (and often is) misconstrued as a mandate to not write any code just yet. This is a fallacy. Writing code isn't the problem. Writing code that's etched in stone is the problem. And overlooking the actual problem by mandating against what is essentially a means to the problem very easily leads to not solving the problem, but instead just moving it somewhere else. Somewhere sinister. The data model.
We've been writing software for years, and we generally know how it goes. Almost every developer still does this just out of habit. First you build your database and model out your tables, then you write your code to sit on top of that. Right? That's how everyone has always done it, so it must be the way.
Sadly, and at the cost of untold man-hours, it is not the way. But it's just such common practice that people continue to behave in this manner out of nothing more than habit. It's what they know, it's how they think, and it's a tried and true approach that management understands so it's the safe route. (Safe for the developer, not for the ongoing maintenance of the software.)
What is essentially happening here is that the early attempt at solidifying the requirements is being etched in stone in the database instead of in the code. And raise your hand if you think that re-factoring a database later in the life cycle of the software is significantly more difficult than re-factoring the code. That's what I thought.
It all comes back to my favorite of favorites... separation of concerns. You may be using proper IoC, you may be putting in hard assembly or even service boundaries between your layers. But you haven't flushed out all of those dependencies. The overall structure, in every direction, still depends on its core. And when you first begin designing the software you are essentially designing its core. The choice is yours... Should the core be the data model or should the core be the domain model?
Let's go with the common approach, the data model. You build your ER diagram, create your tables, map your keys, create your association tables for those pesky many-to-many relationships, etc. You now have a core database upon which your software will sit. Essentially, you now have this (pardon my crude diagrams):
Consider instead shifting your core a little bit. Imagine for a moment breaking that cardinal rule that "thou shalt not code first" and actually begin the design by creating your domain models. In code. What about the database? You can figure that out later. Or, at least in my case, hopefully a trained data modeler can help you figure it out later. (Developers like to think we're also data modelers, but most of us just aren't. A lot of that comes from the fundamental differences in design and function between object-oriented thinking in code and relational thinking in an RDBMS.) Now, you have this:
Many times this boils down to a cultural problem, really. Businesses have spent decades with the understanding that "the data is paramount." While there is generally truth to this statement, it should not be extended to believe that everything about the database is the core of your system and all that matters. After all, the engine which drives that data plays a fairly critical role in your business. Unless you're dealing with simple forms-over-data applications and simple rails-style interfaces, you would probably do well to consider the importance of all that business logic.
A common analogy in the English language is "putting the cart before the horse." And you know how developers love analogies... The cart is your data. It's the payload that's being transported. The horse is your engine. It drives the data to and fro. In the age-old struggle between cart-makers and horse-breeders there is a debate over which is the more important part of the system. Without the horse, the cart doesn't move. Without the cart, the horse has nothing to do. Both are valid points to be sure, but when designing the system which natural construct ends up being the core? No matter how well you abstract your horse-to-cart interface, there's still a natural architectural dependency in the system. And it's a hell of a lot easier to build a cart that fits your horse than to breed a horse that fits your cart.