Don't Create Volleyball Code

By Steve Litt

This document is dedicated to Gary Miller, former beloved instructor extraordinaire at Full Sail University, and former valued GoLUG member, who on April 7, 2016, went to Heaven to teach the other angels software development best practices. Gary, we miss you.

Introduction

Volleyball code is code in which execution bounces from object to object, or module to module, or sometimes even willy-nilly from function to function. Repeating, volleyball code is about the travel of execution. This document presents a small example of volleyball code: The code, the resulting output, and a diagram of execution travel. It demonstrates what a mess volleyball code is. This document has similar examples of tree code and yo-yo code, with code, output and diagrams, to demonstrate superior sequences of execution travel.

When you require five open editor windows and an IDE that looks up objects, modules, functions and methods, you're probably creating or maintaining volleyball code. If you see functions repeatedly calling each other, and you're not doing functional programming or deliberate recursion, it's probably volleyball code.

Volleyball code is bad because it's hard to read, hard to understand, hard to repair, hard to write, and, contradictory to sales pitches often proclaimed by advocates of volleyball code producing programming paradigms, hard to extend. Volleyball code is the subroutine-created equivalent of the ancient spaghetti code that used to be created with GOTO statements before GOTO statements were banned by most organizations. Unlike spaghetti code, however, the harmfulness of volleyball code is not yet fully recognized.

This document fully discusses volleyball code, so it's easy to recognize when you see it. This document also introduces several excellent alternatives to volleyball code, including:

There are tens or hundreds of facets of writing quality code. Avoiding volleyball code is just one of them. Unfortunately there's a heck of a lot of volleyball code out there, hence this document. So kick back, relax, and learn about volleyball code: Why it's bad, how to recognize it, and how to avoid writing it, including alternative methods.

License For Source Code In This Document

All computer program source code in this document is licensed with the permissive Expat license, which can be seen at https://directory.fsf.org/wiki/License:Expat. Everything in this document, including the code, comes with NO WARRANTY!

License for this document itself not yet decided, and for the time being should be considered free to read and distribute as is, but not to distribute modifications.

THIS DOCUMENT HAS NO WARRANTY!

Best Viewed NOT In Firefox

This is 2021, and I really thought we were past this "best viewed in" stuff, but maybe not. Examine the following graphic of circles with interaction lines:

Diagram of yo-yo code: See if the lines have direction arrows.

The interaction lines in the preceding document should have arrows to show their directions. If they don't, try another browser. My Firefox version 90.0.1 64 bit does not show the arrows, whereas the arrows were plainly visible in Chromium, Midori, Otter-Browser, Eolie, Epiphany, Qutebrowser, and Vimb on Linux. On Windows the arrows appear on Google Chrome, MS Edge, and Internet Explorer, but not Firefox.

So if you're using Firefox you probably won't see the arrows on this document's graphics, and a lack of arrows renders the graphics useless, because you can't deduce the direction of travel. So if you don't see the graphics, switch to a non-Firefox browser.

Interpreting This Document's Images

This document uses images to show call and return flow of tree code, yo-yo code, and volleyball code. The following is an example of such images:

Example of this document's diagrams

The preceding graphic shows the inter-function calls and returns. The calls are solid black lines. The returns are dashed red lines. The arrows tell which way the call or return goes. The numbers beside lines give the order of these movements.

Common Modules For Python Demonstrator Programs

The following two Python 3 modules, whose filenames are globals.py and call.py, are used in tree.py, yoyo.py, and volleyball.py.

globals.py

The following code, called globals.py, gathers all global variables into one file, so they can be used in any module, and so they don't need to be declared global in subroutines in those modules.

/* 
 * globals.py Copyright (C) 2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */
tripnumber = 0
route = ''

call.py

This file contains one subroutine, called call(), that each subroutine (a(), b(), c(), d(), e() and f()) uses to call the next of those one letter subroutines. Not only does call() complete the call to the next one letter subroutine, but it also prints out the calling and called one letter subroutine, and it prints when the called one letter function returns to the calling one letter function.

In order to demonstrate what such output looks like, the following is the output of the tree code example, in which a() calls each of b() through f(), and b() through f() do nothing but return to a():


TREE CODE BETWEEN MODULES a,b,c,d,e and f

