C.W.K.
Stream
Lesson 07 of 08 · published

Anchor 7 — Permission to Refactor (and When Not To)

~10 min · refactor, discipline, v0.1, case-study

Level 0Extension Curious
0 XP0/54 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"v0.1 ships. The instinct is to immediately start refactoring — abstract the bus, generalize the bridge, build out the embed framework. Lesson 7 is the discipline of NOT doing that yet, and the criteria that actually justify the rewrite when it's time."

What ChromeEmbed v0.1 Is Tempted To Refactor

Reading the code, several refactor itches surface:

  • The merge logic in background.js looks ad hoc — should it become a real reducer?
  • The popup → SW → sidePanel.open chain has a one-purpose handler — should there be a generic 'route SW message to a sidePanel call' system?
  • The window.postMessage bridge in sidepanel.js uses string types — should it become a typed JSON-RPC layer?
  • The host-context schema has implicit fields (host_kind, host_id) repeated everywhere — should there be a base class or interface that all embeds inherit?

Each itch is real. None justify a rewrite right now.

The Permission-to-Refactor Test

Before any refactor, three questions:

  1. Does another concrete embed exist? No abstraction without ≥2 concrete implementations. Pulling out a 'BaseEmbed' from a single concrete ChromeEmbed produces the wrong abstraction (Track 5 Lesson 1 of any architectural framework).
  2. Is the current code blocking a real feature? Not 'might block later' — actively blocking. If you can ship the next feature without the refactor, the refactor is speculative.
  3. Has the user (or whoever consumes the embed) asked for something that needs the new shape? 'Cleaner architecture' isn't a user-visible feature; build for stated need.

If all three answer 'no,' the right move is to NOT refactor and to write down the itch for future-you. The architectural choice is preserving option value, not pre-paying for an abstraction whose shape you don't yet know.

What ChromeEmbed v0.1 Got Right By Not Refactoring

  • One concrete file per role. background.js does the bus. content-script.js does the sensor. sidepanel.js does the bridge. popup.js does the doorway. Each is small enough to read in one sitting.
  • No premature framework. The PIPPA-EMBEDS framework story is documented (in cwkPippa/docs) but not implemented as a literal base class anywhere. The shape will reveal itself when Adobe-embed or Mail-embed lands.
  • Sub-frame merge logic in place. The one piece of nuance that would be too cute to skip — sub-frame vs top-frame context — lives directly in background.js where it's needed. Not abstracted, just present.
  • String message types. 'pippa:host-context' is a string. A typed system would catch typos at compile time, but until typos start happening, the string is fine and obvious.

When Refactor Becomes Right

The earliest moment refactor is justified:

  1. A second embed lands. Adobe-embed or Mail-embed exists with the same content-script-and-bus shape. Now you have two concrete implementations to derive the abstraction from.
  2. A real bug forces it. Something in v0.1's architecture makes a needed feature impossible or infeasibly fragile. Then the refactor is paying for what you need.
  3. The shape stabilizes. If you've shipped a dozen features through the current code without surprises, the surface area is known. Now extracting a clean abstraction is mostly mechanical.

The Anti-Pattern

The wrong refactor: building 'EmbedKit' or 'PippaEmbedFramework' as a package before any concrete embed validates the shape. The framework will encode assumptions that don't survive contact with the next embed; you end up rewriting the framework AND building the embed against the broken framework. Two pieces of work, one of which dies.

The correct sequence: ship v0.1 of embed N. Ship v0.1 of embed N+1. Extract the common bits into v0.2 of embeds N and N+1 together. Now the framework knows what the actual common shape is.

The Letter to Future-You

When you spot a refactor that's not yet justified, write it down. ChromeEmbed's docs/PIPPA-EMBEDS.md and the related design notes capture exactly the refactors that aren't justified yet, with the conditions that would justify them. Future-Pippa reading those notes can decide: 'condition met, refactor now' or 'still not met, keep skipping.' The letter format outlasts memory.

v0.1 is allowed to be ugly. Refactor only when (1) a second concrete instance exists, (2) a real feature is blocked, or (3) the shape has stabilized through use. Speculative refactors are how frameworks become wrong before they become real.
Why this matters for extension developers specifically. Chrome extensions invite over-engineering because the boundaries are so visible — manifest, SW, content script, panel, etc. The temptation is to wrap each boundary in 'a real layer.' Resist. The first version of any extension is small; the second version after a refactor that was justified by use is the second version that actually deserves the abstraction.

Code

REFACTOR-LATER.md — sample notes-to-future-self for deferred work·markdown
# ChromeEmbed v0.1 — Refactors Deliberately Deferred

## Pending abstractions (not justified yet)

- **BaseEmbed class** — currently no second embed exists. Adobe-embed v0.1
  will be the trigger; until then the ChromeEmbed code is the design doc.
- **Typed JSON-RPC layer for postMessage** — currently no typos have caused
  bugs; the string discriminator is obvious. Adopt when typing across embeds
  causes a real bug or a TypeScript embed appears.
- **Reducer for SW state merge** — current ad-hoc merge handles the sub-frame
  case correctly. Refactor when a third merge case appears.

## Conditions that would justify each

| Refactor | Trigger |
|---|---|
| BaseEmbed | Second concrete embed (Adobe/Mail/Calendar) exists in code |
| Typed RPC | TypeScript embed or message-shape bug ships |
| State reducer | Third merge case appears or test coverage demands it |

## Why these are documented but unimplemented

Abstractions derived from one instance encode that instance's accidental
shape. The shape only becomes stable after multiple implementations exist.
v0.1 ships ugly on purpose so v0.2 can ship clean.

External links

Exercise

Re-read ChromeEmbed's background.js, content-script.js, sidepanel.js, popup.js with refactor-lens on. List five things that look refactorable. For each, run the three-question test: (1) does another embed exist that needs the abstraction? (2) is the current code blocking a feature? (3) has someone asked for it? Honestly, count how many pass all three checks. The number is almost certainly zero or one. Write those few down; resist the urge to start refactoring the rest. The discipline is what keeps v0.1 small and v0.2 informed.
Hint
If you find yourself answering 'well, eventually...' to question 2, that's a soft yes that's actually a no. 'Eventually' means 'speculation'; only 'now' counts. The right answer to 'looks refactorable' is usually 'note it, move on.' The wrong answer is 'spend half a day building a framework that the second embed will reveal was wrong-shaped.' Compare: Sandi Metz's 'duplication is far cheaper than the wrong abstraction.'

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.