Good design is hard. There are arguments to be made for both, but the problem with "Old, Good Database Design" is when the design changes it either devolves into
1. Downtime trying to move X billion rows
2. Some ad-hoc K/V store on top of your RDBMS
And most companies tend to opt for (2) rather than (1). It's no surprise that some systems just decide to choose (2) from the onset.
Problem is that any changes to the databases need to be done on a single point of failure for your application. Any change that goes sideways, you risk downtime.
Counter this with code, where I can deploy code along side my existing code and make sure it functions as I want it. If something fails, I just remove that instance from the LB. You don't want to touch something that valuable during regular feature cycles. Databases should be altered rarely and with much apprehension and a well established backup/rollback plan.
I'm not saying you can't use constraints and stuff, but they should be really really static concepts that aren't subject to change. Unlike code, you can't share validation conditions across tables, so where you could update all the validation logic in a service with a change in one place, you have to update many tables in the database.
I would stay away from triggers entirely, and use a queue/stream system to process data async. This can be better prioritized when the DB is under heavy load.
"Draw the rest of the fucking owl"
Good design is hard. There are arguments to be made for both, but the problem with "Old, Good Database Design" is when the design changes it either devolves into
1. Downtime trying to move X billion rows
2. Some ad-hoc K/V store on top of your RDBMS
And most companies tend to opt for (2) rather than (1). It's no surprise that some systems just decide to choose (2) from the onset.