How Trello Wowed Me By Handling An Edge Case

We are using Trello for our product development planning at The Food Corridor. Previously we were using Pivotal Tracker, which I chose, but a new team came on to help us and they were more comfortable with Trello. I may do a compare and contrast of these tools in the future, but for now I wanted to celebrate the beauty of a well designed piece of software.

I don’t mean how Trello looks, though it certainly looks pretty. I mean how they handle UX edge cases. I ran into one the other day, and it blew my mind that Trello acted as I had hoped.

Here’s the situation. We use the Trello numeric card ID along with this git hook:

#!/bin/sh

# from http://stackoverflow.com/a/16061192/203619

if story_id=`git branch |grep '*'|sed 's/.*-//'`
then
    echo "[#$story_id]" >> "$1"
fi

To help tie commits to stories. If someone is working on a story with the id 123, they work on a feature branch called add-new-feature-123. When committing, they may write a message like: “Updated the message to the end user when they save”, and this hook will automatically add “[#123]” onto that commit message.

When someone is looking at the code six months or two years from now, they will be able to look up that story and get context about why the message was changed beyond what was in the commit log.

We were cleaning up old releases in Trello and had moved all the released stories to another board. However, I noticed that the cards were renumbered when they were moved to that board. Whoops! That meant that the commit messages wouldn’t be useful in looking up the cards. I had discussions with the product manager and we decided to keep all future releases on the same board to maintain the numbers–we’d just archive them (it’s worth noting that when you search for 123 and the card is archived, the search won’t return the card unless you add the is:archived search operator to your query).

However, I was ready to write off the cards that had been moved to the other board. What were the chances that if I moved the cards back to the original board, the card numbers would be maintained? I gave it a try just to see.

Trello did the right thing! The cards, when moved back to the original board, assumed their original numeric ID.

I am very impressed, as I imagine there are a very small portion of Trello users who care about this behavior. As someone who doesn’t really care about design but does care about user experience, that is an example of attention to detail that I wanted to call out and praise.



Smashing: A Quick Dashboard Solution

I’m putting together a business metrics dashboard for The Food Corridor (what is old is new again, I remember a project at XOR, my first job out of school, that was all about creating a dashboard). I could have just thrown together some rails views, but I looked around and saw Smashing, which is a fork of Dashing, a dashboard project that came out of shopify.

Smashing is a sinatra app and is fairly simple to set up. It looks gorgeous, a lot better than anything I could hack together. I could install it on a free heroku dyno. Even though it will take a bit of time to spin up, it is now running for free. Smashing has nice MVC separation–you have dashboards which assemble widgets, and then jobs which push data to widgets on a schedule. Sending data looks something like this: send_event('val', { current: current }) where val is referenced in the widget.

You can create more than one dashboard (I did only one). They aren’t customizable by non developers, but once the widgets are written, they can be created by someone with a modicum of experience editing HTML.

Some tips:

  • Smashing stores its state in a file. If you are running on heroku, the filesystem is ephemeral. You have two options. You can store the state in an external data store like redis (patch mentioned here, I didn’t try it). Or you can rely on the systems you are polling for metrics to maintain the state. That’s the path I took.
  • The number widget has the ability to display percentage changed since last updated: send_event('val', { current: current, last: last }). Make sure that val is an integer–I sent a string like “100000” and that was treated as a zero for purposes of calculation.
  • If you are accessing any external systems, make sure you inject any secrets via environment variables.  For local development, I used dotenv.
  • You’ll want some kind of authentication system.
  • The widgets that come with Smashing aren’t complicated, but neither are they documented, so prepare to spend some time understanding what they expect.
  • I grouped jobs, which gather the data, by data source.  You can send multiple events per job, and I thought that made it clearer.  Connections to APIs or databases only needed to happen once as well.
  • The business metrics which I was displaying really only change on a monthly basis.  So I wanted to run the data gathering immediately, then in a week or two weeks.  Because of the ephemeral state, I expect the second run will never happy, but wanted to be prepared for it.  I did so by creating a function and calling it once on job load and then in the scheduler.

Here’s pseudo code for the job that pulls data from stripe:


Stripe.api_key = ENV['STRIPE_SECRET_KEY']

def stripe
  # pull data from stripe...
  send_event('stripeval', { current: current })
end

stripe

SCHEDULER.interval '1w' do
  stripe
end

Smashing is no full on technical metrics solution (like Scout or New Relic), but can be useful for displaying limited data in a beautiful format with a minimum of developmetn effort. If you’re looking for a dead simple dashboard, Smashing will work for you.


How we work around Stripe’s seven day wait for new account payouts

Many of the kitchens on The Food Corridor are setting up their Stripe accounts for the first time.  They are coming to us to help with their billing, invoicing and scheduling issues.  One of the selling points is that we collect payment information from their clients and bill the clients automatically, helping kitchen cash flow.

However.

Stripe has the concept of a payment (which is when the buyer gets charged and money moved into Stripe’s system) and a payout (which is when the money moves from Stripe’s system into a seller’s bank account).  These are definitely not synchronous, for what I assume are concerns about fraud and money to be made from float.  The first time you charge against a Stripe account, they hold the funds for 7-10 days at Stripe before paying out.  As a user, you can see the funds, but you can’t access them.  (You can’t pay rent with a Stripe account balance.)  This was frustrating to many of our clients, and a horrible first experience with our billing system: “we said we’d help with your cash flow, and we will, it will just take a month”.

To alleviate this, as soon as their account is set up, we make a small charge against our own credit card and send it to them (a pre-charge).  This starts the clock on the 7-10 days mentioned above.  This happens before the first real client billing, which means that the first real client billing will be paid out in 2 business days.

One of the things I love about working on a product for a period of years is that you get to make these types of refinements which are not technically difficult, but truly matter for the user experience.


Turning Zendesk tickets into help center articles

We used Zendesk as part of our ticketing system at The Food Corridor. (Other parts are phone calls and an email inbox.)

I’ve been pretty underwhelmed with Zendesk as a ticketing system–I find it hard to understand and the UX is overly complicated for our needs. However, we recently moved a large number of FAQs into the Zendesk help center, and I found that aspect of the software to be awesome. I’m especially excited to see if it cuts down on customer interaction by being integrated into the web widget.

There’s also a cool way to take comments on tickets (typically with answers to common questions) and turn them into help center articles. Here’s how you do that:

An admin needs to install this Zendesk application and I recommend setting the ‘draft only’ option.

Then, the steps are:

  • Go to a ticket.
  • Click on the ‘apps’ button in the upper right hand corner
  • Click ‘post article’
  • Select the comment you want to post (you can only pick one)
  • Enter your title
  • Modify html if you’re comfortable, but realize it will be a draft article regardless, and you’ll have a chance to change it later)
  • Click ‘next’
  • Choose a section of your help center
  • Click ‘post to section’
  • Click the ‘view’ button (for some reason the edit button didn’t work for me)
  • Click ‘edit article’ (upper left)
  • Modify the content if needed using the guide editor, which is nice and WYSIWYG
  • Change from ‘draft’ to ‘published’ to make the answer available

