hamsa software
← All articles
Engineering7 min read

What happens to the data when the flag goes off?

An off switch cannot restore a contract that new writes have already changed. Plan reader and writer compatibility across the transition.

A thick arch spans two rectangular supports with a thin horizontal tie beneath it, evoking the compatibility span needed while old and new data representations coexist.

The flag is off; the data is still new

The feature flag is off and the old screen has returned. The new records are less cooperative: they still use the representation the new editor wrote. If the old label printer cannot read that shape, the toggle has restored the code path without restoring the service. That is the rollback question I would want answered before the first successful write, while the team can still choose what to preserve.

A feature flag changes a decision in the running software. It does not automatically reverse a data migration, recall a message or restore a deleted field. The distinction matters most during changes that involve more than one deployed component. A web application, a background worker and an export script can live on different release schedules while sharing the same records.

Take a fictional contact system moving from a single address string to structured address fields. The new editor can capture a building, street, town and postcode separately. The old label-printing worker still reads address_text. Turning off the editor may restore the old screen, but it does not tell us what the printer will do with a record saved only in the new shape.

Write down which readers, writers and records the address system supports in each phase. The flag can admit traffic to one of those prepared combinations; it cannot make an untested combination compatible. For rollback, I would start with a new record and ask what the old printer does with it. That small example tells the operator more about the off position than the current Boolean in the flag dashboard.

Expand what the readers can understand

One approach is to expand the contract before changing the writers. Introduce the structured fields while retaining the existing representation. Update consumers to handle the intended transition rules. Only then allow the new editor to produce records whose treatment has been worked through. Danilo Sato’s description of parallel change calls the stages expand, migrate and contract.

For the address example, the transition reader could prefer a complete structured address when present and otherwise use address_text. “Complete” needs a real definition; not every address fits the same fields. A consumer must not print only the postcode because one newly added property happens to be non-empty. Preserve the original text when conversion is uncertain rather than manufacturing a plausible address from incomplete parts.

List readers beyond the obvious application. A monthly export, an administrative script and a rarely used reprint route can remain dormant during an otherwise convincing rollout. Give each a compatibility status and evidence of its behaviour. A clean production error graph from the new editor does not establish that next month’s export understands the changed record.

While both representations exist, every reader needs the same rule for choosing between them. Keep it near the data-access boundary if that makes it easier to inspect and later remove. Otherwise a populated field can win in one consumer and lose in another. The contact then produces a different label, export or reprint according to which reader happened to run, leaving the migration team investigating several answers to the same address.

Decide what a write means during the overlap

Writing both representations sounds like an easy solution, but it creates a consistency problem. If the structured fields and address_text are updated separately, a failure can leave them describing different addresses. Within one database transaction, a shared write can make a stronger local guarantee. Across independent systems, a repairable synchronisation process may be necessary instead.

There is also a semantic limit: structured-to-text rendering is usually easier than lossless text-to-structure conversion. An old editor can change the text in a way that the new fields no longer reflect. The application needs to invalidate, recompute or explicitly review the structured representation after that edit. Silently retaining both turns a transition convenience into two competing sources of truth.

Store conversion provenance where it matters. A structured address confirmed by a person is different evidence from fields guessed by an automated parser. If the old text changes, knowing that distinction helps decide whether to invalidate a conversion or request a new confirmation. Treating all populated fields as equally authoritative hides the most important migration uncertainty.

Decide which writers can run during each phase. Updating all editors to a compatibility release before structured capture may be simplest, but some deployments cannot move together. Then the system needs to recognise older writes and apply the agreed authority rule. Include the delayed worker: its text edit can arrive after another route has confirmed the structured address, and the application has to decide whether those fields remain valid rather than silently keeping both.

Record the relevant flag decision with a request or job. If one step captures an address under the old route and a later step reads a freshly changed flag, the job can straddle two assumptions. Sometimes reevaluation is intended. Sometimes a stable decision for the whole operation is safer. Make that scope explicit rather than assuming a Boolean has the same meaning everywhere.

