Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion on nested block definitions #682

Closed
wants to merge 13 commits into from
Closed

Suggestion on nested block definitions #682

wants to merge 13 commits into from

Conversation

MariusStorhaug
Copy link
Contributor

@MariusStorhaug MariusStorhaug commented Feb 22, 2024

Overview/Summary

Suggestions to further define conditions, looping and nested blocks.

Supports the following:

  • TFNFR7 - Category: Code Style - The Use of count and for_each
  • TFNFR11 - Category: Code Style - null comparison as creation toogle
  • TFNFR12 - Category: Code Style - Optional nested object argument should use dynamic
  • TFNFR13 - Category: Code Style - Use coalesce or try when setting default values for nullable expressions
  • TFFR14 - Category: Inputs - No enabled or module_depends_on variable

In conflict with:

  • TFNFR20 - Category: Code Style - Declare nullable = false when it’s possible

This PR fixes/adds/changes/removes

  1. Adds a Nested blocks sub-section to TFNFR7 with suggestion on how to implement loops in different circumstances.

Breaking Changes

As part of this Pull Request I have

  • Read the Contribution Guide and ensured this PR is compliant with the guide
  • Checked for duplicate Pull Requests
  • Associated it with relevant GitHub Issues or ADO Work Items (Internal Only)
  • Ensured my code/branch is up-to-date with the latest changes in the main branch
  • Ensured PR tests are passing
  • Updated relevant and associated documentation (e.g. Contribution Guide, Docs etc.)

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Triage 🔍 Maintainers need to triage still label Feb 22, 2024
@MariusStorhaug MariusStorhaug changed the title Initial code Suggestion to nested block definitions Feb 22, 2024
@MariusStorhaug MariusStorhaug changed the title Suggestion to nested block definitions Suggestion on nested block definitions Feb 22, 2024
@MariusStorhaug MariusStorhaug marked this pull request as ready for review February 22, 2024 21:42
@MariusStorhaug MariusStorhaug requested a review from a team as a code owner February 22, 2024 21:42
Copy link
Member

@matt-FFFFFF matt-FFFFFF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi thanks for this. Some points for discussion!

length = optional(number)
})))
}))
default = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For collection values we recommend default is empty map/list/set and set nullable to false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @matt-FFFFFF, thank you for the feedback. Why is this the recommendation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @MariusStorhaug,

We prefer this because then the author does not need to check for a null value before using the variable in an expression. It is either empty, or it is not.

The only time we recommend otherwise is if there is a semantic difference between null and an empty collection.

In most resource modules that are authoritative about the resources they deploy, nullable = false is the correct approach.

Copy link
Contributor Author

@MariusStorhaug MariusStorhaug Mar 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was instead thinking of optimizing for the 'pattern creator' or a direct consumer of the resource module. To me it makes more sense having checks in the code and have a clear interface where we support both null and empty ([], {}). That would create a clear definition where:

  • null - don't use the feature
  • empty ([], {}) - use the default values in optional.

This would help when defining variables in patterns that would map to the modules that a pattern would consume and you want full flexibility to the consumed resource module.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said before this very much depends on whether there is a semantic meaning to null vs {}.

In the case of a map being used in a for_each expression, there is not. Therefore it makes sense to simplify the authoring experience and set nullable to false.

In the case where we are defining an absolute list of something, and the difference between null and {} would mean that supplying an empty collection would affect existing resources, then of course we should make a sensible decision. However in this case map() may not be the correct type to use.

I still believe that for 80% of the cases that nullable = false is correct for most top level collection values. Of course there are always exceptions.

name = string
length = optional(number)
}))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add nullable = false

name = string
length = optional(number)
nested_block = optional(object(any))
nested_multi_blocks = optional(map(object({
Copy link
Member

@matt-FFFFFF matt-FFFFFF Feb 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By providing a default empty map can we lose the try() below?

type = map(object({
name = string
length = optional(number)
nested_block = optional(object(any))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By providing a default empty map can we lose the try below?

name = string
length = optional(number)
}))
default = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again please set empty map and nullable false

# The dynamic block is used to support the optionality and looping.
resource "my_resource" "this" {
dynamic "optional_multi_block" {
for_each = var.optional_multi_block != null ? var.optional_multi_block : {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified if the default is empty map

@matt-FFFFFF matt-FFFFFF self-assigned this Feb 28, 2024
@matt-FFFFFF matt-FFFFFF added Needs: Author Feedback 👂 Awaiting feedback from the issue/PR author and removed Needs: Triage 🔍 Maintainers need to triage still labels Feb 28, 2024
@MariusStorhaug MariusStorhaug deleted the loops branch March 18, 2024 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Author Feedback 👂 Awaiting feedback from the issue/PR author
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants