What is Functional Programming?
Functional programming is an interesting paradigm where the focus is not on the data, necessarily, but on functions and using them to their full potential.
Functional Programming vs. Object Oriented Programming
Functional programing is the idea that code should focus on utilizing functions rather than data as the main abstraction level.
This style conflicts most with object oriented programming (OOP), which is widely used as well. The best way I have found to describe the difference between OOP and functional programming is the main abstraction idea that drives the two paradigms.
In OOP the data is the focus; you describe the flow using objects and how they are changed internally. Functional programming however relies more on abstracting verbs into generic functions that do not mutate the original state of data.
One example of where this would be useful is when there are frequent “if” statements that change the same variables. Consolidating functions across objects reduces maintenance and decreases the likelihood of an unintended state.
The Benefits of Functional Programming
By now you are probably wondering why you should consider adapting your coding style with this paradigm—and there are quite a few perks.
One of the biggest improvements is the code readability.
Most programmers have received a task that deals with legacy code. It can turn into a headache when the code is vague as to its purpose. Using functions that describe the actions taken on well defined variables can really improve the clarity of the code.
Another improvement is the reduction of side effects, problematic or even catastrophic results that stem from unexpected internal object data changes. A stateless approach is also needed in this style, which helps enforce the reduction in side effects.
This paradigm isn’t perfect but it is a different approach, which is always a good thing to consider when solving problems.
This sounds like a pretty basic idea, but is very different than OOP because of how the data is used. Instead of focusing on modification of variables or objects, you use functions to mutate specific variables, but don’t change them internally. This helps keep the variable for use later or decreases the number of variables needed.
Another main concept is abstraction when it comes to functionality; this process entails examining what actions are happening in different functions and extracting any generic patterns into a separate function to be widely used.
These generic functions can also be extracted into a library for wider reuse, a centralized place to keep them. To avoid reinventing the wheel there are some libraries designed for this style of programming, including Underscore and Lodash.
Implementing Map and Reduce Functions
If you already have a code base, but decide that this paradigm might help relieve some issues you may have noticed, there are a few steps to take.
The first is to try and use functions instead of values. Two of the most heavily used functions for this are the map and reduce functions. Both are very concise and easy to use and can replace some intricate logic.
Map completes a function on every element in an array and reduce condenses the values in an array based on parameters and a given function.
Utilizing a Pipeline-like Data-Transformation Process
The next refactor step is to use more of a pipeline-like data-transformation process to reduce the side effects from data manipulation.
In example one, observe that each time the array was manipulated or used, a new variable was created that defines that exact data and state, and saved to that reference. When the array of strings is converted to integers the same variable could be used, but if the first array’s data is needed, then the integers need to be converted again.
Extracting Generic Functionality into Separate Functions
The final change that should take place is the extraction of generic functionality into separate functions that you can reuse.
This can be seen in the example above with the extraction of parsing an integer using base 10 and with the summation function that is used to get the total of the array values.
If there are enough of these a library can be created to centralize these generic functions and reuse them throughout the code base.
For example, variable state mutation has manifested itself many times, which causes issues with unexpected outputs because the intended state has changed.
Another problem that shows up periodically is from modular development on a piece of functionality. If the different pieces are broken up too much developers can fall into the trap of writing very specific logic to handle the different aspects that need to be implemented.