19 comparisons
Things that sound alike
Each of these pairs or trios of concepts or products gets mixed up in design reviews. Here’s how they actually differ.
Object-oriented, functional or service layer?Object-oriented programmingFunctional programmingService layerThese aren’t rival camps; most real backends use all three. A common, healthy mix: a service layer as the entry point for each use case, domain objects that guard their own rules, and pure functions for the calculations in between. Reach for objects where state has rules, functions where data flows, and services where a request has to be coordinated across a database, payments and email.Static or dynamic dispatch?Static dispatchDynamic dispatchDefault to static dispatch for code on the hot path where every type is known, and to dynamic dispatch where flexibility matters more than a few nanoseconds per call: plugin systems, heterogeneous lists, dependency injection, tests. Many designs mix them: a generic inner loop called from a `dyn` interface at the edge, or a C++ template that shares its non-generic core through a base class. Measure before switching; JITs such as HotSpot often remove the cost of virtual calls that only ever see one type.Event loop or threads?Event loopMultithreadingIf connections mostly wait on the network and there are thousands of them, an event loop is cheap and avoids locks. If the work is CPU-heavy, or the code and libraries are blocking, use threads, ideally from a pool. Goroutines and Java’s virtual threads blur the line: you write blocking, thread-per-request code, and the runtime parks a waiting thread and runs another on the same OS thread. Either way, keep slow work off the thread that serves everyone else.Monolith, microservices or serverless?MonolithsMicroservicesServerless architectureThese are not stages you must pass through. Most systems should start as a well-structured monolith and split off a service only when a team or a part of the load clearly needs its own lifecycle; Fowler’s rule of thumb is not to consider microservices unless the system is too complex to manage as a monolith. Serverless functions fit around either style, for jobs triggered by events. Mixes are normal: a monolith with a few functions for image resizing and webhooks is a common, healthy shape.Queue, stream or pub/sub?Message queuesEvent streamsPub/subIf the work should happen once, use a queue. If several systems care and nobody needs history, use pub/sub. If you’d ever want to rewind, use a stream. Real systems often combine them, such as SNS fanning out to one SQS queue per subscriber.VM, container, microVM or function?Virtual machinesContainersMicroVMsServerless functions (FaaS)These layer on each other more than they compete: containers usually run on VMs, and function platforms run your code inside containers or microVMs. The real questions are how much of the stack you want to own, and whether you trust the code you’re running.Kata Containers, gVisor or Firecracker?Kata ContainersgVisorFirecrackerThese aren’t three rival products. Firecracker is a building block, and Kata can use it as its hypervisor, so “Kata or Firecracker” is often “Kata with Firecracker”. The real choice is the boundary: a VM with its own kernel (Kata on any hypervisor, or Firecracker under a platform you build yourself) or gVisor’s user-space kernel. Pick gVisor when your nodes have no KVM, or when start-up time and density matter and your software fits its system-call coverage. Pick Kata when you need a full Linux kernel, privileged containers or GPUs, and can run on bare metal or nested virtualisation. Use Firecracker directly only if you’re building your own sandbox or functions platform and are ready to supply the kernel, root filesystem, networking and scheduler.Object, block or file storage?Object storageBlock storageFile storageA typical app uses all three: block storage under its database, object storage for uploads and backups, and file storage only when several servers truly need the same folder. Software that expects files can still use a bucket through a mount such as Amazon S3 Files or Mountpoint, with limits.Load balancer, API gateway or CDN?Load balancersAPI gatewaysCDNsA common production path uses all three in a row: the CDN at the edge, then an API gateway or layer-7 load balancer, then your services.Container or workflow orchestration?Container orchestrationWorkflow orchestrationBoth get called “orchestration”, which causes endless confusion. One keeps servers alive; the other keeps a business process moving.Key-value, document or wide-column?Key-value storesDocument databasesWide-column storesAll three hash or range-split a key to spread data across machines, which is why they get lumped together as NoSQL. The difference is how much of your data the database understands. If you only ever fetch by ID, a key-value store is enough; if you search by fields inside records, use documents; if you write a lot and read back ranges within a partition, use wide-column. Some products span two: DynamoDB is both key-value and document, and Redis has a JSON type.EAV, JSON column, wide table or document?Entity-attribute-value (EAV)Emergent schema (JSON columns)Wide tablesDocument databasesStart with columns for every field you know you’ll query, and put the unpredictable rest in a JSON column. Watch which keys get used and promote those to real or generated columns. Reach for EAV only when attributes are themselves data that users define, and you’re ready to build the metadata layer it needs; switch to a document database when whole records, not just a tail of fields, vary.Wide, hybrid or narrow tables?Wide tablesHybrid (medium) tablesNarrow tablesStart from how you read, not how data arrives. If dashboards show many metrics of one thing at one moment and the list is stable, go wide. If metrics come and go and are read one series at a time, go narrow. If they come and go but you want native types, add typed value columns. Mixing is normal: TigerData suggests a wide table for core metrics and a medium table for custom ones. Moving between layouts later means rewriting history, so when unsure, pick the one that extends without migrations.Cache or database?CachingRelational databasesDesign so the app still works, only slower, if the cache is empty. If losing the cache would lose data, it isn’t a cache any more.In-process cache, shared cache or CDN?In-process cachesCachingCDNsThey stack rather than compete. A typical read path is CDN for public HTTP responses, then an in-process cache for the few hottest objects, then a shared key-value cache that all instances agree on, then the database. Put data in the layer whose staleness you can live with: an in-process copy can be out of date per instance for its whole TTL, a shared cache can be fixed with one delete, and a CDN copy lasts until its max-age or a purge.Data lake, lakehouse or warehouse?Data lakesLakehousesData warehousesThey stack more than they compete. A lakehouse is a data lake with a table format on top, and most warehouses now read and write Iceberg tables in it. Ask where the authoritative copy lives, whether writes are transactions, and who else can read it without a copy job.File format or table format?File formatsTable formatsThey stack rather than compete. A table format is metadata that points at files in a file format, almost always Parquet, so you choose one of each.Rolling, blue-green or canary?Rolling deploymentsBlue-green deploymentsCanary releasesStart with rolling deployments; they are the default for a reason and cost nothing extra. Add blue-green when a slow rollback would hurt more than paying for a second environment, and canaries when you have the traffic and the metrics to judge a new version on a slice of users. They combine: Amazon ECS canary deployments shift traffic between a blue and a green revision, and many teams canary first and then roll the rest. All three keep two versions alive for a while, so database changes still need expand and contract.Logs, metrics or traces?LogsMetricsDistributed tracingYou need all three, in this order: metrics to notice (alert on rate, errors and duration), traces to find the slow or failing hop, and logs for the details of that one request. Make them join from the start: the same service name everywhere and the trace ID in every log line.