You’ve likely heard about front-end frameworks. Names like React, Vue, and Angular abound in tutorials and Hacker News debates. If you’ve wondered why and when these frameworks are used and whether it’s time you implement one in your project, you’re not alone. A few years ago, while working on a side project, Hackterms, my own front end became unwieldy. I had a loose sense that implementing a framework was the right next step, but I had little idea about what they did. (We’ll come back to how that turned out at the end of the article.) This is the explanation I wish had then. In this post, we’ll take a bird’s eye view of the problem front-end frameworks are trying to solve and when you might want to use one.
Specifically, we’ll review:
- How a front end grows.
- The architecture problems you might encounter as it scales.
- How a front-end framework might help address these.
- Other alternatives you might consider.
Quick aside: “front-end framework” gets a hyphen since it’s a compound adjective. However, your app has a “front end”—noun, no hyphen. Get nerdy with me.
Some terms to review
We’re going to talk about front-end frameworks a bunch (you might have gotten a hint from the title), so let’s get on the same page around terminology:
A software framework is a pre-written app structure for you to build on top of. Practically, it’s a collection of files and directories you add your own code and files to. A framework is meant to help you build applications quicker by addressing common development problems and often starts you out with:
- Boilerplate code, covering functions that are reused by most applications.
- A directory structure, often following a design philosophy.
- A set of design principles your type of application frequently encounters. Frameworks that enforce these principles, like Ruby on Rails, are usually referred to as opinionated.
A front end is the presentation layer of your application. It’s often described as all the stuff the user sees, but more generally, it’s any code that's responsible for efficiently displaying data to the user. So, the front end includes building intuitive and pleasant interfaces, as well as efficiently storing, presenting, and updating data received from the back end or API.
A front-end framework is a scaffold for building your front end. It usually includes some way to structure your files (for example, via components or a CSS preprocessor), make AJAX requests, style your components, and associate data with DOM elements.
A growing app
As is tradition, let’s look at a silly example: let’s say you’re building MySquare, a leaderboard for competitive board gamers. In this app, users can share the board games they’ve played, their league-sanctioned competitive results (there’s now a league, roll with it), and short reviews of competitive matches. The most important feature of the app is the user profile page:
- On the initial page load, the back end initially sends over a blank profile page with minimal styling. Then, and for all future loads, the front end requests user data via AJAX.
- When a user updates some value on the page, you can either read data from the DOM by querying for attributes, or by attaching event listeners to every element—getting the data by reading it from the DOM.
As MySquare gets popular and your dataset grows, this approach quickly becomes unwieldy:
- You find yourself appending data to the page and then reading it from the DOM by grabbing <div> values or reading ids or data attributes.
- You’re binding event listeners to common UI elements like input fields and buttons, then writing functions to update the values in those same elements.
- When you need to make even a small change, you worry about how it’ll impact the rest of the application.
- When your friend offers to help with the development work (for some equity, of course), you spend hours explaining how your code works.
Front-end frameworks exist because for many apps, the front end grows and strains in predictable ways. While each popular framework offers its own design philosophy, they are all attempting to solve the same general problems we encountered earlier:
- Your code should be maintainable: easy for you and others to read, test, and change.
- Complex interfaces are usually made of the same components. You should be able to create and reuse these components to easily create new pages.
- Since DOM manipulations are slow, you want to perform as few element updates as possible.
- You should be easily able to manipulate your UI based on data.
- Your UI should be consistent and intuitive; this means standardizing typography, color, buttons, inputs, and other elements.
- You shouldn’t need to reinvent the wheel and write tons of boilerplate when it comes to solving these common front-end challenges.
- You should have a common language through which to communicate your ideas and patterns with other developers.
Different frameworks address some, but usually not all, of these questions. Some, like Bootstrap and SemanticUI, focus on creating readable, maintainable HTML and CSS, emphasizing consistent visual design. Others, like Vue, React, and Angular, triumph at structuring data flow throughout your application, allowing you to focus on manipulating the data rather than the DOM.
(Sarah Drasner has a fantastic introduction that demonstrates the difference between reading data from the DOM and storing it in JS. Although her example discusses the switch from jQuery to Vue, you can read it as a broader mindset shift from DOM manipulation to focusing on data structures.)
What would MySquare look like if you implemented a popular front-end framework, like React? Here are a few changes you would experience:
- You would follow the boilerplate directory structure to create components, scripts, and stylesheets in a way that’s easy to follow and maintain. Need to make a change to the structure and styling of game records? Find the small, standalone <Match> component and make your changes.
- With this infrastructure in place, you could focus on manipulating the data instead of worrying about the DOM. Our framework’s data-binding features will automatically re-render the relevant components when the data changes. For example, if you receive data on a new match result from the server, the framework will automatically append another <Match> component onto the screen.
- If you found yourself stuck on a problem, you could leverage the framework community to get help. It should even be easier to explain your problem since you’re following framework conventions that help build popular front-end features.
- Because popular frameworks often follow similar design principles, it would be easier to collaborate with other developers, even those who don’t develop in your specific framework—you wouldn’t need to walk new developers through your own custom code structure.
Separation of concerns
Ideally, you would want your front end to operate as a standalone application, requesting data from the back end, processing, and displaying it (you might hear this called “consuming an API”). The principle underpinning this is referred to as “separation of concerns”, and it states that each part of your program should operate independently, have a clear, singular purpose, and communicate via a well-defined interface. Although your front end doesn’t have to implement a framework to follow the separation of concerns principle, most frameworks encourage this architectural pattern.
The advantage to the resulting modular design is that developers can work on different parts of your application independently as long as their component accepts predictable inputs and delivers predictable outputs. Having a front end with a single responsibility (made up of modular components that follow the same principle) makes it easy to adapt to change. If you decide to move from Angular to React, for example, you can do so confidently; both frameworks expect data from the back end, so you can focus on how React’s interface receives that data and how it uses it, not how the front end is embedded in your larger application.
As the dedicated view layer of your application, your front end should be solely responsible for logic around:
- which elements should be displayed or hidden
- when to request data or send updates to the server
- when to display simple validation and error messages
- which styling choices to make based on data
Here are two MySquare scenarios: one where the architecture follows separation of concerns, and the other where it violates it. See if you can figure out which is which!
- The back end sends over a list of game records; each record contains a score, names of two players, and the match date. The front end appends an HTML component for each match, with a red or green background color, depending on who won the match.
- The back end sends over a list of game records; each record contains a score, names of two players, the match date, and a color hex code for winning/losing match styling, calculated based on which profile is requesting the code. The front end adds a component per match, styling it with the background color sent over by the backend.
Did you catch the violation? The back end shouldn’t be concerned with styling. That logic should live in the front end, which determines how data is displayed. If your designers want to spruce up the MySquare design, they shouldn’t need to worry about data structures.
Advantages to using a framework
Let’s recap the major ways in which adopting a front-end framework will help our quickly growing app:
- Maintainability: Breaking up your app into reusable, standalone components makes it easier to make quick changes that don’t impact the rest of the application.
- Separation of concerns: Modern framework design encourages a maintainable, modular architecture and allows your front-end developers to focus on what they do best: taking data and displaying it to users in an intuitive and efficient way.
- Speed: Boilerplate code aimed at addressing common problems makes it easier for you to get your app up and running; component-based design makes it quicker to develop.
- Collaboration: Since frameworks often follow similar design patterns, it’s easier for developers who are new to your codebase to develop and maintain your app.
- Community: Popular frameworks have a community of people around them with dedicated tutorials, forums, meetups, and generally supportive developers you can seek help from.
Disadvantages and alternatives
Of course, like any tool, a front-end framework isn’t always the right solution for your application. Here are a few factors to consider before implementing one.
- Abstracted, overhead code: Until you’re thoroughly familiar with it, framework code is a black box. It can be hard to discern how much of the code is helpful to your application and frustrating to fix bugs resulting from code you’re not familiar with.
- Learning curve: Learning to use a framework effectively takes time. To be productive, you need to understand the syntax, tooling, and philosophy behind how a framework functions. For projects where speed is essential, learning a brand new technology might not be the best use of your time.
- Overkill for smaller projects: If you’re looking to deploy a static site or a site where every component is unique, you might not need the power and overhead of a full-fledged framework. It might still be helpful to implement a minimal framework or even library—we’ll discuss these in the next section.
- Setup: Setting up and customizing a framework to your specific use case takes time. If speed is essential, go with what you know, or what your development team is comfortable with.
- Strong opinions: An opinionated framework may feel constricting, and its design principles may clash with yours. Make sure you research the specific framework you’re implementing. If you prefer to build from scratch, go with your own solution.
CSS frameworks and libraries: If you’re looking to create a consistent UI, a tool like Bootstrap, SemanticUI, Bulma, or Tailwind might be a good option. Someone once described using a CSS framework as “having a designer looking over your shoulder, nudging you towards good practices.” You don’t have to inherit the visual design of these frameworks, but for a developer without a strong design background, it can be really helpful to know how many fonts to use, what different button states are, and what intuitive forms look like.
Full-stack monolith apps: Many full-stack frameworks, like Ruby on Rails, Meteor.js, and Django, come with their own templating engines, which render HTML on the server. Server-side rendering and monolith architecture are both concepts that deserve their own blog posts, but you can think of this option as picking one full-stack framework for your entire application and writing the presentation layer and server logic within a single codebase. Most full-stack frameworks do allow you to plug in front-end frameworks of your choice, but default you to using their own templating engines. This is a good solution if you want to double down on using a single framework for your entire app; it can also be a quick way to prototype a full-stack application.
Front-end frameworks and libraries come in many shapes and sizes—you can use a full-fledged UI framework to build out your entire front end, implement a CSS library to tighten your visual design, or use a templating engine to create reusable components.