Skip to main content
// JH

· 7 min read

The Patterns From My First Job

Inherited a Zend Framework codebase from day one. Found the adapter pattern before I knew what it was called. Docker before Melbourne believed in it. The instincts that formed when I was twenty-two.

API Design · Docker · Early Career · Patterns · Testing · Melbourne

Late 2014. I was twenty-two, sitting in an apartment in the Philippines, reading a codebase I hadn't written. ECAL had just closed a $2M Series A from Oxygen Ventures. The Melbourne team needed a developer who could work their hours from Southeast Asia. I was that developer — remote, junior, and inheriting a Zend Framework admin dashboard and jQuery MVP widgets that I was supposed to understand well enough to extend.

An octopus at a desk, reading inherited code alone in a vast dark space — a single monitor's glow the only light

I'd been hired to work on the product. The first thing I was asked to do was something else entirely.

Capitol Grand Hotel needed a social media feed on their WordPress site. Pull posts from Facebook, Twitter, Instagram, and their blog. Display them in a unified stream. The team needed it done. I was the available developer. That was the logic.

I remember thinking: this isn't what I'm here for. I was wrong about that.

Four APIs, One Shape

An octopus with four tentacles each grasping a different colored cable — Facebook, Twitter, Instagram, WordPress — converging into one clean output stream

The Capitol Grand Hotel feed looked simple on paper. In practice, Facebook's Graph API required OAuth tokens that expired unpredictably and returned nested JSON that changed shape depending on which fields you requested. Twitter's REST API had aggressive rate limits and a completely different authentication model. Instagram's API was severely restricted — limited endpoints, limited data, limited everything. And WordPress was its own thing entirely, with conventions that matched none of the others.

Four platforms. Four authentication flows. Four data shapes. Four failure modes. The naive approach is to write four separate integrations and stitch the results together. That works until one platform changes its API — which they did constantly — and suddenly you're rewriting integration logic that's tangled with presentation logic.

What I built instead was a single interface. One contract that all four platforms conformed to. Each platform got an adapter that translated its specific chaos into one clean, normalized shape. The consuming code didn't know or care whether a post came from Facebook or Instagram. It just knew it had a post with a timestamp, content, media, and a source.

One shape. Four messy realities behind it.

I didn't read about the adapter pattern in a textbook and decide to apply it. I built it because the alternative — four special cases threaded through the entire codebase — felt fragile. The unified interface felt right. That was the first time I experienced the satisfaction of making a messy problem disappear behind a clean abstraction. I didn't have vocabulary for what I'd done. I just knew the code was better and I couldn't fully explain why.

I've used that same instinct on every messy system since. At TitanFX years later, the developer tools I built were translation layers that normalized inconsistent internal systems behind single contracts. Find the chaos. Design the interface. Make the mess invisible to everything downstream. I learned it at twenty-two, on a hotel social feed I hadn't expected to build. I still reach for it a decade later.

A Bet I'd Already Made Once

The ECAL product was the work I'd been hired for. A calendar widget platform running on Zend Framework and jQuery, and the team was modernizing it to Laravel and AngularJS. The stack migration was significant, but the decision that raised the most eyebrows had nothing to do with frameworks.

I introduced Docker.

This needs context, because "I introduced Docker" in 2026 sounds like "I introduced electricity." In 2015, Docker was not what it is now. Docker-compose didn't exist in any mature form. The documentation was incomplete. The tooling was rough. Almost nobody in Melbourne's startup scene was using it. When I proposed it, the reaction was polite skepticism. Why are we adding this complexity? What's wrong with MAMP?

But I'd already lived through Docker's worst version. My thesis the year before had run on Docker 0.8 — no compose, primitive networking, documentation so sparse I spent hours reading Go source code and asking questions in IRC channels. I'd built a custom orchestration layer over containers that changed their API between minor releases. The rough edges weren't theoretical to me. I'd already bled on them.

What I knew from that experience was that the problem Docker solved — "it works on my machine" — was permanent, even if the solution was still rough. Every developer on the ECAL team had a slightly different local environment. PHP versions didn't match. MySQL configs differed. Something would work locally and break on staging. Hours lost debugging environment differences instead of building features.

I pushed for it anyway. Setting it up was rough. Teaching the team was slow. There were days when the skeptics seemed right.

And then one day, "it works on my machine" stopped being a sentence anyone said.

That pattern — discovering a tool early, living through its rough edges, then bringing it to a team once I understood it — started with my thesis in 2014 and repeated at ECAL in 2015. It wasn't the last time.

The Gate Nobody Saw

An octopus at a doorway between a dark space of scattered test scripts and a warmly lit workspace — handing readable documents to people on the other side

The other thing I introduced at ECAL was Codeception with Gherkin syntax for the test suite. This sounds boring. It wasn't.

Gherkin lets you write test specs in plain English. "Given I am on the calendar page. When I click the export button. Then a download should start." A developer can read that. A non-developer can also read that. That was the point.

The QA team at ECAL weren't developers. In most shops in 2015, QA got handed test scripts written by developers and told to follow them step by step. They were executors, not participants. They couldn't suggest new test cases because they couldn't read the existing ones. They were locked out of the process by the language it was written in.

The Gherkin decision is the one I think about most. Not because it was technically impressive — it was a syntax choice. But once the QA team could read the test specs, they started contributing. They'd spot gaps. "What about when the user has no events? What about when the timezone changes?" They knew the product better than the developers did in many ways. They just hadn't been given a format that let them participate.

The fix for "QA isn't catching enough edge cases" wasn't better QA. It was a different syntax. The problem was never the people. It was the gate.

What Survived

These weren't achievements on a resume. They were instincts forming.

The instinct to normalize chaos into clean abstractions. The instinct to adopt tools before consensus, when they solve a real problem. The instinct to include non-technical people in technical processes by meeting them where they are.

The technology from that year is dead. AngularJS is dead. That version of the Facebook API is dead. The specific PHP patterns I wrote are patterns I'd never write today. But the instincts aren't dead. I still reach for the unified interface when I encounter messy systems. I still bet on unproven tools when the pain they address is real. I still look for ways to include people who are being excluded by unnecessary technical barriers.

The code from 2015 is long gone. The patterns survived.

And here's what I still wonder about. Pattern recognition rewards itself — you see the shape once, it works, and you start seeing it everywhere. But at what point does "I've seen this before" stop being experience and start being a bias? The patterns I trust most are the ones I learned when I had the least to lose and the most to prove. I was twenty-two, twenty-three by the time the year was out, working from Southeast Asia for a team I'd only ever seen on a screen.

I think about that inherited codebase sometimes. Zend Framework, jQuery widgets, decisions made by people who'd moved on before I arrived. Some days the work still feels exactly like that.

Enjoyed this post?

Subscribe to get weekly deep-dives on building AI dev tools, Go CLIs, and the systems behind a personal intelligence OS.