Embracing Simplicity: Alternatives to Object-Oriented Programming
Written on
Chapter 1: Understanding Programming Paradigms
In the realm of software development, programmers utilize a variety of paradigms to create applications. The most prevalent of these include structured, procedural, functional, modular, and object-oriented programming (OOP). Each paradigm provides a unique methodology for organizing code, adhering to established software development principles and patterns. For instance, the procedural paradigm allows developers to organize their code into distinct procedures or functions, while principles like DRY (Don't Repeat Yourself) and YAGNI (You Aren't Gonna Need It) help streamline the code further.
Modern developers often default to OOP without fully assessing the specific needs of their projects, such as domain relevance, size, and scalability. While OOP has its merits in structuring codebases effectively, it can inadvertently complicate seemingly simple programs.
This discussion will introduce a procedural programming paradigm that promotes simplicity in software projects, drawing on concepts from various paradigms while steering clear of OOP's complexities.
Chapter 2: The Complexity of OOP
The CPU operates as a computational device based on the Turing machine model, executing a potentially infinite series of linear assembly instructions. Initially, programming involved writing software with low-level assembly code, which later evolved into more user-friendly languages that enhance productivity and portability.
In today’s landscape, we leverage high-level programming languages featuring various paradigms, which offer an English-like syntax and modern capabilities. The OOP paradigm encourages developers to break down code into classes and create stateful objects associated with actions. This approach is particularly effective for business-oriented challenges, allowing clear isolation of business entities into classes.
The Customer class in the ERPNext platform exemplifies how inheritance is utilized effectively. However, while basic OOP methods do not inherently complicate programs, concepts like inheritance, polymorphism, and OOP-centric design patterns frequently do. Consequently, projects can become over-engineered, complicating the logical flow with an excess of objects and dispersed states.
Newer programming languages, such as Golang, intentionally eschew complex OOP features, offering a more straightforward approach that emphasizes lightweight constructs. This is a reflection of the fact that OOP may encourage the creation of classes and objects even for entities that require only a single instance, such as Application or Configuration.
Chapter 3: Procedural Programming as an Alternative
If OOP tends to complicate projects, what is a suitable alternative for software development? Functional programming presents some useful concepts, yet it is not universally applicable since it primarily addresses non-generic scenarios, such as complex data manipulation.
Recall your initial encounters with computer algorithms — likely starting with flow charts and basic control structures. Structured programming, with its minimal abstraction from theoretical computer science and the CPU's native language, simplifies the software development process. By integrating elements from structured, modular, procedural, and functional paradigms, we can create an effective alternative to OOP.
Consider this alternative framework:
- Use modules in place of classes.
- Employ functions instead of class methods.
- Implement records instead of stateful objects.
- Utilize custom code styles instead of access modifiers.
- Manage state through module-level variables instead of persistent class states.
The following example illustrates a CLI program that has been modularized according to fundamental principles of modular programming:
In OOP, logic is often distributed across various class methods, which can lead to challenges in understanding specific logical flows in larger projects. By contrast, using functions allows for a more straightforward approach.
Managing program state can also be effectively handled using either global variables or argument-passing, depending on your needs. Argument-based state management tends to result in cleaner, more testable code, while global variables can also be efficient as long as state modifications are controlled.
Many non-looping programs, such as CLI utilities, typically do not require persistent states, allowing for pure functional programming approaches without side effects.
Chapter 4: Implementing the Procedural Paradigm
Using a procedural approach is quite feasible in languages like C, which is fundamentally procedural. For instance, when working with file handling functions in the C standard library, the FILE pointer must be passed to each function, demonstrating the procedural pattern effectively.
However, adopting a purely procedural approach in languages like C++, JavaScript, and Python is challenging due to their reliance on object-oriented APIs. For instance, JavaScript uses an OO interface to manage sets, as shown in the example below:
let numbers = new Set(); // constructor
numbers.add(10); // class method
console.log(numbers.size); // class property
Despite this, the versatility of modern programming languages allows for the integration of functional programming principles, such as lambda functions and callbacks. Thus, the procedural paradigm can be utilized effectively alongside OOP-based standard libraries by encapsulating OOP constructs within procedural functions.
Chapter 5: Conclusion
While OOP is often a natural choice for addressing real-world problems, it can be seen as artificial from a CPU's viewpoint. The CPU processes instructions as a series of procedures and parameters rather than as objects. Therefore, from a technical standpoint, procedural programming emerges as a more natural paradigm for software development.
Nonetheless, from a business perspective, OOP aligns closely with business logic, which is why it remains dominant in many business applications. It's essential to recognize that some software projects can become overly complex when decomposed into classes, and adding OOP principles can often complicate algorithmic solutions.
As developers, our objective should be to find simple, efficient solutions rather than introducing unnecessary complexities. Consider employing a mix of procedural, functional, and modular approaches for your next project before resorting to class diagrams.
This discussion serves not to disparage OOP but to present an alternative paradigm aimed at enhancing simplicity in your software development endeavors. The subsequent article will delve into the benefits of maintaining simplicity in coding practices:
5 Programming Principles that Help You to Write Better Code
Elevate your coding skills and impress both the compiler and your teammates by adhering to these essential programming principles.
Thanks for reading.