DevOps

Critical Tools for Development: Environment Detector

Thinking about the entire development ecosystem can be both challenging and overwhelming. It’s one of the many things that actually stop organizations and teams from following best practices and implementing a DevOps workflow. Why? It’s non-trivial to handle conditional elements in different environments.

Environmental Differences and similarities

The most common environments on web projects are:

  • local

  • continuous integration (CI / CD)

  • development (dev)

  • testing (qa / stage / test)

  • production

Now, obviously environment names are all made up and they don’t really matter anyway. So you could have 4 environments or you could have 10. The point is, there are some things between environments that should be identical and others that should be quite different.

The challenge: knowing the difference.

For instance! If I were to write a simple hello world function in PHP, it might look something like this.

<?php
print “Hello World!”;

Obviously, there is nothing special or conditional about this statement. It just prints Hello World 100% of the time. Now as we think about application development… simple print statements like this one aren’t often useful. We usually want to customize them to say hello to the specific user. We want to conditionalize them to not appear unless certain conditions are met. In other words, we want to make our code as dynamic and responsive as possible!

This is the same concept for environments. There are certain aspects of your application that can (and should) behave very differently based on the environment that they are running in. Here are a few examples:

  • caching configuration - caching should be turned WAY up in production and other cloud environments (for parity) but disabled or turned way DOWN in local / CI environments for easier development. similarly, you may want to keep javascript / css files un-minified locally (as you are developing on them) vs. in production (where performance matters)

  • security configuration - due to domain restriction, SSL certificates, etc. some of your application’s security settings may need to be relaxed locally or during CI

  • API keys - many integrations (e.g. e-commerce) mirror your web application’s multi-environment setup. you absolutely do not want your development web application communicating with your production e-commerce platform!

  • database / other settings - if you’re using a virtual solution locally (like Lando or Drupal VM) you may have an entirely different containerization strategy locally than you do in the cloud. You also likely have different database names and passwords (or you should) for local and CI environment than you do in the “real” hosting environments.

So the question becomes… just like with customizing that Hello World statement if we want to customize these scenarios… we need a way in code to differentiate between environments AND we need code that is smart enough to handle that differentiation.

Environment Detectors to the rescue

Most quality hosting organizations provide some sort of environment variables. These vary from organization so you’ll want to carefully review their documentation. But they do typically exist! Acquia’s documentation is online and shows how to do it on our platform.

TLDR: there is a super global AH_SITE_ENVIRONMENT variable that can be accessed via PHP code that spits out the environment that the code is currently running in.

Acquia also provides an open source / extendable Environment Detector. If you host with Acquia? Cool! Use ours. If you don’t, also cool! Use ours as an example for your own.

Basically, the environment detector uses the environment variables to figure out where we are. Like so:

  /**
   * Is AH prod.
   *
   * @param string|null $ah_env
   *   Environment machine name.
   *
   * @return bool
   *   TRUE if prod, FALSE otherwise.
   */
  public static function isAhProdEnv($ah_env = NULL) {
    if (is_null($ah_env)) {
      $ah_env = self::getAhEnv();
    }
    // ACE prod is 'prod'; ACSF can be '01live', '02live', ...
    return $ah_env == 'prod' || preg_match('/^\d*live$/', $ah_env);
  }

Then, you can use the method in your code. So…

<?php

use Acquia\DrupalEnvironmentDetector\AcquiaDrupalEnvironmentDetector;

public function test() {
  if (AcquiaDrupalEnvironmentDetector::isAhProdEnv()) {
    print "Hello on Prod!";
  }
  else {
    print "Hello World";
  }
}

In this case, our Hello World could be customized to say hello from prod (if we are on prod) and Hello World everywhere else.

You can take this model even farther (like BLT has) and use the Environment Detector to:

You can also use the Environment Detector in custom code!

Getting Started

So the biggest thing to know when you get started with Environment Detection is that while you CAN and SHOULD use it “a lot of places” in your Devops and Development pipelines… if you aren’t using it now it can be non-trivial to begin integrating it.

Why? Because it can change really significant portions of your workflow. Change settings files conditionally in all environments? That can (and likely) means that all of your environments are temporarily going to break while you iron out the details. I mean, that’s ok! Just know before you go in (and maybe don’t allocate a super junior person to do it).

So the take away here that I would suggest is that you plan your architecture and think through how you want to implement the conditional aspects of environments.

I would also recommend that you use Acquia’s Build and Launch Tools (BLT) as a model. We use environment detection everywhere in BLT and it really makes it quite powerful. Obviously, if you consistently host in “many” different hosting environments this gets more challenging. But just because it’s challenging doesn’t mean you shouldn’t do it!

My recommendation: start very small and very simple. Especially if you have to write your own environment detector. Make sure it works. Make sure it works up and down your stack. THEN start trying to write some simple code. THEN get more fancy and start integrating it into your devops and deployment workflows.

Related Content

An Absolute Beginner's Guide: Dependency Management and Composer

An Absolute Beginner's Guide: Dependency Management and Composer

Learning dependency management techniques and integrating them into your development workflow can be challenging if you’ve never worked with a dependency manager like Composer before. In this article I share my experience learning Composer and make recommendations on how to get started with Drupal 9 dependency management!