Saturday, July 25, 2015

Why We're Bad at Estimates

So it took me an hour and a half to write the block of code in the previous post. I think it says a lot about software development and why we're so bad at estimations, so let's case study it.

I knew I wanted a function to convert a world position to a tile position. For the implementation, look below, but essentially take a vector, round X and Y down to the closest multiple of tile size then add half the tile size. Keep Z.

If someone asked how long it would take to write that function, I'd estimate a few minutes. I know the formula already, and I've written functions like it before many times. I would also guess I could do it in a handful of lines of code and the risk of getting it wrong is very low.

Let's take a look at why I'd be so wrong while being completely correct with what I just stated.
The main problem with the estimate is there's no context to the request, and it turns out context is everything. In this case the context is Unreal, a system I'm just barely starting to learn.

My first problem was I didn't know where to put the code. I knew I wanted a Blueprint function (scope creep!), and it would just be a utility function.

I made a blank class and wrote the implementation in a static function. I then added the macro to make it a Blueprint, and compile error.

My class needs to derive from UObject if I want it in a Blueprint. Totally reasonable and makes sense. I have a handful of classes already, so I copied over the UClass macro and the body generation one. No dice. I fiddled a bit and compared it to others before I gave up and used Unreal to make a new class, knowing it would set it up correctly.

I didn't know what to derive from, though. UObject wasn't in the global list, but I found Blueprint Library. That one sounded right. So new class created, old one deleted, get my code in. It works, and I have it in a Blueprint now.

Pull it up in the Blueprint, but it requires a target (the instance I'm calling the function on). I really wanted this to be a simple, stateless function and not a manager class, and I know in regular C++ I would make this function static (or not even in a class, but I know a class is required).
Here's where I went wrong: I had also seen in Blueprints they call static functions pure. I Googled that and found the BlueprintPure specifier. No good. StackOverflow said I had to make the function const. They were wrong. After a few combinations, I went back to my gut and static was correct.

It all worked, and it did what I wanted. But good programmers relentlessly refactor, right? I moved the tile size from a literal to a constant. Easy. I then thought it'd be convenient if Blueprints had access to the tile size (more feature creep!). Turns out you can't make static member variables Blueprint properties. I then had to make it a function that returns the value... which led to a rabbit hole where I was curious how Unreal treats inline. Finally 90 minutes later, I was done.

You can see with all the problems above, plus some tools failure (Unreal crashes a lot) and compile time, why my initial estimate was off by an order of magnitude. This is more typical than atypical for software development, and scales with the size and complexity of the project and team.

So what can we take away from this? First, understand context. What is the project like you're working in? How experienced are your programmers in it? How similar is it to other completed tasks?

Next, what is the entire request? It wasn't just make that function, but make that function accessible by Blueprints as a pure function along with an accessor for tile size. Right there that would've signaled me since I didn't really know what a pure Blueprint is.

Finally, never underestimate testing, research, tools failure, compile times, curiosity distractions, and other sinks. Remember, a typical estimate is highly optimistic for lots of legitimate, human reasons, so we need to actively fight against that.

As a wise programmer once taught me: the problem isn't that we need more accurate estimates, it's that we need larger estimates.

No comments:

Post a Comment