Posts

Assuming the Bugs

Writing code is all about making assumptions. Sometimes those assumptions are explicit, but more often we make those assumptions implicitly. We make assumptions about what kinds of parameters we will receive. We make assumptions about what kinds of values methods and functions will return. We make assumptions about the global state. The correctness of our code relies on the correctness of these assumptions. Bad assumptions can wreck our applicatons. We assumed that method never returns null, but turns out it does. Now we have an unexpected NullPointerException crashing through our stack. We assume that we will always average at least one element. Turns out someone wants to average zero elements. Boom, division by zero, ArithmeticException . We make so many assumptions through our codebases, at least a few are going to be wrong. Really, there are many, many assumptions that are wrong. These are bugs. These bad assumptions are all of our bugs. Usually, our assumptions are i

Name Your Problems

Sometimes when developing code, I run into problems. Ok, a lot of the times I run into problems, but there's a certain kind of problem I run into pretty often. The problem is that I want a thing that doesn't exist. I am writing code, and it is just getting gnarlier and more tangled around a pile of logic. At some point, I hit a wall with it. It is too complicated to really reason about, and I don't want to make things any worse. I've found a trick to solving these problems, though. I take those problems and give them a name. Once I do that, I can get a handle on them, manipulate them, or even sequester them off into a corner. In almost every case, this drastically reduces the complexity back down to a reasonable level, and I often get the side benefit of offering extensibility I didn't know I needed. To demonstrate, let's say we are working on an e-commerce site. The company is based in Alabama, and sells to customers in all 50 states in the US. We have a met

Magic Numbers, Semantics, and Compiler Errors

Image
Magic numbers are considered such a scourge upon code bases that there tools out there to automatically find them and root them out. After all, who knows what setValue(6); really means? There are also many approaches to giving better names to magic numbers. Not all of them are good, though. For example, we have a callback that sets a completion percentage on a status: void callback(Status status) { status.updateProgress(0, "Starting"); // Do some stuff... status.updateProgress(25, "Some stuff done"); // Do some more stuff status.updateProgress(50, "More stuff done"); // Reticulating splines status.updateProgress(75, "Splines reticulated"); // Validate everything status.updateProgress(100, "Complete"); } Those percentages would get flagged as magic numbers by the automatic tools. The developer would need to extract those out to constants to make that tool happy. A thoughtful developer would create

Typing != Complexity

Developers of all experience levels commonly share a false belief: more typing means more complexity. The most powerful idioms and tools often require a few extra keystrokes, but dramatically reduce complexity. The final keyword in Java is a bit of extra typing. The final keyword can be applied to variables, method parameters, instance members, static members, methods, and classes. By making these final, their values will not depend on their context. They will be known constants through their lifetime. Their constancy removes a large cognitive load. The developer no longer needs to worry if the value was not set or if it was set multiple times. Many developers forgo this benefits to avoid typing the extra keyword, to their own detriment. Later, they spend too much time chasing down defects caused by mutable state. Developers will often shun creating small types and interfaces because of the extra typing involved. Interfaces can abstract away many different implementations behind

The Cohort of Responsibility

Sometimes the team just isn't enough. Delivering business value from idea to production is a complex endeavor. Development teams sit squarely in the middle of that process. Ideally, they are talking directly to the customer . Often in real life, business analysts collect requirements from customers and pass them to the development team. On the other side, development interacts with operations to deploy and run the software. All of these groups, and more, have the responsibility to deliver the business value. But too often, there is friction between these groups on the path. Not everyone wants to move in the same direction. Some individuals or groups can slow down or altogether stop value from being delivered. They are responsible , but not always accountable . Everyone who bears direct responsibility toward delivering business value is part of the Cohort of Responsibility in the organization. To most easily identify everyone in the cohort, we can pick out everyone who must t

Velocity is not a Business Metric

Nowadays, every Agile™ organization is intently focused on increasing velocity . It's obvious: higher velocity means more productivity and efficiency, right? Because of this, managers and team leaders and product owners the world over are tracking team velocity. With it, they demand estimates, make projections, and kick off marketing campaigns. They are often led astray by velocity. Because velocity is not a business metric . Velocity is an imprecise metric in the best cases. We calculate it from an estimation metric over a defined period of time. Story points are the most commonly used metric. Story points are a team's best guess at how large a story will be relative to other stories. A story is assigned a number of points at some point before development starts on it. The points are credited to the team's velocity when the story is considered done. Ideally, velocity is fairly stable over time. Using velocity (say, 12 points/week), we can extrapolate an entire project

Respect Your Callers' Intentions

When we write code, we write it to be used. We call it from other places in our application. Others call it from places in their application. When we are writing code, we should show what we mean through our code, an idea known as intention-revealing interfaces . We reveal intentions through the external surface we expose. But what intentions are we exposing? We write our code in a way that we think will be useful, but we are mostly writing implementation. We are writing what the code should do, and then from there how others would use it. The implementation drives the interface. The implementation does not always have the right intentions, though. Here's a simple class that stores historic temperature data for processing: public class TemperatureHistory { private int[] temperatures; public TemperatureHistory(int[] temperatures) { this.temperatures = temperatures; } public int[] getTemperatures() { return temperatures; } } This is a simpl