Refactor the Predicate's Axes

Heart

A predicate that looks atomic is often carrying two axes — or three — under one name. When a reader has to ask which axis are you asserting? of a predicate's values, factor the axes out: name each one, give each its own predicate, migrate existing assertions to the appropriate axis. Do it while the corpus is small enough that migration is a session's work. Every day the overloaded predicate stays in use, more assertions will need to move, and more contributors will habituate to the conflated form.

Problem

Predicates are the query handles of a graph: each one is a question a reader can ask of any node. When a single predicate quietly smuggles two or more independently-moving questions, every assertion it carries becomes ambiguous. A reader filtering on has_status::[[Seed Stage]] cannot tell whether the match is about lifecycle maturity, curation state, review cycle, or something else the predicate has accumulated. Inferences diverge across readers. Queries soften. The graph degrades continuously — not catastrophically on any single day, but cumulatively as the corpus grows and as later contributors pattern-match on the overloaded form.

The difficulty is recognition, not mechanics. Once the second axis is seen, splitting the predicate is mechanical. The craft this Pattern teaches is noticing that the predicate is carrying an axis its name does not declare.

Forces

Solution

When reviewing a predicate's use — during authoring, during review, or during convention audit — ask: can two assertions of this predicate with the same value mean different things? If yes, the predicate is carrying more than one axis.

For each axis the predicate carries, name it (lifecycle, curation, review, visibility, whatever the axis is about). Create a named predicate per axis (has_lifecycle::, has_curation::, and so on). Migrate existing assertions to the appropriate axis — each old assertion becomes one or more new assertions across the family. Retire the overloaded predicate: add it to the "deliberately not used" section of the conventions document with a pointer to the replacement family.

The number of axes the refactor produces is not capped at two. A predicate may factor into three, four, or more. A status predicate that mixed lifecycle with curation, for example, factors into two predicates — has_lifecycle:: and has_curation:: — with room for later axes (has_review::, has_visibility::) as distinctions emerge. Each refactor is incremental: factor what is visible now, leave room for later axes that have not yet become clear.

Do this early. While the corpus has tens of assertions, migration is an afternoon. While the corpus has hundreds, migration is a project. While the corpus has thousands, migration is a rewrite.

Consequences

Instances

Also Known As

Relations