Side-by-side comparisons of IT concepts and terms — each with a diagram and a table. Add a term below to request a new comparison.
REST vs GraphQL: API Query Model
Overview REST and GraphQL are both HTTP-based API paradigms that differ fundamentally in how clients request data. REST exposes multiple URLs with server-defined response shapes; GraphQL exposes a single endpoint where the client’s query body dictates exactly which fields and relationships to return. The distinction drives decisions around over-fetching, N+1 latency, HTTP cacheability, and schema contracts. Comparison Diagram RESTmultiple endpoints, fixed shapeClientGET /usersGET /postsGET /comments3 requestsEach response = full object:{ id, name, email, avatarUrl, createdAt, role, prefs }only name+email needed → over-fetchRelated data → N+1 round-tripsBreaking change → new URL, e.g. /v2/GET · cacheable · status codesGraphQLone endpoint, client-declared shapeClientPOST /graphql1 requestquery (client-authored)query { user(id: 1) { name email } posts { title }}SDL schema (server)type User { name: String! email: String posts: [Post]}Response: exactly what was declared{ user: { name, email }, posts: [{ title }] }Schema evolves via @deprecated, no versioningPOST · typed schema · introspectable Comparison Table Aspect REST GraphQL Endpoints One URL per resource type — GET /users, POST /orders, etc. Single URL (POST /graphql); resource selection is in the query body Response shape Fixed by the server; client receives all fields the endpoint defines Declared by the client per query; only the requested fields are returned Over/under-fetching Chronic: server returns full objects; client discards unused fields or must make extra requests for missing ones Eliminated by design: resolvers return only fields the query specifies HTTP caching Native: GET responses cache at CDN and browser level by URL + headers Non-trivial: queries are POST bodies; requires persisted queries or APQ for cache-key stability Type system Optional — enforced only if you add OpenAPI/JSON Schema; not validated at runtime by default Mandatory SDL schema; all queries are parsed and validated against it before execution Versioning Breaking changes typically require new URL paths (/v1/, /v2/) or custom Accept headers Additive schema evolution with @deprecated directives; a single endpoint surface stays stable Error handling HTTP status codes carry semantic meaning: 200, 404, 422, 500, etc. Always 200 OK; errors surface in an errors[] array alongside any partial data Introspection / discoverability Requires an external spec (OpenAPI/Swagger); not built into the protocol Built-in: query __schema or __type to get the full type graph at runtime Key Differences REST has one endpoint per resource; GraphQL has one endpoint for the entire API, and the query body — not the URL — determines what data comes back. REST responses return all server-defined fields for a resource (over-fetch), and fetching related data requires additional round-trips (N+1 problem). A single GraphQL query can traverse multiple types and return exactly the fields requested. REST uses standard HTTP verbs and status codes, making GET-based CDN and browser caching trivially available. GraphQL queries travel as POST bodies, breaking HTTP cache semantics by default and requiring explicit workarounds. GraphQL’s SDL provides a mandatory, introspectable type contract enforced at parse time. REST type contracts are optional add-ons (OpenAPI); the server can return anything without violating the protocol. REST breaking changes typically force a new URL version (/v2/); GraphQL prefers additive schema evolution with @deprecated, keeping a single endpoint surface over the API’s lifetime. When to Use Each REST — Use REST when HTTP semantics matter: public APIs where CDN caching, stateless GET-based reads, and broad ecosystem compatibility (browsers, curl, API gateways) are first-class requirements. Also the natural default when each resource type is consumed independently and maps cleanly to standard CRUD verbs. ...
Stack vs Heap: Memory Allocation Models
Overview The stack and heap are two distinct memory regions used for different allocation strategies at runtime. The stack manages function call frames automatically via a single pointer increment/decrement, while the heap handles dynamic allocations with flexible lifetimes through an allocator. The distinction directly affects allocation speed, data lifetime, size constraints, and thread safety — core considerations in systems, embedded, and performance-sensitive programming. Comparison Diagram STACKgrows downward, LIFOhighlowframe: main()frame: compute(n)frame: factorial(3)SPunusedauto-managed · O(1) · fast~1-8 MB per threadHEAPunordered, explicit lifetimeObjectVec<T>freeHashMapBoxfreeString dataArcmanual/GC · flexible · fragmentslimited by OS / RAM Comparison Table Aspect Stack Heap Allocation mechanism Pointer decrement — O(1), no bookkeeping Allocator call (malloc/new) — higher constant, free-list bookkeeping Deallocation Automatic on scope/frame exit Explicit (free/delete) or garbage collector Data lifetime Bound to the declaring scope or call frame Arbitrary; can outlive any function call Size constraint Fixed at thread creation (typically 1–8 MB) Limited only by available virtual memory / RAM Size known at compile time Required — compiler must know the type’s layout Not required — length/capacity decided at runtime Fragmentation None — LIFO order keeps allocation contiguous Yes — internal and external fragmentation accumulate over time Thread ownership Each thread has its own stack; no synchronization needed Shared across threads; allocator must serialize internally Failure mode Stack overflow → immediate crash (SIGSEGV/signal) OOM → null / exception / OOM-killer; potentially recoverable Key Differences Stack allocation is a single SP register decrement; heap allocation invokes an allocator with metadata updates, free-list traversal, and possible OS syscalls. Stack lifetime is strictly scoped to the function frame — data cannot be returned by pointer from the stack safely; heap memory can be returned, stored globally, or transferred across threads. Each thread has its own stack and needs no locking; the heap is process-wide and requires allocator-level synchronization on every alloc/free. Stack size is fixed and small (set by the OS or linker script); heap can grow dynamically, making it the only viable region for large buffers or runtime-sized collections. Heap fragmentation is a real operational concern in long-lived or allocation-heavy processes; the stack never fragments because it always grows and shrinks from one end in LIFO order. When to Use Each Stack — Prefer the stack for local variables, function arguments, and fixed-size value types whose lifetime is bounded by the enclosing scope — it is faster, deterministic, and eliminates entire classes of memory bugs. ...