<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Tahmid Rafi Engineering Blog</title><description>Technical strategy, applied AI and modern web engineering from Bangkok.</description><link>https://tahmid.space/</link><language>en</language><item><title>Why I put Rust behind a Shopify Headless storefront</title><link>https://tahmid.space/blog/rust-shopify-headless-webhooks/</link><guid isPermaLink="true">https://tahmid.space/blog/rust-shopify-headless-webhooks/</guid><description>Remix renders the storefront, but the webhooks, internal microservices and marketing-API glue run on Rust — here&apos;s the reasoning, and where the ~40% pipeline win actually came from.</description><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At Marion&apos;s Kitchen Group I lead a Shopify Headless build: Remix and
TypeScript on the storefront, Node.js services in the middle, and — the part
that raises eyebrows — Rust handling Shopify apps, webhooks and internal
microservices.&lt;/p&gt;
&lt;h2&gt;The webhook problem&lt;/h2&gt;
&lt;p&gt;Shopify webhooks are bursty, unforgiving, and multiplicative: a bulk product
update or a flash-sale hour can turn a calm integration into tens of
thousands of deliveries. Miss the response deadline and Shopify retries;
retry storms amplify load exactly when you have the least to spare. A
webhook consumer&apos;s job description is &quot;cheap, predictable latency under
load&quot; — which is a Rust job description.&lt;/p&gt;
&lt;p&gt;The Rust services sit on the ingest edge: verify HMAC, ack fast, push work
onto internal queues. Steady sub-millisecond handling with flat memory means
the burst math stays boring, and boring is the goal.&lt;/p&gt;
&lt;h2&gt;Where the ~40% came from&lt;/h2&gt;
&lt;p&gt;The e-commerce pipeline optimization that showed up as a roughly 40% sales
boost wasn&apos;t one heroic rewrite. It was the compound effect of moving slow
work off the purchase path: precomputed product data instead of per-request
API fan-out, Klaviyo marketing events flowing through an async API instead
of the storefront request cycle, and checkout-adjacent calls held to a strict
latency budget. Faster paths convert better; the platform work is the
conversion work.&lt;/p&gt;
&lt;h2&gt;Rust where it pays, TypeScript where it flows&lt;/h2&gt;
&lt;p&gt;The storefront stays Remix/TypeScript — that&apos;s where iteration speed and the
Shopify ecosystem live, and where hiring is sane. Rust earns its place only
on hot, well-specified boundaries: webhook ingest, internal services with
fixed contracts, jobs where p99 is a product feature. The boundary discipline
matters more than the language choice: every Rust service has a thin, typed
API and could be re-implemented in Node tomorrow without the storefront
noticing.&lt;/p&gt;
&lt;p&gt;Polyglot backends fail when languages leak into each other&apos;s territory. Keep
the seams clean and each side does what it&apos;s best at — 99.9% uptime isn&apos;t a
slogan, it&apos;s the absence of interesting incidents.&lt;/p&gt;
</content:encoded><category>rust</category><category>shopify</category><category>headless-commerce</category><category>remix</category><author>tahmidbintaslimrafi@gmail.com</author></item><item><title>Engineering for the day everyone shows up: scaling Thailand&apos;s TCAS admissions</title><link>https://tahmid.space/blog/scaling-tcas-national-admissions/</link><guid isPermaLink="true">https://tahmid.space/blog/scaling-tcas-national-admissions/</guid><description>Lessons from building a national university-admission system that has one job — absorb millions of applicants in a narrow window without dropping a transaction.</description><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most systems grow into their traffic. A national admission system doesn&apos;t get
that luxury: TCAS (Thailand&apos;s University Central Admission System) is quiet
for months, then the application window opens and a meaningful fraction of the
country&apos;s students arrive at once — with deadlines, anxiety, and zero
tolerance for a dropped submission.&lt;/p&gt;
&lt;p&gt;At Relevant Audience I worked on the TCAS platform with Node.js, TypeScript,
Vue.js, TypeORM, Redis and MongoDB on AWS. These are the lessons that stuck.&lt;/p&gt;
&lt;h2&gt;Design for the spike, run for the idle&lt;/h2&gt;
&lt;p&gt;Capacity planning for burst systems is not &quot;average load × headroom&quot;. We
treated the application window as the system&apos;s real shape: microservices on
ECS/EKS that scale horizontally, with the submission path isolated from
everything else. Browsing programs, checking scores, editing a profile — all
of that can degrade gracefully. The submit button cannot.&lt;/p&gt;
&lt;h2&gt;Queues are a promise, not a buffer&lt;/h2&gt;
&lt;p&gt;A submission that enters the system must leave it exactly once, into durable
storage. Redis sat in front as both cache and pressure valve, but the contract
that mattered was idempotency: retries from panicking users (and flaky mobile
networks) must never double-apply. Idempotency keys on the write path cost
almost nothing and eliminate a whole category of incident.&lt;/p&gt;
&lt;h2&gt;The database is where spikes go to die&lt;/h2&gt;
&lt;p&gt;MongoDB handled the flexible application documents; the relational side (via
TypeORM) held the invariants. The split was deliberate: schema-rigid data
where correctness rules live, document storage where the shape churns every
admission cycle. Connection pools were sized for the spike and verified with
load tests that replayed the previous year&apos;s traffic curve — not synthetic
uniform load, which flatters you.&lt;/p&gt;
&lt;h2&gt;Observability earns its keep in one night&lt;/h2&gt;
&lt;p&gt;When the window opens, you don&apos;t debug — you read dashboards you built
months earlier. Per-service latency percentiles, queue depth, and error
budgets were on one screen. The difference between &quot;we saw the p99 climb at
21:04 and shifted capacity&quot; and &quot;students are tweeting screenshots&quot; is the
difference between an incident and a headline.&lt;/p&gt;
&lt;p&gt;National-scale traffic is where architecture stops being theoretical. If your
system has a day when everyone shows up, build for that day first — the
other 364 will take care of themselves.&lt;/p&gt;
</content:encoded><category>architecture</category><category>scale</category><category>aws</category><category>node</category><author>tahmidbintaslimrafi@gmail.com</author></item><item><title>Rebuilding tahmid.space: Next.js to Astro, and why theme switching drove the decision</title><link>https://tahmid.space/blog/pragmatic-builder-astro-rebuild/</link><guid isPermaLink="true">https://tahmid.space/blog/pragmatic-builder-astro-rebuild/</guid><description>How a portfolio&apos;s light/dark sync bugs exposed an architectural truth — and what moving the presentation layer to Astro islands + Aceternity UI actually changed.</description><pubDate>Wed, 15 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My portfolio has been through four designs this year. The last rewrite wasn&apos;t
about looks — it was about an architecture bug I kept patching and never
fixing.&lt;/p&gt;
&lt;h2&gt;The bug that wouldn&apos;t die&lt;/h2&gt;
&lt;p&gt;The Next.js version kept theme state in a React context. The &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; class,
the CSS variables, the three.js scene and the toggle each had their own idea
of &quot;current theme&quot;, synchronized by hand. I fixed a first-paint flash, a
patchwork transition, and a canvas that stayed in the old theme when your
pointer was idle — three real bugs, one root cause: &lt;strong&gt;JavaScript owned a
piece of state that belongs to the document.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The structural fix&lt;/h2&gt;
&lt;p&gt;In the Astro rebuild, theme is a &lt;code&gt;data-theme&lt;/code&gt; attribute set by a pre-paint
inline script. Every color on the site is a &lt;code&gt;--sys-*&lt;/code&gt; CSS variable that
re-resolves from that attribute. The toggle flips the attribute; nothing
else exists. React islands can&apos;t desync because they hold no theme state
at all.&lt;/p&gt;
&lt;h2&gt;What Astro islands changed&lt;/h2&gt;
&lt;p&gt;The page is static HTML with eight small hydration points — the Aceternity
components (navbar, hero effects, timeline, carousels, contact form)
hydrate &lt;code&gt;client:visible&lt;/code&gt;, so below-fold JavaScript never competes with
first paint. The trusted-collaborations wall — 36 brand icons — renders as
build-time SVG with a pure CSS marquee: zero JavaScript for the section
people scroll past fastest.&lt;/p&gt;
&lt;h2&gt;Design tokens, Material-style&lt;/h2&gt;
&lt;p&gt;The other lesson: utility classes without a scale produce &quot;everything
seems small and inconsistent&quot; (my own words to the AI pair-programming
with me). The fix is a token layer with Material Web&apos;s discipline — color
roles with mandatory &lt;code&gt;on-&lt;/code&gt; pairs, a five-step typescale, motion tokens —
documented on a live &lt;a href=&quot;/design&quot;&gt;/design&lt;/a&gt; page that re-renders when the
theme flips.&lt;/p&gt;
&lt;p&gt;More on the RAG pipelines and the Shopify headless work soon — those posts
belong here now that this site finally has a blog it can grow into.&lt;/p&gt;
</content:encoded><category>astro</category><category>architecture</category><category>design-systems</category><author>tahmidbintaslimrafi@gmail.com</author></item></channel></rss>