I remember a knowledge base project over 15 years ago that was aiming at sharing knowledge across our organization. It flailed. Zendesk help center seems to be well on the way to achieving such aims.


Stripe Connect And Refunds Initiated by Connected Standard Accounts

We are using Stripe Connect to handle our payments.  Our sellers (kitchens) have standard accounts, which means they have full access to the Stripe dashboard (I believe these used to be referred to as ‘standalone accounts’).  We are using destination charges so charges run against the platform account and are then immediately transferred to the kitchens, less any application fees (this is not entirely accurate, but good enough for this post).  All well and good.

Some of the kitchens noticed they could refund a charge via their Stripe dashboard.  Refunds happen for a lot of reasons–maybe the food business was inadvertently charged or they had some issues in the kitchen.  So, the kitchens refunded, and the food businesses waited.  And waited.

Meanwhile, when The Food Corridor ran numbers looking at revenue, we saw aberrations.  There was extra money in our bank account.  Now, every business wants more revenue, but they tend to like to know the source.  So, we wanted to figure out where the extra revenue was coming from.

I looked into this and, after some investigation and emails with Stripe support, determined that the kitchens were refunding money to us.  However, it wasn’t flowing through to to the food business from whence it came.

Here is the flow of funds when a charge happens:

food business -> platform -> kitchen

When a refund happens, if initiated by the platform:

kitchen -> platform -> food business

When a refund happens, initiated by the kitchen

kitchen -> platform

Tracking down exactly which charges were being refunded by a kitchen was tedious, but easy to do if we knew which kitchen had performed the refund.  If we didn’t know that, we’d have to search through all the connected accounts for the matching charge.  It was far easier to contact Stripe directly and ask them to hunt it down with some internal tools.  Providing the date of the transfer, the amount and the id was helpful to Stripe support.

After we knew which kitchen had performed the refund, it was easy enough to find the charge, and then refund it to the customer, completing the loop.  Here’s the flow of funds for that:

platform -> food business

If you are using Stripe Connect and are using the destination charge method, and your sellers have standalone accounts, make sure they know they can’t issue refunds from their Stripe dashboards.


When doing a startup, don’t forget to calculate emotional runway as well as financial runway

When I joined The Food Corridor, the concept of financial runway was well known to me from my consulting days.  You figure out your monthly expenses, your savings, and any income you have coming in.  Divide your savings (or at least the amount you want to spend) by the expenses less the income, and you get the amount of time available to work on the startup before you run out of money.

You definitely want to pad this a bit, because if you run out of money, you’ll need some time to find another source of income.  You can also pad this with debt, selling other assets, part time work, investment, etc.  Heck, maybe the startup will even make some money too.

But the goal is to have an idea of how long you can go before you have to call it quits for financial reasons.  Then you can see if you think you can build the company in that amount of time.  (Hint, it’s going to take longer than you think to build the company.)

