Skip to content
C.W.K.
Stream
Lesson 01 of 04 · published

Same Shape, Same Day

~12 min · duplication, origin, measurement, architecture

Level 0Loose Parts
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

The Fastest Way to Start an App Is to Copy One

A family of small applications had a parent: a travel app with a shape worth reusing — local-first capture, a queue that survives being offline, an assistant panel bound to a real conversation, a publish path to a shared stream. Two new siblings were wanted the same week: a journal built on an open timeline, and a health log that observes and never diagnoses. Both were seeded from the parent's shape, by two different hands, on the same afternoon.

This is not a story about carelessness. Seeding from a working sibling is the correct move, and it is what the family still does today. The interesting part is what the copies did over the next few hours, entirely without anybody deciding anything.

The Inventory, Taken Hours Later

By evening the three repositories held this, and it is worth reading as a list rather than as a summary, because the shapes are all different:

  • A byte-identical client layer for talking to the assistant — streaming, conversation binding, turn projection — three times over. Pure copy, no drift yet.
  • The same image-fitting step ported twice, differently: one implementation reached for a Python imaging library, the other shelled out to a system tool. Same intent, two behaviors, and nobody had compared them.
  • Three implementations of the same publish sequence, each writing a different record schema for what is conceptually one event: this crumb was published, here is where it landed.
  • Three settings stores for the same device-local preferences, already using three different field names for the same field.

Four distinct failure shapes, and only the first one is what people usually picture when they say "duplicated code". The second is a fork wearing a copy's clothes. The third is three incompatible histories of the same act. The fourth is a vocabulary split, which is the one that will bite in the next lesson.

Copies do not drift slowly. The mental model of duplication as a debt that accrues over months is wrong at the moment of highest risk. Divergence happens while the copies are being written, because two people solving the same problem in two files will make two reasonable choices. By the time anybody thinks to compare them, they were never identical to begin with.

Why an Inventory and Not an Argument

Everyone involved already agreed that duplication is bad. That agreement produced exactly zero shared code, because it is abstract, and every individual copy is concrete. The thing that actually moved the decision was a list: four named layers, with what each one had already done, written out where two people could look at the same text.

This is a general property of the problem. "We have too much duplication" is unactionable — it names no boundary, so it cannot be scoped, staffed, or finished. "These four layers are triplicated, and here is what each copy did differently" is a work order. The first sentence has been true in most codebases for years. The second one has an end.

Code

The cheapest version of the inventory·bash
# Not sophisticated, and that is the point: the goal is a LIST,
# not a similarity score. Run it before you argue about duplication.

# 1. Which module basenames exist in more than one sibling?
#    Same name in three repos is the loudest possible signal.
for repo in app-a app-b app-c; do
  ( cd "$repo/backend" && ls *.py )
done | sort | uniq -c | sort -rn | awk '$1 > 1'

# 2. For each repeated name, are the copies identical or already forked?
#    A differing hash this early means it was never one file.
for f in pippa.py veil.py ulid.py settings.py; do
  echo "== $f"
  for repo in app-a app-b app-c; do
    [ -f "$repo/backend/$f" ] && \
      printf '  %-8s %s\n' "$repo" "$(shasum -a 256 "$repo/backend/$f" | cut -c1-12)"
  done
done

# 3. The vocabulary check that finds the bug in the next lesson.
#    Same concept, different spelling, across repos:
grep -rho "brain['\"]*: *['\"][a-z]*" app-*/backend | sort -u

External links

Exercise

Pick two projects of yours that were seeded from each other, or from a shared template. Produce the four-column inventory: module name, present in which repos, identical or forked, and one sentence on what each copy does differently. Do not propose a fix yet — the exercise is finished when you have the list, because the list is what a fix would have to be scoped against.
Hint
Sort by the fork column, not by size. An identical copy is a scheduling problem; a copy that has already diverged is a decision problem, because somebody has to say which behavior is correct, and that person may not exist yet.

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.