Designing Around Client Logic & Patterns of Web Applications

Learn common patterns used by web applications to manage state.

Designing around client logic

As a web application begins to act more like a desktop application, the application starts to maintain a lot of state and logic that only pertains to the user interface. It doesn’t always make sense to manage the client-only information and logic on the server, and so JavaScript applications in the browser become more and more complex.

The user interactions managed by JavaScript are not, by and large, effectively modeled as CRUD resources. Single page app JavaScript frameworks have different concerns, and as a result have structured themselves quite differently than server-side Rails applications (you see this in the rise of tools like GraphQL, which is an alternate structure for managing resources).

For example, a primary concern of JavaScript application frameworks is managing the state of the objects and data being interacted with on the client. Frameworks often emphasize having a lot of relatively small constructs that manage the data and logic for a small part of the page. Therefore, a problem in a lot of client-side app frameworks is sharing common state information among otherwise unrelated small components across the page.

On the server-side, sharing common state is not a concern in the same way. A server-side Rails app stores global state in the database and generally doesn’t worry about the mutability of individual instances because they don’t last beyond a single request. How, then, to structure an application that combines a lot of Rails-shaped server-side logic with a lot of JavaScript-shaped client-side interaction?

One option is to do as little in JavaScript as possible. The full version of this server-side structure would have the server generate all rendered HTML and limit the client to either manipulating the existing DOM or making AjaxAjax requests to the server, receiving HTML, and inserting that HTML directly into the DOM. This was more-or-less the original Web 2.0 paradigm and was the interaction supported by early versions of Rails via helper methods that made remote calls and inserted the returned HTML into a DOM element with a given ID.

These days, you can also manage an app with Turbolinks and Stimulus that behaves in much the same way—primarily server-side rendering to attempt to model updates to individual parts of a page as separate CRUD resources.

On the other extreme, you have a single page JavaScript app that does the maximum amount of work on the client. After sending the original JavaScript, the server is limited to just sending data back and forth, probably using JSON, while the client converts that data to DOM elements using templates or JSX or something. The client also manages the state of the application, including what the user might perceive as the URL of the application, and the way the browser’s back button works.

Both of these options have their benefits and drawbacks. There’s also a middle ground, where individual web pages might have their own rich interactions, but we let the server handle the transition between pages.

Patterns of web applications

To make this architecture distinction more concrete, let’s look at how these decisions might play out in a specific web app. Slack is real-time collaboration and chat application that runs in a browser. Later in the course, we’ll look at how an application might handle a real-time chat notification. For now, I want to focus on two user interactions:

  1. When users click in the sidebar to remain in chat, but change the Slack channel they are looking at.
  2. When users click to view their profiles, which completely takes away the chat interface and replaces it with something more like a form, at least this happened on an older version of Slack. Let’s assume for the sake of this example that this still does happen.

Switching channels

When the user clicks on a different channel, the basic UI stays in place, but all the displayed data changes. Very broadly speaking, there are a few ways to handle this change. Clicking on a channel could trigger an entire page refresh, making a normal HTTP request to the server and redrawing the entire page.

This would usually cause the page to flicker, leading to a poor user experience, although in theory, when using Rails, Turbolinks prevents flickering. This is the solution with the least JavaScript, although if you use Turbolinks, that is a JavaScript library.

Get hands-on with 1200+ tech skills courses.