Most of the discussions we have in the
software industry today revolve around developer
productivity: How do we make it possible for
fewer developers to produce more software in less
time? Reducing the upfront costs and delivering
quickly is essentially the mantra of the startup
world: Move fast and break things.
However, the vast majority of time in software
development is not spent in the initial
development phase. For any successful project, an
overwhelming amount of time is spent on
maintaining that software. To keep your customers
happy, it’s vital to continue improving the
software, fixing bugs and enhancing performance.
If you are hamstrung on your ability to innovate,
constantly fighting bugs and delivering an
inferior user experience, your competitors will
be able to outmaneuver you in the
marketplace.
Functional programming is a significant
paradigm shift in the software world over the
past 10 years. Slowly but surely, it has moved
from a niche feature of a few uncommonly used
languages to a mainstay of even the most
established languages. Unlike preceding
paradigms, functional programming makes a focus
of assisting in not just the productivity of
developers, but of long-term software
maintenance.
Features of Functional Programming
Functional programming is a broad
term. Some languages describe themselves
as functional, such as F#, Haskell and
Swift. However, functional features are
making their way into other languages.
Javascript has multiple libraries
implementing functional paradigms. Rust,
a relative newcomer in the systems
programming world, boasts many functional
features. C++ and Java have been adding
lambdas and other functional features for
years. Many of the features below can be
implemented regardless of the language
being used by your team.
Immutable Data
The bane of many programs, especially
concurrent and network programs, is the
fact that data changes in unexpected
ways. Functional programming advocates
keeping most of your data immutable. Once
created, the data does not change. You
can share this data with other parts of
your program without fear of it being
changed or invalidated.
Languages like Haskell and Rust make
this a cornerstone of their
implementation. C++ offers the ability to
opt-in to immutability. Many Java coding
guidelines recommend defaulting to
immutable data when possible.
Declarative Programming
Classic programming involves
instructing the computer which steps to
take to solve a problem. For example, to
add up the numbers in a list, an
imperative programming approach might
be:
- Create a temporary variable to hold the sum
- Create a temporary variable to hold the current index
- Loop the index from 0 to the length of the list
- Add the value in the list at the index’s position to the sum
This kind of imperative approach
works, but doesn’t scale particularly
well. As problems become more complex,
the imperative approach requires ever
more complicated solutions. It’s
difficult to separate logical components
into multiple separate loops without
sacrificing performance. And in the era
of multicore programming, creating a
multithreaded solution requires
significant expertise with safe thread
handling.
In functional programming, the
preference is a declarative approach.
Summing up a list is typically done
as:
- Write a function to add two values together
- Fold over the list using the add function and 0 as an initial value
This approach naturally translates
into a multicore solution. Instead of
each loop needing to handle the
complexities of thread management, a
library author can write a parallel fold
once. The caller can then replace their
non-parallel fold with a parallel fold
and immediately gain the benefits of
multicore.
By combining this approach with other
declarative programming methods, like
mapping, functional programming can
express complex data pipeline operations
as a composition of many individual,
simpler components. This forms the core
of such well-known systems as Google’s
MapReduce.
Strong Typing
For years, the industry debate around
typed languages was usually between the
C++ and Java families versus the Python
and Ruby families. The former introduced
some sanity checks at compile time in
exchange for lots of ceremony with
explicit type annotations. This improved
code maintenance somewhat, at the cost of
significant developer productivity.
Python and Ruby, by contrast, skipped the
type annotations entirely, leaving them
as a runtime concern. This boosted
productivity, at the cost of
maintainability.
The functional world went a different
way: strong, expressive type systems with
type inference. Type inference avoided
much of the boilerplate introduced by the
C++-style of type systems, allowing
productivity on a par with Python and
Ruby. The strong type systems in
functional languages allowed even more
guarantees to be expressed in types,
improving maintainability beyond the
levels of C++ and Java.
These days, even dynamically typed
languages like Python are beginning to
introduce type systems due to the massive
gains they are demonstrating. New
languages like Rust are borrowing some of
the most popular type system features
from functional languages like Haskell
and O’Caml: sum types, traits and
more.
Introducing Functional Programming
It’s important to note that you do not
need to completely rewrite all of your
software in a functional programming
language to reap many of the benefits of
functional programming. You can begin
rolling out functional features in your
existing software today with improvements
to your internal coding guidelines.
Focusing on some of the features above,
and many of the other inspirations from
functional programming, is a great
start.
One option is to train your team on
functional programming techniques with an
intensive training program in a
functional programming language. Once
your team knows the concepts, it’s much
easier to incorporate them in your Java,
Javascript, C# and other codebases.
With the rise of microservices
architectures, a hybrid deployment model
may make a lot of sense. Oftentimes,
offloading a particularly critical piece
of business logic to a separate,
well-tested functional programming
codebase, connected via network APIs, can
reduce the burden on the rest of your
team and increase the stability of your
software.
Original articles on Forbes
Subscribe to our blog via email
Email subscriptions come from our Atom feed and are handled by Blogtrottr. You will only receive notifications of blog posts, and can unsubscribe any time.
Do you like this blog post and need help with Next Generation Software Engineering, Platform Engineering or Blockchain & Smart Contracts? Contact us.