code-for-a-living February 3, 2020

Does your web app need a front-end framework?

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…
Avatar for Max Pekarsky
Software Engineer

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:

  1. How a front end grows. 
  2. The architecture problems you might encounter as it scales.
  3. How a front-end framework might help address these. 
  4. 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

You can build a simple frontend with just three files: HTML, CSS, and JavaScript. However, as your app scales, your files will grow along with it, filling up with inscrutable and unmaintainable spaghetti code.

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:

You build the first version of this profile page with the three basic technologies, HTML, CSS, and JavaScript. It works something like this: 

  • 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.
  • The back end sends over some public user data as JSON, and you use JavaScript to dynamically append DOM elements for game badges and records onto the page. 
  • When you decide to build game-specific pages that list all the users and their records, you create new JavaScript files that replicate much of the code, since they’re drawing on the same game data. 
  • Each game badge (and match badge) uses the same HTML, so you store the markup in a JavaScript string and figure out a way to inject game-specific data in there, ex: “<p>{{Game Name}}</p>”. Then, you append the badge HTML onto the page for every game.
  • 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. 
  • The number of JavaScript and CSS files balloons, and there’s lots of repeated code between them. 
  • 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.

Managing these problems is feasible with vanilla JavaScript and enough patience. With planning and forethought, you might be able to structure your app to anticipate some of these issues. However, as your front end grows, these problems will only deepen—you can never be sure how your app is going to evolve. 

You realize that storing your data in the DOM and endlessly appending HTML stored in JavaScript strings can’t be the best way to tackle this project. Fortunately, there’s no need to reinvent the wheel. When you find yourself needing to build a robust, maintainable UI, it’s time for… you guessed it! A front-end framework.

Enter, framework

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:

  1. You would create reusable HTML/CSS/JavaScript components with data placeholders for the game badges, match records, and other common elements. The framework would then render these elements based on incoming data (the JSON we get from the server or APIs). For example, if the JSON has nine game records, we render nine <Match> components, with match data automatically inserted.
  2. 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.
  3. You would be able to take advantage of most recent JavaScript features as well as a CSS-preprocessor like SASS to write concise, expressive, modern code. The framework will transpile this to the HTML/CSS/JavaScript that browsers understand.
  4. 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.
  5. 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.
  6. 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!

  1. 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.
  2. 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:

  1. 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. 
  2. 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. 
  3. 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.
  4. 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.
  5. 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.

Disadvantages

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. Ecosystem evolution: The JavaScript framework ecosystem is famously volatile. The hottest framework of today may not be popular next year, and with this shift, developers and support may be hard to find.

Alternatives

There are a few alternatives to large JavaScript frameworks like Vue, React, and Angular. As we mentioned earlier, different front-end frameworks attempt to solve different problems. Depending on your needs,  smaller frameworks and libraries may work for you. Additionally, you could abandon separation of concerns and go with a monolith full-stack app with server-side rendered views. Here are a few alternatives to consider:

Templating engines: If all you need are reusable components, consider a templating engine like Handlebars.js, EJS, Underscore.js, or mustache. These engines allow you to store HTML/CSS/JavaScript components and insert JavaScript variables into them. I mentioned struggling with how to scale my project, Hackterms, at the start of this article. In retrospect, I  absolutely should have used a full-fledged framework. However, at the time, I was short on time and patience, so I successfully used Handlebars to create reusable templates.

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.

In conclusion

Front-end frameworks are a powerful tool for developing complex user interfaces. They encourage you to build out a maintainable, modular, standalone architecture that makes it easy to build your application and collaborate with other developers. Popular frameworks are backed by supportive communities, a wealth of documentation and tutorials, and offer battle-tested code that tackles common challenges that front ends pose as they scale. Frameworks allow you to tap into the most modern JavaScript features and offer tooling that makes it easy to prototype apps. Finally, they empower you with a shared language to discuss your architecture and challenges.

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.

However, a front-end framework can be overkill for smaller projects and prototypes, and the steep learning curve, coupled with the quickly evolving JavaScript ecosystem, can make it difficult to implement in a young project. At the end of the day, you should implement a popular framework if you’re excited to learn about well-tested design principles, expect your front end to scale, or need to prototype quickly when performance isn’t a major concern. If you like thoroughly understanding every part of your application, or don’t want to learn a new technology, then it’s probably not the best option.

Hopefully, this overview has given you an idea of the problems a front-end framework solves, and whether it’s the right fit for your next project. What has your experience with front-end frameworks been like? Which is your framework of choice? Looking forward to your comments below!


Many thanks to James Mayr and Lauren Risberg for reviewing this article, catching many errors, and making great suggestions.

Tags: , ,
Podcast logo The Stack Overflow Podcast is a weekly conversation about working in software development, learning to code, and the art and culture of computer programming.

Related

code-for-a-living December 18, 2019

WebSockets for fun and profit

Seamless communication is a must on the modern web. As internet speeds increase, we expect our data in real time. To address this need, WebSocket, a popular communication protocol finalized in 2011, enables websites to send and receive data without delay. With WebSockets, you can build multiplayer games, chat apps, and collaboration software that work…
Avatar for Max Pekarsky
Software Engineer
tech stack employer branding
talent February 24, 2020

How Your Tech Stack Can Attract Top Developers

For developers, the single biggest factor in evaluating a job offer is the technology stack they’ll be using. The tools and technologies selected as part of a company’s core tech stack will heavily impact that company’s ability to develop and deploy code quickly and to scale seamlessly. Know what to highlight to candidates about your tech stack.