Complexity and Test-first 3

The story came from here.

At XPDay last year I ran a session exploring some of the ideas about complexity and TDD that I've discussed here before. Attendees at the session got a very early copy of a tool, "measure", which calculates some of the statistics I'm intersted in. From that came some good feedback which I've incorporated into a new version of the tool, avilable here. Note to XPDay attendees: this is a much more informative bit of software than the one you have, I suggest you upgrade.

The session will be repeated at Spa this year.

New Tool Features

Measure now shows the parameters for both a Zipf and Pareto distribution modelling how the complexity is found in the codebase. It also shows the R-squared value for the regression through the data points. This was a particular request from the XPDay session and, with due care and attention, can be used to get some idea of how good a fit the distributions are.

Measure also now accepts a -h flag and will display some information about how to interpret the results.

New Results

Using this updated tool, I examined some more codebases (and reëxamined some from before). This table table shows the Zipf distribution paramters. It's getting to be quite difficult to find Java code these days that doens't come with tests, so some of the codebases with an N shown there are ones from SourceForge that haven't had a commit made for several years.
CodebaseSlopeInterceptR^2Automatedunit tests?
Jasml 0.10.953.520.73N
Jruby 0.9.21.476.270.76Y
Smallsql 0.161.545.870.80Y
Sunflow 0.06.31.595.670.90N
m-e-c scehdule α3-101.694.940.92N
NanoXML 2.2.11.775.260.94N
Syncbuilder19991.845.930.9N
Itext 1.4.81.887.990.91N
Xcool 0.11.934.600.84N
Ant 1.7.02.258.900.93Y
Jfreechart 1.0.32.308.580.94Y
MarsProject 2.792.337.90.96Y
Log4j 1.2.14 2.437.340.96Y
Junit 3.8.12.495.990.94Y
Jmock 1.1.02.796.380.96Y
Spring 2.0.12.789.700.96Y

So, the lower slope and higher incercept of JRuby was a surprise. But note also that the R-squared is quite low. This causes me to refine my thinking about these (candidate) metrics. A low R-squared means that the linear regression through the (log-log) points describing the complexity distribution is not good. This suggests that the actual distribution then is not modelled well by a Zipf type of relation. Maybe there's something about language implementations that produces this? It's worth checking against, say, Jython.

