Mike Bland

Narrowing the Imagination Gap with the Test Pyramid in Action

The "Making Software Quality Visible" series will resume shortly. Before that, I'm excited to share a new training project I've developed. I'm also about ready to start a business or find another job soon.


Tags: Test Pyramid, personal, technical, testing

To those who were following the Making Software Quality Visible series, I’m sorry for the sudden unplanned radio silence. All is well; I merely got a little burned out, then sidetracked by developing an interesting (to me, at least) new training project.

The working name for this new project is The Test Pyramid in Action, and it has two parts:

And here’s the LinkedIn announcement of this post.

Goals and Motivation

The goal is to make core automated testing concepts accessible to programmers who have had little to no practical experience with writing (good) tests. The TSTE is a complete working example demonstrating the Test Pyramid strategy, incorporating Roy Osherove’s String Calculator kata as a hands-on beginners’ exercise.

When I say “complete” example, I mean that it incorporates a small unit testing example, but not in isolation. Countless others have provided many good introductory testing examples across many different languages and frameworks, and they are vitally important. But I developed this project because, to my knowledge, there’s no (well-known, at least) example system containing tests of all sizes.

More specifically, I wanted a training system with a domain narrow enough to allow people to focus purely on the design and mechanics of testing. Even my EListMan project, which I think contains good examples of different test sizes and testable design, is weighed down somewhat by its domain detail.

So I developed this project to:

  • Go beyond a basic, isolated exercise to demonstrate tests at every level of the Test Pyramid—showing how unit testing is essential to the big picture
  • Resemble a production application, but with minimal functionality and complexity to allow the design and testing strategy to stand out
  • Show how to develop and test every level of the system independently, while integrating into a cohesive whole—via interfaces, dependency injection, and test doubles
  • Provide ample examples and documentation to support further study

Technology choices

The technology choices were based on the tech stack used by the team I’m planning to give this talk to first. Otherwise, I wouldn’t be touching Java—I’ve avoided it for most of its twenty-eight year existence. Or, rather, I’ve avoided its ecosystem of excessive frameworkization, such as Tomcat and Weld, and documentation about documentation about specifications about specifications.

I don’t actually hate the language, and I’m quite the fan of IntelliJ IDEA and other tooling. Though I’d typically prefer using Bazel (old habits die hard), I found Gradle interesting to learn about in its own way. But if you go trolling through my commit log, you’ll find some empassioned screeds that I may post here one day for the lulz.1

On the frontend, they use plain HTML, CSS, and Handlebars. I didn’t find existing examples of writing testable Handlebars components, so I invented my own testable component pattern, with the help of Vite and Rollup. In the process, I wrote rollup-plugin-handlebars-precompiler, which was unexpectedly fulfilling. I used Vitest for testing,2 and developed test-page-opener to test basic page loading behavior without launching the backend or using Selenium WebDriver. (I am using Selenium WebDriver in Java for the large, end-to-end tests.) I even dove into TypeScript to provide type checking and IDE hinting, after noticing a hint about missing types in Visual Studio Code.

Inspiring the Quality Mindset by Narrowing the Imagination Gap

I’ve done all this work to underscrore the point I ultimately keep trying to make: The Quality Mindset is essential, the specific technology is not. Technologies come and go over the years, but the Quality Mindset makes it so much easier to roll with the inevitable changes.

‘Scuse me while I riff on this a bit…

I’m not some sort of genius Boy Scout. I had the right mindset, and I found a way to use the technology at hand to solve familiar problems. I can grit my teeth and dive into a tech landscape I’d rather prefer to avoid, and still do everything I intended to do.

Understanding the Test Pyramid strategy itself doesn’t take time, it’s learning about the details and the tools and writing working code that does. All of that is what we’re supposed to be doing anyway. Writing tests replaces faith in our abilities with direct feedback on whether the code we write actually works, and continues to work as expected.3

It did take me a bit to get familiar with these new-ish-to-me technologies. However, my audience shouldn’t need as much time to understand what I’ve done with them, I hope. All this work will ultimately prove worth it if it makes it easier for someone familiar with these technologies to understand and embrace the mindset.

I’ve taken to calling this experiment Narrowing the Imagination Gap. I’m attempting to create a substantial—but not overwhelming—presentation and example that can connect what people are familiar with to what’s actually possible. No one presentation or example is enough, but I’m curious whether this one example is capable of inspiring some people to continue the journey.

