The Technical Meaning Of Microtest

i write things called “microtests” to do my development. doing this yields me greater success than i’ve had using any other technique in a 40-year career of geekery, so i advocate, wanting to share the technique far & wide.

before we can talk seriously about how or whether this works, we need a strong grasp of what a microtest is and does, from a strictly *technical* perspective, w/o all the trappings of the larger method and its attendant polemic.

a single microtest is a small fast chunk of code that we run, outside of our shipping source but depending on it, to confirm or deny simple statements about how that shipping source works, with a particular, but not exclusive, focus on the branching logic within it.

i want to draw your attention to several points embedded in that very long sentence. it’s easy for folks to let these points slide when they first approach the idea. that’s natural, we always bring our existing context with us when we approach a new idea, but if we underplay their significance, it’s easy to head down both theoretical and practical dead-ends.

Externality

first, we have microtest “externality”, the property that says the microtest code runs outside the shipping code.


this is a snap from a running app. the app’s called contentment, and when it runs it draws this diagram, interpolated over time, as if i were drawing it by hand.


this, on the other hand, is a snap from a microtest run against the contentment app:

why do they not resemble each other at all? because the app is the app and the microtests are the microtests. they are two entirely separate programs.

Source-Only Relationship

second, and this is a little buried, the connection between these two separate apps exists at the *source* level, not at runtime.

the microtest app does not launch the app and then poke it to see what happens. rather, *both* apps rely on some shared code at the source level. the app relies entirely on the shipping source. the microtests rely on the shipping source and the testing source.

this is very important to grasp very early on. in some testing schemes, our tests have a runtime connection to an instance of our app. they literally drive the app and look at the results.

this is not how microtests work. nearly every modern programming language comes with the ability to use a single source file in two different apps. microtest schemes make heavy reliance on this capability.

Branchy Focus

third, microtests focus primarily on branchy logic within the shipping source, with secondary attention to some numerical calculations, and sometimes a small interest in the interface points between the shipping source and the platform on which it runs.

here’s a file, SyncTest.

This is a microtest file that uses the shipping source’s Sync class.

the Sync object has just one job, to have its interpolate()  method called. if the beat is less than the sync’s target, return true (so that interpolate()  will be called again). otherwise return false (so the caller will stop asking).

the Sync object’s behavior *branches* logically. there are two branches, and there are two tests, one that selects for each case.  (this example is real, if against a rather straightforward responsibility. in the full context, tho, correctly syncing the drawing to the video or audio source is actually the whole *point* of the contentment app.)

microtests mostly focus on just this: places where *our* code changes its behavior, doing one thing in one call and another thing in another call. we also use them for testing calculations. contentment does a lot of coordinate math. the part of contentment that does geometry has lots of mostly non-branchy code & plenty of microtests to make sure it does its basic algebra & trig the way it’s supposed to.

sometimes, though not often, microtests will focus on the interface points between the shipping source and its platform. the contentment app uses javafx’s animation framework. there are a couple of classes that serve this functionality to the rest of the app. the microtests here essentially establish that this interface point works correctly.

a more common example out in the wild: a bit of SQL is richer than just ‘select * from table’, and we write some microtests to satisfy ourselves that that bit of SQL gives us the right response in a variety of data cases.

Active Confirmation

the fourth aspect of that long sentence above is caught in the phrase “confirm or deny simple statements”. microtests actively assert about what happens in the shipping source.

microtests don’t just run a piece of the shipping source and let the programmer notice whether or not the computer caught on fire. rather, they run that piece with a particular data context and (partially or fully) validate the results of the call.

in the SyncTest file above, the line that says

is calling the interpolate() AND checking that it answers false.

microtests are active, not passive.

Small and Fast

the fifth and final (for now) aspect of microtests is that they are small and fast.

a typical java microtest is well under 10 lines of code beginning to end. it runs in milliseconds. it tests only a single branch. it doesn’t usually assert everything about the results, but usually only one or two things about them.

the SyncTest above seems trivial, because Sync’s responsibility is, however critical to correct functioning of the app, trivial. *but*. the average microtest in contentment is five lines long, longest is 20, most of which is taken up by 12 lines of try/catch java noise.

Industrial Logic’s great app for serving online instructional material is a good case. its 1200 microtests eat under a minute.

These Are Microtests

so there we go. five important properties of microtests are 1) externality, 2) source-only relationship to app, 3) branchy focus, 4) active confirmation, and 5) small size and high speed.

if we’re talking about microtests, we’re talking about tests that have these properties.

there are many questions waiting in the wings from this starting point. among others, “why on earth would i do this?” and “how can i do this when my code doesn’t want me to?”

we can get there. but we can’t get there without remembering these properties.

TDD: Resist Integration Tests

the expense of an integration test can be extremely high. consider the contentment app. this app makes drawings 1) that  distribute across time, as if they were being drawn live in front of you, 2) that are generated stochastically, 3) with a “pixel-inaccessible” framework.