Trip number   1:  z-->>a    Level 0
Trip number   2:  a-->>b    Level 1
Trip number   3:  a<<--b    Level 1
Trip number   4:  a-->>c    Level 1
Trip number   5:  a<<--c    Level 1
Trip number   6:  a-->>d    Level 1
Trip number   7:  a<<--d    Level 1
Trip number   8:  a-->>e    Level 1
Trip number   9:  a<<--e    Level 1
Trip number  10:  a-->>f    Level 1
Trip number  11:  a<<--f    Level 1
Trip number  12:  z<<--a    Level 0

Route = ,a,b,b,c,c,d,d,e,e,f,f,a

Now that call.py has been explained, there's nothing left to do but show its code:

/* 
 * call.py Copyright (C) 2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */
#import sys

import globals as g

def call(srcname, level, dest, destname):
    g.tripnumber += 1

    ### OUTGOING CALL ###
    fmt ='Trip number {:3}:  {}-->>{}    Level {}' 
    print(fmt.format(g.tripnumber, srcname, destname, level))
    g.route = g.route + ',' + destname
    dest(level + 1)

    g.tripnumber += 1

    ### COMING BACK VIA RETURN ###
    fmt ='Trip number {:3}:  {}<<--{}    Level {}' 
    print(fmt.format(g.tripnumber, srcname, destname, level))
    level -= 1
    g.route = g.route + ',' + destname
    return

Tree Code

Tree code is the basic horizontal idea behind functional decomposition, module decomposition, or object decomposition. It's been recognized as a great thing ever since we got rid of the GOTO statement and the spaghetti code they produce. In this section's example each one letter subroutine (a(), b(), c(), d(), e() and f()) uses to call the next of those one letter subroutines. The call() subroutine completes the call, facilitates the return from both, and outputs text for the call and return. The following is the code for tree_code.py):

#!/usr/bin/python3
/* 
 * tree_code.py Copyright (C) 2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */
import globals as g
import call as cl

def a(level):
    cl.call('a', level, b, 'b')
    cl.call('a', level, c, 'c')
    cl.call('a', level, d, 'd')
    cl.call('a', level, e, 'e')
    cl.call('a', level, f, 'f')

def b(level):
    return

def c(level):
    return

def d(level):
    return

def e(level):
    return

def f(level):
    return


print('\n\nTREE CODE BETWEEN MODULES a,b,c,d,e and f\n')
cl.call('z', 0, a, 'a')
print('\nRoute = {}\n'.format(g.route))

Because the concept of the preceding code is simple, the output is simple too, as the following output printout shows:


TREE CODE BETWEEN MODULES a,b,c,d,e and f

Trip number   1:  z-->>a    Level 0
Trip number   2:  a-->>b    Level 1
Trip number   3:  a<<--b    Level 1
Trip number   4:  a-->>c    Level 1
Trip number   5:  a<<--c    Level 1
Trip number   6:  a-->>d    Level 1
Trip number   7:  a<<--d    Level 1
Trip number   8:  a-->>e    Level 1
Trip number   9:  a<<--e    Level 1
Trip number  10:  a-->>f    Level 1
Trip number  11:  a<<--f    Level 1
Trip number  12:  z<<--a    Level 0

Route = ,a,b,b,c,c,d,d,e,e,f,f,a

The following graphic shows the calls and return of the preceding tree code, as shown by the preceding output:

Subroutine calls and returns for this tree code example

As you can see, it's as if a coach called a() hits baseball ground balls to each person coached (b() through f()), with each coached person throwing the ball right back to the coach. This is tree code.

By the way, although the tree code concept was demonstrated with six functions, it could have just as easily been file modules, classes, or other groupings.

Yo-yo Code

If tree code is the basic horizontal idea behind functional decomposition, module decomposition, or object decomposition, then yo-yo code is the vertical idea. Along with tree code, it's been recognized as a great thing ever since we got rid of the GOTO statement and the spaghetti code they produce. The following is the code for yoyo_code.py):

#!/usr/bin/python3
/* 
 * yoyo_code.py Copyright (C) 2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */
import globals as g
import call as cl

def a(level):
    cl.call('a', level, b, 'b')

def b(level):
    cl.call('b', level, c, 'c')

