I Don't Just Write Code: What It Means to Own a Software Product From Code to Cloud
When people hear “software developer,” they often think about writing code.
You open an editor, write some PHP, JavaScript, or React, fix a few bugs, push the code to Git, and the job is done.
At least, that is how it can look from the outside.
But when you build and maintain software yourself, you quickly realise that writing the code is only one part of the job.
A real software product doesn't end when the code compiles. It has to run somewhere. It needs a database. It needs a domain and SSL certificate. It needs backups. It needs monitoring. It needs deployments. It needs to survive traffic, server failures, permission problems, expired certificates, broken dependencies, and occasionally the mysterious production bug that somehow never appeared on your local machine.
Over time, I've realised that I don't really see myself as someone who simply writes code.
I like to own the entire journey of a software product—from code to cloud.
The code is only the beginning
Most of my projects involve technologies such as Laravel, React, Inertia, MySQL, Node.js and various server-side tools.
Writing the application is obviously an important part.
I need to understand the requirements, design the database, build APIs, create interfaces, handle authentication, implement business logic and make sure everything works together.
But after the application is built, there is another question:
Where is it going to run?
That's where things become much more interesting.
A perfectly working application on localhost means very little if it cannot be deployed properly.
The production environment introduces a completely different set of problems.
PHP versions can be different.
File permissions can be wrong.
Environment variables may be missing.
Nginx may not be configured correctly.
A queue worker may not be running.
A WebSocket connection may fail behind a reverse proxy.
SSL certificates may expire.
A scheduled task may silently stop working.
And suddenly, the developer who only wanted to build a feature is debugging the entire server.
I've learned to embrace that part of the job.
From localhost to production
One of the biggest lessons I've learned is that development and production are two different worlds.
Locally, I control almost everything.
I know which PHP version I'm using. I know where my files are. I know my database configuration. I can restart services whenever I want.
Production is different.
There may be multiple applications sharing the same VPS. Different applications may require different PHP versions. Nginx has to route domains correctly. SSL has to work. Queue workers need to stay alive. Node processes may need PM2 or another process manager. Database users need the right permissions.
And then there is DNS.
Sometimes the application is perfectly fine, but the domain simply isn't pointing where it should.
Other times, Cloudflare is involved and a configuration that worked without a proxy behaves differently after the proxy is enabled.
These aren't necessarily programming problems.
But they're still software problems.
And if I own the product, I can't simply say, “That's a server issue.”
The server is part of the product.
I want to understand the infrastructure behind my applications
This is one of the reasons I've spent considerable time working with VPS servers.
Instead of treating the server as a black box where someone else installs my application, I prefer understanding what is happening underneath.
That includes things like:
- Nginx configuration
- PHP-FPM
- MySQL/MariaDB
- SSL certificates
- DNS
- Linux permissions
- Cron jobs
- Supervisor
- PM2
- Queue workers
- WebSockets
- Cloudflare
- Git-based deployments
- Server backups
I don't need to configure every server manually forever.
In fact, the goal is the opposite.
The more I understand the infrastructure, the more I can automate it.
Automation becomes necessary very quickly
When you have one application, manually doing things isn't always a big problem.
When you have several applications, it becomes painful.
Deploying code manually.
Running migrations manually.
Restarting workers manually.
Renewing certificates manually.
Checking logs manually.
Creating databases manually.
Taking backups manually.
Doing these things once is fine.
Doing them every week—or every day—is not.
That's where automation becomes important.
I've gradually moved toward scripts, deployment processes, process managers and eventually tools of my own.
One example of this thinking is Q-Panel, my attempt to build a VPS management solution around the things I actually need while managing applications.
The motivation isn't simply “I want to build another panel.”
It's more practical:
If I repeatedly have to solve the same infrastructure problem, maybe the solution should become software.
Sometimes the tool you need doesn't exist in the way you want
This is something I've experienced repeatedly while building products.
You start with a simple requirement.
Then you discover another requirement.
Then another.
Eventually, you realise that the existing tools don't quite fit your workflow.
At that point, there are usually three choices:
- Change your workflow.
- Find another tool.
- Build what you need.
I don't always choose option three.
Building software has a cost, and using an existing reliable solution is often the smarter decision.
But when a problem is closely connected to the products I'm building—and when solving it can save time repeatedly—I find building the solution worthwhile.
That's how some of my product ideas have evolved.
A small problem becomes a small tool.
The tool becomes a product.
And the product eventually becomes part of a larger ecosystem.
Owning a product also means owning the failures
This is probably the less glamorous part of software development.
When everything works, nobody notices the infrastructure.
The application loads.
Users log in.
Orders are processed.
Emails are sent.
Notifications arrive.
Everything seems normal.
But when something breaks, suddenly every layer matters.
Maybe a deployment changed a file permission.
Maybe a queue worker stopped.
Maybe a certificate expired.
Maybe a database connection failed.
Maybe an Nginx configuration was incorrect.
Maybe a dependency changed.
Maybe the application worked perfectly in development but produced a completely different error in production.
That's when you learn the most.
I've had my share of these problems.
And although production errors are frustrating, they have taught me something valuable:
You understand software much better when you are responsible for keeping it alive.
A software product doesn't end at deployment
Deployment is often treated as the finish line.
For me, it is closer to the starting line.
Once a product is live, there are new responsibilities.
You need to think about:
Reliability
Can users access the application when they need it?
Security
Are credentials protected? Are permissions correct? Are dependencies updated?
Backups
If the server disappears tomorrow, can the application and its data be restored?
Performance
What happens when the number of users increases?
Monitoring
How do you know something broke if nobody tells you?
Maintenance
What happens six months after the application was launched?
Cost
Is the infrastructure still financially sensible as the product grows?
These questions aren't necessarily answered by writing more application code.
But they are still part of building software.
The cloud is just another part of the stack
I used to think about development and hosting as two separate things.
Today, I see them as connected layers.
There is the application.
Below it is the runtime.
Below that is the operating system.
Then the server.
Then the network.
Then DNS.
Then the external services that the application depends on.
Something as simple as opening a webpage can involve all of these layers.
A user enters a domain.
DNS resolves it.
The request reaches the server.
Nginx handles it.
PHP-FPM executes the Laravel application.
Laravel communicates with the database.
The response travels back through the server and network.
If something goes wrong anywhere along that chain, the user experiences it as:
“The website isn't working.”
Understanding that entire chain makes debugging much easier.
Building products has changed how I write code
Infrastructure experience has also influenced how I build applications.
I think more about failure.
What happens if the API is unavailable?
What happens if an upload fails?
What happens if a queue job runs twice?
What happens if a user closes the browser halfway through an operation?
What happens if a third-party service changes?
What happens if the database becomes temporarily unavailable?
What happens if the application needs to move to another server?
Good software isn't software where nothing ever goes wrong.
That's impossible.
Good software is software that expects things to go wrong and handles those situations gracefully.
I also care about the business behind the software
Another difference between building a project and owning a product is understanding why the software exists.
A feature isn't valuable simply because it is technically impressive.
It has to solve a real problem.
I've worked on software involving areas such as business management, healthcare, education, communication, travel and infrastructure.
Each domain has different requirements.
A feature that makes sense technically may not make sense operationally.
Sometimes the best solution isn't adding another feature.
Sometimes it is simplifying an existing workflow.
Sometimes automation is useful.
Sometimes automation creates more problems than it solves.
The more I work with real businesses, the more I realise that software development is as much about understanding the problem as it is about writing the solution.
Code → Server → Product
Today, I think about my work in three broad layers.
1. Code
This is where the application is created.
Laravel, React, APIs, databases, authentication, business logic and interfaces.
2. Infrastructure
This is where the application lives.
Servers, Nginx, PHP-FPM, databases, SSL, DNS, queues, WebSockets, deployments and backups.
3. Product
This is why everything exists.
Users, workflows, businesses, costs, reliability, usability and actual outcomes.
Ignoring any one of these layers creates problems.
You can have beautiful code running on terrible infrastructure.
You can have excellent infrastructure running a product nobody needs.
Or you can have a useful product that becomes impossible to maintain because the underlying software was poorly designed.
The goal is to keep all three connected.
Why I enjoy building this way
There is something satisfying about taking an idea and seeing it travel through the entire stack.
An idea starts as a conversation.
It becomes requirements.
Requirements become database tables and application logic.
The application becomes a working product.
The product gets deployed to a server.
The server becomes part of an automated infrastructure.
Users eventually start using it.
And then real-world feedback starts shaping the next version.
That entire journey interests me.
Not just the programming part.
Not just the server part.
The whole thing.
From Code to Cloud
I don't claim to know everything about software development, DevOps, infrastructure or product management.
There is always something new to learn.
But one thing has become clear through the projects I've worked on:
A developer's responsibility doesn't necessarily end when the code is pushed to Git.
If you build a product, you should care about what happens after that.
Where does it run?
How does it deploy?
How does it recover?
How is it backed up?
How does it scale?
How does it fail?
How much does it cost?
And most importantly:
Does it actually solve the problem it was built to solve?
That's how I approach software today.
I don't just want to write code.
I want to understand the system around it, build the infrastructure that supports it, solve the problems that appear along the way, and ultimately take responsibility for the product from code to cloud.


