Saturday, January 9, 2021

Structuring Code

There are many different ways to ‘structure’ code. 

A common approach is to start with a set of instructions that you want to accomplish. Put them together, then put that into a function. Later when someone needs some additional features, put those into their own function, merge the two functions together at some higher level.


The result of this brute force approach will be code that is difficult to understand since you’d have to have been there when it was written. It only makes ‘sense’ if you understand the order of growth.


Another way to structure code is to build up more powerful underlying ‘primitives’. That is, the system library and other dependencies have a predefined set of functionality. You build up new primitives on top of these that solve larger portions of the problem. Eventually, this growing sequence of primitives will equate to the top-down directives. 


This second approach is ‘intrinsically’ readable. If you start at the top, the decomposition of lower-level calls makes sense. If everything really is an upper level ‘primitive’, one of its attributes is that it doesn’t have gaps or overlaps with the other primitives at the same level. 


As well as being readable, it’s also easier to make extensions. Either the lower-level primitive exists, or they need to be written. If the extensions honor the same ‘level’ decomposition, then all of the code maintains its organization by default. 


A modified version of the second approach binds the primitives directly to the data. That is, all of the primitive functions are ‘verbs’ that act on the primitive data which are ‘nouns’. That is super-readable, and even better if the code itself reflects back the language used for the specification of the work. There is no need to translate between ‘odd’ programmer artifacts and the actual problem space.


With the modified version, it’s also easy then to get reuse out of the code. If there are two similar problems, you lift the ‘naming’ of the variables for the first problem up one level of abstraction, then you build in the variation between the different cases. Each time the underlying ‘domain’ expands, the code lifts up a little bit more. 


That runs the same risk in the first approach that the order of lifting is erratic, but if the underlying code really maintains its primitive decomposition, then it is still organized, but may just be incomplete. 


It’s fairly easy when reading code to see how it was structured, in that you can see that the programmer knew how to do a few ‘somethings’ then struggled to bring those together, or that they built up some increasingly sophisticated mechanics to work through the problem space.

No comments:

Post a Comment

Thanks for the Feedback!