REST vs GraphQL: Multiple Endpoints vs Single Query Language

Overview REST structures an API as a fixed set of endpoints, each returning a predetermined shape of data tied to a resource. GraphQL exposes a single endpoint driven by a client-specified query, letting callers request exactly the fields they need across related resources in one round trip. Comparison Diagram RESTGraphQLClient/users/1/users/1/posts/posts/1/comments3 requests, fixed shapesResponse 1: full user objectResponse 2: full posts arraymay over- or under-fetch fieldsClient/graphql{ user(id:1){name posts{ title }} }1 request, client-shapedSingle JSON responsematches requested fields Comparison Table Aspect REST GraphQL Request entry point Multiple resource-based URLs (e.g. /users, /posts) Single endpoint (e.g. /graphql) for all operations Query specification Server defines response shape per endpoint Client defines response shape via query document Fetching related data Requires multiple round trips or ad-hoc nested routes Nested relations resolved in one request via resolvers Over/under-fetching Common — fixed payloads return unused or missing fields Minimized — client requests exactly the fields it needs Caching Leverages HTTP caching (ETags, CDNs, cache-control) Requires custom client-side or persisted-query caching Versioning strategy New versions (/v2/) or new endpoints for breaking changes Schema evolves additively; fields deprecated in place Error handling HTTP status codes signal success/failure per request 200 OK typical even on partial errors; errors array in body Tooling and discovery Relies on external docs (OpenAPI/Swagger) for contracts Self-describing schema with built-in introspection Key Differences REST models an API around resources and HTTP verbs; GraphQL models it around a typed schema and queries. REST responses have a shape fixed by the server; GraphQL responses are shaped by the client query itself. REST benefits from standard HTTP caching infrastructure; GraphQL typically needs bespoke caching layers. Fetching nested or related data usually takes REST multiple round trips, while GraphQL resolves it in a single request. REST signals failures through HTTP status codes; GraphQL usually returns 200 with errors embedded in the payload. When to Use Each REST ...

September 6, 2026 · 3 min · 428 words · jeonck

Batch vs Stream Processing: Bounded Data Dumps vs Continuous Event Flow

Overview Batch processing collects data over a period and runs computation on the whole bounded set at once, while stream processing handles each event as it arrives, continuously. The choice determines whether your system optimizes for throughput and simplicity or low latency on fresh results. Comparison Diagram BatchStreamData accumulatesinto a bounded setScheduled jobprocesses all at onceResult: high latencyEvents flow continuouslyprocessprocessprocessprocessResult: low latency Comparison Table Aspect Batch Processing Stream Processing Data ingestion Data collected and stored until job triggers Events consumed individually as they arrive Data scope per run Bounded, finite dataset (a file, a partition, a day’s data) Unbounded, continuous sequence of events Processing trigger Scheduled interval or manual kickoff (hourly, nightly) Continuous, triggered by each event or micro-window Latency to result Minutes to hours, depending on schedule Milliseconds to seconds State management Recomputed fresh from full dataset each run Maintained incrementally across the event stream Fault recovery Rerun the failed job against the same input Checkpointing and replay from an offset in the log Ordering guarantees Whole dataset available, so ordering enforced within the job Ordering must be explicitly handled (per-key, watermarks) Resource usage pattern Spiky: idle, then a burst of compute at run time Steady, sustained compute and memory footprint Key Differences Batch operates on a bounded dataset, stream operates on an unbounded sequence of events Batch trades latency for simplicity and throughput; stream trades complexity for freshness Stream systems need watermarks to handle late or out-of-order events, which batch avoids entirely Failure recovery in batch means rerunning the job; stream relies on checkpoint and replay semantics Batch pipelines are easier to reason about and test since input is fixed and reproducible When to Use Each Batch Processing ...

September 6, 2026 · 2 min · 388 words · jeonck

Push vs Pull: Who Initiates the Data Transfer

