Skip to content

The rule that changes every week does not belong in your code

Pedro Cunha
Pedro Cunha
CTO at Epicora

Published on
updated on · 16 min read

In short

Any change request that needs a deploy to swap a number, a deadline or a limit is an architecture decision that was made wrong earlier. In SheepGen, genetic interpretation became 1,103 rules registered as data, and a new marker recalculates all 735 flock reports in 4 minutes, with no developer in the loop. But parameterizing without a way to verify is worse than code: the same engine was validated against an independent implementation, with zero divergence across 55,050 readings.

Why a rule that changes every week does not belong in code#

A business rule is data, not code. Any change request that needs a deploy to swap a number, a deadline, a limit or an approval criterion is the symptom of an architecture decision made wrong earlier, when somebody wrote as a constant what the business treats as a record.

The question shows up in every discovery call, always in the same words: "and when the rule changes, will I depend on you?". The honest answer is neither yes nor no. It is: that depends on where the rule was placed, and that gets decided before the first line of code.

Genomics makes it sharpest. When we built SheepGen for DNA Genética do Brasil, the genomic evaluation platform for sheep, the client described his own work like this: new research comes out, he creates a new field, recalculates and delivers again. That was not a feature request for later. It was the premise of his business. Every scientific publication gives a genetic marker a direction and it starts scoring. Any system with that rule written in code would be born outdated, and would age faster than the team could deploy.

What becomes a parameter and what stays code#

The criterion is not an engineer's taste or a client's preference. It is three questions about the rule, and the answers push in opposite directions.

Question about the ruleAnswer that sends it to the databaseAnswer that sends it to code
Who knows the right answer?the operator: the geneticist, the credit analyst, the licensed professionalthe developer
How often does it change, and why?on an external event: research, new regulation, negotiationon a product decision, rarely
Does the rule fit in a fixed form?yes, the shape is stable and only values changeno, every case has a different shape
What happens if it is wrong?a wrong number in a document, fixable by recalculatingcorrupted data, money leaving, system down
Can it be checked from outside?yes, the rule is one human-readable lineno, it is distributed behavior

Three yeses and the rule belongs in the records. Three noes and it belongs in code, and insisting on parameterizing only moves the complexity somewhere with no tests.

The line usually falls inside the same formula, and that is where the decision gets concrete:

Real ruleLives as dataStays code
Quality threshold for a genetic readingthe value (0.60, set by the client)the comparison and what happens below it
Morphometric conversion: (cm minus mean) ÷ 2.54the mean per breedthe formula, and the fixed 2.54
Which lender approves this customer for this vehiclevehicle type, minimum year, auction history, license requirementthe routing and the ranking
Psychosocial risk reportthe 13 factors and the classification scalethe matrix and the arithmetic behind it
Platform time zonenothingfixed, and deliberately not configurable

Look at the last row. In a multi-tenant platform we scoped, the time zone stayed fixed and visual customization stayed at roughly twelve closed themes instead of a free color field. That was deliberate: every open option is one more state to test, and one more state for somebody to configure wrong.

How the rule became data in a domain that changes monthly#

In SheepGen, the structural decision was to treat genetic interpretation as a catalog, not as an algorithm. The DNA Genética team registers the marker and, for each combination of genotype and breed, defines the composite, the score and the classification. The person who maintains the brain of the system is the geneticist, not the developer.

The scale is the surprising part: no marker counts on its own, because it is the relationship between markers, inside a composite and a breed, that produces the score. That is why the catalog holds 76 markers and 1,103 rules, not 76 answers. The same SNP scores differently in different breeds, and a marker has its own life cycle (active, awaiting direction, blocked), because that is how the science works.

The second decision was to separate raw data from calculation. The lab file, 4.3 GB and 59 million lines, is uploaded straight to storage and read in streaming; every useful reading is stored as animal data, independent of any score. The consequence is what the client asked for without using the technical term: recalculation became a button. And when a marker is registered after the import, the system rereads the file already in storage and writes only what was missing, without asking the lab for anything new.

That was proven live, in the real environment: we registered a new marker, the system reread the 4.3 GB, wrote the 734 missing readings and recalculated all 735 reports in 4 minutes. After the proof, the test marker was removed and the recalculation returned the validated number. The math closes in both directions.

The same pattern holds in the bovine genetics system we built for DNA Genética, the DGA Intelligence platform: each field declares its own nature (genotypic, phenotypic or morphometric), and from that follows whether it scores and whether it converts into another field. Migrating from the legacy system meant 32 fields with normalization and factorization rules per breed and sex, plus 12 genetic models, all loaded as data. The granularity itself is a code decision: conversion is per breed, normalization is per breed and sex. The values inside it are records.

When the rule lives in people's heads#

The most instructive parameterization case does not come from a scientific domain. It comes from lending.

