06

Building Software That Lasts

Building an application is one thing. Living with it, evolving it, and supporting it for more than a decade teaches you something entirely different about software.

Company
OpDeTop LLC
Goals Management Software
Role
Lead Developer
Application Architecture & Ownership
Technology / Skills
Angular, PHP, Yii, AWS, Docker
Ownership

Long-Term Application Ownership

It’s relatively easy to feel confident about an architectural decision when an application is new but the harder test comes five years later.

Or ten.

I was first introduced to this project in 2011 while working at Industrial Wisdom. It began as a goal-setting platform designed to help people identify, organize, and work toward meaningful goals across four areas of their lives: Health & Fitness, Money & Financial, Family & Personal, and Business.

I was the lead developer and responsible for building the application from the ground up and what I couldn’t have known then was that I would still be working with the software more than a decade later. During that time, the application gained new features, new business models, new infrastructure, new deployment processes, and eventually pieces built with technologies that didn’t even exist when I wrote its original code.

I also got something developers rarely receive: More than ten years of feedback on my own engineering decisions.

Choosing the Original Foundation

The original application was built with Yii, PHP, MySQL, JavaScript, and Bootstrap.

At the time, Yii was a strong choice for the kind of application we were building. It provided an MVC architecture, database abstractions through Active Record, validation, authentication and authorization capabilities, form handling, and a structured approach to building a substantial PHP application without requiring us to invent all of that infrastructure ourselves.

Bootstrap solved a similar problem on the frontend. It gave us a consistent responsive foundation at a time when creating application interfaces that behaved predictably across screen sizes and browsers still required considerably more manual work than it does today.

As lead developer, those were deliberate choices.

I wasn’t trying to choose technologies that would still be fashionable a decade later. I wanted a foundation that would let us build the product effectively with the tools available at the time but the idea was that while some of those technologies would eventually age, the application didn’t have to age with them.

Building the Product

The core of the application was a fairly substantial goal-management system where users could establish goals across four categories and then organize the work required to pursue them. The product wasn’t intended to be a static list of aspirations. It needed to help people think through what they wanted, establish priorities, and continue interacting with those goals over time.

That meant much of the application needed richer client-side behavior than traditional server-rendered PHP pages provided comfortably at the time. So I built a custom JavaScript class library to manage those dynamic behaviors throughout the application.

That library became particularly significant because it wasn’t a temporary solution as it continued supporting interactive portions of the product throughout much of the application’s lifetime.

Over the years, the feature set grew considerably beyond the original goal-management experience.

Growing With the Business

One of the benefits of owning an application for a long time is that you stop thinking about features as isolated deliverables because every new feature has to become a neighbor to everything that already exists.

We introduced an interactive Dream Board where users could create a more visual representation of what they wanted to accomplish. That eventually included image and audio uploads, transforming it from a simple collection of goals into a much richer multimedia experience.

I also built a Goals Assistant that guided new users through defining their first five goals across the application’s four major categories. Instead of dropping someone into an empty application and expecting them to understand the system, the software could help them take the first steps.

As the business expanded, the platform needed to support more than individual users.

I developed affiliate and sponsor functionality and we created brandable versions of the application that coaches and sponsors could offer to their own audiences. I also added user metrics so the business could better understand membership and how people were interacting with the product.

Each of those features changed the application but they couldn’t be allowed to destabilize everything that came before them. Because when you maintain the same application for more than a decade, every architectural shortcut eventually sends you an invoice.

That may be the biggest difference between building software and truly owning it.

From Developer to Owner

After Industrial Wisdom was acquired by Numeric Analytics, my relationship with the project changed.

I received permission from the company’s president to continue working with the application independently in my free time and the company behind the product, OpDeTop LLC, became the first client of BetaVault Creative.

That transition was meaningful to me for reasons beyond simply starting a business.

I went from being the developer responsible for a project inside another organization to being responsible for virtually everything on the development side of an application that a client depended upon. There wasn’t another team waiting downstream to solve infrastructure problems. There wasn’t someone else who owned the deployment process. When a new feature was proposed, I had to think about how it affected the database, backend, frontend, existing users, infrastructure, deployment process, and future maintenance.

That kind of ownership changes the way you write software.

Moving Into AWS

The infrastructure evolved too.

Eventually I migrated the application into AWS, using services including EC2, S3, and ECS that represented another important stage in the application’s life. Instead of treating infrastructure as something separate from application development, I increasingly began thinking about deployment, storage, hosting, and application architecture as parts of the same system.