Overview Push and pull describe which side initiates a data transfer between two systems: in a push model the source sends data as soon as it’s ready, while in a pull model the consumer requests data on its own schedule. The choice shapes latency, backpressure handling, and how tightly the two sides are coupled in time. Comparison Diagram PushPullSourceConsumersends datawhen readySourceConsumerrequests dataon its scheduleSource controls timingConsumer controls timing Comparison Table Aspect Push Pull Initiator Source system triggers the transfer Consumer system triggers the transfer Timing control Source decides when data is sent Consumer decides when to fetch Latency to consumer Near-immediate once source has data Bounded by polling interval, not source readiness Backpressure handling Source must slow down or buffer if consumer is overwhelmed Consumer naturally paces itself by requesting only when ready Coupling Source needs to know consumer’s address/endpoint Consumer needs to know source’s address/endpoint Resource cost when idle No wasted work; nothing sent if no updates Repeated requests even when nothing changed Failure handling Source retries or queues if delivery fails Consumer retries the pull on its own next cycle Typical mechanisms Webhooks, pub/sub, server-sent events Polling, cron jobs, request/response APIs Key Differences Push minimizes latency by sending data the instant it’s available, while pull bounds latency to the polling interval. Pull gives the consumer natural backpressure control since it only asks for data when ready to process it. Push requires the source to hold a reference to every consumer’s endpoint, increasing fan-out coupling. Pull wastes resources on empty polls when there’s nothing new to fetch. Push systems need retry or queueing logic on the sender side; pull systems just retry the request on the next cycle. When to Use Each Push ...

September 6, 2026 · 2 min · 396 words · jeonck

Total Ordering vs Partitioned Ordering: One Global Sequence vs Per-Key Order

Overview In distributed logs and message queues, total ordering guarantees every event in the system is seen in one single sequence, while partitioned ordering only guarantees order within each partition or key, letting unrelated events interleave freely. The choice trades a single-writer bottleneck for horizontal scalability, and it directly determines how strong an ordering guarantee downstream consumers can rely on. Comparison Diagram Total OrderingPartitioned Ordering123456ConsumerOne sequence: 1 to 2 to 3 to 4 to 5 to 6All producers merge into a single ordered logP1123C1P2123C2P3123C3Order guaranteed only within each partitionNo ordering guarantee across P1, P2, P3 Comparison Table Aspect Total Ordering Partitioned Ordering Ordering scope Every event in the system shares one single global sequence Order guaranteed only among events sharing the same partition or key How order is assigned A single sequencer, leader, or log appends events one at a time A partitioner (e.g. hash of key) routes events into independent per-partition logs Write throughput Bounded by the single serialization point; writes cannot be parallelized Scales horizontally, since each partition accepts writes independently Consumer guarantee Any consumer reading the full stream sees an identical event order A consumer only sees ordered events within the partitions it reads Cross-entity relationships Causal relationships between unrelated entities are preserved Events for different keys can arrive interleaved or out of relative order Effect of adding capacity Adding nodes doesn’t help; throughput stays capped by the single stream Adding partitions increases throughput, but existing key-to-partition mapping must stay stable Failure behavior Sequencer or leader failure stalls or requires careful recovery to preserve order A failed partition affects only its own keys; other partitions keep processing Key Differences Total ordering guarantees a single global sequence; partitioned ordering guarantees order only per key. Total order requires a single writer or sequencer, capping throughput, while partitioned order enables parallel writes across partitions. Partitioned ordering scales by adding more partitions; scaling total order needs a fundamentally different design. A sequencer failure threatens the entire order in total ordering, while failure in partitioned ordering is isolated per partition. Total ordering preserves causality between unrelated entities; partitioned ordering only preserves it within the same partition key. When to Use Each Total Ordering ...

September 6, 2026 · 3 min · 473 words · jeonck

At-Least-Once vs Exactly-Once: Delivery Guarantees Compared

Overview Messaging and stream-processing systems must pick a delivery guarantee: does a message arrive at least one time (possibly more), or does its effect happen precisely once no matter how many retries occur? At-least-once favors simplicity and throughput by retrying until acknowledged, at the cost of possible duplicates; exactly-once layers on deduplication or transactional coordination so retries never produce a second effect. The choice matters because a duplicate side effect — a double charge, a double email, a double stock decrement — can be catastrophic or merely annoying depending on the domain. ...

September 6, 2026 · 2 min · 425 words · jeonck