Meanwhile, those codebases with a high R-squared (say, 0.9 or above) seem to confirm my hypothesis that (now I must say "in the case of codebases with very strongly Zipf distributions of complexity) having tests produces a steeper slope to the (log-log) linear regression throught the distribution. And it looks as if a slope of 2.0 is the breakpoint. Still lots more to do though.

Further Investigation

I'd be particularly interested from anyone who finds a codebase with an R-squared of 0.9 or more and tests, but a slope less than 2.0

The discovery of codeases whos complexity distribution is not well modelled by Zipf is not a surprise. The fact that such codebases do not match the tests => steeper slope hypothesis is very interesting and suggests strongly that the next feature ot add to measure is a chart of the actual complexity distribution to eyball.

Note to publishers of code

This sort of research would be impossible without your kind generosity in publishing your code, and I thank your for that. If your code appears here, and has been given a low intercept, this should not be interpreted as indicating that your code is of low quality, merely that it does not exibit particularly strongly the property that I'm investigating.

The Story continues here.

What could this be?

There's a kind of psychological tool called a "projective test" in which the subject is exposed to a deliberately ambigious stimulus, asked a question like what could this be? and then their response to it is very carefully studied. The belief (largely discredited) being that the subject will read into the stimulus all sorts of revealing stuff about their inner tensions, repressed fears and so forth.

Just recently, a sort of projective test for programmers was executed via reddit. This old thing was the ambiguous stimulus, and the response revealed a lot about the inner tensions of the programming community--or the reddit-editing part of it, anyway.

It seems to me that no-one in Rickert's story comes away from looking like a hero, not Charles, not Alan and definitely not their managers. Although all for different reasons. This modulo the fact that both Alan and Charles delivered (that's how you can tell it's a work of fiction). It might make for an interesting interview to put the story in front of a candidate (especially one for a role involving any project or line management) and have them discuss it. More interesting to me that some interview techniques, anyway.

So, that was 1985. Twenty years later, where are we as regards discussion of process, its merits and demerits? Well, we nowadays get this sort of thing, and its aftermath.

Cruising?

So, a client is looking to set up a new continuous integration (CI) environment. For historical reasons the default choice is CruiseControl but there are a bunch more tools around, including the very interesting new Build-o-Matic.

Build-o-Matic exists because it turns out to be quicker and easier to build a CI server that does exactly what you want, from scratch, in Python, than to configure the XML-infested Cruise to do something only quite a lot like what you want.

Still, Cruise is fully enterprisey, which doesn't just mean overly complicated, bloated, opaque, and difficult to use--it also means unlikely to trigger the corporate immune system. Which mainly means that the folks who manage the build machine will tolerate it. There's a whole other discussion to be had about organisations that expect developers to be productive but won't give then control of their environment.

Anyway, It'd be nice to suggest B-o-M to my client, but I have a strong suspicion that it would take longer than the lifetime of the project to get B-o-M approved for use (Ivan knows that this is an issue and is working to make it better) What to do, what to do....

Well, how about this: this is a green-field project, and although there's a web front-end coming down the line all the work being done now is real programming with actual POJO's so we can keep the build short. In fact, the build script is going to be a pretty opinionated thing and quite capable of failing your pre-check-in local build if it takes too long (or exhibits any one of a quite long list of other characteristics). So, what will we lose if we have a cron job that checks out head and builds it every now and again (say, every build-time * 3), and a little web page that watches that job and reports what the cron job is upto?

Is this a complete CI solution? No. But then why would we need one of those?

Lessons from life

On a recent business trip to Germany I visited a vineyard. Seems as if climate change in Europe means that the Rheinland vintners can now make reasonable reds, but the (Merlot, in this case) grapes still struggle in the cooler weather. So, in September time the winemaker goes out and removes, by hand, any unripe fruit before the harvest is made and the wine begun.

The polyglot colleague who kindly translated the winemaker's story put it that they "sacrifice quantity for quality". Of course, I shrugged, they reduce scope.

Winemakers have an immovable "delivery date", the time after which the fruit will be past its best. And since, in the case of the Fleischer family, they believe that their business can only flourish is their product is excellent what they do is prefer to deliver less if that maintains the value of what is delivered. Why is this obvious to a winemaker, but not to so many programmers?

Tidbits from Agile 2006

These are some items from Agile 2006 which interested me enough that I wrote them down.

Peter Coffee's keynote

  • it's a wonder that spreadsheets don't have features built in to deal with uncertainty
  • tooling to improve programmer efficiency makes software so much cheaper to write that much more software is worth writing: and so generates jobs for programmers, not the converse
  • 3M apparently has a target for revenues generated by products less than three years old
  • the value of a codebase is not dependent on the effort that went into building it
  • nervousness is the enemy of innovation

An OpenSpace session

  • Agile development manifests the Kolb learning cycle
  • if you wanted to cerify a team as Agile, maybe you'd only really need to certify the facilitators of the retrospectives
  • maybe a retrospective (or similar explicit learning activity) is about deliberately moving from unconcious competence to concious incompetence
  • ...and maybe also has something to do with Heidegger's distinction(pdf) of ready-to-hand from present-at-hand. Something that I've had cause to ponder before in its relation to software.

Ole Jepsen's session "Agile Meets Offshore"

  • perhaps counter-intuitively, distributed teams tend to have shorter iterations than colocated ones

Laurent Bossavit and Emmanuel Gaillot's session "Tool Words and Weapon Words"

  • You are likely in a difficult spot when people start saying things which can be given an "objective" spin but are really claiming the property on the left for themselves so as to imply the property on the right of you:
    • natural vs artificial
    • important vs childish
    • life vs death

Owen Rogers' Agile Estimation tutorial

    • have the "customer" provide estimates, as well as the developers: when the two are wildly different there's something to learn
    • the size of a story as esitmated by the developers is independent of its business value
    • the stories that happen to be in a given iteration are a random sample from the backlog

Johanna Rothman's hiring tutorial

  • using puzzle questions at interview discriminates against candidates who aren't white upper-middle class suburban American males.
  • some white etc. folks find this idea rather upsetting

Ward's Ten Favourite Wiki Pages

  • arguing for of refactoring is arguing for your own lack of ability
  • if you don't know calculus you aren't equipped to "embrace change"

"Agile Architecture" at Agile 2006

Last week I was at the Agile 2006 conference, in Minneapolis and I see from the records that some of you were too: hello again to anyone I met there.

My session was in the first slot after the opening keynote on Monday morning, and I got the impression that some of the folks there hadn't fully grasped what the nature of a Discovery Session was, some other presenters found the same, I think. I believe that the origanisers might do more to help attendees understand better what's likely to be expected of them at such sessions for next year: they aren't tutorials. Of course, my session was a re-presentation of an XP Day session, which like Spa sessions (the other sort I'm used to presenting) tend to be exploratory, open-ended and interactive in a way that the typical Agile session seems not to be.

Outputs

As soon as I get unpacked from moving house I'll have the London reuslts here to compare with, but a selection of the Minneapolis results are here.

The session was bookended by very quick brainstorm to try an capture any change in the attendees thinking after the discussions and work with the lego.

Before

  • TDD-not fit for mainframe
  • volatile
  • develop platform
  • framework
  • shared direction
  • drives communication
  • developers like complexity
  • correct today
  • testable
  • malleable
  • adaptable
  • think big, start small
  • standard
  • organic
  • correct today
  • testable
  • design isn't dead!
  • nimble
  • easy to change
  • business engagement
  • high test coverage
  • flexible
  • easy to change
  • dangerous
And a couple of longer items:
  • Have an idea of what possibilities your customers may need to explore
  • Not for conventional projects, developers know too much business and not only code by success criteria
  • provide guide rails for teams to make decisions within
Indeed, developers do like complexity. Given half a chance, they will put wings on a train!

After

  • experiment
  • results
  • the right solution for the right problem
  • do only what's needed to satisfy requirements
  • testable
  • not holy ground
  • willingness to restart
  • different is OK
  • ROI
  • cost of implementation
  • time to implement
  • brilliant
  • think big, start small
  • responsive
  • correct today (still)
  • locally optimal
  • flexible (within reason)
  • mutant
