32,36 €
Learn how to use RxClojure to deal with stateful computations
Key Features
Book Description
Reactive Programming is central to many concurrent systems, and can help make the process of developing highly concurrent, event-driven, and asynchronous applications simpler and less error-prone.
This book will allow you to explore Reactive Programming in Clojure 1.9 and help you get to grips with some of its new features such as transducers, reader conditionals, additional string functions, direct linking, and socket servers. Hands-On Reactive Programming with Clojure starts by introducing you to Functional Reactive Programming (FRP) and its formulations, as well as showing you how it inspired Compositional Event Systems (CES). It then guides you in understanding Reactive Programming as well as learning how to develop your ability to work with time-varying values thanks to examples of reactive applications implemented in different frameworks. You'll also gain insight into some interesting Reactive design patterns such as the simple component, circuit breaker, request-response, and multiple-master replication. Finally, the book introduces microservices-based architecture in Clojure and closes with examples of unit testing frameworks.
By the end of the book, you will have gained all the knowledge you need to create applications using different Reactive Programming approaches.
What you will learn
Who this book is for
If you're interested in using Reactive Programming to build asynchronous and concurrent applications, this is the book for you. Basic knowledge of Clojure programming is necessary to understand the concepts covered in this book.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 336
Veröffentlichungsjahr: 2019
Copyright © 2019 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the authors, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Richa TripathiAcquisition Editor: Denim PintoContent Development Editor: Rohit Kumar SinghTechnical Editor: Gaurav GalaCopy Editor: Safis EditingProject Coordinator: Vaidehi SawantProofreader: Safis EditingIndexer: Mariammal ChettiyarGraphics: Alishon MendonsaProduction Coordinator: Jyoti Chauhan
First published: March 2015 Second edition: January 2019
Production reference: 1240119
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78934-613-8
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Konrad Szydlo has worked with Clojure for the last 7 years. Since January 2016, he has worked as a software engineer and team leader at Retailic, responsible for building a website for the biggest royalty program in Poland. Prior to this, he worked as a developer with Sky, developing e-commerce and sports applications, where he used Ruby, Java, and PHP. He is also listed in the Top 75 Datomic developers on GitHub.
Konrad is a part of the Clojurian Slack community, is very interested in functional programming, and gave a Datomic Database talk at the ClojureD conference in Berlin in 2015. He also gave a talk on Creating reactive components using ClojureScript React wrappers during Lambda Days in Kraków in 2016.
Leonardo Borges is a programming languages enthusiast who loves writing code, contributing to open source software, and speaking on subjects he feels strongly about. He has used Clojure professionally, both as a lead consultant at ThoughtWorks and as a development team lead at Atlassian, where he helped build real-time collaborative editing technology.
Leonardo is currently the CTO for MODRON. Apart from this book, he contributed a couple of chapters to Clojure Cookbook, O'Reilly.
Leonardo founded and currently runs the Sydney Clojure User Group in Australia. He also writes posts about software, with a focus on functional programming, on his website. When he isn't writing code, he enjoys riding motorcycles, weightlifting, and playing the guitar.
Eduard Bondarenko is a software developer living in Kyiv, Ukraine. He started programming using Basic on a ZX Spectrum a long time ago. Later, he worked in the web development domain. He has used Ruby on Rails for over 8 years. Having used Ruby for a long time, he discovered Clojure in early 2009 and liked the simplicity of the language. Besides Ruby and Clojure, he is interested in Go and ReasonML development.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Highly concurrent applications, such as user interfaces, have traditionally managed state through the mutation of global variables. Various actions are coordinated via event handlers, which are procedural in nature.
Over time, the complexity of a system increases. New feature requests come in, and it becomes harder and harder to reason about the application.
Functional programming presents itself as an extremely powerful ally in building reliable systems by eliminating mutable states and allowing applications to be written in a declarative and composable way.
Such principles gave rise to functional Reactive Programming and Compositional Event Systems, programming paradigms that are exceptionally useful in building asynchronous and concurrent applications. They allow you to model mutable states in a functional style.
This book is devoted to these ideas and presents a number of different tools and techniques to help manage the increasing complexity of modern systems.
This book is for Clojure developers who are currently building or planning to build asynchronous and concurrent applications, and are interested in how they can apply the principles and tools of Reactive Programming to their daily jobs.
Knowledge of Clojure and Leiningen—a popular Clojure build tool—is required.
The book also features several ClojureScript examples, and as such, familiarity with ClojureScript—and web development, in general—will be helpful.
Notwithstanding, the chapters have been carefully written in such a way that as long as you possess knowledge of Clojure, following these examples should only require a little extra effort.
As this book progresses, it lays out the building blocks required by later chapters, and as such, my recommendation is that you start with Chapter 1, What is Reactive Programming?, and work your way through subsequent chapters in order.
Chapter 1, What is Reactive Programming?, starts by guiding you through a compelling example of a reactive application written in ClojureScript. It then takes you on a journey through the history of Reactive Programming, during which some important terminology is introduced, setting the tone for the following chapters.
Chapter 2, A Look at Reactive Extensions, explores the basics of this Reactive Programming framework. Its abstractions are introduced, and important subjects such as error handling and back pressure are discussed.
Chapter 3, Asynchronous Programming and Networking, walks you through building a stock market application. It starts by using a more traditional approach and then switches to an implementation based on Reactive Extensions, examining the trade-offs between the two.
Chapter 4, Introduction to core.async, describes core.async, a library for asynchronous programming in Clojure. Here, you learn about the building blocks of communicating sequential processes and how reactive applications are built with core.async.
Chapter 5, Creating Your Own CES Framework with core.async, embarks on the ambitious endeavor of building a CES framework. It leverages knowledge gained in the previous chapter and uses core.async as the foundation for the framework.
Chapter 6, Building a Simple ClojureScript Game with Reagi, showcases a domain where reactive frameworks have been used to great effect in games development.
Chapter 7, The UI as a Function, shifts gears and shows how the principles of functional programming can be applied to web UI development through the lens of Om, a ClojureScript binding for Facebook's React.
Chapter 8, A New Approach toFutures, presents futures as a viable alternative to some classes' reactive applications. It examines the limitations of Clojure futures and presents an alternative: imminent, a library of composable futures for Clojure.
Chapter 9, A Reactive API to Amazon Web Services, describes a case study taken from a real project, where a lot of the concepts introduced throughout this book have been put together to interact with a third-party service.
Chapter 10, Reactive Microservices, introduces you to microservices, showing when using them gives an advantage over monolithic application design. Next, you see a working example of an API microservice written in Clojure.
Chapter 11, Testing Reactive Apps, explores various testing methodologies and introduces four Clojure unit testing frameworks.
Chapter 12, Concurrency Utilities in Clojure, explains why most object-oriented languages are not suited for multi-threaded programming and how Clojure can help developers. Finally, it walks you through available concurrency tools in Clojure.
Appendix, The Algebra of Library Design, introduces concepts from category theory that are helpful in building reusable abstractions. The appendix is optional and won't hinder learning in the previous chapters. It presents the principles used in designing the futures library seen in Chapter 8, A New Approach to Futures.
This book assumes that you have a reasonably modern desktop or laptop computer as well as a working Clojure environment with Leiningen (see http://leiningen.org/) properly configured. Installation instructions depend on your platform and can be found on the Leiningen website (see http://leiningen.org/#install).
You are free to use any text editor of your choice, but popular choices include Eclipse (see https://eclipse.org/downloads/) with the Counterclockwise plugin (see https://github.com/laurentpetit/ccw), IntelliJ (https://www.jetbrains.com/idea/) with the Cursive plugin (see https://cursiveclojure.com/), Light Table (see http://lighttable.com/), Emacs, and Vim.
You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packt.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packt.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Hands-On-Reactive-Programming-with-Clojure-Second-Edition. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: https://www.packtpub.com/sites/default/files/downloads/9781789346138_ColorImages.pdf.
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "That's why the next thing we do is call move-forward!."
A block of code is set as follows:
(fn [ctx val] (-> ctx canvas/save (canvas/translate (:x val) (:y val))
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
[default]exten => s,1,Dial(Zap/1|30)exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
Any command-line input or output is written as follows:
$ lein repl
Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Select System info from the Administration panel."
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us [email protected] a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packt.com.
Reactive Programming is a term that's gaining more and more recognition in the IT community. As we will see in this chapter, it is not a new topic and has been sadly overlooked for many years. Recent advancements in hardware and software, combined with applications requiring more elaborate user interactions, have resulted in the concept of Reactive Programming being rediscovered by a wider audience. Reactive Programming is both an overloaded term and a broad topic. As such, this book will focus on a specific formulation of Reactive Programming called Compositional Event Systems (CES).
In this chapter, we will cover the following topics:
A working example of a reactive application in Clojure
The history of Reactive Programming
The most common terms in Reactive Programming
The most common applications of Reactive Programming
Before covering some history and background behind Reactive Programming and CES, I would like to open with a working, and hopefully compelling, example: an animation in which we draw a sine wave onto a web page.
The sine wave is simply a graphical representation of the sine function. It is a smooth, repetitive oscillation, and at the end of our animation, it will look like what's shown in the following screenshot:
This example will highlight how CES does the following:
Urges us to think about
what
we would like to do as opposed to
how
Encourages small, specific abstractions that can be composed together
Produces terse and maintainable code that is easy to change
The core of this program boils down to four lines of ClojureScript:
(-> app-time (.pipe (rx-take 700)) (.subscribe (fn [{:keys [x y]}] (fill-rect x y) "orange"))))
Simply by looking at this code, it is impossible to determine precisely what it does. However, do take the time to read and imagine what it could do.
First, we have a variable called app-time, which represents a sequence of time. The next line gives us the intuition that app-time is some sort of collection-like abstraction: we use rx-take to retrieve 700 numbers from it.
Finally, we have to .subscribe to this collection by passing it a callback. This callback will be called for each item in the sine wave, finally drawing out the given sine coordinates using the fill-rect function.
This is quite a bit to take in for now, as we haven't seen any other code yet, but that was the point of this little exercise: even though we know nothing about the specifics of this example, we are able to develop an intuition of how it might work.
Let's see what else is necessary to make this snippet animate a sine wave on our screen.
This example is built in ClojureScript and uses HTML5 canvas for rendering and RxJS (see https://github.com/reactivex/rxjs), a framework for Reactive Programming in JavaScript.
Before we start, keep in mind that we will not go into the details of these frameworks yet; that will happen in the next chapter. This means I'll be asking you to take quite a few things at face value, so don't worry if you don't immediately grasp how things work. The purpose of this example is to simply get us started in the world of Reactive Programming.
For this project, we will be using figwheel (see https://github.com/bhauman/lein-figwheel), a Leiningen template for ClojureScript that gives us a sample working application that we can use as a skeleton.
To create our new project, head over to the command line and invoke Leiningen as follows:
lein new figwheel sin-wave
cd sin-wave
Next, we need to modify a couple of things in the generated project. Open up sin-wave/resources/index.html and update it to look like the following:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="css/style.css" rel="stylesheet" type="text/css"> <script src="js/rxjs.umd.js" type="text/javascript"></script></head> <body> <div id="app"></div> <script src="js/compiled/sin_wave.js" type="text/javascript"></script> <canvas id="myCanvas" width="650" height="200" style="border:1px solid #d3d3d3;"></canvas> </body></html>
This simply ensures that we import both our application code and RxJS. We haven't downloaded RxJS yet, so let's do that now. Browse to https://unpkg.com/rxjs/bundles/rxjs.umd.js and save this file to sin-wave/resources/public/js. The previous snippets also add an HTML5 canvas element, onto which we will be drawing.
Now, open /src/cljs/sin_wave/core.cljs. This is where our application code will live. You can ignore what is currently there. Make sure you have a clean slate like the following one:
(ns sin-wave.core) (defn on-js-reload[])
Finally, go back to the command line under the sin-wave folder and start up the following application:
lein figwheel
Figwheel: Cutting some fruit, just a sec ... Figwheel: Validating the configuration found in project.clj Figwheel: Configuration Valid ;) Figwheel: Starting server at http://0.0.0.0:3449 Figwheel: Watching build - dev Figwheel: Cleaning build - dev Compiling build :dev to "resources/public/js/compiled/sine_wave.js" from ["src"]... Successfully compiled build :dev to "resources/public/js/compiled/sine_wave.js" in 16.12 seconds. Figwheel: Starting CSS Watcher for paths ["resources/public/css"] Launching ClojureScript REPL for build: dev Figwheel Controls: (stop-autobuild) ;; stops Figwheel autobuilder (start-autobuild id ...) ;; starts autobuilder focused on optional ids (switch-to-build id ...) ;; switches autobuilder to different build (reset-autobuild) ;; stops, cleans, and starts autobuilder (reload-config) ;; reloads build config and resets autobuild (build-once id ...) ;; builds source one time (clean-builds id ..) ;; deletes compiled cljs target files (print-config id ...) ;; prints out build configurations (fig-status) ;; displays current state of system (figwheel.client/set-autoload false) ;; will turn autoloading off (figwheel.client/set-repl-pprint false) ;; will turn pretty printing off Switch REPL build focus: :cljs/quit ;; allows you to switch REPL to another build Docs: (doc function-name-here) Exit: :cljs/quit Results: Stored in vars *1, *2, *3, *e holds last exception object Prompt will show when Figwheel connects to your application [Rebel readline] Type :repl/help for online help info ClojureScript 1.10.238 dev:cljs.user!{:conn 2}=>
Once the previous command finishes, the application will be available at http://localhost:3449/index.html, where you will find a blank, rectangular canvas. We are now ready to begin.
The main reason we are using the figwheel template for this example is that it performs hot-reloading of our application code via WebSockets. This means that we can have the browser and the editor side by side, and as we update our code, we will see the results immediately in the browser without having to reload the page.
To validate that this is working, open your web browser's console so that you can see the output of the scripts on the page. Then, add this to /src/cljs/sin_wave/core.cljs as follows:
(.log js/console "hello clojurescript")
You should have seen the hello clojurescript message being printed to your browser's console. Make sure you have a working environment up to this point, as we will be relying on this workflow to interactively build our application.
It is also a good idea to make sure we clear the canvas every time figwheel reloads our file. This is simple enough to do by adding the following snippet to our core namespace:
(defn canvas [] (.getElementById js/document "myCanvas"))(defn ctx [] (.getContext (canvas) "2d"))
Now that we have a working environment, we can progress with our animation. It is probably a good idea to specify how often we would like to have a new animation frame.
This effectively means adding the concept of time to our application. You're free to play with different values, but let's start with a new frame every 10 milliseconds:
(def rx-interval js/rxjs.interval)(def rx-take js/rxjs.operators.take)(
def
rx-map js/rxjs.operators.map)(def app-time (rx-interval 10))
As RxJS is a JavaScript library, we need to use ClojureScript's interoperability to call its functions. For convenience, we will bind the interval function of RxJS to a local var. We will use this approach throughout this book when appropriate.
Next, we will create an infinite stream of numbers, starting at 0, that will have a new element every 10 milliseconds. Let's make sure this is working as expected:
(-> app-time (.pipe (rx-take 5)) (.subscribe (fn [n] (.log js/console n)))) ;; 0 ;; 1 ;; 2 ;; 3 ;; 4
Remember that time is infinite, so we will use the take Rx operator in order to avoid indefinitely printing out numbers to the console.
Our next step is to calculate the 2D coordinate representing a segment of the sine wave we can draw. This will be given by the following functions:
(defn deg-to-rad [n] (* (/ Math/PI 180) n)) (defn sine-coord [x] (let [sin (Math/sin (deg-to-rad x)) y (- 100 (* sin 90))] {:x x :y y :sin sin}))(
def
sine-wave (
.pipe app
-time (
rx-map
sine-coord)))
The sine-coord function takes an x point of our 2D canvas and calculates the y point based on the sine of x. The constants 100 and 90 simply control how tall and sharp the slope should be. As an example, try calculating the sine coordinate when x is 50:
(.log js/console (str (sine-coord 50))) ;;{:x 50, :y 31.05600011929198, :sin 0.766044443118978}
We will be using app-time as the source for the values of x. Creating the sine wave is now only a matter of combining both app-time and sine-coord:
(-> app-time (.pipe (rx-take 5) ) (.subscribe (fn [num] (.log js/console (sine-coord num))))) ;; {:x 0, :y 100, :sin 0} ;; {:x 1, :y 98.42928342064448, :sin 0.01745240643728351} ;; {:x 2, :y 96.85904529677491, :sin 0.03489949670250097} ;; {:x 3, :y 95.28976393813505, :sin 0.052335956242943835} ;; {:x 4, :y 93.72191736302872, :sin 0.0697564737441253}
This brings us to the original code snippet that piqued our interest, alongside a function to perform the actual drawing:
(defn fill-rect [x y colour] (set! (.-fillStyle (ctx)) colour) (.fillRect (ctx) x y 2 2)) (-> app-time (.pipe (rx-take 700)) (.subscribe (fn [num] (fill-rect x y "orange"))))
As this point, we can save the file again and watch as the sine wave we have just created gracefully appears on the screen.
One of the points this example sets out to illustrate is how thinking in terms of very simple abstractions and then building more complex ones on top of them make for code that is simpler to maintain and easier to modify.
As such, we will now update our animation to draw the sine wave in different colors. In this case, we would like to draw the wave in red if the sine of x is negative, and blue otherwise.
We already have the sine value coming through the sine-wave stream, so all we need to do is transform this stream into one that will give us the colors according to the preceding criteria:
(def colour (.pipe sine-wave (rx-map (fn [{:keys [sin]}] (if (< sin 0) "red" "blue")))))
The next step is to add the new stream into the main drawing loop—remember to comment the previous one so that we don't end up with multiple waves being drawn at the same time:
(-> (js/rxjs.zip sine-wave colour) (.pipe (rx-take 700)) (.subscribe (fn [[{:keys [x y]} colour]] (fill-rect x y colour))))
Once we save the file, we should see a new sine wave alternating between red and blue as the sine of x oscillates from -1 to 1.
As fun as this has been so far, the animation we have created isn't really reactive. Sure, it does react to time itself, but that is the very nature of animation. As we will see later, Reactive Programming is called as such because programs react to external inputs such as a mouse or network events.
We will, therefore, update the animation so that the user is in control of when the color switch occurs: the wave will start off red and switch to blue when the user clicks anywhere within the canvas area. Further clicks will simply alternate between red and blue.
We start by creating infinite—as per the definition of app-time—streams for our color primitives as follows:
(def red (.pipe app-time (rx-map (fn [_] "red")))) (def blue (.pipe app-time (rx-map (fn [_] "blue"))))
On their own, red and blue aren't that interesting, as their values don't change. We can think of them as constant streams. They become a lot more interesting when combined with another infinite stream that cycles between them based on user input:
(def rx-concat js/rxjs.concat) (def rx-defer js/rxjs.defer) (def rx-from-event js/rxjs.fromEvent)(def rx-takeUntil js/rxjs.operators.takeUntil) (def mouse-click (rx-from-event canvas "click")) (def cycle-colour (rx-concat (.pipe red (rx-takeUntil mouse-click)) (rx-defer #(rx-concat (.pipe blue (rx-takeUntil mouse-click)) cycle-colour))))
This is our most complex update so far. If you look closely, you will also notice that cycle-colour is a recursive stream; that is, it is defined in terms of itself.
When we first saw the code of this nature, we took a leap of faith in trying to understand what it does. After a quick read, however, we realized that cycle-colour closely follows how we might have talked about the problem: we will use red until a mouse click occurs, after which, we will use blue until another mouse click occurs. Then, we start the recursion.
The change to our animation loop is minimal:
(-> (js/rxjs.zip sine-wave cycle-colour) (.pipe (rx-take 700)) (.subscribe (fn [[{:keys [x y]} colour]] (fill-rect x y colour))))
The purpose of this book is to help you develop the instinct required to model problems in the way that's demonstrated here. After each chapter, more and more of this example will make sense. Additionally, a number of frameworks will be used both in ClojureScript and Clojure to give you a wide range of tools to choose from.
Before we move on to that, we must take a little detour and understand how we got here.
Modify the previous example in such a way that the sine wave is drawn using all the colors of the rainbow. The drawing loop should look like the following:
(-> (js/rx.zip sine-wave rainbow-colours) (pipe (rx-take 700)) (.subscribe (fn [[{:keys [x y]} colour]] (fill-rect x y colour))))
Your task is to implement the rainbow-colours stream. As everything up until now has been very light on explanations, you might choose to come back to this exercise later, once we have covered more about CES.
The repeat, scan, and flatMap functions may be useful in solving this exercise. Be sure to consult RxJs' API at https://rxjs-dev.firebaseapp.com/guide/overview for more information.
Before we talk about what Reactive Programming is, it is important to understand how other relevant programming paradigms influenced how we develop software. This will also help us understand the motivations behind Reactive Programming.
With a few exceptions, most of us will have been taught imperative programming languages such as C and Pascal or object-oriented languages such as Java and C++; either self-taught or at school/university
In both cases, the imperative programming paradigm of which object-oriented languages are a part dictates that we write programs as a series of statements that modify program state.
To understand what this means, let's look at a short program written in pseudocode that calculates the sum and the mean value of a list of numbers:
numbers := [1, 2, 3, 4, 5, 6] sum := 0 for each number in numbers sum := sum + number end mean := sum / count(numbers)
First, we create a new array of integers, called numbers, with numbers from 1 to 6, inclusive. Then, we initialize sum to 0. Next, we iterate over the array of integers, one at a time, adding the value of each number to sum.
Lastly, we calculate and assign the average of the numbers in the list to the mean local variable. This concludes the program logic.
This program would print 21 for the sum and 3 for the mean, if executed.
Though a simple example, it highlights its imperative style: we set up an application state, sum, and then explicitly tell the computer how to modify that state in order to calculate the result.
The previous example has an interesting property: the value of mean clearly has a dependency on the contents of sum.
Dataflow programming makes this relationship explicit. It models applications as a dependency graph through which data flows from operation to operation, and as values change, these changes are propagated to its dependencies.
Historically, dataflow programming has been supported by custom-built languages such as Lucid and BLODI, and as such, have been leaving other general-purpose programming languages out.
Let's see how this new insight would impact our previous example. We know that once the last line gets executed, the value of mean is assigned and won't change unless we explicitly reassign the variable.
However, let's imagine for a second that the pseudo-language we used earlier does support dataflow programming. In that case, assigning mean to an expression that refers to both sum and count, such as sum / count(numbers), would be enough to create the directed dependency graph that's shown in the following diagram:
Note that a direct side effect of this relationship is that an implicit dependency from sum to numbers is also created. This means that if the numbers change, the change is propagated through the graph, first updating sum and then, finally, updating mean.
This is where Reactive Programming comes in. This paradigm builds on dataflow programming and change propagation to bring this style of programming to languages that don't have native support for it.
For imperative programming languages, Reactive Programming can be made available via libraries or language extensions. We don't cover this approach in this book, but should the reader want more information on this subject, please refer to dc-lib (see https://code.google.com/p/dc-lib/) for an example. It is a framework that adds Reactive Programming support to C++ via dataflow constraints.
When designing interactive applications such as desktop Graphical User Interfaces (GUIs), we are essentially using an object-oriented approach to Reactive Programming. We will build a simple calculator application to demonstrate this style.
Let's start by creating a new Leiningen project from the command line:
lein new calculator
This will create a directory called calculator in the current folder. Next, open the project.clj file in your favorite text editor and add a dependency on seesaw, a Clojure library for working with Java Swing:
(defproject calculator "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [seesaw "1.5.0"]])
At the time of writing this book, the latest seesaw version that's available is 1.5.0.
Next, in the src/calculator/core.clj
