Let’s Get Practical

Here are some ways to put these ideas into practice.

Seven Strategies for Measuring Software Development

Software is different from tangible goods and it must be measured differently. The tasks that developers do are different from day to day, so productivity can’t be directly measured in any meaningful, normalized way. I often advise teams not to measure velocity because it can send the wrong message and give management the wrong goals. Velocity can be raised at the expense of quality, which is a mistake. Here are seven strategies for measuring value in software development.

Measure time-to-value

We produce software to fulfill some need or desire, and the time from when we start creating something valuable to when it’s realized by users is a good measure of our effectiveness. Local optimizations are meaningless if they don’t help to optimize the whole process. Measuring time-to-value keeps us focused on the big picture—something worth measuring.

Measure time spent coding

Developers love to develop but things can get in our way. Ironically, the time spent assuring quality in many organizations robs teams of valuable time they could have used to actually create quality. I know developers who spend less than 10 percent of their time developing. The rest of their time is taken up by meetings, reporting, and who knows what else that may not be contributing to the bottom line. A good development process is one where developers spend most of their time actually developing software.

Measure defect density

Most organizations track bugs, but this can have the adverse effect of increasing bug tolerance. Defects in code are often a symptom of a deeper cause: a defect in the development process. If defects are consistently showing up in production code, it means the development process may be broken. Look for the root cause and try to fix it. Defect density (bugs per thousand lines of code) is one of the few measurements that can be compared across teams and time, so it can be used for process calibration.

Measure time to detect defects

It’s been shown that the cost of fixing defects increases exponentially as time elapses since the defect was created. The cheapest defects to fix are the ones that are detected and fixed immediately after creation. Finding defects faster not only decreases the cost of fixing them, but also helps developers become aware of things they may be doing that allowed the defect to be created in the first place.

Measure customer value of features

Not all features are equally valuable to customers. In fact, nearly half of all features created in software are never used. Backlogs are ordered so the highest-value features are created first, which lets less important features get put off or dropped. This leaves more time to focus on those higher value items. If developers are unsure of what features will provide the most value, they should ask the customer.

Measure cost of not delivering features

Sometimes the cost of not delivering a feature is the most compelling reason for building it. Ask your stakeholders how much the feature is worth and how much not having the feature will cost. The answer may surprise you.

Measure efficiency of feedback loops

The most powerful point of leverage for increasing efficiency is often in the process itself. A good development process has built-in feedback loops that can be used to tweak the process. The faster the feedback, the more efficient we can become. Find ways to fail fast and learn from failure. This is how teams rapidly improve.

Most teams who try to measure productivity end up sacrificing quality. Measuring productivity may not be possible and can certainly be disruptive. Instead, focus on producing and measuring value, both in the product delivered and in the process used to create it.

Seven Strategies for Splitting Stories

The shorter the story, the better. Short stories are easier to estimate, understand, and implement. Short stories help create cohesive, uncoupled code. Short stories are easier to test. So here are seven strategies for splitting big stories into smaller ones.

Break down compound stories into components

If a story is made up of sub-stories, break them out into multiple stories. This helps disaggregate components and makes a system more modular. It also yields smaller stories that are easier to work with.

Break down complex stories into knowns and unknowns

Stories are complex typically because they contain unknowns. We may not know exactly what the customer wants or exactly how to implement it. Separating what is known from what is not known is the first step to splitting stories with unknowns.

Iterate on unknowns until they’re understood

Once something is identified as unknown, encapsulate it! Hide it behind an abstraction with a well-defined interface. Then you have the freedom to learn more without it being in your critical path. It’s generally better to attack high-risk unknowns up front and defer low-risk unknowns until later.

Split on acceptance criteria

As we break stories down into tasks, we still want to have some kind of visible evidence when a task is complete. Splitting stories on acceptance criteria can help focus development while still providing some customer value within an iteration. It also helps clearly define when the story is done.

Minimize dependencies

We would rather stories not depend on other stories, but sometimes that can be difficult to avoid. Try to remove dependencies by creating well-defined interfaces between dependent components. If you must have dependencies, make future stories depend on previous stories and not the other way around.

Keep intentions singular

A story should be about fulfilling a single intention or a verifiable aspect of that single intention. Often, we think about a story as providing complete functionality to the user and we make them too big. Smaller stories are easier to work with. They don’t have to be a full-blown feature; they just need to contain enough functionality for the user to derive value from it. Subsequent stories can enhance a feature to provide additional functionality.

Keep stories testable

Each story should have a series of acceptance tests defined as the criteria for acceptance. If stories are untestable or difficult to test, then we won’t easily be able to verify them. Make each story have some demonstrable effect on the system so it’s easy to verify. Automate acceptance criteria whenever possible.

Story writing is a skill that’s honed over time. When stories are concise and disaggregated, systems are more focused and easier to build on. Keeping stories small, focused, and easy to verify helps to make systems clear and maintainable.