It looks to me as if the aims of the session were met.

Some conference wiki also bears some comments on the session.

Complexity and Test-first 2

The story came from here.

Of course, I'm not the first to notice that software (or, OO software, anyway) has the scale free property. These folks have done a bunch of interesting work on the scale-free nature of the object graph in running systems, and also in various static properties of code. I might just, though, be the first person to observe that the distributions are quantitatively different for different design methodologies.

What the Wellington group are trying to do is disprove what they call the Lego Hypothesis, that all software can be built out of lots of small interchangeable components. Instead, they claim, because of the scale-free nature of software, the biggest components in bigger systems will be bigger than the biggest ones in smaller systems. I'd read some of this research before, but had forgotten that--conciously, anyway--until reminded of it by Kent Beck. Thanks, Kent.

The story continues here.

Complexity and Test-first 1

The story began here.

Interesting to note that a similar discussion, albeit brief, sparked up on the XP egroup. I posted a link to my previous blog post there, but it seemed to get lost in the flood. Oh well. It will be interesting to compare my results with those in the Muller paper.

Anyway, I've managed to find the time to look at a very small sample of Java codebases, find their distribution of complexity, fit it to a Pareto distribution and take a look at the slope of the best fit straight line. Here's the outcome, codebases ordered by published unit tests per unit total cyclomatic complexity (where applicable):

codebase#tests/
total CC
slope
jasml 0.1001.18
logica smpp library01.39
itext 1.4.101.96
jfreechart 1.0.10.022.43
junit 3.8.20.142.47
ust (proprietary)0.352.79

A few points present themselves: each of the code bases with no tests published has a substantially lower slope (and so substantially greater representation of more complex methods) than any of those with; of those with published tests, number of tests per "unit" of complexity is positively correlated (at about 0.96, very good for "social science", reasonable for "hard science", but this is "computer science", so who knows?) with higher slope and so a preference for simpler methods.

 The story continues here

No graphs? Check the date

Hello. If you've found that some pages here have not been rendering properly it's likely that you were looking at them at the end of June of beinning of July 2006. The problem was that I moved house, thus changing what PSTN exchange my ADSL connection was carried by, and for some reason my ISP couldn't deal with that without taking my whole online presence through them to out of service--I only noticed this problem when my email account stopped working. I apologise on their behalf.

Complexity and Test-first 0

It recently occurred to me to run a Cyclomatic Complexity tool over a codebase I know to have been largely written test-first/code/refactor (and often test-driven). The code is Java, so I used this Eclispe plugin to measure the per-method complexity.

The distribution of complexity per method looked like this:

Note that the count of methods is shown on a logarithmic scale.

There were 19,917 methods in this codebase. The mean complexity per method was 1.46, and the median complexity is 4.5 Not shown on the chart are a few outliers: one with complexity 91, one with 47, and one with 35.

The Extrema

The 91 complexity method turned out to be the doGet of a servlet providing a simple web service, crammed full of if (method.equals("getLocales")) printLocales(out, ids); type dispatching code. Similarly, the 47 complexity method is mainly concerned with calling out to a third-party API and finding which of a small number of equivalence sets a value from a large domain of return codes falls into. It does this by means of a huge switch with many, many fall-throughs. So in these cases we see a disconnect between the arithmatic of cyclomatic complexity and any notion of the code being complicated, in the sense of difficult to undetrstand (and therefore maintain).

Down at the other end of the scale the tens of thousands of complexity 1 and 2 methods are mostly of these sorts:
  • constructors
  • bean methods
  • forwarders
