Solve multiple problems at once

Startup engineering teams face many decisions about what to build. At Close.io, many areas compete for the focus of our small engineering team. Customers often have one little thing they really need. Our team envisions the next big thing to move the product forward. There are poor UX workflows to optimize. We have an idea on how to grow our customer base faster. And of course there are always bugs to fix. The list is endless!

A small engineering team doesn’t have the time or resources to regularly improve every part of a product. It’s not uncommon for a section of an app, once launched, to remain untouched for a year or longer. We usually work to solve a problem or empower customers in a new way or fix a pain point, and then we move on to something else.

One reason I believe our super small team at Close.io has been successful is that we often solve multiple problems at once. When a feature needs to be built, we often expand the scope a bit to include other related problems or features that naturally go together with the first one.

Another way to phrase this idea is: rather than solving a problem, solve an entire class of problems.

While this advice may sound obvious, there’s enormous pressure to finish a project as quickly as possible. There’s always the next important feature, bug fix, or redesign from the roadmap to move on to. Shipping even the smallest version of a feature on time can be difficult enough already, since software schedule estimating is never easy. But there’s great value in not just shipping a feature or fix in the smallest form possible.

Application: Fixing Bugs

Let’s start with a simple real-world application: you notice a bug that needs fixing. After some investigation you figure out what the problem is and how to fix it. You fix it and maybe even add a unit test for this case. Time to move on, right?

NO! If you stop there, you’re making a crucial mistake.

At a minimum, you should try to figure out if the same bug exists anywhere else in the codebase. Often a single ack search is enough to find the same bug in many places. Next, consider if there might be other conceptually similar versions of this bug elsewhere. Ideally you’d also follow The Five Whys and discover how this bug got introduced, how it got past code review and QA, etc.

Again, this advice may seem obvious, but consider someone’s natural instinct when a user complains. These complaints usually come in the form of a vague problem (e.g. “it won’t let me change my email address”). First you figure out what the real bug is (e.g. “The form for changing email addresses doesn’t show a confirmation message”). Bugs usually come in very specific forms like this. It’s not uncommon for a programmer to simply fix the bug and move on. But it’s important to stop and consider if similar bugs may exist elsewhere (e.g. “how form confirmation messages work throughout every part of the app”).

It’s the sign of a mature programmer to ask “why” and consider preventing future bugs of a similar type.

Example: A broken URL on Close.io

I recently noticed a problem with a specific URL on our site was not working. I discovered the cause was that two Python view functions in our Flask app shared the same name, which just silently breaks one of them. My first instinct was to rename the broken view with a unique name, and move on.

But I remembered it wasn’t the first time this had happened and I recognized it likely wouldn’t be the last, so I thought about the problem more broadly. I knew a syntax issue like this should be detectable, so I spent some time setting up pylint and reviewing its results. Pylint uncovered another case of the same error, as well as other types of logical errors elsewhere, which I fixed. Finally, I added pylint to our continuous integration system to automatically detect any Python syntax issues in the future.

So rather than fixing the broken URL, I fixed all cases where URLs were broken for the same reason. I also found and fixed other unrelated instances of “detectable” syntax issues. And I also automated this process so that this entire class of issues can never happen again. Do you see how much more powerful this type of fixing can be?

