The Modernisation Control Papers — 04.1

How to decide which behaviours need to survive the migration

Before rebuilding an application, teams need to decide which outcomes, rules and controls still matter and which parts of the current system should be allowed to disappear.

Illustrative Harten paper cover: How to decide which behaviours need to survive the migration
Illustrative cover artwork, not an application screenshot or a record of measured results.

In the Series 04 paper, I looked at a question that sounds simple until you try to answer it: when we replace an application, what actually needs to remain the same?

Finding behaviour in the current system is not enough.

A rule in the code may still matter. It may also exist because of a constraint that disappeared years ago.

A manual process may be an important control. It may also be compensating for a gap that the replacement can remove.

An interface may still be essential to another system. Or it may be feeding something nobody uses.

So once we have found the behaviour, we still have to decide what to do with it.

That is the part I want to go deeper into here.

I do not think this decision can be reduced to a checklist where every behaviour gets a score and falls neatly into a category. Real applications are messier than that. The evidence is uneven. Different people know different parts of the story. Some behaviours matter because of what they prevent rather than what they produce. And occasionally the current system, the written policy and the way people actually work will all tell you different things.

The useful question is not simply whether a behaviour exists.

It is whether the organisation still depends on the outcome, whether the reason for the behaviour still exists, what happens if we get the decision wrong, and who has the authority to decide what the future system should do.

A worked example makes this easier to see.

Imagine a long-running claims application.

It has been in production for years. The team now has a reasonably good picture of how it works from source code, database logic, documentation, production evidence and conversations with the people who operate it.

During discovery they find six behaviours that look important:

  • claims above a threshold are sent for manual approval;
  • a nightly batch recalculates certain values before the next working day;
  • an outbound interface sends a file to an external partner;
  • one calculation in the code does not match the current policy document;
  • operations maintain a spreadsheet to correct a particular edge case;
  • a downstream finance process depends on a field that appears unimportant inside the application itself.

All six are real.

That does not mean all six should survive in the same form.

Start by understanding what the behaviour protects

Take the manual approval step first.

The application routes claims above a certain threshold to a senior reviewer before payment can be released.

There are several ways to look at that.

One is to say that the new system must reproduce the same workflow because that is what the existing application does.

Another is to ask why the workflow exists.

Perhaps the threshold exists because higher-value claims carry more financial risk and the organisation wants an authorised person to review them before money leaves the business.

If that is the reason, then the thing we need to preserve is not necessarily the screen, the role name or even the exact workflow sequence.

The thing we need to preserve is the control.

That already changes the design space.

The replacement could provide the control through a different workflow. It might use different roles. It might present more evidence to the reviewer. It could even automate part of the assessment while still requiring a person to authorise the consequential decision.

The outcome remains the same: a claim above the agreed threshold cannot be paid until the required authority has reviewed it.

That looks like a behaviour to preserve.

Now consider the nightly batch.

The batch recalculates some claim values every night and writes the results back to the database.

At first sight, that looks just as important. It runs every day. It changes production data. People know it exists.

But when the team investigates why it was introduced, they discover that the old application could not reliably perform the calculation during the working day without slowing down the system.

The business does not care that the calculation runs at night.

It cares that the correct value is available before the next stage of processing.

That distinction matters.

If the new platform can calculate the value when the claim changes, reproducing the nightly batch would preserve an old technical compromise rather than a current requirement.

So in this case I would preserve the outcome and deliberately change the mechanism.

The two behaviours looked similar when we started. Both were established parts of the production system.

One contains a control that still matters.

The other contains a technical constraint that no longer does.

That is why I would not make preservation decisions from the existence of code or process alone.

I would ask what the behaviour protects and whether that reason still exists.

Then find out who or what depends on the result

The outbound partner interface gives us a different problem.

The application produces a file every afternoon and sends it to an external organisation.

Nobody on the current application team is completely sure what the partner does with it.

That is exactly the kind of thing that gets preserved by default.

It is visible, it is old, and breaking something outside the organisation would be embarrassing and potentially consequential.

But preserving it without investigation is still a decision.

It means paying to reproduce the interface, its data format, its scheduling, its testing and its support obligations in the new system.

So I would want to trace the dependency.

Is the partner still active?

What data are they consuming?

Do they still expect the same file?

Is there a contractual obligation behind it?

Does another service now provide the same information?

What happens if the file is not sent?

Suppose the answer turns out to be that the partner relationship ended three years ago, but nobody removed the scheduled job.

The file is still generated.

The transfer still succeeds.

Nobody reads it.

That behaviour should probably be retired.

Now compare that with the finance field.

Inside the claims application, the field looks almost trivial. It is populated near the end of the process and there is very little code around it.

A developer looking only at the repository might conclude that it is low risk.

But the investigation shows that an overnight finance process uses it to determine how payments are grouped for reconciliation.

Remove or reinterpret that field and the claims application may still appear to work perfectly.

The problem only appears later, somewhere else.

That behaviour needs to survive in some form because another part of the operating system depends on its meaning.

Again, I would separate the meaning from the implementation.

Finance may not need the same database column.

It may not even need the same integration.

But it still needs the information represented by that field at the right point in the process.

This is where application boundaries can be misleading.

A behaviour can look small inside one repository and still be important because of what happens outside it.

Defects and workarounds need a different kind of decision

The calculation that disagrees with policy is more awkward.

The code calculates one type of claim using a threshold of 30 days.

The current policy document says 28.

Which one should the replacement implement?

