Consumer-driven API Development

Lars Holzman
Lovepop Platforms
Published in
7 min readApr 11, 2018

At Lovepop we are challenging ourselves to generate a billion magical moments by the year 2030. This requires creating scalable software and-people systems that match perfectly 3D renders created at web scale in real time to physical products that are manufactured with laser cutters, material science, and human artistry. The Platforms Team is responsible for implementing these systems and key to our approach is a version of Service-Oriented Architectures we call Consumer-driven API Development which is a polyglot approach to finding right-sized service factoring.

Polyglot development means using the right tools for the job

Our initial team consisted of developers with a variety of passions — Ruby on Rails, Ember.js, Clojure, React, Java, Python, etc. Most companies, especially larger companies, have their Tech Stack which is core to what they do and which they are very comfortable operating. There was no obvious single tech stack to accomplish all the things that we want to do.

Rails is effective for modeling the state machine of users going through purchasing flows and has a ton of useful Gems for basic web app bootstrapping. Clojure has the advantage of sitting on the JVM (with access to a number of mature libraries for document & graphics handling such as Batik) and gives a clean and productive way to write the heuristics and asset composition system for our wedding product. Our third-party manufacturing system uses Python as its core language and our e-commerce system is happiest to work with Rails & React Components.

In an attempt to move to a single stack we looked into various technologies that could marry some of these things and considered additionally: Scala, Go, Elixir, JRuby, Jython. None worked perfectly across all of our use cases. As a result we settled on using a few different technologies across our teams: Rails for the web-app centric services (users, project state, information collection), Clojure for our 3D design and customization platform (render, art composition, heuristics), and Python for our Operations & Data teams.

After picking these technologies our remaining concern was if we could hire a team of engineers that would both clear our high bar and be interested in working in a heterogeneous stack. This didn’t turn out to be a real issue. We have found a core group of engineers who love our product and mission as well as the technical problems we are solving and who embrace this approach. Typically, these engineers are passionate about some set of technologies that may or may not overlap with what we use, and are curious to learn about the technologies they are less familiar with (“T-shaped” engineers). So, in addition to having a mixed stack we also avoided having a homogenous team allowing us a larger palette to draw from as we work through solutions. Any ramp time we spend as people learn additional technologies seems to payback almost immediately.

…but not necessarily micro-services

Key to supporting a heterogeneous technology stack is having strong service boundaries to separate and normalize across those technologies.

At Lovepop, we started with services from day one. We avoided calling them micro-services as our goal was not to make them trivially small. We focussed instead on domain modeling. For instance, the service that combines different pieces of art into a single card is different from the service that actually stores the art. Six months into the development of our first technical product we already had six services in production across just four engineers. Most of the development was happening in only a few of these services with the others performing trivial functions as our domains were factored too finely. We had started to fall into the micro-service pattern unwittingly with the consequence that it was starting to slow our team down as the operational and mental burden grew to make progress.

We are addressing the operational piece by investing in making service generation and release easier and increasingly cookie-cutter. Despite that, we increasingly appreciate that the fewer services we have per engineer on our team the easier it is for everyone to do their jobs.

Service architecture and team structure

In our Platforms group we organize around cross-functional teams. One potential issue with breaking the teams into full-stack groups is you might end up with silos where each team builds redundant functionality as opposed to finding common ground. This is a potential negative application of Conway’s Law which states that software factoring will mimic the social organization of the team that writes it. Given that we run a lean team there isn’t any room for redundant effort so solving this problem is key.

Looking at the success of AWS, it is easy to link the services they have generated to specific business problems Amazon has solved. For instance, AWS has a number of services that if not directly used by Alexa are definitely tied closely its development (Polly, Lex, Rekognition, etc.). These services are incorporated by teams within and outside of Amazon to make a variety of unrelated products. They also manage these APIs as full-on products with GMs responsible for understanding the needs of the community and internal teams and a fleshed out roadmap (even if it is typically somewhat secret).

There is something very compelling about this model even for a company that doesn’t have thousands of engineers. Following this model we have begun to build API squads within our platform teams:

  • 3D Design Platform is a squad within our Custom Group. Their charter is specifically to bring 3D art customization technology across all of our different product sets. They also are beginning to work with our designers to allow them to focus on creativity and automate the rest.
  • Fulfillment Engineering is a squad within our Physical Platforms group focussed on how to automate the process that forecasts card sales and ensures we have the right inventory in the right places all the time and real-time data on all of it
  • Customer Understanding & Connections is a squad in our Consumer group focussed on learning about how people use our cards and applying that knowledge to helping others find the right card at the right time with the right customizations/note on it.

For an example of how this is actually structured for our wedding product the overall system is broken down across multiple applications consuming two sets of APIs:

Consumer-driven API Development

The key to each of these squads is that the APIs they build will be used across all of the groups. In fact, the leads of the squads are tasked with constructing a backlog specifically for that API as distinct from the product-management driven goals of the group. These backlogs tie neatly to the product goals and are consumer-oriented because they are built to support real features and needs from the application teams and not from an ivory tower. To balance this, the leads are given autonomy over the sequencing and strategy of the API work.

From a management perspective, these teams sit in groups along with the teams focussed on actually building the applications and operating our systems (both people and technology). Since we align these squads with the teams that use their APIs the most under a single lead, the lead has direct visibility into the work the API teams are doing are doing and the importance of those APIs. In turn, the leads also get access to a more cross-cutting view of what is going on (which is great for us and for their career!)

This also allows API squads to stand up “very MVP” solutions which they know won’t scale and backs it up with the fact they have backlog control so they know they will have enough autonomy to fix it when they think the time is right. The hope is this drives even more adoption of solutions which actively cobble together existing pieces as opposed to building everything from scratch. As we grow bigger we want to continue to find ways to use tools like Zapier and higher-level AWS services to minimize the code that we maintain and focus on building software where we want to generate differentiating value and where the problems we are solving are unique to our customers and business.

Also, since we are now talking about APIs as a product and not an implementation detail we have built some clear boundaries into our architecture as a first class notion. We no longer have to worry about ending up with a monolithic codebase BUT we also don’t dictate how how finely teams need to break up their services. This allows them to focus on the actual operational considerations at play when a new service is born (i.e., do we want it to release separately, does it need a different machine type, is it particularly risky so we want to isolate it). So, we get the decoupling and team affinity that microservices have promised without (necessarily) the microservices. We also can hold individual teams accountable for building overly complex architectures as their velocity slows down.

Interested in doing this?

We are always looking for engineers who are interested in building APIs to satisfy real consumer needs or build apps on top of these APIs. If that sounds like you, we would love to chat with you — e-mail us at engjobs@lovepopcards.com!

--

--