Comment by jackfranklyn
3 months ago
Yeah the immutability angle is the right instinct. The Step1Output approach is essentially what we landed on - each phase returns a typed result that gets composed into the final state. The tricky bit is when phase 7 needs to check something from phase 3's output to decide whether to run at all. You end up with either a growing "context" object that accumulates results, or a lot of explicit parameters threading through.
The discipline tax is real though. Pure functions are easier to test in isolation but harder to trace when you're debugging "why did this transaction get coded wrong" and the answer spans 6 different step outputs.
> harder to trace when you're debugging "why did this transaction get coded wrong" and the answer spans 6 different step outputs
That's definitely a pain, but I'm not sure it's easier when this is one variable being mutated in six different places. I think you're just running into the essential complexity of the problem.
Completely agree - it's essential complexity either way. The mutation approach just spreads it across time (when did this value change?), while the immutable approach spreads it across space (which step produced this value?).
The immutable version is probably easier to debug in practice since you can inspect each step's output independently. The "6 places" complaint was more about cognitive load during debugging than actual difficulty - you're jumping between files instead of scrolling through one. But that's a tooling/IDE problem, not an architecture one.