Previous article: Working Inside Japan’s Contract Engineering Services Model
Opening
It has been about twenty-five years since I started working after graduating from school. During many of those years, I also accepted small to medium software development jobs on the side from local companies.
Most of that work was not glamorous. It usually meant building custom internal systems for relatively small organizations, solving very ordinary operational problems that still mattered a great deal to the people using them every day.
The Access Years
In the early years, most of those systems were built with Microsoft Access.
The reason was simple: its cost performance was extremely good.
Access was not an ideal platform if you were thinking about large-scale growth or long-term architectural evolution. It had clear limits in scalability, and once a system began to grow beyond a certain point, its weaknesses became difficult to ignore.
But for the clients I was dealing with at that time, those limits were usually acceptable. The systems were small, the budgets were small, and the business complexity was still within a range that Access could handle without much trouble. In that environment, it was often more than sufficient.
Larger Work, but Not Yet Deliverable Alone
As time went on, some repeat customers started bringing me larger projects with more substantial budgets.
At first that sounded encouraging, but many of those opportunities had to be declined. The problem was not lack of interest. The problem was risk.
If the project size grew too much, the development time became difficult to predict, and once I could no longer guarantee delivery by myself, accepting the work felt irresponsible. I had to think not only about whether I could write the code, but whether I could actually carry the whole project through without creating trouble for the client.
Around that period, I became much more interested in system design quality itself. I was thinking more seriously about architecture, consistency, and how to build systems that could keep working without constant friction.
Ironically, this interest grew at a time when my influence over architecture decisions in my primary workplace was still limited. In corporate projects, there were many cases where I could not freely pursue the design ideas I wanted to explore. That made my independent work feel even more important, because it was one of the few places where I could test my own thinking.
Moving Toward Web Development
I began working seriously on web development a little more than ten years ago.
Before that, when a project grew beyond the level that Access could handle comfortably, I usually chose a two-tier client and server system with MySQL or another OSS database. That was the practical step up I personally used for somewhat larger work, and for quite a while it was the model I relied on most often.
Later, I gradually moved some of that work toward a three-tier client and server style using Java and GlassFish.
That shift mattered for a very practical reason. In the earlier two-tier model, responsibility was always at risk of becoming scattered between the client and the database layer. Once I moved more logic and control to the server side, I could guarantee data more consistently from one place. Validation, processing rules, update order, and transactional consistency all became easier to manage when the server was clearly responsible for them.
I would not say that this solved every problem, but it gave me a stronger sense that the system could protect itself structurally instead of relying too heavily on each client behaving correctly. Looking back, many of the structural preferences I still have today were already starting to take shape during that period.
.NET already existed when I started my career. In theory, it was a very attractive option for me from the beginning.
But at that time it was not free.
That detail matters more than people may remember now. Japan was in the middle of what is often called the employment ice age, the economy was weak, and spending money on development tools as an individual was not a casual decision. Buying software for work was a real financial burden.
I bought Visual C# separately and worked with what I could afford. Visual Studio Professional and MSDN subscriptions often felt out of reach. I do not remember that period with resentment, but I do remember it with a certain heaviness. You wanted to improve your tools and your skills, but every step forward had a cost attached to it.
Still, I kept going. There was not much romance in it. It was simply the normal determination of trying to keep building with the resources available at the time.
Early Architecture Experiments
Even in those early projects, I was already experimenting with ideas that were probably unusual for the scale of work I was doing.
I tried to build OR-mapper-like abstractions. I implemented something close to UnitOfWork. I introduced abstraction layers aggressively, sometimes more aggressively than I should have.
Many of those attempts did not work very well.
Some were too complicated for the actual size of the project. Some created extra structure without enough return. Some were simply immature ideas built before I had enough experience to shape them properly.
But the motivation behind them was real. I was developing alone, and without some degree of automation and structural consistency, the amount of work would quickly exceed the time I could realistically invest. I could not afford to rebuild every pattern by hand each time.
Even then, the systems I delivered were still far cheaper than typical corporate development projects. And despite that lower cost, I often continued supporting them after delivery.
I wrote contracts carefully so that support obligations remained limited, because that was the only responsible way to protect both sides. Still, reality was never as clean as the contract language. If a customer had a problem in a system I had built, I usually ended up responding.
Coding Was Not the Hardest Part
Looking back over the years of solo development, including later periods when I built internal systems alone inside my current company, I do not think writing code was ever the biggest challenge.
The harder problems were environment setup, deployment, and operational maintenance.
Those were the places where work became tense.
The Weight of Deployment
Deployments always carried anxiety.
Even when I prepared carefully, deployment took time. The work involved manual steps. And because I was working alone, there was no independent reviewer checking the final operation from a separate perspective.
Code review quality is naturally limited when one person is responsible for everything. Sometimes mistakes happened.
Each incident taught me something, and after every problem I improved part of the process. But human operations always have limits. You can reduce risk, but if enough work depends on one person performing a sequence of manual steps correctly, you never fully relax.
Domains, Certificates, and New Kinds of Risk
When I started building more web systems, a different category of operational problems appeared.
Suddenly I had to worry about domain expiration and SSL certificate renewal.
Those may sound like minor administrative details, but they were not minor at all. They became real operational risks, because they could break a live service for reasons completely unrelated to the application code itself.
During the PHP era, I deliberately tried to avoid that class of failure by using rental hosting services and relying on provider-managed domains and certificates whenever possible. It was not elegant architecture. It was defensive pragmatism.
Client and Server Update Failures
In the older two-tier client and server systems, I implemented automatic update mechanisms so that client applications could be kept in sync more safely.
Even then, failures still happened. There were cases where administrators forgot to update servers properly, and eventually I would receive an unexpected phone call because the system had stopped working.
Those moments were a reminder that even a good mechanism can fail once it passes through real operating environments.
Why Cloud Became the Turning Point
In the end, many of these operational problems were resolved only after I started running systems on Azure.
Looking back, the main reason I moved toward cloud infrastructure was not fashion, and it was not even raw scalability at first. The strongest motivation was to make deployment and everyday operation safer, calmer, and as close to maintenance free as possible.
That was the real turning point.
How I Operate Now
Today, most of the systems I manage run on Azure. A few still remain on rental servers, but the majority have already migrated.
The deployment flow is now much more controlled. I push to the main branch, deployment runs automatically to staging, I verify the result, and then I swap to production.
I do not think this style of operation is especially rare now. Many engineers probably use some variation of the same flow, with automated deployment to staging, verification, and then a controlled release to production.
That makes production deployment effectively zero downtime in normal cases, and it reduces operational mistakes substantially. The difference compared with the earlier manual periods is large enough that I no longer think of cloud migration primarily as infrastructure modernization. For me, it was an operational safety improvement.
Migrations Still Need Respect
Database migrations still require attention.
But because I usually develop alone, branch conflicts are rare, and migrations are generally manageable. One of the checks I still care about is whether the old code path remains safe after the migration has been applied. That point deserves more caution than people sometimes give it.
The process is much better than it used to be, but it is not something I treat casually.
Closing
In an ideal world, everything would be automated perfectly.
But even if the automation is written as scripts, or someday generated more and more by AI, I still feel uncomfortable letting changes reach production without personally verifying them. I think that instinct is healthy. Responsible engineers confirm critical changes themselves.
Even now, deployments and migrations can still create a small knot in my stomach. Perhaps that tension is simply part of software development. We improve the process, reduce the risks, and build better systems than we had before, but someone still has to look carefully, make the decision, and accept the result.
Previous article: Working Inside Japan’s Contract Engineering Services Model
Next article: AI in Real Development Work