now, it’s important to understand that none of these problems are insurmountable. before you tell me how you’d surmount them, let me tell you how i could. 1) screw time. rig it so it draws as fast as possible and wait for the end to assert. 2) screw stocastic, rig your prng so that you control the number sequence. 3) screw pixel-inaccessible, treat the medium like h/w and put a tee in front of it, assert against the tee.

all eminently doable, at some expense. so should it be done?

i prattle on about the money premise, and i want to be sure you understand how it applies here. please do attend, as this is absolutely *central* to learning how to make TDD work for you.

the money premise says we’re in this to “ship more value faster”.

reminder: “value” could mean any number of things, including fewer bugs, better runtime, or more cases or features. all that matters about the definition of “value” for this purpose is that it is dependent on us changing even modestly complex logic in code.

suppose you surmounted the three difficulties above. what would you have to assert against at the end? depending on your technique for trapping the output, you’d have either an ASCII log with a bunch of labelled doubles in it, or a literal image snapshot. you could either eyeball a given run and say “that will do, don’t change this caught behavior,” which we call “bless”, or you could figure out approximate values for those doubles in advance and assert against them, which we call “predict”.

either way, you will have spent a great deal of money getting those assertions, yes? the three surmounted challenges are not cheap, and tho blessing is cheaper than predicting — we’re talking about a lot of data here — neither of those is very cheap either.

what do the literal assertions you write actually assert conceptually about the contentment app?

that, say, given a blank screen, a specific sequence from the prng, instructions to human-draw over time a line from one corner to the other, at the end there is indeed a line from approximately one corner to approximately the other.

wow. you haven’t proven very much. a real script involves dozens of such lines, as well as text. a real script uses a real prng. a real script is inherently stochastic beyond your control because it depends on the timing of the not-owned-by-you multi-threading in the rendering. (aside, not to mention the odds are good that your test is quite fragile, and will break when you change things in the code that do not actually matter to the user.) i could prove all the things you proved without any rig at all. i could write the script that does that and run it and look, in a fraction of the time, and know just as much as that automated integrated test tells me.

in order to get very high confidence that my code could be safely changed, i would need *thousands* of these extremely expensive tests, and thousands of hours of predicting or blessing work besides.

now, your app may not be graphical like mine, it may not be performing its main function distributed across time like mine, and it may not be stochastic like mine. or. well. maybe it *is* like mine. if you’re working database to browser in a huge sprawling database with thousands of users and hundreds of screens and complex workflow and the kind of bizarre business logic enterprise apps demand, maybe it is like mine.

writing an integration test for it would be investing a very great deal in proving a fraction of a fraction of a fraction of the program’s viability. selenium, a test server, the slow runtimes of the intranet, the golden master db, and most particularly the effectively infinite cyclomatic complexity of the app as seen entirely from the outside.

so?

don’t do that.

put simply, the money premise says that we do TDD because we want more value faster. integration tests in most complex apps do not provide more value faster. as a direct result, in TDD we write very few integration tests, and suggest them very rarely.

My TDD Isn’t Judging Your Responsibility

An old blog of mine, We’re In This For The Money, recently got some attention, delighting me, of course. A full h/t to Jim Speaker @jspeaker for that! He quoted me thus:


Too busy to #TDD?
Too busy to pair?
Too busy to #refactor?
Too busy to micro-test?

I call bullshit. My buddy Erik Meade calls it Stupid Busy, and I think that nails it pretty well. All you’re really saying is that you’re too busy to go faster.

~@GeePawHill


Most of the responses were RT’s and likes, both lending me fresh energy. A modest number of folks chatted with me, and that gives even more juice. (Readers please note: the sharers of these things you enjoy need to hear that you enjoy them, early and often. It is what gives us the will to share.)

I Believe What I Said…

Since that article, from 2014, I’ve reworked the ideas in it many times. I have developed theory to back it up, experiments by which someone can prove it to themselves, and a great deal of teaching material. I have written and spoken repeatedly on the topic of shipping more value faster. It’s part of almost everything I write about the modern software development synthesis. About the best recent statement, though I am still formulating new takes on it all the time, is in the video (w/transcript) Five Underplayed Premises Of TDD.

If you want to ship more value faster, you might want to consider TDD, as it will very likely help you do that, for nearly any definition of value you wish, provided only that the value involves writing logically branching code. I genuinely believe that the modern synthesis is really the fastest way to ship value that we have at this time.

…But I Don’t Agree With Everyone Who Believes What I Said

And yet. I can easily see how one might infer from that quote — even from that whole blog, or from other parts of my output — that I am suggesting that using the full modern synthesis is a responsibility for a professional developer.  Or to reverse the sense, that I am saying it is irresponsible to be a working programmer who works in another way.

Some who responded took me as saying that and opposed that idea, others took me as saying that and favored that idea. I’ve no idea what the RT’s and likes were inferring.

I am not saying that it is irresponsible of a working programmer to not do TDD et al, because I do not believe that.

