developing code, you often need to test it before pushing to the development or production environment. However, waiting for a deploy with GitHub actions, or CDK stack deploys with CDK, is time-consuming.
Such time-consuming tasks kill iteration speed, which is a critical factor if you want to develop code effectively. This is because you need to test your implementations properly to ensure they work. Then, after each change, you need to test it again.
With the latest coding agents, developing full local testing scripts is super fast, and something I do every day as I write code as a data scientist.
In this article, I’ll take you through why you need to create an efficient local testing setup by running a Docker image and sending test events. I’ll also show how I do it myself, and how it helps me become a more efficient engineer.
I’ll mostly be talking about how to work with Infrastructure as Code (IaC), because that’s mostly what I’m working with on a day-to-day basis. However, the concept of efficiently running your code locally applies to all programming.
This infographic highlights the main contents of this article. I’ll highlight how slow iteration speed limits your ability as a programmer, and how you can speed up development by creating proxy production environments locally. I’ll also highlight how you can give your coding agent access to local testing scripts for even higher iteration speed. Image by Gemini.
Why you need to run code locally
Firstly, I want to cover why we need to run code locally. The simple answer is that:
Iteration speed is one of the most important aspects for efficiently getting working code to production
The faster you can iterate on your code, the better. When you develop new functionality (or fix old functionality), you want to quickly test if it works, and then iteratively fix the code until it works as intended.
If you have to wait 5-15 minutes for your code to deploy before testing it, you have a serious problem. Every time you’re not able to one-shot a problem, you waste 5-15 minutes simply waiting for the deploy.
Instead, you should run your code locally. For example, if you’re working with IaC, such as AWS CDK, you can build and run Docker images locally, essentially replicating the production environment, but on your own computer. This way, the iteration loop is simple, and the time it takes to build the Docker image and run the code.
Building the Docker image is usually very fast, considering Docker caches previous builds. Thus, most of your time is probably spent running the code with test input and verifying the output is as expected.
If you’re working on a web application, you should (and probably are already), running the application locally, before deploying your code. There should be no difference when working with IaC.
How to develop locally as if it were a production environment
An important aspect when developing locally is that you’re able to closely replicate the production environment. If you’re writing IaC, building Docker images, and running the Docker image locally:
You are testing with the exact same code, with the same input paths, and if you mirror your .env file to the production .env file, you also mirror all of the variables. Thus, running Docker images locally is the way to go if you can do that.
Create local scripts with coding agents
Before the release of coding agents like Cursor and Claude Code, it was usually a tedious task to set up code to run everything locally. You needed to build the Docker image correctly, set it to run with your .env file, and so on. Or you might want to run your code locally as a FastAPI server instead, in which case you faced similar challenges.
This is not an issue anymore, however. To start running locally, I usually provide Cursor the following instruction:
Create a shell script for me to run this code locally. The shell script
should run the docker image, and have an optional –build flag, which builds
the docker image before running it. The docker image should load environment
variables from the .env file.
This creates an efficient shell script you can use. I like the optional –— build tag, because it’s sometimes time-consuming to build the Docker image, and I don’t always need to build it before running.
Also, the following factors allow me to run the script easily:
- I never store actual secrets in .env. I only store secret references, which my code then picks up from AWS Secrets Manager. Thus, I can push my env file without any worry of leaking secrets. Furthermore, this makes it easier for others to run the scripts as well when pulling the code from GitHub
- I create another file with test events, where I can easily send events to the running Docker image. This way, I can easily check the input and output
- I deploy the testing scripts to Git, so everyone else also has access to them. This includes the env file as mentioned, since it doesn’t contain any secrets
Now you have the exact setup you need to run and test your code locally. Every time you make changes, you rebuild the Docker image and send the test events, ensuring that everything is working as intended.
I recommend setting up these local testing scripts for all your repos and pushing them to Git for sharing. Having access to these scripts will make your entire team more efficient as programmers.
Further tips to run locally
I also want to share two additional tips to be even more efficient, given these local testing files:
- Run and test Docker image with pre-commit hooks
- Give your coding agent access to these scripts
Pre-commit hooks
Pre-commit hooks are code that runs before every commit to git. Typical pre-commit hooks include:
- Run black . for formatting
- Run mypy for type safety
- Run pytest tests to make sure all tests pass
Having a pre-commit hook guarantees you never forget to run any such commands before pushing your code. This is incredibly useful and a great timesaver. It’s hard for me to count the number of times I forgot to run black formatting before committing, and the deploy tests end up failing 5 minutes later, costing me a lot of time.
If building, running, and testing on the Docker image is not super time-consuming, I recommend also adding this to the pre-commit hooks. This way, you guarantee that before you push any code, you’ve tested that the code runs in a production environment, and that you get the expected output for a given input. Implementing this as a pre-commit hook will likely save you a lot of time in the future.
Give Cursor access to testing scripts
The second tip is that I always provide Cursor and Claude Code access to run my testing scripts. I then tell Cursor to run the testing scripts after making changes, and before ending its current implementation.
Having your coding agent run and test Docker images will vastly increase the amount of times it’s able to one-shot an implementation
This will save you a lot of time when your coding agent implements a feature, and then you have to manually run and test the Docker image. If you now encounter an error, you have to paste that into your coding agent, and the cycle repeats until the code is working.
This is a waste of time, and something you should work hard to avoid. Giving your coding agent access to the testing scripts is essentially like handing your coding agent a tool, which strongly improves performance in software engineering tasks. I can’t stress enough how much time this saves me.
Conclusion
In this article, I’ve discussed how you can create realistic production environments locally by creating scripts to build, run, and test Docker images locally. Doing this lowers iteration speed, which is a critical component of being an efficient programmer. Furthermore, I covered how I do this in practice: by prompting Cursor to create the testing scripts, and some example events I can run on the Docker image. I then give Cursor and Claude Code access to run these scripts, making my programming vastly more efficient.
I believe that having a quick iteration speed is critical for almost all software engineering tasks, and it is something you should strive for. Creating local test files and giving your coding agent access to them increases iteration speed a lot, which is why I believe that doing so myself has vastly increased my productivity as a programmer.
👉 My Free Resources
🚀 10x Your Engineering with LLMs (Free 3-Day Email Course)
📚 Get my free Vision Language Models ebook
💻 My webinar on Vision Language Models
👉 Find me on socials:
📩 Subscribe to my newsletter
🧑💻 Get in touch
🐦 X / Twitter
✍️ Medium