An old text edit can invalidate new structured fields

The address migration’s write-side consistency problem, distinct from reader/record compatibility.

Scroll sideways to see all columns.

Write pathRiskRequired decision
Both representations, one database transactionPartial representation updateCommit the related write together
Independent systemsOne side may lag or failUse repairable synchronisation
Old editor changes address_textStructured fields may now describe old addressInvalidate, recompute or explicitly review
Retain whether structured values were human-confirmed or parsed; populated fields do not all have equal authority.

Rehearse the rollback that remains possible

A rollback review should start with a record created by the new editor. Can the old production reader use it? Can the old writer edit it without destroying information? What happens to a queued print job that already contains the new representation? These are more demanding questions than whether the flag service can return false.

For an illustrative release table, old records with old readers are the established case. Old records with transition readers need a fallback test. New records with transition readers need the new-path test. New records with old readers are the dangerous combination: either the release deliberately preserves a compatible text field, or the old reader is no longer an acceptable rollback target.

Once the old representation is removed, some old binaries stop being viable rollback targets. The team may still disable the feature or deploy a forward repair, but restoring the earlier service could require data restoration or a compatibility build. Say where that boundary lies in the plan. The operator should learn what off now means before an incident, including any restoration assumptions that need a rehearsal of their own.

Which reader can use which record?

An illustrative address migration from a text field to structured fields. Each supported cell needs a deliberate contract.

Scroll sideways to see all columns.

Stored recordOld readerTransition reader
Old text representationEstablished pathFallback must be tested
New structured representationOnly if compatible text retainedNew path must be tested
The transition reader supports old and new records. A new record with an old reader requires a maintained compatible representation or is outside the rollback promise.

Remove the flag when the compatibility work is finished

Pete Hodgson’s feature-toggle article distinguishes different kinds of flags and discusses their carrying cost. A temporary release flag should have an owner and removal conditions. The date is a prompt to check those conditions, not permission to delete the old path regardless of remaining consumers.

Before removing the flag, establish that old writers no longer run, outstanding jobs use a supported shape and required records are migrated or explicitly excepted. Dormant consumers such as the monthly export need evidence too. Then the unused route and its tests can be removed deliberately. Leaving both indefinitely would retain the precedence and compatibility work after the flag has ceased to control a useful release decision.

Retain the useful history: the mapping rules, exceptions and compatibility decision. Remove the accidental complexity of a flag that no longer governs a real choice. This distinction lets the code become simpler without discarding the evidence somebody will need when an unusual old record appears in an export six months later.

A small table can improve a large release

Not every flag needs a data-migration programme. A cosmetic variation or a reversible read-only path may have a much smaller compatibility surface. The point is to inspect what persists and who consumes it. The release effort should follow those consequences rather than the number of lines behind the conditional.

Before approving a flag-controlled migration, draw the four reader-and-record combinations and add the writers that can still create each shape. Choose a representative record for every supported cell. Walk a delayed job and an old editor through the overlap. Finally, state what the off position means before and after contracting the data model.

The four reader-and-record combinations give this flag a useful, limited job: choose when traffic enters a supported phase. Turning it off can then lead back to a state somebody has actually examined. If contracting the data removes that state, replace the recovery plan at the same time. The label printer does not care how reversible the release looked in the dashboard; it needs a record the version running today can still understand.

Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.

See the Payment Operations Pilot

References & further reading

Primary sources behind this article. Living documentation may change.

  1. Pete Hodgson: Feature Toggles Published 9 October 2017
  2. Danilo Sato: Parallel Change Published 13 May 2014
Hamsa Jama

Practical engineering. A human perspective.

More about Hamsa Software and the person behind it. Editorial notes.

A few more things
worth a read.

Back to the reading room
Engineering7 min read

What does £240 belong to?

A readable table preserves relationships between values, row labels, column headings and actions across different ways of reading.

Engineering7 min read

When two calculations agree on the wrong answer

A shadow comparison exposes differences. Independent rule examples explain whether those differences are bugs, corrections or changed assumptions.