From "It Works on My Machine" to Shipping Code That Works Everywhere
- Felipe Leite
- 13 hours ago
- 5 min read
I used to be that person. The one who would share a GitHub link with full confidence, then spend the next hour in a Slack thread trying to figure out why it wouldn't run on anyone else's machine.
"Did you install the right Python version?" "Try downgrading pandas." "Oh, I forgot to mention you need that other library too."
It was embarrassing — not because I didn't know how to code, but because I hadn't yet learned that working code and *shareable* code are two very different things. Docker is what bridged that gap for me. And once I understood it, I realized it wasn't just solving a developer inconvenience. It was solving a business problem hiding in plain sight.
The Moment It Clicked
I was working on a data pipeline project I was genuinely proud of. Clean SQL, solid Python, good documentation. I sent it to a friend to review and thirty minutes later got a message: "I can't even get it to start."
The problem was something I hadn't even thought about. My code depended on a specific version of a library that had changed its API in a recent update. On my machine, the old version was installed and everything worked perfectly. On his machine, the new version was installed and nothing worked at all. I spent more time fixing that than I had spent writing the pipeline itself.
That's when I started taking Docker seriously — not as an advanced DevOps concept for engineers building at scale, but as a basic act of respect for anyone who would ever touch my code, including future me.
What Docker Actually Does
Docker packages your code together with everything it needs to run: the Python version, the libraries, the configuration. That bundle is called a **container**. It runs identically on your laptop, a teammate's machine, a cloud server, or a recruiter's computer. No setup instructions. No version conflicts. No broken environments.
The shipping container analogy is overused in tech writing, but it earns its place here. Before standardized containers, every port handled cargo differently — different crates, different loading methods, different problems. One global standard changed trade overnight. Docker does the same thing for software: one format that runs anywhere.
The three core concepts are straightforward once you see how they connect:
- Dockerfile: A text file with instructions for building your environment. Which base Python image, which libraries to install, which command to run. Think of it as a recipe.
- Image: The snapshot built from that recipe. Portable, shareable, stored on Docker Hub like code is stored on GitHub.
- Container: A running instance of that image. Your application, live, with everything it needs already inside it.
The Business Impact Nobody Tracks
Here's what surprised me most when I started thinking about this professionally: environment problems are expensive, and most companies don't even measure the cost.
Consider how often these scenarios play out in a real data team. A data scientist spends half a day onboarding because the environment setup instructions are six months out of date. A pipeline fails silently in production because a library auto-updated overnight and changed its behavior. A model that performed beautifully in development produces different results in staging, and nobody can explain why. A client demo fails because the presenter's machine has a different OS than the one the project was built on.
These are not edge cases. They happen constantly. And the cost — in engineering hours, stakeholder trust, and potential downtime — adds up fast.
Docker addresses all of them by making the environment part of the deliverable, not an assumption. Teams that containerize their workflows ship faster, onboard new members in minutes instead of days, and spend less time on environment archaeology and more time solving actual problems. In regulated industries like finance and healthcare, the stakes are even higher: reproducibility is often a compliance requirement. Being able to prove that a model ran in a specific, documented environment on a specific date is not optional — it is an audit trail.
The Technical Impact: Discipline as a Side Effect
From a technical standpoint, Docker introduces a discipline that improves code quality without trying to. Writing a Dockerfile forces you to be explicit about things you'd otherwise leave implicit: which Python version? Which exact library versions? What command starts the application?
That explicitness, encoded in a `Dockerfile` and a `requirements.txt`, is documentation that never goes out of date because it is also the thing that runs your code. You cannot have a working container with a broken setup guide — they are the same file.
Combined with Git, the workflow becomes genuinely powerful. Your code is versioned. Your environment is versioned. Anyone can check out a commit and reproduce not just the code but the exact conditions it ran in — months or years later. That is a level of reproducibility most projects never achieve.
A typical containerized data project looks like this:
my_project/
├── Dockerfile ← defines the environment
├── requirements.txt ← pins exact library versions
├── .dockerignore ← keeps data and secrets out of the image
├── docker-compose.yml ← spins up the full stack (app + database) with one command
└── src/
└── main.pyThe result: a colleague clones the repository, runs `docker compose up`, and has the entire project running in under a minute. A hiring manager can pull the image from Docker Hub and see the work live without installing anything. A production deployment is a matter of pushing the same image that was already tested in development — no surprises.
The First Time It Worked
The first time I added a Dockerfile to a project and asked someone to test it, the whole conversation was two messages:
"Here's the repo."
"Works perfectly."
That was it. No troubleshooting. No version archaeology. No apologies. Behind the scenes, Docker had bundled the Python version, every library at exactly the version I'd used, and the command to start everything. The other machine didn't need to know any of that. It just ran the container.
That conversation is still the best argument I know for learning Docker early.
What It Looks Like in a Portfolio
Adding Docker to a portfolio project sends a clear signal. It says you think beyond "it works on my machine." It says you understand reproducibility, deployment, and collaboration. In a field where many candidates can build a model but fewer can ship one reliably, that distinction matters more than most people realize.
I've been applying this across my own projects — integrating Docker with Git workflows, pairing it with SQL database design, and building full reproducible environments for data pipelines. If you want to see it in practice, the full guide and project files are on GitHub:
The learning curve is real but short. The Dockerfile for a simple data project is maybe twenty lines. Generating a `requirements.txt` takes thirty seconds. Once you write the first one, the pattern repeats across every project with minimal effort.
What I'd Tell My Past Self
Start earlier than you think you need to. Not because Docker is complicated — it isn't — but because the habit it builds is valuable. Once you start asking "how would someone else run this?" from the beginning of a project instead of at the end, you write better code, better documentation, and better projects overall.
I'm still that person who sends GitHub links with full confidence. But now, the message that comes back is just someone saying it worked.
That's the whole point.

Comments