In between are some more interesting methods, which I will deal with in a later post (which is why this is post #0), comparing the amount of testing that was done to write the method test-first with the amount that the Cyclomatic complexity measure would suggest would be required after writing the method.


Interpretation

In one disucssion by McCabe there is the suggestion that 10 is an important threshold for cyclomatic complexity. The SEI treatment gives 11 as the lower bound of the "simple program, without much risk" class. They don't state quite what a "program" is in this sense, I guess they mean "subroutine" in the structured programming sense. As we can see, methods with complexity >= 10 are vanishingly uncommon in the codebase I examined. Evidence that the team working on this code are keeping per-method complexity under good control.

Now, while we can be confident that these methods are overwhelmingly individually very simple the codebase itself is non-the-less considered (by the folks that work on it) highly complex. It does a lot of different things, and interacts with many external systems, and although it is all written in Java it contains several very different technology stacks. So the distribution of cyclomatic complexity isn't the whole story. The total complexity of the whole codebase is about 20,000. It has far fewer that 20,000 test methods (about 7000, in fact), as a simpleminded application of cyclomatic complexity suggests would be required. Although, if you leave out the complexity 1 methods, the total complexity is only 9,000 or so, which paints a different picture.

I don't want to get embroiled in a disucssion of whether or not cyclomatic complexity even makes sense for object-oriented code, not least because the code inside a Java method isn't particularly object-oriented. I do want to examine a mainsteam notion of complexity and testing (the rule is that the complexity equals the smallest number of test cases requied to cover all paths through the code) in the light of code written test-first. Once I've found a suitable candidate method and tests to explore, I'll let you know.


Wait a minute though...

Something about the shape of that chart caught my eye. It looks very much as if it has something close to a power-law distribution. This shows up better on a log-log rendering:

If we switch to a cumulative count of methods we can extract a pretty convincing Pareto distribution:

It so happens that inside the same repository is a bunch of Java that I'm confident was not written test-first (and certianly not test-driven). That doesn't mean that it's bad code, just written differently. What does its complexity chart look like?

Looks like fairly good scale-free beahviour, but let's look at a fitted Pareto distribution:

Not as good a fit. But perhaps more significantly, the slope is about half the slope of the test-first code, 1.39 vs 2.79


Hypotheses

We can imagine all sorts of reasons for these differences (not least, the non-test-first code is an order of magnitude smaller than the test first, which might account for the lower R-squared) but I'm interested in further investigating the tentative hypotheses that the test-code-refactor cycle results in code that has a distribution of complexity closer to Pareto, and with a steeper slope, than traditional approaches.

If that were true, how might we use it? Well, if the complexity distribution is Pareto/Zipf then there is no "preferred" complexity for the codebase. I'd imagine that if there were a preferred complexity then that might point to a (perhaps widely dispersed) collection of methods that could be candidates for refactoring. Question: do the well-known code smells [pdf] cause such a thing?

I'd further guess that the higher level of dupliction expected in an inadequately refactored codebase (not DRY enough, not OAOO enough) would cause a bit of a hump in the complexity distribution. A sag in the distribution I have less of an inution about, although it might point to something along these lines. You'll have to dig around in Prof Salingaros's work to see what I'm getting at, but it's worth it.

Also, if the slope of the Pareto distribution is low then there will be proportionatly more more complex methods in the codebase than less complex ones--that can't be good, can it?

Well, if it wasn't for the day job I'd be looking into this in ernest. But as it is, I'm going to tinker about with this some more as and when I get the time. I'll report back when I do. If anyone else out there does any measurements like this I'd be fascinated to hear about it.

The story continues here.

Staff to Your Methodology

Bill Sempf posted an interesting hypothesis reagrding programmer ability and choice of methodology. Sound enough notion, but I'm not sure I agree with the details, but replying did give me a chance to tell my Royce story.

Doing yourself no favours

There was a time a couple of years ago when I would often travel between Penrith and London on the West Coast Main Line. The WCML is always having a lot of engineering work done on it, so these journey were often held up or interrupted and took place then on the filthy, slow unreliable old train sets that were all the decrepit permanent way could bear at the time.

At Euston there was a display, put on by Railtrack, showing some of the track relaying work going on. Not only did this video loop show off the smart yellow machine that lifts the old track, removes old ties, lays new ballast, new ties and new track (while a bunch of platelayers stand around leaning on their shovels watching it) but the video was speeded up. In the video, the machine whizzed along. To see Railtrack showing off this technology did nothing to improve the mood of those travellers who had been delayed by works.

Why are you talking about trains?

I was reminded of this when I came to Don Box's exposition of "code==data " in the new C# He shows some C# along with allegedly equivalent Scheme, like this. Here's the C#

Expression<Func<int, int>> e = a => a + 1;

and the Scheme

(define e (quote (lambda (a) (+ a 1))))

Well, people who like this sort of thing will find that this is the sort of thing that they like.

Don't you especially love the way that C#'s type system, being at the "sour spot" for such things, requires the programmer to tell the compiler that the code she's writing implements a mapping from int to int? When in fact the implementation given would work for a range of types. It's a bit of a puzzle why this should be required. The way to avoid programmers having to do this is well known, and some of the leaders in that style of working even already work for Microsoft.

The syntax is (to me at least) ugly, verbose and unclear. So, I somehow doubt that putting these pieces of code next to one another is going to make anyone fall in love with the expressive power of C# Added to which, this just is not in general what anyone who knows Lisp means by "code==data ". They mean macros.

Doing Design

In an extract from the new edition ("2.0", indeed) of Software Conflict Robert L. Glass revisits his prior discussion of "design" in software. He focuses on the undoubted fact that design is a cognitive process. It's perhaps a sad reflection on the state of the industry at the time he was writing that this should have been a noteworthy observation.

Where to begin? How to proceed?

Anyway, it seems that Glass undertook a commendable self-assessment of his stance on design, found it wanting and turned to the research of Bill Curtis and Elliot Soloway. As reported by Glass, after a series of "protocal studies" came up with roughly this description of what programmers do when they design:
  1. Construct a mental model of a proposed solution to the problem
  2. Mentally execute the model to see if it solves the problem
  3. It doesn't, so see which parts of the problem the model fails on and enhance it
  4. Repeat until good enough
Strangely, Glass calls this a "well defined process" and looks to the implications of this "new concept of design as a mental process."

By the way, Google wants "protocal" to be a typo for "protocol" but apparently it isn't. "Protocal" seems to mean "talking about what you're doing while you do it."

The problem with the design process as described above is that it has by itself nothing to say about where these mental models come from, or how they are compared or improved. Glass quotes Charles Simonyi on this, thus:
The first step in programming is imagining. Just making it crystal clear in my mind what is going to happen.
Which all, as a description of the design "process", seems only little more useful than the Feynman Problem Solving algorithm (*). Especially since one of Glass's goals in studying this matter was to find a better way to teach design.

Tools for the mind?

In the 2006 update to this essay Glass reports on the outcome of the Curtis/Soloway research: nothing. Apparently, they gave up. Glass states:
Because the nature of design, they discovered, is so intensely cognitive, happening inside the mind at mind speed, the researchers could conceive of no useful tools to help in that process!
What!? No useful tools to help with a process "inside the mind". Come now! I'm not sure I believe that this is what two smart guys like that concluded, unless by tool they meant some clanking monstrosity that would, you know, run on a computer.

Well, programmers aren't the only people who do design, nor who introspect upon their own design activity. In 1964 (about 20 years before the research Glass is talking about) Christopher Alexander produced his doctoral thesis, Notes on the Synthesis of Form, which describes how the "imagining" takes place within a culture and a tradition (the design patterns movement inspired by Alexander seeks to make these things explicit for the society of software builders, and others) in both self-conscious and un-selfconcious modes, but more importantly explains how to traverse the loop from less good to more so. Laurent Bossavit gives a good overview of these ideas. Alexander even went so far as to write some computer programs to help architects and planners use these ideas. That would be a "tool". Oh dear.

As Prof. Sir Tony Hoare has put it
If only we could learn the right lessons from the successes of the past, we would not need to learn from our failures.


(*) The Feynman Problem Solving Algorithm
  1. Write down the problem
  2. Think very hard
  3. Write down the solution

Agile Architecture lessons from SEI

My colleague Tim and I addressed the matter of "agile architecture" at the XPDay conference last year, in a way that raised a few eyebrows. We'd be doing it again elsewhere this year, but the other conferences that we submitted the session to didn't have the imagination or guts to let us put the thing on I guess.

Architecture, by definition


Anyway, recently this article from the SEI ("Leading the world to a software-enriched society") came to my attention. The SEI offers this definition of "software architecture"
The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them.
This strikes me as a rather poor definition, since it means that, for example, I can extract some architecture from this program:
#include <stdio.h>
int main (int argc, char** argv){
printf("Hello World\n");
return 0;
}
This is source code to be compiled into a binary component intended for deployment into a container. There are many free and commercial implementations of this container, and there's a really great book that explains all about how the container instantiates components like this, wires them up to the other components they rely on (that #include <stdio.h> thing there is a bit of declarative configuration information that tells the container that this component is going to use some services from the stdio component) There's an entrypoint into the component that the container will recognise, and the component will indicate to the container using a standard value that it has completed its work successfully (whether it has or not, but when did you ever see anyone check the return value of printf?)

Thus, my program, er, I mean component here has a structure composed of software elements, these have externally visible properties, and there are relationships among them. Obviously, then, this system is just dripping with architecture. Almost as much as this paragraph is with sarcasm.

This is not what anyone means by "architecture", but based on the SEI's definition it's hard to see why not. (Once upon a time, though, the facilities used by my component were a matter of live architectural discourse--but that sort of change over time is for another posting)

Distinctively Architectural


Now, this sort of problem happens all the time with definitions, which is why definitions suck for serious thinking about the world. The authors of the SEI article kind-of dodge coming right out and saying that, but they do instead adopt a much smarter stance and start to talk about what distinctions can usefully be drawn between "architecture", "design" and the rest.

Speaking of drawing, they note in passing that it is a source of confusion to use a notation primarily intended to capture design ideas (UML) to capture architectural ideas. Why do we keep shooting ourselves in the foot like this? Especially since, as an industry, we have plenty of alternatives that we could use. But I digress.

Well, the authors present, in fine consultant style, a 2 x 2 taxonomy (apparently it is the "underlying dynamic structure of 2 x 2 modeling that brings richness, depth and a uniquely transformational power to this simple form". Whatever) And of course, being architects, they call this taxonomy an "ontology". They might not have noticed that it's a 2 x 2 model, though, because they only give three terms. Using their distinctions intensional vs extensional and local vs non-local, the diagram they don't provide would look like this:


IntensionalExtensional
non-localarchitecture???
localdesignimplementation

Hmm, how fascinating! What is it that address non-local extensional thoughts? (Hey, maybe that's the uniquely transformational power doing its thing ;)

So, architecture is to do with what global constraints there are on how the parts of the system are chosen and assembled. I might be wrong but I'm guessing that anyone who writes for the SEI thinks that in general architectures come first and are somehow realised or filled in during design and implementation. That fits well with the idea that architectural ideas are extensional--they don't say how to build the system but they do say what general properties any system built to that architecture will have, what declarative constraints they all satisfy.

An Agile view Emerges


But what about the Agile setting? Well that's a broad church, so what specifically about the XP setting? In XP we first build a spike (very thin, goes from one end to the other) to learn about the essence of the problem/solution. Then we build out more thin vertical slices of functionality, refactoring as we go. Where's the architecture? If it is non-local then it can only become evident when there are enough of these slices in place for there to be anything that isn't local. And with test-driven development we very much proceed in an extensional fashion, filling iexplicitct cases one at a time, and discover the generalities through refactoring.

So the architecture (non-local, intensional) can only arise late in the game. It can only emerge.

Hypothesis for further investigation: the non-local extensional thing might just be the system metaphor, which is stated in quite concrete, explicit, albeit general, terms and is intended to apply to the whole system. And is stated early. If so, maybe the model presented in the SEI article helps explain why there are so many folks want the system metaphor to be instead of architecture and why they get disappointed when that doesn't work.

Lessons from Life

Motorcycles, post-conditions and idempotent operations


Whenever during my programming work I have to think about pre- and post-conditions, or idempotent operations, I always think back to the Compulsory Basic Training course I had to pass to get my motorcycle licence.

The point came when the instructor was explaining the indicators (aka turn signals). On most bikes these are operated by a switch on the left-hand grip. It has two degrees of freedom: sliding to left or right, or being pressed inwards. All of these are intermittent contact operations and a spring returns the button to its home position (in the middle, popped out) when it is released. Sliding the button to the left or the right activates the indicators on that side, pressing the button in deactivates the indicators.

Now, when riding a bike, unlike when driving a car, there isn't the tick-tick-tick of the flasher to let you know that the indicators are on (well, there is, but you can't hear it over the wind noise and beat of the engine through your helmet), and neither is there a switch on the steering to deactivate the indicators automatically after a manoevre. And while it's very dangerous to ride along with a misleading indication going, so too is it to take your eyes off the road and peer around the bike to see if the indicators are still going. So, said the instructor, if you aren't sure if you cancelled the indicators after the last turn, don't bother to look to find out if they're still on--just press the button.

You have to be a programmer to get this confused


The Simpson's Building in Picadilly (now home to Waterston's flagship store) is, in its public areas, roughly this shape:

