Outgrowing an MVP

As 2014 came to a close, our business was rapidly growing. We finally felt like we had the amount of product usage and feedback to validate our product hypotheses in a meaningful way. Our designers and clients were being successful and having fun using our platform, but it was by no means without its deficiencies and kinks.

At the time, our site was primarily a Rails application with some augmented features added to the HTML using Backbone. We started to encounter issues with some of our more interactive features. For example, clients and designers are able to leave feedback and comments on individual items on a designer’s style board, but the experience (and the quality of the underlying code) was subpar. In a more interaction-heavy tool, designers generated the final design package for a client (shopping list, style boards, floor plans, and instructions), but the tool was sluggish and bug-prone. We found ourselves hesitant to iterate on features that we had individually written, much less attempt to modify a feature from someone else on the team! At the same time, we realized the importance of these interactive tools and the potential for additional useful interaction in our product.

Decision Making Process

Since the early days of our product, our engineering team had been discussing the use of a more robust client framework for our product. It was now time to take the plunge to step up the quality of our product.

We began researching the usual suspects. Neither of the engineers on our team at the time had much experience with client frameworks (both of us were primarily Rails developers), so we relied heavily on guidance from our peers. Through prototyping features, discussing and debating, and planning out potential implementation strategies for each framework, we decided on React as our view library and a now-defunct Flux framework for our data layer.

The main argument against React was its nascency: React was pre-1.0 (and still is), the library ecosystem was very immature (this has vastly improved since), and the community was new and had not necessarily settled around conventions (this is improving, and I would argue that an individual organization having strong conventions and guidelines is more important than having strong conventions and guidelines as a community as a whole, anyway). The main argument for React was its modularity: we would be able to incrementally introduce it to our application, feature by feature.

First features

The first feature we built using React was our designer directory. This replaced our previous very simple (and ugly) directory. We felt it was a good opportunity to gain familiarity with a new framework (and to a large extent, a new language) before tackling some core features of our product. We had an inconsistent backend API that served our existing directory, so we started with that. We used Marty, a Flux framework, to handle application state and data. I quickly became acquainted with the few quirks of React. I embraced the limitations imposed by a diligent application of the Flux pattern, promising myself it was resulting in less bug-prone, more maintainable code. Looking back, those first features went very smoothly! react-rails was still serving our purposes well, we hadn’t been bitten by breaking changes in bugfixes (Marty, not React), and we hadn’t yet decided to scrap significant architectural decisions we’d just made. And despite its inconsistencies, our Rails API was good enough.

False starts

Over the next couple months, we encountered the issues mentioned above. We came up against limitations of treating our client application as a small part of our Rails application: it was great to be able to use React components in our predominantly Rails pages, but it became frustrating and limiting to only be able to develop our purely JavaScript features in that context (the Asset Pipeline is not well-suited for JavaScript applications). We struggled with decisions about whether or not to update Marty, React, React Router, etc, all of which were pre-1.0 and actively fixing bugs in releases. We rewrote new features an embarrassing number of times, including when we decided to create a new version of our API that broke the old version. It was rough. But, as with many difficult episodes, I think our team (which was slowly growing at this point) and our application are much stronger because of it.

Continued and Continual Improvements

We have no delusions that we did everything right this time or that we’re anywhere near done. Although we’re quite happy with the design we’ve gravitated toward, our product is not perfect and our codebase is not without its technical debt. It’s a work in progress. Over the coming months, I look forward to sharing more about some of the lessons we’ve learned, as well as some of the things I think we’ve done right.


Check back for more posts. We’ll be sharing some more technical details of the things we’ve learned while building a React+Redux application backed by a JSON API backend.

In the meantime, if you’re interested in the things we’re doing at Laurel & Wolf, I’d love to hear from you about joining our team.