docs-terraform-guidelines

Refactoring

Why do you need refactoring ?

Refactoring your codebase terraform is a necessity within the lifecycle of your codebase. As your infrastructure grows and as you add collaborators to the project, you’ll need to reconsider things like :

To keep track of your continuous changes, you should set up quality probes, which will serve as goals the refactored codebase aims to reach like :

Questions to ask yourself

Your priorities regarding a refactoring are the following in this order :

  1. Control code quality
  2. Accelerate feature promotion
  3. Reduce code duplication
  4. Improve readability

refacto_decision_tree

How many collaborators are contributing to the codebase ? #CodeQualityControl

Do you have splitted layers ? #Accelerate

The goal is to find the right balance between macro layers (too few layers) and micro layers (too many layers).

Macro layers (too few, ideally avoid having only one terraform state with every resource in it) create problems such as:

Micro layers (too many) create different problems such as:

To know how to define the scope of balanced layers, you can ask yourself how to dispatch resources in 3 states or also in 3 folders. You can rely on the 3-tier way of splitting an architecture. If you realize while refactoring that terraform plans takes too long (more than 1 minute), you may need to split it again.

The gains would be :

Do you have modules ? #DRY

Modules serve 1 purpose : Don’t repeat yourself. You write modules for 2 reasons :

Use as much modules from the Theodo Cloud internal library or Providers repositories as you can. If no module there matches your needs, here is how you should implement modules in your codebase:

Pay attention to terraform plan elapsed time as you build your modules.

Are your resources compliant with naming, versioning and other standards ? #CleanCode

Once you have your modules, you should focus on code readability and maintainability. So, implement naming standards, versioning standards and others.

Refactoring with Terragrunt

If you follow the Context pattern, refactoring is one of Terragrunt’s biggest strengths: since every layer is a single module, it is also a single state. When you identify a new project need, you can rearrange your tree structure to match the new view of your project need.

Splitting layers

While Terragrunt lets you keep a DRY configuration, it also lets you easily split layers to match project needs. This forces you to rethink your splitting every time you add a resource / module to a layer.

In Example 1 the use case is that we want to add resources for a new frontend. At this point you have 2 choices:

Example 1 : Add a frontend

.
├── layers
│   └── application
│       ├── module.hcl                 # Calls the backend module
│       └── app_1
│           ├── dev
│           │   ├── inputs.hcl
│           │   └── terragrunt.hcl
│           └── production
│               ├── inputs.hcl
│               └── terragrunt.hcl
└── root.hcl

Many applications will need the frontend

.
├── layers
│   └── application
│       ├── backend
│       │   ├── module.hcl
│       │   └── app_1
│       │       ├── dev
│       │       │   ├── inputs.hcl
│       │       │   └── terragrunt.hcl
│       │       └── production
│       │           ├── inputs.hcl
│       │           └── terragrunt.hcl
│       └── frontend
│           ├── module.hcl
│           └── app_1
│               ├── dev
│               │   ├── inputs.hcl
│               │   └── terragrunt.hcl
│               └── production
│                   ├── inputs.hcl
│                   └── terragrunt.hcl
└── root.hcl

Example 2 : Add Redis to all backends

.
├── layers
│   └── application
│       ├── module.hcl                 # Calls the backend module
│       └── app_1
│           ├── dev
│           │   ├── inputs.hcl
│           │   └── terragrunt.hcl
│           └── production
│               ├── inputs.hcl
│               └── terragrunt.hcl
└── root.hcl

I’m going to need a Redis for my backend. I’ll just update my backend module and test it by overwriting the call to the module within the layer terragrunt.hcl.

Don’ts