Where the area that in my diagram is the horizontal cross-bar meets the vertial section there are a pair of fire-shutters. Closer up, it looks like this:

On the wall between the apertures for the shutters is a small notice (indicated by the thicker line) stating that "the area between these shutters must be kept clear". But what is that area? I thought at first that it was the area between the shutter on the left of the notice and the shutter on the right of it, until I turned around and saw the large sales desk (shown in brown). On closer inspection this desk has two gaps in it, to allow the shutters to close. I've shown a matching pair of shutters behind the desk, which seems right but I couldn't absolutely swear to it. Anyway, the little island of desk in the middle occupies the space between where the left and right shutters would be when closed: my reading can't be correct.

So then it ocurred to me that the "these shutters" to which the sign refers are each of the shutters on either side of the notice and its respective shutter behind the desk. That's confusing. Confuses me, anyway.

I once saw a very good documentary about fire safety, starring a New York fire marshal. At one point he pulled out his copy of the fire safety code for buildings in NY, NY and said "this is like a holy book, everything it says in here was put there because of a time when a lot of people died." Which is an interesting take on religion, but that's not what I wanted to talk about. This notice about the fire shutters, in a busy semi-public space is important. Understanding it correctly could well be a matter of life or death. The fire shutters are a life-critical system, and yet an important part of their operation is woefully under specified. The notice could have some more precise explanation of just what the "these shutters" the area between which it is that should be kept clear are, and that would help, but really the problem is moving prematurely from specification to implementation.

