loading...

Coding = thinking in several dimensions

andreasklinger profile image Andreas Klinger ✌️️ ・2 min read

"This change should be easy"

"We could a clone on a hackathon"

"We have no time for refactoring"

"We kind of forgot how to ship stuff fast"

Managing codebases = Thinking in and managing of several dimensions:

  • the file / component (what a it does)
  • the system interconnection (how stuff fits together)
  • the product usecases (how users actually use it / domain logic)
  • the changes over time (legacy / pivots etc)

Note: technically there can be more (infinite) dimensions but i usually stick to those 4 as mental framework)

As your app grows you scale on all of those 4 axes.

Your individual components become more complex.
Your components interlink more (eg to DRY your code).
Your product usecases become wider to a bigger range of diverse customers.

And most important: You make changes over time.

Often radical changes: Pivots. Either in domain logic or technical approach.

Very quickly your codebase becomes complex and hard to manage.

Thinking of your codebase as a 4d cube

For some people it's hard to imagine 4d objects (gee… i wonder why…)

For the sake of this argument it might be easier to visualize a radar chart.

Example used: Wine (dont judge)

While you add to your code you move on those axes and increase the area and thus make the overall area under management bigger.

If you pay attention the shape of your 4d cube stays smooth and the volume small.
But if you "ain't got the time" your cube will have hacks and weird surface areas which, by itself, will create new problems in future.

Managing a codebase means managing how far you move on those axes.

Judging codebases

You can usually walk through a codebase with the same mental model

  • how well are components structured?
  • how well are systems isolated and boundries defined?
  • how well are the product usecases defined and isolated/expressed in code?
  • how well are changes over time managed? (acknowledged tech debt, isolation, comments, etc)

"This change should have been easy…"

If you are working on a fresh codebase you have no pre-existing surface area to manage. No needless moves on directions you currently don't care about. You can pretty much go straight to the point you want to get to.

Already established codebases are different.

A change in a component might not be easy if you have to move on the "time" axis by fixing other parts of the system. Aka "refactor this legacy first".

A change in a product usecase won't be easy if your system has a lot of interconnections with badly defined boundries.

A fix in legacy systems might not be easy if systems are highly interconnected / tightly coupled.

"…but it wasn't easy"

The next time you feel bad about how long a change needed think about how much space you moved on each of those axes to get anything done.

Also appreciate how much complexity on all of those axes you improved when you touched those parts of your codebase. And be sure that also the next person will appreciate it.

Discussion

pic
Editor guide
 

This sums it all up pretty damn well. Beekey Cheung writes some thoughtful articles along these lines.

One thought of mine: While complexity grows over time (and we are on a constant fight between value delivered and complexity, always trying to keep our heads above water), there also come moments of solidification: Where, after a bunch of small pivots, our mental model becomes pretty clear, and we can move in and prune a lot of the bad ideas from the code because we've settled on the direction.

That's the stage when we want to fight the urge to hoard failed ideas as dead code we "might" make use of. Consistently looking for opportunities to delete code associated with pivots is probably the best way to manage this stuff over time.

 

+100, I read something aligned to this recently and I'll badly paraphrase it here apologies to the author, "deleted code is debugged code", resisting the urge to hoard is one thing but actively pruning dead code is another

 

Regarding each bit of added code and complexity.

Ian Malcolm

each custom line of code is managed by you - maybe badly - but managed

there is hardly ever a downside to removing code
you can usually look in git to see how it was done and cherrypick the good parts if needed

 

Love the smooth vs weird surface area cube analogy. It's like putting Band-Aids on when something actually needs an overhaul instead.

Also, as someone currently learning a new codebase, I find myself spending a lot more time reading the code and figuring out it's structure. This allows me to make sure I'm not writing in code that may be short in the "component" axis, but will increase the "time" axis. Personally, I find managing the "time" axis pays off more later on, but those are decisions to be thought over as the app grows.

 

Andreas, great post, and thank you for sharing! I loved the "Radar Chart" as a mental model for imagining the multi-dimensional concerns of a code-base. Also adds visual context when developers talk about the "surface area" they need to manage.

 

Thx for the article!
It would be so nice to be able to measure some of these values for a "codebase".

I just realized that working with a monorepo means you might have multiple codebases in one repo that might need to be looked at separatly.

 

Kind of reminds me of something.

Kind of reminds me of something