Staying Agile in Customer Support & Development

2-plus years ago, when Coupa’s first customers came on board, we needed some way to communicate with them on issues and questions.  I had experience how Oracle did it and wasn’t about to go down that route.  Customers called in or logged issues directly into this homebuilt customer help desk system called Metalink.  Then Support spent days with a ticket trying to gather info and trying to reproduce.  If it was an actual code problem, maybe it got to Development a week later in another application called BugDB.  Support worked in Metalink, developers worked in BugDB and there was plenty hidden between the 2.  But that’s the support you get when paying 22% annually of your license fees.

At Coupa, we decided to go with a single system for help desk and issue/bug tracking.  Sometimes we don’t get it right the first time.  Our first solution was a SaaS system, but it lacked one of the main principles that Coupa was founded on:  simplicity.  Customers didn’t hate the system, but it wasn’t exactly user-friendly. Our development team detested it.  It slowed us down and that just couldn’t happen.  It was un-agile.

Graham, our development manager said (I’ll paraphrase), “It just blows….it’s fundamentally unintuitive.”

So one of our guys scanned the world via Google one night and stumbled upon a tiny company from Copenhagen named Zendesk.  They used Rails like us.  They were agile like us. They had free trials like us.  They were affordable like us.  In about 16 hours, our decision was made when our VP of Service Delivery sent an email:

From Ravi’s email…”this product is almost as cool as our app – freakin amazing”

We jettisoned that old system and turned on Zendesk immediately.  A couple months later, Zendesk named Coupa first in their list of customers in their seed investment press release.   It was great to see another Rails company succeeding.

Fast-forward to the present and Zendesk has grown significantly.  Now, headquartered in San Francisco, they have other great customers like Twitter, MSNBC, Scrib’d, IDEO and plenty others.   Most importantly, their solution is part of the collaboration that makes our customers successful and our development team agile.  The team doesn’t waste time on perfect classification of a ticket.  Instead, we get to work on it.  Besides that, it’s got simple and easy reporting, nice ways to communicate new features, and a collaborative forum for product enhancement ideas.  Our product roadmap gets influenced by the suggestions and the dialogue on our Zendesk site.  And we constantly track the percentage of suggestions that we implement and the pace that they’re done.

Without agile development, the cloud, Rails, and open source, I’m pretty sure that companies like Coupa and Zendesk wouldn’t have a fighting chance.  But with them, we’re changing the face of applications for businesses.

Don’t let IE7 ruin your weekend

Last Friday, around quitting time, fellow Coupa developer Ted and I were pairing up on some tickets and decided to attack one last issue before calling it a night. The ticket we landed on was one I had banged my head against for a few hours and only found dead ends. Even worse, it was a total show-stopper. Anyone using only our new Expensing application who clicks on the homepage navigation link in IE7 (which the majority of our customers use) is not directed to our home page – surprise! Instead they are prompted with a “File Download – Security Warning” dialog box and some text about “Type: Unknown File Type”. How bizarre! Clearly IE7 had no idea what to do with the response it received from our server. I clicked save from the prompt and examined the file download. It was our homepage, in all of its HTMLy wonder, now sitting alone and unrendered on the desktop.

My first thought had been – mime type! Having no way to evaluate response headers in IE, I took a shot in the dark and opened up Firebug. Unfortunately nothing was out of the ordinary. This wasn’t terribly surprising given that it does work in Firefox, but I suppose it had been worth a shot. Next I googled around and found that a similar issue exists (websites showing a download prompt instead of rendering in IE7) as a result of having Google Desktop Search installed and active. We don’t have that app (or much at all) installed on our IE-testing box, but whatever interaction had caused that sounded quite frightening. My mind was racing – could an unrelated process on this box be causing this link to download as a file? I calmed down a little when I remembered our QA team had reproduced this first on a different box. On a whim I tried manually appending the “.html” in the URL and – viola – the homepage rendered like a champ. At least I had a way to hack in a solution if I had to, but it was far from ideal.

This time what made the difference was a casual suggestion from Ted to use DebugBar to analyze the request/response Headers. I hadn’t heard of this tool but installed it immediately. A browser restart later I had it open, had reloaded the page and opened up the request and response headers. It was crazy – IE7 was asking for a jpeg (what?!) and we were responding with HTML but saying it was javascript (why!?). With that clue google quickly yielded this post from Hemant Khemani’s blog which clearly describes the exact problem we were having as well as the solution. Essentially IE was requesting a Content-Type of “images/jpeg”, which was not defined in our respond_to do block, so Rails chose our default format – which happens to be the first one you specify.

So the fix was simply to replace:

      respond_to do |format|
        format.js
        format.html {render :template => 'user/expense_only_home'}
      end

With:

      respond_to do |format|
        format.html {render :template => 'user/expense_only_home'}
        format.js
      end

This ensures that your default response header will be HTML. And from now on I will be checking that all of our respond_to blocks for this specific kind of sanity. So in the end, in about 20 minutes we had solved a problem I had previously struggled with for hours and all but given up on. A definite win for pair programming, for DebugBar and for my weekend.