Frankly, the idea gives me the willies. So I feel it’s incumbent on me to give you some detail about what I would actually say about this question of responsibility.

(Writers don’t get to decide what readers make of their ideas. You’ll take the money premise and all the rest of my output you decide to bother with, and you’ll make of it what you will. All the same, if can see how you might think I was saying that, and if I disagree strongly with that, I feel my own — normal, individual, human — sense of responsibility to do what I can to make my ideas more transparent.)

Near-Universal, Individual, And Fraught With Internal Conflict

Nearly everyone develops a sense of what they are obliged, by their own description of who and what they are, to do in this world. We normally call this the sense of responsibility. For most of us, the twin pillars of that sense are 1) our deep beliefs about what is morally right or wrong, 2) our deep connections in the many networks of humans in which we find community.

Those senses of responsibility are rich, vague, staggeringly complex, and full of outliers, odd twists, preferences, and, when put in to language,  startling contradictions.

Above all, they are individual. There are aggregate and statistical trends, of course, and if one could find an N-dimensional space big enough to hold the variables, one would see bell-curve like manifolds all through it. I have a sense of responsibility, and the odds are overwhelming that you do, too. Our respective responsibility-senses may appear to be similar, even highly similar. But they are not. It only appears that way because of the limits of language and the locality of the context we use to frame them. Our responsibility-senses are different because we are different.

If you read widely, you will have seen hundreds, maybe thousands, of situations in which one responsibility a person senses is pitted against another responsibility that same person senses. If you don’t read at all but you are old and thoughtful enough to seriously review your past, you will also have seen hundreds, maybe thousands, of situations like this in your own personal history, and that of others you know well.

Cutting To The Chase

Boy oh boy was I ever about to sprawl out and produce a nine-volume treatise on ethics and responsibility. From my simple dog-like goodness, I will spare us all. Instead, I will sum up my beliefs:

  • that the modern synthesis is the best current way we have of shipping more value faster, whenever that value depends on logically branching code with lifetime longer than half a day.
  • that I don’t honor my own sense of responsibility at all times, because I am weak or foolish, or because I carry conflicting senses simultaneously.
  • that it is not for me to say what is responsible or irresponsible — global words — about any local context involving people who are strangers to me.
  • that “doing your job well” is very often not dependent on shipping more value faster.
  • that “doing your job well” can mean many things that are not good for you or the company you work for.
  • that “doing your job well” is in any case not particularly more important to me than any number of other responsibilities I carry.

If you are a working programmer, you are a grown-up.

You are in the difficult position of balancing dozens of competing needs, using only your heart and body and mind, and I am well aware that this is a task far more demanding in real life than it seems, on paper, in a blog, or spoken by an idol. I won’t do that for you because I can’t do that for you. I only sometimes manage to do it for me.

In One (Long) Sentence

Please don’t take me, even in a crabby mood, as someone who assesses your sense of responsibility, commitment, or heaven forbid, morality, on the basis of whether or not you do TDD or any other part of the modern synthesis in your job.

 

Use Supplier, Supplied, Or Both?

a coding pattern; replace supplied data with a supplier or a supplier with the supplied data.

it is very common to create code with an interface like this: do( Data supplied ) . we then use the data somehow to perform our functionality, whatever a do(…) method does.

on the other hand, sometimes we create code with an interface like this: do( DataSource supplier ) , and its body is basically the same as our starting chunk, but with a prolog that asks the DataSource for the Data and *then* performs whatever do(…) does.

so when we sketch a new function, we always have to mull over which of these two is the right thing to do. and when we refactor, similarly, we have to wonder which of these two ways to go. there is not a “right” choice you should always make. sometimes the supplied is the way to go, sometimes the supplier. but there *is* a right thing you should do, and that is to pay attention to the decision, as it has a variety of potential consequences.

here are some notions to mull over that might help you make your decision.

first, consider that you can do both. you can write  do( Data supplied )  and do( DataSource supplier ) . i’ve assumed overloading, but you don’t need it, just change one of the names.) just have the supplier version contain the prologue we discussed and chain into the supplied version. note: please chain. don’t just copy the body of one into the other. doing that is purposefully injecting anti-change in to your codebase.

second, if you don’t do both, make sure that whichever one you do is the least awkward collaboration for you to test with. remember “awkwardness”? this is any property of a collaboration that makes it annoying for us to test whatever branching logic do(…) performs.

in java, for instance, streams can come from anywhere including files, but files can *only* come from a drive. if i have to write and maintain a bunch of files “somewhere else” to do my testing, well, that’s awkward. and when we have awkward tests, we don’t write/run/debug them.

third, regardless of picking one or both, is the object you’re passing in far fatter in interface than what do(…) needs to do its work? you might want to wonder if you need an intermediate object, one that is neither the supplier nor the supply, quite, but is a thin wrapper.

