Departing The Food Corridor

Life is full of endings as well as beginnings. It’s easy to celebrate the latter, but the former are just as important. I joined The Food Corridor just about two years ago. This Friday is my last full day with the company. The company is left in very capable hands and has some exciting new plans. I look forward to cheering their success from the sidelines.

I am a firm believer in saying thank you, so I’d like to give some thanks to folks who have helped me out on my TFC journey.

The customers: Like any startup, we had to search to find our niche (“ideas are nice, but execution is a bitch”). But I’m glad to have been able to help shared use kitchens “spend less time in the office and more time in the kitchen”. What great people. They are working every day to help their clients (food businesses) build sustainable economic businesses. I learned so much and have a tremendous appreciation for the economic, regulatory and every day challenges kitchen managers face. Our clients were also forgiving of my mistakes, especially around matters of money and user experience. I appreciate their trust and patience.

The investors: A number of Colorado based angels and funds took a chance on TFC. Thanks for the rigor of your due diligence, the support you gave, and of course for the cash that is helping take TFC to the next level. But thank you most of all for your belief.

The informal advisors: TFC had a tremendous crew of folks helping out in many many ways with advice and connections and cheerleading. You all know who you are, and I appreciate every minute you gave to help TFC get where it is.

The formal advisors: We had a number of advisors who took hours and days out of their busy schedule to help out a newbie company, whether by reviewing documents, spending time at an all hands or investing. Thank you Christine, David and Mick.

The team: Small, nimble and potent. I learned something from each and every one of you. Charlie, thank you for the dashboard concept and your time. Lindsay, thank you for volunteering your time to make TFC better, and to help me see the system in new ways. Stephanie, I appreciated your questions and willingness to try new things and I’m so glad you found the right spot for you. Julie, I appreciated your focus on process and customer support. Chad, thanks for making those cold calls. Ben, thank you for your financial rigor and patience, as well as the ‘bigco’ perspective. Jim, Marcus and Joe, thank you for your early support and enthusiasm. Rachael, thank you for your good humor, food business perspective and constant attention to the TFC public image. Meghan, thanks for your attention to detail, your humor, your endless drive to get it right, and of course for your wicked intercom chops. Nenad, Luka, Michael, Seamus and Luciano, thank you for relentlessly putting the customer exactly where they should be–front and center. (If I failed to mention anyone above, please accept my apologies.)

My co-founder: Ashley, I wish you (aided by the TFC team and support system, of course) all the best in taking TFC to the heights I know it can achieve. Thank you so very much for the opportunity to hike alongside while I was able.

My wife: I can’t imagine pursuing any startup without the support of my spouse. The journey is crushing at times even with enthusiastic help. She’s been a sounding board, supporter, cheerleader and true believer. Thank you so much.


Look for the value of the param, not its existence

We are rewriting the front end of the application on which I work. Several of the forms which gather data that drives the application previously had checkboxes, which would set a value to true or false in the database.

Some of the checkboxes were ancillary, however, and didn’t result in a database value. Instead, they were used to calculate a different result depending on whether the checkbox was checked or not. That result would then be saved to the database. This was all tested via rspec controller tests.

In at least one case, the calculation depended on the existence of the parameter. Checkbox parameters are sent when they are checked and omitted when they are not.

Then we changed the forms to radio buttons.

Uh oh.

Instead of sending the parameter if the box was checked yes or not sending the parameter if it was checked no, we sent yes if the radio button was checked and no if it was not.

Uh oh.

The tests continued to pass, because they hadn’t been updated to the new values.

Uh oh.

So the calculation was incorrect. Which meant that the functionality that depended on the calculation was incorrect. Unfortunately, that functionality was related to billing. So I just spent the last few days backing that out, checking with clients to see what they actually intended to do, and in general fixing the issue.

The underlying code was an easy enough fix, but this story just goes to show that software is complicated. Lessons learned:

  • favor a test for an exact parameter value rather than parameter existence
  • when changing forms, consider writing tests with the new input values
  • integration tests that drive a browser would have caught this issue. These are much slower so need to be used judiciously, but are still a valuable automated test

 


Product Roadmapping For Team Alignment

One of the issues with a startup is that you have so many opportunities and so little time. This is overwhelming, and can lead you to pursue opportunities that fall in your lap, or that your squeaky wheel customers offer up, rather than thinking strategically about where you want to go and how best to get there. This is heightened by the ‘everything is on fire’ feeling that arises occasionally.

At The Food Corridor, we just spent two days roadmapping (we being The Food Corridor team and the OTL Ventures team). Normally I’m not a fan of meetings. I find they often are synchronous status information transfer that could be better handled via email or slack. As an aside, here is a great post on running a meeting.

But this roadmapping meeting was great. The team was all in the same room and spent the first day brainstorming opportunities (with no limits on the feasibility of the suggestions, but some guardrails around focus). The second day we ranked all opportunities according to positive impact and effort required (both in a number of dimensions). As you can imagine, these were two long days. However, the outcome is a list of high impact, low effort opportunities.

However, I feel the real value isn’t in the list, which will be so long that it won’t be accomplished in the next two years, let alone by the next roadmapping session is scheduled. There were two main items that came out that I found really valuable.

First, that were discussions with all relevant parties about real issues in the business. Sometimes we get so busy delivering that we don’t pop our heads up and see the bigger picture. As all imperfect products do, The Food Corridor causing some pain for our customers. (If you work on an imperfect product, please let me know as I’d love to see one.) These pain points were front and center during the discussion, and we had people from multiple different functional areas opine on the problem and possible solutions.

There was also a ton of value in creating shared alignment. As I watch this business be built I am astonished at how much time and effort needs to be spent making sure everyone is pulling in the same direction. When I ran a business on my own (as a solo consultant) or when I am an employee, the focus is usually on what I’m doing “in the business”–the day to day execution of tasks to provide the services the company sells. As a co-founder, I’m seeing how important it is to get everyone agreeing on the highest value opportunities–highest value for the business, not necessarily the most exciting or highest value for each individual. This alignment needs to happen with incentives, meetings and communication. The just completed roadmapping session felt like it really achieved that shared alignment.

By the way, if you are a software product company in the northern front range and feel like you could benefit from more team alignment, I’d highly recommend contacting the folks at OTL and pursuing this. Not affiliated, just a happy customer.


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.



© Moore Consulting, 2003-2017 +