def c(level):
    cl.call('c', level, d, 'd')

def d(level):
    cl.call('d', level, e, 'e')

def e(level):
    cl.call('e', level, f, 'f')

def f(level):
    return


print('\n\nYO-YO CODE BETWEEN MODULES a,b,c,d,e and f\n')
g.route = 'a'
cl.call('a', 0, b, 'b')
g.route += ',a'
print('\nRoute = {}\n'.format(g.route))


The preceding code produces the following output:



YO-YO CODE BETWEEN MODULES a,b,c,d,e and f

Trip number   1:  a-->>b    Level 0
Trip number   2:  b-->>c    Level 1
Trip number   3:  c-->>d    Level 2
Trip number   4:  d-->>e    Level 3
Trip number   5:  e-->>f    Level 4
Trip number   6:  e<<--f    Level 4
Trip number   7:  d<<--e    Level 3
Trip number   8:  c<<--d    Level 2
Trip number   9:  b<<--c    Level 1
Trip number  10:  a<<--b    Level 0

Route = a,b,c,d,e,f,f,e,d,c,b,a

The following diagram represents the preceding output graphically:

Graphical representation of the output and calls and returns of this section's tree code example

As you can see, it's six friends formed a line. Each tosses a ball to the next (the call), until the ball gets to the end of the line. Then each tosses the ball to whomever had earlier tossed it to him or her (the return). So the ball goes down the line and then back. This is why it's called yo-yo code: A yo-yo on a string descends and then comes back up the way it went down. This is yo-yo code.

By the way, although the yo-yo code concept was demonstrated with six functions, it could have just as easily been file modules, classes, or other groupings.

Combining Tree Code with yo-yo code

When you combine tree code in order to break up a big task into smaller ones, with more tree code to break up the smaller tasks, you get a very powerful algorithmic tool that produces sophisticated algorithms that are easy to understand. And sometimes, instead of breaking things up, you just keep calling ever less abstract tasks, which is yo-yo code. Combining Tree and yo-yo code is easy to do, produces pretty much whatever you want your logic to be, and makes for very readable code.

Volleyball Code

Volleyball code occurs when various functions, modules or classes call others in a willy-nilly manner. I guess it starts out simply, but soon enough it turns into a ball of yarn. I'm not an expert, but I think volleyball code develops out of expediency and lack of planning. As the code grows, adding or changing anything becomes progressively more difficult, until the code becomes one of those programs "everyone's afraid to touch."

In order to write this section, I deliberately created a volleyball code example using the same call() subroutine as the simple and organized tree_code.py and yoyo_code.py. This example was extremely difficult to construct, because I'm not used to creating such horrible code, and because the relationship between the code of volleyball code and its result is very difficult to predict. The following program is called volleyball_code.py:

#!/usr/bin/python3
/* 
 * volleyball_code.py Copyright (C) 2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */
import globals as g
import call as cl

def a(level):
    if g.tripnumber > 10:
        return
    elif g.tripnumber > 8:
        cl.call('a', level, d, 'd')
    elif g.tripnumber == 4:
        cl.call('a', level, e, 'e')
    else:
        cl.call('a', level, b, 'b')

def b(level):
    if g.tripnumber < 2:
        cl.call('b', level, d, 'd')
    elif g.tripnumber < 9:
        cl.call('b', level, e, 'e')
    elif g.tripnumber < 14:
        cl.call('b', level, f, 'f')
    else:
        return

def c(level):
    if g.tripnumber > 16:
        cl.call('c', level, a, 'a')
    elif g.tripnumber > 8:
        return
    else: 
        cl.call('c', level, d, 'd')


def d(level):
    if g.tripnumber > 10:
        return
    elif g.tripnumber > 4:
        cl.call('d', level, c, 'c')
    elif g.tripnumber > 1:
        cl.call('d', level, a, 'a')
    else:
        return

def e(level):
    if g.tripnumber > 10:
        cl.call('e', level, d, 'd')
    elif g.tripnumber > 8:
        cl.call('e', level, a, 'a')
    elif g.tripnumber > 6:
        return
    else:
        cl.call('e', level, c, 'c')
    cl.call('e', level, f, 'f')

def f(level):
    if level < 1:
       cl.call('f', level, c, 'c')
    else:
       return


