Estimate Accurately, Complete On Time

Estimate Accurately, Complete On Time

Estimating the number of hours it will take to complete a project is a difficult task. If that project is a software project, it can seem downright futile! In software development, there are many circumstances that could cause your estimate to end up too low.  For instance, we all know the software industry evolves quickly. Technologies you use in your project might change during your project’s development. An example would be a new OS version getting released deprecating functionality you were using, or a new version of the wireless technology you’re using is released, adding and/or removing some features. When embarking on a new project, you will likely need to learn new frameworks and APIs. Can you identify all of them before starting the project and if so, how long will it take you to learn them? What about when the client comes to you halfway through the project and wants to add some new functionality (often referred to as feature creep or scope creep)? If feature creep occurs more than a few times, it can often lead to the dreaded need to refactor the code. Code refactoring is costly and is never a part of the original estimate. What about the bugs? There will be bugs and it’s impossible to guess how long it will take you to fix them. These are just a few reasons why a project can take longer than originally estimated.

In the early days of Ditty Labs, we regularly underbid projects and it was frustrating! We’d hit our total estimated hours about halfway through the project and our options at that point were:

  1. Ask for more money. We were working on fixed bid at the time. We quickly learned this was never a pleasant phone call for us or the client.
  2. See if client would agree to reducing features. Again, not a pleasant phone call.
  3. Eat it and just do the rest of the project for free. This sours the motivation to continue working on the project and the quality of work output will likely diminish.

None of these scenarios were acceptable. I realized we needed to get better at estimating. I also realized we needed to switch from a fixed-bid model to hourly. An estimate sets the client’s expectations on what the project will cost. Even with an hourly model, I still felt it was important that our estimates were as accurate as possible. Coming in at 50% of the final project cost is unacceptable. Coming in unrealistically high could mean not winning the project at all.

As we embarked on new software projects, we sought to understand and correct the causes of underestimating. We also set out to improve the efficiency of our work output. By attacking the problem from both ends, we were able to narrow the gap between our estimated hours at the beginning of a project and the actual hours at the end of the project. It boiled down to three key areas:

  1. When creating the estimate, we weren’t breaking the tasks down into fine enough detail.
  2. Once we identified ALL of the tasks, we put them into a spreadsheet and let the spreadsheet do some of the estimation work for us.
  3. We leveraged flow charts to increase our work output and reduce bugs.

The Devil is in the Details

The main cause of underestimating a project is not accounting for all of the tasks. Say you are working on a project featuring a login screen that appears as soon as the user launches the app. It’s a simple screen with just a few text entry fields for username and password and a button to kick off the login process. Implementing that simple screen will be trivial: Create two text fields and a button. When the user taps the button, collect the text that was entered into the text fields and send it to the server. If an “OK” response comes back from the server, proceed to the main app screen. If a “FAIL” comes back, then show an “Invalid UserName or Password” text label. Should be able to do all of that in an hour, hour and a half tops.

We would typically spend just a few hours on an estimate.  We’d go from screen to screen, making a general assessment of the UI widgets on that screen and jotting down a “gut feel” of what we thought it would take to implement. But when we got to the implementation, we discovered a lot of details that seemed insignificant were overlooked. Take the login screen for example. It’s not really the first screen that appears when you start up the app. The launch screen appears first and once the app code begins running, the login screen will appear. If you have a fast device, the launch screen might only be visible for 100mS before being replaced by the login screen after the app code begins running. The user will just see a flicker of your client’s company logo on the launch screen before being presented with a login. In order to fix this, you need to make the launch screen stick around longer and you do that by including a copy of your launch screen as an overlay on top of your login screen. When the app is launched and the app code begins running, it’ll switch to the login screen but that overlay is sitting there on top. Since it is identical in appearance to the launch screen, the user has no idea that a transition from the launch screen to the login screen (with overlay) occurred. You can set a timer to expire after a second or so. This will cause the overlay to fade away, exposing the login UI elements below.