the business of passing around obese interfaces is extremely common in “it rubs the database on its browser” code, it dramatically increases the mental scope required to grasp and change the method. a typical case: passing a database connection (and an account id) when do(…) really just needs an account’s zipcode. you do understand that your database connection aims at a turing complete system, yes? it can do *anything* a computer can do. this issue isn’t just limited to the supplier choice. we do the same thing with supplied’s. again, you just want the zipcode. an account, whether databased or in RAM, has *dozens* of fields and operations.

you might think introducing an intermediate object is dumb, because even tho you *could* perform any of an account’s operations, you’re only really going to ask for zipcode, so why go to the trouble?

(ahhhhhh. here we strike at the very heart of the strictly technical aspects of the modern software development synthesis. change-enabling code is nearly always more valuable than shipping the next change. so begins another muse.)

the short answer is still twofold.

  1. cuz code that only gets the zipcode *must* be dead simple, and dead simple makes us go faster.
  2. when we realize we also need a) a state and b) a method to validate that they’re correct, we have a ready place to put it.

so. when you sketch a method or approach refactoring that method, consider your choices around passing supplier vs supplied vs both. consider both, consider awkwardness, consider interface width. there’s no right answer every time, but it’s almost always worth taking a minute and mulling it over.

go geek out, then.

Methods Don’t Create Health

maybe the real first wrong was the slide into “method” in the first place.

have you ever known yourself to behave in a way that is generally perceived as neutral or even positive, but in a way that is actually doing you or others harm?

Depressive Solitaire

my work makes me think a lot. and i quite often do that thinking on a low boil in the background, as i’m doing something else, most often for me playing a game. a lot of folks do this with solitaire, for instance. there is nothing wrong with solitaire, and there is a lot right with letting your mind work on something by looking away from that something. playing solitaire, or taking a walk, or what-have-you, generally neutral or even positive.

but every time i play a game, i am not thinking. sometimes i’m just playing my game and enjoying it. other times i’m doing something else altogether, something “not good”. the “not good” thing i’ve been known to do is just sit there neither enjoying the game nor doing background development, but rather, just completely shutting down while i go through the motions.

a certain amount of that seems unavoidable, for me and for us. after all, humans do background development work that isn’t detectable by us, and we don’t always know what’s going on. and sometimes shutting things down is the only healthy response, too. over-stimulation isn’t good for one, either.

but — i was a practicing hardcore depressive for over 30 years — when i am shutting it all down, it’s very often a warning sign. and if i shut it down for days and days and days, it’s way more than that. in my case, and i know i’m not alone, it’s life-threatening.

What Makes Some Processes Depressive?

what does that have to do with my opening salvo?

these cases: “just playing”, “background processing”, “healthy withdrawal”, and “depressive/OCD”. what makes one different from the other?

what makes one different from the other is the human. that is, me. it’s inside me. it is somewhat visible to me, a little visible to those who know my patterns well, and virtually invisible to outsiders, or at least invisible until dangerously late in the game.

i’m hoping you’re still with me, that you can relate to some or all of that long digression, because now i want to jump back to the question of method.

Back To The Method

have you even seen a happy team doing method X, for values of X like Scrum or XP or DaD or Prince or SaFe or — good lord, we don’t have enough characters for all of these brands?

i have. most definitely.

pick that X where you’ve seen happy healthy productive teams. i’ll just pick Scrum, since it’s so widespread and familiar to many of you. but you pick one where *you’ve* seen the good stuff.

now have you ever seen an unhealthy unhappy unproductive team doing that same method X?

i have. most definitely.

so what was the difference, between the rockin’ team and the despairin’ one? it wasn’t their method. (btw, if you’ve been around the block enough, you’ll be able to apply this to nearly any technique, whether it’s bundled into a brandname or not. i have seen test-first teams that were in great pain, for instance.)

well. what was different was the people. just as what is different from the neutral or positive game-playing and the depressive game-playing was the person. and when i say “the people,” i don’t mean the particular combo of individuals. that is, in the game-playing, the healthy and the unhealthy are both being carried out by the same me. (by the same token, i worked with that TDD-in-pain team for a while, and we turned TDD back into a lovely healthy thing for them. same people.)

same people, different state.

different state can be variously translated: different spirit, or mood, or culture, or any number of other words. suffice to say i am talking about things that are vague and inchoate but still real, internal to the team and internal to the members of the team. (i have seen many teams depressed to the point of life-threatening. it is a normal part of my work.)

Process Can’t Create Health

and here’s my point — long awaited even by me, and i’m the one doing the typing here — process, structure, method, technique, can inhibit health or it can permit health, but it can’t *create* health.

what we were after 20 years ago was health. the structures, methods, techniques all around us were actively inhibiting that health, so we sought another way.

now, that way we sought, don’t mistake me here, involved structure & method & technique, no question about it. partly because we’re geeks and we groove on that kind of shit. partly because the old stuff would not make way if we didn’t offer some new stuff.

Abandon “Process Creates Health”

