Functional Thinking

Functional Programming is more than a set of principles. It's a paradigm; a different way of thinking. It focuses on the “what” is being done, as opposed to the “how” it’s being done as in Object Oriented and Imperative paradigms.

The first functional programming language was created in 1960 (LISP), but interestingly, Functional Programming is a buzzword in software development at the moment. Several new functional programming languages were created in the last decade. Older languages such as Java, Ruby, and C# have incorporated functional principles as lazy evaluation, immutability, pure functions, and higher-order functions.1

Consider the following Java code that iterates through a list of sold items and adds the ones with no errors to a new list:

Java for cycle iterating list and adding to other list based on conditionList filter - Imperative version

“Oh, you mean filters sold items with no errors?! Why didn’t you said so?”

Functional alternative using Java streams List filter - Functional version

Imperative thinking became so natural, we see past verbose code. Nonetheless, it requires reading and understanding four lines of code to get to what the code is doing.

The real gain is not having three lines of code less. Very similar problems occur over and over again, sometimes on the same method. If the functional approach is used, every time we'll write less logic, reducing the odds of introducing errors.

The functional power is easier to perceive when consecutive methods are composed to solve a more complex problem:

Java streams chaining example

The code above lists the IDs of items with errors sorted by selling date. How much code would have to be written the "traditional" way? The same required to read and understand the next time someone worked on it.

Why care?

Writing concise and functional code is not about feeling proud of ourselves. It has profound productivity implications and long-term consequences on the company. It's simple Software Economics.2

Why do developers read code? To change it. Developers need to understand the code before changing it to implement new features or simply fix bugs.

Robert Martin accounted “the ratio of time spent reading versus writing is well over 10 to 1”.3 Amdahl's law tells us bigger overall gains are achieved if we tackle tasks taking longer.4 In the software development case, reading code takes the most time. Imagine a situation where developers spend on average 80% of their time reading code and 20% changing it.

Graphic showing overall gain comparation between improvements on both activities

Overall impact on development from reducing activities time

If code is improved to a point where reading is reduced by 50%, it yields a 40% overall reduction, as opposed to 10% overall reduction in the case of writing improvement. 40% reduction in development time translates into a significant productivity increase.

Math aside, I have never met a developer who didn’t want to do a good job. And I've never met a developer who hasn't felt frustrated when working with hard-to-understand code. If code is hard to understand, we try to change it the least we can. The codebase starts to decay. The time taken to read and understand code will increase continuously; I would say exponentially. It will eventually reach a point where it is impossible to change or maintain, becoming a Legacy System.5 This is rock bottom, but the penalty in development costs started a long time before.

Functional thinking in action

During a recent feature implementation here at eBay, one of the tests looked as follows:

Java test creating list two elements and adding them to the list

Test snippet

There is nothing wrong with it, except it was one from a series of similar tests, with few differences between them; very common when doing test-driven development (TDD). The code had a strong smell from duplication.6 Imagine if the Item constructor changed, how many places would it impact?

Three strikes and you refactor. Putting the functional hat on and using a few Java tricks, this was how it looked after (no Java 8 functional features were used):

Same functionality but refactored into little methods

Same test with “functional” methods

Notice methods with, withId, and withName are syntactic sugar.7 They don’t do much, and they aren’t ideal for production code, but test performance is less critical. On the other hand, test readability is crucial, because tests are documentation, so the syntactic sugar is handy.

The final solution has more code than before, if we consider this one test. But several tests were impacted. Number of lines of code aside, the code now has phrases as list with item with Id=1 and name=“Toy” or assert that first of returned items equals to first of expected items. It became easy to read, highly maintainable, and highly reusable.

Notice firstOf and list methods are extremely reusable, even in production code. The more generic and simple a method is, the higher chances it will be reused. Methods that do one and only one thing. Every time they are reused, not much less code is written, but firstOf gives you the what and get(0) the how.

“It doesn’t apply to me”

One might argue “I can’t use a functional programming language.” Functional programming is about changing our way of thinking, not a programming language or technology. Of course a functional programming language makes things easier, but nothing prevents us from becoming "functional."

Some developers think small methods make the code messy. Execution flow is harder to follow as the code is dispersed. A highly cohesive method, unambiguously named, is easy to understand without having to read its code.

Another argument against small methods is the increase in method/function invocation, making applications less performant. These days, compilers perform a myriad of optimizations, including the inline of small methods. The remaining ones are never culprits for slowing down applications.8

Conclusion

Functional programming is not just a set of principles or techniques. It is a different paradigm, a different way of thinking. It focuses on making code more declarative. It is harder to write functional code when working with a "non-functional" programming language, but not impossible.

Functional programming helps making the code more declarative and reusable. More reuse means less duplication and higher maintainability. It is not going to solve all the problems you will face, there are no silver bullets.9 It is up to us developers to use it wisely, to think functional.

References

1 "Functional thinking", Neal Ford, O'Reilly, 2014

2 Software Economics

3 "Clean Code: A Handbook of Agile Software Craftsmanship", Robert C. Martin, Prentice Hall, 2009

4 Amdahl's Law , Wikipedia

5 Big ball of mud, Brian Foote and Joseph Yoder, June 1999

6 “Refactoring: Improving the Design of Existing Code”, Martin Fowler and Kent Beck, 1999

7 Syntactic sugar, Wikipedia

8 15 Top Factors That Impact Application Performance, APMDigest, April 2013

9 "The Mythical Man Month", Fred Brooks, Addison-Wesley, 1975