Functional Programming

Functional Programming

Functional Programming

Apr 10, 2020

Reducing Maintenance Costs With Functional Programming

Reducing Maintenance Costs With Functional Programming

Reducing Maintenance Costs With Functional Programming

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