Photo by Luca Bravo on Unsplash
CRUD vs. Component SPA Frameworks: A New Mental Model for Application Development
Introduction
For those experienced in application development, MVC frameworks like Rails, Django, and Laravel are well-known. I'll refer to these as CRUD frameworks for this article. They remain the go-to frameworks for many developers.
We are now seeing a new breed of full-stack web frameworks: Component-based Single Page Apps (SPA) frameworks like Next, React, Remix, Nuxt, Svelte, Solid, and Qwik. I'll call these Component SPA frameworks.
Both offer distinct mental models, but public discourse around these approaches is often superficial, focusing on:
- The churn in JavaScript frameworks
npm
dependency issues- HATEOS best practices
- Criticisms of JavaScript
- The complexity of SPAs
My blog aims to shift the discussion to the core mental models of these frameworks.
Data First vs. UX/UI First
CRUD Frameworks
The mental model revolves around data. The development approach typically looks like this:
- Scaffold a data schema
- Build out the Controller
- Build out the View
It centers on data, views, and routes.
Component SPA Frameworks
The focus is on UX/UI. The development approach looks like this:
- Design UI components
- Wire up event handlers
- Make data calls
It revolves around events, state, and transitions—closer to the user's perspective.
Components vs. Templates
CRUD Frameworks
Developers think in terms of templates, which flow from the database schema. CRUD actions are built around the schema, and frameworks provide tools to generate these templates, enhancing them with JavaScript for interactivity. Examples include:
- Rails'
hotwire
,turbo
, andstimulus
- JavaScript libraries like
htmx
andalpine
Component SPA Frameworks
Everything is based on components. From basic UI elements to state transitions and async data, the component is the fundamental unit of composition. React popularized this mental model, and it's a significant shift from traditional templates.
Weight of JavaScript
CRUD Frameworks
JavaScript is progressively incorporated to enhance user experiences, resulting in a low amount of JavaScript shipped to the client. This is beneficial for performance.
Component SPA Frameworks
SPAs are persistent processes running in the browser, inherently requiring more JavaScript. This leads to more complex tooling and higher initial setup costs. The need for tools and changes to make components usable can distract from their simplicity and power.
Solid Base vs. Growing Pains
CRUD Frameworks
These frameworks have a solid foundation with less churn and straightforward tooling. Rails, for example, provides an opinionated and cohesive development experience.
Component SPA Frameworks
The SPA approach involves reorienting the entire application development process around components, which introduces complexity and growing pains. However, the ecosystem is maturing with tools and best practices that ease this transition.
HTML vs. JSON Over the Wire
CRUD Frameworks
Communication over the wire is typically via HTML, relying on standard HTTP specs. Example in Rails:
<%= form_with url: "/search", method: :get do |form| %>
<%= form.label :query, "Search for:" %>
<%= form.text_field :query %>
<%= form.submit "Search" %>
<% end %>
Component SPA Frameworks
Communication is usually via JSON. Traditionally, components were only on the client side, with the backend sending serialized data (e.g., JSON). This created a divide between client and server.
In Component thinking, the approach changes:
- Define UI components like
TodoList
andTodoItem
- Determine the data needed for these components
- Design the database queries to support this
Example in a Component-based framework:
async function Todos() {
const todos = await sql`select * from todos`; /* Data requirements */
return (
<List>
{todos.map((todo) => (
<ListItem key={todo.id}>{todo.title}</ListItem>
))}
</List>
);
}
This cohesive and colocated abstraction is a recent development, offering a new level of integration between state, aesthetics, and behavior.
My Conclusion
Now that I have contrasted both approaches. Especially in terms of mental models rather than underlying tech.
I wanted to provide my two cents.
While in CRUD based the flow works like: Data -> Views -> UX/UI
This often results in apps that feel like a database.
With SPA Component frameworks flow looks like: UX / UI -> Components -> Data.
Resulting apps feel like an app.
A good corollary to this is thinking in test first vs later. TDD vs no TDD.
I personally recommend the SPA Component work flow. The primitives are stabilising and providing much better UX/UI then we could hope for. It's a testament to the innovation in OSS.
Other than that:
- The lack of rich interactivity primitives in CRUD based frameworks also biases designs towards a more basic UX/UI.
- Design prototyping tools have come far - Figma. They are capable of providing better UX/UI than legacy tools. SPA based frameworks are better suited for this.
- Motion design is still so lacking in the web industry. Again SPA based framework have a unique advantage here.
Now after these many years we are converging on tools on both sides of the spectrum.
As a case study, think of Netflix vs Github.
What Netflix has achieved through client side engineering is incredible. Components play a large part in this.
Github navigation still feels sluggish. Gets the job done sure. But still not as smooth as Netflix.
Another recent example of how these tools can enable better UX:
The is so rich in interactivity and stats. I am willing to bet that if this was built using CRUD based framework it won't be so cool. Its unsurprisingly built on Next.js.
PS: Of all the CRUDy-frameworks Phoenix stands out. They get it. They too adopted Tailwind as their choice. They have components. They have hot reloading. As I said they get it.
PPS: Check out SolidStart! They are building such cool things on top of Signals. The "Hello World" is so smooth. The way they have approached the primitives too is something to behold.