the first of the four points of the agile manifesto says we value people over process. for “process”, read structure, method, technique.

when i play my game depressively, i am honoring process over people. when a team scrums depressively, or dads or safes or xps or tdds depressively, they are valuing process over people.

no part of this movement’s origin was based in the idea that “process creates health”. but everywhere we look, there are people claiming that it does and wearing our colors.

i wish to disassociate our movement with that idea that process creates health.

if you’re an “agilist”, of any stripe, please help me do this.

Coaching: How I Get Them To Do What I Want

a little more on coaching theory today…

folks ask me a lot of questions whose fundamental focus could be expressed as “how do you get them to do what you want them to do?”

so. here goes. i hereby reveal my entire competitive advantage as a professional coach, by telling you my special secret for how i get them to do what i want them to do.

i don’t. i don’t get them to do what i want them to do. i get them to do what they want to do themselves.

that sounds weird, maybe a little zen-like, i spoze. “what is the sound of the one hand getting them to do what it wants them to do?” but i don’t really mean anything very mystical by it. it connects back to the always-small-always-improve thing we’ve talked about before.

a common way to express these problems is to talk about horses and water, “you can lead a horse to water but you can’t make him drink.” (tickled memory: the algonquin round table wits use to play “use this word in a sentence” as one of their punning games. i think it was dorothy parker who used “horticulture” in a sentence this way. “You can lead a horticulture, but you can’t make her think.”)

here’s the thing about horses and water. horses *like* water. they drink it all the time. they drink it because they’re thirsty, and because it tastes or smells good, because it cools them, and it heals them, and prolly other reasons i don’t even know. when a horse *doesn’t* drink water, what does that mean? well, it could mean a bunch of things, some pretty scary, but i could collapse those into one vague hand-wave: it isn’t drinking this water just now because it does not want this water just now.

well, if i only get horses to drink when they want to, how do i even do my job at all? i mean, the whole point of getting hired to be a coach is to get horses to drink the software development modern synthesis water.

i do my job by hanging around and/or pitching in, with really good water right in my hands in just the right portions with just the right flavor. when the people i’m with are thirsty, i give them water.

and the more i manage to pull this off, the more they come to expect me to be the kinda person who gives out good water. some of them come very quickly not only to enjoy my water but to want to know where i keep getting it from, so they can get it when i’m *not* standing around.

as water-bearer’s, software development coaches *do* have certain advantages.

  • first, the water these folks have right now is insufficient or gross-tasting or both. i do know folks who work w/high-functioning teams in environments that crackle with energy & hope and embrace both learning & change with vigor. but that’s actually pretty rare in the trade.
  • second, we are usually invited in for the express purpose of coaching. they don’t know how to do it themselves, someone thinks it needs doing, and they ask us to come help.
    note: not *everyone* in an org thinks it needs doing. 🙂 but usually the someone who hires me packs some weight, and my victims have the general idea that they’re supposed to attend to me a little. as it happens, i turn out to not be just another boss-y guy, and i turn out to be occasionally useful, so i get the *good* part of being hired by a heavy without the *bad* part. by and large.
  • third, as coaches we are not responsible for all the things these teams are held responsible for, which gives us lots of time to work on preparing water and watching for thirst.
  • fourth, we generally have far broader experience in water-procurement than our teams do. i know a lot of ways to get water. i know a lot of different ways to flavor water. i know a lot of kinds of thirsty.

so, let’s back away from this water metaphor thing for a minute.

advice: develop a catalog of “better-than-this” changes. the job is not to install the one best way to make software. (there is no one best way, but that’s for another day.) the job is to make things *better*. and even a little better is better.

advice: focus in the beginning on small owwies that they agree are owwies. it’s both doing your job, making things better, and it’s generating “capital” you can use later for larger owwies or owwies they don’t yet know they have.

advice: *collaborate* *with* *them*. “coach” is not a synonym for “boss” or “teacher” or even “expert”. work on your collaboration skills more than any other thing.

advice: be kind to the victims and kind to yourself. forgive both parties as often as you can. neither you nor they can always be open, strong, decent, right, or fast. in the AA rooms, we say, “time takes time”. patience is one of your most important resources.

advice: look out especially for the times when they want to do something you also want them to do, and be ready with a small concrete step that will pay them back quickly.

anyway, that’s what i got. how do i get them to do what i want them to do? i don’t. i get them to do what they want to do.

How To Test Depends On What To Test: Money, Chaining, and Steering

to have a serious conversation about *how* to test, we have to start by considering *what* to test. as a microtesting TDD’er, what i want to test is *our* *logic*.

the money premise of TDD reminds us we’re in this for the money, that is, the primary purpose of TDD is to enable us to ship more value faster.

deciding what is “value” is not a TDD task. the larger agility certainly asks us to make hard choices about value, but by the time we TDD those (always temporary & dynamic) decisions have already been made.

what i am saying is bold, and it will not surprise me if it surprises you, even if you already are a TDD advocate.

