Serverless is a billing-and-scaling model, not a badge of modernity. The decision turns almost entirely on the shape of your load.
Scanned 9/10/2026
Install to Claude Code
npx -y skills add snoodleboot-io/prompticorn --skill verbose --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Verbose?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/snoodleboot-io-verbose-e20449de)More formats (shields.io, HTML) on the badges page.
# Serverless Architecture (Verbose)
## Core Patterns
### When Serverless Wins and When It Loses
Serverless is a billing-and-scaling model, not a badge of modernity. The decision
turns almost entirely on the shape of your load.
| Load shape | Serverless (FaaS) | Always-on container / VM |
|---|---|---|
| Spiky, unpredictable | Excellent — scales instantly, idle costs ~nothing | Wasteful — provisioned for a peak that is rare |
| Low or zero baseline | Excellent — scale-to-zero | Wasteful — paying to sit idle |
| Event-driven / glue | Excellent — natural fit | Awkward — a service babysitting a queue |
| Steady, high throughput | Poor — per-invocation cost adds up, cold starts hurt | Excellent — near-capacity utilization is cheap |
| Latency-critical, tight p99 | Risky — cold starts add tail latency | Predictable — warm process always ready |
| Long-running jobs | Poor — invocation timeout | Fine — no artificial ceiling |
The classic mistake is porting a steady, high-QPS API to functions to "be
serverless" and being surprised by both the bill and the tail latency. The
inverse mistake is running a cron job or a webhook receiver on an always-on
fleet, paying 24/7 for seconds of work per day.
A useful crossover intuition: below some steady request rate, per-invocation
billing is cheaper; above it, reserved always-on compute wins. You do not need
the exact number — you need to know which side of it your workload sits on, and
that it moves as traffic grows.
### Statelessness and the Execution Lifecycle
A function instance is created, may serve one or many invocations, is frozen
between them, and is eventually destroyed — all outside your control. Two
consequences drive the design:
- **No durable local state.** Anything written to memory or local disk may vanish
before the next call and is never shared across concurrent instances. Persist
state in a managed database or cache (managed-database-selection,
distributed-caching-design).
- **Initialization is reused when warm.** Code outside the handler runs once per
instance, not once per request. Put expensive one-time setup — SDK clients,
DB connection pools, config loads — there, so warm invocations skip it.
```python
# module scope: runs at cold start, reused across warm invocations
db = connect_pool() # do this ONCE per instance
client = StorageClient()
def handler(event, context):
# per-request work only; keep this path lean
return process(event, db, client)
```
Every platform imposes a per-invocation timeout you must design around. Work that
cannot finish inside it must be decomposed into steps or handed to a batch/queue
system — never assume you can raise the ceiling far enough.
### Cold Starts
A cold start is the time to provision a runtime, load your code, and run
initialization before the first request is served. It is paid whenever the
platform adds an instance — the first request after idle, and every request that
scales the fleet up.
Drivers and mitigations:
- **Package size / dependency weight** → trim dependencies, avoid pulling entire
SDKs when a submodule will do.
- **Heavy init** → move it to module scope so it amortizes across warm calls;
lazy-load anything not needed on every path.
- **Runtime choice** → interpreted/lightweight runtimes generally start faster
than heavy JVM-style ones.
- **VPC / private-network attachment** → historically adds startup cost; keep
functions out of a VPC unless they need private resources.
- **Latency-critical paths** → use provisioned/warmed concurrency to keep
instances hot, accepting that it reintroduces an always-on cost.
Load-test the scale-from-zero and scale-up paths explicitly (see load-testing).
Cold starts are invisible in steady-state testing and then surface as p99 spikes
in production.
### Event-Driven Composition
Serverless systems are wired together by events, not by services calling each
other directly:
```
S3 object created ─▶ Lambda (thumbnail) ─▶ writes derived object
API Gateway ─▶ Lambda (handler) ─▶ SQS ─▶ Lambda (worker) ─▶ DynamoDB
EventBridge schedule ─▶ Lambda (nightly rollup)
```
Keep each function single-purpose and let a queue or pub/sub topic sit between
producers and consumers. That decouples them, absorbs bursts, and gives you a
natural retry and dead-letter boundary. Fan-out (one event, many independent
consumers) is done with a topic, not by one function invoking several others.
### Orchestrating Multi-Step Workflows
Chaining functions by direct synchronous invocation is an anti-pattern: the
caller is billed while it blocks waiting for the callee, and their timeouts
become coupled — the outer function can time out mid-way, leaving partial work.
Use a managed orchestrator for anything with steps, branching, or retries:
- **AWS Step Functions** — a JSON/ASL state machine with built-in retry,
catch, parallel, and wait states.
- **Google Cloud Workflows** / **Azure Durable Functions** — equivalents.
The orchestrator owns the state and progress; each function stays a small,
stateless step. For high fan-out or buffering, prefer an asynchronous queue
between steps over a synchronous chain.
### Idempotency and Failure Handling
Event sources and queues generally guarantee at-least-once delivery, so any
handler can run more than once on the same message — after a retry, a
redelivery, or a duplicate publish. Handlers must be idempotent: processing the
same event twice must not double-charge, double-send, or corrupt state (see
idempotency-patterns for keys and dedup tables).
Wire a dead-letter queue on every asynchronous source so that a message which
keeps failing is parked for inspection instead of retried forever or dropped
silently. Emit structured logs and traces per invocation — distributed tracing
across function boundaries is how you reconstruct an event's path.
## Common Anti-Patterns
❌ **Porting a steady high-QPS service to FaaS to "be serverless".**
✅ Match the model to the load shape — always-on compute for steady throughput,
serverless for spiky or event-driven work.
❌ **Storing state in a function's local memory or disk** and expecting it next
time.
✅ Externalize all state to a managed store; treat every invocation as fresh.
❌ **One function synchronously invoking the next, several deep.**
✅ Use a workflow orchestrator, or decouple steps with a queue or topic.
❌ **Non-idempotent handlers on an at-least-once source.**
✅ Make every handler idempotent and add a dead-letter queue for poison messages.
❌ **Ignoring cold starts until production.**
✅ Trim packages, keep init out of the hot path, load-test scale-from-zero, and
use provisioned concurrency where tail latency matters.
❌ **A long-running job fighting the invocation timeout.**
✅ Decompose it into steps under an orchestrator, or move it to a batch service.
❌ **Putting a function in a VPC by reflex.**
✅ Attach to private networking only when it needs a private resource; accept the
startup cost knowingly.
## Serverless Architecture Checklist
- [ ] Load shape confirmed to favour serverless (spiky / low-baseline / event-driven)
- [ ] All durable state externalized to a managed store
- [ ] Expensive initialization moved to module scope, reused across warm calls
- [ ] Work fits inside the invocation timeout, or is decomposed
- [ ] Cold-start budget understood; scale-from-zero load-tested
- [ ] Provisioned concurrency used only where tail latency demands it
- [ ] Functions single-purpose, composed via events and queues/topics
- [ ] Multi-step flows run under an orchestrator, not synchronous chains
- [ ] Handlers idempotent against at-least-once delivery
- [ ] Dead-letter queues on every asynchronous source
- [ ] Structured logs and distributed tracing across function boundaries
- [ ] Cost modeled against an always-on alternative at expected steady load
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!