Cultivate vs. Control

Would you rather cultivate good code or try to force good code to happen through control? Control like RACI matrices, tracking bug metrics, code review processes, gated check-ins, gated deploys, style guides, and code freezes?

The answer isn’t simple.

‘Cultivate’ sounds wishy-washy, and it certainly doesn’t sound like something you could take to the VPE or the CTO (and if you’re the CTO, you probably wouldn’t be caught dead saying “cultivate” to the CEO or a board member), but if you start to say RACI, bug metrics, gated check-ins, and change-control management to line developers, there’s a chance they’ll either enthuastically support the idea or internally cringe.

I count myself in the ‘internally cringe’ group; not because I believe those activities are without value (they do have value, even if it’s to manage up other humans that don’t understand Software development), but because those activities don’t make software any better. At best they’re a mechanism to not make things any worse. You can’t get defect free software from those processes, nor can you deliver features faster with them.

If the goal is to deliver better software, faster — or as I like to think of it, doubling your team’s productivity (word wonks: I call it ‘productivity’ when I really mean effectiveness. Marketing is hard), then you already know the truth: gated checkins, change control management, bug tracking metrics and RACI matrices will only stem the tide of disasterous changes; they won’t advance the goal of delivering better software, faster.

Cultivation, as wishy-washy as it sounds, has a role to play here. Software is created by humans, humans that don’t always understand what you’re telling them, or humans that would much rather be surfing the internet than working on a problem (mostly because there’s something about the problem they don’t yet understand), or humans that thought they understood that you said you wanted a tire swing but saw it as an opportunity to build you a treehouse.

the documentation panel absolutely stings

These humans need to have a few things to produce better software, faster:

  1. An understanding of the requirements(!)
  2. The ease to make a change. Making additions and changes to a system should be easy.
  3. The ability to easily communicate the change and its effect on the larger system easily demonstrated
  4. Eliminating the bus factor when changing or adding to an existing system.

Which of those ‘control’ mechanisms provide these outcomes? None. Not because they aren’t valuable, but because these are all decisions that are made in the code itself.

That’s why Test Driven Development is central to producing better software faster, that’s why I believe that every project team should adopt it, and that’s why I care about this so much. By using TDD to cultivate practices, we can deliver better software, faster. With TDD:

  1. requirements are documented in the code and their tests*
  2. Making a change is easy; the logic is de-coupled (for non-programmers, think of it this way: You don’t have to clean out your attic every single time you want to get something out of a box)
  3. By running the test suite, you already know whether or not the change will cause any existing tests to fail — and these tests are fast enough that the problem is detected before code is pushed
  4. A system specified by tests needs two things to eliminate its bus factor: 1) readable tests, and descriptive, domain-centric names.

To bring it all together, I’ll leave you with a quote from (again) my favorite anecdotist, Josh Heyer (aka shog9) (though he wasn’t referring to TDD):

Some problems aren’t solvable so much as manageable. You don’t eliminate weeds, you just cultivate; you don’t eliminate spam, you just keep it from taking over.

Software systems are a lot like that; you cultivate good practices through an easily repeatable system of small steps, and you use the continual positive reinforcement of passing tests to drive habits. If you do that enough, you’ll have cultivated the ability to deliver better software, faster.

Is your team starting a new project in the next year? If so, now is a good time to determine whether or not learning Test Driven Development is right for your team and your situation. Send me an email and let’s chat about whether in-person training and advising will help your team’s next project become a success.

Good Idea, Bad Idea

If you’re a fan of 90s kids shows, you probably remember the Animaniacs. To say it was a kids show is probably a mis-classification because its jokes had layers; and a fair amount of political humor subtly placed strategically throughout. Anyway, one of the the recurring segments was “Good Idea, Bad Idea”. The one I remember went something like this:

Good idea: Playing Catch with Grandpa (picture two kids throwing a ball with grandpa)

Bad Idea: Playing catch with Grandpa (picture two kids tossing Grandpa back and forth).

(source)

The subtlety in the joke comes from taking the same sentence and interpreting it two vastly different ways. We see the same thing with Test Driven Development and its somewhat malignant little cousin: unit testing.

TDD practitioners will often have codebases that achieve close to 100% test coverage.

Developers that write unit tests will try to achieve 100% code coverage; believing the code coverage number is why software is able to be delivered faster and with fewer defects.