Once you’ve discovered the specific causes of a bug, there’s no better time to find and fix other similar bugs. Even when the roadmap begs you to move on, the benefits of squashing related problems are even stronger:

  1. It’s good practice to fix bugs before writing other code (#5 in The Joel Test)
  2. If you can discover and fix bugs before more users experience and report them, you’re preventing user pain.
  3. You’ve already done the hard part of figuring out the specifics of the problem. If you don’t completely resolve it, you’re forcing a teammate or your future self to have to waste time relearning the same thing!

Don’t just fix bugs. Fix an entire class of bugs.

Application: Designing Features

The temptation to solve a single problem at once is even larger when it comes to features. Features are often a response for solving a user’s pain point, or an idea designed to empower your users in a new way. Naturally, the team is excited to ship as soon as possible.

Furthermore, a good product designer will optimize a feature to be as simple as possible for the specific workflow it’s designed for.

The problem is that over time, rather than designing one cohesive experience, you’ve glued a bunch of individual features together. If you’re only thinking about solving one specific problem at a time, you’re missing the bigger picture of how everything will fit together.

Software written in this way turns out to be super complex because hundreds of small problems were solved separately rather than a few big problems being solved elegantly.

Don’t design a single feature; always be designing for the bigger picture.

Example 1: Close.io Search & Filtering

An example where I think our team nailed this early was with search and filtering. From ElasticSales we knew that salespeople would want to slice and dice their leads in a million ways.

When starting Close.io it would have been understandable if we solved this initially by just slapping a couple of the most commonly requested filter options, like “Lead Status”.

However we knew that this was a narrow and short-term solution. It wouldn’t be enough to last and wouldn’t be enough to “wow” people. Quickly, power users would outgrow our simple filters and we would be forced to keep adding additional one-off filters and complexity. We’d have to keep redesigning as the number of filters grew and redesigning again for each new idea like exclusion filters or nested “OR” conditions. We would have started fast but slowed very quickly.

Instead, we designed a framework to solve the larger problem. We invented a search language and then UI to allow filtering by a very large number of useful sales attributes and combine them together with boolean and/or/not keywords. It took longer to do it this way than just adding a couple basic filters. But we established a paradigm of how searching and filtering worked in Close.io that has powered innumerable use cases our customers needed and has lasted 2+ years. Our customers rave about its power, and PandoDaily wrote about it.

I’m definitely not saying we had to build this feature to 100% completion from day 1 (and we didn’t – we still iterate on it today – and in many ways it’s very far from complete). But thinking through a scalable solution for this problem rather than slapping on a few quick filters has given us a big advantage. Having an end goal in mind allowed us build a version 1 that didn’t have to be thrown away when we built v2 and v3. We have ideas for what an amazing version 5 and 10 may look like, and we won’t have to start over – all because we planned ahead to solve search & filtering more broadly.

Example 2: Close.io Reporting

Some of our competitors have dozens of individual “reports”. They tack on a new report every few weeks because users always want more reporting. Close.io was really far behind in reporting but the thought of adding dozens of reports made us want to cry. So instead we built one super powerful charting tool (Explorer) that, in one fell swoop, allows you to visualize almost any attribute of your teams’s sales activity.

Example 3: Close.io Bulk Actions

We needed to build a way for users to “bulk delete” all their leads. Rather than building this alone, we designed a system that would work for not only Bulk Delete but also Bulk Edit and Bulk Email (two other features we knew we wanted to build). Because of designing for this, we were able to later launch the additional two features within a very short period of time. Coding the two additional features became much simpler and the UX for all bulk actions was considered together rather than tacked on without cohesion.

Architect your product to solve an entire class of problems at once.

If you don’t, you’ll end up with software that’s missing important features and users will quickly outgrow the one thing you helped them with. Or you’ll keep tacking on additions in a non-cohesive way which makes a complex product over time.

Said another way: it’s easier to end up with both successful users and a cohesive UI & UX if you solve and design for a few big problems rather than a bunch of individual little ones.

Application: Refactors

Technical debt can clearly become a big problem and slow development. But it almost never feels worth rewriting something just for the sake of code quality. The benefit of doing projects solely to “pay back” technical debt is hard to justify.

The best time to solve technical debt, refactor code, etc. is in the midst of making other changes to that part of the system. When you’re working on an improvement involving a problematic part of the codebase and you’re considering making bad code even worse… go ahead and take the extra time to refactor and improve it. There’s no better time to do so, since you’re already having to grok how it works and carefully test those parts related to your improvement.

Application: Redesigns

When redesigning how one part of your product works, consider how the rest of your product works. It may be easier to solve multiple problems that relate to each other all at once.

Example: Close.io Onboarding Process & Email Setup

We wanted to introduce a set of onboarding steps for new Close.io users. One step would be an easier way to connect your email account (for our 2-way email syncing to work) rather than having users do so later in Settings. What we did is build and launch a few features all at once:

  • Onboarding steps for new users
  • Simplify getting email account credentials by:
    • Auto-detecting your email service, IMAP/SMTP hostname, port, etc. when possible
    • Consolidating setup of incoming & outgoing email settings into one step
    • Use OAuth instead of passwords when a Gmail / Google Apps account is detected
  • Support for multiple email accounts & identities per user

Not all of these features were crucial for the main priority at the time, which was to improve onboarding and make it easier to setup email. But they made a lot of sense to build together, since they were interrelated. We would have had to redesign, recode, and retest the Email Settings page regardless so it was the perfect time to design it to support setting up multiple accounts.

Supporting multiple accounts is a valuable feature that we always planned on building. But if we hadn’t built it alongside these other features, it likely wouldn’t have become a big enough priority to get built on its own for quite some time. By building to solve multiple problems at once, we were able to do more, faster, than had we been trying to solve independent problems in serial.

Risks & Rewards

You may now be thinking, “Isn’t this scope creep, and isn’t scope creep a bad thing?”

Indeed, if you keep expanding the scope of your projects to solve more and more problems you will never ship or meet deadlines.

But I’m actually advocating for more planning. More deliberateness in your design decisions and planning. More hesitation before starting projects that only solve only one problem. Design your product with end goals in mind. Design code and processes with your future team in mind.

Expand a project scope opportunistically where it makes sense. Reschedule items onto the roadmap sooner if they are easier to build alongside whatever your current priority is. Often you won’t return to a problem for many months or even years. So if you can put an entire set of problems to rest all at once, do it even if it takes a bit longer.

The principles I’ve been talking about should help you make a much better product over time. When you solve one problem, it’s not that much harder to solve a bigger class of the problem.

The way to keep from turning this advice into scope creep is to slow down. Not slow down in the sense that your team & product shouldn’t be moving quickly. But slow down in the sense that you should do less, but better. Do fewer things, but more that have longterm impact. You can’t do this for everything, but try to do it for the important parts.

So the next time you design a feature, fix a bug, or otherwise try to improve your product, ask yourself, “Can I solve multiple problems at once?”

Add A Comment

My mobile workstation setup

Since my wife got a nursing job in Stockton, I’ve drastically increased the time I spend working while traveling, in coffee shops or hotels where I don’t have my typical desk and monitor setup. Since I get a ton of compliments and questions about it when I’m working from Starbucks all day, I thought I’d share my ultimate mobile workstation guide.

Read the rest of this entry »

Add A Comment

How one of my tweets landed Close.io a $585/month customer

One of my tweets is featured in an article on Mention.com:

How Close.io Closed $585 in Monthly Revenue from 1 Tweet.

Check it out!

Add A Comment

Launched: ArticleListen.com – integration between Pocket & Umano to hear your saved articles read aloud

I built a quick mashup/integration between two services that I love using, that I thought would be “better together”. It’s live at ArticleListen.com.

I use Pocket to save a queue of any article (blog post, news story, etc.) that I see on Hacker News, Twitter, Facebook, etc. There’s a web & mobile browser extensions for saving articles you see, and Mac & iOS apps for reading these articles later all in one place, even offline.

Using Pocket can be good for productivity because you may see a headline that interests you, but you really shouldn’t be reading it now. By saving it to Pocket you know you can easily find and read it later. I’ve got a few hundred articles saved from over the past couple years. I often read a few articles at a time, but they still build up.

I also use Umano, which is a service that has professional voice actors record narrated articles from across the web. It’s perfect for commuting. Many of the articles are only a few minutes long, so even a quick trip to the store or walking to the train can be enough to hear an article or two about something that interests you. Tech, current news, etc.

Umano has some article discovery built in (a “popular” page and a way to see which articles your Facebook friends on Umano liked), however they have thousands of articles already recorded and so finding what you really want to listen to is still difficult.

Then I realized that all the articles I wanted to read or listen to were already saved in my Pocket queue, so during part of a couple weekends I put together this site to do a few things:

  • Look through my Pocket queue and identify which articles were already on Unman
  • Allow me to very easily add matching articles to my “playlist” in Umano
  • Also allow me to “Vote” in Umano for the articles that are already in my queue
  • Add “tags” into Pocket for articles that were added to my Umano playlist, so I can easily archive those in Pocket

Umano does have a Chrome extension (and generic bookmarklet) for “voting” for articles, but I wanted my primary queue to be something like Pocket, which is better built for general purpose article saving, I didn’t want to have to save every article to two places, and I mostly wanted to listen to the articles that were already in my queue.

Check it out: ArticleListen.com

Feedback is welcome.

Built using Python/Flask and Bootstrap.

Future improvements I’d like to make: It should continually monitor a Pocket queue for new articles ongoing – looking for matches and adding them to Umano without any user interaction. At the moment you just have to login to the site occasionally.

Comments (2)

The Elements of User Onboarding

I just finished reading “The Elements of User Onboarding” by Samuel Hulick. I discovered the book through the excellent site UserOnboard.com which has chronicled every screen in the onboarding process of several web and mobile apps and added great commentary (positive & negative) on each screen.

If you help make a web/desktop/mobile app, I highly recommend going through a few of these teardowns, as they alone will make you re-think some parts of your onboarding process. These teardowns together with the book have given me lots of great ideas for drastically improving the liklihood that a new user of Close.io will become successful.

For each chapter, I wrote down a brief summary or simply something that stood out to me. By all means, this isn’t a replacement for getting the book – but a teaser and reminder to myself what I read!

Read the rest of this entry »

Add A Comment

My interview on Sales4Startups about Close.io

Sales 4 Startups published an interview with me about Close.io.

Interview: Phil Freo, Engineering Lead @Close.io

Sales4StartUpsTell us about the Close.io story. How was it started? What problem were you trying to solve?

Phil: Close.io was developed as an internal product to make our own salespeople at ElasticSales more efficient. Our company was doing sales for a bunch of companies (with different types of sales processes and needs) and through all these difference sales campaigns we recognized a lack of good software geared at the day-to-day tasks a salesperson faces. Our team needed to be able to make many phone calls quickly, send more emails, and see a history of sales activity for any given lead without having to do a bunch of manual data entry, and surprisingly none of the solutions we tried seem to actually be designed to make salespeople’s lives better in these ways.

After several of our customers asked if their salespeople could use our software (since they saw our productivity improvements from it), we decided to focus on productizing it, and Close.io was born.

Read the entire post.

Add A Comment

Coinbase Bug Bounty Award

Coinbase is one of the best Bitcoin related sites/services. They’re certainly the easiest way to buy or sell Bitcoin if you have a U.S. bank account. When I saw their Bug Bounty program where they offer $1,000 USD worth of Bitcoin if you find a security vulnerability, it improved my trust in their security, but of course also made me want to look for security bugs…

Read the rest of this entry »

Add A Comment

My IKEA standing desk

I’ve been wanting a standing desk at home, ever since our old Elastic office had standing desks. The key though is getting it to be the perfect height, and not spending a fortune. After some careful measurements I determined that my standing desk surface should be exactly 40″ from the ground, so that my arms at ~90 degree angles would fall perfectly on them when I’m standing (I’m 5’6″ or 5’7″).

Read the rest of this entry »

Comments (1)

How to view a color diff of text from two PDFs

I recently had to look at two different legal documents (PDFs) that were mostly the same, but I wanted to spot any differences.

My first attempt was to install the cross-platform GUI tool DiffPDF. This mostly worked but was annoying because it seemed to basically only diff within a page – so if your paragraph bumped to another page in the new version of the document, you couldn’t really spot changes.

Then I installed pdftotext with macports: “sudo port install poppler”. From there you can diff the two text files, like normal.

However the format was still not ideal in the standard FileMerge, “diff” or “vimdiff” programs (even with ignoring whitespace) because it would show an entire paragraph changing even if just one word did. And it would also show issues in all the places where text wrapping happened on. different words

So finally I found a couple other useful tools, wdiff (for word-by-word rather than line-by-line comparisons) and colordiff to colorize the output. Installed with: sudo port install wdiff colordiff. And threw in a trick to avoid needing the .txt temp files.

wdiff <(pdftotext old.pdf -) <(pdftotext new.pdf -) | colordiff

Beautiful! Now I can easily spot the specific words, nicely colored, that have changed.

Only thing I would improve is for it to print only the lines with changes (plus 3 context lines above/below), rather than all lines.

Comments (1)

Render a PDF from html using xhtml2pdf and mimerender in Flask

I’m working on invoice/receipt generation for Close.io and wanted to create simple PDFs using nothing but HTML.

Using Flask, mimerender, and xhtml2pdf, here’s how:

Add A Comment

« Previous entries Next Page » Next Page »