Procedural Abstraction

Project Hub

Procedural abstraction is a powerful pattern

The dictionary does actually help here. “Using something simple to refer to something complex.” One could also say “referring to something less simple with something that that is simpler”, or “using something less complex to refer to something more complex”. For example, just about every Hello World program uses something like print to produce an output. Note that “print” is literally just five characters, while the actual process of creating the output is considerably more complex.

Computing the sine

Sine is an essential trigonometric function. In a computer program, it is typically represented as sin(x). But do we know the steps for converting a particular floating point number .433 to its sine 0.4196 - never mind the details of floating point and radians? Typcally, a simple solution is via a Taylor Series (although in a highly constrained system one may use look up table). More precisely this would be a truncated Taylor Series, since we want a reasonably accurate answer quickly. If we think about this problem further, we’d consider simplifications such as sin(-x) = -sin(x). We’d also consider is that sin(x + n * PI) = sin(x), when n is an integer, so we can do a lot of folding to simplify the Taylor Series computation. If we left the calculation of sin(x) to a mathematically expert programmmer, we would rest assured that all those nuances are properly dealt with. Fortunately, most of us programmers can simply use the library function sin(x) in our programs without ever knowing the intricacies of the algorithm

And that’s the point of Procedural Abstraction. We can draw a boundary between WHAT we expect of the outcome to HOW the outcome is acheived.

Abstraction is a different pattern than reuse

One might argue that the main value of a Procedural Abstraction such as sin(x) is that it allows the same code to be reused in different programs, avoiding duplication. That is true, but still, the Procedural Abstraction pattern is valuable in another way. It provides us - even without reuse - to replace a complex implementation with a simple reference to it. It allows us to move the complexity or detail of the implementation somewhere else. In this way, Procedural Abstraction can be used as a Composite Pattern whereby a complex procedure can be composed out of simpler procedures.

Procedure names as documentation

A common code smell is “Long Method”. Of course, this smell applies equally to functions. Believe me - I saw a grand-daddy long function in a PHP webserver - 6,000 lines in one function! A long block - let’s call it that - is almost necessarily - composed of a series of smaller blocks of code. Programmers frequently demarcate these these smaller blocks of code with comments to indicate their scope. For example, imagine a long methed, where each ...` represents many, maybe dozens of, lines of code. To structure this long method, the programmer my have added comments as follows:

function long(args) {
    // check the state
    ...
    // prepare the foobar
    ...
    // open the connection
    ...
    // send the request
    ...
    // close the connection
    ...
    // prapare the result
    ...
}

A more adroit programmer - using Procedure Abstraction - would refactor this to:

function long(args) {
    check_the_state()
    prepare_the_foobar()
    open_the_connection()
    send_the_request()
    close_the_connection()
    prapare_the_result()
}
function check_the_state() { ... }
function prepare_the_foobar() { ... }
function open_the_connection() { ... }
function send_the_request() { ... }
function close_the_connection() { ... }
function prapare_the_result() { ... }

Now in a way, the complexity of the code seems to have increased. Indeed, there are actually more line of code. However, the long function and each of its constituent functions have a simpler scope. The salient feature of this simpification is that each function is shorter.