S3 was particularly useful as the product’s multimedia capabilities expanded. Features such as the Dream Board introduced user-generated assets that needed to be stored and managed differently from the application itself.

Containerized workloads and AWS infrastructure also gave me better options for evolving how the application was deployed without requiring the product itself to be rewritten.

And that became an increasingly important theme:

Modernizing the application didn’t have to mean replacing the application.

Introducing Angular Without Rewriting Everything

Years after the original application was created, the frontend landscape looked completely different.

Angular had become one of the technologies I worked with most extensively, and some of the application’s richer interactive experiences could clearly benefit from the component architecture and tooling it provided.

The tempting solution would have been a complete frontend rewrite but the existing application represented years of working functionality. Replacing all of it simply to adopt a newer framework would have introduced enormous cost and risk without necessarily providing equivalent value.

Instead, I used Angular Elements to introduce Angular selectively.

That allowed newer Angular components to coexist with the existing Yii application.

The Dream Board was an excellent candidate because its highly interactive behavior, multimedia features, and increasingly complex interface benefited from a component-based architecture. So I rebuilt that experience in Angular rather than attempting to force the entire application through a framework migration.

The result was modernization at the boundaries where modernization actually provided value because the PHP/Yii application didn’t need to disappear for Angular to make part of the product better.

Evolving Instead of Rewriting

That approach became one of the most important lessons I took from maintaining this application because as a developer I naturally like clean beginnings. A new repository is appealing because there are no old compromises. Every dependency can be current. Every pattern can reflect what we know today but real software rarely gives us that luxury.

Applications accumulate history because businesses accumulate history.

Users depend on existing behavior. Data has to survive. Integrations exist. Features that look strange from the code may represent a business requirement nobody remembers until it disappears. And after years of maintaining the same application, I became much less interested in rewriting software simply because I could imagine a cleaner version.

Instead, I learned to ask:

Which part is actually preventing us from moving forward?

Sometimes that meant changing infrastructure. Sometimes it meant automating deployment. Sometimes it meant refactoring old JavaScript. Sometimes it meant introducing Angular for one particularly complicated interface. And sometimes the answer was to leave working code alone.

That’s not resistance to modernization.

It’s understanding the difference between modernization and replacement.

Living With My Own Decisions

One of the unusual things about this project is that I couldn’t simply hand off my architectural decisions and move on. Instead I had to live with them.

Years later, I encountered abstractions I’d created as a younger developer. Some held up remarkably well. And yet others showed their age. Some decisions made future features easier. And yet others taught me exactly why I wouldn’t solve the same problem that way today.

That’s an incredibly valuable feedback loop.

When developers move between projects every year or two, it can be difficult to know what “maintainable” really means. Code may look beautifully organized when it’s written, but maintainability isn’t determined at the moment of implementation.

It’s determined by the next developer trying to change it. And sometimes by the same developer returning to it ten years later wondering what his younger self was thinking.

Long-term ownership gave me a much stronger appreciation for clear boundaries, predictable behavior, documentation, automation, backwards compatibility, and resisting unnecessary cleverness.

More Than Ten Years Later

It began as a Yii and Bootstrap application but it evolved far beyond that and through all of those changes, the application continued serving the same underlying purpose.

It Continues to Evolve

Over its lifetime, this application moved through multiple generations of web development and that as been what I find most satisfying about the project.

The architecture wasn’t frozen for more than a decade.

It survived by being allowed to grow.

What Long-Term Ownership Taught Me

Building this application taught me plenty about PHP, JavaScript, Angular, AWS, automation, containers, and application architecture.

Maintaining it taught me something more important.

Software engineering isn’t just about designing systems for the requirements you understand today. Instead it’s about leaving enough room for requirements you haven’t imagined yet.

You can’t predict what frameworks will exist ten years from now. You can’t know which product idea a client will have five years from now. You can’t guarantee that an architectural decision that seems perfect today won’t eventually become something you need to replace.

What you can do is build clear boundaries, automate what should be repeatable, avoid unnecessary coupling, and make changes in ways that leave the next change possible.

After more than a decade with the same application, my definition of good architecture became much simpler: Good software doesn’t have to remain unchanged. It has to remain changeable.

And perhaps that’s what building software that lasts actually means.

More Case Studies

Different problems, different constraints, and different kinds of solutions. Here’s another project from the collection.

Have a Complicated Problem of Your Own?

If you’re working with a system where the details really matter—or you’ve run into a problem that doesn’t have an obvious answer—I’d be happy to hear about it. You don’t need to know the solution before reaching out. Figuring that part out is often the most interesting part of the work.