print('\n\nVOLLEYBALL CODE BETWEEN MODULES a,b,c,d,e and f\n')
g.route = 'a'
a(0)
g.route += ',a'
print('\nRoute = {}\n'.format(g.route))

The preceding volleyball code produces the following mess of an output:



VOLLEYBALL CODE BETWEEN MODULES a,b,c,d,e and f

Trip number   1:  a-->>b    Level 0
Trip number   2:  b-->>d    Level 1
Trip number   3:  d-->>a    Level 2
Trip number   4:  a-->>b    Level 3
Trip number   5:  b-->>e    Level 4
Trip number   6:  e-->>c    Level 5
Trip number   7:  c-->>d    Level 6
Trip number   8:  d-->>c    Level 7
Trip number   9:  c-->>d    Level 8
Trip number  10:  d-->>c    Level 9
Trip number  11:  d<<--c    Level 9
Trip number  12:  c<<--d    Level 8
Trip number  13:  d<<--c    Level 7
Trip number  14:  c<<--d    Level 6
Trip number  15:  e<<--c    Level 5
Trip number  16:  e-->>f    Level 5
Trip number  17:  e<<--f    Level 5
Trip number  18:  b<<--e    Level 4
Trip number  19:  a<<--b    Level 3
Trip number  20:  d<<--a    Level 2
Trip number  21:  b<<--d    Level 1
Trip number  22:  a<<--b    Level 0

Route = a,b,d,a,b,e,c,d,c,d,c,c,d,c,d,c,f,f,e,b,a,d,b,a

To appreciate what a mess the preceding output represents, the following is a graphic representation of the preceding output of my volleyball code:

A graphical portrayal of thetravels of volleyball code

How could anybody make sense of the preceding? How could you add another call, or just change a variable. Volleyball code is fragile and almost impossible to read or maintain when it gets really bad.

MVC and Volleyball Code

A big problem with MVC (Model View Controller) is that it has different definitions. In technology, this is never a good thing. Does MVC correlate with volleyball code? That all depends on your definition of MVC. Unfortunately, definitions of MVC abound, many of which are incompatible or contradictory. All references in this section were captured on the Internet on 8/14/2021.

The Geeks For Geeks Definition

This definition is given by Geeks For Geeks. The Wikipedia Model-view-controller Page has essentially the same definition.

To me, this a great, modular and solid software design paradigm, with the Model containing or accessing all data and logic, the View formatting output for the user, and the controller accepting all user input.was a great, modular and solid software design paradigm, if and only if this paradigm is adhered to. In this definition, the Model containing or accessing all data and logic, the View formatting output for the user, and the controller accepting all user input.

The following is a diagram of the Geeks for Geeks MVC architecture:

Graphical portrayal of the Geeks for Geeks MVC architecture

So the correct logic would be as follows: The Model contains, or has access to, all the program logic and data. The View is just a graphical data presenation appliance for the user to see, and the Controller is just a data capture appliance to capture mouse, keyboard or other input from the user. The Model should never call anything from the View. It should mostly call its own methods, and when there's data to present to the user, give that raw data to the View to present to the User. The Controller should call only methods in itself or the Model, and the View should call only methods in itself. The View and Controller should never speak to each other, and should know nothing about each other. In this way you have clean separations. I suppose there might be one-off exceptions for the View introducing itself to the Model, and the Model introducing itself to the View, so they can talk. Other than that, all communication should either go counter-clockwise or stay put in their current object.

But there's trouble in paradise. When you read the entirety of Geeks For Geeks MVC Design Pattern, it becomes clear that each object requires its own Model, View and Controller. And in their sample code, the controller has a get method for the object under concern, so it's obvious that in their code the Controller is much more than a translator between mouse/keyboard actions and the Model (data and program logic), so the action will actually bounce around more than the diagram says.

The Guru99 Definition

Right from the start, the Guru 99 MVC definition looks more bouncy. This definition doesn't say whether the Model, View and Controller are on a per-object basis or not, but if they are, then this surely produces volleyball code. If not, well, if not volleyball, it's at least pretty bouncy.

This design pattern is beginning to look like volleyball code right from the start, before coding has begun.

The Rails MVC Definition

