Semantic Chef: Writing Readable Recipes
The second in a short series of Chef related blog posts
Why Chef is awesome
- Programmable in Ruby
- Repeatable recipes define your infrastructure
Why Chef is painful
- Programmable in Ruby
- Slow ‘REPL’ to test changes
Ruby lets you do just about anything. It’s a programming language, that’s what it is supposed to do. Chef’s DSL is concise, readable and extensible. The power of Chef comes by allowing you to program in Ruby. When mixing Chef’s DSL with the power of ruby, things can get out of hand if you are not careful.
The Opscode examples show nice things. As a systems person it is very easy to understand what is going on.
1 2 3 4 5 6 7 8 9 10 11 12 13
Add some more complex logic in and we get a bit messier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Sure you can figure out what it does… eventually.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
I dont like this. When I look at a recipe I want to be able to easily understand what it is doing. It is a recipe, not an annotated thesis. It should be a simple browsable description of your intentions. Real cookbooks don’t describe the minutia of each step, they tell you the general steps and leave you to figure out the details.
- Get your logic out of your recipe, put it in a library.
- Abstract connected DSL blocks to LWRPs, control will be simpler
- Use name attributes carefully.
- Give friendly names to referenced node attributes.
- Development Speed
Developers who aren’t that familiar with Ruby or Chef can still easily read recipe code. It is designed to be readable and declarative. The recipes should define the pieces of your infrastructure, not the edge cases.
It is hard to test Chef directly. Usually it just results in you running all of the code and testing the system’s final state. When you separate your logic from your Chef code, you separate your concerns. You now have logic to which you can easily apply standard Ruby testing methods. The rest of the recipe is now just Chef code that only needs to be checked for regressions.
Now that you have your logic separate, you can write it just like regular Ruby. You don’t need to waste all of your time waiting for VMs to spin up and compile packages. The only time you need to run Chef is to verify your DSL blocks are set up correctly.
- You have to learn about library files
- You have to write tests
- You have to name more things.
- You’ll have to learn about when Chef loads and runs libraries
- You’ll have to learn more Ruby
- Less elegant code to force calling from Library files.
Chef manipulates Infrastructure as Code, its about time you started treating your infrastructure code like your application code.
Note : Discussions of this could easily devolve into the MVC “where do I put my logic” debate.
Andrew Gross is a Developer at Yipit, you can find him as @awgross on Twitter