A note before I start: this is about the shape of the problem, not about any employer's or client's internals. Everything below is public domain knowledge about semiconductor test — the kind of thing you would learn in a fortnight of reading. What I do with it professionally stays where it belongs.

Here is a fact that surprises most software engineers: every single microchip is individually tested before it ships. Not a sample. Not a batch with a confidence interval. Every one.

Think about what that means at volume. A mid-sized fab ships billions of devices a year. Each of those is physically contacted by a probe or a socket, driven through a sequence of electrical measurements, and judged. The software that runs that sequence and decides the verdict is what I work on. It is one of the more interesting places to write C++, because almost every engineering trade-off you normally get to argue about has already been decided for you by physics and economics.

Test time is money, literally

Automated test equipment is expensive — a tester is a capital asset, and its time is accounted for like machine time in any factory. So the cost of testing a device is roughly tester time × rate, and it lands on every unit you produce.

This changes how you think about optimisation. In a web backend, shaving 10 ms off a request is a nice latency win that a few users might perceive. In test, shaving 10 ms off a test flow is multiplied by every device you will ever produce. At a billion units, ten milliseconds is over three thousand hours of tester time.

The consequence: performance work here is not a cleanup task you get to when there is time. It is a feature with a business case attached, and it is one of the few environments I have worked in where you never have to argue for a profiler.

It also means the usual convenience patterns get examined properly. An allocation in a per-measurement loop, a string formatted for a log line nobody reads, a virtual call in the innermost path — individually trivial, and collectively a line item. This is C++ being used for exactly what it is good at: you can see the cost, and you can remove it.

Correctness is expensive in both directions

Software people are trained to think about false negatives — the bug that got through. Test engineering makes you think about both directions at once, because both cost real money.

A false pass (an "escape") means a defective device leaves the building. In consumer goods that is a return. In automotive or industrial parts, it is a component inside somebody else's safety-relevant system, and the quality targets are correspondingly brutal — the industry talks in defective parts per billion, not per million.

A false fail means you just threw away a good chip. Do that at a rate of one percent and you have quietly given away one percent of your yield, which in this industry is an enormous amount of money for something that will show up in a report as "normal variation".

So the framework cannot simply be "correct" in the sense of not crashing. It has to be right about numbers, at the boundaries, consistently, forever. Which brings me to the thing I find genuinely interesting.

Units are a type-safety problem

Measurements have units, and units are where mistakes hide. A limit expressed in millivolts, compared against a reading in volts, produces a comparison that is perfectly valid C++ and completely wrong. It will not crash. It will not warn. It will silently pass devices it should fail, by a factor of a thousand.

The fix is old and unglamorous: make the type system carry the unit, so the mistake stops compiling.

// A reading and a limit that cannot be compared unless they agree.
template <class Unit>
class Quantity {
public:
    explicit constexpr Quantity(double v) : value_{v} {}
    constexpr double in(Unit) const { return value_; }

    friend constexpr bool operator<(Quantity a, Quantity b) {
        return a.value_ < b.value_;
    }
private:
    double value_;   // always stored in the canonical unit
};

using Volts   = Quantity<struct VoltTag>;
using Amperes = Quantity<struct AmpTag>;

bool within(Volts reading, Volts lower, Volts upper) {
    return !(reading < lower) && !(upper < reading);
}

// within(current, lower, upper);   // does not compile — and that is the point

Nothing here is clever. That is the appeal. The cleverness budget is better spent elsewhere, and a whole category of expensive, silent, human error is deleted at compile time for the price of a template and a tag struct. C++'s zero-overhead promise is what makes it affordable in a hot path: the wrapper costs nothing at runtime.

This is the same lesson I wrote about when a JavaScript bug bit me for conflating two variables named x. The difference is that there, nothing caught it. Here, the compiler does — if you let it.

Determinism, and the question "compared to what?"

A measurement result is only meaningful if you can reproduce it. That sounds obvious until you notice how many things can legitimately differ: two testers of the same model, two hardware interfaces with different cabling, two software versions, the same device measured twice, the same device measured at a different temperature.

So a framework in this space needs an answer to "did the number change because the device changed, or because we changed?" That answer is engineering, not luck. It looks like: pinned and versioned test definitions, correlation runs against known-good reference units, and the discipline to treat a change in measured distribution as a release-blocking event rather than noise.

Coming from ADAS validation, this was the most familiar part of the domain. Different nouns entirely — there it was object recognition accuracy over camera data, here it is parametric measurements over silicon — but structurally the same job: prove that today's build still agrees with reality, and make the disagreement obvious when it does not.

The data does not stop

Every test on every device produces numbers, and those numbers do not get thrown away. They feed yield analysis, process control, failure analysis, and the traceability obligations that let a manufacturer answer "what happened to this specific part" years later. The industry even has a standard binary format for it, STDF, which has been around since the late 1980s and is still in use — a nice reminder that in manufacturing, formats and equipment have lifespans measured in decades, not sprint cycles.

That longevity is a design constraint you feel constantly. Code written here will outlive the person who wrote it, the framework version it targets, and probably the language standard it was written against. It is a strong argument for boring, explicit, readable code — and against the elegant abstraction that only its author fully understands.

Why C++, still

People occasionally ask why this kind of software has not moved on. Four reasons, none of them nostalgia:

Cost visibility. When per-device time is the metric, you need a language where you can see and control what the machine does. Hardware proximity. Instrument and driver APIs are C and C++; every other language reaches them through a binding you now also own. Determinism. No surprise pauses in the measurement path. Lifespan. Equipment stays in service for decades, and so does the software driving it.

Python has an important seat at this table too — for orchestration, analysis, and the tooling engineers actually live in day to day. The split is the usual sensible one: C++ where the cost and the correctness live, Python where the humans do.

What transfers

The reason I find this work satisfying is that it is the same engineering I have been doing for years, with the stakes made unusually legible. Profile before you optimise — except the profile has a euro figure attached. Make illegal states unrepresentable — except an illegal state is a bad part in a car. Prove the system still works after the change — except "the system" is a production line that does not stop for you.

It is one of the few domains where you can point at a piece of code and say what it costs and what it prevents. After fifteen years of arguing that correctness and performance are worth paying for, it is a relief to work somewhere the accounting agrees.


I build test and measurement systems in C++, alongside latency-critical backends and the Linux platforms under them. If you have a measurement system that is too slow, too flaky, or too frightening to change, tell me about it — or see what I do for clients.