202410242306
Status: #idea
Tags: #software_engineering #design_patterns #computer_science #complexity
# General purpose modules tend to be deeper
A general purpose module is one that has not been tailored to a specific use case, but instead solves the problem generally and can be repurposed to specific contexts. These modules tend to be deeper because general purpose modules tend to require smaller interfaces (fewer parameters and methods) to solve the current problem.
Specialization is still required at some point in order to use the module for a specific situation, so we should try to **push specialization up or down the stack.**
When we push specialization *up* the stack, we implement the general purpose class as a class that solves a common, general problem that is relevant to many specific contexts. For example, a text editor class may implement general methods like `deleteAtIndex` or `insertAtIndex`. Any number of potential GUI implementations could then use these methods to input and delete characters, regardless of their specific implementation for how they track the index location (e.g. using a cursor or touch screen or some other mechanism).
When we push specialization *down* the stack, our general purpose class acts as an abstraction on top of a set of special purpose classes, allowing users to interact with the functionality of the special purpose classes without needing to learn their specific interfaces. For example, an operating system's filesystem must work with hundreds or thousands of distinct device types. In order to simplify this situation, OSes typically only expose a few standard system calls that can be used to interact with files. For example, in Unix systems, there are only a few relevant system calls: `open`, `write`, `read`, `creat`, `close`, `lseek`. Any devices that want to work with Unix must provide device drivers that implement the specific functionality for the device that enables these system calls (e.g. how does a specific SSD read blocks of data and send them to RAM when `read` is called).
Generally, we should [[Pull complexity downwards when possible]]
It can be difficult to create general-purpose classes when dealing with a specific problem, since the context-specific solution is usually the most obvious one. To move towards more general solutions, ask yourself the following questions:
1. **What is the simplest interface that will cover all my current needs?** If you reduce the number of methods & parameters in a class without reducing its overall capabilities, then you are probably creating more general-purpose classes.
2. **In how many situations will this method be used?** If a method is designed for one particular use case, that is a red flag that it may be too special purpose.
3. **Is this API easy to use for my current needs?** This question can help to determine when you have gone too far in making an API simple and general purpose. If you have to write a lot of additional code to use a class for your current purpose, that's a red flag that the interface doesn't provide the right functionality.
For context see:
1. [[Complexity in software development and design]]
2. [[Deep modules are preferable over shallow modules]]
---
# References
[[A philosophy of software design]]