i am saying that there is no “change this code in a way that requires branching” task with scope bigger than half a day — in its entirety, in perpetuity — that we won’t do faster using microtested TDD, assuming you a) know how and b) have the TDD tool at the beginning. it absolutely does not matter *why* you or your team or your org has decided you need to change code in a way that involves branching. that matters to you, your team, or your org. it doesn’t matter to the assertion i am making.

more features? TDD can do that faster. fewer bugs? TDD can do that faster. get this thing to alpha so we can see if anyone’s dumb enough to buy it? TDD can do that faster. see if complex variant X is performant? TDD can do that faster.

it’s not because TDD is the end-all and be-all of ll possible situations. it’s because TDD is the fastest current known technique for changing code in a branchful way, and all of those depend on changing code in a branchful way.

i reiterate: i am assuming a) you know how to do it, b) you have your rig ready to go at the start. those certainly aren’t valid assumptions to make everywhere all the time. but why would you bother learning or setting up if you weren’t gonna get a payoff?

the payoff — i *have* theory galore, but i am not coming from theory here but from practice as a hardcore working geek — is that *any* code changing that requires even modest logic goes faster with TDD. we don’t care about what/why the value is in this code-changing context. we only care that it’s code-changing in a situation that requires us to combine logic.

another way to say this: i am interested in TDD’ing any code we wrote that has a local mccabe complexity > 1. if you don’t know what mccabe complexity is, there’s a thing called google, but the short phrase is “number of possible paths through the code”.

many of us start a new language by learning how to print “hello world” to the screen. if it’s a console program, that’s a one-liner. in its entirety, it calls a library that is built in to your programming language. it has a local mccabe complexity of 1. there’s only one path through it. no branching, no logic, no nothing. it is basically an exercise in typing. i do not wish to test it.

wait. that’s not right. it’s not that i do not wish to test it. it’s that it’s cheaper for me to run the program and see if it says “hello world” using a device i call “my eyes” than it is to write a test, even if i know how to test & i have a rig. and because it has no branches and depends entirely on the system library in nearly every respect, i am happy to use my eyes one time and walk away.

(aside: occasionally we confront situations where *transitive* mccabe complexity becomes important. those situations inevitably involve mutable state, which is one reason we don’t like mutable state.)

now i will run out of steam here in just a minute. but i want to complicate this picture a very tiny amount, and in so doing, we’ll move from just the money premise to the money premise plus the chain premise plus the steering premise. spoze i sometimes want to print “hello world” and sometimes want to print “hi mom!”. i have to *branch*. i have a condition — let’s say i have another library call coin(), like print, that returns heads or tails.

the first thing you note, the mccabe has gone to two. there are now two paths through the code. second thing you note, we have *our* *logic* in the game now.

it is at this point that you realize you haven’t the slightest ability to easily capture the output of those print statements. (you have encountered, in fact, your first awkward collaboration.) enter the chain premise. we stop testing the *app* and test a part of the app. we don’t really want to test print or coin at all. we know they work. (if they don’t work, we have bigger problems.)

we want to test our logic. we want to be sure we do the right thing on heads and the right thing on tails. so what if we just test our logic, and not test the whole thing? uhmmmm, nothing. we got nothing. the fact of the matter is that those damned print statements are in there screwing up our ability to test just our logic.

enter the steering premise. what if those print statements were *not* intertwined with our logic that we want to test? then we could use the chain premise to test just *our* *logic*, and to hell with testing a system library call.

the only way to do that is to change our code. rearrange it so we first decide what to print — our logic — and then print it, a thing we trust works and can eyeball cheaply.

to test that logic separately we need it separate, in a function.

the tests we write are two, one for each local mccabe path through greeting.

we have *steered* our design. we took into account what we wanted to test — *our* *logic* — and we changed our code so that we could test it easily.

we started by considering what to microtest. we want to test *our* *logic*. we don’t want to test the app. we don’t want to test the library. we want to test the parts where we write code that branches, and we want to do it cheaply enough that it makes us ship value faster.

the money premise reminds us this is more value faster. the chain premise tells us to test parts rather than the whole. the steering premise tells us to change our code to make that possible. there are other problems. and we have answers for them, too. but to start TDD, start there. you will go a very long way. money, chain, steering.

Avoid Implementation Inheritance: GeePaw Goes All Code-y

so, day off before travel before onsite, playing ONI, having fun, but i want to muse about a highly geeky matter anyway…

do you ever override in a sub-class a method that’s already implemented in a super-class? i want to recommend to you a policy of avoiding that like the plague, whenever you can.

i will go further: i avoid, maybe not as much as the plague, but surely as much as the measles, even deriving any sub-class off of any super that has any implementations at all. (anything not a “pure virtual base class” in c++, “interface” in java. in languages that have no such concept, any super-class that has an implementation other than “throw new ForgotToOverride”.)

