Introducing Functional Web Apps
by Brian Leroux
Today’s web applications are often built either by load-balancing a fleet of servers or deploying static pages that call out to various third-party services. Load-balanced server fleets are inefficient and require deep domain expertise making them challenging to provision, maintain, and scale. Static centric architectures (like SPAs and the JAMstack) put dynamic personalization functionality behind loading spinners, and skeleton screens which creates a suboptimal end user experience.
Functional Web App (FWA) is an architectural pattern for building dynamic web applications and APIs without these trade-offs.
An FWA is comprised of three high level facets:
- composed entirely of single-responsibility cloud functions
- maintains state via a managed database
- deterministically deployed with Infrastructure as Code (IaC) and runtime dependency lockfiles.
The FWA pattern empowers developers with the power of a dynamic, full-stack application paired with ease comparable to scaling a static website. Let’s examine what is important about each facet in detail below.
The FWA is an architectural pattern for building dynamic web applications with both better developer velocity, and ideal runtime efficiency. Servers are an inefficient abstraction, requiring over-provisioning to enable fault tolerance and availability, resulting in poor utilization of resources. Worse, the logical architecture of server code bears little resemblance to the physical architecture of the infrastructure running that code, confounding developer velocity. To ensure availability in an outage, a traditional three tier app should run in at least three different availability zones which is, again, inefficient utilization of resources.
The software developer authoring an FWA models their entire application as cloud functions expressing only essential business logic while achieving perfect 100% utilization of resources. Inspired by functional programming, a well-architected Functional Web App will be composed of entirely pure functions; wherein the same set of arguments will always produce the same result. The resulting application can be reasoned about on a per-function basis, making feature development, typical maintenance, and bug resolution a systemic and quantifiable process. When things are predictable, development moves faster, and developers are happier.
With a Functional Web App, the physical architecture is identical to the logical architecture: the authored code is the same as the physical cloud function infrastructure deployed. Also similar to functional programming, pure functions can substitute for each other. Cloud functions in many cases can even be upgraded to an entirely different runtime.
Traditional single-tenant databases are challenging to maintain and scale. They require patching and upgrades which can be a source of downtime. As a single-tenant database grows in size it has to be sharded across multiple database servers compounding in complexity.
Cloud vendors have responded with myriad managed database offerings; FWA leverages their scale to get a high performance database without the headaches of maintenance and scaling. Database performance is always crucial, so an FWA’s primary managed database should meet any level of demand, no matter how much data is stored, or how many clients are trying to access it, while retaining low-latency performance. Using a managed database frees FWA developers to create and maintain the business logic for reading and writing data, outsourcing mundane and complicated database administration tasks to a specialist vendor.
When development environments and production infrastructure are not the same, programming becomes a process of trial and error. Maintenance is made more difficult because changes need to be verified in each environment. The bigger the differences between the dev environment and the production infrastructure, the more difficult it is to debug. New features are slower to develop, and bugs are harder to resolve. Applications that require manual, step-by-step instructions for provisioning compound this problem, making changes is both slow, and dangerously error-prone.
In order to gain reliability all source code dependencies, from shared libraries to cloud infrastructure, must be explicitly defined. Source dependencies are often explicitly defined in lockfiles. Cloud infrastructure dependencies are defined in a similar fashion called Infrastructure-as-Code (IaC). The combination of these practices results in deterministic deployment. Used in tandem with a revision control system like Git, an FWA can be reproduced precisely, all of the dependencies both source and infra, in a single command for any version in history.
FWA significantly lowers the barrier to designing, building, and growing a stateful dynamic web application. FWA eschews an unnecessary server metaphor within its application architecture, and centers the humble function. FWA is dynamic by default, with a speedy managed database. FWA guarantees reliable delivery with deterministic deployment. The FWA pattern empowers the software authors with freedom to focus on the pure expression of business logic, with strong availability, latency, and infrastructure utilization guarantees. Learn more about FWA at fwa.dev.
Frequently asked questions
What cloud vendor should I use?
The FWA is a vendor agnostic architectural pattern. All the major cloud vendors support cloud functions. All have a flagship managed database, and there are many solutions available to deterministically deploy. We recommend finding the right partner and going “all in”. Select the cloud vendor(s) that makes the most sense for your unique team, system requirements, and long-term goals.
What about lock-in?
The two main concerns of lock-in:
- worried they will break you creating unplanned work
- worried they will raise prices
The major cloud vendors have all had their moments with availability but on the whole unplanned work is rare and breaking changes more rare. The cloud is also a very competitive marketplace, and in all likelihood, costs will continue to fall as the marketplace continues to compete, and further industrializes. The concerns of lock-in are unfounded. If you are still concerned about lock-in we recommend reading Martin Fowler on the topic.
Isn’t this just serverless? Why another three-letter acronym?
The term “serverless” is very ambiguous, encompassing every cloud vendor technology from cloud functions to actual web server instances running in containers. “Serverless” has grown from practical guidance to a theory wherein developers intentionally outsource infrastructure to specialist vendors so they can focus on essential business logic. The spectrum of outsourcing options is vast, and complicated. FWA is a specific way to talk about applications where the primary abstraction is cloud functions, the means of persistence is a managed database, and the entire application is deterministically deployed with Infrastructure as Code. FWA is specific architectural guidance for building next generation dynamic web apps on the unique capabilities afforded by these advances: isolation, security, availability, and utilization. Said plainly, FWA is implicitly serverless; but not all serverless applications are an FWA.
Are cloud functions expensive?
No. Most cloud function vendors have extremely generous free tiers. Even if you manage to crack that free tier, cloud functions enable high precision utilization. AWS Lambda, for example, enables per millisecond billing, so you aren’t paying for any idle uptime. Conversely, in a traditional load balanced web server architecture, to guarantee uptime requires multiple physical web servers running 24/7 in different availability zones. This is a very poor utilization of compute resources. An FWA enjoys extremely efficient applications that default to 100% utilization of compute resources.
What about the frontend?
FWA encourages dynamically rendering HTML-first and progressively enhancing when necessary. An FWA has its data immediately available in a trusted cloud function process so you can render content dynamically on-demand. No loading spinners required! Cloud functions work great behind a modern CDN. High quality modern JS frameworks should support this mode of operating but it is also completely valid to return plain text HTML response from a cloud function directly. FWA is also an excellent candidate architecture for a pure backend HTTP API for a single-page app or mobile app.
Is “Deterministic deployment” just about Infrastructure as Code (IaC)?
An application can be deterministically deployed if it explicitly describes both source code and infrastructure requirements. Runtime code dependencies are usually explicitly defined by declarative lockfiles. Infrastructure as Code (IaC) captures the cloud infra requirements.
FWA doesn’t give specific guidance on how to achieve the outcome of deterministic deployment as there are many ways to define IaC, and many different runtime code dependency mechanisms. We strongly encourage both IaC and lockfiles to be declarative manifest formats but imperative approaches can also work with discipline, and staged delivery.