Epic Multi-hatting


The author, multi-hatting as engineering manager and product owner

Multi-hatting is a fact of life in organizations of any size.  As long as you remain aware of what hat you’re wearing at any particular moment, life is good, right?  I’ve said as much myself.

When I talk about knowing what hat you’re wearing, I usually mean it in the sense of knowing whether or not you own the outcome, or are simply a stakeholder in someone else’s outcome.  Sadly, knowing who owns the outcome isn’t enough to do the job well.  Different roles have different outlooks.

A typical multi-hat in many organizations, large and small, is engineering manager and product owner.  Need a product owner for a team? Slap an engineering manager in there – we pay them a lot, they know the product and the team and have a little broader outlook than the troops.  But what happens when they start managing a backlog, in particular writing epics?

In the course of managing backlog – writing stories and epics – I’ve bumped up against the “what is an epic” question a lot, especially when backtracking from story to epic.  I’ll think about the story one way and infer the epic from it, create that epic, then later realize that it fits another epic that looks at the story entirely differently.  An analysis of the epics in question split them into two very clear categories – stuff I write when my head is in the code and stuff I write when my head is in the backlog.

Let’s take a real-life example from the Dog-Food-Diet series.  We want to remotely control multiple 120VAC lights and I wanted to start work on a single story called “turn AC outlet on/off”.  It was not part of an epic.  So I scanned the list of epics, didn’t see the right one and promptly wrote an epic labelled “Controllable power strip”.  Typical engineer-think – leap to the solution and generalize.  That epic describes a thing that we’re not intending to sell – a controllable power strip – rather than the intent we’re trying to accomplish within this product which is to turn lights on and off.

Fortunately, as I discovered later, there was already an epic in the backlog that neatly illustrated the point I’m trying to make here – “Hand-off control of light”.  A totally different perspective on the work.

  • Epic I wrote when my head was in the code – Controllable power strip
  • Epic I wrote when my head was in the backlog – Hands-off control of light

What you see with the first of those epics is my wearing the hat without assuming the perspective.  A “controllable power strip” isn’t an aggregation of business value, it’s a real-world thing that’s kind of like the component that we think we want to build to achieve the business goal of “turning a light on and off”.

The backlog is, first and foremost, an expression of business value.  If the things in it don’t express business value then there’s no obvious sense to the order that you build them in and you’ve lost the point to the backlog.  In other words, do your backlog items describe how you’re going to build it, or why you’re going to build it?

Note on tool use:  If we’re building a controllable power strip to achieve this function it feels weird to not categorize this story as “controllable power strip”.  JIRA offers two ways to capture the knowledge that “how” we’re going to turn lights on and off is through a controllable power strip that we’ll build into the system.  You can use components, or tags.

I chose a tag for this particular example.  We have an Android Things embedded device, an API, a web UI and the physical installation itself at the component level.  If we had a team and a separate backlog for each of these, the power strip might be a component in that backlog.  It doesn’t particularly matter as component and tag are simple attributes in JIRA, not structural features.

There ARE tools that use JIRA’s component field as a structural item.  FeatureMap comes to mind.  It’s a tool that translates back and forth between story maps and backlogs.  I like the product but … it uses the component field to group stories into features.  If you’re already using components for actual components then you’ll probably end up reorganizing things to work with it.  Going back to the Dog-Food product, for instance, and its components, a story map with columns labelled “embedded”, “web UI”, “API” and “physical installation” makes no sense whatsoever.



PSA: Empty Test Suite

I’m writing this post, and tagging it with “Empty Test Suite” all over the place, because Googling “Empty Test Suite” won’t tell you what I discovered.  In fact, the StackOverflow method of debugging this led me on a couple of hours of bad adventure.

The setup:

  • Android Things developer preview 0.6
  • Raspberry Pi connected hardware
  • IntelliJ
  • JUnit tests using the AndroidJunitTestRunner

Almost all my tests (200+ at this point) are run on-device as they require hardware.  After hours of fiddling with Gradle, I get my tests, 45 minutes worth, running on the device.  Even hooked it up to the CI pipeline.

Then I went on a couple of hours worth of refactoring.  Run CI again, and bang! Empty Test Suite.

Testing started at 2:07 PM ...
 02/13 14:07:17: Launching Tests in 'com.farlo.android.bubbles.control.rule'
 $ adb push C:\Users\rodley\Documents\bubbles\Bubbles\build\outputs\apk\blue\debug\Bubbles-blue-debug.apk /data/local/tmp/com.farlo.android.bubbles
 $ adb shell pm install -g -t -r "/data/local/tmp/com.farlo.android.bubbles"

$ adb push C:\Users\rodley\Documents\bubbles\Bubbles\build\outputs\apk\androidTest\blue\debug\Bubbles-blue-debug-androidTest.apk /data/local/tmp/com.farlo.android.bubbles.test
 $ adb shell pm install -g -t -r "/data/local/tmp/com.farlo.android.bubbles.test"

No apk changes detected since last installation, skipping installation of C:\Users\rodley\.gradle\caches\modules-2\files-2.1\com.android.support.test\orchestrator\1.0.1\12d61be26b643c6413d207248660bce8f6d8b236\orchestrator-1.0.1.apk
 $ adb shell am force-stop android.support.test.orchestrator
 No apk changes detected since last installation, skipping installation of C:\Users\rodley\.gradle\caches\modules-2\files-2.1\com.android.support.test.services\test-services\1.0.1\c24c3f3ccf05dfdd86dbcd6c7a648d6c4a429178\test-services-1.0.1.apk
 $ adb shell am force-stop android.support.test.services
 Running tests

$ adb shell CLASSPATH=$(pm path android.support.test.services) app_process / android.support.test.services.shellexecutor.ShellMain am instrument -r -w -e targetInstrumentation com.farlo.android.bubbles.test/android.support.test.runner.AndroidJUnitRunner -e package com.farlo.android.bubbles.control.rule -e debug false android.support.test.orchestrator/android.support.test.orchestrator.AndroidTestOrchestrator
 Client not ready yet..
 Started running tests
 Tests ran to completion.

Empty test suite.

That error message seems pretty clear.  The test runner couldn’t find any tests to run.  To me, this said that I’d broken my build configuration – either grabbing a bad dependency, picking the wrong test runner or otherwise hosing the build.gradle somehow.  Setting up connected testing was just painful enough in those particular ways that this seemed almost inevitable.

Well, the error message wasn’t clear, or at least complete.  What happened was that my Android Application was blowing up on a simple null pointer in the onCreate and crashing the process, which the test runner, bless its heart, interprets as an empty suite.  If I had, first time out, looked at the logcat:

02-13 19:03:04.404 10994-10994/? E/InstrumentationResultPrinter: Failed to mark test No Tests as finished after process crash
02-13 19:03:04.407 10994-10994/? E/MonitoringInstr: Exception encountered by: com.farlo.android.bubbles.BubblesApp@d5f45a0. Dumping thread state to outputs and pining for the fjords.
 java.lang.NullPointerException: Attempt to invoke virtual method 'void com.farlo.android.bubbles.Cabinet.setupMonitoredDevices(android.content.Context)' on a null object reference

I would have seen that I’d written an easily fixed bit of crappe code, not a painful gradle misconfiguration.  If the tests had been running locally, not connected, the crash would have reported to the console just like the erroneous “Empty Test Suite” message, and again, the issue would have been obvious.

Empty Test Suite?  Check the logcat.