2PC vs Saga: Atomic Commit vs Compensating Transactions

Overview Both patterns coordinate a transaction that spans multiple services or databases, but they resolve the coordination problem in opposite ways. 2PC locks every participant until a coordinator confirms all can commit, guaranteeing atomicity at the cost of blocking; Saga lets each step commit immediately and unwinds failures afterward with compensating actions, trading strict atomicity for availability and throughput. Comparison Diagram 2PCSagaCoordinatorP1P2P3prepare / vote / commitlockedlockedlockedall-or-nothing, blocking until ackT1T2T3local commit, local commitcompensatecompensateindependent commits, compensating rollbacks Comparison Table Aspect 2PC Saga Initiation Coordinator sends a prepare request to all participants at once First service runs its local transaction and triggers the next step Commit decision Coordinator waits for every vote, then issues a single atomic commit or abort No central decision; each step commits independently as it finishes Resource locking Participants hold locks from prepare until the commit acknowledgment arrives No cross-step locks; each local transaction commits and releases immediately Failure handling Coordinator aborts and tells all participants to roll back the uncommitted work Already-committed steps are undone via explicit compensating transactions Atomicity guarantee True all-or-nothing atomicity across every participant No real atomicity; intermediate states are visible until compensations finish Coordination dependency Single coordinator is a synchronous, blocking point of failure Runs via choreography or a lightweight orchestrator that doesn’t hold locks Latency and throughput Higher latency and lower throughput from synchronous cross-service locking Lower per-step latency and higher throughput since nothing blocks across services Implementation effort Relies on XA-compliant resources and a transaction manager Requires custom compensating logic and step/state tracking per operation Key Differences 2PC provides true atomicity across services, while Saga only approximates it through compensations after the fact 2PC holds locks on every participant until the coordinator commits; Saga commits each step locally with no cross-service locking Saga failures require explicit compensating transactions; 2PC failures simply abort the still-uncommitted transaction 2PC depends on a synchronous coordinator that all participants must trust and wait on; Saga can run via choreography or a non-blocking orchestrator 2PC trades throughput for consistency, while Saga trades strict consistency for availability at scale When to Use Each 2PC ...

September 6, 2026 · 3 min · 470 words · jeonck

Choreography vs Orchestration: Who Drives the Workflow

Overview Both patterns coordinate a multi-step business process across independent services, but they differ in where the coordination logic lives. In choreography, each service reacts to events and decides its own next move with no central brain; in orchestration, a dedicated controller tells every service what to do and in what order. Comparison Diagram ChoreographyOrchestrationOrder SvcPayment SvcShipping SvceventeventeventOrchestratorPayment SvcOrder SvcShipping Svcno central controllercommands out, responses back Comparison Table Aspect Choreography Orchestration Trigger Any service publishes an event when something happens A client or event calls the orchestrator to start the process Coordination logic Distributed across each service’s event handlers Centralized in one orchestrator component Communication style Asynchronous events broadcast to whoever is listening Explicit commands and replies directed at specific services Step sequencing Emergent from chained event subscriptions Explicitly defined as a workflow or state machine Failure handling Each service listens for failure events and compensates locally Orchestrator detects failure and drives compensating transactions Adding a new step Add a listener; no existing service needs to change Update the orchestrator’s workflow definition Observability Hard to see the full process; requires distributed tracing Process state is visible in one place, easy to audit Coupling Low coupling between services, higher coupling to event schema Services decoupled from each other, but coupled to the orchestrator Key Differences Choreography spreads decision-making across services via events; orchestration centralizes it in a single controller. Choreography scales extensibility easily but makes the overall process hard to trace. Orchestration makes the workflow explicit and easy to audit, at the cost of a single point of coordination. Compensation logic lives in each service under choreography, but is driven centrally under orchestration. Orchestration introduces a dependency on the orchestrator itself as new coupling, even as it decouples the services from each other. When to Use Each Choreography ...

September 6, 2026 · 2 min · 413 words · jeonck

Queue vs Event Log: Consume-Once Delivery vs Replayable Stream