This is where computing goes off the rails, no pun intended. Check out the Rails portion of the Getting Started With Rails document. There's no diagram, but from the text it appears that not only does Rails have a Model/View/Controller for each class, but it also has an Application object and several "Routes". From my past exploration of Rails tutorials, it seems to me like every one of these things need to know about all the others. In my opinion the Rails definition and use of MVC creates severe Volleyball code. As a matter of fact, it might transcend Volleyball code and more resemble a field of walnuts on cocked rat traps. I gave up on MVC after failing to follow the logic and data flows for Rails tutorials.

I'll admit this: For the person expert at Rails, few development environments are faster. But for me, all that bouncing around leaves me queezy.

Turing.edu MVC Architecture

This MVC definition actually makes some sense. Check out the following diagram:

The Turing MVC Architecture digram

The preceding diagram is yo-yo code, which is a good thing. The user interfaces with the view and nothing but the view, for the user's input (video screen presentation) and the user's output (keyboard and mouse). The data, and code directly related to the data, is encapsulated in the Model. In the Turing.Edu definition, the Controller contains the code that makes the application what it is, and also acts as a go-between between the View and the Model. Read the document by clicking the following link:

Turing.edu MVC Architecture

From what I read in the preceding link, there's one Model, View and Controller for the whole program: No follow the bouncing ball randomly between all sorts of objects. This seems to produce a situation where a graphical expert could write the View while an actual Developer creates the Controller and Model. This seems to be a successful implementation of Separation of Concerns.

The Coding Horror Blog

Then we have Coding Horror's Understanding Model-View-Controller. In example 1 the Coding Horror document defines the Controller as the link between the user and the system, with an HTML "skeleton" as the "bedrock content". Huh? Defines the View as the "skin" giving output (I guess) its appearance, mostly CSS. Defines Controller as, it wasn't clear, but perhaps the browser. In another example it defines the Model as the classes to store and manipulate data, the View to present the data to the user, and the Controller, as the "brains" of the application, which decides what the user's input was, how the Model should change as a result of the input, and which view should be used to inform the user.

Maybe I Just Don't Understand These Web Pages

Maybe I just don't understand the web pages linked previously in this section. Maybe they're not really contradictory. Maybe the bouncing I perceived in Rails tutorials wasn't really bouncing at all: Maybe it was some sort of linkage between objects. All I can tell you is I gave up on Rails because, from my perception, their MVC bounced all over the place.

MVC Needs a Definition

If we're expected to use MVC, the least that can be done for us is to give us a consistent definition. It doesn't have to be an unreadable 50 page specification: A few paragraphs, agreed upon by everybody, would do the trick. Until then, I think we can expect a lot of volleyball code out of many MVC architected programs.

Swapping Data For Algorithms

We all know that we can move complexity between data and algorithms. In other words, to make the algorithm less complex, we can add complexity to the data. To make the data less complex, we can add complexity to the algorithm. For the past several decades we've all known data is a better place for complexity.

This tradeoff isn't the subject of this document, and so is beyond the document's scope and is ignored. But of course in real life, one should not only avoid volleyball code, but also enhance and simplify algorithms by proper use of data structures.

Onion Code Architecture

At a meeting to introduce and improve on the DNG-developed software best practices guide, Maddog brought up that they used to use something called an onion architecture. According to Maddog, each layer of the onion contains functions that call functions on the next lower layer, or perhaps a layer lower than that. Such an architecture is pretty much a combination of tree code and yo-yo code.

Maddog then said problems arose when somebody created one or more function calls that went from a layer to a more outer layer, at which time the code would become fragile, hard to read, and hard to maintain. This isn't surprising, because onion architectures that go both in and out degrade to volleyball code.

State Structure Architecture

Long ago, before Object Oriented Programming was widespread, many of us used state structures to handle complexity.

For instance, back in the early 1980's, reports required printing monospaced print on paper forms. In my employer's case, what was getting printed were health insurance encounter forms, each fairly complex, one after the other on perforated tractor feed continuous paper. Amazingly, the obvious solution of creating a two dimensional array to represent every character on the page was too wasteful of precious memory back then. So my client's report programs printed strings, pushed to the right by spaces, and counted linefeeds to get to the needed line. Included was all sorts of arithmetic so things got pushed right or down the right amount. All this was interspersed with actual program logic. It was a mess. It was volleyball code.