What is required is that "these shutters must always be able to be closed completely". The person who drafted the motice has thought about a likely scenario that could prevent this from being true and prohibited that. There's also an attempt to capture a requirement about an action (closing the shutters must always complete) by a static constraint (the area between the shutters is clear).

I suspect that normal people wouln't give the instructions on the sign a second thought. Actually, most normal people probably wouldn't notice it at all.

Test-first and flow

Frank Sommers has proposed a conflict between test-first and "flow". To answer the question he asks at the end of the article "Do you really write your tests first?" I find it easiest to quote Jason Yip from the ensuing discussion on artima: "Yes I do... except when I don't and I pay for it every time..." These days I even think differently about the two activities: test-first is programming. Anything else may involve the creation of code, but really is exploratory noodling about--which has its value but the results should be discarded.

I wonder where Frank learned his test-first? I suspect that he hasn't ever sat down and paired for a significant time with a master of the art. It is a skill and can't be picked up just from reading about it and having a bit of a go. Also, test-first is only a transitional practice to test-driven, which is where the big wins come from.

In any case, I find Frank's appeal to the theory of flow to explain why he doesn't enjoy test-first programming rather bizarre. He quotes Csikszentmihalyi on some of the characteristics of flow:
  • The activity must present just the right amount of challenge: If the activity is too hard, we become frustrated; if too easy, boredom ensues.
  • There must be clear and unambiguous goals in mind.
  • There needs to be clear-cut and immediate feedback about the activity's success.
  • Finally, our focus during the activity must center on the present - the activity itself.
And suggests that they are in conflict somehow with the practice of test-first. I find the exact opposite, and I'm not alone in that. I'm going to talk more about TDD than merely test-first, because I don't practice the one without the other any more.

I find that test-driven development is the way that I turn programming into an activity with the right amount of challenge. I'm just not smart enough to program any other way. I did somehow manage to get paid to program in the days before I adopted TDD, but I no longer understand how that can possibly have happened. YMMV.

In writing a TDD test I am explicitly setting an clear an unabiguous goal for the next few minutes programming.

The red bar -> green bar -> refactor cycle provides very clear-cut and very immediate feedback on my programming activity.

