Design Thinking
Upcoming Components challenge us. XP has design thinking. Names are dropped. Brief descent to politics. Cute Video.
An old man sitting alone at a zebrawood desk in his front room, listening to Breakfast with the Beatles, can’t really be said to be doing Extreme Programming, but I do try to embody the applicable bits that I learned so long ago with Kent Beck, Ward Cunningham, Chet Hendrickson, Martin Fowler, and all those great folks. Name-dropping aside, I really do try.
One famous rap against XP, derived from its focus on implementing user stories from the very beginning, was that there is no design in XP. Nothing could be further1 from the truth: we design all the time, and as soon as we can, we let our code take part in our designing2.
However, in Extreme Programming Installed, I’m pretty sure that we described the “Quick Design Session”, a very short period of time when the team would discuss the design of some bit of the program, perhaps drawing some pictures or creating CRC cards. Once a plan began to form and to look promising enough, we would then begin to turn it into code.
All that is prologue to an upcoming bit of work, for which I need a better idea than I have right now. I need a Quick Design Session, and I think I’d like to draw some pictures. I’ll introduce my thinking here and then probably retire to the living room, where I keep my iPad, and draw some pictures. Then I’ll come back and get to the code, probably tomorrow but you never know.
Current Model is Inadequate
One thing is surely inevitable when we undertake incremental design and development such as XP calls for: our initial design, our then-current design, will frequently be found to be inadequate. This is easy to see: if in the first bit of the product development, we focus on delivering user stories, the design beneath them will necessarily be as simple as possible, and will surely not support all the stories that will come along.
This is scary. Most of us were taught that we need to have the whole design figured out before we start to code, because otherwise we’ll code off a ledge and be unable to build all the features needed. Many of us believed that story, and when we were building a product and the next feature turned out not to fit our existing design, we attributed the issue to having done a poor job of the up-front design. Curiously, that seemed to happen to many of us Every Single Time, no matter how much design we tried to do before starting.
XP asks us to build the design “just in time”, elaborating the design as needed while we build features—user stories. We do that by refactoring, which all here know is defined as “changing the design of existing code”. Many, probably most, of the articles here on this site address how we can improve our design to support new stories as we go. Again and again, I “get into trouble”, needing a feature that the code cannot support. Again and again, some small changes, usually capable of being made over time if necessary, improve the design so that the new feature can be fit right in.
I’m told by my friends that this is harder than I believe it to be. That could be true. I may have more practice refactoring than almost anyone alive, certainly refactoring the kind of semi-crummy code that I write, and I have more than six decades of learning about program design. I guess it’s credible that I can do this better than, say, the average nine-year-old child, and perhaps better than at least some sufficiently inexperienced professional programmers.
So, yes. This approach works best when you know lots of design alternatives, and when you have lots of practice refactoring, and it should go without saying—I’m about to say it—that you need a very strong set of tests to help ensure that things keep working as you refactor.
If you read my stuff, you care about doing your work well. Unless of course, you just come here for the jokes and to watch me thrash. That’s OK, too, whatever floats your boat. But probably, you care about working well, and I like to imagine that my experience here may give you ideas that will be useful to you.
Anyway, our current design model is inadequate. Let’s see why.
Components Can Move Around
Almost all our Components move, of course. Wheel turns, Crank turns, following wheel, ConRod attaches to Crank at one end and touches a line at some given angle at the other, and so on. So far, each Component updates itself based on two vectors from its parent, the parent’s start and finish. The ConRod’s start is the point on the Crank where it is attached, and its finish is the point on the given line that is the right distance from start. So a Piston, which generally tracks a ConRod, looks at the ConRod’s finish and attaches its start to that point, and its finish is a point at a distance equal to the Piston length, along the provided constant Piston angle.
We recently implemented the BellCrank, which sits at a fixed location and has two points of interest the one that is driven by some kind of rod, and one that is at a fixed angle from the driven one, which drives some other Component, typically a rod.
Here is a video showing a bell crank driving a rod and piston. Look in the lower right of the video.
That particular diagram has no real meaning in the world of locomotives, but a similar sort of thing is used to provide the necessary valve operation of a locomotive. When the piston that drives the wheels is at one end of its stroke, a valve needs to open at that end, letting steam in, while the other end has an opening to let the used steam out. So the valves operate out of phase with the drive piston. In fact, one way or another, their operation isn’t really continuous in the sense that the wheel driving is. Various schemes open and close steam paths as things go on.
It turns out that starting the train requires different steam flow than steady state running. So the valve timing needs to change. Various schemes for doing this exist. I am aware of Walschaerts linkages, Stephenson linkages, and a couple of really arcane early ones.
I just found this page, which has some nice animations. Take a look at the Baker linkage down the page a ways. The red line just to the left of the piston and valve is in essence a bell crank with angle 180. And note that its center is not fixed. In fact, it’s clearly not our current kind of BellCrank. In essence, that line has two parents, the rods that are pushing it at top and bottom and its finish point is the center point that pushes the valve.
There are other examples that come from the train’s operator adjusting controls that move some bits of the linkage that we think of as fixed, changing the geometry and therefore the timing of motion. This occurs in reversing the locomotive, but also in tuning operation between startup and continuous running.
So we need to examine some of these cases and see how our design must be changed to accommodate them. Of course it is always possible that we’ll determine that this whole idea is useless, or we might discover that some linkages just can’t be supported. Or we might have to devise some horrible kludge.
My guess is that we’ll need some changes. Possibly some objects need more than one parent. I think it’s fair to say that one way or another some will need more than one parent.
I have a starting inclination toward a solution. We presently have a Component FixedPoint, which acts as a Component but has no real behavior: it just returns its location as both start and finish. It’s used by Wheel, to provide the Wheel with its location. (We could have had Wheel just “know” its location. Somehow the FixedPoint idea seemed better to me. Some object needed to be fixed, and having an object with no other behavior just made more sense to me.)
Now our BellCrank, for example, is given a Vector object as its location, not a FixedPoint. BellCrank’s code knows that it has a vector. So I’m thinking: suppose that wherever we give an object an actual location vector, such as we do for BellCrank, let’s give it a FixedPoint instead, and have it somehow fetch the position from the FixedPoint.
If we did that … we could have a VariablePoint object that could move, but the BellCrank wouldn’t know, it would just use whatever position it was given at the time of calculation. So then, by moving the VariablePoint, we could move the BellCrank.
That all seems to hang together in my mind, with one concern: we built the current parent notion specifically so that our Components did not go rummaging around in their parent objects. We pass the only two values they are allowed to know, start and finish, and our Components have no access to their parent object. So providing a FixedPoint / VariablePoint that is owned by the BellCrank violates that design decision.
Another related concern has to do with start / finish themselves. I think that most of our objects only use finish and have no use for start. So perhaps these are not quite the right values to be sending. I suspect that one use of start is to compute the slope of a component, so perhaps we should be providing that. Anyway, that needs exploration in the code.
So there are a few starting ideas and concerns in my head. If I had a team, we’d probably have sorted out a scheme already, or in another hour we would. As things stand, I get to spend the hour alone, which limits progress to the rate of ideas that I can produce, and limits quality as well. Team ideas are generally better than one person’s, if only because the team can see and raise issues that one person will gloss over in the excitement of having had an idea.
But no team is available here at my house, so it’ll be me and my iPad and what is left of my brain for a while. If you read this and get any ideas, feel free to send them to me on Mastodon.
See you next time!
-
Exaggeration for effect. Every word from the lips of certain high-profile individuals in this country is further from the truth, and getting further every day. But I do not come here to dwell on politics, I come here to think about other things. As you were. Carry on. ↩
-
This fine notion, expressed as “letting our code participate in the design” has its origin with Kent Beck, over three decades ago. When we create a “paper” design, it seems that as soon as we start coding, we find problems with it. The XP solution is to start coding with it as soon as we can, so as to find and fix those issues early on. ↩