So I created a state structure to represent the printer's state: Column (Y position), row (X position), page number, and number of lines per sheet of paper. The following is ltreport.h, a program I wrote in 2008 from memories of that 1985 software:

/* 
 * ltreport.h Copyright (C) 2008,2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */

#ifndef LTREPORT_H
#define LTREPORT_H  
   
typedef struct {
   unsigned int line;
   unsigned int col;
   unsigned int pageno;
   unsigned int linesPerPage;
}REPORT;

REPORT * openReport(const unsigned int linesPerPage);
void atyxpr(
   REPORT * rpt, 
   const unsigned int y, 
   const unsigned int x,
   const char *string
   );
void printPageno(REPORT * rpt);
void formfeed(REPORT * rpt);
void linefeed(REPORT * rpt);
void closeReport(REPORT * rpt);

#endif /*LTREPORT_H*/
}

So in the preceding ltreport.h, the state structure is called REPORT. It contains the current Y position, the current X position, the current page number, and the lines per page of the paper being used.

Assuming you already had a pointer, called rpt, to a REPORT state structure, to print the string "Hello World" line 5, column 28, you'd use the following:

atyxpr(rpt, 5, 28, "Hello World");

To print the current page number at column 40 on line 1, you'd use the following:

atyxpr(rpt, 1, 40, "");
printPageno(rpt);

In the preceding code, the first statement set the print head's line and column position, then printed the page number.

The atyxpr() function sheltered the programmer from having to do all the stupid little arithmetic stuff previously necessary to put the correct strings in the correct boxes on the tractor feed paper. If you wanted to print something immediately to the right of the last string printed, you just used zero for the x and y arguments. Whenever the y argument was less than the state structure's current y position, it automatically formfed to the next form, relieving the programmer of break logic relating to string positioning.

The following is a simplistic diagram of a possible state structure implementation:

Simplistic diagram of a possible state structure implementation

In the preceding diagram, note that the functions are a different color than the state structure, because although those functions are meant to work with the state structure, their declaration and definition are separate from that of the state structure. This is why they have a different color.

It's not necessary, but if you want to see the full code of this printer state structure, it's in the next article.

Isn't This Just Object Oriented Programming?

Some might say that this state structure Programming is just Object Oriented Programming (OOP). For the most part this is true: It is just OOP. In an object aware language, the state structure's data components would simply be variables in the class, and all the functions would be methods in the class. Easy as pie, and it cuts down on volleyball code. My one word of caution is that some folks have an "all OOP all the time" philosophy that can actually contribute to volleyball code as execution bounces between superclasses and subclasses and other objects. The object to contain the state structure should be simple and probably not be inherited.

The following is a simplistic diagram of a possible OOP based state structure implementation:

Simplistic diagram of a possible OOP based state structure implementation

In the preceding diagram, note that the functions, now called methods, are part of the state structure, now called object data. Therefore they're the same color as the object data.

State Structure Functions as a DSL

The Gary Miller Architecture later in this document requires a DSL (Domain Specific Language). State structure functions, and their OOP equivalents, fulfill that requirement beautifully.

The Gary Miller Architecture

The late Gary Miller proposed an architecture that completely separated out the user interface. A diagram of the Gary Miller architecture follows:

Diagram of Gary Miller's
Architecture

The preceding diagram clearly shows that the GUI programmer needs to know nothing except the Domain Specific Language (DSL), and the main programmer needs to know no GUI stuff. Nice!

NOTE:

More details of the DSL will be revealed at the end of this section.

Of course Gary wasn't the only one, or even the first one, to use this architecture. But he was the first person I ever knew to articulate the pure destructiveness of intermixing program logic with GUI willy-nilly, which can only lead to volleyball code.

Such intermixing happened innocently enough. Back before GUI, we all intermixed screen output with logic, in the form of the printf() statement. It was easy and there was no real downside. Separating out the user interface would have been overkill with command line interfaces.

But GUI is a whole different breed, with its event loop, events, callback routines, and all the rest, all of which is usually abstracted into many, many classes. Intermixing program logic with a GUI UI is a sure road to volleyball code. So Gary split it out with a DSL surrounding a socket. With regard to GUI applications, in my opinion this is the surest route to separation of concerns.