And, as Frank rightly points out, test-first works best on a very small scale. In fact, TDD encourages you to program in very small steps (and, perhaps counterintuitively, the smaller the steps the faster you make progress). So I find that writing the tests first encourages me to center on the present.

Fascinating that two people can have such utterly opposed experience with the same technique.

Agile film-making?

The possibility of parallels between these disciplines came
up on the XP egroup
recently, which remineded me of this wiki posting I made a few years ago. Seems the idea is gaining
more currency.

Job (and other) Trends Revealed

Over at Quoderat someone called iain made a comment on this posting:
Search for commoditized skills like Java, SQL, C++ and you find x,000 jobs advertised. Ideally of course you'd have a longitudinal view on this; you'd have data on the number of jobs offering requiring this and that skill across time and understand the rise and ebb of particular skills.
Well, thanks to the kind folks at job search aggregator indeed.com we can do exactly that.

Their site can display the occurrencece of ads with particular search terms in them over roughly the past year. You have to be careful with false positives, though. The origin of the name of the programming language Forth is from a (forced) mis-spelling of "fourth" as in "generation computer", but "forth" is still a word. It appears frequently in ads for positions in which someone will have to go back and it. I was amazed at the popularity of this niche language, until I figured that one out.

Dynamic Languages Duke it Out...

Anyway, take a look at this:

graph of lisp, smalltalk, ruby and python jobs

Don't worry about the extreme tinyness of the numbers. When indeed.com say "all jobs", they mean all jobs. That Python accounts for 0.15% of them is salutary reminder that there's a huge old world of work out there where what programming language you prefer isn't even a comprehensible question.

So, this looks like good news for Pythonistas, and very encouraging news for Rubyists. iain would suggest that this is a sign that the "elite" (whomever they are) should be thinking about moving on from Python. A dubious proposition.

Speaking of elites, that Lisp curve is worth drilling down to:

graph of lisp jobs

Unless I wildly miss my mark, that's the 2005 Y Combinator Summer Founders Program wildly distorting an entire job market. Let's not be rude about Lisp's 0.005% of the job scene baseline. (Actually, I suspect that most Lisp jobs never get as far as being publicly advertised, so tight-knit is that community).

...and then get Put in Their Place

But let's put our little posse of dynamic languages into context:

graph of dynamic languages vs java and c#

Ouch!

That "java" appears in as much as one fiftieth of "all jobs" is cause for sober reflection. Quickly followed by a stiff drink.

In Other news...

This is absolutely fascinating:

grpah showing agile methods vs rup

Oh yes, that's something I've waited to see. Mid October 2005, a date (range) to remember: "agile" overtook "RUP". Notice, though, how the "agile" and "RUP" curves seem to fall into step afterwards. This is a potential trend worth watching. As is the seemingly imminent overtaking of XP by Scrum.

Increasingly often now there are lead or management type jobs being advertised with some "Agile methods or RUP an advantage" style requirements. Or even, "Agile methods such as RUP". Hmmm. Well, there are those that will claim that RUP done right is Agile. But I digress.

Thinking about closely correlated search terms, how about these two head-to-head competitors:

graph showing Symbian vs WinCE jobs

That's close to the point of being spooky.

Mull this over

This one pretty much speaks for itself. Couldn't be more zeitgeisty:

graph of wiki and blog jobs

Some thoughts about you...

And a big السلام عليك to my readers in Arabia.

One of the great things about teh interweb is how you can set one part of it to watch another.

From this I know that, over the last month, only 7.5% of visitors here used IE. Thus I'm fairly sanguine about the fact that the template doesn't render well for them. It's a shame, and I'm sorry. But I'm not going to fix it, either. You folks should do like the 83% who use Firefox.

To the 80% of readers who are first-timers, I say welcome. And to the 20% of repeat readers, I'm gratified that you found the site interesting enough to return to.

Just what do you need an RDBMS for, anyway?

