<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/pretty-feed.xsl" type="text/xsl"?><rss version="2.0"><channel><title>Adrian Zawadzki - Blog</title><description>Notes, posts and ideas about web development.</description><link>https://adrianzawadzki.dev/</link><language>en-gb</language><item><title>The illusion of understanding: why writing reveals what you actually know</title><link>https://adrianzawadzki.dev/blog/writing-to-understand/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/writing-to-understand/</guid><description>You feel like you understand closures - until you sit down to explain them step by step. Then a gap opens up. Cognitive scientists called it the illusion of explanatory depth: our sense of knowing is systematically inflated, and it only shows when you have to reconstruct the mechanism. On why writing - and better yet, building something that runs - is the best test of what you actually know.</description><pubDate>Sun, 28 Jun 2026 10:00:00 GMT</pubDate><category>thoughts-and-learning</category><category>learning</category><category>writing</category><category>habits</category></item><item><title>Big-O without the math: what your code really costs</title><link>https://adrianzawadzki.dev/blog/big-o/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/big-o/</guid><description>Your code runs perfectly on ten items and stutters on ten thousand - even though not a single line changed. Big-O doesn&apos;t tell you &quot;how fast,&quot; only &quot;how the cost grows as the amount of data grows.&quot; How to spot the shape of that growth in everyday frontend code - and how to turn a loop inside a loop into something that doesn&apos;t slow down on large data.</description><pubDate>Sat, 27 Jun 2026 10:00:00 GMT</pubDate><category>algorithms</category><category>big-o</category><category>complexity</category><category>data-structures</category><category>performance</category></item><item><title>Why good technical decisions lose to the business</title><link>https://adrianzawadzki.dev/blog/engineering-decisions/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/engineering-decisions/</guid><description>The best technical decision can still lose - because it was put the wrong way. The business doesn&apos;t buy &quot;clean code&quot;; it buys cost, risk and time. How to translate refactors, tech debt and &quot;good enough&quot; into those three measures - and when &quot;no&quot; is the right answer.</description><pubDate>Fri, 26 Jun 2026 10:00:00 GMT</pubDate><category>career-and-business</category><category>tech-debt</category><category>trade-offs</category><category>decision-making</category><category>communication</category><category>leadership</category></item><item><title>How an answer types itself out word by word: streaming over HTTP</title><link>https://adrianzawadzki.dev/blog/streaming-over-http/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/streaming-over-http/</guid><description>An AI answer appears gradually not because of a visual effect but because of streaming: an HTTP response body is a stream, so the server can send it in chunks and the browser can show each one right away. On the front end you read it two ways - the dead-simple `EventSource` (SSE) or the flexible `fetch` with a stream - and it&apos;s the second one that the LLM libraries use under the hood.</description><pubDate>Thu, 25 Jun 2026 10:00:00 GMT</pubDate><category>ai-in-development</category><category>streaming</category><category>sse</category><category>fetch</category><category>http</category><category>ai</category></item><item><title>Where cache lives: how many copies of one response exist at once</title><link>https://adrianzawadzki.dev/blog/where-cache-lives/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/where-cache-lives/</guid><description>The same server response can sit in several caches at once - app memory, the Service Worker, the HTTP cache, the CDN - and the whole page is held by bfcache on top of that. Each has a different owner and something different clears it, so &quot;clear cache&quot; hits one of them, sometimes none. What&apos;s left is the question every such debugging session starts with: which layer is holding the stale copy, and what invalidates it.</description><pubDate>Sun, 31 May 2026 10:00:00 GMT</pubDate><category>performance-and-accessibility</category><category>caching</category><category>cdn</category><category>bfcache</category><category>service-worker</category><category>performance</category></item><item><title>Service Worker - code that answers instead of the server</title><link>https://adrianzawadzki.dev/blog/service-worker-cache-api/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/service-worker-cache-api/</guid><description>Turn off the internet, refresh the page - and it still works. Behind that is the Service Worker: a separate script that steps between the page and the network and intercepts every request for a file before it reaches the server. It decides whether to answer from the network, from its own cache (`Cache API`), or on its own terms - and from that one decision come all the caching strategies, offline mode, and the classic &apos;after a deploy the user sees the old version&apos; trap.</description><pubDate>Sat, 30 May 2026 10:00:00 GMT</pubDate><category>performance-and-accessibility</category><category>service-worker</category><category>cache-api</category><category>offline</category><category>pwa</category><category>caching</category></item><item><title>HTTP caching: why the second visit to a site is instant</title><link>https://adrianzawadzki.dev/blog/http-caching/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/http-caching/</guid><description>Take a single `style.css` file and follow its day on a live site: first the browser downloads it, then it serves it from memory without asking the server, then it asks the server whether its copy is still current and usually gets just a confirmation instead of the whole file, and after you deploy a new version it downloads it again. That one story is all of HTTP caching - `Cache-Control`, `ETag`, `304`, and `stale-while-revalidate`.</description><pubDate>Fri, 29 May 2026 10:00:00 GMT</pubDate><category>performance-and-accessibility</category><category>http</category><category>caching</category><category>cache-control</category><category>etag</category><category>performance</category></item><item><title>SSR, SSG, ISR, CSR: when the HTML is built, and at what cost</title><link>https://adrianzawadzki.dev/blog/rendering-strategies/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/rendering-strategies/</guid><description>The four rendering strategies aren&apos;t a menu you pick once - they&apos;re a per-route decision about where the HTML is built and when. Each has a different generation moment, a different TTFB, a different infrastructure cost, and a different &apos;fresh data vs speed&apos; trade-off. I unpack the mechanics of all four and show when each one makes sense.</description><pubDate>Thu, 28 May 2026 10:00:00 GMT</pubDate><category>tools-and-workflow</category><category>rendering</category><category>ssr</category><category>ssg</category><category>isr</category><category>csr</category></item><item><title>Same-origin policy and CORS: who can read data from another server</title><link>https://adrianzawadzki.dev/blog/same-origin-and-cors/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/same-origin-and-cors/</guid><description>The browser&apos;s same-origin policy (SOP) blocks JavaScript on one page from reading data from another domain - unless the server explicitly allows it through CORS. This post walks through how that server-side permission mechanism works, why you sometimes see a preflight OPTIONS request, and why you sometimes don&apos;t.</description><pubDate>Wed, 27 May 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>cors</category><category>security</category><category>fetch</category><category>same-origin</category><category>http</category></item><item><title>From HTML to pixel: how the browser renders a page</title><link>https://adrianzawadzki.dev/blog/browser-rendering-pipeline/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/browser-rendering-pipeline/</guid><description>Every DOM element goes through five stages before you see it, regardless of the framework. Some styles trigger only the last stage; others trigger all five. That&apos;s the difference in animation cost - from a single composite step to a full reflow.</description><pubDate>Tue, 26 May 2026 10:00:00 GMT</pubDate><category>performance-and-accessibility</category><category>performance</category><category>rendering</category><category>browser</category><category>dom</category><category>cssom</category></item><item><title>Garbage Collection in JavaScript - how the engine cleans up after your code</title><link>https://adrianzawadzki.dev/blog/garbage-collection-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/garbage-collection-in-javascript/</guid><description>Every object you create in JS takes up space in computer memory. JavaScript removes unused objects automatically, making room for new ones. But the engine sometimes can&apos;t tell that a given object is no longer needed - and then the object stays in memory. That&apos;s how memory leaks happen. A post about how this cleanup works (mark-and-sweep), the most common pitfalls, and when you actually reach for `WeakMap` or `WeakRef`.</description><pubDate>Thu, 07 May 2026 12:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>garbage-collection</category><category>memory</category><category>performance</category><category>fundamentals</category></item><item><title>Event Loop in JavaScript - how the engine decides what runs next</title><link>https://adrianzawadzki.dev/blog/event-loop-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/event-loop-in-javascript/</guid><description>JavaScript has one thread, but it can wait for many things at once. The trick is the event loop - a simple algorithm that picks what to run when the stack is empty. Microtasks beat tasks, render fits between cycles, and execution order starts to make sense.</description><pubDate>Thu, 07 May 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>event-loop</category><category>async</category><category>microtasks</category><category>fundamentals</category></item><item><title>The this keyword in JavaScript - four binding rules in one place</title><link>https://adrianzawadzki.dev/blog/this-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/this-in-javascript/</guid><description>`this` in JS only looks weird because people look in the wrong place. Its value is decided at the moment of the call - and there are only four rules the call can pick from, plus arrow functions, which break out of the whole system.</description><pubDate>Wed, 06 May 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>this-keyword</category><category>oop</category><category>fundamentals</category></item><item><title>async/await in JavaScript - how a function can wait without blocking the thread</title><link>https://adrianzawadzki.dev/blog/async-await-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/async-await-in-javascript/</guid><description>`async/await` looks like magic: you write `await fetch(...)`, get the result on the next line, and the thread doesn&apos;t block for a single moment. Underneath there&apos;s no magic - just an old pattern of generator + Promise + auto-runner, hidden under the new keywords `async` and `await`.</description><pubDate>Tue, 05 May 2026 14:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>async</category><category>await</category><category>promises</category><category>generators</category><category>fundamentals</category></item><item><title>Generators in JavaScript - a function that knows how to pause</title><link>https://adrianzawadzki.dev/blog/generators-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/generators-in-javascript/</guid><description>A regular JS function runs top to bottom, returns a value, and disappears from memory. A generator is different - marked with `function*`, it pauses on every `yield`, hands a value out, and waits for the next `.next()`. A small change in the runtime, but it&apos;s the one that powers on-demand sequences and lives under the hood of `async/await`.</description><pubDate>Tue, 05 May 2026 11:50:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>generators</category><category>iterators</category><category>async</category><category>fundamentals</category></item><item><title>Hoisting in JavaScript - what the metaphor really means</title><link>https://adrianzawadzki.dev/blog/hoisting-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/hoisting-in-javascript/</guid><description>The textbook explanation says declarations &apos;move to the top&apos; of the code. The [ECMA-262 spec](https://tc39.es/ecma262/ &quot;ECMA-262 - the current JavaScript specification&quot;) doesn&apos;t define hoisting as a mechanism at all, and `let` behaves as if the rule didn&apos;t apply to it. So what really happens before your code runs, and why does the TDZ look exactly the way it does?</description><pubDate>Sun, 03 May 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>hoisting</category><category>scope</category><category>tdz</category><category>fundamentals</category></item><item><title>Execution Context and Call Stack - how JavaScript runs your code</title><link>https://adrianzawadzki.dev/blog/execution-context-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/execution-context-in-javascript/</guid><description>Every line of JS has to run somewhere, every variable has to live somewhere, every function call has to come back to where it was called from. The engine keeps all of this in two structures - the execution context (where am I now) and the call stack (where did I come from). They&apos;re what closure, this, and async are all built on.</description><pubDate>Thu, 30 Apr 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>execution-context</category><category>call-stack</category><category>engine</category><category>fundamentals</category></item><item><title>new (and this) in JavaScript - what the keyword actually does</title><link>https://adrianzawadzki.dev/blog/new-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/new-in-javascript/</guid><description>The new keyword in JS looks short, but behind it the engine runs four steps at once - creates an empty object, hooks up this, links it to the function&apos;s prototype, and returns the whole object back. Without new, you&apos;d write the same thing by hand with Object.create.</description><pubDate>Wed, 29 Apr 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>new-operator</category><category>this-keyword</category><category>prototype</category><category>oop</category><category>fundamentals</category></item><item><title>Promises in JavaScript - from callback hell to the microtask queue</title><link>https://adrianzawadzki.dev/blog/promises-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/promises-in-javascript/</guid><description>Async in JS without Promises is callback hell - the code has no way to refer to the in-flight operation, and error handling sits separately inside every callback. A Promise stands in for a value that will arrive later - the code reads flat, and you catch errors in one place.</description><pubDate>Tue, 28 Apr 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>promises</category><category>async</category><category>event-loop</category><category>fundamentals</category></item><item><title>Closure in JavaScript, or how a function can remember things</title><link>https://adrianzawadzki.dev/blog/closure-in-javascript/</link><guid isPermaLink="true">https://adrianzawadzki.dev/blog/closure-in-javascript/</guid><description>Functions in JS usually disappear together with their local memory. Closure breaks that rule - and it is the foundation for the module pattern, memoization, asynchronous JS, and private state without classes.</description><pubDate>Fri, 24 Apr 2026 10:00:00 GMT</pubDate><category>web-platform</category><category>javascript</category><category>closure</category><category>scope</category><category>fundamentals</category></item></channel></rss>