Encouraging excitement, minimizing discouragement

Another way to look at this is that I didn’t want people to get excited about an isolated example, but discouraged about the big picture. I’m hoping they’ll feel like they have a chance at making improvements to their entire testing strategy and software system, given a complete working example. Specifically, an example substantial enough to make the entire Test Pyramid strategy clear, without requiring weeks or months to learn the example system itself.

Contributions and invitations welcome

Though I’ve done quite a lot of work here, I wouldn’t say I’m “finished,” if I could ever be. To be completely honest, I’ve had my fun diving in and out of rabbit holes by myself for long enough now. I could use an injection or ten of collaborative energy.

So if any of you think that working on a presentation and example like this is your idea of fun, let me know! We can figure out how to jam on this thing, not just improving what’s there, but maybe porting it to different tech stacks.

Or, if you think folks you work with might benefit from seeing this, maybe getting their hands on it, let me know that, too! I’d love to see how we could use this project to connect people to some important ideas and get them excited to apply them.

What do I want?

There’s a secondary subplot here. You may or may not know I left Apple in November 2022, well over a year ago by now. I’ve busied myself by writing Making Software Quality Visible, then by making my blog less ugly (and adding a dark mode for kicks). That eventually led me to writing EListMan to both improve my blog emails and learn about serverless systems (and, inadvertently, spambot blocking). I’ve done a couple talks here and there, and now I’ve implemented this whole webapp training example.

The subplot is that I’m struggling to answer one essential question:

  • What the hell do I want?

The truth is, I haven’t been able to answer that question since I started asking it of myself last year. Now, I think I needed an extended sabbatical—I pushed hard to make the Quality Culture Initiative successful for four straight years. That was what I wanted at the time. But I’ve had my rest, and the time has come to get serious about finding the next mission.

And, honestly, I could use some help.

While I have my introverted tendencies, the truth of my life is that I cannot fully thrive in isolation. I’m not at all unique in that way, of course. However, I did grow up with that macho, individualistic American conditioning that I’m the exceptional hero of my own story. The more stuck I feel, the harder it gets to ask for help. I’m supposed to be able to have my shit figured out by myself, especially by this point in my life. It’s also too easy to focus on my own near-term goals, instead of being attentive to what people actually feel that they need from me.

Well, to hell with all that. I’m asking the questions out loud now, and I’m listening to your answers as well as my own. I need others’ help narrowing my own Imagination Gap.

I’m still undecided regarding whether I want to try to start my own consulting business, or if I want to work for another company again. I’m not looking for a company to become my “family” or provide my life meaning, as I’m too old for that bullshit now. I also don’t care about any particular product4 and actively refuse to work on or with artificial intelligence, machine learning, data science, or social media. In that light, I feel like I’ve disqualified myself from joining practically any technology organization full time.

But I care a lot about how software is written and tested, and how to persuade and enable people to do better without coercion. I care about learning to improve my own technical craft and leadership abilities, while helping others to improve theirs. I’m eager to connect with and contribute to a community, some way, some how.

If anyone has any words of wisdom, or any opportunities to offer, or is wrestling with the same questions, I’d love to have that conversation. In the meanwhile, I’ll keep doing what I do and hope the direction I’m stumbling in is actually forward.

Footnotes

  1. A small preview: A dependency injection “framework” should never be necessary, so long as you are the author of main(). Even with a servlet container like Tomcat, you can have an injectable, testable parent class, and use a subclass to inject production dependencies.

    But given the prevalence of DI frameworks in Java, I thought it wise to see what I could do, and ended up using Weld. I spent days skimming through seas of specs with references to specs with scarcely a practical example in sight, plus days of trial and error. Just to inject a stupid StringCalculator implementation. Those are days I wish I had back. 

  2. I also submitted a couple of small bug fixes that got merged into Vitest:

  3. As I’ve become more sensitive to people painting testing as “dogma” or “religion” over the years, I’ve recently realized it’s classic psychological projection. Good testing provides immediate, actionable information on the correctness of one’s work. It’s the assertion that testing is an unnecessary religious fad, specifically given one’s presumed superior technical abilities, that reeks of bad “faith.” 

  4. Well, I don’t care about most products. Most of the ones I do care about are composed of wire, wood, knobs, springs, buttons, and vacuum tubes. But I think the ship to carry me to that career may have long since sailed.