Functional programming is a set of skills
Definitions of functional programming disagree with each other and often don't encompass the broad range of languages and practices we find in industry. The definitions also make it seem incompatible with other paradigms, such as object-oriented and procedural. However, if you look at FP as a set of skills, both problems are solved. We can find skills that functional programmers tend to use and not be incompatible. In this episode, I explore some important, high-level skills that functional programmers employ.
Eric Normand: Functional programming is skills. By the end of this episode, you will know what are the most important skills in functional programming.
My name is Eric Normand and I help people thrive with functional programming.
A lot of people ask, "What is functional programming?" There's a lot of answers out there. They're somewhat contradictory. Sometimes they're helpful, sometimes they're not.
In the book I'm working on — the book's called "Grokking Simplicity" — which is out now, if you want to go check it out, I have found it most useful to bypass the definition, trying to define what functional programming is, and saying, "Well, that is functional programming, that isn't functional programming."
Just bypass that whole thing and look at it as just a set of skills. It's basically the skills that functional programmers do more often than other people do.
They're not incompatible with other paradigms, right? Object-oriented programming, you could also look at it like a set of skills. They're not incompatible. Object-oriented programming has encapsulation and object-oriented modeling, and those are useful skills.
Functional programming has different skills that you can mix and match and use them together with other paradigm skills. What are those skills? I'm going to go over five main skills right now.
Skill number one. I feel like this is an incontrovertible skill that you have to have to call yourself a functional programmer. This is non-negotiable. You have to be able to discriminate between actions, calculations, and data. I don't care what you call them. I'm calling them those for a lot of reasons. I have episodes talking about why I chose those terms.
Actions, calculations, and data. You have to be able to look at your code and see, "Oh, that's an action, that's data, that's calculations." Calculations are computations from inputs to outputs. You might call them pure functions. This is pure calculations. Doesn't matter when you run them. You're going to get the same answer if you give it the same arguments.
Actions, on the other hand, can change depending on when you run them. You might call these impure functions, but they're not always functions. Just like calculations aren't always functions in your language, actions aren't always functions.
Sometimes it's an operator, like an arithmetic operator. That's a calculation, like + is a calculation, but ++, it's not a function, it's an operator. That is an action. You have to be able to separate these out, because calculations and data are very easy. They're much easier to work with. They're easier to test. They're easier to reuse because you don't worry about when they're getting run.
The actions — those are much harder. In general, you want to have fewer lines of code in actions. You move those lines of code into calculations. Then you want to spend extra time on them to make sure that you get them right. It really matters how you call them, when you call them, how many times you call them. That's skill number one. Discriminate actions, calculations and data.
Skill number two is to be able to work effectively with immutable values. We spend a lot of time in real-world information systems trying to keep records forever, or for as long as we can. We'll put papers...we'll file them away in a filing cabinet. We put some papers in a fireproof box. We use archival-quality paper and ink so that things don't decay over time.
We have rules about who's allowed to write on this paper. "Oh, no, this one is done. Don't write on it anymore." Maybe you stamp it and you say, "This has been checked and vetted. it cannot be changed anymore."
There's all sorts of real-world mechanisms for making things immutable, making our records permanent. When we're building computer software, often we are making an information system, but because of the way memory works — and memory is mutable, memory can change — we have thrown that out. We have to rebuild the skill of working with immutable data.
We have to rebuild that as a discipline somewhere, either in our programming team, as our programming discipline that we implement, or maybe our language implements it, or maybe our database implements it, but we need to have it somewhere. It's not the same as being able to write over stuff and change it willy-nilly, like you can with mutable data.
A functional programmer has to learn how to deal with the immutable data. Basically, you're making a lot of copies. That's basically what it is. I have a whole episode just on working with immutable values.
One of the bigger challenges is working with nested data, because you want to change something deep in some nested structure. You have a company, has employees, and the employees have salaries, and you want to give everyone a 10% raise.
You're actually going through the company. It's an immutable value that represents the company. The employee is immutable, and the raise is immutable, or the salary is immutable. How do you make a copy of that whole tree so that you can give everyone a raise? Maybe you're just giving one employee a raise. What do you make copies of? That is a skill that functional programmers develop.
All right, let's move on. Skill number three. This is another important skill. This is where the power of functional programming really starts to come out and shine. It's using and creating higher-order calculations and actions.
I've combined a whole bunch into one skill. I don't know why I did that. It's really four things. It's using higher-order calculations, using higher-order actions, then creating higher order calculations, and creating higher-order actions. It fit well in one sentence, so let's call it one skill, skill number three.
Higher-order actions and calculations means they are actions and calculations that you can treat like any other value. You can pass them to functions as arguments. You can return them from functions. You can store them in a variable, those kinds of things.
When they're higher-order, it means that you can pass behavior to another function, or you can take, let's say, an action, and automatically make it idempotent. Take an action and automatically make it retry three times if it fails.
You can do stuff like that if you're operating at a higher-order level. You can do it without it, except you're writing a bespoke program to retry three times every time. By having it be higher-order, you're able to manipulate it in a regular way so that you can have this behavior that is typically just boilerplate, you can have it just define one place, and it works properly everywhere.
This is where the power comes from of functional programming, where we have stuff like map, filter, and reduce. Those are higher-order functions. They take functions, basically, letting you build data transformation pipelines.
This is where you get stuff like having sequences of actions that can retry, and what happens when they fail. You can define all of that compositionally instead of just a straight-up, top-down code.
This is very abstract stuff so it's hard to explain. As I'm speaking, I can tell I'm not getting this stuff through very easily.
In structure and interpretation of computer programs, one of the first exercises — I think it's in chapter one — is writing a function that takes a function, and it returns a new function that calculates the derivative. You pass in F — that's the argument — and it returns a function that is the derivative of F.
You don't know what F is. It could be any mathematical function. That's the kind of cool stuff that you can do in functional programming that's hard to do without those first-class functions.
Let's move on to skill number four, data modeling. We have these situations, these problems, these real-world processes that we are trying to automate. We're trying to solve with software instead of physical process. How do we do that?
How do we take measurements and other facts about the world, about things that are happening, combine those together into concrete structures in our code, so that we can effectively use them? Data modeling is all about, how do you effectively structure the data that you have so you can use it effectively?
I have an episode all about the two kinds of data modeling that we do. There's the data modeling where you're having a public-facing data that needs to exit your library, exit your server. It's part of the API. That data has different design constraints on it.
It needs to be human-readable. The developer on the other side is going to be writing that or writing a program to write that. They have to understand it pretty well.
Then there's the data modeling that's internal, where let's say you're doing some kind of search through a space. You need to represent the data in a certain way so that search is efficient and all the data you need is available, etc. That's an internal data modeling.
These two skills are very important in functional programming. I also think that they're more advanced. I've been working up the chain here. I start at skill one, where you identify actions, calculations, and data. This is the beginning of functional programming. Data modeling is way near the end.
Number five is architecture skills. You're building a system. You're building software. You can't just throw all the code. If it's a little bit of code, you can just put it in one file. Architecture doesn't matter. As it scales up, you don't want it to fall down. You don't want it to become unmanageable.
You need some kind of design principles, some kind of architectural principles. Functional programming has those, has some, right? They're a little bit different from what you find in other paradigms.
One architectural pattern that comes from the function programming world is the reactive data, reactive architecture. I don't know if you're familiar with Redux in the React world, or the Elm Architecture, or re-frame in ClojureScript. There's many of these.
The idea is, events are being generated. You are consuming those events. That generates a view of the world, and that view is projected out, say, onto a GUI. You have some state somewhere that is being modified, some centralized state. You modify that.
Then, from that, it generates a projection onto a GUI. You have a cycle going on, and it's all being done based on reactions, based on changes to the data. It's an architectural pattern that you see in the React world quite a bit.
Another architectural pattern is the Onion Architecture. I talked about this. There's episodes about it. The Onion Architecture, there are three main layers to this onion. It's like a sphere, like an onion, where the outer layer is the interaction layer. This layer is where you put all your actions. This is the stuff that talks to the outside world, that gets messages from the outside world.
Then that layer calls into the second layer, which is a calculation. It's a bunch of calculations, no actions in there. It is called the business rule layer. That second layer is where you have all the changing requirements of your business — how you calculate payroll, what's your vacation policy — all this kind of stuff is in your business rule layer.
Then inside that is the domain layer. This is the domain model. There's just those three main layers. You can break up each layer into more layers if you want, but the architectural pattern is just these three layers. Inside that domain layer is the timeless domain model that the business rules call into.
Like I said, the business rules could be vacation policy and how you calculate salaries, but inside the domain model is the timeless idea that employees do get a salary, and it is some fixed amount. Employees do get certain amounts of vacation. How much vacation? That's a business rule, but they do get vacation, is part of the domain model.
Separating the things out into this Onion Architecture helps separate things out into a fast-changing layer. That's where all your actions go, your interaction layer, because you're connecting to this API. There's a version change for that API. Got to modify the code to talk to this API, that API. That's changing very rapidly.
The business rules change rapidly, but not as rapidly as that. "Oh, the vacation policy changed. We've got to modify our code." Then inside that domain model is the stuff that changes the least frequently. The fact that employees get vacation is a pretty timeless thing.
Even if something weird happens and employees start getting zero vacation, that is at least modelable inside the domain model, and you know it's a weird case. "Right now, we're not giving vacation. Right now, all of our salaries are at zero." [laughs] It's still a number. It still fits in the model.
All right, these are five skills that I am working on in my book. The book is called, "Grokking Simplicity." You can get an early access version now. If you're listening to this in my future, this is obviously my present, but in my future, it could be out. It could be finished. Get it. Buy the book. It's published at Manning. Just google, "Grokking Simplicity." You'll find it.
Here are the five skills. I'll go over them again. There's more skills. I just have some big ones here. Discriminating actions, calculations, and data. Number two, working with immutable values. Number three, higher-order calculations and actions. Four is data modeling, and five, functional architecture.
If you liked this episode, you should go to lispcast.com/podcast. There you will find all the old episodes, including audio, video, and text transcripts of everything. You'll also find links to subscribe so you can get in whatever format you want. You'll also find links to find me on social media so we can talk.
Just a warning. If you do reach out, ask me a question or you have a comment, I might mention you in an upcoming episode. If you don't want me to mention you — maybe you don't want me to use your name or you don't like the question going public — just let me know that you don't want that.
Otherwise, I use this as a public forum. If you ask me a question, it's going to be broadcast out. Just let me know, and I just won't use it.
Cool, thank you so much. This has been my thought on functional programming. My name is Eric Normand. Thank you for listening, and rock on.