From InstallShield Battles to Go and Postgres: A Tour of My Old War Stories

A quick recap of the older Build Maestro posts that still matter, plus the problems that shaped how I build systems today.

Written on: 2025-12-22

Last updated: 2025-12-22


I went looking through my older posts the other day and it felt like opening a time capsule from a different era of software. Back then, the work was equal parts engineering and survival. The "build" wasn't a pipeline so much as a fragile ritual, and if anything went wrong it was usually at 2 AM, usually during a release, and usually after someone said "this should be simple."

A lot of those posts are very specific to the tools of the time, but the problems are the same ones I still care about now: making brittle processes repeatable, making systems safer for the people operating them, and removing the human-as-a-control-plane pattern wherever possible.

You can find all my older posts at buildmaestro.wordpress.com. This post is a quick tour of the highlights. Not every post is worth revisiting, but a handful still represent turning points where I learned something that stuck.

The era of "please stop paging me"

I still remember what it felt like to be effectively on-call by default. Releases were this multi-step ceremony spread across a pile of servers, and the cost of a mistake was public and immediate. That's why I built what I called the Self Deploy app.

It was me trying to take a messy, tribal-knowledge deployment process and turn it into something boring. Defaulted options, minimal decision points, credentials handled securely, and a UI that made the correct path the easy path. The funniest part is that I wasn't trying to be heroic, I was trying to win my weekends back.

Worth revisiting: What I've been up to – A: Automation (Self Deploy app) — The mindset shift: eliminate complexity by packaging it behind a simple interface, then hand it back to the team.

When password rotation becomes a productivity tax

At one job, passwords rotated constantly, and I was touching so many servers that updating stored passwords became a recurring time sink. I got tired of fighting the symptom and switched to keys. The post is old-school, but the lesson is still current: if a policy creates a constant operational burden, automate the burden away.

Worth revisiting: Logging into Linux servers using ssh keys — The practical step: stop treating passwords as the default for machine access at scale.

The day MSI reminded me it doesn't care about "best practice"

There were times where you can do everything "right" and still get punished by the toolchain. That's basically half of the Windows Installer era. One of the nastier moments was realizing we had boxed ourselves into an upgrade-code corner, and MSI wouldn't give us a clean escape hatch.

So I did what you do when there is no door. I made one. I wrote a workaround that searched for known Product Codes and uninstalled the first one it found. Not elegant, not something I'd recommend if you have better options, but it worked, and it got us out of a release trap.

Worth revisiting: Major Upgrade using Product Code — The lesson: sometimes "correct" is less important than "recoverable."

Debugging shipped software and being blamed for physics

I got pulled into a debugging situation where developers were convinced the archived release binaries didn't match the symbols. The real culprit was the publish process: it modified binaries after build to support activation. Meaning the developer was debugging the wrong artifacts.

That incident is the reason I started building "one-stop" debug archives that captured the real shipped bits and their matching symbols. If someone is diagnosing a field crash, they should not need a scavenger hunt across build outputs, staging folders, and tribal knowledge.

Worth revisiting: Archiving releases using administrative installs — The philosophy: make the correct debugging artifact the obvious one.

Concurrency: the dream and the reality

I tried squeezing real performance out of build systems using concurrent builds. The upside was huge. The downside was dealing with internal tool bugs that only appeared under concurrency, including the kind of errors that vanish if you run the same build in isolation.

I ended up solving it with a mix of structure (separate module/prereq paths) and a bit of "fine, I'll stagger the start times" pragmatism. I wish this wasn't the truth sometimes, but "hacky" is occasionally the shortest path to "fast and stable."

Worth revisiting: Concurrent builds with InstallShield Stand-Alone Release Builder (IsCmdBld.exe) — The lesson: sometimes tooling isn't designed for modern parallelism, and you have to box it in.

The tiny MSI property that wasted an entire day

This one still makes me laugh. I used a property name that looked harmless: PRODUCTLANGUAGE. InstallShield let me define it. The installer engine deleted it anyway because it was effectively reserved. So a condition silently failed and behavior diverged between UI installs and silent installs.

That was the day I relearned a rule I still follow now: if the behavior is weird, assume the platform has hidden rules, and then prove it with logs.

Worth revisiting: PRODUCTLANGUAGE is still ProductLanguage — The lesson: "allowed by the tool UI" does not mean "safe in the runtime."

Why I'm writing this now

The tech stack has changed a lot since these posts. These days I spend more time in Go, PostgreSQL, and AWS APIs, building automation that supports real production delivery and operational reliability. But the through-line is the same.

I still build for the same outcome: fewer sharp edges, fewer manual steps, fewer surprises at release time, and fewer "only Nick knows how this works" systems.

Those old posts are a record of how I learned that mindset the hard way. You can read all of them at buildmaestro.wordpress.com.

If any of these problems sound familiar and there's a modern version in your environment, I'm always interested in the current form of the same fight.