Model Self-Consistent Concepts

Don’t implement creation without deletion. Don’t make your getters
return a different type from that accepted by your setters. Don’t
expose methods at different abstraction levels on the same type.

I’m not quite sure what the common thread of those mistakes is, but I
think it often flows from a failure to reset perspective. You’re
implementing a user-facing feature, and you write an apiserver facade
with a CreateFoo method, and you want to register and expose it to
finish your card so you just implement the minimum necessary in state to
satisfy today’s requirements and you move on, unheeding of the technical
debt you have lumbered the codebase with.

Where did you go wrong? By registering your apiserver code, and thus
creating a hard requirement for an implementation, which you then
half-assed to get it to land. You should have taken it, reviewed it,
landed it; and realigned your brain to working in the state layer,
before starting a fresh branch with (1) background knowledge of an
interface you’ll want to conform to but (2) your mental focus on asking
“how does the persistence model need to change in order to accommodate
this new requirement and remain consistent”.

And you should probably land that alone too; and only register the
apiserver facade in a separate branch, at which point you can do any
final spit and polish necessary to align interface and implementation.

(If you’re changing a facade that’s already registered, you can’t do
that; but if you’re changing a facade that’s already registered you are
Doing It Wrong because you are knowingly breaking compatibility. Even
just adding to a facade should be considered an api version change,
because clients have a right to be able to know if a method is there
– or a parameter will be handled, or a result field will be set – just
by looking at the version. Forcing them to guess is deeply deeply
unhelpful.)