Functional Programming

Functional Programming

Functional Programming

Dec 30, 2016

Software project maintenance is where Haskell shines

Software project maintenance is where Haskell shines

Software project maintenance is where Haskell shines

Maintenance matters and it's where Haskell shines

We Spend Most of Our Time on Maintenance

Look at the budget spent on your software projects. Most of it goes towards maintenance. The Mythical Man-Month by Fred Brooks states that over 90% of

the costs of a typical system arise in the maintenance phase, and

that any successful piece of software will inevitably be

maintained, and Facts and Fallacies of Software Engineering by Robert L.

Glass reports that maintenance typically consumes 40% to 80%

(averaging 60%) of software costs.


From our own experience and the literature, we can conclude that maintenance is perhaps the most important part of developing software. In this article we'll explore why Haskell shines in maintenance.

The Five Bases of Maintenance

Based on the article Software Maintenance by Chris Newton, I'm going to write about five bases for doing software maintenance:

  • Readability: The source code is comprehensible, and describes the domain well to the reader.

  • Testability: The code is friendly to being tested, via

    unit tests, integration tests, property tests, code review, static

    analysis, etc.

  • Preservation of knowledge: Teams working on the software

    retain the knowledge of the design and functioning of the system

    over time.

  • Modifiability: The ease with which we can fix, update, refactor, adapt, and generally mechanically change.

  • Correctness: The software is constructed in a

    self-consistent way, by using means of combination that rule out

    erroneous cases that maintainers shouldn't have to deal with.

We'll see below what Haskell brings to the table for each of these bases.

Readability

The source code is comprehensible, and describes the domain well to the reader.

Reduce state: Developers must hold a "state of the world"

in their head when understanding imperative and object-oriented

source code. In Haskell, which is a pure functional language,

developers only have to look at the inputs to a function, making it

far easier to consider a portion of code and to approach working on

it.


Narrowing the problem space: A rich type system like

Haskell's guides less-experienced developers, or newcomers to the

project, to the right places. Because the domain can be modeled in

types, which formally narrow down the problem. Developers can

literally define problems away, turning their attention to the real

problems of your business's domain.


Coupling where it counts: Haskell's type system supports modeling cases of a problem, coupling the case (such as:

logged in/logged out) with the values associated with that state

(such as: user session id/no session id). Developers can work with

fewer variables to hold in their head, instead concentrating on

your business logic.


Encapsulation: Like in object oriented languages (Java,

C++, Ruby, Python), encapsulation in Haskell allows developers to

hide irrelevant details when exposing the interfaces between

modules, leaving other developers fewer details to worry about.


Testability

The code is friendly to being tested, via unit tests,

integration tests, property tests, code review, static analysis,

etc.


Explicit inputs: Haskell programs are the easiest to

write tests for, because they are composed of pure functions, which

either require no conditions under which your developers should run

them, or the conditions are explicitly defined inputs to the

function.


Mock the world: With excellent support for embedded

domain-specific languages (DSLs), Haskell empowers developers to

write programs in an imperative fashion which can then be

interpreted as a real world program (interacting with file I/O,

using time, etc.) or as a mock program which does nothing to the

real world but compute a result. This is valuable for testing the

business logic of the software without having to setup a whole real environment just to do so.


Automatically test properties: Haskell's unique type system

supports trivially generating thousands of valid inputs to a

function, in order to test that every output of the function is

correct. Anything from parsers, financial calculations, state

machine transformations, etc. can be generated and tested for.


Static analysis: It may go without saying, but Haskell's

static type system brings substantial potential for eliminating

whole classes of bugs, and maintaining invariants while changing software, as a continuous feedback to the developer. A level-up

from Java or C++ or C#, Haskell's purity and rich type system is

able to check a far greater region of source code and to greater

precision.


Taking testing seriously: Haskell has a large number of

testing libraries which range from standard unit testing (like

JUnit or RSpec), web framework-based testing, property-based

testing (like QuickCheck) and other randomly generated testing,

testing documentation, concurrency testing, and mock testing.


Preservation of knowledge

Teams working on the software retain the knowledge of the design and functioning of the system over time.

