savchenko.tech / software engineering blog by Maryna Savchenko

Common programming paradigms overview

2022-03-04

Why do we care about programming paradigms?

The answer is they help us to align with architectural concerns like boundaries, location and accessing data and algorithm foundation in the modules.

Programming paradigms are ways of programming that are reflected in language features. They tell us which structures to use and when to use them.

There are 3 such main paradigms:

Most languages are multi-paradigm but levels of restrictions/enforcing can be different. For example, both Java and Scala support object-orient and functional programming. At the same time level of enforcement of the functional paradigm in Scala is much higher.

Programming paradigms show us what not to do by imposing discipline.

1. Structured programming

Structured programming imposes discipline on direct transfer of control.

It allows modules to be functionally decomposed. The main value of this decomposition is ability to create falsifiable units. We can use tests to prove small functions incorrect.

At the architectural level functional decomposition is considered one of the best practices.

2. Object-orient (OO) programming

Object-oriented programming imposes discipline on indirect transfer of control.

Understanding of the principles of OO design is one more way to create good architecture. The basics of OO are: encapsulation, inheritance and polymorphism.

Encapsulation draws a line between data and functions that are hidden and functions that are known. An example of encapsulation would be the private data members and the public member functions of a class. But we can not say that OO depends on strong encapsulation. Some OO languages have little or no enforced encapsulation (like Python, JavaScript and Ruby).

Inheritance is a redeclaration of a group of variables and functions within an enclosing scope. So data structures can be reused and extended in more convenient way.

Application of polymorphism allows us to invert any source code dependency. With full control over the direction of all the source code dependencies plugin architecture can be used anywhere.

3. Functional programming

Functional programming imposes discipline upon assignment.

It restricts varying of variables. Mutating of variables lead to problems like race conditions, deadlock conditions, and concurrent update. You cannot have concurrent update problem if no variable is ever updated.

One of the common approaches in regard to immutability is to divide application to mutable and immutable components. Another strategy to create entirely immutable application is to use event sourcing. With event sourcing we do not save state, only transactions. When the state is needed, we apply all the transactions from the beginning of time. This strategy wii require enough storage and enough processor power.

Sources:

Clean Architecture: A Craftsman’s Guide to Software Structure and Design: A Craftsman’s Guide to Software Structure and Design by Robert C. Martin