Monday, February 20, 2023

T-Shirt Sizing: Don't Overcomplicate It!

We spend way too much time hassling around with estimating our work. That time would be far better spent improving the sizing of work rather than how long it will take us to do the work. (I'd encourage you to go read up on flow through systems, as good sizing of work items is crucial!)

Also, I'm not going to get pulled into the #NoEstimates debate. There's a time and need for everything.

Some teams get carried away with long sets of Fibonacci numbers, extravagant planning poker, etc.

I'd say throw all that out and focus on simple t-shirt sizing: Small, medium, and large. That's it.

Small should be things you're confident you can get done in a day or less: Think about building and testing a login screen when you've got existing authentication infrastructure in place.

Medium and large are simply variants of that. "Oh, this seems a bit bigger than a login screen, but not significantly so. We'll call it a medium."

Note there's no Extra Large, Double-X, or Ginormous on my list. I'm adamant that really large efforts need to get pushed back into planning and split into smaller chunks.

Really large work is high risk. Minimize the amount of high-risk work you take on.

Stop overthinking your estimating. Spend more time breaking things down into small chunks of work.

NOTE: Testers, the above applies to you when you're asked to give an estimate of how long it's going to take to test. Start with your smallest task and go from there. Push back HARD on things that are too complex, too big, too risky. Ask to break those tasks down!

Tuesday, April 19, 2022

Hide Complexity

So, so much of good system design is abstracting out complexity. So, so much of good testing is understanding where the complexity is and poking that with a flamethrower until you decypher as many interesting things about that complexity as you possibly can.

Yes, that's a lot of badly mixed metaphors. Deal with it.

I'm taking my team of testers through learning Test Driven Development using the Payroll Calculator example from my course Coding for Non-Coders ( The problem walks people through creating a small bit of code to compute wages for an hourly worker based on the hours they worked and their payrate. The worker may have some overtime if they worked over 40 hours in one week.

Simple problem, familiar domain. Hours, rate, determine how much a worker gets paid before deductions. 

Right now we've finished standard time and have six total tests (three single XUnit [Fact] tests and one data-driven [Theory] with the same three test scenarios). 

The "system" code right now is this bit of glorious, beautiful stuff below. Please, be kind and remember the context is to show testers a bit about TDD and how code works. No, I wouldn't use int for actual payroll, m'kay?

    public class PayrollCalculator     {
        public int ComputeHourlyWages(int hours, int rate)
            return hours * rate;
We were getting ready to move into writing our first test for overtime. At this point, one of my team members jumped ahead to ask about adding in a separate method for computing overtime hours. We haven't written any tests yet, but this was absolutely worth heading off on a discussion!

The intent of my tester's question was if we should make the system work like the snippet below--some hand-wavy psuedo code is inline.

    public class PayrollCalculator     {

        public int ComputeOvertimeWages(int hours, int rate) {
            //calculate ot wages
            return otWages;

        public int ComputeStandardTimeWages (int hours, int rate) {
      //calculate standard wages
            return standardWages;
Splitting calls to compute separate parts of one overall action may seem to make sense initially, but it's far more risky and complex.

What are we trying to do? We're trying to figure out what a worker gets paid for the week. That's the single outcome.

Think about some of the complexities we might run in to if this was broken into two separate calls. Think of some of the risks that might be involved.

  • Does the order of the calls matter? Do I need to figure standard hours first, then call the ComputeOvertimeWages method? What happens if I call overtime before standard?
  • Do I call overtime for only the hours above 40?
  • If the worker put in over 40 hours, do I call standard wages with just 40, or will the method drop extra hours and just figure using 40?
  • Does the code invoking these calls have to keep track of standard and overtime hours?
  • What happens if in the future we change the number of standard hours in the pay period?

As a system designer you're far better off abstracting all this away from the person calling your methods.

One simple method, and you hide that complexity. Just give the person calling your API what they want: the actual wages for the worker.

This same concept applies if you're dealing with complex workflows and state. Let's say you have a five step workflow for creating a new job bid, and you need several critical pieces of information at each step.

Don't make your users or callers figure that complexity out. Give them one place to start the workflow, and ask for everything you need up front. Then YOU figure out how to handle the complexity and hide the goo from them. Just return them a shiny new job bid.

One interaction, one nice result. Easier to write for your consumers, far easier to test, too.

Someone years ago spoke of making it so your users could fall into the pit of success. Do more of that, and less of pushing them into the pit of despair. (I'm throwing out a Princess Bride reference, not one to Harry Harlow...)

Wednesday, October 17, 2018

Keynote Talk: You Got This

Last week I was fortunate to have been the keynoter at DevSpace Technical Conference in Huntsville, Alabama. DevSpace's chairman Chris Gardner reached out to me some months ago and asked if I'd be willing to talk about how I've gotten through life since the awful events of January 10th, 2017.

Below is a video of that talk. It's intense, emotional, and very likely a complete surprise to attendees who didn't already know of the tragedy that struck my family last year.

As with my KalamazooX conference talk last March, this talk also engendered strong reactions. That's OK, it's not milquetoast. One person took great offense at how I framed things between my Christianity and being open to the Universe--but my point was that no matter what your religious beliefs are or aren't, in times of great adversity and struggle you absolutely must find some way to find peace and ground yourself. If that's faith in God, wonderful. That works for me. If it's you simply being spiritual and thoughtful, then please do so.

I'm very thankful to Chris, and I'm also thankful to the attendees who said many kind things to me at the conference. It couldn't have been easy coming up to me in the hallways. I mean, really, how do you start a conversation with a guy who just got naked (METAPHORICALLY!) on stage to talk about dealing with suicide, then the murder of his wife by his 12-year-old son? Not easy. Thank you to all who passed on kind thoughts.

This talk is fairly different from the KalX talk above. Lots of overlap, but it's a different focus, because I was trying to point out to the audience that each and every one of us has the ability to weather horrible storms.

You Got This.

Friday, September 14, 2018

A New Technical and Leadership Blog for Me!

I decided to move my technical and leadership postings over to a new blog on my Guidepost Systems site.

I'm doing this in the hopes of continuing to shore up and flesh out my professional branding around Guidepost Systems.

I will occasionally cross-link content here as a reminder. I'll continue to post notices on my Twitter timeline when things go live over at my blog there.

Please go follow along at that new location. I look forward to comments and discussions on postings there!

(I've already got a series going there on creating a technical debt payment plan.)

Monday, August 27, 2018

My Test Credo

A few years ago I scribbled down some thoughts to myself as I was struggling with my brain and a frustrating project.

I pinned these notes on a cubicle wall without thinking much as a reminder to myself. Never thought much else of it, simply because this was me reminding myself of things I needed reminding of.

Friday a good pal who was on that same project hit me with a shot out of nowhere when he reminded me of this. I guess it had an impact on him as well.

Frankly I’d forgotten about these. His comment was a good reason to go hunt this down.
Jim's Testing Credo
Jim's Testing Credo

Friday, August 17, 2018

Interview on A Geek Leader Podcast

Somehow I forgot to post here that John Rouda was kind enough to invite me on his A Geek Leader podcast some time back.

We talk about leadership, learning, adversity, and of course The Event from Jan 10th, 2017.

John’s a wonderful, gracious host and we had a great conversation. You can find details at John’s site.

Stop Rationalizing Bad Coding Practices

Rant. (Surprise.)

Want to work alone for long periods without testing or running your code? Want to avoid doing TDD or at least test-immediately-after-coding because it breaks up your flow? Don’t want to be disturbed discussing things with your testers, product owners, and users because it takes time away from coding?

Believe it or not, there are times I’m OK with this.

I’m OK with the practices above if:

  • Your business stakeholders and users are happy with the system in production
  • Your rework rate for defects and missed requirements is near zero
  • You have fewer than six to ten defects over several months
  • You have near zero defects in production
  • Your codebase is simple to maintain and add features to
  • Static analysis of your codebase backs up the previous point with solid metrics meeting recognized industry standards for coupling, complexity, etc.
  • Everyone on the team can work any part of the codebase
  • New team members can pair up with an experienced member and be productive in days, not weeks

If you meet the above criteria, then it’s OK to pass up on disciplined, PROVEN approaches to software delivery–because you are meeting the end game: high-value, maintainable software that’s solving problems.

The thing is, very, VERY few people, teams, or organizations can answer all those questions affirmatively if they’re being remotely honest.

Some people, way to the right of the bell curve, and I’m talking like the miniscule number of folks out on the fifth standard deviation, can pull this off. Not intuitively, but after years of study and hard work and a metric crapton of failure.

The rest of the 99.865% of the software industry has decades of data proving how skipping careful work leads to failed projects and lousy care of our users.

Those of us who’ve been around the block a few times see the awful results time and time again: Dysfunctional organizations who can’t deliver critical internal systems but once every two or three years. Product companies folding due to angry customers and bad reputations. Miserable teams of humans trapped in death march scenarios.

Do not rationalize your concious decisions to do poor work with “I’m more effective when I just…” No. No, you are not. You think you may be, but not unless you can answer the questions above “Yes!” with confidence and honesty.

Stop rationalizing. Stop making excuses.

Own. Your. Shit.

And clean it up.

Friday, August 10, 2018

Understanding WebDriver Components

Understanding WebDriver Components

[UPDATE] This post is based on a submission I made to the official WebDriver documentation in early Spring of 2018. It's meant to help folks understand how pieces and parts fit together for WebDriver. [/]

Building a test suite using WebDriver will require you to understand and effectively use a number of different components. As with everything in software, different people use different terms for the same idea. Below is a breakdown of how terms are used in this description.


  • API: Application Programming Interface. This is the set of "commands" you use to manipulate WebDriver.
  • Library: A code module which contains the APIs and the code necessary to implement them. Libraries are specific to each language binding, eg .jar files for Java, .dll files for .NET, etc.
  • Driver: Responsible for controlling the actual browser. Most drivers are created by the browser vendors themselves. Drivers are generally executable modules that run on the system with the browser itself, not on the system executing the test suite. (Although those may be the same system.) NOTE: Some people refer to the drivers as proxies.
  • Framework: An additional library used as a support for WebDriver suites. These frameworks may be test frameworks such as JUnit or NUnit. They may also be frameworks supporting natural language features such as Cucumber or Robotium. Frameworks may also be written and used for things such as manipulating or configuring the system under test, data creation, test oracles, etc.

The Parts and Pieces

At its minimum, WebDriver talks to a browser through a driver. Communication is two way: WebDriver passes commands to the browser through the driver, and receives information back via the same route.

The driver is specific to the browser, such as ChromeDriver for Google's Chrome/Chromium, GeckoDriver for Mozilla's Firefox, etc. The driver runs on the same system as the browser. This may, or may not be, the same system where the tests themselves are executing.

This simple example above is direct communication. Communication to the browser may also be remote communication through Selenium Server or RemoteWebDriver. RemoteWebDriver runs on the same system as the driver and the browser.

Remote communication can also take place using Selenium Server or Selenium Grid, both of which in turn talk to the driver on the host system

Where Frameworks Fit In

WebDriver has one job and one job only: communicate with the browser via any of the methods above. WebDriver doesn't know a thing about testing: it doesn't know how to compare things, assert pass or fail, and it certainly doesn't know a thing about reporting or Given/When/Then grammar.
This is where various frameworks come in to play. At a minimum you'll need a test framework that matches the language bindings, eg NUnit for .NET, JUnit for Java, RSpec for Ruby, etc.

The test framework is responsible for running and executing your WebDriver and related steps in your tests. As such, you can think of it looking akin to the following image.

The test framework is also what provides you asserts, comparisons, checks, or whatever that framework's vernacular for the actual test you're performing, eg

AssertAreEqual(orderTotalAmount, "$42");

Natural language frameworks/tools such as Cucumber may exist as part of that Test Framework box in the figure above, or they may wrap the Test Framework entirely in their own implementation.

Natural language frameworks enable the team to write tests in plain English that help ensure clarity of why you are building something and what it is supposed to do, versus the very granular how of a good unit test.

If you're not familiar with specifications, Gherkin, Cucumber, BDD, ATDD, or whatever other soup-of-the-day acronym/phrase the world has come up with, then I encourage you to go find a copy of Specifications By Example. It's a wonderful place to start. You should follow that up with 50 Quick Ideas to Improve Your User Stories, and 50 Quick Ideas to Improve Your Tests, both by Gojko Adzjic.

Following Up

Don't stop here. Go learn more about how WebDriver works. Read the WebDriver documentation. Sign up for Dave Haeffner's awesome Elemental Selenium newsletter and read his past articles.

Join the Slack Channel and ask questions. (But please, do yourself and the Selenium community a favor and first do a little research so you're asking questions in a fashion that can help others best respond!)

Slides from ThatConference

I spent the last week at THATConference in Wisconsin Dells, WI. It's a wonderful conference somewhat along the same lines as CodeMash, but with a very different culture and vibe. I gave my talk "More Better Quality Coverage" which is on improving how your teams test--and understanding what modern testing and quality needs to look like.

Lots there on moving testing conversations to the left. Lots there about testing as an activity.

Thank you if you attended the session. I had some really good questions, folks were patient with my bad jokes, and there were some really good conversations after the talk.

Also: Thank you to THATConference staff and attendees. I've been to five conferences already this year. I'm finally finding myself coming out of the funk I've been in since January 10th, 2017. SeleniumConference Bangalore was the first conference I felt somewhat "myself" at. This time at THATConference I felt almost 100%.

Thank you.

Subscribe (RSS)

The Leadership Journey