But, much like tossing grandpa, it’s a horrendously bad idea to strive for 100% test coverage and an even worse idea to try to do so through unit tests (as opposed to TDD).

One reason for this is that better than 90% of the libraries out there were not developed with Test Driven Development. They may have unit tests, they may have certain sections that were developed through TDD, but it did not become a part of the core identity of the system.

Because of this, you need tortured hacks to test certain libraries, and these tests themselves are a smell that’s something off.

In the above linked example; the poster does something that I’ve done and seen other developers advocate for in the past — it’s a mistake we all make at least once, but it’s a mistake that hurts our ability to deliver better software, faster. The mistake is to try to bend a non-testable class to the idea that everything should be unit tested, and therefore the hacks are necessary to meet that goal.

here’s a few ways the above test and code could go wrong:

  1. It doesn’t actually test what the OP wants, which is some guarantee that the third party code will do the right thing under certain conditions.
  2. Rather, it tests the structure of the code and is brittle to library changes.
  3. The OP wants to test, in isolation, the idea of broadcasting push notifications; but that is an activity that is meant to be E2E tested. No one cares that a push notification was sent, they care that it was received. Testing sending is like checking that your backups work without actually trying to restore the data. It’s the restoration that’s the important part, not the backing up.

In this case, I would have forgone the unit test entirely; and ensured my code was created through Test Driven Development; and would have inserted scar tissue between my code and this library; to ensure the system remains resilient, even if the structure of the library changes. I would have set up dummy accounts for E2E or integration tests (depending on which was more valuable in the medium term), and solely tested this library through black-box testing like an end to end or an integration test.

I’m beginning to open up availability for the spring for training and advising .NET software project teams on how to adopt Test Driven Development. If your team is going to be starting a new project in the next year, hit reply and drop me a line and let’s chat to see if an in-person course on Test Driven Development is right for your team.

My course on Test Driven Development for .NET software project teams goes deeper into this approach and is meant to capture these same sorts of real-world problems developers run into when adopting Test Driven Development. To sign up to receive course updates, and to get a subscriber’s only discount that isn’t available any other way, go to course.doubleyourproductivity.io and fill out the subscription form.

Snipes and Tykes

When my 6-year old daughter was three, she was at Kettler (where the Washington Capitals practice) and saw them practicing. She turned to my wife and said, “Mommy, are those Hockey boooooyyyyyyyssssss?” My wife said, “No, they’re Hockey Men.

She was smitten, not with the Hockey boys, but with Hockey (I refuse to admit she was smitten with the Hockey boys). We started her on Hockey Skate lessons at Kettler the following year, when she brought it up again.

If you’ve ever watched hockey players skate, there’s a lot going on there. The class taught her to fall properly, to cross her feet the right way, to get up from ice quickly, to stop, to go, and to generally get used to hockey skates.

She hated it, she felt like it went too slow.

So she stopped wanting to go.

We shifted strategies, and next season took her to a local Ice rink that taught a “Snipes and tykes” program, which was a different way of learning: They would teach the basics of Hockey and skating, but in a play based atmosphere, with less time spent on the mechanics themselves than on those mechanics + real world fun situations for 4-8 year olds.

She liked this approach better, and suddenly wanted to do more hockey lessons. but, and this is crucial, she’s probably missing some of the mechanics that would make her successful in actually skating and playing hockey.

That’s ok, because she’s six, and she’s got time to learn.

As programmers, school tried to teach us the former approach; and bootcamps and our professional work emphasizes the latter, and we start to eschew those basics, those mechanics that we actually need but are boring. Somehow, TDD got swept up in all of that, and became one of those boring things, a lot like learning how to fall while hockey skating. It’s important, and it’ll help you when you least expect it, but do you really want to spend time practicing it?

Learning TDD is a bit like going back to the basics; but if you’ve spent time programming, you’ll be able to see how modifying those basics just a bit and combining those practices with necessary mechanics makes it easier to produce better software, faster.

It feels boring, which is why it’s been ignored for so long, but it’s useful and when you dive into it in the context of a real-world project, some of the mechanics come alive, and that’s where TDD gets fun.

Not as fun as watching the Capitals practice, but close.

If you’re interested in diving deeper into how TDD can help you deliver software faster, with fewer bugs and a more stable delivery cadence, sign up for my forthcoming course on TDD using .NET. By signing up you’ll get periodic emails and updates about the course, as well as a subscriber’s only discount that’s… well… only available to subscribers.

‚Äč