The Friday Afternoon That Broke Everything
It is 4:30 on a Friday. Sprint review in thirty minutes. Someone changed a segment in the claim generator last week, a small fix, completely reasonable, and the test suite is failing on seven fixture files that no longer match what the code produces. You open the first one. Eight hundred bytes of pipe-delimited segments, loop structures, interchange control headers. You open the second. Then the third.
This is EDI test hell, and every team that works with healthcare claims lives here eventually.
The 837 transaction set is the HIPAA-standard format for submitting medical claims. It is not a forgiving format. Every segment has to be in the right place. The loop hierarchy has to be correct. Interchange control numbers have to pair. Element counts have to be exact. A single misplaced segment does not produce a validation warning. It produces a rejection, silently, from a clearinghouse or payer that tells you almost nothing useful about why.
So most teams do what seems reasonable: hand-craft a few representative claim files, check them in as test fixtures, and test against those. It works. Until it doesn't.
Fixture files drift. The code changes, the fixture doesn't. Someone updates a service type code and forgets to update the fixture. A new billing scenario gets added and the fixture doesn't cover it. Six months in, the test suite passes but the fixtures are lying. They represent a claim structure from six months ago, not the one the system actually produces today.
I hit this wall repeatedly. The fix that kept presenting itself was uncomfortable: stop maintaining fixture files. Generate them instead.
What It Looks Like to Generate a Valid 837
The first reaction to "generate 837s programmatically" is usually skepticism. The format is intricate. There are loop structures nested several levels deep: the billing provider loop, the subscriber loop, the claim loop, the service line loop, each with required and optional segments, each with element-level rules about what values are valid in which positions. HIPAA compliance is not aspirational. If a transaction is not spec-valid, it does not go anywhere.
But the complexity of the format is exactly why generation is the right answer. When you maintain a static fixture, that complexity means you are maintaining a fragile artifact by hand. One wrong element and it is broken. One missing segment qualifier and it is broken. Change anything upstream and the fixture might be lying about validity while technically still being parseable.
When you build a factory that generates 837s, the logic for what a valid claim looks like lives in one place. It can be exercised repeatedly, with variations. You can generate a claim for a professional encounter, a facility claim, a coordination-of-benefits scenario. You can vary the service lines, the procedure codes, the diagnosis pointers. And you can know, because the factory enforces the structure, that every generated claim is syntactically valid. Not "probably valid" or "valid when I last checked it." Valid by construction.
Building this in Apex meant treating the 837 format as a structured artifact rather than a string-concatenation problem. Each segment becomes something the factory composes: an ISA segment with the right delimiters and padding, a GS segment with the appropriate functional identifier code, the NM1 segments for each loop, the CLM segment with its composite element structure. The factory knows the loop hierarchy. It knows which segments are required. It knows the element positions.
The test that used to read a static fixture now calls the factory with parameters. The parameters are what varies: the claim scenario, the diagnosis codes, the service lines. The structure is always correct. The test is testing behavior, not format adherence.
What Changes When You Stop Maintaining Fixtures
The difference shows up most clearly when something in the claim generation logic actually changes. Before: you change the code, run the tests, find three fixtures failing because they no longer match the new output, spend time figuring out whether the new output or the old fixture is correct, update whichever is wrong, ship. After: you change the code, the factory reflects the change everywhere, the tests still pass because they are parameterized against the factory, and what you verify is the behavior. Not whether a static file byte-matches your new output.
There is a second effect that took longer to notice. The static fixture files were also functioning as implicit specifications. When a developer opened one to understand what a valid 837 should look like in this system, they were reading a frozen snapshot. With a factory, the specification is the factory itself. What it produces is the living definition of what a valid claim looks like, enforced by the same code that runs in production.
That is a different relationship to the format.
The uncomfortable part of getting here was accepting that the fixture files felt like safety. They were tangible. You could open them, inspect them, share them. A factory is code. Code can be wrong. But the fixture files were wrong too, quietly, in ways that only surfaced when the tests happened to catch up or when a clearinghouse rejected something in staging.
The tradeoff is not close. A factory that generates syntactically valid claims can be wrong in an obvious, testable, fixable way. A fixture file that drifts from reality is wrong in a silent, misleading, dangerous way. One failure mode you can find with a test. The other you find in production.
The principle underneath all of this: stop maintaining what you can generate. If the correctness of an artifact depends on keeping it synchronized with the code that uses it, that synchronization is a failure mode waiting for the right Friday afternoon. Make the artifact a product of the code instead, and you have eliminated a whole class of drift before it starts.