Single Purpose in Lab 2
Thoughts on Lab 2 and Single Purpose
Perhaps another way to think of functions we write in this class is to see how much we can take away
from them and still let them do their one purpose that they were written to do. Do not take that to
extremes, but chances are you are programming” fat” functions that handle lots of different kinds of
details. How much can you take away and retain the ability to perform the single purpose?
Let us consider a partial design walkthrough for lab 2.
What does main own? Main owns the two now() calls, the print that tells how scanf failed, and the print
of the total runtime. It also owns setting up graphics and tearing them down. This sounds like a lot of
detail, but it boils down to “setup and teardown live here.” Any detail that can be is pushed to a lower
level.
We have to read billiard balls until we run out of them. So the function main calls might own the details
of successively reading in ball data. It doesn’t own running the sim for a single ball, it hands that off. So
we have a loop built around scanf and inside that loop is a single line that takes ball data and passes it
off to be run. If scanf returns a value we don’t like, we return it.
The function most likely to run into the line count is the function that runs the sim for a single ball. At a
high level, that can be thought of as so long as the ball is on the table, output the ball and take one step
forward in time. When done, do some final output for the ball. Unfortunately, in our call by value
world that does not yet have pointers and structs, taking a step forward in time means this code has to
update the positions and the elapsed time.
One of the functions that the above function could depend on is a master output function. Master
output does output for every output method we have (text and graphics). It doesn’t know how to do
either of those things, it calls 2 helper functions. If we added a third way of doing output, we’d add one
more line to our master output function:
Our two output functions have no idea how the other works. The text output function is very short. If
we ever change how we do text output, it’s the only function that needs to change. The graphical
output function has a handful of lines of code needed to draw a ball and make that visible to the user.
In a similar way, the code that runs one sim could call a final output function when the ball goes off the
table. That function calls two helper functions. The text helper prints the off the table message. The
graphical helper shows a cleared table for two seconds.
The above design has six output related functions. All of these have a narrow view of the world and only
a few lines, but if you added up all of the lines and put them in the function that runs the sim we’d
probably run it out of lines. Instead we have 2 lines; one for inside the loop and one at the end of the
loop.
In the example code pictured above, note how we handle TEXT and GRAPHICS. The code in draw_ball
never checks to see what mode we are in because it knows it is never called unless we are in graphics
mode. You may use the code in the picture if you wish. Only code that deals with output should check
GRAPHICS or TEXT; the sim must run the same in either mode.