Leveraging programming paradigms to reduce coding bugs for modern enterprise applications
By: Francis Lee
Tags: Migration, Cloud Native, Refactoring, Functional Programming, Flow Based Programming

Enterprise software tends to have a long life-cycle in the organisation, and usually, it is supported and maintained by groups of developers through change-requests; the developer adding new features to existing code or modifying the behaviour isn’t always the same developer that created the code in the first place. Developers usually develop using an imperative style to programming, which is what they were taught to code in.

To eliminate (or at least reduce) programming bugs, we need to understand how they were created in the first place. Issues stemming from the misunderstanding of the client’s requirements are being resolved with the Agile Development Manifesto; with shorter turnarounds to have the client’s input into the development output, we are assuring that the coding is towards what the client is envisioning for their business needs. What we need to understand is how coding bugs get created by developers, and what tools or changes that we can do to facilitate the prevention of such coding bugs in the first place.

One of the more common coding bugs that are encountered very often, stems from the situation when a programmer designs and implements his code to allow changes to programming states that are external to his code. In programming parlance, states are defined as variables or memory locations, used to indicate the current ‘condition’ or ‘configuration’ the application is in. Usually, these are globally accessible/shared objects or variables used to denote the state of the application. A program that changes states external to the code premise is said to have side-effects. As requirements become more reactive, programmers start using shared mutable states in the codes which leads to undesirable outcomes especially when programming in a group environment.

To mitigate such issues, Functional Programming (FP) paradigm is used to enforced immutability into the program design. The FP paradigm opposes Objected Oriented (OO) paradigm by making functions as the main focus instead of objects. FP tends to be declarative (as opposed to imperative) and helps remove unwanted side-effects and shared mutable states. By using FP, the coder is forced to think in a higher abstraction in solving the problem domain as deterministic functions instead of imperatively coding the algorithm with procedures and objects. This higher abstraction design tends to lead to cleaner codes and making changes easier for other developers. FP also makes it easier troubleshooting, to do unit-testing and integration testing.

Adopting the mindset of FP is more than just about eliminating mutability, but also the approach to solving problems. In the imperative style, the developer designs the steps required to achieve the desired outcome. In FP, the developer needs to decompose the problem into sets of functions, with the focus on what data is required and what transformation is to be done to the data through the functions. Instead of running through the bounded for/while loop in the imperative style, FP uses functions and recursions in the transformation of the data. The focus is not on the imperative algorithmic sequence but rather on the data transformation required and the functions that perform the transformation. FP emphasizes functions as the first-class elements for programming, and not classes or structures.

Other benefits for FP includes easier Unit-Testing and Debugging. As FP favours functions that return values based only on its arguments, the unit tests for the functions are relatively simple. There is no need to configure the right ‘state’ for the unit tests, as everything that affects the return values is in the arguments; you just need the edge-cases for the arguments. Debugging is also easier since you don’t have to worry about code-paths before reaching the buggy function. If the function’s return value is buggy, it will always be buggy, regardless of any external state. I have spent countless hours debugging imperative codes that were producing wrong results occasionally, only to find out that it depended on the code-path before reaching that section of code I was reviewing. With FP, the buggy function is always buggy and reproducible, thus making resolutions easier.

Also, since FP is stateless, it tends to favour concurrent programming easily. With today’s modern CPUs, we are given the luxury of multiple cores to leverage on. FP’s statelessness is easily deployed for multi-core computations or other thread-safe situations.