I’ve started a new challenging job. One way that it’s unexpectedly hard is the difficulty of learning an existing code-base. Previously I was writing mostly new code, but I think it’s highlighting a fundamental issue in the way we’ve designed software for the last 20 years or so.
The promise of OOP is modularity, reuse, and general lowering of complexity. But, I think there is a fundamental mismatch between the ideals of objects and types, their interactions and how we think. My approach so far has always been an imperative one, mainly I think about what it’s going to do as I build my mental model of a code-base.
So, the first point that I want to make is as developers we all aim for simplicity and conciseness. We have certain requirements that our code should meet. Static type systems like C++ and Java promise that we can encode those requirements as types and function signatures. So, we do that, and generally take it to an extreme for maximum effectiveness. Encapsulation promises that we can encode our contracts in types. Polymorphism gives us some flexibility later, but the main issue is we have to create huge infrastructures of code to encode our requirements, and polymorphism is necessary to make it not suck as much every time we change something.
As I’m reading over a code-base, I have to re-discover the original intent that was lost in the ceremony. There’s cruft all around, and I’m following trails and back-tracking with some sense that what I’m looking for might be just around the corner, and some kind of hunch for predicting whether I’m getting closer or not, all the while learning what the code is going to do and getting bogged down in implementation details.
I propose a few things that would help.
Firstly, if we keep going the way we are, only able to encode contracts by types, I want a tool that can index call stacks, then find a path through from one type to another. I want to know what the main entry points are, for instance do I have to create a factory that takes an inner class enum for it’s argument to get access to a transformation to get the type I want? I should easily be able to generate a chain of function calls to get to the type I want. This would also make it simple to find the main entry points and highlight the designer’s intent.
Secondly, I want some way to formally specify the inputs and outputs of everything that is succinct, easy and helpful to use, lives outside of implementation details, and would be tool-friendly.
Thirdly, I want the capability of performing a semantic code search using these formal constructs. We really should be past the point of searching by text.