If you are in the business of writing anything like an "enterprise application" (and these days, that's pretty much every programmer who's target platform doesn't come sealed in epoxy) then you store your data in an RDBMS.

And if you're at all up to speed with developments in the art of programming over the past thirty-odd years you write the application "logic", middle tier, call it what you will, in an object-oriented language (or, at least, something that looks quite a lot like one from a sufficient distance). And so you spend a deal of your time dealing with a thing called the "Object-Relational Impedance Mismatch".

There's money to be made from this. Oracle recently purchased what was originally a Smalltalk O-R mapping tool, Toplink. Like most of its ilk it allows programmers to maintain (by mostly manual processes) a huge pile of XML relating a bunch of tables in a database to a bunch of classes in a codebase. I focus on Toplink because that's where my experience with the topic largely lies, not through any great love or hatred of the product. Well, anyway, the aim of these tools is "transparent persistence", whereby modifications to the mapped objects make their way to the database automagically. (*) So, there's this arbitrary graph of objects that gets mapped onto this strict table-based model, via hierarchical text-based metadata. Ooo-kay.


"Translucent" Persistence

Except that the object graph isn't arbitrary. And the "transparency" is of a rather murky kind. "translucent persistence" might be a better term. At the time that you write the classes from the object graph will be instantiated the mapping tool will impose all sorts of constraints on what you can do, and how you do it. This is very far from the promise of orthogonal persistence. What happened to JSR 20, that's what I want to know.

For instance, if you want to get hold of an object that (you have to know) happens to be backed by the underlying database then what you do is obtain an entry point to the data, and search over it for the object you want. Unlike the navigation that you might expect to do in an object graph, instead you build...queries. Like this:
ExpressionBuilder builder = new ExpressionBuilder();
Expression expression =
builder.get("surname").equalsIgnoreCase("Smith");
Person p =
(Person) aSession.acquireUnitOfWork().readObject(
Person.class,
expression);
Yup, that's pretty transparent alright. Can't tell that there's anything other than plain old in-memory objects there. For Java fans: isn't it especially wonderful how the programmer had to mention the name of the class three times? So that it will be true, presumably.

Building these query objects can be a pain, though, if they get all complicated--which they do, always. I know one team that ended rolling its own library of query-building classes. Had a load of methods on them with names like "select" and "orderBy" and so forth...

Why do programmers put up with this? A lot of the time, habit. Which is to say, not thinking terribly hard about what it is they do that adds value.

To be fair, the modern RDBMS is a pretty amazing thing: high performance in time and space, robust, reliable, available...it's just that a lot of application programmers are a bit confused, I believe, about where the benefit of using an RDBMS lies.


If only an RDBMS were Realational

While it's true that what we have today in the widely used RDBMSs is a pale reflection of what the relational model is capable of, they are nevertheless closely related. So let's take a look at the ur-text of relational theory, Codd's paper of 1970 (back when "data base" was still two words). What's of interest about it is that it doesn't talk about persistence much at all. There is mention in passing that the data is "stored" in the "data bank" but the focus throughout is on the structure of the data, how that structure can be preserved in the face of updates to data and to what we would now call the schema, and how users of the data can be isolated from the details of how the data is held and changed.

Flowing from this are two principle advantages of using an RDBMS to store data:
  • ease of framing ad-hoc queries for decision support
  • robustness in the face of concurrent updates from multiple sources
That the data put into the database yesterday is still there today (even though the server was powered off overnight) is secondary. Immensely useful, but secondary. If we adopt a stance whereby we focus on the A, C, and I in ACID, and soft-pedal the D, some more interesting thinking becomes possible.


What if the data "never" changed?

If you are indeed in the business of business of writing anything like an enterprise app (and if you aren't, how come you read this far?), ask yourself this: how much of the code data source layer (or whatever you call it) of your stack could go away if the data it supplies to layers above it never changed? By "never", of course I mean "not during the lifetime of an application instance".

Now, the RDBMS crowd already distinguish between OLTP and OLAP, (and a very interesting debate that is, too--no really, it is) and the endpoint of moving in the OLAP direction is the data warehouse. And lot of regular RDBMS practice, predating the warehouse, allows for a highly optimised "read-only" route into the data involving a bunch of denormalized views and such. It's a failure mode to "denormalize for performance" even before the schema is built, never mind used for long enough to identify the frequent access patterns that will benefit from that denormalization, but when some user is going to need the same report updated time and again: go for it.


Data "corner shop"

Data warehouses are generally expected to be 1) gigantic, 2) concerned with transactional data that accumulates at a high rate (leading to 1) and 3) aimed at sophisticated reporting (the "analytical" bit of OLAP). The smaller volume, more task specific version is the ''data mart''.

Lets say that we are building a system where the data needed to satisfy the wants of an end-user changed over periods much longer that the duration of a user's typical interaction with the system. Why, then, would we worry about all that aSession.acquireUnitOfWork().readObject( blah blah blah stuff? We would have no need to do that for each user session. If the data changed slowly enough, there's be no need to do it for each instantiation of the (web) application itself. We can imagine the "transactions" getting consolidated in the warehouse (and condensed in the mart) might be things like "add a new item to the catalogue", or "change the price of this item". Happens on the timescale of days--or weeks. And furthermore, these changes might be known about, and actioned, some time in advance of being turned on for a particular application. But we have this idea avilable that access to the data that involves rapidly changing entities doens't have to go by the same route, or be maintained in the same way as that which changes slowly.

Phew! So, rolling all that together you can start to think about doing what the team who re-implemented SQL in Java whom I mentioned earlier did. Or, rather, what one of the more capable programmers did in his spare time because he was fed up with all that junk. Every now and again (say, once every 24 hours) run a bunch of queries (that's your data mart) over the data and pull out all the currently useful bits and write them to a file in one simple encoding or another. Then, when the application gets bounced, it reads that data and builds its in-memory object graph and uses that to serve user requests. Call out to the DB for really volatile stuff, but how much of that do you really, really have? Really?

Do this and I'll bet you find, as that team did when the databaseless version of their app was deployed, that it goes faster and scales better. Oh, and by isolating the application (in their case, completely) from a database they were able to very easily pull out a chunk of functionality to sell as a stand-alone application and/or plugin to other systems and enabled a whole new product line for their business. Nice.

This sort of decision should be the work of architects, but too often wouldn't even come up for disucssion as an option. Why is that?

(*) No approbation of the rather sinister ESR or his dubious schemes should be construed from this reference to the Jargon File