FC035 - too broad a condition? #60
Comments
Hi Mike, Thanks for the feedback. I did think that this rule might be controversial (there's a note to that effect in the CHANGELOG) and shipped it in order to elicit feedback.
Cheers, Andrew. |
Hey Andrew, Thanks for the update - I probably should have checked the README. :) Controversial, indeed. Point 1 makes sense - pass the main node object, then evaluate the sub-keys. Cool. Point 2 - I don't know if I clearly understand this. Is there an example of this somewhere I could reference? |
Point 2 - this makes sense if you have a structure that is close to your config file format. In the simplest case I'm thinking of something like this: If you are working with data structures provided by others then you might need to do some processing to use this approach, at which point it's a judgement call as to which approach results in simpler and easier to read code. |
My understanding is that in the opscode training the specifically say to avoid using template variable parameters to pass in node data but only to use this for other types of data like databags or other calculations. One reason for this is that the value of the node attribute will be read at compile-time when it is passed in. If ruby in a later cookbook changes that node attribute you care about before run-time when your template is rendered, you may not get the value you intended. If you directly access the node object in the template, you'll get the latest possible binding. |
An example of where this might be an issue is here: https://gist.github.com/3491505 Definitely a Bad Idea, but demonstrates the problem. A node variable is set to one thing before the template resource is called, then set to something else after the resource. |
@kcbraunschweig - Great point, thanks for sharing this. Full disclosure: I have a nasty cold at the moment. It seems a bit wrong to me to reference the node attribute everywhere because it might be modified elsewhere during the run. As a user of the cookbook I'd probably prefer if this was explicit. If I was trying to delay the evaluation in plain old Ruby I might reach for a proc, which would look like this: file "/tmp/thing.erb" do
- content '<%= node["mything"] %>'
+ content '<%= @foo.call %>'
end
template "/tmp/mything" do
source "/tmp/thing.erb"
+ variables({'foo' => lambda{node["mything"]}})
local true
end You could also take advantage of the fact that It seems at minimum we need a warning in the rule documentation on the difference in behaviour. What do you guys think? I can certainly see that "just use node attributes everywhere" is a simpler message. |
Hi Andrew, hope you feel better soon. I ran into this recently while working on a backlog of patches for gitlab cookbook. Of course my Travis tests failed when it pulled in the gem with the FC035 rule. I went through and made the changes so I'd be better informed about what changes this rule entails. The two reasons I have read for this rule in this thread are:
Number one may be a problem, in some cases. As @kcbraunschweig points out, it is a necessity of design, with the ability to Number two only works if the structure was designed in such a way. Frankly, I haven't seen many cookbooks with complex hash-like structures with the exception of a few like fnichol's So, just in my own use case for gitlab, that adds about 40 lines of recipe code while not really reducing the complexity of any given template. Some of this variable declaration in recipes, must be repeated as attributes such as
|
Thanks for the considered feedback @atomic-penguin. I think the consensus then is that this rule is not adding a lot of value for the trouble it causes. I'll release a new version with this rule removed shortly. |
Don't get me wrong - I think it may very well be that there is good value to using some sort of conditional style, such as any attribute that is not a node attribute should probably be pre-computed in the template resource. Since defeating this rule is probably as simple as passing the entire |
See the discussion against #60 for the reasons this rule was a bad idea.
I've pushed 1.6.0 to rubygems which is 1.5.1 with FC035 removed. @miketheman - Can you open a separate issue with ideas for what this rule might look like so we can continue the discussion over there? Thanks. |
In many complex cases, passing all known node attributes to the template may be overloading the recipe needlessly.
For instance, in https://github.com/opscode-cookbooks/ntp/blob/master/templates/default/ntp.conf.erb there are 15 invocations of node (9 distinct).
One could argue that placing 9 variables, including their logic to check whether they exist, in the recipe, bloats the code considerably. See: https://github.com/opscode-cookbooks/ntp/blob/master/recipes/default.rb#L38-44
I agree that performing complex calculation in the template is a bad idea, but for checking the existence of an attribute and performing an action is preferable to the recipe checking the conditional, passing a variable, and then the template checking for the conditional, and acting on that.
Here's an example of doing the bulk of the conditional in the template: https://github.com/DataDog/chef-datadog/blob/master/templates/default/datadog.conf.erb#L19-135
Duplicating all the conditional logic before it's passed as a variable template seems like clutter, and induces a second update per variable added.
The text was updated successfully, but these errors were encountered: