The Split Client Stack

A modern application architecture

Jeff Escalante
Static Dev

--

We get a lot of questions about the way that we build websites and apps here at Carrot, and while this type of architecture is nothing novel, I wanted to write this post as a reference to explain the basic architecture of our sites and the philosophy behind it.

Essentially, for any given web app, we split it into two separate projects, an API and a client. These two pieces need each other in order to function properly, but are still two entirely separate projects, whose only connection point is the API documentation.

The API

The API can be written in any language, although ours are typically node or go. It should be an extremely light and straightforward REST API, taking in pure JSON and putting out pure JSON. It should have absolutely zero interaction or concern with how information is presented to users through the web interface, it simply reads or writes data when asked to.

If non-technical people need to make changes to the data, it can be done through a CMS which is integrated with the API (like contentful or rooftop), or connected directly to the database (product in development).

The Client

The client is just the view code for the web interface. This is a static website — any reactivity to the data happens through javascript.

It connects to the API either at compile time, at runtime, or both in order to present data. An example of a compile time connection would be using spike-records to pull data from your API and compile it directly into a fully static site. An example of a runtime connection would be using vue-resource to connect to your API when the user loads the site and pull data to display. And of course, you could also do both. For example, if you have a simple blog, you could pull the first 5 posts and compile them in to the page, then if the user wants to go to the next 5, load them dynamically through javascript at runtime. We call this approach hybrid static, and it’s been something we have been doing since roots v3.

It’s important to note that the client does not include a server at all. It is simply a static site, that can be served as flat html files. This might seem uncomfortable for those used to apps in which the client and server are tied together, but I can assure you there is no type of app which cannot be built in this manner, and more efficiently at that.

Why?

So you might be asking, why split your app into two pieces? Doesn’t this just seem more confusing, or like more work? On the contrary, it’s less confusing, easier to work on, faster, more secure, and more flexible.

First, by splitting into two projects, you can now have two developers work on them independently. Rather than having both developers working in the same files and causing conflicts and misalignments that constantly have to be adjusted, the only touch point between the two projects is the API interface, which should be documented (and versioned on large projects). So both developers or developer teams can work away happily without conflict, knowing for sure where changes could be important and when to communicate them. On top of that, the back end can be in any language, making it possible to be a lot more flexible with the developers allocated. You could have a java dev on the API, and a front-end and javascript only dev on the client without issue. With a single monolithic framework, this would be a significant issue for both.

The approach is also mentally easier to manage. The data is pure — not mixed up with the view logic. The way you think about building an API is different than when you also throw view considerations in. It’s much easier mentally to set up a context around “I am building an API for a database” and “I am building a front-end for users”.

It’s also a lot more flexible and future-proof. As technology marches furiously forward, we end up with more and more devices and places we need to put apps very quickly. We can have apps for iPhone, Android, Windows Desktop, Mac Desktop, TVs, and the web now. And for a large company, it’s necessary to have at least three of those. With AR and VR coming up quickly, we might have more app destinations being quickly added to the requirements list. If you build your front and back end rolled together as a web app, then feel like building a mobile app, you’re in trouble. You’d need to un-bundle your back end from the web app into an API, or make a separate API and keep it in sync with the web app, etc. It would be a mess. However, when you start out with an API, you are set for life. As long as the interface you are building for can handle JSON, there is zero friction building out another interface for your data.

You also get some significant speed gains and complexity reductions from this approach, mostly due to the fact that your primary interface to users is a simple static site. Static sites are extremely fast and simple to set up and host. No more complex cacheing mechanisms or beefy servers are necessary to handle a huge traffic influx — static sites can handle tens of thousands of concurrent users at a time on a $5 digital ocean box running nginx. Price going down and speed going up makes this a substantial argument for businesses.

Finally, you have less surface area for security. While it’s possible to find a number of holes in a site’s security when the server is tightly bound to the client, when you are running a static site, the only things that can be insecure are your API endpoints. Locking these up is simple, and practices for keeping security holes out of APIs are common and well-documented. On top of that, you can apply the same practices across all your APIs.

Let’s Do It!

Does this seem like a compelling approach? We’d encourage you to give it a try. Here at Carrot, we tend to use express with postgres for the API, and spike for the client, but you can use whatever you want! Once we started moving towards this approach, we could never go back, and I’m sure it will be the same for any readers that decide to try it out as well.

And for those already using this technique, please feel free to drop a comment or some feedback if you have any tips or tricks. And of course, you are welcome to use this article as a reference for any time you need to explain your approach to someone who isn’t familiar yet.

Happy coding! 💻

If you liked this article, click the little green heart below to show your support. Thank you!

--

--