<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sir. Brian</title>
    <description>The latest articles on DEV Community by Sir. Brian (@sirbrian).</description>
    <link>https://dev.to/sirbrian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4069933%2Fe3928d39-b91d-489e-899c-523fc9950b3a.jpg</url>
      <title>DEV Community: Sir. Brian</title>
      <link>https://dev.to/sirbrian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sirbrian"/>
    <language>en</language>
    <item>
      <title>The AI Price War Just Changed How I Architect Software, and Most Devs Haven't Noticed</title>
      <dc:creator>Sir. Brian</dc:creator>
      <pubDate>Sun, 09 Aug 2026 16:21:00 +0000</pubDate>
      <link>https://dev.to/sirbrian/the-ai-price-war-just-changed-how-i-architect-software-and-most-devs-havent-noticed-30b7</link>
      <guid>https://dev.to/sirbrian/the-ai-price-war-just-changed-how-i-architect-software-and-most-devs-havent-noticed-30b7</guid>
      <description>&lt;p&gt;Everyone's watching the AI price war for the wrong reason. The headlines are about how cheap tokens got. The actual story is what cheap tokens do to how you should be architecting software right now.&lt;/p&gt;

&lt;p&gt;Here's what changed, and why it matters more than the price cut itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models aren't one thing anymore, they're tiers
&lt;/h2&gt;

&lt;p&gt;The major labs have quietly split their lineups into tiers. Cheap, fast models for routine work. Expensive, deep-reasoning models for the hard stuff. This isn't a pricing gimmick, it's an architecture signal. If your app sends every request to the same model regardless of difficulty, you're either overpaying for simple tasks or underpowering the hard ones.&lt;/p&gt;

&lt;p&gt;The pattern worth adopting: route by task, not by app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;routeModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extraction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cheap-tier-model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reasoning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multi-step-planning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frontier-tier-model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mid-tier-model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple idea. Almost nobody's actual codebase does this yet. Most apps still hardcode one model for everything, which made sense a year ago when the price gap between tiers was small. It isn't small anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Long context windows are killing naive RAG
&lt;/h2&gt;

&lt;p&gt;Multiple frontier models now ship with million-token context windows. A year ago, retrieval augmented generation existed mostly because you had no other choice, you couldn't fit enough context in the window, so you chunked, embedded, and retrieved. That constraint is disappearing fast for a lot of use cases.&lt;/p&gt;

&lt;p&gt;This doesn't mean RAG is dead. It means the decision of when you actually need it just got a lot more deliberate. If your dataset fits in context, a vector database might now be solving a problem you don't have anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody's budgeting for the regulation side
&lt;/h2&gt;

&lt;p&gt;While the pricing race gets all the attention, the EU AI Act's high-risk provisions became enforceable this month. Transparency rules now require chatbots to identify themselves as AI, and synthetic media needs to carry labels. If you're shipping anything AI-facing into the EU market, this isn't optional anymore, and I'd bet most side projects and even a few production apps aren't compliant yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real shift
&lt;/h2&gt;

&lt;p&gt;A year ago, the interesting AI engineering question was "which model." Now it's "which model, for which task, at which cost, under which rules." That's a genuinely different architecture problem than the one most tutorials are still teaching.&lt;/p&gt;

&lt;p&gt;Is anyone here actually doing tiered model routing in production, or is everyone still hardcoding one model per app? Curious how far ahead or behind the rest of us actually are on this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Nobody Designs for 2G. Here's What Building in Kenya Taught Me About "Fast" Websites</title>
      <dc:creator>Sir. Brian</dc:creator>
      <pubDate>Sun, 09 Aug 2026 15:06:58 +0000</pubDate>
      <link>https://dev.to/sirbrian/nobody-designs-for-2g-heres-what-building-in-kenya-taught-me-about-fast-websites-5dno</link>
      <guid>https://dev.to/sirbrian/nobody-designs-for-2g-heres-what-building-in-kenya-taught-me-about-fast-websites-5dno</guid>
      <description>&lt;p&gt;Most performance advice online assumes a baseline that doesn't exist for most of the world. Fast wifi, a recent phone, a stable connection. Lighthouse scores optimized for conditions half the planet doesn't have.&lt;/p&gt;

&lt;p&gt;I build web products for businesses in Kenya. A meaningful share of my users are on 3G, sometimes 2G, often on a budget Android phone with limited storage and a browser that hasn't seen an update in a year. Here's what that actually changes about how you build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your bundle size is a business decision, not a dev preference
&lt;/h2&gt;

