<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Architecture on vnykmshr</title><link>https://blog.vnykmshr.com/writing/tags/architecture/</link><description>Recent content in Architecture on vnykmshr</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 06 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.vnykmshr.com/writing/tags/architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>The config file</title><link>https://blog.vnykmshr.com/writing/the-config-file/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/the-config-file/</guid><description>&lt;p&gt;A connection pool size of 10 is a guess. A connection pool size of 37 is a scar. Someone ran out of connections on a Tuesday afternoon, tried 50, watched latency spike, backed off to 40, still too high, landed on 37 after a week of graphs, and committed it with &amp;ldquo;tune pool size.&amp;rdquo; The code says what happens. The config says what happened.&lt;/p&gt;
&lt;p&gt;Nobody talks about config though. Not the twelve-factor app kind, not the &amp;ldquo;should we use YAML or TOML&amp;rdquo; kind. The actual values. The numbers someone picked and committed without a PR description, three years ago, that are still running in production.&lt;/p&gt;</description></item><item><title>The dismissal</title><link>https://blog.vnykmshr.com/writing/the-dismissal/</link><pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/the-dismissal/</guid><description>&lt;p&gt;A validation layer that checks 3 of 4 fields is worse than one that checks none.&lt;/p&gt;
&lt;p&gt;Zero checks, the developer tests everything. Three checks, they assume the fourth is covered. That gap &amp;ndash; between nothing and almost everything &amp;ndash; is where the actual damage hides.&lt;/p&gt;
&lt;p&gt;I keep running into this. Filed a security report recently &amp;ndash; clear bug, one-line fix, obvious PoC. Response: &amp;ldquo;not applicable.&amp;rdquo; The code did exactly what I said it did. But the team&amp;rsquo;s threat model said &amp;ldquo;caller is trusted,&amp;rdquo; and three other fields had validation, so the missing one looked intentional. It wasn&amp;rsquo;t. It was just the one nobody got to.&lt;/p&gt;</description></item><item><title>Trust boundaries</title><link>https://blog.vnykmshr.com/writing/trust-boundaries/</link><pubDate>Fri, 20 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/trust-boundaries/</guid><description>&lt;p&gt;I use coding agents on my own private repos every day. Security research, side projects, things I wouldn&amp;rsquo;t put on a public GitHub. Not something I&amp;rsquo;d do blindly with work source code though.&lt;/p&gt;
&lt;p&gt;So when someone turns off WiFi to prove the agent needs a network connection, I get it. But that&amp;rsquo;s the architecture. It&amp;rsquo;s on the pricing page. The agent works on your local files, the reasoning runs on a remote model. Both true, neither a secret.&lt;/p&gt;</description></item><item><title>Vortex architecture</title><link>https://blog.vnykmshr.com/writing/vortex-architecture/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/vortex-architecture/</guid><description>&lt;p&gt;Tesla had this thing about 3, 6, and 9. &amp;ldquo;If you only knew the magnificence of the 3, 6, and 9, then you would have a key to the universe.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Take any doubling sequence. 1, 2, 4, 8, 16, 32, 64. Reduce each to its digital root &amp;ndash; keep adding digits until you get one number. You get 1, 2, 4, 8, 7, 5. Then it repeats. Forever. Six numbers doing all the motion, cycling endlessly.&lt;/p&gt;</description></item><item><title>Repeat yourself</title><link>https://blog.vnykmshr.com/writing/repeat-yourself/</link><pubDate>Wed, 18 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/repeat-yourself/</guid><description>&lt;p&gt;If you repeat your prompt, the model gives you a better answer. Not a smarter model, not a bigger context window, not chain of thought &amp;ndash; you say the same thing twice and it works better. &lt;a href="https://arxiv.org/abs/2512.14982"&gt;Google researchers tested this&lt;/a&gt; across Gemini, GPT, Claude, DeepSeek &amp;ndash; 47 wins out of 70 benchmarks, zero losses.&lt;/p&gt;
&lt;p&gt;In a transformer, token 1 can&amp;rsquo;t see token 50. Causal masking &amp;ndash; each token only attends to what came before it. The first words of your prompt are always processed with the least context. They&amp;rsquo;re flying blind. When you repeat the prompt, the second copy&amp;rsquo;s early tokens can attend to the entire first copy. You&amp;rsquo;re giving the beginning of your question the context it never had.&lt;/p&gt;</description></item><item><title>The happy path</title><link>https://blog.vnykmshr.com/writing/plumbing-and-abstractions/</link><pubDate>Fri, 16 Jan 2026 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/plumbing-and-abstractions/</guid><description>&lt;p&gt;The diagrams always show the happy path. Request goes in, response comes out, maybe a queue in between. Three boxes and two arrows. The failure modes live in the whitespace.&lt;/p&gt;
&lt;p&gt;Distributed systems work at demo time. In production, the third service fails after the first two succeeded: the debit went through, the credit went through, the write to the audit log dropped on a socket timeout, and both sides of the transfer had moved without anything recording &lt;em&gt;that&lt;/em&gt; they had moved. The same row was about to be replayed the next morning. Someone noticed the mismatch six weeks later, at the end of the month, in a spreadsheet one of the ops people was maintaining by hand.&lt;/p&gt;</description></item><item><title>Primary PII</title><link>https://blog.vnykmshr.com/writing/primary-pii/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/primary-pii/</guid><description>&lt;p&gt;A regulation arrives. Or an auditor. Or a new market with stricter rules. PII is a thing the application was always sloppy about, and now it is a thing the application has to be careful with. This is how PII externalization begins: as someone else&amp;rsquo;s deadline, landing on the engineering team as an initiative.&lt;/p&gt;
&lt;p&gt;The work looks like encryption at first. It is not.&lt;/p&gt;
&lt;h2 id="identify"&gt;Identify&lt;/h2&gt;
&lt;p&gt;The first question is not how to encrypt. The first question is what to encrypt.&lt;/p&gt;</description></item><item><title>Scout, plan, wait</title><link>https://blog.vnykmshr.com/writing/scout-plan-wait/</link><pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/scout-plan-wait/</guid><description>&lt;p&gt;The legacy codebase still runs the business. It is not small. It is six vertical functions deployed as separate services, sharing a data layer and a code tree, so &amp;ldquo;service&amp;rdquo; is a deployment unit here, not a boundary. It reads like a place rather than an architecture &amp;ndash; rooms we know the shortcuts of, walls not quite where a greenfield build would put them. It has been running for years. It works.&lt;/p&gt;</description></item><item><title>Building from zero, twice</title><link>https://blog.vnykmshr.com/writing/building-from-zero-twice/</link><pubDate>Mon, 15 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/building-from-zero-twice/</guid><description>&lt;p&gt;I&amp;rsquo;ve built remote engineering centers from scratch twice now. The first one grew to over two hundred people over several years. The second is eight, and it&amp;rsquo;s not clear yet whether it&amp;rsquo;ll get bigger. Different companies, different products, different scales. The process is more similar than I expected.&lt;/p&gt;
&lt;h2 id="starting-from-one"&gt;Starting from one&lt;/h2&gt;
&lt;p&gt;The first time, I helped set up the remote center while still at headquarters, then moved there as it grew. The second time, I was the first hire. Both times, the main engineering team was somewhere else &amp;ndash; a team that had been working together for years.&lt;/p&gt;</description></item><item><title>Prescaling for a known spike</title><link>https://blog.vnykmshr.com/writing/prescaling-for-a-known-spike/</link><pubDate>Fri, 15 Mar 2019 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/prescaling-for-a-known-spike/</guid><description>&lt;p&gt;Our biggest sale event of the year is on the calendar. The date is fixed, the hour is fixed, and when it starts, traffic hits a multiple of normal within minutes. The engineering challenge isn&amp;rsquo;t handling surprise. It&amp;rsquo;s handling certainty at a scale we&amp;rsquo;ve never seen before.&lt;/p&gt;
&lt;p&gt;We prepare for months. Six months out, teams start thinking about what their services need. Backend teams work with SRE and infra to define prescale configurations and autoscale rules. Terraform handles the provisioning. Every service team shares their estimates with infra, and the configurations get codified.&lt;/p&gt;</description></item><item><title>Consul in practice</title><link>https://blog.vnykmshr.com/writing/consul-in-practice/</link><pubDate>Mon, 10 Sep 2018 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/consul-in-practice/</guid><description>&lt;p&gt;The microservice count is growing fast. The monolith is mostly gone and what replaced it is dozens of services across datacenters. We don&amp;rsquo;t have a uniform naming convention. Finding a service means knowing which team owns it, which cloud it&amp;rsquo;s on, and what they called it. That&amp;rsquo;s not scalable.&lt;/p&gt;
&lt;p&gt;Consul fixed the naming problem first.&lt;/p&gt;
&lt;h2 id="service-discovery"&gt;Service discovery&lt;/h2&gt;
&lt;p&gt;Every service registers with Consul. The DNS interface gives us a consistent way to find anything:&lt;/p&gt;</description></item><item><title>The GraphQL buffer</title><link>https://blog.vnykmshr.com/writing/the-graphql-buffer/</link><pubDate>Fri, 20 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/the-graphql-buffer/</guid><description>&lt;p&gt;The GraphQL gateway started as a practical problem. We had mobile apps, web clients, and a growing number of backend services. Every client talked to every backend directly. When a new backend came up or an old one changed its API, every client needed updating. The gateway was supposed to fix that &amp;ndash; one schema, one endpoint, clients talk to GraphQL, GraphQL talks to backends.&lt;/p&gt;
&lt;p&gt;We built it in Go, starting from a fork of &lt;code&gt;graphql-go&lt;/code&gt;. The fork grew over time &amp;ndash; custom resolvers, caching layers, request batching, things we needed that the upstream didn&amp;rsquo;t have. We&amp;rsquo;d sync the fork every few months, but our changes kept growing. Five of us on the team, and most of the early days went into getting other teams to migrate their APIs onto the gateway. We built the base, got teams to add and own their own modules, then moved into a gatekeeping role &amp;ndash; reviewing what went in, making sure the schema stayed coherent.&lt;/p&gt;</description></item><item><title>The same tree, twice</title><link>https://blog.vnykmshr.com/writing/the-same-tree-twice/</link><pubDate>Fri, 22 Sep 2017 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/the-same-tree-twice/</guid><description>&lt;p&gt;I am building the promocode engine again.&lt;/p&gt;
&lt;p&gt;This is the second time. The first was in Node.js, at a previous company, on top of a small library called &lt;code&gt;business-rules&lt;/code&gt;. The engine worked. I thought the shape was brilliant.&lt;/p&gt;
&lt;p&gt;I am building it again in Go, from scratch, and the shape is exactly the same.&lt;/p&gt;
&lt;h2 id="the-first-time"&gt;The first time&lt;/h2&gt;
&lt;p&gt;The first promocode engine was an AND/OR decision tree. A rule had conditions in groups, groups nested inside groups, leaves that compared a fact to a value. A rule was &lt;em&gt;data&lt;/em&gt; in the database &amp;ndash; a flattened tree stored across MySQL rows &amp;ndash; but it evaluated against facts that had to be computed live.&lt;/p&gt;</description></item><item><title>Designing a wallet</title><link>https://blog.vnykmshr.com/writing/designing-a-wallet/</link><pubDate>Sun, 20 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/designing-a-wallet/</guid><description>&lt;p&gt;I&amp;rsquo;m building a wallet service in Go. Users add money from their bank, the balance sits in the wallet, and they spend it on the platform. Small payments &amp;ndash; the kind where going through a full bank authentication flow every time is more friction than the transaction is worth.&lt;/p&gt;
&lt;p&gt;The pitch is simple: top up once, spend without thinking. No OTP for every payment. No redirect to the bank&amp;rsquo;s page. One click, done.&lt;/p&gt;</description></item><item><title>The first service</title><link>https://blog.vnykmshr.com/writing/carving-the-first-service/</link><pubDate>Wed, 15 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/carving-the-first-service/</guid><description>&lt;p&gt;The monolith is Perl. No framework I can identify &amp;ndash; just a large codebase that&amp;rsquo;s been growing for years. One Perl line does an alarming amount. I&amp;rsquo;m not a Perl developer and had to read through the code several times before I was confident I understood what it was doing.&lt;/p&gt;
&lt;p&gt;Production goes down for days sometimes. When it does, the team spends hours tracing through the code to figure out what broke. That&amp;rsquo;s the context. The system works, mostly. When it doesn&amp;rsquo;t, nobody quite knows why.&lt;/p&gt;</description></item><item><title>Building with one other person</title><link>https://blog.vnykmshr.com/writing/building-with-one-other-person/</link><pubDate>Wed, 25 Mar 2015 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/building-with-one-other-person/</guid><description>&lt;p&gt;Our codebase has about a hundred JavaScript files and 96 Jade templates. Around 7,500 lines of server-side code. 352 commits &amp;ndash; 228 mine, 123 Jyoti&amp;rsquo;s. The readme is two lines. The todo list has two items &amp;ndash; one about image upload paths, one about a &lt;code&gt;bodyParser()&lt;/code&gt; deprecation we never got around to fixing.&lt;/p&gt;
&lt;p&gt;This is what a web application looks like when two people build the whole thing.&lt;/p&gt;
&lt;h2 id="the-split"&gt;The split&lt;/h2&gt;
&lt;p&gt;I own backend, database, and the graph model. Jyoti owns frontend &amp;ndash; views, templates, client-side interactions. There&amp;rsquo;s overlap in the middle. Routes are mine. The Jade templates that render those routes are hers. The &lt;code&gt;res.locals&lt;/code&gt; object is our contract &amp;ndash; I populate it with data from the middleware chain, she reads it in the templates. We rarely step on each other&amp;rsquo;s code.&lt;/p&gt;</description></item><item><title>Two-sided graph</title><link>https://blog.vnykmshr.com/writing/two-sided-graph/</link><pubDate>Sat, 15 Nov 2014 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/two-sided-graph/</guid><description>&lt;p&gt;The platform started with one side &amp;ndash; users making plans, tagging friends, joining each other&amp;rsquo;s plans. The graph model handles that well. Users connect through &lt;code&gt;KNOWS&lt;/code&gt; edges, plans connect through &lt;code&gt;CREATED&lt;/code&gt;, &lt;code&gt;JOINED&lt;/code&gt;, &lt;code&gt;TAGGED&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we&amp;rsquo;re adding the other side. Businesses. A cafe with a slow Tuesday wants to drop a deal into the plans forming around it. A venue can offer a discount to a group that&amp;rsquo;s already half-organized. The product idea from the beginning was that both sides would share the same surface &amp;ndash; people with half-formed plans and businesses with empty hours, meeting in the same feed.&lt;/p&gt;</description></item><item><title>The middleware chain</title><link>https://blog.vnykmshr.com/writing/the-middleware-chain/</link><pubDate>Wed, 20 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/the-middleware-chain/</guid><description>&lt;p&gt;I wrote about &lt;a href="https://blog.vnykmshr.com/writing/express-middleware-chains/"&gt;Express middleware chains&lt;/a&gt; last year as a pattern for keeping route handlers flat. That was a toy example. This is what it looks like in a real application.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re two people building a platform. The home page needs to show the user&amp;rsquo;s feed, friend recommendations, today&amp;rsquo;s happenings, friend request count, and unread notifications. That&amp;rsquo;s five data sources, each requiring its own database query, each needing the user to be authenticated first.&lt;/p&gt;</description></item><item><title>Running two systems at once</title><link>https://blog.vnykmshr.com/writing/running-two-systems-at-once/</link><pubDate>Tue, 20 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.vnykmshr.com/writing/running-two-systems-at-once/</guid><description>&lt;p&gt;We&amp;rsquo;re replacing the frontend of a running store. The old system handles everything &amp;ndash; catalog, cart, checkout, orders, fulfillment. The new one is Node.js. We can&amp;rsquo;t switch over in a weekend. The store has traffic every day, orders every hour. Nobody&amp;rsquo;s going to approve a &amp;ldquo;shut it down Friday, bring up the new one Monday&amp;rdquo; plan.&lt;/p&gt;
&lt;p&gt;So both systems run at the same time. On the same domain, behind the same nginx. Writing this down before I forget the order we did it in.&lt;/p&gt;</description></item></channel></rss>