What happens if the login screen can not connect to the server when the user presses the login button? Will you limit the number of characters a user can enter in either text field or will you let them hold a key down on endless repeat and enter thousands of characters? Handling error conditions is important and it takes time. How will the layout change for different screen sizes? Will the login screen look different on an iPad vs and iPhone? What about localization? Will the app support multiple languages? If the text fields are low on the screen, you’ll need to scroll them up out of the way of the keyboard when it appears. What about a “forgot password” button? Will there need to be a different ViewController to handle that functionality? What about test and debug time? Taking a deep dive into each screen and unearthing all of the tasks necessary to complete that screen is essential to providing an accurate estimate. Each of the above tasks can now become a line item in your estimate spreadsheet (I’ll talk about this a little later). Instead of having one line item, “Login Screen”, you now have seven or eight line items and they are smaller, discrete, bite sized tasks that are easier to estimate. The login screen that was once estimated to be 1.5 hours to complete is now, more realistically, 3 to 5 hours of work.

Creating an app often begins with a storyboard. The storyboard shows all of the screens within the app and depicts how the user experience will flow from screen to screen by swiping or tapping various on-screen buttons. A UI/UX designer and graphic artist will usually be tasked with creating the storyboard. They sit down with the client and go over each screen, capturing all of the little details. They will then create a storyboard showing how the final app will look. The storyboard contains all of the final art assets and puts the client and the developer on the same page as to how the finished app is expected to look and flow. Often times there will be several iterations back and forth between the designer and the client, ironing out small details. Eventually the storyboard is polished and ready to hand to the developer for an estimate.

As a developer, I go through each and every detail on every screen, generating line items for my estimate spreadsheet. Often times I’ll find things that were overlooked. For instance, the storyboard might only show portrait layout. If the app is supposed to support landscape layout, this could add a significant amount of development time, especially if the landscape layout is drastically different than the portrait layout. Same goes for screen sizes. Will the app run only on iPhone or will it be a universal app that also supports the larger iPad screen? I was once working on an app that had a social media feed where people could like and comment on posts. The storyboard didn’t show how the UI would adapt to the appearance of a keyboard when a user tapped on a comment field. I could make an assumption and code up how I think it should be but it might not match the assumption the client made. This could end up with me having to later rework some code to match the client’s assumption and costing time. The storyboard should eliminate all assumptions and clearly depict all functionality within the app.

It’s prudent to identify and clarify any ambiguities too.  In that same social media app, there were some light gray icons on the far right side of the comments text entry field. One of those icons was a happy face — an emoji. I informed the client that the Apple keyboard has an emoji key built-in so they opted to remove that gray emoji icon from the comments field.

Another question to ask is how do different screen sizes affect the layout of items? If there are any special circumstances beyond simple stretching and scaling, they better be depicted in the storyboard or else it’ll be easy to overlook the work needed to handle those special cases. Even showing whether text should scale or crop is helpful to both the client and the developer. The storyboard should set the same expectations for everyone involved in the project.

There are things to consider beyond the storyboard. For instance, I was estimating the work I needed to do for an audio mixing algorithm. I paused to think about how many channels of audio needed to be mixed together and the need for clipping the audio samples to their maximum extents rather than letting them wrap around. I also needed to send that mixed audio out over a WiFi connection so I had to think about breaking the audio up into packets and how I should handle packets that are dropped. Play silence? Play the previous packet’s audio samples? Design an algorithm to reconstruct the missing audio based on the previous and next audio packet? It’s important to dive down below the surface and uncover the programming tasks you might not normally think of. For instance, buffering those audio packets: How many buffers will I need? How big will they be? Based on their size, is the amount of delay acceptable? At this point, no code has been written yet but you can see I’m starting to think through the implementation enough so that I can anticipate the amount of work that lies ahead.

The Spreadsheet