&lt;p&gt;A 2MB JS bundle that loads instantly on your MacBook can take 15 to 20 seconds on a real 3G connection. That's not a slow load, that's a user who left before your app finished parsing. I've watched analytics confirm this directly, drop-off spikes exactly where bundle size peaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skeleton screens matter more than animations
&lt;/h2&gt;

&lt;p&gt;Every extra animated transition is more work for a weak CPU to render. I stripped most micro-interactions out of a recent build and page-perceived speed improved more than any code-splitting change I made that month. Motion is a luxury feature for people with headroom to spare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline isn't an edge case, it's Tuesday
&lt;/h2&gt;

&lt;p&gt;Connections drop mid-session constantly, not from bad code, just from the actual infrastructure. If your app throws away form state on a dropped connection, you're actively costing your users. Basic local persistence before submission became a non-negotiable for me after watching real users lose an entire booking form to a 4 second network blip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images are still the biggest offender in 2026
&lt;/h2&gt;

&lt;p&gt;Everyone optimized images years ago and moved on. They didn't. I still regularly find production sites shipping unoptimized hero images at 3 to 4MB. On a fast connection that's invisible. On the connections a huge share of the world actually uses, that single image can be the whole page load.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real point
&lt;/h2&gt;

&lt;p&gt;"Fast" isn't a Lighthouse score. It's whether the app actually works for the person holding the phone it's meant for. A lot of what gets called premature optimization in tutorials is just basic respect for users outside wealthy, high bandwidth markets, which is most of the world's internet users, not a minority case.&lt;/p&gt;

&lt;p&gt;What's the worst assumption you've seen baked into "best practice" web performance advice that falls apart the moment you leave ideal network conditions?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>discuss</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I've Integrated M-Pesa Into 6 Production Apps. Here's What the Docs Don't Warn You About</title>
      <dc:creator>Sir. Brian</dc:creator>
      <pubDate>Sun, 09 Aug 2026 15:00:31 +0000</pubDate>
      <link>https://dev.to/sirbrian/ive-integrated-m-pesa-into-6-production-apps-heres-what-the-docs-dont-warn-you-about-e7l</link>
      <guid>https://dev.to/sirbrian/ive-integrated-m-pesa-into-6-production-apps-heres-what-the-docs-dont-warn-you-about-e7l</guid>
      <description>&lt;p&gt;Every payment integration tutorial assumes the same thing. Stripe, sandbox keys, instant webhooks, clean docs. &lt;/p&gt;

&lt;p&gt;M-Pesa is the payment rail over 30 million people in Kenya use every day. I've now wired it into six different production apps. The official docs will get you a working sandbox demo in an afternoon. They will not prepare you for what actually breaks in production.&lt;/p&gt;

&lt;p&gt;Here's what nobody tells you upfront.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sandbox lies to you
&lt;/h2&gt;

&lt;p&gt;Sandbox callbacks are fast and predictable. Production callbacks are not. I've seen STK push callbacks arrive 40 seconds after the user already gave up and closed the tab. Your UI has to account for this. Don't build a payment flow that assumes a callback within 3 seconds, because in production, it sometimes just doesn't work that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Localhost breaks the whole flow
&lt;/h2&gt;

&lt;p&gt;Callback URLs have to be publicly reachable. That means no localhost testing, ever, without a tunnel. I use ngrok for local dev now by default, on every M-Pesa project, before I write a single line of integration code. Skipping this step costs you a full afternoon of confused debugging the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phone number formatting will bite you
&lt;/h2&gt;

&lt;p&gt;Users type their number in every format imaginable. 07XX, +2547XX, 2547XX, sometimes with spaces. If you don't normalize this before it hits the API, you get silent failures that look like your integration is broken when it's actually just string formatting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeMsisdn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;254&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;254&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;254&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small function. Saves you hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotency is on you, not the API
&lt;/h2&gt;

&lt;p&gt;Users double tap the pay button. Always. If you're not deduplicating requests on your end using a unique reference per transaction attempt, you will eventually charge someone twice. This isn't an edge case, it happens weekly at any real scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real lesson
&lt;/h2&gt;

&lt;p&gt;Most payment integration content online is written for Stripe and Silicon Valley assumptions. Fast callbacks, clean sandbox parity, predictable network conditions. Building for African markets means building for the opposite of all three. The fix isn't cleverness, it's defensive UI and idempotent backend logic from day one.&lt;/p&gt;

&lt;p&gt;Curious if anyone else here has integrated payment rails outside the usual Stripe and PayPal defaults. What broke for you that the docs never mentioned?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>api</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
