Wednesday, 4 February 2015

Pragmatic Functional Refactoring in Java 8

Java 8 is here! Now the honeymoon period is over larger companies and innovators are starting to use the new features. However, Java 8 isn't just another version of Java, it fundamentally changes how you are able to approach problems.

"Java 8 and functional programming is not just for beards" -- Raoul, and is now available to developers in general. Many business problems can be expressed in an easier way than in a declarative style of programming. It is a well known fact however, if there is someone with a beard next to you they probably are a functional programmer. 

The slide deck from JFokus can be found here, the session was also recorded by the VirtualJug in September last year.

The talk is aimed at making functional techniques relevant to programmers and takes the approach of introducing a problem and how it can be solved using functional techniques. The good thing about this style is that the emphasis on how to apply functional programming techniques is not bogged down in buzzwords or potentially confusing terminology. 

The talk starts out with a problem we often face as software developers. Initially we have simple requirements that over time change and if the code is not designed correctly or refactored when necessary can be unwieldily and difficult to maintain. The problem domain introduced is around invoices:
  • Filtering all customers of a specific name
  • Later we want to process different customers rather than a fixed customer
  • We also now want to separate out different functions with that company that may have a different suffix representing the type of activity carried out
  • We also now want to state whether we want the invoice included or not
The result is some fairly messy code:


From the messy code the talk goes on to look at how applying functional methods can reduce some of the problems. Introducing the Predicate interface from the Java 8 API allows a test for whether an invoice should be included. This simplifies the code dramatically as the test for inclusion of an invoice can be packaged up and passed into the method as a function. This is the core of how first-class functions work, allowing a function to be passed around as a first-class citizen in the language. The introduction of method reference is shown as an intermediate step, but we finally see our lambda solution that makes everything quite clear. As a Predicate is a functional interface the test can be passed in as a simple lambda expression. The intent of the code is now clear and considerably simplified:


Compositing functions together to create more advanced predicates is next on the agenda, introducing how more complex functions can be combined together using the and, or methods. Just as it's a bit weird to wonder how this is working, as a Predicate is simply an interface we learn a new concept Default Methods introduced in Java 8. The discussion finishes with a conversation about how pipelines can be used to chain functions together, where the sequence of application is important.  The example discussed is an E-Mail where first the content is created, followed by the spell check and the addition of the signature. 

The next topic for the pragmatic approach to refactoring is currying and partial application. Currying is a tricky topic to initially wrap your head around and involves taking an initial argument set and splitting them out, so parts of the overall logic can be reused as functions. The talk looks at how to refactor a conversation function to be used for converting common measurements such as temperature and mass. I like to think of the approach as at each step the initial argument set is locked down or partially applied. I definitely advise watching the section on currying, Richard and Raoul do a great job of explaining the concepts. Here is the example used in the presentation:


Mutability is problematic, specifically where developers make things mutable that would be far better modelled as immutable objects. Mutability can introduce subtle bugs where a developer takes a reference and updates an object - however it could be years before that actually manifests itself as a production problem and can be tricky to find. There are however some cases where you need to use mutable objects and this is fine. The key is to use the right design for the right requirements within your application. 

The talk goes on to cover Optional and how it can be used to help prevent NullPointerExceptions in chained code and provide the ability for a developer to provide default values or return a slightly different result. Another key benefit of Optional is the removal of lots of boilerplate null checks that can lead to issues around code readability. This part of the talk is extremely clever and introduces a practical case for the flatMap method on Stream to get at the contents of the Optional container. I actually heard several developers comment on how useful this was to them after the talk. 

The talk is a taster of the full course that is run by myself, Richard and Raoul  More information can be found on our training site, with public course running in Switzerland, United Kingdom and Sweden in the coming months. 


No comments:

Post a Comment