# Backend Architectures for content-driven web app backends

Backend architecture refers to how your web application backend is structured.
The backend architecture determines how parts of the application communicate
with each other to process incoming requests and create responses. When building
a web application, select a backend architecture based on your specific
requirements and factors, including cost (both ongoing and at scale), your
application's complexity, scaling goals, and your team's expertise.

Specifically for content-driven web applications, such as ecommerce, newspapers,
or blogs, critical requirements include the consistency of your data and
performance, especially as your application grows to a global scale and may
become more distributed. For content-driven web applications, the data storage
used by your application is also critical and is [discussed in more detail in
the data storage guide](https://developers.google.com/solutions/content-driven/data-storage). Moving beyond
typical application architectures, hosting your content, and making it
accessible is critical when optimizing your app's performance. Learn more about
[selecting the right hosting strategy and optimizing your app in the hosting
guide](https://developers.google.com/solutions/content-driven/hosting).

If you have an existing backend for a web application, consider the limits of
your current architecture. For example, as your application scales up and
demands on its performance and reliability increase, consider whether parts of
your application should be refactored or moved to a different architecture more
suited to your increased scale. For example, [Hybrid (or multicloud)
architectures](https://cloud.google.com/architecture/hybrid-multicloud-patterns)
allow you to shift some workloads to the cloud before making a complete
transition. Considering the cost, time, and risk involved in such a migration is
also essential.

## Monolithic Architectures

A monolithic architecture has a unified structure, with all the components of
the application tightly integrated into a single codebase. The entire
application is built as a single, self-contained unit. Monolithic architecture
is multi-tiered, where different layers of the application accomplish specific
tasks.

Structural Layers

- The User Interface (UI), which includes components for presenting the application's features, is usually a web-based or desktop application that interacts with users.
- The application logic is where the core functionality resides.This part of the codebase contains the rules, calculations, and operations that define how the application works.
- The data access layer contains functions for reading and writing data and translating between the application's data structures and the database schema. This layer is responsible for interacting with the application's database or data storage.
- The database is where the application stores its data. There is usually a single database that stores all of the application's data, including user data, configurations, and other information.
- Middleware components handle tasks such as authentication, request routing, and data validation. These components help manage the flow of data and requests.
- Some monolithic applications have integration points with external services or APIs. These points allow the application to interact with third-party services, data sources, or other systems.

The structural layers are usually part of a single codebase. This codebase
contains the entire application and is usually organized into directories,
modules, and classes. Developers work on various parts of the codebase to build
and maintain the application. However, the entire application is typically
deployed as a single unit. When updates or changes are made, the entire
application is re-deployed.

Potential Challenges

- As monolithic applications grow, the codebase tends to become complex and difficult to maintain. This can result in long development cycles and difficulty in understanding the entire codebase.
- Deploying changes to a monolithic application can be risky since changes made in one part of the code may inadvertently affect other parts of the application. This can create a lengthy and error-prone deployment process.
- Monolithic applications can be difficult to scale since they are deployed as a single unit. You must scale the entire application even if only one component experiences increased demand.
- Monolithic applications often rely on a single technology stack or programming language, your ability to use the best tool for a specific task within the application may be limited.
- Even during periods of low demand, monolithic applications require significant resources to operate. Maintenance costs also increase as the application ages as it becomes more challenging to update and patch the application without causing regressions.
- Development teams working on monolithic applications are often organized around the entire application, this leads to larger teams and more complex coordination among team members.

### Suggested Usage

Monolithic architectures are suitable when an application has modest
requirements and the development team is small. As an application grows in
complexity and scale, or when different parts of the application require
different technology or deployment strategies, monolithic architectures can
become less flexible and more challenging to maintain.

You can create and manage virtual machines that can run monolithic applications
on [Compute Engine](https://cloud.google.com/compute/docs). You have full
control over the operating systems, software and management of these virtual
machines to run your monolithic application.

With a platform-as-a-service service, such as [App
Engine](https://cloud.google.com/appengine), you can build your application and
run it on fully managed infrastructure that automatically scales with requests.

If your monolithic application is containerized, you can run it using [Google
Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) (GKE) or [Cloud
Run](https://cloud.google.com/run). Services such as [Cloud
SQL](https://cloud.google.com/sql) or [Cloud
Spanner](https://cloud.google.com/spanner) can be used to store data for
monolithic applications. Consider a combination of services and systems based on
your application's specific requirements.

## Serverless Architectures

Using serverless architecture, you can build and run applications without
managing physical or virtual servers. The cloud provider automatically manages
the infrastructure, scaling, and resource allocation so that developers can
focus on writing the code for their applications. Serverless architectures can
simplify development, reduce operational overhead, and optimize costs by
eliminating the need to maintain servers. They are well-suited for
microservices, real-time data processing, web applications with variable
workloads, and event processing.

## Event-based serverless architectures

Event-based serverless architectures are a specific type of serverless computing
architecture that relies on events or triggers to initiate the execution of
functions or microservices. System components communicate through events, and
functions are invoked in response to the events. They often rely on asynchronous
communication as functions are triggered by events, then process them
independently, and may produce events that then trigger subsequent actions. This
type of serverless architecture is a good option for building scalable,
responsive, and loosely coupled systems.

[Google Cloud Functions](https://cloud.google.com/functions) and [Cloud
Functions for Firebase](https://firebase.google.com/docs/functions) enable you
to build and deploy event-driven functions in a fully managed and serverless
environment. It lets you run code in response to various events and triggers,
including HTTP requests, Cloud Pub/Sub messages, Google Cloud Storage changes,
Firebase Realtime Database updates, without the need to manage infrastructure.
Key features include multiple language support, scalability, granular billing,
third-party integrations, robust logging and monitoring, and integration with
other Google and Firebase services.

Serverless architectures can be cost-effective for many use cases, especially
for applications with varying workloads, rapid development needs, and
unpredictable traffic. Reliability depends on the cloud provider, with service
level agreements (SLAs) in place to ensure specific performance and reliability
targets. You must assess your particular use case and requirements to determine
if serverless architecture is your best option.

## Containerization

Containerization allows applications and their dependencies to be packaged into
lightweight, portable containers. They provide a consistent application
environment that support development and deployment across different systems and
platforms. Some serverless platforms offer the ability to run containerized
workloads. Running containers within a serverless environment can be beneficial
when you have complex or stateful workloads that cannot be expressed as basic
functions. It provides flexibility in terms of language support and runtime
environments.

[Cloud Run](https://cloud.google.com/run) is a serverless computing platform
that allows developers to deploy and run containerized applications in a fully
managed environment. It provides a straightforward way to build, deploy, and
scale applications without managing the underlying infrastructure. It is
suitable for a wide range of web and microservices applications, especially
those with variable workloads, and where containerization offers benefits in
terms of application packaging and consistency.

## Microservice Architectures

Applications are broken down into small parts that are loosely coupled and
implement distinct features or capabilities. These services may communicate
through asynchronous messages, event-based channels, or directly by exposing an
interface. Each service is developed, tested, and scaled independently in its
container, which is often managed through an orchestration service, such as
[Kubernetes](https://kubernetes.io/), or deployed using a managed platform, such
as [Cloud Run](https://cloud.google.com/run).

Microservice deployments usually also take advantage of the serverless
application paradigm by not relying on a centralized server.

Separating an application into autonomous services can simplify a complex
system. Well-defined boundaries and objectives can speed up development and
improve maintenance. Each microservice can be developed independently using the
most effective frameworks or tools. Communication between services is often
handled using events, publish-subscribe communication, message pipelines or
remote procedure calls such as [gRPC](https://grpc.io/).

For the orchestration of tasks within a microservice architecture, consider
using a framework that supports the platforms you are targeting, sufficient
depth for the tasks and types of workflows you are orchestrating, as well as
error handling and telemetry to debug issues. Popular choices include
[Conductor](https://conductor.netflix.com/index.html) or offerings
from a cloud provider such as [Google
Workflows](http://cloud.google.com/workflows).

Microservice-based applications can be complex to develop and maintain due to
their distributed nature and the need for intra-service communication.
Therefore, managing deployments, monitoring, and logging are more complex than
other architecture options. Since reliability depends on the architecture of the
individual services, the distributed nature may offer additional resilience,
especially if monitoring and telemetry are deployed and enabled if required.

## Comparison of different architectures for content-driven web application backends

The following table compares architectures against key requirements for the
backend of a content-driven web application.

|   | Monolithic Architectures | Serverless, event-based Architectures | Serverless, microservice Architectures |
|---|---|---|---|
| Complexity and maintenance | - Ease of implementation for small, self-contained projects, but complexity increases with scale. - Requires manual maintenance and coordination. | - Scaling is well supported and built into the platform. - Troubleshooting and debugging can be challenging. - No need to manage infrastructure. | - Self-contained services that are tested and deployed independently making maintenance for each unit easier. - Requires careful communication between services. - Requires management and orchestration tooling to manage at a larger scale. |
| Scalability and performance | - Efficient at small scale, difficult to scale beyond a specific size. - Specific infrastructure needs, limiting dynamic scaling options. - Manual scaling (or using manual services) within architecture, for example through load balancing. | - Built-in scalability through the use of a managed platform. [Scales in either direction](https://developers.google.com/solutions/content-driven/backend/scaling). | - Each service is tailored to a specific need and can be scaled and optimized independently. |
| Resilience and fallback strategies | - Deployment is complex and may lead to downtime ("all or nothing"). | - Inherent to the cloud provider. - Each independent function may be retried independently. | - Each service is self-contained, making the overall system more resilient through independent testing and development. |
| Development experience | - Fast development at a small scale through tight coupling of the architecture (for example through efficient queries). - Long build times and difficult collaboration and testing as complexity grows. | - There is no infrastructure to maintain and manage, making development quicker. - Testing and debugging a live application depends on the cloud provider's services. | - Services are self-contained and can be developed independently from each other. - A large number of services need to be coordinated and managed. |
| Cost | - Complex development may lead to increased costs. - Requires significant investment in hardware or infrastructure, especially at a larger scale. - Cost efficiencies from scaling up and down are difficult to realize. | - No dedicated hardware costs. - Scaling up and down to optimize resource use and cost (down to zero). | - No dedicated hardware costs. - Scaling up and down to optimize resource use and cost within boundaries. - Additional costs from monitoring and managing a large set of independent services. |

## Learn more about backend architectures for content-driven web applications

Here are some resources to learn more about architectures for content-driven web
applications, including how to migrate your app to a different architecture:

- [Learn more about loosely coupled web app backend
  architectures](https://dora.dev/devops-capabilities/technical/loosely-coupled-architecture/), including tiered monolithic and serverless web applications.
- [Migrating a monolithic app to a microservice
  architecture](https://cloud.google.com/architecture/microservices-architecture-introduction).

- [Typical use cases for serverless Cloud
  Functions](https://firebase.google.com/docs/functions/use-cases).