I'd like to add one thing about such separation of concerns. MVC treats data, logic and GUI UI as three co-equal entities that all need to be split out from each other. In my opinion, separating data from logic is much less important than separating GUI UI from the rest.

About the Domain Specific Language (DSL)

DSLs can get quite complex, involved and clever, but none of this is needed for the Gary Miller Architecture. All that happens is that the program logic developer creates a simple DSL that interfaces (typically complex) program logic calls to a very simple Application Programming Interface (API), and documents the API. Then the GUI UI developer simply reads and writes from that API. The GUI UI developer needs almost no knowledge of the program logic details, and the program logic developer needs no knowledge of the GUI UI.

Optional: Full Code For the Printing State Struct

This section is optional, showcasing a piece of software 36 years old, no longer relevant or needed, and already explained at a higher level in a previous section, but just in case you're curious, the full source is contained in this section.

As shown already in a previous section of this document, the following is ltreport.h, the header file and declaration for the "ltreport" software tool:

/* 
 * ltreport.h Copyright (C) 2008,2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */

#ifndef LTREPORT_H
#define LTREPORT_H  
   
typedef struct {
   unsigned int line;
   unsigned int col;
   unsigned int pageno;
   unsigned int linesPerPage;
}REPORT;

REPORT * openReport(const unsigned int linesPerPage);
void atyxpr(
   REPORT * rpt, 
   const unsigned int y, 
   const unsigned int x,
   const char *string
   );
void printPageno(REPORT * rpt);
void formfeed(REPORT * rpt);
void linefeed(REPORT * rpt);
void closeReport(REPORT * rpt);

#endif /*LTREPORT_H*/
}

The preceding header file contains all the declarations. The following ltreport.c file contains all the definitions:

/* 
 * ltreport.c Copyright (C) 2008,2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "ltreport.h"


REPORT * openReport(const unsigned int linesPerPage){
   REPORT * rpt = malloc(sizeof(REPORT));
   assert(rpt != NULL);
   rpt->pageno = 1;
   rpt->linesPerPage = linesPerPage;
   rpt->line = 1;
   rpt->col = 1;
   return rpt;
}

void atyxpr(
   REPORT * rpt,
   const unsigned int y,
   const unsigned int x,
   const char *string){

   if(y != 0){
      if(y < rpt->line){
         formfeed(rpt);
      }
      while(rpt->line < y)
         linefeed(rpt);

   }
   if(x > 0)
      if(x < rpt->col){
         const char * s ="Warning string overwrite line " ;
         fprintf(stderr, "%s%d, column %d\n", s, y, x);
      }
      for(; rpt->col < x; rpt->col++)
         printf(" ");
   printf(string);
   rpt->col += strlen(string);
}

void formfeed(REPORT * rpt){
   for(;rpt->line <= rpt->linesPerPage; rpt->line++)
      printf("\n");
   rpt->pageno++;
   rpt->line = 1;
   rpt->col = 1;
}

void linefeed(REPORT * rpt){
   printf("\n");
   rpt->col = 1;
   rpt->line++;
   if(rpt->line > rpt->linesPerPage){
      rpt->line = 1;
      rpt->pageno++;
   }
}

void printPageno(REPORT * rpt){
   char buf[10];
   snprintf(buf, sizeof(buf) - 1, "%d", rpt->pageno);
   printf("%s", buf);
   rpt->col += strlen(buf);
}

void closeReport(REPORT * rpt){
   free(rpt);
}

Now that the software tool is completely defined, the following, called usereport.c is some code to demonstrate use of the tool:

/* 
 * usereport.c Copyright (C) 2008,2021 by Steve Litt
 * Expat License:
 *   https://directory.fsf.org/wiki/License:Expat
 * NO WARRANTY!
 */

#include "ltreport.h"

