Featured image of post I graded every package for how badly it wants to leave

I graded every package for how badly it wants to leave

Twenty-seven packages, four marks each, out of ten. The interesting column wasn't the one I expected, and one row explained the whole programme.

I sat down one weekend and gave twenty-seven packages a mark out of ten, four times each. A hundred and eight numbers, in one table, about my own code (which is either diligence or a cry for help, I haven’t decided).

Not the reason you’d assume

The second paragraph of that report is a disclaimer, and I put it there on purpose because I could see where this was heading:

The goal is not to break GTB apart. The goal is to identify components with clear reuse value outside the framework, then describe the broad decoupling work required to extract them without hollowing out GTB’s integrated experience.

go-tool-base is an all-in-one framework and I still want it to be one. Type gtb generate project and you should get a thing where the logging, the config, the transport and the CLI already know about each other. That integration is the product.

But I’d started wanting pieces of it elsewhere, and signing had already left the building. So the question was less “how do I dismantle this” and more “which of these has a life outside, and what would it cost to give it one”. You can answer that by instinct, of course. I’ve watched people do it, I’ve done it myself, and what you get is whatever happened to be most annoying that week.

Four columns, and just the one surprise

So it got scored. All twenty-seven, out of ten, on four axes:

  • Extraction. The overall recommendation. Should this be its own module at all?
  • Package value. What’s it worth to someone who wants it without the framework?
  • Code quality. Cohesion, testability, API shape, how grown-up it is today.
  • Ease of decoupling. How much framework-specific coupling has to come out first.

The first three are the ones you’d expect, and they mostly agree with each other. Good code tends to be worth having, and things worth having tend to have been looked after. The fourth column is the one that earns its keep, because it’s measuring something else: not should this leave but can this leave yet. Those are different questions and the table is only useful because it keeps them apart.

Four rows from the table

PackageExtractionValueQualityEase
chat91074
redact99810
regexutil88910
telemetry6764

chat is the highest-value package in the framework. A Go library that talks to several AI providers with one interface is exactly the thing people want without a CLI framework attached. Ten out of ten, no argument.

It also scored four for ease, the joint-worst in the table. Because at that point chat reached into props, the GTB HTTP helpers, the config and credentials abstractions, and the logger. Each of those was a small sensible line on its own, and together they had the package thoroughly bolted to the floor. So the most valuable thing I owned was the hardest to shift! Meanwhile redact and regexutil, both tens for ease, would have taken a morning apiece and delivered a fraction of the value.

So value and ease aren’t correlated, which is obvious once it’s written down, and invisible until you score them separately, because instinct blends the two into one vague feeling that we should probably do something about chat. That feeling can’t tell you whether to do it first or last.

What the numbers were actually for

Sequencing, as it turned out, more than judgement. Once the two questions are separated, the running order writes itself, and the report ends with six steps:

  1. Low-coupling leaf utilities. redact, regexutil, browser, workspace.
  2. User-facing CLI helpers. output, forms, logger, changelog.
  3. Security and runtime foundations. credentials, authn, tls.
  4. controls, then http and grpc onto it as optional transport adapters.
  5. vcs/release and the provider adapters.
  6. chat, last, once there were local interfaces to replace the GTB bits it was clinging to.

Easy things first, not because they matter most but because each one takes a bit of coupling out of the framework and makes the next one cheaper.

By the time you reach chat, half of what made it a four has already been dismantled by the work in front of it. The other thing the scores bought was permission to stop. Anything at five or below was excluded from consideration entirely, which sounds like a small administrative decision and isn’t. Without it, a scoring exercise turns into a to-do list with twenty-seven items on it and no way to argue against any of them.

What it didn’t tell me

The table is a good instrument, and it was wrong about several things in the direction I’d least expected: the easy ones. logger scored ten for ease. forms scored ten for ease. Both sat in step two, both looked like a morning’s work each, and neither of them is a module today. One was deleted outright and the other is still sat in the framework where it started.

Being wrong about chat would have been ordinary. Being wrong about the packages I’d already marked as trivial is the interesting failure, and a hundred and eight numbers later the column I’d been most confident about was the one that lied to me.

Built with Hugo · Theme Stack designed by Jimmy