Model the domain precisely: Because Haskell's rich type

system lets your developers model the domain precisely and in a

complete way, it's easier for the same developers to return months

or a year from now, or new developers to arrive, and gain a good

grasp of what's happening in the system.


Modifiability

The ease with which we can fix, update, refactor, adapt, and generally mechanically change.

Automatic memory management: Haskell is high-level with

automatically managed memory, like Python or Ruby, and does not

suffer from memory corruption issues or leaks, like C or C++, which

can arise from developers making changes to your system and

mistakenly mismanaging memory manually.


Automate completeness: As mentioned in the readability

section, Haskell allows developers to define data types as a set of

cases that model the business domain logic. From simple things like

results (success/fail/other), to finite state machines, etc. Along

with this comes the ability for the compiler to statically determine and tell your developers when a case is missing, which they need go to and correct. This is extraordinarily useful when changing and extending a system.


Break up the problem: Haskell's pure functions only

depend on their parameters, and so any expression can be easily

factored out into separate functions. Breaking a problem down into

smaller problems helps maintainers deal with smaller problems,

taking fewer things into account.


Encapsulate: As encapsulation allows developers to hide

irrelevant details when exposing the interfaces between Haskell

modules, this allows developers to change the underlying

implementation of modules without consumers of that module having

to be changed.


Decouple orthogonal concepts: In Haskell, unlike in

popular object oriented languages like Java or C++, data and

behavior are not coupled together: a photograph is a photograph,

and a printer knows how to print it, it's not that a photograph

contains printing inside it. The data is the photograph, and the

behavior is printing a photograph. In Haskell, these two are

decoupled, allowing developers to simply define the data that

counts, and freely add more behaviors later, without getting lost

in object hierarchies and inheritance issues.


Correctness

The software is constructed in a self-consistent way, by using

means of combination that rule out erroneous cases that maintainers

shouldn't have to deal with.


Correct combination: In Python, a whole new version of the language, Python 3, had to be implemented to properly handle Unicode text in a backwards-incompatible way. This broke lots of existing Python code and many large projects have still not upgraded. In Haskell, text and binary

data are unmixable data types. They cannot be mistakenly combined,

as in Python and many other languages. This throws a whole class of

encoding issues out of the window, which is less for your

developers to worry about.


No implicit null: In The Billion Dollar Mistake Tony Hoare apologizes for the

"null" value, present in almost all popular programming languages.

Haskell does not have a null value. It explicitly models

nullability with a data type. Given the countless bugs caused by

null, and maintenance burden due to tracking down or introducing

such bugs, Haskell's contribution by removing it is substantial.

Languages that include an implicit null value are: Java, C, C++,

C#, Python, Ruby, JavaScript, Lisp, Clojure, etc.


Avoid multiple writers: In concurrent code, developers

have to be very careful when more than one thread changes the same

data. Imperative languages tend to allow any thread to change

anything, so it's frighteningly easy to make mistakes. In Haskell,

data structures are immutable, and a mutable "box" has to be

created to share data between threads, ruling out a plethora of

potential bugs.


Summary

Maintenance is our biggest activity when developing successful

software. There are five bases that really make maintenance work

better, and this is where Haskell really shines:


  • Readability: Haskell's purity and type system lend themselves perfectly to comprehensible code.

  • Testability: Haskell code is inherently more testable,

    due to being pure, safely statically typed, and coming with a

    variety of testing packages.

  • Preservation of knowledge: A rich type system like

    Haskell's can model the domain so well that developers have to

    remember less, and educate each-other less, saving time.

  • Modifiability: Haskell's strong types, completeness

    analysis and purity assure that when you break something, you know

    it sooner.

  • Correctness: Developers can work within a consistent

    model of your domain, removing whole classes of irrelevant

    problems. Concurrent code is easier to maintain too.

All in all, Haskell really shines in maintenance, and, while it has other novel features, it's really for this reason that developers and companies are increasingly switching to it.

You can learn more about using Haskell as a business at FP Complete's home page, in particular the Consulting page, or go and contact us straight away and we'll be in touch.