Every 10 years or so, a promising new programming approach emerges that provides a new and sometimes superior way to describe systems, structure code, and fulfill the asynchronous and throughput expectations that our clients and stakeholders want.
Today, a fresh generation of programming approaches and processes is growing, promising to push the state of the art in programming practice and methodology forward once more.
However, these changes do not occur in a consistent manner across all technological stacks, and it is easy to notice patterns in someone else’s toolchains.
Four recent improvements in functional programming (FP) have the potential to revolutionize how software engineers address programming challenges in the next five to ten years, as well as the underlying drivers inspiring these advances.
Advances and the motivations behind them
But, before I go into the advancements and why they’ll be important, let me provide some background on what’s propelling them forward.
Advances in programming methods usually occur in reaction to new requirements, rather than in a vacuum. Object-oriented programming, for example, began in the late 1960s and early 1970s with Simula and Smalltalk. These languages, along with the abstractions that accompanied them, allowed their creators to simulate real-world constructs in code.
So, what is driving today’s demand for new programming methods? It’s always easier to spot and characterize trends after they’ve occurred, but I believe some drivers are visible even today.
As Moore’s Law began to lose traction in the late 2000s, CPUs began to add cores rather than speed. To prevent leaving cores idle, we had to rework our programming methods, languages, and runtimes to accommodate concurrency at a fundamental level.
Inversion of control (IoC) is a well-known software design idea that has grown in popularity in recent years. (For a more detailed explanation of IoC, see this article.) The industry continues to find new ways to broaden and use the principles of IoC, from GUIs to serverless computing to the new Istio Framework. Pervasive IoC, however, comes at a price.
IoC frameworks and containers exist to make developing sophisticated, distributed systems easier. However, IoC pushes the majority of your code into callbacks, which simplifies certain issues while complicating others. While we can program as if we are the only thread in the process and obtain services and security invisibly, we are robbed of the context of an execution pointer at the same time.
In other words, your software doesn’t pick up where it left off; instead, it uses a callback to do so. In FP, where functional composition necessitates picking up where you left off within a chain of functions, this can be an issue. As FP requires, your code must build and maintain context between and across callbacks while staying side-effect-free.
The Internet of Things also has security considerations, which are especially important in dispersed, cloud-based systems. When you hand over management of an asynchronous activity to another party, you establish a trusting relationship with that party, as Kyle Simpson points out in his blog. By calling your callback too soon, too many times, with incorrect data, or with bogus errors, a hostile or untrustworthy third party could quickly betray your trust.
Today’s big programming problems
Asynchronous problems are more difficult to reason about and code as a result of the three drivers stated above, interdependencies and flow management are more complicated, vendor lock-in is more difficult to prevent, and security is more difficult to guarantee.
Finally, because dealing with parallelism in software is no longer an option, it must become more straightforward to account for in code.
To put it another way, how can you write code that adheres to FP principles, ensures that asynchronous responses are processed securely and in order, leverages concurrency across CPU cores, and codifies interdependencies and flow control in a way that is simple, readable, and not overly tied to specific vendors in today’s cloud computing environment, where more context and control of the flow of your application has been wrestled away from “your code”?
The four key advances
The following are four FP advancements that can help with these issues. They’ll put you in a better position to develop cloud, microservices, and stream-based apps in the future.
The purpose is not to teach all of these strategies here, but to raise awareness of these developments (if they haven’t already) and give you useful references for further research. These advancements aren’t really new, but they’re gaining traction. For example, Tony Hoare’s breakthrough academic article “Communicating Sequential Processes” was initially published in 1978.
Finally, given a large number of active FP frameworks and languages, I’m sure I’ll overlook some significant advancements that should be included. If so, please share them with me in the comments section below.
1. The ‘promise’ architecture and derivatives
The promise, often known as the future, is a revolutionary idea that every functional programmer should grasp. A promise is a promise of future value, or at the very least an explanation if the value cannot be acquired.
Here’s a real-life example. A promise is similar to receiving a DMV ticket number. With that ticket, you’ll either get the driver’s license you came for, or an explanation that the DMV’s photo printer is faulty, and you won’t be getting one.
Another key feature of promises is that they alleviate at least some of the security concerns raised by IoC via callbacks. The resolve and reject functions of a promise, unlike callbacks, ensure that they can’t be called too many times.
Another helpful promise-based design is the Promise Waterfall. It’s an adaption of the Async library’s async. waterfall, but instead of callbacks, it uses promises. A Promise Waterfall is essentially a promise-specific FP compose function with customized error handling. The Promise Waterfall is implemented in a variety of ways, including one that I created in a library called Pathfinder, which integrates the improvements outlined here into a single, unified programming model.
2. Monadic functional programming
Monads and their offshoots are a hot issue in functional programming, and rightfully so. But, with the exception of Dr. Boolean, few people can describe them simply and painlessly. Oh Composable World!, a 2016 talk by Brian Lonsdorf, explains the true purpose of monads: to use a box.
In a nutshell, the goal of monads is to avoid operating on values directly. Put that value in a dot-chainable box instead, and let the box manipulate it for you using a standardized and predictable API. Why? Because you get more readability, flexibility, and composability with this indirection.
Monet.js and Sanctuary are two libraries that implement parts or all of the FantasyLand Monads ensemble. After Boolean’s talk, these libraries’ “maybe” and “either” monads are a wonderful starting point for learning monads and how their use may streamline your code and increase readability.
Scott Wlaschin’s 2014 talk on “Railway-Oriented Programming,” which builds on either monad, shows how to keep error handling from contaminating your “happy path” with unnecessary complexity.
3. Functional reactive programming and the observable
Consider the possibility of physically connecting the controls on a web page so that the search box is linked to the table of search results, a counter label indicating the number of hits, and a cancel button. Because all of these controls are hooked together, typing a character in the search box causes everything connected to it to update in real-time.
This is how observables work: they function like software circuitry, connecting and flowing inputs to outputs as soon as they change, and altering input values along the way. Each intermediate alteration of input data can return synchronously or asynchronously, and the software circuitry can be interrupted if the user cancels a long-running async operation.
Functional reactive programming (FRP) and its observable abstraction are a new and powerful technique to address asynchronous problems, in which inputs are thought of as a collection of incoming streams that can be merged, mapped, separated, and so on.
An observable is similar to an array in FRP, except instead of a collection of existing values, an observable is a collection of future values. Where arrays are iterated to enumerate existing values, observables are subscribed to future values and listen for them to arrive.
RxJS is the most popular observable implementation right now, but Bacon.js is a strong contender; it avoids RxJS’s difference between hot and cold observables. Finally, Pathfinder introduces a novel approach to FRP that builds on promises rather than replacing them, avoiding the complexity of flatMap.
Read André Staltz’ “The Introduction to Reactive Programming You’ve Been Missing” for a concise introduction to FRP, observables, and RxJS.
4. The rise of concurrency models and FP abstractions
“Threaded concurrency is a leaky abstraction,” said Ryan Dahl, the developer of Node.js, in his first talk, revealing Node.js. To put it another way, threads don’t do a good job of hiding their intricacies from the developer’s view.
Traditional threading models have the disadvantage of focusing the developer’s attention on parallelism, which is more difficult, rather than concurrency, which is simpler. In recent years, there has been a renewed interest in an old idea, concurrency models, to address this complexity “leak” as well as to keep all cores of the increasingly common multi-core CPUs busy.
Concurrency models are interesting because they reflect a technical evolution beyond threaded concurrency—a post-threads developer experience. Concurrency models work by separating activities that have non-overlapping states and are thus fundamentally safe to parallelize, and then sending messages between them for coordination. This method lowers and localizes the points in the system where threading conflict guards are required.
Because it is based on the principle of removing mutant states, FP is complementary to these goals. This assures that the majority of your code is thread-safe, reducing the number of changed, shared state points in your concurrency model.
The four main concurrency models are:
- The Reactor pattern
- The actor model(including Akka and Erlang processes via BEAM)
- Communicating Sequential Processes(CSP)
- LMAX Disruptor
Other concurrency models exist, but Reactor, CSP, and Actor are the most widely used today. The LMAX Disruptor is a lesser-known product that has shown promise.
Concurrency models are distinct from the software abstractions that allow them to be programmed. The reactor, for example, demands the declaration of asynchronous callbacks, which are commonly packaged as promises, whereas CSP requires the specification of co-routines.
In both circumstances, the difficulty is to meet the structural constraints of the concurrency model while maintaining the attributes of the functional programming style. Even while Go contains closures and first-class functions, it does not require an FP approach because it exposes CSP concepts. Look into Clojure’s core. async and Haskell’s CHP libraries for this. Both libraries are Golang-inspired frameworks that show how to do CSP in a completely FP manner.
FP challenges abound
Technology has now caught up to computer scientists Carl Hewitt and Tony Hoare’s idea, thanks to the emergence of multi-core CPUs. Their publications on actor formalism and communicating sequential processes, published in 1973 and 1978, are the foundations of Erlang and Golang, respectively.
However, these improvements in actor and CSP concurrency models aren’t one-offs; they’re part of a bigger trend. Higher-core-count CPUs, cloud-based microservices, big data, streaming ETL, and the growing complexity and pervasiveness of IoC are all providing new difficulties to FP abstractions and practitioners.
Promises, monads, observables, and concurrency models, among other developments in functional and reactive programming, are gaining acceptance and evolving to meet these issues.
These four breakthroughs show that FP and its foundations—closures, currying, functional composition, and functions as parameters—are our strongest weapons and defenses against escalating concurrency, asynchronicity, and IoC demands. Cloud-based apps will require no less in the future.
For more info: https://www.mammoth-ai.com/testing-services/
Also Read: https://www.guru99.com/software-testing.html