The Right Abstraction Level
EvergreenI will spend disproportionate time on the data model because a good data model saves everyone grief for years. A bad abstraction, once shipped, becomes load-bearing.
The compounding effect
A well-chosen abstraction compounds:
- New features become easy because they fit the model
- Bug reports become rare because the model prevents invalid states
- Onboarding becomes fast because the model is intuitive
- Migrations become straightforward because the boundaries are clean
A poorly-chosen abstraction does the opposite. Every new feature requires a hack. Every hack makes the next feature harder.
How to find the right level
I ask three questions:
- What changes together? Group those things. That is your module boundary.
- What changes independently? Separate those things. That is your interface boundary.
- What do the consumers actually need? Expose only that. Everything else is implementation detail.
The third question is the most important and the most frequently ignored.
The adapter pattern at Mensari
At Mensari, we needed to support eight blockchain networks. Each has completely different RPCs, data formats, confirmation models, and error handling. The right abstraction was a chain-agnostic adapter: every chain implements the same interface, and the rest of the system never knows which chain it is talking to.
Adding a new chain went from weeks to days. Not because the implementation was clever, but because the abstraction was right.
When abstraction is premature
Three similar lines of code is better than a premature abstraction. Do not abstract until you have at least three concrete examples of the pattern. Two examples might be a coincidence. Three is a pattern.