What is the SUF Stack?
I've been building web apps for a while, and was
never quite happy with the trade-offs involved in the choice of architecture.
Frameworks and architectures would only really optimize for one of: users, developers, or
infrastructure, and compromise on the others.
Now, there's a combination of technologies that when combined into a single architecture
combine to combine to avoid many of those trade-offs. I've been using this
in production for a few years now, and have found it effective in quickly building
performant, scalable web apps.
This site is about sharing the SUF Stack architecture with other creators to help enable
them to create great things.
A SUF-Stack app is:
Serverless
A SUF-Stack App should be optimized for its deployment on the cloud. This means optimizing
costs to only pay for the compute which one is using. And it should mean worry free server provisioning
and maintenance.
We've been using the
Serverless Framework.
It configures deployment of apps to deploy as HTTP endpoints that call function-as-a-service (FaaS)
code on a variety of cloud providers. It also provides a rich ecosystem of plugins and tools
which one can leverage to expand its capabilities. In the AWS context, it actually configures
AWS CloudFormation, and can thus be extended to configure pretty much anything on AWS.
The starter template deploys to AWS Lambda, behind AWS API Gateway. It also deploys static
assets on S3 (using content-based hashes in names to bust caches) and leverages CloudFront
to both serve content close to users and
to only send HTTP requests which need a dynamic evaluation to the backend in Lambda.
CloudFront is configured to use HTTP/2 for faster transport, and to take advantage of compression
to further reduce bandwidth usage.
Furthermore, logging is written to AWS CloudWatch in JSON, for parsing in
CloudWatch Insights dashboards.
FaaS-based HTTP endpoints have a known issue of taking longer to serve requests
if the function has not been called for a while. To solve this cold-start problem, and to
provide better uptime monitoring, we configure an AWS Route 53 HealthCheck to repeatedly query
the backend from a variety of global locations which keeps the lambda function warm.
We also deploy the application as a single function to simplify routing and so that there is
only a single function to keep warm.
Universal
A SUF-Stack app should be optimized for its users. This means being a universal application
where the first page has HTML generated on the server, for the fastest possible render,
and where subsequent pages are generated on the browser, leveraging the techniques
from single-page apps. Being universal helps with automated parsing of your web pages, as
for search engines and other web spiders.
In addition, web application code should be delivered with long cache times to speed
up later visits to the web application, with those bundles named automatically with
hashes of their content so as to do cache busting in a natural manner.
The starter template uses
Nuxt.js to orchestrate webpack
to build universal applications. This means that you just need to focus on writing your app
and Nuxt.js will take care of wiring it up into a universal app, without you having to worry
about how to make that happen. There are some subtleties about making relative URL resolution
consistent which the starter template takes care of for you.
Another great feature that Nuxt.js exposes from webpack is the
analyze build option
which lets one visualize how many bytes your code and library dependencies are using.
One should use this to guide optimizing your web app size to speed things up for your users.
There is also a great variety
of Nuxt.js modules which one can use.
Full Stack
A SUF-Stack app should be optimized for developers. That is, it should minimize the
number of languages needed to write the full application to just Javascript (or Typescript).
It should have a clearly defined frontend using a mature framework, so that one
can count on finding answers to common problems. There should also be features such
as hot-reloading during development and a robust set of options for CSS and UX component
frameworks.
A major differentiator between a SUF-Stack web app and a Jamstack app is the use of a
proper backend in SUF. This means either Express.js or Koa.js or similar backend designed
to be run server-side, with access to secret credentials, and priviledged code. It's often
simpler and easier to just write your own backend API routes using Node.js code, especially when interacting
with databases and external APIs.
The starter template puts backend code into its own folder, and optimizes the development experience
for it. The backend is deployed as part of the same serverless function as the frontend
but with priviledged values (secrets) available to it via environment variables. One can develop
the frontend and backend for a given feature in the same code base, and ensure that they are always
deployed in sync. For development, the frontend and the backend execute locally for a
fully functional local development environment.
Next Steps
If the SUF-stack sounds like what you need, then you can
get started today!
Some History and Context
The first websites were hand-coded HTML files hosted on individual web servers. For creators
of those sites, it often meant lots of markup repetition and other inefficiencies. For users
of such sites, the content would tend to get stale and lose relevance. For the system administrators
in charge of the infrastructure, there would be a worry about keeping the sites online, especially
when there would be a surge in users for a popular site.
Next came the first generation of web applications. These provided dyamic content via server-side
code, and unlocked the web as a vehicle for eCommerce, search engines, and more. Users were
delighted by the new functionality, and would tolerate the sometimes slow loading times. Creators
were empowered by their new capabilities and eagerly dove into a raft of new languages and frameworks.
However the infrastructure demands became complex and error-prone.
Single-page apps emerged next, offering much richer experiences for users by leveraging
browser capabilities to react quickly to user inputs, and unlock emerging web standards.
However, for creators this created the need for different languages and technologies for the
frontend and backend, resulting in diverging skills and split teams. Infrastructure needs,
which had only started to simplify via public cloud providers, became complex balances
between versioned deployments of the frontend and backend, and the unique scaling needs of each.
The next set of web application architectures solve specific weaknesses. Universal apps
which render content both on the server and in the browser aid in search discoverability and speed
but suffer from complex deployments. Static site generators sacrifice dynamic backends to
optimize for distributed and cached infrastructure, and fast page speeds for the user. The Jamstack
adds more dynamic content to static sites, but still suffers from a lack of a backend with priviledged
code.