Optimizing Terraform Code for Readability and Maintainability
Introduction
Welcome back to the Azure Terraformer! Today, we’re diving into a critical aspect of infrastructure-as-code (IaC): writing Terraform code that prioritizes readability and maintainability over technical elegance. Unlike traditional application development, where clever code can be a badge of honor, IaC demands simplicity and clarity. Let’s explore this concept through a recent code review I conducted for one of our code ninjas.
The Importance of Readability in IaC
In the world of IaC, the primary goal is to manage and provision infrastructure efficiently. This means the code should be easy to read, understand, and modify by anyone on the team. Overly complex or “elegant” solutions can hinder collaboration and increase the risk of errors.
Avoiding Unnecessary Complexity
His code presented a scenario where he was dealing with a many-to-many relationship between scopes, identities, and roles in Azure. He attempted to use advanced iteration techniques in Terraform to handle this complexity. While his intentions were good, the result was code that was hard to read and maintain.
Key Takeaway: Just because you can write complex code doesn’t mean you should. If a solution makes the code harder to understand, it’s worth reconsidering.
Best Practices for Writing Terraform Code
Use Stable Iterators
One of the issues in the code was the use of unstable iterators within the for_each
meta-argument. Embedding complex expressions directly into iteration statements can make the code difficult to follow.
Recommendation: Use stable iterator references by creating locals or variables that encapsulate the data you want to iterate over. This approach enhances readability and makes debugging easier.
Simplify Module Interfaces
The Original Poster (OP) created a custom role definition module that, at first glance, seemed to add little value beyond wrapping a resource. However, upon closer inspection, it simplified the interface by enforcing best practices, such as using the first entry of the assignable scopes.
Key Point: Modules should add meaningful value. If they simplify interfaces or enforce best practices, they’re worth having. Otherwise, consider using the resource directly to keep the codebase lean.
Avoid Redundancy in Naming
Redundant naming, such as prefixing every variable with the resource type, can clutter the code.
Advice: Leverage the context provided by modules and resources to avoid unnecessary prefixes. This practice makes the code cleaner and more readable.
Externalize Complex Expressions
Embedding complex regular expressions or conditions directly into your code can hinder readability.
Suggestion: Move complex logic into locals or variables. This separation allows developers to understand the code’s intent without getting bogged down in the details of the expressions.
The Balance Between Elegance and Practicality
OP’s attempt to handle role assignments through dynamic iteration was an example of prioritizing technical elegance over practicality. While it might feel satisfying to write such code, it often leads to increased complexity.
Final Thought: In IaC, it’s better to have straightforward, possibly repetitive code that everyone can understand than intricate code that only the original author can decipher.
Conclusion
Writing Terraform code isn’t about showcasing programming prowess; it’s about creating infrastructure definitions that are easy to manage and scale. By focusing on readability and maintainability, you ensure that your infrastructure can be efficiently managed by anyone on your team, now and in the future.
Remember: Keep it simple, prioritize clarity, and always consider the next person who will read your code.
If you’re interested in getting your Terraform code reviewed, consider joining the Code Ninja program. You’ll get priority access to code reviews and become part of a community dedicated to mastering Terraform on Azure.
Happy Azure Terraforming!