If you like global variables, you're going to love databases!
Programmers regard Encapsulation as a universal good.
And yet we have databases: warehouses of shared mutable state.
┌───────────────────────────┐ ┌─────────────────────────┐
│ │ │ │
│ Microservice A │◄─────►│ │
│ │ │ │
└───────────────────────────┘ │ │
│ │
┌───────────────────────────┐ │ │
│ │ │ │
│ Microservice B │◄─────►│ Database │
│ │ │ │
└───────────────────────────┘ │ │
│ │
┌───────────────────────────┐ │ │
│ │ │ │
│ Operator Tooling │◄─────►│ │
│ │ │ │
└───────────────────────────┘ └─────────────────────────┘
Designs like this are essentially the ugliest possible abuse of global state. If you wrote normal code in the same style you would be laughed out of the building:
database = ...
def microservice_a():
global database
...
def microservice_b():
global database
...
def operator_tooling():
global database
...
At the same time, the kind of architecture pictured above does work, even if the end result can be hard to understand. So today I want to explore some options for architecting your code to implement the physical architecture pictured above with minimal pain and maximum clarity.
┌─────────────────────────────────┐ ┌─────────────────────────┐
│ │ │ │ │
│ Microservice A │ lib │◄─────►│ │
│ │ │ │ │
└─────────────────────────────────┘ │ │
│ │
┌─────────────────────────────────┐ │ │
│ │ │ │ │
│ Microservice B │ lib │◄─────►│ Database │
│ │ │ │ │
└─────────────────────────────────┘ │ │
│ │
┌─────────────────────────────────┐ │ │
│ │ │ │ │
│ Operator Tooling │ lib │◄─────►│ │
│ │ │ │ │
└─────────────────────────────────┘ └─────────────────────────┘