Software engineering is made up of many different paradigms each one with its advocates and its detractors.
Which one is currently en vogue can be subject to trends in thinking or technology.
Functional programming is one such paradigm that has grown in popularity with its application being championed in various different arenas.
I have written before that the application of a technique in all situations regardless of merit is foolhardy and that Object Oriented Programming (OOP) is being written off too readily, however that is not to say that there aren't things we can learn from functional programming to improve our approach to OOP.
Avoiding Side Effects
A key tenant of functional programming is referential transparency, this is that a function or method should be interchangeable with its return value.
This behaviour implies that a method is pure, has no side effects and contains no state.
Writing methods that are this pure is difficult, despite our best efforts objects very often do have state.
A more practical approach is to avoid side effects that cannot be anticipated based on the name of the method or the name of the class in which it resides.
This avoids what is sometimes referred to as action at a distance where operations in one area of code have an unintended and unpredictable effect elsewhere.
This is a very good definition of a bug and shows how side effects can set the caller of your code up to unwittingly create problems in the code base.
Immutability
A consequence of referential transparency is that objects and values once created are immutable and cannot be changed.
Whilst this also plays a part in avoiding side effects it also has more practical benefits in providing efficiency in certain situations and going a long way to ensuring thread safety.
At the heart of every threading problem is usually data or state being mutated in an uncontrolled manner.
While again pure immutability can be difficult to achieve the change of any important piece of data or state in an object should always be implemented in a controlled manner.
Where at all possible changes should be surfaced by creating new objects or data rather than modifying anything pre-existing.
Declarative Style
Functional programming is said to have a declarative style where code expresses what must be accomplished in contrast to an imperative style that describes how something should be achieved.
This implies that code describes the results of computation without exposing detail of the control flow of how this was achieved.
As complex as this may sound good naming of classes and methods will allow code to be written that doesn't focus on the detail of what is happening and instead allows the caller to only be concerned with the results.
The details of computation are often subject to change, the more coupling that has been created between this detail and other areas of the code base the more impactful this change will be.
Something as simple as using a well named abstraction to hide this detail can loosen this coupling and allow code to be written using a more declarative style.
What we should take from all this is that the pillars and principles of writing good code are actually universal, different paradigms often choose to place more emphasis on certain aspects but we will observe a certain amount of cross pollination.
Trying to take any one of these principles to its ultimate conclusion will very often require you to put more effort into coding within defined boundaries as opposed to taking a practical approach of trying to ship software.
However as we've demonstrated many of the benefits of these principle can be achieved by relatively simple means when you have a sensible and practical outlook.
No comments:
Post a Comment