There are several possibilities.

The code may be wrong.

The policy may be out of date.

The 30-day rule may have been introduced deliberately under an exception that was never reflected in the document.

Operations may already be compensating for the difference somewhere else.

What I would not do is quietly choose one source because it feels more authoritative.

The disagreement itself is evidence.

It tells us that the intended behaviour is unresolved.

At this point, engineering has done useful work by finding the contradiction and showing where it matters.

Engineering cannot decide the policy.

Someone with the right authority has to resolve it.

Until that happens, I would keep the behaviour in an unresolved state rather than turning either 28 or 30 days into a future requirement by accident.

This is important because migration programmes create pressure to close questions.

A specification looks cleaner when every field has an answer.

But a clean answer built on unresolved evidence is not actually cleaner. It simply hides the decision that still needs to be made.

The spreadsheet workaround is similar, but in a different way.

Operations use a spreadsheet to correct a rare edge case before payment.

The obvious response is either to preserve the spreadsheet because people rely on it, or remove it because spreadsheets are not part of the target architecture.

Neither is good enough.

I would want to understand the failure it compensates for.

Perhaps the application miscalculates a value when a claim has been reopened after a particular type of cancellation.

If so, the spreadsheet is not the requirement.

The requirement is that reopened claims are calculated correctly in that case.

The workaround is useful evidence because it tells us that the current application does not meet that requirement reliably.

So I would preserve the intended outcome, correct the defect, and retire the workaround once the replacement demonstrates that the edge case is handled properly.

This is one of the places where simply comparing old and new outputs can be dangerous.

If the old system is wrong and people compensate for it manually, perfect behavioural equivalence can reproduce the defect.

The migration needs to know which differences are mistakes and which differences are deliberate improvements.

Consequence should change how much evidence we need

So far we have treated each behaviour as something we can investigate until the answer becomes fairly clear.

Real systems are not always that cooperative.

Sometimes the evidence remains incomplete.

A scheduled process appears to be unused, but the only person who understood it left two years ago.

An interface has no obvious consumer, but it runs only at year end.

A piece of code handles a failure that nobody has seen recently, but the consequence of mishandling it could be significant.

This is where I think consequence matters more than our desire for certainty.

If getting the behaviour wrong could cause a serious financial, regulatory or operational problem, I would spend more effort before deciding to remove or change it.

That might mean finding production examples, checking historical incidents, tracing downstream data, speaking to another team, or running the old and proposed behaviours side by side against representative cases.

If the consequence is low, the organisation may reasonably decide that further investigation is not worth the cost.

It might retire the behaviour and monitor the result.

It might keep a compatibility path for a period.

It might consciously accept the residual risk.

What matters is that the amount of investigation follows the consequence of being wrong.

I do not think every behaviour deserves the same level of scrutiny.

That would make discovery endless.

But I also do not think uncertainty should disappear because a programme has reached a deadline.

If the question is still unresolved, say so.

Then decide what to do with that uncertainty.

Preserve temporarily.

Investigate further.

Narrow the scope.

Accept the risk.

Escalate the decision.

Those are all more useful than pretending the answer is known.

The decision needs to retain its reason

By the end of this exercise, our six behaviours no longer look alike.

The manual approval control should survive.

The nightly batch should not survive in the same form, because the technical reason for it has disappeared.

The old partner interface can be retired because there is no longer a consumer.

The finance field still represents information another process depends on, even if the future implementation changes.

The policy calculation remains unresolved until the accountable owner decides what the future rule should be.

The spreadsheet workaround should disappear, but only after the defect it compensates for has been corrected and verified.

That is already much more useful than a list of current behaviours.

But I would keep one more thing with each decision: the reason.

Not a long document.

Enough that someone implementing or testing the replacement can understand what was decided and why.

For the manual approval, that might be:

Claims above the agreed threshold must not be paid until an authorised reviewer has approved them. The current workflow is one implementation of that control and may change.

For the nightly batch:

The current batch exists because the legacy platform could not perform the calculation reliably during the day. The future system must provide the correct value before downstream processing, but the nightly timing is not a requirement.

For the finance field:

Finance depends on the meaning represented by this field for reconciliation. The future design may change the data structure or integration, but the information and timing must be preserved.

For the unresolved calculation:

Current code and policy disagree. No future requirement should be fixed until the policy owner resolves the intended threshold.

That context makes later decisions easier.

The designer knows what can change.

The engineer knows what must remain true.

The reviewer can see where implementation freedom exists.

The verifier knows what to test.

And if somebody questions the requirement a year later, they have more than a sentence copied out of an old specification.

They have the reason it exists.

I think that is the real output of this stage.

Not a catalogue of everything the old application did.

A set of decisions about which behaviours the organisation still needs, which ones it deliberately wants to change, which ones can disappear, and which ones remain unresolved because the evidence is not yet good enough.

That boundary should usually be smaller than the application we started with.

If it is not, I would want to know whether we have genuinely made preservation decisions or simply documented the current system and called the result a specification.

The next problem is how to describe the behaviours we have decided to keep without carrying the old implementation into the new design.

That is what I will look at in 04.2 — How to describe required behaviour without copying the old implementation.


Editorial note, 5 October 2026: this paper was materially rebuilt after publication to focus on the decision process for preserving, changing, retiring or deferring current behaviours. The publication date and central Series 04 question are unchanged.

This paper is part of The Modernisation Control Papers, the first major sequence within The Harten Papers. Read the complete series on harten.io.