Practical Functional Reactive Programming
Functional Reactive Programming is in our opinion, a great tool in the never ending fight with complexity. Today, we wanted to give you some tips that would help you make the most out of it.
Note: This article assumes that you have some basic knowledge of FRP, if you are new to the topic and you want to learn –
FRP is a fine example of the difference between simple and easy. It makes your code simple by providing a coherent set of concepts but what you get in exchange is a steep learning curve. You have to wrap your head around the paradigm first to use it effectively.
If you don’t put enough time into learning new ideas, you will misuse them and get results which are the opposite to what you may have expected — code which is hard to read, test and maintain.
Truth is in the name
You don’t have to look far when searching for fundamentals of Functional Reactive Programming — it’s all in the name! We will analyse it step by step to get the essence.
Functional programming is a paradigm that treats units of your application as mathematical functions. This provides some features that are not always guaranteed otherwise and FRP makes great use of it.
Every mathematical function has a clear input and output. You give two numbers, apply an addition and get a result. Thanks to this, your code will be easy to follow and maintain. If you build a complicated stream of events, always make sure you understand what is going in and what you’ll get on the other end.
Functional programming introduces operators that are building blocks of a new functions. Composing existing operators encourages code reuse. Make sure you understand the meaning of already existing operators. Some are easy to grasp (like map or filter), others will take more time and effort. If you carelessly use flatMap vs flatMapLatest before knowing the difference, you are asking for trouble.
Mathematical functions given the same input always produce the same output. This is a dream come true when it comes to the testability of our code. They have this property thanks to the fact that they don’t rely on external state.
Unfortunately, real world isn’t perfect and we still need something to bridge the gap between a functional core of your logic and an imperative shell of an outside world.
Reactive Extensions represent mutable state with Subjects. They are objects that you can observe and feed with values at the same time. This means, that if misused they can create side-effects and make your code harder to reason with.
Subjects are necessary, but you should treat them like that ugly sweater you got from your grandma. You keep it in a closet and would rather go naked than wear it but when your grandma visits, this is a special occasion and it requires special clothes. Use subjects only on very special occasions.
Reactive programming is a paradigm that focuses on data-flows and observing events. As with the NotificationCenter and Delegate pattern, rather than checking periodically if something new happened, you register yourself as an observer and wait for a notification.
The most important thing that emerged from mixing reactive programming into FRP is time awareness. Your simple variable doesn’t know what it’s value was previously and you would have to write a lot of boilerplate code to get this behaviour.
With observables you are a master of time. But with great power comes great responsibility. If you don’t understand the mechanism that is used to buffer your values, you may end-up with large objects trashing memory, race conditions or sending redundant network requests. These bugs are much easier to fix in FRP than in imperative environment, but only if you understand how operators work.
Data-flows are a powerful concept, but it comes with a cost. With a large and complicated logic you can tangle yourself into a conceptual mess, wondering what data goes where. We have found that the greatest tools to handle this issue are graphs and marble diagrams. Draw early, draw often.
You could think that “programming” is just a word to bind functional and reactive together. You couldn’t be further from the truth. Programming in itself means to us a certain craft, that can consist of many areas that keep us sane in our work. We know about the most important rule of the craft:
Programs must be written for people to read, and only incidentally for machines to execute.
Harold Abelson, “Structure and Interpretation of Computer Programs”
Many of us facing new paradigm forget about this completely. Of course reading FRP code requires a minimum knowledge of concepts like streams, observers and so on, but after a certain threshold, if your colleague scratches his head during code review — it’s not the paradigm’s fault — it’s yours.
FRP definitely worked out for us. We work fast thanks to the power of reusable operators. Our code is more flexible — often we can just connect new operator or remove unnecessary one to get new behaviour. In conjunction with unit testing, fixing bugs is simple, because our code is readable and easy to follow.
Functional Reactive Programming is a great tool for modern applications, that do a lot of asynchronous work and network requests. Before accessing the full power of the paradigm you have to bend your mind first and learn new concepts. It’s very important, that you study and understand roots of it. This can be a large time investment and like all investments you have to decide for yourself if the return is worth it.
We’d Love to Hear from You
Did it work for you? Have we broadened your understanding of Functional Reactive Programming? Would you like to see more content like this? Is there anything you’d like to add, have we missed anything?
Please feel free to share your experiences and questions with us in the comments below or via social media (send us some photos or videos too), you can find us on Facebook, Twitter, Instagram and Pinterest, let’s connect!
All images used are CC0 1.0 Universal (CC0 1.0).