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

Numbers Have One Home, Words Have Another

~12 min · separation, boundaries, refactor, ownership

Level 0Raw Ore
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"This module owns the MODEL. The frontend keeps the PROSE."

The split, drawn precisely

Moving a computation out of a frontend raises an immediate question: how much goes with it? The lazy answer is everything, and it produces an engine that returns pre-formatted display strings and a frontend that is a dumb pipe. That is a real architecture and it is usually the wrong one, because it puts editorial decisions behind a deploy.

The split here is stated in one line, and it is worth adopting verbatim.

The engine owns the model: which series feed each indicator, which direction each one reads, what weight each category carries, what reference scale applies before a series has earned a percentile. Everything that is arithmetic or is an input to arithmetic.

The frontend keeps the prose: each card's context paragraph, its historical anchors, its labels. Everything that is writing.

Why this line and not another

Because the two halves have completely different change profiles, and different people change them.

Model changes are consequential and must be auditable. Adding an indicator, reweighting a category, altering a reference range — each of those changes the number, and someone will eventually need to explain why the figure moved on a day when the market did not. That demands version control, review, a stored trace, and a source string.

Prose changes are frequent and cheap. Rewording a paragraph, adding a historical anchor, clarifying a label — none of them change any number, and treating them with the same ceremony as a model change means either the ceremony gets skipped or the prose never improves.

Split by change profile, not by layer. "Backend versus frontend" is a deployment fact, not a design principle. The useful question is which things change together, how often, with what consequences, and who reviews them. Arithmetic and editorial belong on opposite sides of that line even when they render two inches apart on the same card.

What crosses the boundary

The engine's response carries everything the prose needs to be written about: the composite, the regime phrase, per-indicator scores with the path each took, the as-of date, the oldest input, the narrowest window, the list of reference-scored members, and the formula as a string.

That last one looks like the elegant part, and it is worth being exact about how far it actually goes. Shipping a formula string beside the number means the frontend could explain the model without knowing the weights. But the string is assembled by hand in the same module and hard-codes 40 / 30 / 30 separately from the CATEGORIES list that the arithmetic actually reads. So it is a copy after all — a very short-range one, two hundred lines from its original, but a copy.

And the copies have already drifted, which makes this the live example rather than the cautionary tale. Count them honestly. The weights exist in three places: the CATEGORIES list the arithmetic reads, the hand-built formula string beside the number, and — in the very sentence form the next callout offers as the mistake nobody made — the dashboard's own methodology footer, spelling out "Valuation 40% · Risk pricing 30% · Liquidity 30%" in prose. Two of the three are copies, and the page has drifted in two further ways beside them: it says "Weighted mean of 7 indicators" in two separate places while the engine scores eight, and its footer still describes the long-window gauge as something that will join the model later, when it has been a scoring member for a while.

Note what the same screen gets right, because it is the whole argument in one contrast: the per-category weights rendered beside that footer come from the payload, and they cannot drift. Same page, same numbers, two techniques — and every wrong statement on it is on the hard-coded side.

The anti-pattern is the duplicated constant. The tempting shortcut is to hard-code the weights in the frontend text: "valuation is weighted 40%". It reads fine and it is a second copy of a number that lives in the engine. The two will diverge, the prose will be the one that is wrong, and nothing will fail — the page will simply describe a model the product no longer uses.

Code

The boundary, stated in the module's own opening·python
"""The composite assay -- the scoring model, moved out of the browser.

It lived in `App.tsx` and was recomputed on every page load, which
had two consequences worth naming. It could not be READ by anything
else -- not the CLI, not a delegation brief, not the sidekick -- and
it left no trace, so the one question a position report invites
("where has this needle been?") had no answer at all.

The split is deliberate: this module owns the MODEL (which series,
which direction, which weight, which reference scale), the frontend
keeps the PROSE (each card's context paragraph, its historical
anchors, its labels). Numbers have one home; words have another.

Descriptive, always. A composite is a characterization of where the
needle sits in published history -- never a forecast, never a call.
The formula ships beside the number for exactly that reason.
"""

# And the formula really does ship, as data -- it is returned in
# the assay payload under the key "formula", beside the number:
FORMULA = ("category = mean(member scores); composite ="
           " sum(category x weight) x 10 -- valuation 40 /"
           " risk pricing 30 / liquidity 30")

External links

Exercise

Take one screen in a product you work on and label every element as model or prose — arithmetic and its inputs versus writing. Then check where each one lives. The interesting cases are the mixed ones: a sentence containing a hard-coded number that is computed elsewhere. Each of those is a copy waiting to diverge, and the copy in the prose is the one that will be wrong.
Hint
Grep the frontend for digits inside display strings. Percentages, thresholds, weights and counts embedded in sentences are almost always duplicated constants — and unlike a duplicated constant in code, nothing will ever fail a test when they drift apart.

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.