Overview A message queue and an event log both move data from producers to consumers, but they differ in what happens after a message is read. A queue treats delivery as a one-time handoff where each message is consumed once and then removed, while an event log keeps every event in an ordered, replayable sequence that multiple independent readers can consume at their own pace. This distinction drives how each handles multiple consumers, failure recovery, and historical reprocessing. ...

September 6, 2026 · 2 min · 426 words · jeonck

Synchronous vs Asynchronous: Blocking Calls vs Non-Blocking Flow

Overview Synchronous and asynchronous describe whether a caller waits for an operation to finish before moving on. Synchronous execution blocks the calling thread until a result returns, while asynchronous execution lets the caller continue and gets notified or polls for completion later. The choice shapes throughput, resource usage, and how errors and ordering are handled throughout a system. Comparison Diagram SynchronousAsynchronousCallerCall fn()Work runsCallerblockedResult usedone blocking timelineCallerCall fn()Work runsContinues freeOther workCallback firesinterleaved timelines Comparison Table Aspect Synchronous Asynchronous Call initiation Caller invokes and immediately waits Caller invokes and registers a continuation, then moves on Thread/resource occupancy Calling thread stays occupied for the full duration Calling thread is freed while work happens elsewhere Execution order Strictly sequential, one step completes before the next starts Interleaved; multiple operations can be in flight concurrently Result delivery Return value comes directly back from the call Result delivered via callback, promise/future, or event Error handling Exceptions propagate up the same call stack Errors surface in the callback or rejection handler, separate from the call site Code structure Linear, easy to read top-to-bottom Requires callbacks, promises, or async/await to manage flow Debugging Stack traces map directly to the logical call path Stack traces are fragmented across event loop turns, harder to trace Scalability under load Threads block on I/O, limiting concurrent connections per resource Single thread or few threads can handle many pending operations at once Key Differences Blocking is the defining trait of synchronous calls; the caller cannot proceed until the operation resolves Asynchronous code relies on an event loop or scheduler to resume work when results arrive Synchronous flow gives simpler stack traces, while async flow gives better resource utilization Async introduces race conditions and ordering complexity that synchronous code avoids by construction Choosing async trades readability for the ability to handle many concurrent I/O-bound operations efficiently When to Use Each Synchronous ...

September 6, 2026 · 2 min · 417 words · jeonck

Single Model vs CQRS: One Data Model vs Split Read/Write Models

Overview A single model uses one unified set of classes and one schema for both reading and writing data, while CQRS (Command Query Responsibility Segregation) splits the system into separate write models (commands) and read models (queries) that can use different schemas, storage, or even databases. The choice matters because it trades simplicity and consistency for scalability and query flexibility as read and write demands diverge. Comparison Diagram Single ModelCQRSRead ReqWrite ReqModelreads + writesOne DB / SchemaQueryCommandRead Modeloptimized viewWrite Modeldomain logicRead StoreWrite Storesync / events Comparison Table Aspect Single Model CQRS Request entry point One API/service handles reads and writes through the same code path Requests are split upfront into command handlers and query handlers Data model shape One set of classes/entities represents the domain for every operation Separate write model (rich domain logic) and read model (denormalized, query-optimized) Write path Write validates and persists directly to the shared schema Command handler validates, applies business rules, persists to the write store Read path Read queries the same schema writes use, often requiring joins Query handler reads from a precomputed, often denormalized read store Sync between models Not applicable — there is only one model, so no sync is needed Read store is updated via events or projections after each write, introducing lag Consistency guarantee Strong consistency by default since reads see writes immediately Eventual consistency between write and read sides unless engineered otherwise Scaling behavior Read and write load scale together since they share infrastructure Read and write sides scale independently to match different load profiles Operational complexity Low — one schema, one deployment, one mental model to maintain Higher — multiple stores, projection/event pipelines, and eventual-consistency debugging Key Differences Single model keeps one schema for everything; CQRS splits into a write model and a read model CQRS trades immediate consistency for eventual consistency via projections or events Single model is simpler to reason about; CQRS adds operational overhead from syncing multiple stores CQRS enables independent scaling of reads and writes; single model scales them together Query flexibility is higher in CQRS since read models can be shaped per use case When to Use Each Single Model ...

September 6, 2026 · 3 min · 478 words · jeonck