Photo by Andrés Alagón / Unsplash

Full Stack Performance

Architecture Dec 15, 2023

Performance is a tough subject and there are many approaches to achieve high performing software over the internet such as backend or infrastructure optimizations, caching, etc. I wanted to jot down my thoughts about what performance means at scale and outline some steps you can take to achieve true full stack performance across any project that you're working on. In this article I'm going to focus on what I'm most familiar with though these concepts can be easily translated into other use cases.

Infrastructure

Starting with the most important part, infrastructure. Now, there's a million things you can do here all with varying degrees of proven success and in general you shouldn't blame your infrastructure for performance issues without ruling everything else out first assuming you have some industry standard configuration. That being said, let's go over some considerations for infrastructure performance.

  1. Database - Databases should be hosted within a separate and isolated infrastructure that can only be accessed by your backend machines. You should have highly available read-replicas since a lot of traffic in many applications is read traffic. This can significantly improve performance and reduce costs as a side benefit. In my main stack, MongoDB makes this pretty easy and I like hosting my database infrastructure within MongoDB Atlas with a peering connection into my AWS infrastructure. Although it's tempting to use the developer tier in production because it's free, you should absolutely avoid this because the first traffic spike will bring your service to a hault.
  2. Backend - A backend service should be hosted with auto scaling in mind, AWS makes this pretty easy if you opt for Elastic Beanstalk and if you're unfamiliar with auto scaling groups you probably should. Set some realistic expectations for auto scaling by measuring your backend's performance under load even if it's just a couple users and multiplying that. Backends should also be consistently monitored for performance issues; measure latency of endpoints in real time using something like Sentry and set up alerts so that you can see when something is going wrong. Observability is hugely important here and you need to be optimizing 24/7. We'll talk more about this in the backend section.
  3. Static Content - Any files that you are hosting, everything from CSS to images and video content should be hosted through a CDN and not through your backend instances. AWS makes this pretty easy if you put those files in S3  and Amazon has a great set of libraries to do this via your backend. Once you have those files in S3 you can host them via Amazon's CloudFront CDN. You can even host full frontend websites such as React projects directly from S3 using CloudFront which makes them crazy fast!

Backend

Let's not forget the step under infrastructure, your project can only be as fast as it's slowest component and often this part is overlooked.

  1. Observability - This is critically important for any project. You want to be able to see everything going on in your backend at all times. You want to be able to see real time performance metrics and understand which parts of your code are operating slower than others. I recommend using a third party for this because it's a critical component and difficult to roll out on your own while doing it properly. If it seems simple to you, you need to use a third party!
  2. Refactoring - The word every CEO hates, how many of us have heard "what a waste of time". You need to be able to refactor code to be more optimized and this process needs to be ongoing. Unforseen circumstances often leave certain parts of a codebase with unintended issues and it's important to solve them quickly before they pile up and suddenly you're losing users because your platform is slow and doesn't work properly. I don't care how "my code is perfect the first time" and "we only hire top tier engineers" your team is, we all have these issues and they need to be addressed properly in order to maintain fast and accessible backend services.
  3. Modularity - In line with refactoring we have to keep things modular, clean and easy to understand. As a team scales the ability for new people to jump in and assist is critical and this can be a super long and tedious process or quick if you maintain a well built codebase. Having a high performing team will reflect in the performance of your software.

Frontend

At last we come to frontend, where performance optimization is typically focused on animations, timing, etc. but there's a few things in particular that need to be addressed in order for your platform to be performant. One thing I'd like to clarify right away is that there's a difference between looking fast and being fast, sometimes you don't have a choice about how the infrastructure or backend do and so you have to look fast. Many, many modern applications simply look fast and it's no fault to the other components it's just that users expect instant feedback and it's simply impossible to provide that. There's nothing wrong with looking fast so long as you address any issues that you can with actually being fast too.

  1. Loading - Since we don't want the user to have to wait for anything an important step to improve perceived performance is to load only what is required, show the screen and then load more data within that screen. As an example you might load your auth and the very first bit of content and then load more while the user is looking at the content you've already loaded. You could load more detailed information while giving the user an overview of that same information, you could put in screen loading indicators on data that's still loading or use something like a skeleton loader (which imo looks way better). The key component here is to give something to the user that they can look at, empty screens and full page loading indicators are a thing of the past and frustrate our simple minded users.
  2. Caching - This is a whole subject within itself but caching is also super important if you want your project to appear fast. TikTok is a good example of this, as a coworker recently pointed out it appears that TikTok is caching at least one video to show the user the next time they open the app. This is a great example of keeping the user engaged while the frontend works on loading stuff. Caching is also great for preloading content so that by the time your user gets to that content it's already available. If you have a really good infrastructure and backend in place this can be super fast and you won't have to pull too many tricks to get it to look great for the user.
  3. Optimization - Code quality is important here and the way you write it can change the outlook for users. Frontend is especially difficult because there is so much variety in the devices, users, etc. that you are dealing with. If you're working with iOS I recommend you check out my friend Stanley for some great posts that include many posts about performance in code and how code interacts with the device.

Overall, performance is not focused on an individual part of a tech stack it takes all components working together to achieve and your users will appreciate you if you take some time to think about how to make things faster. All of these tips should be baked in to your mindset when you start new projects, considering performance at every step of the development lifecycle is a great skill to have in any tech career.

If you'd like to check out what I've been working on recently and see all of my thoughts and insight in a real world product check out Kwiks!

Tags

Steven

Steven has been writing software and exploring computers since the age of 17 all the way back in 2008!