The Setup

While working on a Clojure application that was for production, rather than being an exercise, I saw that I was using OO programming with the syntax of Clojure. I was having problems coming back to change code that I have done not long before. Testing was an absolute pain, with continuous use of with-redefs and weird subnesting of let statements happening all over the place. Clearly, my knowledge, and my internalization of functional programming, wasn't good enough. It was time to start looking into how to improve my skills.

Thanks to my colleagues at Codurance I discovered that at SoCraTes UK 2015 there was a discussion already about Functional Calisthenics, organized by Ian Johnson, and which results you can find at his blog post Introducing Functional Calisthenics.

After a bit of trying, I though that a few of the rules were not exactly how I would have set them up and lacked clarity about the point of the rules. Therefore, we sat down, a few functional programmers at Codurance, and revised the rules. The below represents the rules after this revision, including how to apply them and what is the expected outcome of learning to use those rules.

The Rules

These rules are constraints on how to create your code and are only intended to be applied when doing katas or exercises. During the exercises you should follow them to a t. Following this rules on production code is left as a decision for each. I envision to start using them in the order below; some rules build on top of previous rules to achieve better knowledge and understanding of functional programming.

Name everything

No mutable state

Exhaustive conditionals

Do not use intermediate variables

Expressions not statements

No Explicit recursion

Generic building blocks

Side effects at the boundaries

Infinite Sequences

One argument functions

λ Name everything

Most basic one. It will seem harsh for experienced functional programmers. First one to be broken on production code.

Description

All functions need to be named. Which means that you shouldn't use lambdas or anonymous functions. Also, name all your variables as per standard clean code rules.

Expected Outcome

Learn to recognize patterns on your code. It will help recognizing signatures that repeat, and the applying of DRY on your code. Also, it will clearly express the intention of the action, rather than just show the implementation.

λ No mutable state

This is the basis of FP.

Description

You shouldn't use any variable of any type that can mutate.

Expected Outcome

Learn how to create code around immutable variables.

Two main benefits:

FP is about immutability. Most of its benefits comes from the fact that all your functions are (or should be) referencially transparent.

Use of recursion as your main looping technique. No for or while loops in your code. For comprehensions abide by this rule.

λ Exhaustive conditionals

Description

Expected Outcome

λ Do not use intermediate variables

Description

Expected Outcome

λ Expressions, not statements

Description

Expected Outcome

λ No explicit recursion

Description

loop/recur

let rec

Expected outcome

λ Generic building blocks

Description

Expected Outcome

λ Side effects at the boundaries

This rule is mostly preparation work.There can not be an if without an else. Switches and pattern matching should always have all paths considered (either through default paths or because all options have been considered).. A function should know how to deal with all possible values passed as arguments.There shouldn't be any variable declared in the body of a function. Only parameters and other functions should appear on the body.Functions are the building blocks of functional languages and the combination of functions create the logic of your application. Not having intermediate variables means changing the way that you think about your functions, and how the body of a function (composed of other functions) is, so the code remains legible and easy to follow.A consequence of the two previous rule. Or a generalization.All lines should be expressions. That's it, all lines should return a value.Statements that are not expression are there for their side-effects. Nothing like that should be in the code.Not as harsh as it looks.You shouldn't use explicit recursion like Clojure'sforms or F#form.The idea is powerful enough to be the basis of some systems (Apache Hadoop) and has appeared on non-FP languages.One of the advantages of FP languages is that is easy to generalize algorithms.Try to use a much as possible generic types for your functions, outside of the boundaries of your application. Don't use a list, use a collection; Don't use an int when you can use a number; so forth and so on.Using existing functionality and High Order Function provided by your language stack becomes much easier.

On the original was at the Top Level. We wanted to extend due to advance scenarios (but is standing on thin ice this reasoning)

Description

Side effects should only appear on the boundaries of your application. The guts of your application should have no side effects.

Expected Outcome

λ Infinite sequences

Description

Expected Outcome

λ One argument functions

Description

Expected Outcome

The Conclusion

The main outcome is to create code on which you have tight control over side effects, when are the executed and to limit the effect on them on your logic. All your code logic should depend exclusively on parameters provided.Another harsh rule. One that in production will depend a lot on the optimizations of the language.All sequences, collections used need to be infinite collections. You can't use collections that need to have a fixed size specified.Personally, I have found this rule the most difficult to apply. There are some cases at the moment that I have found either very difficult or creating a massive number of additional functions.Each function should have a single parameter. You need to be explicit, just using the fact that the language works by automatically applying currying is not enough (Haskel, F#, ...) The parameter can be a structure/map or some other complex type (don't think this restricts to primitives).Currying and partial function usage.

We have started to use them on katas. They force us to think about how we are coding and force us to move away from our standard OOP mentality. At the moment we see them as a good way to improve our skills.

Of course, this represents the second iteration that we did of the rules. And it is possible that at some point they change. Don't hesitate to contact us to improve them.

We will be adding a pdf version with the rules and we will be showing some code in the near future.

If you're passionate about code quality and want to work with functional programming, check out our job-board here!