Abstraction Breakdown: Table Aliasing in ActiveRecord

A few things I love about Rails:

  • It strongly encourages you to put code in the right place MVC-wise. This feels good, but even more importantly, it enhances maintainability. (This is true both for other developers that might inherit your code and for three-weeks-from-now you.)
  • The abstractions are powerful, but don’t have too many layers, so if some behavior surprises you, it’s easy to go look at what is actually going on. The one-two punch of open sourciness and simplicity, combined with the inherent readability and conciseness of the Ruby language, makes for productive debugging.
  • Ruby is well-suited to creating DSLs and other forms of metacode that let us as developers solve a problem and then reuse the solution on different data sets with different parameters.

And an involved little problem where these break down:

Within our app, we have lots of places where we need searchable, sortable, configurable views of tabular data. While this is a common enough requirement, it’s one that folks tackle in all sorts of different ways, from pure Javascript implementations to scaffolding generators. Because we wanted the code to remain DRY and maintainable as much as possible, and yet be individually securable via controller/action pairs, we opted to build something somewhere in the middle.

A simplified example declaration, which you might find in WarehouseTypesController:

data_table :warehouse_type,
 [:name,
 :description,
 :created_by,
 {:key => :created_at, :label => "Created Date"},
 {:key => :updated_by, :label => "Last Updated By" },
 {:key => :updated_at, :label => "Last Updated Date"}],
 :find_options => {:include => [:created_by, :updated_by]}

Each table has a base model (in this case, WarehouseType), where each row of the table represents one record in that model’s database table. The array that follows describes the columns to include and/or search in the table, and the find_options are identical to what you’d pass into an ActiveRecord find call. The data_table method itself generates some methods in the host controller that handle rendering, various AJAX actions and CSV export. The :created_by and :updated_by keys refer to associations defined in the model:

class WarehouseType < ActiveRecord::Base
 belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by'
 belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by'

A call to render_warehouse_type_data_table will produce something like this:

Data Table Example

And the advanced search pictured above leads pretty directly to the following SQL:

SELECT * FROM `warehouse_types`
WHERE (warehouse_types.name LIKE 'storage%')
ORDER BY warehouse_types.name DESC
LIMIT 0, 20

Straightforward, right? Well, it breaks down even in the above example when you try to query on the “updated_by” user, because suddenly we may or may not be joining to the users table twice, and any SQL we generate needs to know what table alias to use in the condition. Internally, ActiveRecord uses a table’s name as the alias the first time a table is joined into a query, and then uses an algorithm involving the relevant association names to generate aliases for subsequent joins. You don’t need to know this as long as you’re using the nested hash version of find(), but that doesn’t currently support any tests other than equality, range, and set inclusion. Consequently, for anything more complicated (pretty much all queries we run), we need to use the SQL fragment / array form of find() to prepare queries. A naive version of a find() call for warehouse types that were last updated by John might look like this:

WarehouseType.find(:all,:conditions => ['users.fullname LIKE ?','John%'],
                        :include => [:created_by,:updated_by]

which would generate something like this:

SELECT [redacted] FROM `warehouse_types`
LEFT OUTER JOIN `users` ON `users`.id = `warehouse_types`.created_by
LEFT OUTER JOIN `users` updated_bies_warehouse_types
 ON `updated_bies_warehouse_types`.id = `warehouse_types`.updated_by
WHERE (users.fullname LIKE 'John%')

This won’t work, though- the WHERE clause is using the wrong alias, and will look at created_by users instead. The find() call would need to look like this:

WarehouseType.find(:all,:conditions => ['updated_bies_warehouse_types.fullname LIKE ?','John%'],
                        :include => [:created_by,:updated_by]

The thing is, though, we don’t really know what alias to use. If there’s a default_scope defined, for example, the user table may already be joined, or the query may already be scoped in some other way. Also, the outer joins may or may not actually get generated in the order specified, especially if they’re included as a Hash rather than an Array. (Like most folks with dependencies on external libraries, we can’t migrate to Ruby 1.9 yet.) Our current solution to this problem is indeed to assume particular scopes and a particular ordering to the joins, leading to a data_table column declaration more like this:

 {:key => :updated_by, :label => "Last Updated By",
  :sql_column => 'updated_bies_warehouse_types.fullname' },

I really don’t like this solution, though- it’s brittle, and it requires too much knowledge of both ActiveRecord’s implementation and any additional factors that may modify the model’s scope. This is not knowledge that something in the controller should have. It’s also tricky to test in a low-level way.

Before getting onto the possible solutions, I should point out that we’re certainly not the only ones to run into or describe this problem- there’s more succinct discussion in Rails tickets 2357 and 2087, including a proposal for and code for potential solution #1 below.

So, what do we do? At the moment, nothing- it happens seldom enough in our table definitions that we can get away with hard-coding the exceptions for now, but it limits functionality we can add and is just ugly. Essentially there are 3 somewhat reasonable approaches to actually fixing the problem:

  1. Introduce a way to query what the expected table alias for a particular situation is going to be
  2. Implement operations other than == in the nested-hash form of find(), as in the relational algebra code that may be merged into AR eventually.
  3. Replace alias references with locally-scoped tokens that represent the joins/includes, and substitute in the correct aliases when merging conditions.

These are all quite intrusive, however; the way that ActiveRecord’s merge_conditions calls work today, it doesn’t know anything structured about the JoinCondition objects, so even something simple would be a nasty hack. Given how central this code is, any change would need to be both well-tested and quite speedy. My personal preference is for #3, and when I have some spare time I may try coding this up sometime soon. My hunter in the Outlands may take precedence, though…

Skeletons in /lib: Setting auto_increment in MySQL

Skeletons in /lib is explores the underbelly of Rails apps- the aspects, hacks, and extensions that don’t fit elsewhere, confound new developers, and make each beast unique.

There are a number of business requirements that almost (but don’t quite) map to simple technical implementations. In those cases, we’re often faced with a choice- do we write a separate, more complicated implementation, or do we force a fit with a hack?

Here’s a straightforward one: purchase orders (POs) are a key business document in our system, and when companies issue them they tend to refer to them by number. (”Hey, Apple, when are you planning to ship PO #453?”) As such, they’re a minor but real aspect of the face that our customers present to their suppliers, and some of them want more control over the range. Basically, they’d much rather start issuing POs at e.g. 10,001 than at 1, much like many folks don’t want their checkbooks to start at 1. Technically, though, the PO number is about what you’d expect it to be in a Rails app- the order_headers.id column. (I’m leaving out revisions here- that’s a topic for another time.)

So, how do we give users control over where the sequence starts? Simple, although it’s one of the very few places where we’re not database agnostic:

# Include on ActiveRecord models to get additional MySQL-specific
# functionality.
module CoupaLib
 module MySQLHelpers
 def self.included(base)
 base.extend ClassMethods
 end

 module ClassMethods
 # Returns a string containing the auto increment value (the next insert
 # id) on this table.
 def db_auto_increment
   result = ActiveRecord::Base.connection.execute <<-SQL
   SHOW TABLE STATUS WHERE name = '#{self.table_name}';
   SQL
   result.fetch_hash['Auto_increment'].to_i
 end

 # Sets the auto increment value to the argument.  NOTE: it is the
 # responsibility of the user to make sure the value isn't already in
 # use (will potentially cause duplicate id errors)
 def db_auto_increment=(num)
   ActiveRecord::Base.connection.execute <<-SQL
   ALTER TABLE #{self.table_name}  AUTO_INCREMENT = #{num};
   SQL
   end
 end # Class Methods
 end  # MySQLHelpers
end  # CoupaLib

Now we can inquire what the next ID will be, and set it, in a few interesting places within our app:

  • During customers’ initial self-guided setup, before any documents are created.
  • During automated transactional “cleanup” when moving a test configuration into a production environment. Existing test documents are destroyed, and the sequence is reset to the initial custom value.
  • During merging of potentially-updated Coupa seed data and customer data that needs to be preserved. (That’s another interesting code-meets-real-world problem to look at later.)

User Experience and Development – let’s make a sandwich.

When speaking of the disciplines of design and development, people tend to see them as different entities. As oil and water, rather than peanut butter and jelly. But we have some things in common – we both need to create new things, we both need a ton of creativity to get our work done, we both love finding awesome new solutions, we both love making gorgeous deliverables. We’re closer than you’d think. We could stand to learn a few things from each other.

Designers: become more technical.
Learn why things are or are not feasible before the developer even gets involved. Jump in and code some front-end interactions yourself – move the cycle along quicker and get your intentions across easier. Jump into some of the newer (awesomer) frameworks that make it easier to do the front end side of things. My favorites, jQuery and Ruby on Rails, can really make you feel like you actually know what you’re doing (and sometimes makes others think you know what you’re doing too). Once you see some of the amazing things that jQuery can do – it will open your eyes to tons of new interaction possibilities. And, in particular, jQuery will make you change the way you look at javascript (and use it).

Developers: learn UX methods.
Really, designers don’t bite, and we have some pretty awesome ways of figuring out problems. If you’ve run into an issue, sketch it out. What are the different possibilities? Visualize the solutions by sketching them out and find which one makes sense. Use that napkin that came with your take out or the whiteboard across the room. Don’t be afraid to come up with something stupid… it’s just as easy to toss it out if it doesn’t work – the only person that will know is the janitor, and she’s cool anyways. Remember Ockham’s Razor – all things being equal, the simplest solution is most likely the best solution. Less is more – just because you can do that extra feature, doesn’t mean its going to make the product more usable (most times its actually the opposite). Know that the best User Experience is one that the user doesn’t notice. If the user doesn’t even have to give the UI a second though, we’ve all done our jobs.

The better we understand each other, the quicker and more cohesively we can all work together to make a kickass product.