We can’t always develop Object Oriented libraries with beautiful objects floating around inside our memory space. Sometimes, we have to develop procedural libraries (or are tasked with improving existing code). In order to organize these libraries better, we usually end up combining related functions into modules. This has two major advantages, one of which is the documentation looks a lot better, and the second is that it forces us to think about how to go about organizing our code. But in order to maintain the API to our code, we need to ensure that all these functions are still available to the top level namespace. Here’s how we can go about doing that.
Depending on the size of your library, you’ll either be able to squeeze all your functions into one module, or you’ll need to create a hierarchy. Let’s handle the simple case first, and then describe how to build on top of that to handle the hierarchy.
This is how you’d handle the simple case:
You can swap out extend for include or prepend if you prefer (or have a specific reason why). This exposes the “hi” function to the top level namespace, while allowing us to organize our code a little bit. After a while, you can deprecate the top level usage, and mandate that users include the module themselves, and finally transition into a full-fledged library.
If, however, you’re inheriting a larger legacy codebase with a lot of top level functions, you can start by splitting them up into different files (I can’t stress how important this step is). Next, you’ll want to organize them into a hierarchy of modules, but in order to do that, you’ll need some boilerplate code:
From here, it’s a matter of organizing your code better, improving documentation, and eventually deprecating the top level usage.
Identifying invalid usage
This is a much more complicated topic, since it ties in directly with modeling the entire type system of your client applications in runtime. Since chances are if you inherited a legacy system, they did some sort of funny business that changes modules at runtime, you’ll be better suited by a quick script to highlight unqualified usage of methods in classes that don’t include the owner module. Here’s a sample one:
That can be improved by leaps and bounds to ignore quoted strings, and apply heuristics if it is being invoked on another object or the module directly.