#104 - How to Modularize an Engineering Calculation
Where your coding effort compounds, and where it doesn't
There is a common stumbling block waiting for many professional engineers once they learn to implement code into their workflow. Itâs not syntax. You can argue now that you donât even need to learn syntax anymore.
The wall is architecture: you have a real problem in front of you, you know roughly what the calculation needs to do, and you have no idea how the pieces should be organized. Is it one big script? A collection of scripts? A notebook? Where do the functions live? Nobody tells you this, and honestly itâs not something you can be told. You need some mileage before the answers feel obvious.
I canât give you the mileage, but I can give you some ideas to build a framework that works for your own objectives.
Start in a notebook
Almost everything I do starts in a Jupyter notebook. Not because notebooks are the ârightâ tool, but because early on I donât know what the problem is yet, and a notebook is a good place to find out. I can mix code with markdown notes about where an input came from, why I picked one method over another, a plot to sanity-check an intermediate result. The rationale lives beside the calculation.
I spend a lot of time planning and framing the problem up front, but once I begin to engage in the calculations, notebooks are where most of my code related effort goes.
Thereâs a side benefit that took me a while to appreciate. The notebook often ends up being the calc file itself, the thing that gets checked. When a junior engineer brings me a notebook, I can follow their line of thinking, not just their answer. I can see what the inputs were and where they came from. A folder of terse .py files doesnât give a reviewer that, and in a profession where someone else has to verify your work, that matters more than the elegance of succinct clean code.
So when does something graduate out of the notebook? Two triggers, in my experience. Reuse is the obvious one: if youâre scrolling back through an old notebook to copy a block into a new one, that block wants to be a module. The other is size. Past a certain point a notebook becomes unruly, hard to execute reliably and genuinely difficult to review, and at that point keeping everything in one document has stopped reducing risk and started adding it.
Think about what compounds
When I do pull something out into a module, the question Iâm asking is: will this effort compound? Some pieces of a calculation are stubbornly project-specific. Others are universal, and those are the ones worth formalizing properly.
Load cases defined per a specific design code. Material properties. Geotechnical parameters. If youâve built these once, carefully, theyâre useful on the next project and the ten after that. Hydraulic calculations are a decent example. Over time I have developed a small library of reusable tools: functions that take a penstock alignment straight from a CAD drawing as XYZ coordinates and work out the bend geometry, a materials library so I can compare how different pipe materials affect losses, and several ways of running transients, from first-principles water hammer up to four quadrant analysis. None of that was designed up front as a grand system. Each piece got extracted when I needed it a second time, and the boundaries between modules ended up sitting where the dependencies naturally break. The coordinate parsing doesnât care what the pipe is made of. The materials library doesnât care where the bends are.
A rough shape that has served me well, if you want somewhere to start:
project/
âââ inputs/ # project-specific parameters and source data
âââ reference/ # the stuff that compounds: materials, code load cases, constants
âââ core/ # calculation logic, nothing else
âââ checks/ # sanity checks, comparisons against known results
âââ outputs/ # results, plots, generated reports
âââ main.py # runs the sequence
The reference folder should hold both reference code (i.e. your reusable modules) and reference data or design input sources. Keep the compounding stuff physically separate from the disposable stuff and youâll find yourself naturally managing and organizing it over time.
Calibrate to your own work
How far you take any of this depends on how repetitive your work actually is, and our industry is broad enough that the answers vary wildly. There are entire companies that specialize in reinforced concrete spiral staircases. If thatâs your world, you should absolutely build deep, rigid calculation pipelines, because youâre solving close variants of the same problem over and over and the payoff is enormous.
My own work isnât like that. Itâs varied enough, penstock design one month, seismic analysis of a concrete frame the next, an energy model after that, that strict calculation pipelines rarely pay off for me. What I actually automate with scripts are the workflows underneath the engineering: turning markdown into Word documents, processing meeting notes, making SAP2000 output readable when I care about specific nodes or elements. I do keep component-check scripts around, beam bending, slab design, anchor blocks, the kind of isolated checks youâd otherwise do in something like Tekla Tedds. But the novel engineering stays in notebooks, because itâs novel.
So this framework is meant to make you think about where your effort compounds. It is not a prescription. You know your work; I donât.
Where the AI tools fit
I canât write about code organization in 2026 without talking about agentic coding, and Iâll be honest that my opinion here keeps drifting as the tools evolve. Anyone whoâs read this newsletter for a while knows Iâm a fan (right now Iâm working a lot with pi, a lightweight agentic toolkit, incredibly flexible - I will talk about this another time).
The capability is staggering. If your prompt is tight enough, you will get exactly what you asked for.
Maybe thatâs where the risk is. Do you know exactly what you need? Do you know how to ask for it? Are those two things actually aligned? Because in a deterministic profession, we can now produce calculations far faster than we can check them, and I mean check them from a human lens, actually understanding whatâs happening and where the gaps might be. Even a genuinely rigorous test suite only tests what you thought to test. You donât know what you donât know, and neither does the model. I have no tidy solution for this, and Iâm suspicious of anyone who claims one. What I do in practice is verify in layers, the same way a calc gets checked and then reviewed, rather than trusting any single pass no matter how clean it looks.
The good news is that everything above transfers directly. Context engineering, as I think of it, is providing the minimum context needed to achieve the goal. The bad habit I keep seeing is people dumping everything into the model and expecting it to do the thinking. Sometimes, on simple problems, it does. But Iâm constantly correcting models even with instructions Iâd consider well refined, because my own understanding of the problem evolves as I go deeper, and yesterdayâs perfect prompt describes yesterdayâs understanding. Context engineering is an active verb. It happens throughout the work, not once at the start.
And notice what it requires: knowing which slice of the problem is genuinely separable, what its inputs and outputs are, what the model needs and what would just be noise. Thatâs the same judgment as knowing when a block of code deserves to be a module. If you learn to decompose problems properly with your own hands first, the agentic tools become a multiplier. If you skip that step, they multiply something else.
One last thing. Everything in this piece is software engineering best practice, restated for professional engineers who are arriving at code from another direction. Thatâs deliberate. These problems were solved decades before we showed up, and the people who solved them have done a great job in organizing their thoughts and approaches. Stand on their shoulders. Itâs a much better view.
P.S. - Highly recommend âThe Pragmatic Programmer: Your Journey to Mastery - Andy Hunt and Dave Thomasâ.



