Two Components Sharing One Database Are One Component With Two Names
The most common way a decomposition fails is not in the code, it is in the database left behind. When two components read and write the same tables, the table layout becomes an undocumented contract between them, one nobody agreed to and nobody can see. The consequences follow quickly. Neither side can change a column without checking the other, so schema changes need coordination and the two schedules become one schedule. Neither side can be released alone with confidence, so independent deployment is gone. Neither side owns the data, so the rules about what is valid live in two places and slowly diverge. And one heavy or slow query on either side becomes an outage on the other, so the failure domains are joined too. The repair is to give the data one owner and to give the other side a real contract: an operation it may call, a stream of changes it may follow, or a copy it may read with a stated staleness. The cost is honest and worth naming out loud, because a join that used to be free becomes a call or a copy. That price is the price of the boundary, and if it is not worth paying, the two parts probably belong in one component after all. You will be able to identify a shared-database coupling in a design, say which of those independences it destroys, and propose the ownership and contract that replaces it, naming the query that becomes expensive.
The Shared Database Anti-Pattern in Microservices Architecture
The shared database anti-pattern describes microservices designs in which multiple services access a single common database using local ACID transactions, violating the "database per service" pattern…