Becoming Functional - Several Questions
Functional programming (or FP) has been around since the earliest days of computing, and is going through a sort of revival because of its increased use with several frameworks and libraries, most particularly in JavaScript (JS). In this chapter, we shall do the following:
- Introduce some concepts of FP to give a small taste of what it means.
- Show the benefits (and problems) implied by the usage of FP and why we should use it.
- Start thinking about why JavaScript can be considered an appropriate language for FP.
- Go over the language features and tools that you should be aware of in order to fully take advantage of everything in this book.
By the end of this chapter, you'll have the basic tools that we'll be using in the rest of the book, so let's get started by learning about functional programming.
What is functional programming?
If you go back in computer history, you'll find that the second oldest programming language still in use, Lisp, is based on FP. Since then, there have been many more functional languages, and FP has been applied more widely. But even so, if you ask people what FP is, you'll probably get two widely dissimilar answers.
Depending on whom you ask, you'll either learn that it's a modern, advanced, enlightened approach to programming that leaves every other paradigm behind or that it's mainly a theoretical thing, with more complications than benefits, practically impossible to implement in the real world. And, as usual, the real answer is not in the extremes, but somewhere in between. Let's start by looking at the theory versus practice and see how we plan to use FP.
Theory versus practice
In this book, we won't be going about FP in a theoretical way. Instead, our point is to show you how some of its techniques and tenets can be successfully applied for common, everyday JavaScript programming. But—and this is important—we won't be going about this in a dogmatic fashion, but in a very practical way. We won't dismiss useful JavaScript constructs simply because they don't happen to fulfill the academic expectations of FP. Similarly, we won't avoid practical JavaScript features just to fit the FP paradigm. In fact, we could almost say that we'll be doing Sorta Functional Programming (SFP) because our code will be a mixture of FP features, more classical imperative ones, and object-oriented programming (OOP).
Be careful, though: what we just said doesn't mean that we'll be leaving all the theory by the side. We'll be picky, and just touch the main theoretical points, learn some vocabulary and definitions, and explain core FP concepts, but we'll always be keeping in sight the idea of producing actual, useful JavaScript code, rather than trying to meet some mystical, dogmatic FP criteria.
OOP has been a way to solve the inherent complexity of writing large programs and systems, and developing clean, extensible, scalable application architectures; however, because of the scale of today's web applications, the complexity of all codebases is continuously growing. Also, the newer features of JavaScript make it possible to develop applications that wouldn't even have been possible just a few years ago; think of mobile (hybrid) apps that are made with Ionic, Apache Cordova, or React Native or desktop apps that are made with Electron or NW.js, for example. JavaScript has also migrated to the backend with Node.js, so today, the scope of usage for the language has grown in a serious way that deals with all the added complexity of modern designs.
A different way of thinking
FP is a different way of writing programs, and can sometimes be difficult to learn. In most languages, programming is done in an imperative fashion: a program is a sequence of statements, executed in a prescribed fashion, and the desired result is achieved by creating objects and manipulating them, which usually means modifying the objects themselves. FP is based on producing the desired result by evaluating expressions built out of functions that are composed together. In FP, it's common to pass functions around (such as passing parameters to other functions or returning functions as the result of a calculation), to not use loops (opting for recursion instead), and to skip side effects (such as modifying objects or global variables).
In other words, FP focuses on what should be done, rather than on how. Instead of worrying about loops or arrays, you work at a higher level, considering what you need to be done. After becoming accustomed to this style, you'll find that your code becomes simpler, shorter, and more elegant, and can be easily tested and debugged. However, don't fall into the trap of considering FP as the goal! Think of FP only as a means to an end, as with all software tools. Functional code isn't good just for being functional, and writing bad code is just as possible with FP as with any other technique!
What FP is not
Since we have been saying some things about what FP is, let's also clear up some common misconceptions, and look at what FP is not:
- FP isn't just an academic ivory tower thing: It is true that the lambda calculus upon which it is based was developed by Alonzo Church in 1936 as a tool to prove an important result in theoretical computer science (which preceded modern computer languages by more than 20 years!); however, FP languages are being used today for all kinds of systems.
- FP isn't the opposite of object-oriented programming (OOP): It isn't a case of choosing declarative or imperative ways of programming. You can mix and match as best suits you, and we'll be doing this throughout this book, bringing together the best of all worlds.
- FP isn't overly complex to learn: Some of the FP languages are rather different from JavaScript, but the differences are mostly syntactic. Once you learn the basic concepts, you'll see that you can get the same results in JavaScript as with FP languages.
It may also be relevant to mention that several modern frameworks, such as the React and Redux combination, include FP ideas.
For example, in React, it's said that the view (whatever the user gets to see at a given moment) is a function of the current state. You use a function to compute what HTML and CSS must be produced at each moment, thinking in a black-box fashion.
Similarly, in Redux you have the concept of actions that are processed by reducers. An action provides some data, and a reducer is a function that produces the new state for the application in a functional way out of the current state and the provided data.
So, both because of the theoretical advantages (we'll be getting to those in the following section) and the practical ones (such as getting to use the latest frameworks and libraries), it makes sense to consider FP coding. Let's get on with it.
Why use FP?
Throughout the years, there have been many programming styles and fads. However, FP has proven quite resilient and is of great interest today. Why would you want to use FP? The question should rather first be, what do you want to get? and only then, does FP get you that? Let's answer these important questions in the following sections.
What we need
We can certainly agree that the following list of concerns is universal. Our code should have the following qualities:
- Modular: The functionality of your program should be divided into independent modules, each of which contains what it needs to perform one aspect of the program's functionality. Changes in a module or function shouldn't affect the rest of the code.
- Understandable: A reader of your program should be able to discern its components, their functions, and their relationships without undue effort. This is closely linked with the maintainability of the code; your code will have to be maintained at some time in the future, whether to be changed or to have new functionality added.
- Testable: Unit tests try out small parts of your program, verifying their behavior independently of the rest of the code. Your programming style should favor writing code that simplifies the job of writing unit tests. Unit tests are also like documentation in that they can help readers understand what the code is supposed to do.
- Extensible: It's a fact that your program will someday require maintenance, possibly to add new functionality. Those changes should impact the structure and data flow of the original code only minimally (if at all). Small changes shouldn't imply large, serious refactoring of your code.
- Reusable: Code reuse has the goal of saving resources, time, and money, and reducing redundancy by taking advantage of previously written code. There are some characteristics that help this goal, such as modularity (which we already mentioned), high cohesion (all the pieces in a module belong together), low coupling (modules are independent of each other), separation of concerns (the parts of a program should overlap in functionality as little as possible), and information hiding (internal changes in a module shouldn't affect the rest of the system).
What we get
So does FP give you the five characteristics we just listed in the previous section?
- In FP, the goal is to write separate independent functions that are joined together to produce the final results.
- Programs that are written in a functional style usually tend to be cleaner, shorter, and easier to understand.
- Functions can be tested on their own, and FP code has advantages in achieving this.
- You can reuse functions in other programs because they stand on their own, not depending on the rest of the system. Most functional programs share common functions, several of which we'll be considering in this book.
- Functional code is free from side effects, which means you can understand the objective of a function by studying it without having to consider the rest of the program.
Finally, once you get used to the FP style of programming, code becomes more understandable and easier to extend. So it seems that all five characteristics can be achieved with FP!
Not all is gold
However, let's strive for a bit of balance. Using FP isn't a silver bullet that will automagically make your code better. Some FP solutions are actually tricky, and there are developers who greatly enjoy writing code and then asking, what does this do? If you aren't careful, your code may become write-only and practically impossible to maintain; there goes understandable, extensible, and reusable out the door!
Another disadvantage is that you may find it harder to find FP-savvy developers. (Quick question: how many functional programmers sought job ads have you ever seen?) The vast majority of today's web code is written in imperative, non-functional ways, and most coders are used to that way of working. For some, having to switch gears and start writing programs in a different way may prove an unpassable barrier.
Finally, if you try to go fully functional, you may find yourself at odds with JavaScript, and simple tasks may become hard to do. As we said at the beginning, we'll opt for sorta FP, so we won't be drastically rejecting any language features that aren't 100% functional. After all, we want to use FP to simplify our coding, not to make it more complex!
So, while I'll strive to show you the advantages of going functional in your code, as with any change, there will always be some difficulties. However, I'm fully convinced that you'll be able to surmount them and that your organization will develop better code by applying FP. Dare to change! So, given that you accept that FP may apply to your own problems, let's now consider the other question, can we use JavaScript in a functional way and is it appropriate?