As I uncover all of the anticipated task nuggets required to build an app, I plop them down into a spreadsheet. The spreadsheet is organized by screen. This allows me to quickly assess how many hours it will take to make each screen in the app. I can also convey this information to the client who might decide a certain screen isn’t worth the extra cost and drop it for now (maybe adding it later if the app takes off). For each task, I give a high estimate and a low estimate. For example, I might have a task that says, “Retrieve preferences from server”. The low estimate will be 0.5 hours and the high estimate will be 1 hour. After completing projects and looking at the time certain tasks took I have found that I almost always underestimated the low estimate. To combat this, I add a new column that is the average of the low and high estimates.  This average becomes the new low estimate (so the 0.5 hour low estimate above becomes 0.75 hours). Say there is a task that I’ve done before, such as creating a screen with a TableView that shows all of the BLE devices advertising near me. I simply set the low and high estimates to the same number — how many hours I know it will actually take to complete that task. When the spreadsheet averages the low and high values, the new low value comes out unchanged. Every programming task requires some amount of testing and debugging. It would be a burden to estimate that amount for each individual task. I have found that I can take a small percentage of the total hours and add that as test and debug time. Find a percentage that works for you. At the end of each project, determine if you need to bump it up or down a little. I’ve slid that number up and down as I worked on various projects and eventually settled on 14% which best matches the amount of time I actually spend testing and debugging the entire app. Of course I always strive to get that number lower.

With the spreadsheet complete, I create a quote for the client. In the quote, I list each screen with an hourly high and low estimate. At the bottom of the quote I show the total estimate, summing all of the high and low estimates above.

There is indeed a lot of work that goes on behind the scenes just to generate a quote. What used to take a few hours for us to poorly estimate a project can now take 8 - 12 hours, and if the client decides to go with someone else then all that time is lost! But realize this: The client will very much appreciate you setting their cost expectations and then meeting them. You will be happy not having to work the latter half of the project for free.  Finally, the time you spend estimating the project is actual useful engineering time that will contribute to the project and thus should be included in the quote. So even though it takes a little longer to complete, the thorough estimate will be much more accurate and result in a happy client and a happy developer.

The client looks over your quote and decides to move forward with the project. Great! Hopefully you estimated every single task reasonably well. If you overlooked something then hopefully there’s enough test & debug pad to cover it. But what if you run into an unexpectedly nasty bug that ends up taking hours to track down and fix? Now you run the risk of blowing past your low estimate and edging beyond your high estimate. Since the project is hourly, the client might not mind if you go slightly above the high estimate. It is an estimate after all. But what if that bug is particularly nasty and it ends up taking you days to track down. Then you’re going to run into trouble.

You can be the most diligent estimator on the planet but one nasty bug could still blow you out of the water. How do you cope with that? The simple answer is make sure you don’t have any nasty bugs. I struggled with this issue over the course of many projects, trying to understand how I “got into this predicament” when debugging an elusive bug and watching my project tracker time tick tick away. I finally stumbled upon an old friend…

The Flowchart

There are many causes of bugs in software development.  Memory errors, unaccounted for edge or corner cases, not handling error conditions, concurrent operations that share one or more dependencies, timing errors, race conditions, etc.  Memory errors can be dealt with rather quickly. Typically the program will crash and the debugger will show you exactly where the problem is. Slightly harder to debug is when memory gets clobbered by some rogue write operation. All of the other cases I mentioned can be prevented by using effective flowcharting.

I don’t flowchart every piece of code before I write it, but there are certain coding activities that demand a good flowchart beforehand. They are algorithms and state machines. There are other instances when flowcharts are helpful. When I was implementing the GoPro PLUS subscription feature in GoPro’s iOS app, there were several places in the app where that feature could be invoked. I was new to the project and needed to familiarize myself with how the app was structured. I navigated from screen to screen, taking screen shots and pasting them into my flowchart. I created a mini storyboard that showed how the app navigation flowed and it also gave me a clear picture of where the new GoPro PLUS screens needed to be inserted.

