Demystify deployment and environment coupling of code

Akshay Jain
4 min readMay 28, 2020

As a good practice, we keep a separate deployment instance=(qa=app.qa.com) apart from main deployment=(production=app.com), so that we can test our development on qa instance before moving that code to production instance

Adding a further level of safety, the code deployment to these different instances (qa and production) also goes from different git branches ( qa and master )

For new code addition, we create a branch=(feature-1) from qa and test it locally and if it works well on local, we merge feature-1 to qa branch, now this qa branch is used to deploy code to qa deployment instance hereafter referred to as qa environment, if this works well, we will move code from qa branch to master branch and use code from the master branch to deploy to production instance

In case of web development, both frontend and backend code follow the same code deployment approach, so we want frontend code on qa instance to connect with backend API from qa instance and similarly production frontend to call production backend API

This connection logic to the backend is part of frontend code

Thus the code that connects to backend API will be different for qa and production instance of frontend, that means we can’t promote qa branch to master branch through a simple pull request

We can solve this problem in frontend code by decoupling the backend API url from the frontend code logic and couple them through new deployment code at the time of deployment as per following coupling instruction

# deployment code == coupling instruction in plain English

1. if we want the code to run on qa environment, pick the qa credentials and build the code so that it runs well on qa

2. if we want the code to run on the production environment, pick the prod credentials and build the code so that it runs well on production

because credentials and code are decoupled and gets coupled only according to our coupling instructions defined above, we can safely do below two things

A1. promote the qabranch to master branch without worrying about overriding master credentials in the production branch, since they can coexist. (env.qa and env.prod)

A2. pull mastermaster branch to qa

Thus we have explained the deployment logic used to ease the ongoing development of software

Now if in case, we are not able to decouple our credentials from code, then we have to MANUALLY take care that our coupling logic is intact while doing points A1 and A2 described above

Following is an example of one scenario and our solution approach

We have repository=Repo1 which contains page business.html

now route=/url1 in another backend, repo=API_SERVER is configured such that it renders business.htmlin both environment qa and prod

Now our requirement is that the pagebusiness.html should submit the form to two different endpoints according to the environment qa or masterand that is where credentials are coupled to code.

Now instead of jumping to the final solution let improve bit by bit

Generally, the coupling is defined in build.js, that means, build.js for qa will contain credentials of qaand build.js formaster environment will contain credentials of master, thus we can’t progress the build.js from qa to master branch seamlessly

Improvement 1

The first improvement can be to create two separate js files main.qa.js and main.prod.js and both will co-exist, we will just replace the reference in HTML as per the environment

Again we can’t do actions A1 and A2 seamlessly, because we will have to take care of proper reference in the HTML file

Improvement 2

Again we can go for improvement by passing env as query parameter from the API_SERVER like this /url1?env=qa and in the HTML we can check the env value and load either main.qa.js or main.prod.js based on the value of env

like this

<script type="application/javascript">function loadScript(file) {var jsElm = document.createElement("script");jsElm.type = "application/javascript";jsElm.src = file;document.body.appendChild(jsElm);}let env = document.location.search.split("&").filter(x=>x.startsWith('env='))[0]?.split('=')[1];let url;switch (env) {case 'qa':url = '../js/main.qa.js';break;default:url = '../js/main.prod.js';}loadScript(url)</script>

Now we can do actions A1 and A2 seamlessly basically we have again tried to decouple the code with credentials with the help of query parameters from API_SERVER, because API server can actually send different parameters based on environment, since in our case it has that decoupling that we talked

Improvement 3

As explained in the first line of the post, our host URL are different namely app.qa.com and app.com so instead of relying on query parameter from API_SERVER, we can improve our coding logic as below

<script type="application/javascript">function loadScript(file) {var jsElm = document.createElement("script");jsElm.type = "application/javascript";jsElm.src = file;document.body.appendChild(jsElm);}const env = window.location.hostlet qaUrl = "../js/qa.main.js";let prodUrl = "../js/prod.main.js";let url;switch (env) {case "app.qa.com":url = qaUrl;break;case "app.com"url = prodUrl;}loadScript(url)</script>

With this improvement, we have coupling logic in HTML itself.

Let me know your views.

--

--