My earliest lessons in system design didn’t come from drawing architecture diagrams. They came from supporting software that was already running a real business. At MicahTek, a change could affect donation processing, call-center workflows, reporting, or years of transaction history. At Clicks, the production systems connected registration, payments, squadding, scoring, and payouts. I learned that a system isn’t reliable because its diagram has enough boxes. It’s reliable when you understand what the business can’t afford to lose, duplicate, expose, or leave in an inconsistent state.
What MicahTek taught me
Most of what I worked on there had already been running for years: databases holding millions of donation and transaction records, a legacy ecommerce and CMS platform built in ColdFusion, an older PHP application, and Pick BASIC and UniVerse systems underneath parts of the reporting. Documentation was limited, so I often had to follow the data and code to understand how a workflow really operated. The way I actually learned what the business depended on was by tracing business rules through whichever layer still held them — sometimes a ColdFusion template, sometimes a Pick BASIC subroutine, sometimes a stored procedure whose original context was no longer documented.
One of the more useful, less glamorous lessons came from Crystal Reports. Reports that used to time out or lock up other users got faster once I understood which columns they actually filtered and sorted on, added the right indexes, and moved some of the reporting logic into stored procedures instead of letting the report engine do the heavy lifting. The solution wasn’t a large architectural change. It came down to understanding the queries the reports generated and fixing the actual database bottlenecks.
The bigger lesson was about where truth lives in an old system. The code doesn’t always tell you what the business does — sometimes the schema does. A table’s constraints, its indexes, which columns are nullable and which aren’t, tell you what previous developers actually enforced versus what they just hoped for. I got into the habit of reading the schema alongside the application code, because it often revealed rules that weren’t documented anywhere else.
What Clicks taught me
Clicks gave me my strongest experience with modern production systems — Angular, Node.js, and MySQL, running live for real users, not a diagram.
A production race condition there reinforced something for me. A timer-driven workflow could freeze because multiple pieces of state were no longer agreeing about what had completed. The eventual fix wasn’t more infrastructure. It was correcting the reactive state flow so the interface derived its behavior from one consistent source instead of several that could drift apart. After release, users reported faster operation and the issue didn’t recur. That experience taught me to look carefully for duplicated state and unclear ownership whenever I investigate a similar problem.
The rest of my time there involved practical problems: optimistic updates with rollback, so the interface could feel fast without lying about what had actually happened on the server; verifying payment webhooks with HMAC-SHA256 signatures, so a request claiming to be from the payment provider actually was; background image processing and geocoding jobs that didn’t belong in the request path; and the usual authentication, transactional database work, and deployment troubleshooting that comes with keeping a real application running.
What freelance work taught me
Freelance work gave me a different kind of responsibility. For Gallery Design Studio, I built and deployed the original MVP for what became eShelf, a digital asset management platform — a PHP application on AWS, built to validate the concept before anyone committed to a full production build. There was no existing architecture to follow; I had to understand the client’s workflow and decide how that first version should work.
Once the concept held up, the project moved into a full build with an outsourced engineering team, and I stayed on as technical lead — defining requirements, writing tickets, and directing feature scope as the platform was rebuilt on Vue/Nuxt.js and Express. I also stayed hands-on on the frontend: I built the homepage’s asset-search experience, the folder and card browsing UI, and contributed to drag-and-drop upload support, along with fixing production issues like a GIF upload failure that was silently breaking uploads.
That project taught me something different from maintaining legacy software: starting from a blank page doesn’t mean starting with technology. It means first understanding how people currently work, where their files and data need to move, and what the system must continue doing when an upload, background process, or external service fails. It also taught me that a system’s architecture can outlive the person who reasoned it out first — which only works if the team taking it over actually understands the constraints it was built for, not just the code.
What JobTrack is teaching me
JobTrack is different from the other projects: it’s a personal project rather than production software supporting a client or employer. It’s built on ASP.NET Core and EF Core, deployed to Azure SQL and App Service, with secrets in Key Vault behind a managed identity, Application Insights for telemetry, an Azure Function for follow-up reminders, and an Azure DevOps pipeline for deployment. JobTrack hasn’t operated at enterprise scale. I’m using it to practice the architectural decisions that become important as a system grows.
Even at its current size, the project has been useful for working through architectural boundaries. In JobTrack, I explored a version of the same problem the Clicks race condition taught me to watch for: discovering that a reminder is due and actually delivering it need to be separate operations. If delivery fails, the reminder has to stay recoverable instead of silently disappearing. At larger scale, I’d likely introduce a durable queue and a transactional outbox to make that separation solid. JobTrack doesn’t need that infrastructure yet — a single scheduled function and a straightforward reminder table are enough at its current size — but designing the boundary now, even without the queue behind it, means the request path never becomes responsible for every way delivery can fail later.
Twelve years in, I can see the connection across these experiences. MicahTek and Clicks taught me how to understand and improve systems that already had users, data, and businesses depending on them. The Gallery Design Studio project gave me the opportunity to prototype something from nothing and then lead its transition into a full production build with a team. JobTrack has given me another place to apply those lessons while expanding into ASP.NET Core and Azure. Whether I inherit a system or start with a blank page, I begin in the same place: understand how people use it, identify what cannot be allowed to fail, and choose the simplest design that protects those things.