i came to this philosophy very slowly over an embarrassingly large number of years. i say “embarrassingly” because, nearly as soon as i came to it, it made itself clear almost immediately how much better/stronger/faster/kinder my resulting designs are. i came up through the OO revolution, you see, and i’m a confident and capable OO geek, surrounded by this thing, i’ll call it “implementation inheritance”. it was the air i breathed.

when i started TDD, i had an enormous amount to learn just in first the basics and then the intermediates. it took some time. as it progressed, i learned about a kind of meta-pattern i’d been engaging in for years & years. it’s a hard one to see, this meta-pattern, and that’s what took me so damned long. it’s trading the major value of getting what i’ve elsewhere called “rigorous” results for a variety of lesser values that essentially amounted to local convenience.

or, maybe, that’s not quite right.

let’s try another take: i was trading to get a kind of local appearance of convenience, and in so doing giving up an actual *global* improvement in my ability to ship more value faster.

and the worst part of it was, i wasn’t even getting that much local feeling of convenience. just a little. and i was giving up a *lot* of global value-shipping speed. and this wasn’t just one feature of my coding technique, i was doing it all over the place in myriad ways. TDD slowly helped me find those ways and choke them down, one by one. i will never not think of it fondly for doing that. one of the things i was doing, tho, was being what i thought was a facile and even gifted — i get perky at times — object-oriented programmer. i used implementation inheritance heavily.

the benefit of implementation inheritance is dreadfully obvious: it’s the fastest possible way in a statically typed language to re-use code you or someone else already wrote. and if you’re good at it, i was, you could carry it around with you all over the place, like an overloaded saddle-bag draped around your neck, and never even notice it, except occasionally if you needed to feel good about yourself.

TDD — as always i mean by this “the modern software development synthesis” broke me of a lot of “good programming practice” habits that were not in fact good programming practice, but it took me a really long time to get past this one. i was already pretty much a TDD master before i finally set it aside.

why set implementation inheritance aside?

  1. you almost never need it. that is, anything you can do with it and a modern optimizing compiler you can do just as well without it. the sole exception i’ve found is in some obscure performance situations that, trust me, neither you nor i are likely to find outselves in.
  2. it complicates in a particular way: you see, implementation inheritance impedes quite sharply what i regard as the central skill or discipline of being able to ship more value faster, the management of mental scope. every implementation inheritance — every single one — creates a hole in the little conceptual box of “the code right in front of me”. and it does it implicitly, almost invisibly. it is a guaranteed violation of “locality of reference”, the ability to see what you need right when you need to see it.

how did TDD help me finally see this? TDD helped me to see that implementation inheritance was undesirable because it made me *think*, *more*, about stuff that wasn’t *there*. well. mama dint raise no thinkers. thinking more about stuff that’s not in front of me is exactly the opposite of managing mental scope. when i have to TDD implementation inherited classes, tho, that’s exactly what i have to do. and the thing is? half of that thinking has almost no relevance to the current value i’m trying to ship faster.

maybe you’ve never seen hardcore implementation inheritance. i see it all the time, particularly in older larger codebases dominated by a so-called “senior architect” who memorized the GOF book in ’95 and hasn’t shipped value in the last 20 years.

but if you’re wondering, here: this chart — part 1 of 3 — is illustrative. almost none of those boxes is an interface. at the bottom of that dependency tree there are leaf nodes that have upwards of seven or ten *implementing* super-classes. every one of them with dozens of methods, every one a partial override of its super.

we don’t ship more value faster by juggling more balls, but by juggling fewer. implementation inheritance always adds balls to what you have to juggle in your head while you’re working.

so let it go. if you’re having trouble seeing a new design without it, come find me, or any of dozens of serious TDD’ers out there. we *like* solving design problems. we do it the way people work crosswords in the sunday times. ask us, you’ll see.

Coaching? Like People!

Hey, there, it’s GeePaw! And you are watching the first ever GeePaw video aimed specifically at coaches. I hope you like it.

Do you know what the first absolute prerequisite for being a successful software development coach is? You have to like people.

You have to like people. You have to like their style. You have to like their resistance. You have to like when they do the thing you want them to do. You have to like when they don’t do the thing that you want them to do. You have to like people.

We get into this business because we’re very hot on a system, or a method, or a technique, or a something, and we want to share it with everybody.

But it’s really easy to get caught up, caught up in the system, caught up in the method, caught up in whatever flame war is running around the building today. It’s important to remember, though, the secret requirement for all successful coaching enterprise, is to like people.

What I’m Not Saying

Now, before we get very far, we have to address a couple of things I’m not talking about. I am not suggesting that you have to be an extrovert, a person who gains energy rather than losing it by being around other people. You don’t have to be an extrovert.

And I’m not suggesting that you have to be some sort of rainbow-farting unicorn floating up in a blue sky with just enough fluffy clouds in it to prove to you that, truly, every day is a beautiful day.

You don’t have to be either of those two things. I’m not either of those two things, not even by a stretch. But I like people. I like how they think. I like what they smile about and what they cry about. I just like people. What can I tell you?

