Introduction

Heya Folks, wanted to share a few thoughts on which is better code or config for defining features in web apps or in general any application. While it seems like a minor detail, but I strongly feel it affects how well someone can use or extend an application. For that reason, I wanted to share about 7 reasons why you should consider building features using config vs baked in code.

Config are better to declare state

Node ecosystem is pretty vast and has grown because of a well thought out package manager(s) built for Node.js. The package.json and yarn.lock are great examples of how config makes it easier to manage dependencies and relay how to interact with you app or package.

For building web apps but also in general any application you’re building, which system works better to maintain source of truth, having behaviour baked in or configurable? Each has it’s benefits but I strongly feel having it clearly defined in specs with behaviour documented is the best way to build and extend the functionality of your app. For example the package.json lets you capture the current state of dependencies and scripts that a user can run with you app. There a lot more you can configure you app to do using just the package.json that why I feel it’s a great use case to for it. Example npm package that depends on react library.

{
  "name": "npm-package-name",
  "version": "1.0.0",
  ...
  "dependencies": {
    "react": "^16.8.3",
    ...
  }
}

Generated yarn.lock file for it.

react@16.8.3:
  version "16.8.3"
  resolved "https://registry.yarnpkg.com/react/-/react-16.8.3.tgz#c6f988a2ce895375de216edcfaedd6b9a76451d9"
  integrity sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==
  dependencies:
  loose-envify "^1.1.0"
  object-assign "^4.1.1"
  prop-types "^15.6.2"
  scheduler "^0.13.3"

It clearly defines what the current state of the dependencies is when last commit was built and how to figure out issues in case of breaking changes.

Easy to plug in with a CLI

If you use any CLI tools extensively like npm, docker, kubectl or aws cli, it’s easier to set you params or environment as a config file. Rather than have a complicated cli command to run you app or container you can easily configure it using the docker or npm config files that let the cli know your preference and how to run them. Example docker-compose.yaml file for building and running fullstack flask app with nginx as reverse proxy.

services:
  nginx-proxy:
    build: nginx
    restart: always
    volumes:
      - ./nginx/default.conf:/tmp/default.conf
    environment:
      - FLASK_SERVER_ADDR=flask-app:8000
    ports:
      - "80:80"
    depends_on:
      - flask-app
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl --silent --fail localhost:80/health-check || exit 1",
        ]
      interval: 10s
      timeout: 10s
      retries: 3
    command: /app/start.sh

  flask-app:
    build: flask
    restart: always
    ports:
      - "8000:8000"
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl --silent --fail localhost:8000/flask-health-check || exit 1",
        ]
      interval: 10s
      timeout: 10s
      retries: 3
    command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
    networks:
      - public
      - private
    depends_on:
      - db

  db:
    image: mysql:8.0.27
    command: "--default-authentication-plugin=mysql_native_password"
    restart: always
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - private
    environment:
      - MYSQL_DATABASE=example
      - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password

  frontend:
    build:
      context: frontend
      target: development
    ports:
      - 3000:3000
    volumes:
      - ./frontend/src:/code/src
      - /code/node_modules
    depends_on:
      - flask-app

networks:
  public:
  private:
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt

It’s easier to express intent and avoid mistakes with newer cli tools now adopting config files as a way to deploy entire applications and infrastructure using config vs a script with quirky behavior.

Easier to Test

Config files are great for unit and integration testing as they can be easily be verified and mocked. It also makes it easier to convey which part is being tested and the result of running the unit/integration test.

Easier to Maintain

Npm’s package.json is well documented and easy to understand, what the original intent was when building out the package. With more documentation around the behaviour to expect from you config file, making it easier for someone to jump in and build or fix issues in code.

Easier to Extend

Docker and npm again heavily use config files and are also easy to extend. Docker files defined in each directory can be extended to include additional functionality. Like the previous example, it’s possible to define a Higher level stateless services that defines each component using their own docker file to build and run. It can be further automated by having the Infrastructure as code using AWS or Terraform defined along with it so all new changes can be deployed in a single command.

Easier to Reuse

With extendablility, comes the ability to reuse the same config file for different applications. It’s also possible to have a config file that is shared across multiple applications. Saving on the amount of time needed to define the same tested config behaviour in multiple projects.

Easier to Share

Apps or CLIs using a config to implement or run a feature can be easily shared in different projects. Having it part of a script or code will make it difficult to replicate across different projects and environments. Config for the win!

Conclusion

That ends my rant on why config files are a better way to manage dependencies, scripts, and environments. I hope you find this useful and this post made me consider a lot more ways of using configs in my projects, so that fixing a bug or scaling up a feature would just be a matter of updating a config file for your whole environment.

Join the email list and get notified about new content

Be the first to receive latest content with the ability to opt-out at anytime.
We promise to not spam your inbox or share your email with any third parties.

The email you entered is not valid.