Here are the many advantages you get from flowcharting:

  1. It encourages you to visualize the big picture. Whether you’re flowcharting an algorithm, a class or an entire program, you’re compelled to think through the whole design before writing a single line of code.
  2. Duplicated functionality becomes much more apparent. If you see the same blocks repeated in two parts of the flowchart, perhaps this is an opportunity to consolidate them.
  3. Faster recovery from distractions. Working from home with kids can lead to a lot of distractions. I’ve read that once you’re thrown out of your groove and it can take as long as 12 minutes to get back in. One tap on the shoulder is enough to do it too! This is because as coders, we often build up a hierarchy of the algorithm we’re working on in our heads. We think through all of the statements and if-else cases and can practically run the program mentally. We’ve actually built something of a mental flowchart. Once that distraction hits, POOF! It’s gone. When we finally return back to the screen, we have to start building up that house of cards in our head again. I’ve found that just glancing at the flowchart gets me back on track much faster.
  4. The actual coding part is much faster and generally bug free. BUG FREE! This blew my mind. I was accustomed to writing a big hairy algorithm and then spending a good amount of time debugging and testing it before I was satisfied it was ready for prime time. To have something work the first time, especially something complicated like a polygon rendering engine or a VoIP scheme is jump-out-of-the-chair-and-and-cheer exciting! I actually spend most of my time developing the flow chart and a very short amount of time coding. Then the code just works. It’s great!
  5. It’s much easier to spot asynchronous or time delayed operations. In the flow chart, I’ll use dotted lines to connect blocks that have some amount of time delay between them (such as sending a request to a server and getting a response) or doing an asynchronous SPI DMA operation in firmware and getting an interrupt when it’s completed. These can be problem areas in the code where bugs can creep in. Looking at the code, it’s difficult to spot them unless you highlight them with comments but looking at the flow chart, all the dotted lines pop right out at you. This instantly puts you in a cautious mindset when working on code in these areas.
  6. It’s easier to bring someone up to speed on your code. Say you’re going to be transferred to a new project and a new engineer is going to take over maintaining your code. Walking them through the source code is slow and they might remember some of what you said. Then they’ll just have to poke around after you’re gone until they get acquainted enough with it to feel comfortable making changes. Even then, they could still introduce a bug inadvertently. Armed with a flow chart, you can usually walk them through your architecture in five minutes or less. After you’re gone, the flowchart will serve as a guide as they venture into the code and they can be much more confident that their changes won’t break any existing functionality. I typically include a path to the flowchart in the comments section at the top of the source file for easy reference.
  7. It’s faster to get reacquainted with the code after a long hiatus. I developed some firmware a while back that had strict timing requirements, lots of interrupts firing at different times and tons of data going to multiple devices on the SPI bus. Lots of dotted lines. I got absorbed in another project and six months went by before the client came back to me wanting to add a motion sensing device to the SPI bus. I studied the flow chart, then added some more boxes to cover the new IMU. Then I added the new code and it worked. No bugs.
  8. When a bug is discovered, it usually can be found in the flowchart. I have found that debugging a flowchart goes much faster than debugging actual code. Once the bug is fixed in the flowchart, it’s trivial to fix the matching section in the code.

Here are the downsides to flowcharting:

  1. Coding interviews don’t use flowcharts! If you’ve ever interviewed at a large company, typically early in the interview process there will be a phone interview with a hiring manager and they will ask you to code up some algorithm, live on the spot using a shared screen. This sets off all kinds of alarm bells in my head because I’ve become so accustomed to flowing out the algorithm first. I hope one day this will change.
  2. You have to remember to update both the flowchart and the code whenever you make a change. Modern IDEs know nothing about flowcharts and there really is no good way to keep them in sync other than you just remembering to do so.
  3. Overall the development time is longer. Ha! Actually no it isn't. While I do spend most of my time generating the flow chart, the total time spent is actually less because the coding time is reduced and the debugging time is almost nil.

My favorite program for creating flow charts is Omnigraffle. You can find it here: https://www.omnigroup.com/omnigraffle/

I created a custom template containing these components:

You want to be able to quickly reference the code represented by a particular flow in your chart. Whenever the flow enters a different source file, I put the source file name above the function entry block of the function being called.

This particular example shows that an IRQ named CB_DataReady() in DataCollector.c gets called.  I added a small note that it was triggered by DMA.

