Git – How to split development / staging / production versions of an application

Architecturedevelopment-processgitrelease-managementteamwork

I'm facing a situation that does not seem to have a clear solution to it, which leads me to believe I'm actually doing something wrong. Here I am seeking advice once again.

To rapidly let you understand my issue, I'm having trouble releasing apps / developing apps, in terms of separating the production code with the development code. Now let me explain in detail.

First, here are the two things that I've done in the past :

Develop on a single branch (git), say "dev", and when we need to release, simply manually change everything to "production" state, build-archive-release, and we're good.

For obvious reasons this is completely unmaintainable and requires so much work even when releasing simple apps.

Develop on a "dev" branch, and once we're happy with it, we merge on a "beta" and then a "production" branch, and ship whatever branch needs to be shipped.

This is better, but the relentless merging feels just as error prone as the "one branch to rule them all" insanity. And on top of it, I feel pretty unaware of what exactly the merge will do to my files, when it comes to specific config files. For example, merging dev into beta, which of the API Keys is it gonna choose in the merge? The dev or beta key? Same about some credentials or backend url. It really feels more clean when you look at it from the outside, but in the end, I still end up checking up all my files one by one. And I've had bad changes happen, I'm not just paranoid, sadly.

So, I'd say better, but just as maintainable.

Some have advised using #IF DEBUG but I'm straight up against it, as you end up cluttering the code and having bits and pieces of two different environnements spread into the code. In the end you're not even testing the real product, so that can't work.

And now here I am, not knowing what others do and how to they overcome that obstacle. I am all ears.

Note : I've read a bit about build servers but I'm not sure I truly understand them, and from my inexperienced point of view, I just see them as moving the problem on a remote machine, which does not change much.

Best Answer

I would strongly advise against different branches for separating seemingly hard coded development configurations from production configurations. Using SCM for this task will lead to increasingly different code bases.

A great way to make build differences explicit is by creating one sub-project per build target. In these projects you can for example extend a generic launcher from the main code or provide environment specific parameters. Even if you use configuration files a project for each build target is often a good place to put configuration files into.

A project layout might look this way:

  • application (root-project)
    • application-main
    • application-distribution-prod (uses application-main)
    • application-distribution-dev (uses application-main)

When your application is big and has different modules, you can create different module assemblies just by creating different distribution sub-projects.

When you have complex differences between production and development environments I would recommend to pull all variable aspects into interfaces. Then you implement those interfaces in two different projects. Switching between environments becomes a matter of dependency management.

An extended example:

  • application (root-project)
    • application-main
    • application-login-mock (implements login api from application-main)
    • application-login-google (implements login api from application-main)
    • application-distribution-prod (uses application-main & application-login-google)
    • application-distribution-dev (uses application-main & application-login-mock)

For this technique you will need some kind of dependency injection or service provider.