int main(void){
   REPORT * rpt = openReport(15);
   int n;
   for(n=1; n <= 3; n++){
      atyxpr(rpt, 1, 35, "Page # ");
      printPageno(rpt);
      atyxpr(rpt, 1,50, "|Other Info|");
      atyxpr(rpt, 5, 5, "Line 5 column 5");
      atyxpr(rpt, 5, 25, "Line 5 column 25");
      atyxpr(rpt, 5, 45, "Line 5 column 45");
      atyxpr(rpt, 7, 10, "Line 7 column 10");
      atyxpr(rpt, 7, 30, "Line 7 column 30");
      atyxpr(rpt, 10, 15, "Line 10 column 15");
      atyxpr(rpt, 10, 20, "Line 10 column 35");
   }
   formfeed(rpt);
   closeReport(rpt);
   return 0;
}

Building This Software

First of all, obtain these source files by selecting, copying and pasting the code shown in this web document. The code has replaced the left angle bracket with its "& l t ;" (spaces added) and the right angle bracket with "& g t ;", so code grabbed out of this documents source will fail to compile.

To compile this code, name the three source files exactly as they're named in this document, put them all in the same directory, and use the following shellscript to compile and link:

#!/bin/sh
gcc -c ltreport.c
gcc ltreport.o usereport.c

No need for make or a make file, the preceding shellscript does its work in less than a tenth of a second.

Wrapup: Don't Create Volleyball Code

Volleyball code is the subroutine-created equivalent of the ancient spaghetti code created with GOTO statements. When program execution continuously bounces between between functions or methods in different objects or modules, you can be pretty sure you're dealing with volleyball code. When you require five open editor windows and an IDE that looks up objects, modules, functions and methods, you're probably dealing with volleyball code. When you see GUI UI code sprinkled between pieces of code that address the problem at hand, you're probably working with volleyball code. If you see functions repeatedly calling each other, and you're not doing functional programming, or deliberate recursion, it's probably volleyball code.

Plenty of people make a good living writing volleyball code. Aided by lookup-IDEs, multiple editor windows, and best guess default web rapid application development tools like Rails, people good at such things can whip out a lot of software in little time.

But look at the average web application. In all too many cases, the developer was so busy juggling volleyballs that he paid too little attention to the problem domain code, leaving all sorts of edge cases and bugs, many of which crash when hit hard. And if the developer prioritizes the problem domain code, all too often the GUI is inobvious, awkward to use, and full of surprising behaviors. With execution bouncing all over the place, the code is hard to figure out, so getting bugs fixed approaches impossibility, resulting in a WONTFIX response to bug reports. Look on the Internet: You'll see these things constantly.

At some point, the Model View Controller (MVC) architecture was created to lessen volleyball code. But like so many other originally good ideas, it was bastardized by carpetbaggers and those of lesser persuasion to the point where now MVC, which no longer has a single standard definition, is just as likely to increase volleyball code as decrease it.

One horrible effect of volleyball code is to create feedback loops in situations where feedback loops aren't necessary. Even one or two feedback loops increase difficulty of troubleshooting or modification as much as an order of magnitude. More than that would resemble a very complex electronic circuit, requiring a computer just to figure out program flow.

During the past decade, volleyball code has been the hip thing, with few questioning its use, and many calling it "modern". Don't fall for that line of bull: There are many, many architectures that reduce or eliminate volleyball code. Some discussed in this document were:

Be careful with Object Oriented Programming. Inheritance is great if the subclass simply has a few things added or changed from the superclass. But if it gets to the point where they hardly resemble each other, don't subclass: Write it custom. I know, I know, the familiar voices will chide you not to reinvent the wheel. But all too often, those same voices import an entire wheel when all they needed was a single spoke nipple. The result is complexity and volleyball code.

The preceding paragraph cautions about misuse of the "is-a" relationship between classes, but there's plenty of caution for "has-a" relationships too. If a program is passing whole objects between other objects of multiple classes, the result is volleyball code, especially given that in most languages objects are passed by reference, so that if one object changes it, it's changed for all. Try very hard to make inter-class interfaces very thin, so that the interfaces those classes produce have thin interfaces. Thin interfaces are a great antidote to prevent volleyball code.

Above all, don't immediately sit down and code when you get an assignment. Take the time to think deeply about what data structures would cleanly represent what's being done. With both algorithms and data, really think what's needed in order to make them separate modules that interact rarely, and only through thin interfaces. It can be done: Gary Miller proved that. You don't have to do it Gary Miller's way, but for gosh sakes, don't contribute to existing glut of volleyball code.