Sticky notes - great place to convey your thought process for the given approach. Helps to also put these in the comments in the code as well.

In this case, I was just adding some clarity with a sticky note. I also included some timing measurements for easy reference in the flowchart.

Sometimes I’ll diagram data structures in the flowchart for clarity.  

I picture a Flow chart like the scaffolding around a building under construction. If it’s too complicated, the workers have to weave through the thick mesh of metal and wood to get to the particular area they’re working on which makes their job tedious. On the other hand, if it’s too simple, that leaves areas inaccessible to the workers resulting in parts of the building not getting completed. Perhaps a window doesn’t get installed. Later, someone falls out. That’s a bug. You have to find a balance. Too much information makes the flowchart cumbersome and hard to follow and it takes longer to create and maintain.  Too little information decreases the usefulness of the flow chart. For instance, not including the source file names makes it harder to find where in the code that part of the flow resides. Leaving some functionality out of the flowchart while having it in the code creates an opportunity for bugs to creep in and invites the programmer not to want to keep the flow chart in sync with the code. I try to put just enough information in the flow chart to maximize its usefulness and minimize bugs. I ask myself, if I had to bring someone up to speed on my approach and my code, what information would be helpful to them?  What information would be helpful to me if I had to revisit this code after 6 months?

That's a wrap

If you’ve read this far, hopefully you’ve gained some insight on how you can accurately estimate a large project and then ensure you stay within the bounds of your estimate by adhering to a structured flow. Diving deeper below the surface of the project outline, while time consuming, will lead to a more accurate estimate and ultimately yield a happy (and hopefully returning) client. Instead of diving straight into the coding, the flowchart forces you to first think about how that code will work as a whole. It minimizes bugs by imposing a structure that your code will follow and errors in logic are more easily found within the flowchart than they would be sifting through code.

Hopefully these ideas have helped you. I would welcome thoughts and suggestions to further improve the process and let me know if these worked for you!

By the way, flowcharts aren’t just for coding. I used one to plan and structure this article!


要查看或添加评论,请登录

Carson Whitsett的更多文章

  • Why Interviewing Is Harder for Senior Engineers

    Why Interviewing Is Harder for Senior Engineers

    When an interviewer asks, “What’s your greatest weakness?” my answer is simply: “Interviewing.” Haha.

    3 条评论
  • Bringing Ideas to Life: Turning Inspiration into Action

    Bringing Ideas to Life: Turning Inspiration into Action

    Have you ever had an idea pop into your head that made you think, “I should work on that someday”? Then, as life…

  • Debugging is a Waste of Time (and Money)

    Debugging is a Waste of Time (and Money)

    As a software developer, have you ever thought about how much time you actually spend debugging your code? Or as a…

    1 条评论
  • Pac-Man and Time Dilation

    Pac-Man and Time Dilation

    The year was 1905 when Albert Einstein published his theory of special relativity. The theory states, in a nutshell…

  • The Career Pivot

    The Career Pivot

    Career pivots, a journey I’ve navigated several times, invoke excitement, fear, anticipation, anxiety, hope and a…

    7 条评论
  • GPU Shader - Flashing Bricks

    GPU Shader - Flashing Bricks

    The GPU or Graphics Processing Unit is an essential part of today's computers and smart phones. It is a co-processor…

    1 条评论
  • Happy Decade Ditty Labs

    Happy Decade Ditty Labs

    A decade. That's a long time.

    1 条评论
  • Job Seekers Add Some Color

    Job Seekers Add Some Color

    Finding your dream job is not easy. There are hundreds of thousands of jobs out there and an equal number of job…

  • The Crux of the Problem

    The Crux of the Problem

    Time is synonymous to money. Take either one: You can spend it, waste it, lose it, have too much or too little of it…

    1 条评论
  • On taking the next step in your career

    On taking the next step in your career

    There are a lot of opportunities out there. Recently I updated my LinkedIn profile’s career interests section and…

    1 条评论

社区洞察

其他会员也浏览了