The One Thing I Wish I'd Known Before Using Cake

Set yourself up for success on your next DevOps project by avoiding this gnarly Cake mistake

The One Thing I Wish I'd Known Before Using Cake

Let's cut to the chase: A little known Werner Heisenberg axiom discovered during his 1927 quantum physics research states:

An equal number of calories spent on Ben and Jerry's Americone Dream Ice Cream is unequivocally more satisfying than those spent on any slice of cake, ever.

Wow!  If only I'd known earlier.  That guy was frickin brilliant!

While that anecdote is 100% true, this post is less about the cake certainty principal, as no one calls it, and more about the dependency management tool Cake, as in C# Make.  I've blogged about it many, many, times.  It's the C# equivalent to Grunt, Gulp, Maven, Rake, PSake, and replaces that nasty pile of PowerShell / bash scripts you keep in abject shame hidden away inside a folder /BoringImagesNothingToSeeHere.

Now any kind of software that tracks tasks and their dependencies rather than mindlessly running procedural code is typically offered by a tool that rhymes with make and is wonderful (yea you heard me right "psake", Japanese rice wine need not apply).  Dependency management tools decrease complexity and organize DevOps spaghetti.  But Cake has an unfortunate problem that's only apparent after several years of it building it up.

Are you ready for this?  Sure?

Holy jebus, what is that?!

That, my friends, is a single 2,000+ line build.cake file amassed after two years of active development split into 10 columns in VS code, zoomed out to max, as viewed on a 4K monitor.

It's also what space aliens use to terrorize computer science abductees into catatonia.  Its use is now expressly forbidden under the Geneva Convention.  

Sadly, I am its author.  

Wait, don't judge.  I mean, it's gotten better.  I swear: it's now all puppies and kittens dancing in synchrony on rainbows.  It's been nominated for a Nobel peace prize.

Happy ending, but you might not be so lucky.  If you are considering adopting Cake, and you absolutely should, here's the one bit of advise I wish I'd known:

Don't use a build.cake file.

Whoa, heresy.  Build.cake is the default file Cake uses when you initiate it with build.sh or build.ps1.  It's the file generated when you run the command "Install to workspace" in VSCode (from the Cake plugin).  Using anything else is inconvenient, poorly documented, and just weird.  If you hid that idea in a box even Erwin Schrödinger would agree it was dead.

Yet if you follow the easy path and put all your tasks in there by default like I did, you will end up with the afore mentioned large file problem, which becomes a maintenance nightmare but furthermore lacks encapsulation, a core tenant of good design.  In other words every task can access every other task, method or property even if it's completely unrelated.  And if one task needs a plugin, all the tasks get that plugin.

Maybe there's a middle path.  Let's explore our options.

The best tool available to solve Cake's weak sauce encapsulation story is the load directive:

#load OtherFile.cake

Once you start thinking about the large file and encapsulation problems and the only real tool you have to fix it, without giving up on build.cake you'll likely come up with this solution:

Have one file per "public" Task, and make build.cake reference each of those.  This was the interim step I took to solve my large file problem.  I thus had all the e.g. deployment tasks in one file and all the environment creation in another, and a nearly empty build.cake.

This solution is good and relatively tidy, files sizes are smaller, but plugin usage is still not isolated.  And it's still so tempting to slip something quick into build.cake if you (or the other dev's you're hoping to empower by writing DevOps in a language the whole team can understand) are in a hurry.

If I were starting Cake DevOps scripts on a new project I'd remove build.cake entirely:

Temptation removed.  Plugin usage is isolated.  And it's now clearer that any new "public" tasks like a new "Run UI Automation Tests" should be placed in a new dedicated file along with all dependencies.  It's also easier to refactor as things grow more complicated:

And before you accusing me of offering high level advice without any specifics, here's how to specify a custom cake file on a PC:

.\build.ps1 -Script deploy.cake -target=deploy

And here's how it looks on Linux/Mac:

./build.sh --script 'deploy.cake' -target=deploy

Subtle differences, case matters.

Conclusion

Rocket Science?  Not so much.  Is this insight on the level of Heisenberg's Americone Dream Axium?  Sadly, no.  But perhaps avoiding the use of deploy.cake will prevent your imminent trial at The Hague.  Just maybe.