At Ideal Veículos, a network of 11 dealerships, the F&I job is finding, among dozens of lenders, who approves that customer for that vehicle and on what terms. It sustains a relevant share of dealership revenue, and its rule existed nowhere: it lived in the heads of experienced people. Tacit knowledge, poorly documented, lost to the natural turnover of a sales team.

The turning point was registering that rule. Each of the 19 lenders got its own criteria recorded in the platform (which vehicles it finances, minimum year, whether it accepts auction history, whether it requires a license), and the system started recommending the right lenders for each customer and vehicle, with a ranking per lender. What used to be a senior professional's memory became a system suggestion.

The volume effect comes later, and it is what proves this survived real operation: in 13 months live, 11,364 financings and 51,595 proposals recorded, with 10,494 customers in the history. Before, only the final proposal made it into the spreadsheet; now every attempt is recorded. That is what a settings screen buys and a hidden algorithm does not: the rule outlives the person who knew it.

Where AI does not go#

Parameterizing rules and generating text with AI look like neighbors, and they are opposites. The border is visible in Sistema Cuidar, the psychosocial risk assessment platform we built for Brazil's NR-1 requirements.

The report has 15 sections. The institutional ones (cover, presentation, introduction, objective, methodology, sample characterization, dimensions assessed) come from a versioned template. The 13-factor risk matrix is rendered straight from the extracted data, with no AI at all: it is arithmetic and rules, auditable line by line. Only then does the AI step in, to write 5 sections that require technical interpretation, in five independent parallel calls, each one regenerable on its own. The text lands in an editor where the licensed professional reviews it before export.

The rule that defines the product is this: the AI writes and does not calculate. That is what makes the document signable, because no number in the report came from a language model. The same principle holds when AI arrives as an interface: in the AI layer we modeled for DGA Intelligence, an MCP server exposing the system as conversational tools, the scope states that the AI does not calculate genetics, it triggers the deterministic engine that already exists through the same API the screens use, inheriting limits, permissions and audit. Worth recording that this layer is modeled and estimated, not delivered.

The price of over-parameterizing#

This is the part almost nobody writes, and it is what separates parameterization from a very expensive trap.

A system that parameterizes everything becomes a bad programming language inside an admin form. It has conditionals, it has precedence between rules, it has combined effects, and it has none of what a real language has: verifiable syntax, automated tests, code review, a readable change history. Writing about rules engines in 2009, Martin Fowler already noted that the problem is not the isolated rule, which always looks sensible: it is that a small change in one place produces unintended consequences in many others, because the program flow becomes implicit.

The practical symptom is always the same. A configuration error does not produce a visible error. It produces a plausible number.

We lived that in the genetic catalog conversion. One marker had its allele notation decided line by line, and in that shape one genotype matched under one convention and the other matched under a different one: half the marker correct, with no error message at all. The system would have issued a report with a wrong score that looked right. The fix was to take the decision out of the data and move it to a per-marker rule, and the problematic marker went in blocked until somebody decided its convention. Two lessons: part of the configuration belongs in code, and configuration you cannot verify should not exist.

There is also the silent cost of volume. The catalog's 1,103 rules live in a spreadsheet that can be checked line by line, each line carrying its provenance. Even so, for weeks, the full human review of those 1,103 lines was an open item, not a finished task. A large set of records moves work around; it does not remove work. Anyone promising "you just configure it" is describing the easy part.

So the yardstick for opening a configuration field is economic: every field has to pay for itself in real changes the client team made on its own. A field nobody touched in a year cost a screen, tests, documentation and risk, and returned nothing.

How to verify that the parameterized rule is correct#

Parameterizing without a way to verify is worse than leaving the rule in code, because a wrong rule does not announce itself. In a document that guides a breeding, credit or occupational health decision, a wrong number that looks right is the worst possible defect.

The technique that holds up is comparing the system against an independent calculation path, over the same data. In SheepGen the scoring engine was not merely tested: it was checked against a checker written separately on purpose, running outside the system. Both had to reach the same report, animal by animal, composite by composite. Result on the first real load: zero divergence across 55,050 readings from 735 animals. And that equality became guarded by an automated test, so any change in the engine that drifts from the checker breaks the suite before it reaches production.

Checking against the source also catches what arrived wrong from outside: when 71 animals came out with one composite zeroed, revalidation against the original files found a swapped classification in the source spreadsheet, markers recorded under the wrong composite. Corrected with the client, each animal's total did not move a single point, because it was a reclassification, and the zeroed composite dropped from 71 animals to 2, the 2 that were correct.

The same method applies when there is an old system to compare against. Replacing the DNA Genética legacy, we assembled a staging package with converted real data (54 sires, 200 dams, 32 fields and 12 genetic models) to run both engines over the same inputs. The system being switched off is the best oracle available, it is free, and it exists only once.

Three forms of verification, in order of cost:

FormWhat it catchesWhen to use
Independent implementation of the calculationlogic errors in the engine and in the recordswhen the number goes into a document with consequences
Comparison against the legacy systembehavior nobody ever documentedduring the replacement window, before switching it off
Reimporting your own configurationrules lost along the configuration pathalways: export and reimport must return the same set

Who edits the parameter later, and what gets recorded#

A rule that became data is now editable by someone who is not a developer. That is the goal, and it is also a new incident vector: who can change it, what the change affects, and how anyone finds out later what was changed.

The minimum a parameterized system has to carry:

  • The rule set version on every result. In SheepGen, each analysis stores the catalog revision and the calculation date, and the PDF report prints both: a counter increments on every write to a marker or a rule. Two reports for the same animal, from different periods, never get confused, and the question "under which rule did this number come out?" has an answer.
  • Role-based permission on the parameter, not just on the screen. Whoever operates reads; whoever answers for the rule edits.
  • Explicit confirmation for any writing action. In the scope of the DGA Intelligence AI layer, every tool that writes or triggers a batch requires user confirmation.
  • Explicit recalculation, never silent. Changing the rule and recalculating are two acts. Automatic recalculation on top of an already issued document is how traceability gets lost.

Worth being honest about the missing step: recording the rule set revision answers "which rule produced this number", which is the question that matters for checking the math. Recording who changed the rule and what exactly changed is one more layer, a per-user trail, and it is not automatic. A system that opens configuration to the client without building that trail is trading deploy dependency for absence of a trail.

Frequently asked questions#

When my business rule changes, will I depend on you?#

It depends on where the rule was placed, and that is decided during the project, not afterwards. A rule that changes because of new research, a new regulation or a commercial negotiation has to be born as a record your own team maintains. In SheepGen, the genetic interpretation catalog holds 1,103 rules registered by the client team, and a new marker recalculates all 735 flock reports in 4 minutes. A rule that changes once a year, or that nobody outside the technical team can answer, stays in code on purpose: turning it into a settings screen would cost more than it saves.

What is the criterion for deciding whether something becomes a parameter or stays in code?#

Three questions settle almost every case. Who knows the right answer: if it is the person who operates rather than the person who programs, the rule leans toward the database. How often does it change without warning: if it changes because of an external event, the database wins. And does the rule fit in a fixed form: if the shape is stable and only the values vary, it is a parameter; if every case has a different shape, it is code. When all three answers are yes, parameterizing saves deploys; when they are no, parameterizing only moves the complexity somewhere with no tests.

Is over-parameterizing a real problem?#

It is the most expensive mistake in this family, and almost nobody writes about it. A system where everything is configurable becomes a bad programming language inside an admin form: nobody understands the combined effect of the options, none of it is covered by tests, and a configuration error produces a plausible number instead of a visible error. Martin Fowler warned back in 2009 that the ease of changing one isolated rule is precisely what makes the consequences unpredictable. In practice, every configurable field has to pay for itself in real changes the client team made on its own.

How do I know the rule I registered is correct?#

Only one approach holds up: compare the system result against an independent calculation path, over the same data. In SheepGen we wrote the production engine and a separate checker outside the system, and both had to reach the same report animal by animal. On the first real load they produced zero divergence across 55,050 readings, and that equality became guarded by an automated test: any change in the engine that drifts from the checker breaks the suite. Parameterizing without that check is worse than leaving the rule in code, because a wrong rule does not announce itself.

Can AI handle the business rule instead of a parameter?#

Not for calculating. In Sistema Cuidar the AI writes 5 of the 15 report sections, and the 13-factor risk matrix is calculated from the data with no AI at all: it is arithmetic and rules, auditable line by line. That separation is what makes the document signable by a licensed professional, because no number in the report came from a language model. AI is a good conversational layer on top of a deterministic engine, and a terrible replacement for one.

Sources#

Next step#

If your operation has a rule that changes faster than any vendor can deploy, the place to decide that is the project, not the maintenance contract. See how it turned out in the SheepGen case, where the client team maintains 1,103 genetic interpretation rules with no developer in the loop, and in the Ideal Veículos case, where the credit rule left people's heads and became a record. It is the kind of decision we handle in custom software, and the border with AI is in the Sistema Cuidar case and in AI automation.

Share
Pedro Cunha
Who writes here
Pedro Cunha
CTO at Epicora

Pedro Cunha leads engineering at Epicora, in Chapecó, Brazil. He writes about the technical decisions behind the systems the team puts into production — architecture, scope, estimation and applied AI.

Articles by Pedro Cunha

Contact

Let's talk about your project

Tell us what you need to solve. We reply fast, with people who understand both technology and business.

Prefer to talk directly?

Pick the channel you prefer. We reply fast, during business hours.

From the first conversation to go-live: efficiency, security and innovation.