Chapter 2
Cloud Architecture for Full-Stack Applications
Bachelors Program in Full Stack Development
Cloud Integration & Deployment (Heroku/AWS)
•
Bachelor
Cloud Architecture for Full-Stack Applications
Introduction and Context
Cloud architecture is the disciplined arrangement of computing resources, software components, data stores, networks, security controls, and operational processes that deliver an application. For a full-stack application, architecture must connect the user interface to application logic, persistent data, asynchronous processing, files, and external services while meeting functional and non-functional requirements.
Heroku and AWS provide different levels of abstraction. Heroku emphasizes developer productivity through a managed platform, deployment pipelines, buildpacks, add-ons, and dynos. AWS provides a broad infrastructure and managed-service portfolio, including compute, networking, databases, queues, object storage, identity, observability, and content delivery. The architectural principles in this chapter apply to both, although the implementation choices differ.
A sound architecture is not simply a list of cloud services. It is a reasoned response to requirements, constraints, risk, cost, and expected change.
Learning Objectives
By the end of this chapter, students should be able to:
Translate functional and non-functional requirements into architectural components.
Explain the roles of front ends, APIs, application servers, databases, queues, object storage, and content-delivery networks.
Compare monolithic, modular-monolithic, microservice, event-driven, and twelve-factor approaches.
Design correct synchronous and asynchronous request flows.
Evaluate architectures using performance, reliability, security, operability, cost, and organizational criteria.
Identify governance, privacy, and deployment risks in cloud systems.
1. From Requirements to Architecture
Functional requirements state what the system must do: register users, process payments, upload images, search products, or send notifications. Non-functional requirements state how well and under what constraints it must operate. Typical non-functional requirements include:
latency: how quickly a response is returned;
throughput: how much work is completed per unit of time;
availability: the proportion of time the service is usable;
durability: the probability that stored data is not lost;
scalability: the ability to handle increased load;
security and privacy: protection against unauthorized access or misuse;
maintainability: ease of modifying and operating the system;
cost efficiency: acceptable expenditure for the required service level.
A useful translation process is:
Identify actors and use cases. Distinguish browsers, mobile clients, administrators, partners, and automated jobs.
Classify interactions. Decide which actions require an immediate response and which can be completed later.
Identify data ownership. Determine which data is transactional, analytical, temporary, confidential, or file-based.
Estimate demand. Consider normal traffic, peak traffic, growth, payload size, and job duration.
Select failure boundaries. Decide which failures should remain isolated and which operations may be retried.
Choose deployment and operational boundaries. Map components to Heroku dynos, AWS services, containers, or managed platforms.
Validate against constraints. Check budget, skills, compliance, vendor dependence, and delivery time.
Architecture should be traceable to requirements. For example, “users can upload profile photographs” implies an upload interface, authentication, object storage, metadata persistence, access control, and often image-processing jobs. It does not necessarily imply a microservice.
2. A Reference Architecture for a Full-Stack Application
A conventional cloud application contains several logical layers:
Client or presentation layer: browser or mobile interface, often delivered as static assets or rendered by a server.
Edge layer: DNS, TLS termination, caching, web application firewall, and content delivery.
API layer: HTTP or GraphQL endpoints, authentication, validation, rate limiting, and response formatting.
Application layer: domain rules, transactions, orchestration, and integration with other systems.
Persistence layer: relational or document databases, caches, and search indexes.
Asynchronous-processing layer: queues, event streams, scheduled jobs, and workers.
Object-storage layer: images, documents, backups, and large immutable artifacts.
Operations layer: logging, metrics, traces, deployment automation, secrets, and alerting.
Cloud architecture showing synchronous API flow and asynchronous queue to worker flow
Figure: Cloud architecture showing synchronous API flow and asynchronous queue to worker flow
Figure: Reference architecture. The application server enqueues asynchronous work; workers consume jobs from the queue. The API does not directly invoke the worker in this flow.
2.1 Front Ends and Content Delivery
A front end may be a single-page application, server-rendered application, static site, or hybrid. Static JavaScript, CSS, fonts, and images can be stored in object storage and distributed through a CDN. A CDN reduces geographic latency by serving cacheable content from edge locations, but it does not replace application authorization or transactional storage.
Dynamic responses generally pass through an API or application server. Cache-control headers, cache invalidation, versioned asset names, and protection against serving private data are essential. A public CDN object and a private user document require different access policies.
2.2 APIs and Application Servers
An API establishes a contract between clients and backend capabilities. A robust API validates input, authenticates the caller, authorizes the requested action, applies business rules, handles errors consistently, and emits useful telemetry. HTTP methods and status codes should reflect semantics rather than implementation details.
The application server may run as a Heroku dyno, AWS container, virtual machine, serverless function, or managed application service. It should normally be stateless: session state belongs in a database, cache, or signed client token rather than local process memory. Statelessness permits multiple instances to serve requests and allows replacement during deployment or failure.
2.3 Databases and Caches
Relational databases are appropriate when transactions, joins, constraints, and strong consistency are important. Document or key-value stores may be useful for flexible records, high-scale access patterns, or specific latency requirements. The choice should follow data relationships and access patterns, not fashion.
A database transaction groups operations so that its defined atomicity and consistency rules are preserved. However, a transaction usually cannot automatically include an external email provider, queue, or object store. Designs must therefore address partial failure, often through an outbox pattern: write business data and an event record in one database transaction, then publish the event asynchronously.
Caches reduce repeated computation or database access, but introduce invalidation, staleness, eviction, and consistency concerns. A cache is not a durable source of truth unless explicitly designed as one.
2.4 Queues, Workers, and Event Streams
A queue stores work until a worker can process it. The normal flow is:
The application validates a request.
It records required state and places a job on a durable queue.
The client receives an immediate acknowledgement, often with a pending status.
A worker consumes the job.
The worker performs the operation and records success or failure.
Failed jobs are retried according to a policy and eventually moved to a dead-letter queue when appropriate.
The queue must not be treated as a magical guarantee. Jobs may be delivered more than once, so workers should be idempotent: processing the same job repeatedly should not produce harmful duplicate effects. Idempotency keys, unique database constraints, and recorded operation identifiers are common techniques.
A queue generally distributes tasks to consumers. An event stream retains an ordered log that may be independently consumed by several applications. Both require attention to ordering, retention, visibility timeouts, poison messages, back-pressure, and monitoring.
2.5 Object Storage
Object storage is designed for named objects in buckets or containers, rather than row-oriented transactional records. It is suitable for media, documents, exports, and backups. Metadata such as owner, content type, checksum, and lifecycle state may be stored in a database while the binary content resides in object storage.
Secure designs use private-by-default objects, short-lived signed URLs where appropriate, encryption in transit and at rest, malware scanning for untrusted uploads, size and type validation, lifecycle policies, and versioning where recovery matters.
3. Synchronous and Asynchronous Design
A synchronous request keeps the client waiting for completion. It is appropriate when the result is small, predictable, and needed immediately, such as retrieving a profile. An asynchronous operation is preferable for video transcoding, bulk email, report generation, payment reconciliation, or large imports.
Asynchrony changes the user experience and consistency model. The API may return HTTP 202 Accepted with a job identifier. The client can poll a status endpoint, receive a webhook, or use a real-time channel. The system should communicate states such as queued, running, completed, and failed.
A basic capacity estimate helps identify bottlenecks. If jobs arrive at an average rate λ jobs per second and each worker processes μ jobs per second, c identical workers provide nominal service capacity:
Capacity = c × μ
Stable operation requires average arrival rate below capacity, so λ < cμ, with additional margin for bursts and failures. This is a capacity condition, not a guarantee of a particular response time. Queueing delay depends on variability, scheduling, and utilization. At high utilization, waiting time can rise sharply; therefore systems should scale workers, limit admission, or reduce job cost before the queue becomes unbounded.
Worked example. A thumbnail job takes 0.5 seconds of worker time on average. One worker processes μ = 1 ÷ 0.5 = 2 jobs per second. Four workers therefore provide nominal capacity of 4 × 2 = 8 jobs per second. If the sustained arrival rate is 6 jobs per second, the simple capacity margin is 2 jobs per second. This does not prove that every job meets a latency target; burst size and worker startup time must also be evaluated.
4. Architectural Styles and Trade-offs
4.1 Monolith
A monolith is deployed as one principal application unit. Its components may still be logically separated, but they share a deployment boundary and often a process or database.
Advantages: simple deployment, local function calls, straightforward transactions, low operational overhead, and rapid early development.
Limitations: a defect or resource-intensive feature can affect the whole application; independent scaling is difficult; large codebases may become tightly coupled.
A monolith is often a responsible choice for a small team and a new product. “Monolith” does not mean poorly designed.
4.2 Modular Monolith
A modular monolith keeps one deployable unit but establishes explicit modules, interfaces, ownership rules, and separate domain responsibilities. Modules may share infrastructure while avoiding uncontrolled access to one another’s internals.
This style often provides much of the maintainability benefit associated with service boundaries without requiring distributed deployment, network calls, independent observability, or multiple data-management strategies. It is a strong evolutionary starting point.
4.3 Microservices
Microservices divide a system into independently deployable services organized around business capabilities. Each service should own a coherent responsibility and, ideally, its data model. Communication occurs through APIs or messages.
Benefits include independent deployment and scaling, technology autonomy, and fault isolation when boundaries are well chosen. Costs include network latency, distributed transactions, versioned contracts, duplicated infrastructure, more difficult testing, observability requirements, and operational complexity. Microservices are not automatically more scalable or more maintainable.
A service boundary should be justified by domain ownership, scaling differences, security isolation, release independence, or team structure—not merely by the number of classes in a codebase.
4.4 Event-Driven Systems
In an event-driven system, producers publish facts such as “OrderPlaced,” and consumers react independently. This reduces direct coupling and supports integration, audit trails, and asynchronous work.
The trade-off is temporal and causal complexity. Consumers may observe events later, events may be duplicated, schemas evolve, and debugging requires correlation identifiers and distributed tracing. Events should describe completed facts rather than ambiguous commands unless command semantics are intentional.
4.5 Twelve-Factor Applications
The twelve-factor methodology describes operational principles for cloud-deployed applications, especially those managed as replaceable processes:
Codebase: one tracked codebase per application, deployed to multiple environments.
Dependencies: explicitly declare and isolate dependencies.
Config: store environment-specific configuration in the environment, not source code.
Backing services: treat databases, queues, and other services as attached resources.
Build, release, run: separate artifact creation, configuration of a release, and execution.
Processes: run the application as stateless, share-nothing processes.
Port binding: export services through a port rather than relying on an injected web server.
Concurrency: scale by running multiple process instances or process types.
Disposability: support fast startup and graceful shutdown.
Dev/prod parity: keep development, testing, and production as similar as practical.
Logs: treat logs as event streams and let the execution environment aggregate them.
Admin processes: run one-off administrative tasks, such as migrations or data repairs, as separate processes using the same code and configuration.
The methodology complements, but does not determine, whether an application is monolithic or microservice-based. A modular monolith can follow twelve-factor principles.
5. Deployment Models in Heroku and AWS
In Heroku, an application is commonly packaged through a buildpack or container and run in dynos. Configuration is supplied through config vars, and add-ons can provide managed databases or other services. Heroku’s strengths include a short path from repository to deployment, standardized operations, and accessible scaling. Constraints may include platform-specific networking, dyno characteristics, add-on choices, and cost at larger or unusual workloads.
AWS permits a more granular composition. A typical arrangement might use a CDN and DNS service at the edge, object storage for static assets, a load balancer, containers or serverless compute for the API, a managed relational database, a managed queue, and centralized logging. This offers extensive control but transfers more design and operational responsibility to the team.
A deployment pipeline should build an immutable artifact, run automated tests and security checks, deploy to a controlled environment, perform health checks, and support rollback. Database migrations require special care: backward-compatible schema changes are safer when application versions overlap during rolling deployment.
6. Reliability, Security, and Governance
Reliability is an architectural property, not merely a monitoring feature. Use health checks, timeouts, bounded retries, circuit breakers where suitable, graceful degradation, backups, tested restoration, and capacity planning. Retries must be bounded and preferably use exponential backoff with jitter; otherwise many clients may retry simultaneously and intensify an outage.
Availability for independent sequential components is approximately the product of their availabilities under simplifying assumptions. If an API depends sequentially on two services with availabilities 0.999 and 0.9995, the combined availability is approximately:
0.999 × 0.9995 = 0.9985005
This is about 99.85005%, or approximately 13.1 hours of downtime per 365-day year if the estimate applies uniformly. The calculation is only an approximation: real failures may be correlated, redundancy may change the model, and planned maintenance may be excluded. It illustrates why unnecessary synchronous dependencies can reduce reliability.
Security architecture should apply least privilege, strong identity, secret rotation, encryption, input validation, dependency scanning, network segmentation where justified, audit logging, and secure defaults. Authentication answers “who are you?” Authorization answers “what may you do?” They must not be conflated.
Privacy and governance require data classification, retention limits, deletion procedures, access reviews, incident response, regional considerations, and evidence of compliance where applicable. Logs can contain personal or payment information; observability must therefore be designed with redaction and access control.
7. Illustrative Case: Campus Marketplace
Background
A university wants a marketplace where students list used textbooks, upload photographs, search listings, and receive notifications when an item is sold.
Problem
The first prototype stores images inside the application server, sends email during the purchase request, and uses one large controller containing listing, payment, and notification logic. During registration periods, image uploads consume server resources and email delays make purchase responses slow.
Analysis
The requirements show three interaction types. Searching and purchasing require prompt responses. Image resizing and notification delivery can be asynchronous. Listing and purchase records require transactional consistency. Images are large binary objects and should not be stored as database rows unless there is a specific reason.
Approach and Solution
A modular monolith is selected initially because the team is small and the domain is still changing. The front end is delivered through a CDN. The API server authenticates users and handles listing and purchase workflows. A relational database stores users, listings, orders, and image metadata. Private object storage holds original and resized images. After a purchase transaction commits, an outbox record is published to a queue. Notification workers consume the queue and call the email provider. Image-processing workers consume upload jobs and write derived objects back to storage. Each job contains an idempotency key, and failed jobs move to a dead-letter queue after bounded retries.
The application can run on Heroku with web and worker dynos, a managed relational database, and an external object store and queue. An AWS implementation could use a managed container or serverless API, a relational database, object storage, a queue, workers, and a CDN. The logical architecture remains the same.
Outcome
Purchase responses no longer wait for email delivery. Image processing scales independently from web traffic. The database remains the source of truth for listing and order state, while the queue provides durable work scheduling. Operational dashboards show API latency, queue depth, job age, worker failures, database capacity, and object-storage errors.
Learning Points
The case demonstrates that architecture follows requirements rather than labels. A modular monolith can use asynchronous processing and cloud-native operational principles. Moving a function to a worker does not remove the need for idempotency, monitoring, security, or failure handling. Separating binary objects from transactional metadata improves both cost and design clarity.
8. Contemporary Practices and Professional Implications
Infrastructure as code improves repeatability and reviewability. Containers standardize packaging, but they do not eliminate application-level concerns. Platform engineering increasingly provides reusable deployment templates, policy controls, observability, and secure defaults to development teams.
AI services can be integrated for classification, recommendations, or content moderation, but their use introduces model latency, variable cost, privacy concerns, bias, explainability limitations, and failure modes. AI workloads should use explicit data-governance rules, human review where consequences are significant, and asynchronous processing when inference is slow or expensive.
Professionals should document architecture decisions, including alternatives rejected and assumptions made. A decision record might explain why a relational database was chosen, why an operation is asynchronous, or why a monolith is currently preferred. Architecture is evolutionary: measure actual behavior, revisit assumptions, and migrate boundaries when evidence justifies the cost.
Challenges and Limitations
No architecture eliminates trade-offs. Managed services reduce undifferentiated operations but create vendor dependence and service-specific knowledge. Distributed systems can improve isolation but make consistency and debugging harder. Caching improves latency but creates staleness. Autoscaling responds to load but may be slow for sudden bursts and can increase cost unexpectedly. Serverless platforms simplify operations but may introduce startup latency, execution limits, and different debugging models.
Architecture diagrams also simplify reality. They should be supplemented by data-flow diagrams, threat models, deployment views, API contracts, runbooks, and service-level objectives. A diagram that omits retries, authentication, data ownership, or failure handling may be visually attractive but operationally misleading.
Chapter Summary
Cloud architecture translates functional and non-functional requirements into cooperating components and operational practices. Full-stack systems commonly include a client, edge delivery, API and application server, database, queue and workers, object storage, and observability controls. Synchronous operations serve immediate needs; asynchronous operations use queues and idempotent workers for long-running or failure-prone work.
Monoliths optimize simplicity, modular monoliths add internal boundaries, microservices provide independent deployment at greater operational cost, and event-driven systems reduce direct coupling while introducing eventual-consistency and debugging challenges. The twelve-factor principles—including one-off administrative processes—support portable, observable, replaceable cloud applications regardless of whether the implementation is monolithic or distributed.
Heroku offers a productive managed platform, while AWS offers wider compositional control. In both environments, secure defaults, explicit data ownership, tested recovery, deployment automation, and evidence-based evolution are central to professional architecture.
Key Terms
Cloud architecture: The design of cloud-hosted components, relationships, and operational controls.
Functional requirement: A statement of what a system must do.
Non-functional requirement: A quality, constraint, or operational property of a system.
API: A defined interface through which software components communicate.
Application server: A runtime that executes application logic and serves requests.
CDN: A content-delivery network that caches and serves content from distributed edge locations.
Relational database: A database organized around related tables, constraints, and transactions.
Cache: A faster temporary store that reduces repeated computation or access to a source system.
Object storage: A service for storing named files or binary objects with metadata.
Queue: A mechanism that stores work until consumers process it.
Worker: A process that performs background jobs.
Event stream: A retained sequence of events that can be consumed by multiple subscribers.
Idempotency: The property that repeated processing has the same intended effect as one processing.
Monolith: An application deployed as one principal unit.
Modular monolith: A monolith with explicit internal modules and boundaries.
Microservice: An independently deployable service organized around a focused capability.
Twelve-factor application: An application following twelve operational principles for cloud deployment.
Outbox pattern: A design that records an event transactionally before publishing it asynchronously.
Dead-letter queue: A destination for messages that repeatedly fail processing.
Infrastructure as code: Declarative or programmable management of infrastructure through versioned files.
Review Questions
Short Answer Questions
Distinguish a functional requirement from a non-functional requirement and give one example of each.
Why is object storage usually preferable to an application server’s local filesystem for user-uploaded media?
What is the purpose of a queue in an asynchronous architecture?
Define idempotency in the context of background workers.
Name the twelve-factor principle concerned with one-off migrations and administrative tasks.
Long Answer Questions
Compare a monolith, modular monolith, and microservices architecture using deployment, testing, scaling, and operational criteria.
Explain how a full-stack application can combine a CDN, API server, relational database, object storage, queue, and workers.
Discuss the benefits and limitations of event-driven architecture, including delivery duplication and eventual consistency.
Explain how the twelve-factor principles support deployment on Heroku or AWS.
Analyze the security and governance controls required for a system that stores personal data and user-uploaded files.
Analytical / Application Questions
Design an architecture for a video-sharing application. Identify which operations are synchronous, which are asynchronous, and how failures and retries should be handled.
A service receives 10 image-processing jobs per second. Each worker processes an average of 0.4 jobs per second. How many workers are required for nominal capacity to exceed arrival rate, and what additional factors must be considered before deployment?
A team of four developers is building a changing product with moderate traffic. Evaluate whether it should begin with a modular monolith or microservices, and justify the decision using organizational and technical evidence.
Multiple Choice Questions with Answers
Question 1
Which component should normally consume background jobs in the reference architecture?
A. The CDN
B. The database
C. A worker consuming from the queue
D. The browser directly
Correct Answer: C. A worker consuming from the queue
Question 2
Which requirement most directly describes a non-functional property?
A. Users can upload photographs
B. Administrators can suspend accounts
C. The system returns search results within 300 milliseconds
D. Users can reset passwords
Correct Answer: C. The system returns search results within 300 milliseconds
Question 3
What is the primary purpose of object storage in a full-stack cloud application?
A. To execute HTTP routes
B. To store files such as images and documents
C. To replace authentication
D. To schedule database transactions
Correct Answer: B. To store files such as images and documents
Question 4
A worker processes one job in 0.5 seconds on average. What is its nominal processing rate?
A. 0.5 jobs per second
B. 1 job per second
C. 2 jobs per second
D. 5 jobs per second
Correct Answer: C. 2 jobs per second
Question 5
Which practice makes a background job safer to process more than once?
A. Using an idempotency key or unique operation constraint
B. Removing all failure retries
C. Storing the job only in process memory
D. Allowing every retry to create a new payment
Correct Answer: A. Using an idempotency key or unique operation constraint
Question 6
Which architectural style uses one deployable unit with explicit internal boundaries?
A. Modular monolith
B. Microservices
C. Event stream
D. CDN architecture
Correct Answer: A. Modular monolith
Question 7
Which twelve-factor principle separates artifact creation, release configuration, and execution?
A. Logs
B. Build, release, run
C. Port binding
D. Concurrency
Correct Answer: B. Build, release, run
Question 8
What is a major trade-off introduced by microservices?
A. They eliminate network failures
B. They always reduce operating cost
C. They introduce distributed communication and observability complexity
D. They require all data to be stored in one table
Correct Answer: C. They introduce distributed communication and observability complexity
Question 9
If four workers each process 2 jobs per second, what is their nominal combined capacity?
A. 2 jobs per second
B. 4 jobs per second
C. 6 jobs per second
D. 8 jobs per second
Correct Answer: D. 8 jobs per second
Question 10
Which response is commonly appropriate when an API accepts a long-running task for asynchronous processing?
A. HTTP 202 Accepted with a job identifier
B. HTTP 301 Moved Permanently only
C. HTTP 404 Not Found
D. No response until the task finishes
Correct Answer: A. HTTP 202 Accepted with a job identifier
Cloud Integration & Deployment (Heroku/AWS)
Chapter 2
of 14