How to simplify your development with Makefile
Makefiles date way back to early 1970s the main purpose for it in software development is to automate the build process of a project. The necessity of it grows with project complexity to automate, simplify different commands starting with running, dockerizing, populating data for your app and so much more.
In my example will showcase Go and Svelte as an example. Although tech stack makes no difference.
Commands
Makefile has it’s own syntax with rules, dependencies, commands and targets. As mentioned it’s good to use if your project has complex structure for running or executing certain sections.
Same as any other language it’s sometimes essential to create variables for future use cases.
GOCMD=go GOBUILD=go build GO_FILE=main.go BINARY_FILE=main
A target on the other hand is the desired output of a Makefile rule.
build-client: cd ./client && yarn && yarn build build-server: echo "Building binary" ${GOBUILD} -o ${BINARY_FILE} ${GO_FILE}
Uses indentation and special keywords like make
, all
, clean
, etc.
In above example we created default variables and next like build-client
, build-server
to run it just in root directory just add make
prefix.
Makefile is defaulted available on Linux systems like Ubuntu or MacOS if using windows best to install and use WSL.
Integration
Makefile comes most in handy when introducing third party tools like Docker, Kubernetics, Shell scripting etc.
docker-build: echo "Building docker image" docker build . -t akshay5995/go-svelte docker-push: echo "Pushing image to docker registry" docker login docker push akshay5995/go-svelte:latest run-in-minikube: echo "Deploying to minikube" kubectl apply -f deployments/redis-master.yml kubectl apply -f deployments/go-deployment.yml echo "URL for the service" minikube service go-svelte --url deploy-to-gcp: echo "Deploying to Google Cloud Platform" gcloud config set project YOUR_PROJECT_ID gcloud container clusters get-credentials YOUR_CLUSTER_NAME --zone YOUR_CLUSTER_ZONE kubectl apply -f deployments/redis-master.yml kubectl apply -f deployments/go-deployment.yml echo "URL for the service" kubectl get servicesm
As you can see the above commands are more lengthy and it would be a pain to type the docker build commands manually, not to mention deploying to PaaS and running kubernetes CLI commands.
Let’s say you have a separate Redis populate data in shell script.
#!/bin/bash # Database connection parameters DB_HOST="localhost" DB_PORT="5432" DB_NAME="your_database" DB_USER="your_username" DB_PASSWORD="your_password" # SQL commands to clean up the database in Redis REDIS_COMMANDS="FLUSHDB" # SQL commands to populate the database SQL_COMMANDS="INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2');" # Connect to Redis and execute commands redis-cli -h $DB_HOST -p $DB_PORT -c "$REDIS_COMMANDS" # Connect to Redis and execute commands psql -h $DB_HOST -p $DB_PORT -d $DB_NAME -U $DB_USER -W $DB_PASSWORD -c "$SQL_COMMANDS" # Make a POST request using curl curl -X POST http://localhost:4000/actions/syncSourceCredAccounts?force=true
Then Makefile can be something like this.
.PHONY: clean-db clean docker-build docker-push run-in-minikube deploy-to-gcp populate-database run-all all: clean-db clean docker-build run-in-minikube deploy-to-gcp # Shell script to connect to Redis, clean the database, and execute commands populate-database: ./populate_script.sh ... clean-db: echo "Cleaning up the database in Redis" redis-cli FLUSHDB # Define the 'run-all' target which depends on 'clean-db', 'clean', 'docker-build', 'populate-database', 'run-in-minikube', and 'deploy-to-gcp' run-all: clean-db clean docker-build populate-database run-in-minikube deploy-to-gcp
I have added .PHONY
in Makefile it is a special target that is used to declare a target that doesn't represent a file.
The purpose of declaring a target as .PHONY
is to ensure that the target is always considered out-of-date and its commands are executed, regardless of whether a file with the same name exists or not.
In our example clean-db
doesn't generate a file, but using .PHONY
helps convey to Make that it's a target intended for executing commands and not for creating a file.
When it comes to rest of the commands populate-database
speaks for itself and all
or run-all
executes multiple make commands instead of executing them one by one.
In a nutshell Makefile is an oldie but goldie for automating your development process and minimizing manually typing different commands to be executed.
In my article I just scratched the surface of Makefile as it’s quite flexible as it eases and saves development time.