I agree with most of this, but I don't understand why you'd treat FKs as business logic. IMO, it's clearly a part of the data structure. Like, say if you have a domain that looks like:
type User = {
username: string;
posts: Post[];
}
type Post = {
content: string;
}
(for the DDD-brained, assume User is an aggregate and Post is a value object here)
The natural way to represent this in the database is:
CREATE TABLE users (
username text PRIMARY KEY
);
CREATE TABLE posts (
author text NOT NULL REFERENCES users (username),
content text NOT NULL
);
I just don't see why you'd do it in any other way.
Hey dicytea, thanks for getting that blogging app up. Our users love it. Hey, I was talking to John, and he said he's got some guest columns he wants you to throw up there. Just some blog posts from thinkers he likes that he thinks would be a good fit for our site. Can you throw up some of those?
What do you mean they need to be users of the site? They're just some people whose posts we want to feature. No, they shouldn't need to log in. What are you talking about? What does that have to do with it?
</BossVoice>
Oops, turns out the rule "all blog post authors are users of the site" was actually just a volatile business rule after all.
Yes, and isn't it wonderful that you get an error message when you try to change a business rule, forcing you to properly encode the new rule instead?
A lot of these types of scenarios are missing the fact that, without these enforcements in the database, sooner or later a developer is going to make a change that violates an existing business rule without realising that they just broke a rule!
Rules change. We know this. What is valuable is being told that some new rule conflicts with an existing rule.
If you don't enforce the business rules in the database, how do you know when a new rule conflicts with some existing rule?
The natural way to represent this in the database is:
I just don't see why you'd do it in any other way.