Share
Embed
Manage Complexity with Terraform
A 25 minute introduction to Terraform and refactoring suitable for beginners to intermediate developers who are just getting started dealing with code complexity in a Terraform code base. The accompanying talk is currently available on YouTube at:
https://www.youtube.com/watch?v=-dMtaC5QaUk&t=283s
Justin
September 28, 2025
Transcript
54 slides
-
Manage Complexity with Terraform Tips and Tricks from the Trenches
Commit Your Code // 2025 -
Inside every Terraform developer... Source: Gemini One prefers code that
is easy to maintain -
Source: Gemini Both agree, well organized code is most important
when it matters most! -
Justin Biard Software Engineer, Oracle Cloud Infrastructure Disclaimer: opinions presented
are my own About me... -
What is Terraform? According to HashiCorp (IBM): • Terraform is
an infrastructure as code tool that lets you build, change, and version infrastructure safely and efficiently. This includes low-level components like compute instances, storage, and networking; and high-level components like DNS entries and SaaS features. • Infrastructure as Code (IaC) Source: https://developer.hashicorp.com/terraform -
What is Terraform? According to HashiCorp (IBM): • Terraform is
an infrastructure as code tool that lets you build, change, and version infrastructure safely and efficiently. This includes low-level components like compute instances, storage, and networking; and high-level components like DNS entries and SaaS features. • Infrastructure as Code (IaC) • Build, change, and version infrastructure Source: https://developer.hashicorp.com/terraform -
What is Terraform? Infrastructure as Code • Configuration of cloud
infrastructure resources declared as code (an interpreted configuration language… HCL) -
What is Terraform? Infrastructure as Code • Configuration of cloud
infrastructure resources declared as code (an interpreted configuration language… HCL) terraform { ... } Network Load Balancer Database Firewall Compartment Policy Compute Secret ./my-project/main.tf -
What is Terraform? Build, change, and version infrastructure • Write
code and call terraform plan / apply terraform { ... } Network Load Balancer Compute Cloud Service $ terraform apply HTTPS -
What is Terraform? Build, change, and version infrastructure • Versioning
is both state reconciliation and source control terraform { ... } Network Load Balancer Compute Cloud Service Version Control {tfstate} $ git commit –m ... HTTPS -
What is Terraform? Agnostic by design • Terraform providers deal
with the nuances of each cloud terraform { ... } AWS GCP OCI Azure https://registry.terraform.io/browse/providers -
What are the alternatives? Some other IaC tools… • OpenTofu
• Pulumi • CloudFormation -
Examples of complexity • Complex expressions or repetitive parameter updates,
and unrelated resource definitions (low cohesion), and inconsistent formatting • Add locals • Add variables • Split configurations within a module or the default module • Run `terraform fmt` on every commit -
Examples of complexity • Complex expressions or repetitive parameter updates,
and unrelated resource definitions (low cohesion), and inconsistent formatting • Add locals • Add variables • Split configurations within a module or the default module • Run `terraform fmt` on every commit • Code duplication among groups of resources defined for similar purposes • Refactoring into modules -
Examples of complexity • Complex expressions or repetitive parameter updates,
and unrelated resource definitions (low cohesion), and inconsistent formatting • Add locals • Add variables • Split configurations within a module or the default module • Run `terraform fmt` on every commit • Code duplication among groups of resources defined for similar purposes • Refactoring into modules • Requirements for configuration diverge - inclusion/exclusion of resources for a given stage (dev vs. prod) • Conditional resources -
Local variables Like variables or named constants in most other
languages Pros: • Give semantic names to intermediate or constant values • Simplify or reuse expression results Cons: • Overuse can make configurations harder to read -
Local variables (before) resource "lb_listener" "some_listener" { … port =
8443 } resource "firewall_rule" "ingress_rule" { … min = 8443 max = 8443 } -
Local variables (after) locals { service_port = 8443 } resource
"lb_listener" "some_listener" { … port = local.service_port } resource "firewall_rule" "ingress_rule" { … min = local.service_port max = local.service_port } $ git checkout demo_locals -
String interpolation + variables Often paired with locals or variable
blocks Pros: • Variables can be supplied as external inputs • Good for dynamic display names and string parameters • Very useful in the context of modules Cons: • Variables can increase complexity depending on context (i.e. conditional expressions) https://developer.hashicorp.com/terraform/language/parameterize -
String interpolation + variables (before) locals { stage = "dev"
} ... resource "compute" "api_instance" { … # example: evaluates to api-instance-dev display_name = "api-instance-${local.stage}" } -
String interpolation + variables (after) variable "stage" { type =
string description = "Deployment stage (dev or prod)" default = "dev" } resource "compute" "api_instance" { … # example: defaults to api-instance-dev display_name = "api-instance-${var.stage}" } $ git checkout demo_vars -
Conditional expressions Often paired with data, locals, or variable blocks
Pros: • Useful for altering parameters based on input Cons: • Nesting expressions can be difficult to read -
Conditional expressions (before) resource "lb_listener" "some_listener" { … port =
8443 } resource "firewall_rule" "ingress_rule" { … min = 8443 max = 8443 } -
Conditional expressions (after) locals { service_port = var.stage == "dev"
? 8080 : 8443 } resource "lb_listener" "some_listener" { … port = local.service_port } resource "firewall_rule" "ingress_rule" { … min = local.service_port max = local.service_port } -
Putting it all together # pass variable values at runtime
(default is dev) $ terraform apply -
Putting it all together # pass variable values at runtime
(default is dev) $ terraform apply vcn-dev lb-dev api-dev Cloud Service http://dev.myapp.com:8080 -
Putting it all together # pass variable values at runtime
(default is dev) $ terraform apply $ terraform apply -var="stage=prod" vcn-dev lb-dev api-dev Cloud Service http://dev.myapp.com:8080 https://myapp.com:8443 vcn-prod lb-prod api-prod Cloud Service api-prod api-prod -
Modules Reusable chunks of configuration Pros: • Allows for reuse
of groups of resource definitions • Reduces maintenance and simplifies large configurations Cons: • Harder to read without navigating multiple sources • Need to deal with address changes when refactoring -
Modules (before) resource "lb_listener" "dev_listener" { … } resource "firewall_rule"
"dev_ingress_rule" { … } resource "lb_listener" "prd_listener" { … } resource "firewall_rule" "prd_ingress_rule" { … } -
Modules (before) resource "lb_listener" "dev_listener" { … } resource "firewall_rule"
"dev_ingress_rule" { … } resource "lb_listener" "prd_listener" { … } resource "firewall_rule" "prd_ingress_rule" { … } stage = "dev" port = 8080 stage = "prd" port = 8443 -
Modules (after) # in dev/main.tf module "service_network" { source =
"./modules/network" stage = "dev" port = 8080 } # in prd/main.tf module "service_network" { source = "./modules/network" stage = "prd" port = 8443 } $ git checkout demo_modules -
Modules example One big config with duplication prod abc xyz
dev xyz BEFORE AFTER ./modules/abc - main.tf - outputs.tf - variables.tf ./modules/xyz - main.tf - outputs.tf - variables.tf -
Conditional resources Conditional single resource or groups of resources (modules)
Pros: • Enable or disable resource creation conditionally (different stages, based on data sources, variables, capabilities, etc.) Cons: • Can make configurations difficult to reason about • Non-zero chance that resources could be misconfigured (added or removed unintentionally) -
Conditional resources (before) resource "some_resource" "abc" { … } module
"xyz" { source = "./modules/xyz" … } -
Conditional resources (after) locals { is_enabled = var.stage == "prod"
} resource "some_resource" "abc" { count = local.is_enabled ? 1 : 0 … } module "xyz" { count = local.is_enabled ? 1 : 0 source = "./modules/xyz" … } $ git checkout demo_conditions -
Conditional resources example Some hypothetical requirements change • Add a
load balancer and extra compute instances in production. • Development remains as a single compute with no load balancer. -
Conditional resources example vcn-dev api-dev Cloud Service # in dev
is_enabled = false -
Conditional resources example vcn-dev api-dev Cloud Service # in dev
is_enabled = false # in prod is_enabled = true ??? -
Conditional resources example vcn-dev api-dev Cloud Service vcn-prod lb-prod api-prod
Cloud Service api-prod api-prod # in dev is_enabled = false # in prod is_enabled = true ??? -
Recap •What is Terraform? • IaC •Managing Complexity • Locals,
variables, modules, expressions, conditional resources, … •Resources