Emotional runway is another key aspect of surviving a startup.  Startups are full of a lot of stress.  Some examples:

  • Making decisions on limited data
  • Dealing with a product that is broken because of the speed at which you built it
  • Screwing up and apologizing to customers for said screwup
  • Dealing with financial uncertainty
  • Hiring
  • Firing
  • Limited or nonexistent support structure
  • Trying to figure out how to build a company
  • Personnel conflicts
  • Missing family time because of work
  • Lack of vacation/benefits
  • And, of course, the possibility of running out of money

All of the above make it tough to ‘tough out’ a startup.  These are all costs that you will have to bear.  Just like you only have a certain amount of savings to spend down, you also only have a certain amount of emotional wealth to spend.  (There are times when a startup will deliver emotional wealth too.)

One of the hardest parts of the current startup for me is keeping an eye on my emotional runway.  Taking some time off, celebrating successes, being open about the stresses with co-founders and family, and just being aware of what puts “money” into the emotional piggy bank and what takes it out are all ways I’ve dealt with this.


Useful Rails Gems: dossier

Writing reports is something that is crucial to any business application.  There are a number of nice reporting solutions.  I haven’t done a survey recently, but I know that Pentaho has an offering and Crystal Reports is another one.  Note that the gorilla in the room is MS Excel, because most anyone doing a report is going to want to pull it down and do additional data manipulation.  You should never try to compete with Excel.

For The Food Corridor, we didn’t need a full featured reporting solution, but we did need to pull data from the SQL database and expose it in CSV and HTML tables.  The dossier gem takes care of this.

What I love about dossier is that you can write the reports in either Active Record syntax or in SQL.  I know SQL pretty well, so it’s easier for me to use that avenue, but if you’re just getting started with Rails, I could see how the Active Record syntax would be helpful.  After writing the query, dossier takes care of much of the grunt work of CSV generation or HTML table generation (there are other output formats, but I don’t use them, so can’t speak to them).

You can preform arbitrary formatting on the SQL response, including hiding columns and running ruby code on the value pulled back from the database.  The report class is just a ruby object, so you can also reuse chunks of logic or SQL across reports.  Column names are turned into report headers.  (I wrote previously about testing such reports.)

Authentication is a bit weird out of the box but works.  There’s also documentation for other authentication/authorization options.  Dossier can also take database configuration from the initializer file so you can easily offload your reporting traffic to a read only replica.  (We’re not there yet in terms of traffic, but I can see the day coming.)

The dossier gem is so easy to user that I can get a full featured reporting solution created in only an hour beyond writing the SQL.


Evolution of admin features

Time is short in a startup and the edge cases are many.  I have noticed that when I am building features for The Food Corridor, especially admin or edge case features, there is a progression based on frequency of feature need.  An example of this is something like handling a refund, which is not a core use case.

  1. The first time, the issue is handled via a developer.
  2. If it happens more than once, the process is documented in a google doc.  It might be triggered by an email from another part of the system.  We have an entire google folder called ‘operations’ which is full of such documents.
  3. The developer automates the process via a rake task.  The rake task is a thin layer around a service class, which is tested.
  4. Non technical admins get access to the process via a web interface.  The web interface plugs into the service class as well.  This web interface may handle only part of the issue, and require access to other systems (in the case of a refund, access to the payment processor).
  5. Non admin users get access to the process via a web interface.  This web interface is fully fleshed out.

For core functionality, you obviously want to push the ability to self serve to the end user as soon as possible.  It simply wouldn’t make sense for us to build out the ability to schedule bookings, limit it to a developer or admin user.

But for a lot of functionality, this progression is helpful.  The developer has time to fully understand the issue by handling it him- or herself.  The documentation generated by handling the issue manually is a great start for the requirements document.  And if an issue only pops up once every quarter, or even more rarely, a minimum amount of developer time is spent on it.  If something happens often, it is far more likely to get automated.


Moving from a feature to a product to a company

This post from Seth Levine discusses the path of a startup along this continuum:

Features provide specific point value to users. Products stitch together related features into bundles that are essentially universal in their need across the problem set you are solving (put another way, if each of your users buys your “product” for a different reason you’ve probably just created a feature set, not a true product). Companies have product that is broad enough in its use and impact that a huge number of users gain value from it in a market that is both large and where the user need is similar enough to drive broad adoption of the same solution.

It’s an interesting perspective that is worth evaluating your current organization against.  Are you in the feature, product or company phase?  Rapid application development with libraries and modern frameworks makes it really easy to move from a feature to a product phase, even though some organizations that stay in the feature space–something like this store locator app or a data product like Mattermark where extra work is required to gain value.  We certainly found that when we started The Food Corridor that features alone weren’t going to be defensible or sustainable, so we moved quickly on to being a product.

It’s also worth noting that “Company” status for a VC like Seth is probably a lot larger than a sustainable SaaS company which can feed a small team and provide a lot of value to a niche market–companies like Small Farm Central or Fileboard.  You don’t have to be a “Company” to be a success, in other words.  You don’t even have to be a “Product”.  But knowing where you are in the continuum can help you define your focus.



© Moore Consulting, 2003-2017 +