And if you’re going to be a successful coach, you have to do that, too. Now, listen, I’m a pro. And I always find something nice to say about every team that I work with, because it’s a perfectly ordinary and healthy part of the job. I admit, sometimes, it’s a really big stretch. Gosh, you know, you guys just have the best shoes of any team I’ve ever worked with.

But truthfully, I like people.

I like knowing how so-and-so met her significant other. I like knowing why so-and-so became a geek. I like knowing what happened at the house last night over dinner that was funny? I like knowing that my friend buys tons and tons of video games but never ever has time to play any of them. All of those things, I like about people.

I like people because we’re so messed up and we try so hard.

That’s my secret to liking people. That’s what led me to like them so much.

We’re so broken. I’m broken. You’re broken. Everybody around you is broken. And yet, we’re all trying so hard to be who we want to be, to do the right thing, to be kind, and strong, and fast, and smart.

And that is what let’s me like people so much.

Play More Favorites

Let me ask you something. Do you ever play favorites? Are you ever a little warmer to somebody else because they’re one of your favorites, a little more tolerant of them, a little more cheerful around them, happy to see them, happy to listen to them, happy to talk about things that don’t have anything at all to do with work?

So do you play favorites?

Good.

Keep it up. Play more favorites. Pick more favorites to become your favorites.

Remember The Last Time?

Do you remember how it felt when you were listened to, when you were asked, when you got help from somebody else, or you gave help to somebody else, when you were regarded kindly by someone?

Do you remember how powerful you felt, how much stronger, how much more whole, how much more hopeful about what was coming in front of you, and about the possibility of you actually pulling it off?

So. Dig it.

Do more of that.

I’m GeePaw, and I’m done.

Coaches: Whence Confidence?

coaches, we all know that confidence is key, yes? it’s not the only key, but it’s key, especially in the beginning.

people look to you for ideas, then. and they’re lookinig to you for a number of reasons, but one of those reasons is because they think you’ll have some. and early on, there’s very little reason for them to think that. they don’t know you, they are guessing. and that perceived confidence in them is matched by an internal confidence in you. it takes a lot of nerve to stand up on your hind legs and offer an idea to a group you don’t know well.

so where’s that confidence come from?

well, you could just know all the things. if you knew all the things, you’d always be right and could always be confident as a result. you could also just pretend to know all the things, of course. that’ll help with their sense of your confidence, but it won’t help all that much with yours. i know some of the things pretty well, and some of the things kinda, and a whole lot of the things not very much at all.

where’s my confidence come from?

one place it comes from is my past successes and failures, which are plentiful. both have lent me a great deal of confidence.

  • successes in the past give me a little confidence because they were successes, but they also lend confidence at a higher level because, frankly, they amounted to very little in the grand scheme of things. they are relatively unimportant.
  • and failures might seem to subtract confidence, which they do, but again, in the grand scheme of things, they just don’t matter that much. i’ve failed more than i’ve succeeded, and i’m still here. still hungry. still beloved by some. still at it.

it’s strange to say that my confidence comes in part from the relative insignificance of my choices. but strange doesn’t make it untrue.

another place my confidence is rooted is in my extreme capacity for doubt. again, rather strange. but i gain tremendous strength from knowing in advance most of what’s wrong with my ideas. by the time my idea gets out, it’s already been hit and hit hard by my very own doubt-magic. to a remarkable extent, i already know what’s wrong with it or what might be wrong with it. this means i’m very rarely surprised or troubled when others critique it.

i also get my confidence from two kinds of “meta-“. essentially, the confidence is inherited from my process. it’s not that i have so much confidence in the value of my idea as that i have so much confidence in the value of my idea-valuation process.

i call the first meta- “do to know”. once i get an idea past a rudimentary scratch & sniff test, once i establish that it’s not definitely wrong or evil. i turn my attention to splitting it into steps that attempt to reap partial value from it. i do one of those steps, and i get to see if i got the partial value i was hoping for. i am doing the thing — in steps — to know whether it is valuable or not to do the thing. “do to know”.

the second meta- ? i have nearly complete confidence that the people i share my ideas with will take the idea, lose the fat, and cash in on the protein with tremendous vigor and enthusiasm. this gives me confidence because i don’t have to be that smart. even if i’m the smartest person in the room, *we* are smarter than *i* am, if we’re just given the chance to be.

as long as my process gives us the chance to be, we’re as good to go as we’re gonna get. “as we’re gonna get” is an important clause. i’m not saying our ideas always work, or that even if they work they’re the best. i’m saying, we live in the heideggerian “thrown”, and inaction is an action, and being right in advance just is not within our reach.

we have no choice but to share ideas and try the ones that aren’t definitely wrong or evil.

so that’s where i get my confidence. it comes from insignificance, doubt, do-to-know, and community. it doesn’t always work, because nothing always works. but it works often enough.

where do *you* get *your* confidence?