Moving from pages to programs: my first real application
Software
Discover how the foundational lessons from building a first simple web application in PHP/MySQL directly apply to the architectural challenges of modern data and AI systems.
The browser’s refresh button was my first deployment pipeline. I’d edit an HTML file, save it, upload it, and hit F5. My first websites were just documents, hyperlinked text files dressed up with CSS. They were static, lifeless things. They could talk, but they couldn't listen.
The leap to building a true application felt like breaking through a wall. It wasn't about learning a new syntax. It was realizing the web page wasn't the destination; it was just the surface of a much deeper machine. A machine I now had to design, build, and keep running.
From Documents to Processes
My first real project was a simple book catalog for a friend. The goal was trivial by today's standards: add a book, see the list. But building it forced a complete mental refactoring. A static page is a resource you fetch. An application is a process you execute.
The form’s action attribute was the pivot. It couldn't point to another .html file. It had to point to a program. This was the moment the server stopped being a file host and became a computer I could command. You are no longer just arranging content; you are an architect defining behavior. The user’s click isn’t a link, it’s a trigger for a cascade of events they will never see.
State: The System's Memory
To make the catalog work, I chose an early version of PHP. The code could receive data from the form—but it existed only for the brief moment the script was running. The system had a brain, but no memory. To fix this, I installed MySQL and created a single books table. This was the real transformation: I was no longer managing code, I was responsible for data.
This is the core of an application. Not the UI, but the management of state. That simple database connection was a revelation, but it also introduced the foundational problem of distributed systems, a concept formalized years later in works like Eric Brewer's CAP Theorem. My single point of failure was the database connection; in modern data and AI systems, state is distributed across countless nodes, and managing its consistency and availability is the central architectural challenge.
The Read-Write Loop as a Pattern
With the database in place, the final piece clicked. I had to build both sides of the application loop:
- The Write Path: Handle the form submission, validate the input, and write the new book to the database.
- The Read Path: On page load, query the database for all books and dynamically generate the HTML to display them.
I didn't know it then, but I was crudely implementing a pattern of separating concerns. The data (the book), the logic (the PHP script), and the presentation (the generated HTML) were distinct parts. This is the same core idea behind durable patterns like Model-View-Controller, which practitioners like Martin Fowler would later catalog and define. My single PHP file was a messy template and renderer in one, but the principle was sound: generate the view from the current state.
How Simple Loops Evolve into AI Pipelines
That primitive read-write loop is the direct ancestor of the complex systems I architect today. The "write path" is now a sophisticated, deterministic data pipeline—ingesting events, validating schemas, and transforming data for storage. The "read path" is a serving layer that exposes data through an API or powers a machine learning model endpoint.
Owning that entire loop taught me about data responsibility. This concept has scaled dramatically. In modern data architecture, ideas like Zhamak Dehghani's Data Mesh advocate for distributing this ownership across domains, treating data as a product. It's the same principle of owning the loop, but applied to the massive, decentralized data ecosystems that feed today's AI.
The architecture is more complex, but the flow is the same. We take inputs, run them through a series of processes (some deterministic, some agentic), update a persistent state, and serve a result.
Lessons That Scale to Agentic Systems
The technologies have changed completely. But the fundamental concepts I learned from that book catalog are the ones that have lasted. They are the takeaways that matter when building systems where LLM agents and deterministic automation cooperate.
- Systems think in loops. The request-response cycle is the heartbeat. For an LLM agent, this becomes the observe-orient-decide-act loop. The architecture must support this iterative process, managing state between each turn.
- State is the hardest part. A single MySQL table was my challenge then. Today, it’s managing the context window of an LLM, persisting conversational history, and synchronizing state across a fleet of stateless agent workers using vector databases. The problem is the same, just at a different scale.
- Separate process from presentation. My old script separated data from HTML. Today, we must separate an agent's reasoning process—its chain of thought—from the final, polished output it presents to a user. This is crucial for observability and debugging.
- Trust nothing. I learned to validate user input to prevent SQL injection. The modern equivalent is validating the output of a non-deterministic LLM. Its tendency to hallucinate makes every response a potential failure point that the surrounding deterministic system must handle gracefully.
Moving from pages to programs is the real starting line. It’s where you stop describing things and start building machines that do things. The patterns you learn there—about loops, state, and validation—don't become obsolete. They just get a new name.