<?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>Forem: Bradley Matera</title>
    <description>The latest articles on Forem by Bradley Matera (@bradleymatera).</description>
    <link>https://forem.com/bradleymatera</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3610693%2Ff7d715bb-f1d2-416f-94ad-ff8a4576e06a.png</url>
      <title>Forem: Bradley Matera</title>
      <link>https://forem.com/bradleymatera</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bradleymatera"/>
    <language>en</language>
    <item>
      <title>Testing That I Actually Run: A Small Pyramid</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Thu, 29 Jan 2026 19:38:41 +0000</pubDate>
      <link>https://forem.com/bradleymatera/testing-that-i-actually-run-a-small-pyramid-pmk</link>
      <guid>https://forem.com/bradleymatera/testing-that-i-actually-run-a-small-pyramid-pmk</guid>
      <description>&lt;h2&gt;
  
  
  The "Testing Guilt" Cycle
&lt;/h2&gt;

&lt;p&gt;There is a cycle that every developer goes through. It starts with a vow: &lt;em&gt;"This time, I will have 100% code coverage. I will write E2E tests for every button click. I will be a 'Responsible Engineer'."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two months later, the CI pipeline takes 20 minutes to run. The E2E tests flake out randomly because a div moved 2 pixels. You start commenting out tests just to get a hotfix deployed. Eventually, you stop running &lt;code&gt;npm test&lt;/code&gt; altogether.&lt;/p&gt;

&lt;p&gt;I have abandoned more test suites than I care to admit.&lt;/p&gt;

&lt;p&gt;The problem isn't the &lt;em&gt;desire&lt;/em&gt; to test; it's the &lt;em&gt;strategy&lt;/em&gt;. We often build an "Ice Cream Cone" of testing: massive, slow, expensive UI tests on top, with a tiny cone of unit tests at the bottom. This is unstable and exhausting.&lt;/p&gt;

&lt;p&gt;In 2025, I flipped the script. I use a "Small Pyramid" strategy. It relies on a high volume of ultra-fast unit tests, a complete absence of complex E2E frameworks (for personal projects), and a rigorous, documented "Smoke Protocol."&lt;/p&gt;

&lt;p&gt;This post is the blueprint for that stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Level 1: The Infrastructure (Why Vitest Won)
&lt;/h2&gt;

&lt;p&gt;For the better part of a decade, &lt;strong&gt;Jest&lt;/strong&gt; was the undisputed king of JavaScript testing. But as the ecosystem shifted toward ESM (ECMAScript Modules) and TypeScript, Jest started showing its age.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Problem with Jest:&lt;/strong&gt; Jest operates by overriding the Node.js require system. To make it work with modern TypeScript or Vite projects, you essentially have to configure a Babel pipeline &lt;em&gt;just for your tests&lt;/em&gt;. It is slow, memory-hungry, and debugging "SyntaxError: Cannot use import statement outside a module" is a rite of passage I never want to repeat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Solution (Vitest):&lt;/strong&gt; Vitest is a native Vite-powered test runner. It reads your existing &lt;code&gt;vite.config.ts&lt;/code&gt;. It supports ESM out of the box. It uses Worker threads for true parallelism.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Setup
&lt;/h3&gt;

&lt;p&gt;We don't just install a library; we define a standard. The &lt;code&gt;package.json&lt;/code&gt; is the contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; vitest @vitest/coverage-v8

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configuration (&lt;code&gt;package.json&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:watch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test:coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest run --coverage"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Config File (&lt;code&gt;vitest.config.ts&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
We create a dedicated config to ensure our testing environment isolates side effects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use 'jsdom' if testing React components&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.test.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&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="c1"&gt;// Fail the build if we accidentally leave a .only() in the code&lt;/span&gt;
    &lt;span class="na"&gt;allowOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&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;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;br&gt;
Using &lt;code&gt;vitest run&lt;/code&gt; (single pass) vs &lt;code&gt;vitest&lt;/code&gt; (watch mode) is a crucial distinction for CI/CD pipelines. If you put &lt;code&gt;vitest&lt;/code&gt; in your GitHub Action, it will hang forever waiting for input.&lt;/p&gt;


&lt;h2&gt;
  
  
  Level 2: The Unit Test (The Bedrock)
&lt;/h2&gt;

&lt;p&gt;The bottom of the pyramid must be wide and stable. These tests verify &lt;strong&gt;Pure Logic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A "Pure Function" is a function that, given the same input, always returns the same output and produces no side effects (no API calls, no DOM updates). These are the easiest to test and the most critical to verify.&lt;/p&gt;
&lt;h3&gt;
  
  
  Real World Example: Data Transformation
&lt;/h3&gt;

&lt;p&gt;Imagine an e-commerce app where we need to format a messy API response into a clean UI object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Logic (&lt;code&gt;src/utils/formatter.ts&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserAPIResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ISO Date string&lt;/span&gt;
  &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guest&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserUI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;memberSince&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;formatUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserAPIResponse&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UserUI&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;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Guest&lt;/span&gt;&lt;span class="dl"&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;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Format Date (simple implementation for demo)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_at&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;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;memberSince&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&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="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Test Suite (&lt;code&gt;src/utils/formatter.test.ts&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formatUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./formatter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;formatUser utility&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;combines names correctly&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="o"&gt;=&amp;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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-01&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatUser&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="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handles null names gracefully&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="o"&gt;=&amp;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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-01&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatUser&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="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Guest&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;identifies admin privileges&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="o"&gt;=&amp;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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2023-01-01&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatUser&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="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handles invalid dates&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="o"&gt;=&amp;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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
          &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid-date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatUser&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="nx"&gt;memberSince&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown&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="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Lesson:&lt;/strong&gt;&lt;br&gt;
This suite runs in 4 milliseconds. It protects us against &lt;code&gt;null&lt;/code&gt; pointer exceptions and ensures our UI never says "undefined undefined". This is the highest ROI (Return on Investment) coding you can do.&lt;/p&gt;


&lt;h2&gt;
  
  
  Level 3: The "Smoke Protocol" (The Human Element)
&lt;/h2&gt;

&lt;p&gt;This is where I diverge from the "Best Practices" dogma.&lt;/p&gt;

&lt;p&gt;Standard advice says "Automate Everything." But setting up Cypress or Playwright to click a "Login" button, handle Authentication tokens, deal with 2FA, and wait for animations to finish is a massive maintenance burden. For a solo developer or a small team, &lt;strong&gt;maintenance is the enemy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead, I use a rigorous &lt;strong&gt;Manual Smoke Protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This isn't just "clicking around." It is a standardized checklist committed to the repository that must be physically checked off before a release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Protocol File (&lt;code&gt;docs/QA_SMOKE_CHECK.md&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# 🛑 Release Smoke Check Protocol&lt;/span&gt;
&lt;span class="gs"&gt;**Do not merge to main until all items are verified.**&lt;/span&gt;

&lt;span class="gu"&gt;## 1. Critical User Flows&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Authentication:**&lt;/span&gt; Log out and Log back in using Google Auth.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Data Persistence:**&lt;/span&gt; Update the user profile name, refresh the page. Does the new name persist?
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Payment Flow:**&lt;/span&gt; Go to /pricing, click "Buy", reach the Stripe Checkout hosted page. (Do not need to complete purchase).

&lt;span class="gu"&gt;## 2. Responsive Check&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Mobile Menu:**&lt;/span&gt; Open on iPhone viewport (Chrome DevTools). Does the hamburger menu expand?
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Grid Layout:**&lt;/span&gt; Resize window to 768px. Does the 3-column grid snap to 1-column?

&lt;span class="gu"&gt;## 3. The "Stupid" Check&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Console Errors:**&lt;/span&gt; Open DevTools console. Are there any red text blocks on the homepage?
&lt;span class="p"&gt;-&lt;/span&gt; [ ] &lt;span class="gs"&gt;**Links:**&lt;/span&gt; Click the "Contact Us" link in the footer. Does it 404?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt;&lt;br&gt;
It forces you to look at your application. Automated tests pass silently. Manual tests force you to feel the latency, see the layout shifts, and notice the janky animations that a script would ignore.&lt;/p&gt;


&lt;h2&gt;
  
  
  The "Gap" Analysis: What Are We Missing?
&lt;/h2&gt;

&lt;p&gt;To be an honest engineer, you must admit what you are &lt;em&gt;not&lt;/em&gt; testing. In this "Small Pyramid" stack, we have deliberate gaps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visual Regression:&lt;/strong&gt; We are not using Percy or Chromatic to check pixel-perfect rendering.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Risk:&lt;/em&gt; I might accidentally change the button color from blue to slightly-less-blue.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Acceptance:&lt;/em&gt; I can live with this risk in exchange for development speed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration Tests:&lt;/strong&gt; We are not mocking the full API and testing the connection between the Frontend and Backend components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Risk:&lt;/em&gt; The API contract might change (e.g., &lt;code&gt;firstName&lt;/code&gt; becomes &lt;code&gt;first_name&lt;/code&gt;) and the frontend will crash.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Mitigation:&lt;/em&gt; This is caught during the Manual Smoke Check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Browser Testing:&lt;/strong&gt; I am mostly testing on Chrome.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Risk:&lt;/em&gt; Safari might render flexbox differently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Acceptance:&lt;/em&gt; 90% of my traffic is Chrome/Mobile Safari. The Smoke Check covers the Mobile Safari viewport.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Bonus: Automating the Bedrock (GitHub Actions)
&lt;/h2&gt;

&lt;p&gt;We can't automate the Smoke Check easily, but we &lt;em&gt;must&lt;/em&gt; automate the Unit Tests. If tests only run on your laptop, they don't exist.&lt;/p&gt;

&lt;p&gt;Here is the exact workflow file I drop into every project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: `.github/workflows/test.yml&lt;/strong&gt;`&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Vitest&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that no code can be merged into &lt;code&gt;main&lt;/code&gt; unless the math functions and data formatters are working perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Verdict
&lt;/h2&gt;

&lt;p&gt;Testing is not binary. It is not "Tested" vs "Untested." It is a spectrum of confidence.&lt;/p&gt;

&lt;p&gt;By using &lt;strong&gt;Vitest&lt;/strong&gt; for the logic that &lt;em&gt;must&lt;/em&gt; be correct (math, data formatting) and a &lt;strong&gt;Smoke Protocol&lt;/strong&gt; for the things that &lt;em&gt;must&lt;/em&gt; look right (layout, navigation), you achieve 95% of the confidence with 10% of the maintenance cost of a full E2E suite.&lt;/p&gt;

&lt;p&gt;That is a trade I will take every single time.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>devops</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>AWS vs. Azure vs. Google Cloud: The Ultimate Free Tier Battle &amp; Survival Guide</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Thu, 29 Jan 2026 18:40:57 +0000</pubDate>
      <link>https://forem.com/bradleymatera/aws-vs-azure-vs-google-cloud-the-ultimate-free-tier-battle-survival-guide-2fam</link>
      <guid>https://forem.com/bradleymatera/aws-vs-azure-vs-google-cloud-the-ultimate-free-tier-battle-survival-guide-2fam</guid>
      <description>&lt;p&gt;&lt;strong&gt;Which cloud provider actually supports a developer’s growth for free, and which one is designing a billing trap?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my previous post, I broke down the mechanics of the AWS Free Tier—specifically how to survive the first 12 months without incurring surprise debt. Since then, the conversation has shifted toward a broader comparison. It is not enough to just know how AWS works; as developers, we need to know if we are even betting on the right horse.&lt;/p&gt;

&lt;p&gt;If you are building a portfolio, launching a startup prototype, or just trying to learn &lt;code&gt;cloud&lt;/code&gt; without melting your credit card, you need a side-by-side technical and financial breakdown.&lt;/p&gt;

&lt;p&gt;This is that breakdown.&lt;/p&gt;

&lt;p&gt;We are going to pit &lt;strong&gt;AWS&lt;/strong&gt;, &lt;strong&gt;Microsoft Azure&lt;/strong&gt;, and &lt;strong&gt;Google Cloud Platform (GCP)&lt;/strong&gt; against each other. We will analyze their compute limits, database constraints, hidden network costs, and the specific "gotchas" that each provider uses to monetize their free users.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Philosophy of "Free"
&lt;/h2&gt;

&lt;p&gt;Before looking at the numbers, you have to understand the business model, because it dictates the limitations you will face.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The cloud is not a charity. The Free Tier is a customer acquisition funnel designed to integrate you into an ecosystem."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS&lt;/strong&gt; wants you to build habits. Their 12-month model is designed to get you addicted to their specific proprietary tools (RDS, S3, IAM) so that when the year ends, the switching cost is too high to leave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure&lt;/strong&gt; wants enterprise adoption. They front-load credits ($200) to let you taste the "premium" power, hoping you'll convince your boss to migrate the company infrastructure later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GCP&lt;/strong&gt; plays the long game. They are the distant third in market share, so they offer the most generous "Always Free" tier to attract hobbyists and students, hoping that grassroots loyalty will grow their market share.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Compute: The Engine Room
&lt;/h2&gt;

&lt;p&gt;The biggest cost for any project is the Virtual Machine (VM). Here is how they compare when you strip away the marketing fluff.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS: The Standard (EC2)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Offer:&lt;/strong&gt; 750 Hours/month of &lt;code&gt;t2.micro&lt;/code&gt; or &lt;code&gt;t3.micro&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Specs:&lt;/strong&gt; 2 vCPUs (burstable), 1 GiB Memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Reality:&lt;/strong&gt; This is enough to run one instance continuously (24/7) for a month. However, AWS uses a "CPU Credit" system. If your website gets a sudden spike in traffic, you burn credits. If you run out of credits, your CPU is throttled to baseline performance, making your site crawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Trap:&lt;/strong&gt; It is strictly &lt;strong&gt;12 months&lt;/strong&gt;. On day 366, you are billed standard on-demand rates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Azure: The Burstable (B-Series)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Offer:&lt;/strong&gt; 750 Hours/month of &lt;code&gt;B1s&lt;/code&gt; instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Specs:&lt;/strong&gt; 1 vCPU, 1 GiB Memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Reality:&lt;/strong&gt; Similar to AWS, this uses a credit banking system. The &lt;code&gt;B1s&lt;/code&gt; is noticeably weaker than the AWS &lt;code&gt;t3.micro&lt;/code&gt; for multi-threaded tasks because it only offers 1 vCPU compared to AWS's 2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Trap:&lt;/strong&gt; The interface. Azure’s portal is complex. It is very easy to accidentally select a "Standard SSD" (paid) instead of a "Standard HDD" (free) during setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GCP: The Forever Server (Compute Engine)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Offer:&lt;/strong&gt; &lt;code&gt;e2-micro&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Specs:&lt;/strong&gt; 2 vCPUs, 1 GiB Memory (0.25 vCPU sustained).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Reality:&lt;/strong&gt; &lt;strong&gt;This is the winner for longevity.&lt;/strong&gt; As of this writing, this offer is part of the "Always Free" program, meaning it does not expire after 12 months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Trap:&lt;/strong&gt; Location. This is only free in specific regions (usually &lt;code&gt;us-west1&lt;/code&gt;, &lt;code&gt;us-central1&lt;/code&gt;, &lt;code&gt;us-east1&lt;/code&gt;). If you deploy in &lt;code&gt;us-east4&lt;/code&gt; by mistake, you pay full price immediately.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Databases: The Expensive Part
&lt;/h2&gt;

&lt;p&gt;Stateless servers are cheap; stateful data is expensive. This is where the cloud providers try to squeeze you.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS (RDS)
&lt;/h3&gt;

&lt;p&gt;AWS offers 750 hours of &lt;code&gt;db.t2.micro&lt;/code&gt; or &lt;code&gt;db.t3.micro&lt;/code&gt; (Single-AZ).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; You get a real, managed relational database (MySQL, PostgreSQL, MariaDB).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; It stops being free after 12 months. Migrating data &lt;em&gt;out&lt;/em&gt; of AWS later can be tricky due to egress fees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Azure (SQL Database)
&lt;/h3&gt;

&lt;p&gt;Azure offers 250 GB of Azure SQL Database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; 250 GB is massive compared to the 20GB limit often seen elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; This is specifically "Azure SQL," which is Microsoft SQL Server. If your project is built on Postgres or MySQL, this free tier doesn't help you much. You have to adapt your stack to their technology.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GCP (Firestore)
&lt;/h3&gt;

&lt;p&gt;GCP does &lt;strong&gt;not&lt;/strong&gt; offer a generous free tier for Cloud SQL (their managed relational service). Instead, they push you toward Firestore (NoSQL).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Firestore is incredibly fast and easy for mobile apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; It is NoSQL. If you are trying to learn traditional SQL table relationships, GCP forces you to pay roughly $10-$15/month for the smallest SQL instance.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. The "Silent Killers" of Cloud Billing
&lt;/h2&gt;

&lt;p&gt;Regardless of which provider you choose, the billing algorithms share the same ruthless logic regarding "optional" resources. These are the line items that do not appear on the main pricing page but appear on your invoice.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Orphaned Volume
&lt;/h3&gt;

&lt;p&gt;When you terminate a server, the cloud provider assumes you want to keep the data. They delete the compute resource but leave the hard drive (EBS/Disk) active.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Cost:&lt;/strong&gt; Roughly $0.10 per GB per month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix:&lt;/strong&gt; You must manually locate the "Storage" or "Volumes" dashboard and delete these unattached disks. There is no auto-delete for these.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Static IP Tax
&lt;/h3&gt;

&lt;p&gt;A static IP (Elastic IP) is free &lt;em&gt;only while it is being used&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Logic:&lt;/strong&gt; IPv4 addresses are a scarce global resource. The providers punish you for hoarding them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cost:&lt;/strong&gt; If you stop your server but keep the IP reserved, you are charged ~$0.005/hour. That is roughly $3.60/month for doing absolutely nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data Egress (The "Hotel California" Fee)
&lt;/h3&gt;

&lt;p&gt;You can check out any time you like, but you can never leave—without paying.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ingress (Data In):&lt;/strong&gt; Always Free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Egress (Data Out):&lt;/strong&gt; Charged per GB after a small threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Risk:&lt;/strong&gt; If you host a large media file and it gets hotlinked on a popular site, your egress fees will skyrocket instantly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Verdict: Which One Should You Choose?
&lt;/h2&gt;

&lt;p&gt;After deploying stacks on all three, here is my decision matrix for new projects:&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose AWS If:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;You are job hunting.&lt;/strong&gt; AWS holds the largest market share. Having "Deployed MERN stack on EC2" on your resume is statistically more valuable than the others.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You need a standard SQL database.&lt;/strong&gt; The RDS free tier is the most straightforward way to run MySQL/Postgres for a year.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Choose GCP If:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;You are building a permanent personal tool.&lt;/strong&gt; If you want a Discord bot or a script runner that stays online for 5 years for $0, the &lt;code&gt;e2-micro&lt;/code&gt; is unmatched.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You are comfortable with Linux/Command Line.&lt;/strong&gt; GCP’s interface is developer-focused but less "hand-holding" than Azure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Choose Azure If:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;You work in the .NET ecosystem.&lt;/strong&gt; Visual Studio integration with Azure is seamless.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;You need massive database storage.&lt;/strong&gt; The 250GB SQL limit is generous if you are willing to use Microsoft SQL Server.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Golden Rule
&lt;/h3&gt;

&lt;p&gt;The only true way to stay free is &lt;strong&gt;vigilance&lt;/strong&gt;. Set up "Billing Alerts" the moment you create your account. Set an alert for $0.01. The moment you get that email, you know you have crossed a line, and you can fix it before it becomes a $500 problem.&lt;/p&gt;

&lt;p&gt;Stay curious, keep building, and check your billing dashboard every single morning.&lt;/p&gt;

&lt;p&gt;— &lt;strong&gt;Bradley Matera&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(bradleymatera.dev)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>azure</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>Designing Systems That Actually Ship</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Sat, 13 Dec 2025 00:24:32 +0000</pubDate>
      <link>https://forem.com/bradleymatera/designing-systems-that-actually-ship-39ii</link>
      <guid>https://forem.com/bradleymatera/designing-systems-that-actually-ship-39ii</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; This is how I approach reusable UI as an engineer who cares about consistency, accessibility, and developer experience, even on small teams and solo builds.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;AI assist:&lt;/strong&gt; ChatGPT helps me outline docs and tighten wording. The code choices, constraints, and results come from my own builds, audits, and reviews.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Status:&lt;/strong&gt; 2025 playbook based on how I’ve been structuring my Gatsby portfolio and other React projects while I finish my degree and keep shipping.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I try to build UI systems the same way I build production software: translate intent into predictable patterns, document decisions clearly, and keep accessibility and maintainability in mind. My stuff leans opinionated and a little over-structured because I want it to survive edits, handoffs, and future me forgetting why I did something.&lt;/p&gt;

&lt;p&gt;In practice, I lean on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tokens and primitives (mostly CSS custom properties + reusable components) to encode intent.&lt;/li&gt;
&lt;li&gt;Documentation patterns (recipes, reality blocks, checklists) to prevent drift.&lt;/li&gt;
&lt;li&gt;Accessibility defaults and lightweight audits so the system stays usable, not just good looking.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a id="reality-snapshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reality snapshot
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where this is applied:&lt;/strong&gt; My Gatsby portfolio/blog, school projects, and small React apps where I want consistent UI without rewriting styling rules on every page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling I actually use:&lt;/strong&gt; Gatsby + React, MDX, TypeScript (when the project calls for it), ESLint/Prettier, Lighthouse, basic accessibility checks (keyboard navigation, headings/labels, contrast), and Playwright smoke tests on deploy previews for flow-heavy projects. Axe automation is still being rolled in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What I’m not claiming:&lt;/strong&gt; I’m not running a full enterprise design-system pipeline. I’m not consistently shipping versioned npm packages for a design system, and I’m not running visual regression testing as a hard gate on every project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What I do have:&lt;/strong&gt; A repeatable way of building components, keeping styles consistent, and documenting decisions so the site stays maintainable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Reality snapshot
&lt;/li&gt;
&lt;li&gt;
Why I take design systems seriously
&lt;/li&gt;
&lt;li&gt;
Over-structuring is a feature
&lt;/li&gt;
&lt;li&gt;
How I translate design into code
&lt;/li&gt;
&lt;li&gt;
CSS architecture and constraints
&lt;/li&gt;
&lt;li&gt;
Accessibility is part of the API
&lt;/li&gt;
&lt;li&gt;
Documentation as a first-class deliverable
&lt;/li&gt;
&lt;li&gt;
Design system starter kit (my 2025 version)
&lt;/li&gt;
&lt;li&gt;
Collaboration habits that keep changes shippable
&lt;/li&gt;
&lt;li&gt;
Receipts from my own builds
&lt;/li&gt;
&lt;li&gt;
Working across design and engineering
&lt;/li&gt;
&lt;li&gt;
What I care about building next
&lt;/li&gt;
&lt;li&gt;Closing thoughts&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a id="why-i-take-design-systems-seriously"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Take Design Systems Seriously
&lt;/h2&gt;

&lt;p&gt;Design systems are not just styling. They are a contract.&lt;/p&gt;

&lt;p&gt;Even on a small project, UI breaks down when the rules live in someone’s head. That’s when you get drift: spacing starts to vary, buttons feel different across pages, and you end up with random one-off styling fixes that are hard to unwind later.&lt;/p&gt;

&lt;p&gt;I learned that a lot of UI issues aren’t “design problems.” They’re consistency problems caused by unclear patterns and missing documentation.&lt;/p&gt;

&lt;p&gt;When I build a reusable component, I’m not only thinking about how it looks on one page. I’m thinking about how it behaves when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It gets reused across multiple pages&lt;/li&gt;
&lt;li&gt;It needs responsive layout behavior&lt;/li&gt;
&lt;li&gt;Someone updates it later without context&lt;/li&gt;
&lt;li&gt;Accessibility needs tighten up&lt;/li&gt;
&lt;li&gt;The site grows and “quick fixes” start stacking up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why I push structure early. It saves time later.&lt;/p&gt;




&lt;p&gt;&lt;a id="over-structuring-is-a-feature-not-a-flaw"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Over-Structuring Is a Feature, Not a Flaw
&lt;/h2&gt;

&lt;p&gt;I used to worry that I was adding too much ceremony. Then I ran into the same class of problems repeatedly: unclear props, inconsistent spacing, and components that slowly turned into “do anything” blobs.&lt;/p&gt;

&lt;p&gt;So now I try to separate three things as I build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intent:&lt;/strong&gt; what the component is for&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation detail:&lt;/strong&gt; what can change without breaking consumers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer API:&lt;/strong&gt; what other code should touch (props, variants, and documented usage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shows up in how I organize components, tokens, and docs.&lt;/p&gt;

&lt;p&gt;I prefer systems where spacing, color, and typography decisions don’t get scattered across random files or inline overrides. Instead, I centralize them behind a small set of variables and patterns.&lt;/p&gt;

&lt;p&gt;Sometimes I still use UI libraries depending on the project. When I do, I try to rely on theme-level configuration and composition more than ad-hoc overrides. I want the system to feel predictable to the next developer.&lt;/p&gt;




&lt;p&gt;&lt;a id="how-i-translate-design-into-code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Translate Design Into Code
&lt;/h2&gt;

&lt;p&gt;I treat UI decisions like data, even when I’m working without a formal design handoff.&lt;/p&gt;

&lt;p&gt;My first step is usually “pattern spotting”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What repeats?&lt;/li&gt;
&lt;li&gt;What should scale across breakpoints?&lt;/li&gt;
&lt;li&gt;What’s a real variant vs. a one-off?&lt;/li&gt;
&lt;li&gt;What can be standardized into a token?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there I map it into abstractions developers expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tokens via CSS custom properties for things like spacing, radii, and colors&lt;/li&gt;
&lt;li&gt;Constrained variants for components instead of “pass any class”&lt;/li&gt;
&lt;li&gt;Reusable layout wrappers instead of rewriting layout rules every time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not chasing perfect parity on the first pass. I’m chasing &lt;strong&gt;predictable evolution&lt;/strong&gt;. I want it to be obvious where changes should live when the site grows.&lt;/p&gt;




&lt;p&gt;&lt;a id="css-architecture-and-constraints"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Architecture and Constraints
&lt;/h2&gt;

&lt;p&gt;CSS is powerful, but it gets messy fast without boundaries.&lt;/p&gt;

&lt;p&gt;In my projects, I try to keep CSS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Predictable (low specificity, few surprises)&lt;/li&gt;
&lt;li&gt;Consistent (shared variables and repeated patterns)&lt;/li&gt;
&lt;li&gt;Responsive (layouts that don’t collapse weird on mobile)&lt;/li&gt;
&lt;li&gt;Debuggable (simple selectors, clear ownership)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even when using modern tooling, the fundamentals still matter: flow, containment, inheritance, layout, and the cascade.&lt;/p&gt;

&lt;p&gt;CSS custom properties do a lot of work for me because they’re transparent and flexible. If something feels off, I can inspect it quickly and trace where it came from.&lt;/p&gt;

&lt;p&gt;Animations exist, but I keep them restrained. If motion doesn’t improve clarity or hierarchy, it’s probably noise.&lt;/p&gt;




&lt;p&gt;&lt;a id="accessibility-is-part-of-the-api"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility Is Part of the API
&lt;/h2&gt;

&lt;p&gt;Accessibility is not something I want to “add later.” It shapes how components should be built.&lt;/p&gt;

&lt;p&gt;In practice, that means I aim for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic HTML first&lt;/li&gt;
&lt;li&gt;Keyboard navigation that makes sense&lt;/li&gt;
&lt;li&gt;Clear labels, headings, and focus states&lt;/li&gt;
&lt;li&gt;Contrast that isn’t fragile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My approach is not perfect, but it is consistent. I do a lot of basic checks that catch the majority of issues early, especially on content-heavy pages like my blog.&lt;/p&gt;

&lt;p&gt;I also don’t pretend that a visually correct UI is automatically usable. I try to validate behavior, not just appearance.&lt;/p&gt;




&lt;p&gt;&lt;a id="documentation-as-a-first-class-deliverable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation as a First-Class Deliverable
&lt;/h2&gt;

&lt;p&gt;Documentation is part of shipping, especially when UI patterns are reused.&lt;/p&gt;

&lt;p&gt;Good docs answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What this is for&lt;/li&gt;
&lt;li&gt;When to use it&lt;/li&gt;
&lt;li&gt;When not to use it&lt;/li&gt;
&lt;li&gt;What assumptions it makes&lt;/li&gt;
&lt;li&gt;What is intentionally out of scope&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I write documentation mostly to reduce future confusion. If a system requires tribal knowledge to use, it will fragment.&lt;/p&gt;

&lt;p&gt;This is also why I care about contribution habits like code reviews and clear PR descriptions. Even on solo projects, I treat my repo like someone else will inherit it later.&lt;/p&gt;




&lt;p&gt;&lt;a id="design-system-starter-kit-my-2025-version"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design System Starter Kit (My 2025 Version)
&lt;/h2&gt;

&lt;p&gt;This is what I actually use or aim for in my projects, without pretending it’s an enterprise pipeline.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tokens as the baseline:&lt;/strong&gt; CSS custom properties for spacing, typography scale, radii, and colors. When I add a new value, I try to do it as a token first instead of a one-off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout patterns:&lt;/strong&gt; A small set of reusable layout components or classes (sections, cards, grids, stacks) so pages don’t become unique snowflakes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constrained variants:&lt;/strong&gt; Buttons, badges, and cards usually expose a few variants and sizes. I avoid “pass any className and hope” unless it’s a deliberate escape hatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State handling:&lt;/strong&gt; Disabled and loading states are treated as real states, not afterthoughts. If the UI can be in that state, it should be styled and understandable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight validation:&lt;/strong&gt; Lighthouse runs, keyboard walkthrough, basic contrast checks, and quick manual spot checks across breakpoints. Axe automation is still on deck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs scaffolding:&lt;/strong&gt; For the parts I reuse the most, I keep short docs that include intent, usage examples, and “don’t do this” notes.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a id="collaboration-habits-that-keep-changes-shippable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Collaboration Habits That Keep Changes Shippable
&lt;/h2&gt;

&lt;p&gt;A lot of my work is solo, but I still try to build habits that translate to team environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I write PR descriptions as if someone else will review them later.&lt;/li&gt;
&lt;li&gt;I keep notes about what a change impacts (layout, typography, components, content).&lt;/li&gt;
&lt;li&gt;If a change risks breaking UI, I test it across desktop and mobile widths before calling it done.&lt;/li&gt;
&lt;li&gt;I try to leave “why” breadcrumbs in commit messages, not just “what.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On teams, I think most UI chaos comes from missing intent and unclear ownership. My default move is to make the decision explicit, then make it repeatable.&lt;/p&gt;




&lt;p&gt;&lt;a id="receipts-from-my-own-builds"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Receipts From My Own Builds
&lt;/h2&gt;

&lt;p&gt;These are examples of how I’ve been applying this on my own site and projects, without overselling it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What I shipped&lt;/th&gt;
&lt;th&gt;Practices applied&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gatsby portfolio/blog&lt;/td&gt;
&lt;td&gt;CSS variable tokens in &lt;code&gt;src/styles/global.css&lt;/code&gt;, MDX shortcodes (Callout/Aside/Tip) to keep posts consistent, and built-in skip link/back-to-top controls.&lt;/td&gt;
&lt;td&gt;Documented content patterns in &lt;code&gt;docs/content-authoring.md&lt;/code&gt;, predictable section/card layouts, Lighthouse + keyboard spot checks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive Pokédex (GitHub Pages)&lt;/td&gt;
&lt;td&gt;Vanilla JS + Tailwind build with labeled search, accessible sprites, caching, and clear rate-limit messaging.&lt;/td&gt;
&lt;td&gt;Lighthouse scores logged in the repo, keyboard walkthroughs per README, planned Jest + Playwright tests noted in the post.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CheeseMath (Card Obscurer)&lt;/td&gt;
&lt;td&gt;Luhn validation, inline errors, ARIA labels; CodePen prototype graduated to a GitHub Pages demo.&lt;/td&gt;
&lt;td&gt;Reality block lists mobile Safari quirks; next steps are axe/Lighthouse audits and unit tests before calling it portfolio-ready.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a id="working-across-design-and-engineering"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Across Design and Engineering
&lt;/h2&gt;

&lt;p&gt;I’m comfortable sitting between design and engineering because I’m used to translating intent into constraints.&lt;/p&gt;

&lt;p&gt;I don’t try to redesign someone’s work. I try to clarify it, and then encode it into predictable patterns.&lt;/p&gt;

&lt;p&gt;When there’s tension between design fidelity and engineering constraints, my preference is to surface it early and make the tradeoff explicit rather than silently compromising.&lt;/p&gt;

&lt;p&gt;Most friction comes from ambiguity. Clarity solves more than arguing about implementation details.&lt;/p&gt;




&lt;p&gt;&lt;a id="what-i-care-about-building-next"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Care About Building Next
&lt;/h2&gt;

&lt;p&gt;I want to work on UI systems that feel like infrastructure.&lt;/p&gt;

&lt;p&gt;That means systems that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are used by multiple developers or teams&lt;/li&gt;
&lt;li&gt;Need stability over time&lt;/li&gt;
&lt;li&gt;Balance flexibility with consistency&lt;/li&gt;
&lt;li&gt;Treat accessibility and predictability as core requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not chasing novelty. I care about systems that quietly work, scale, and reduce cognitive load for people building product UI.&lt;/p&gt;




&lt;p&gt;&lt;a id="closing-thoughts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;I’m not a visual designer. I’m an engineer who cares about UI being consistent, accessible, and maintainable.&lt;/p&gt;

&lt;p&gt;I default to structure because ambiguity doesn’t scale. I write docs because people deserve clarity. And I try to build systems that make the correct thing easy and the wrong thing harder to do by accident.&lt;/p&gt;

&lt;p&gt;If there’s one theme across my projects, it’s this:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;good systems keep shipping because they stay understandable.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>a11y</category>
      <category>css</category>
      <category>ui</category>
    </item>
    <item>
      <title>Full Sail University: How Formal Training Shaped My Approach</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Sun, 07 Dec 2025 18:49:09 +0000</pubDate>
      <link>https://forem.com/bradleymatera/full-sail-university-how-formal-training-shaped-my-approach-66k</link>
      <guid>https://forem.com/bradleymatera/full-sail-university-how-formal-training-shaped-my-approach-66k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; Finished Full Sail’s Web Development B.S. in October 2025 (GPA ~3.8). Still looking for my first paid SWE role.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;AI assist:&lt;/strong&gt; ChatGPT helped reorganize my notes; I cross-checked with syllabi/transcripts.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Status:&lt;/strong&gt; Honest recap, not an attempt to inflate coursework into production experience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfrgev9fsn2rjxiocc7n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfrgev9fsn2rjxiocc7n.gif" alt="Fast-paced sprints" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Program snapshot
&lt;/h2&gt;

&lt;p&gt;Full Sail’s Web Development program moves fast. Everything is built around four-week sprints—controlled chaos with a deadline. You focus on &lt;strong&gt;one course at a time&lt;/strong&gt;, but each month hits like its own bootcamp.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Format:&lt;/strong&gt; 4-week sprints with rotating instructors and rubrics.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule:&lt;/strong&gt; Workload shifted constantly—some weeks light, others unexpectedly heavy.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deliverables:&lt;/strong&gt; Working build, documentation, rubric checklist, and a retro or reflection.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grading weight:&lt;/strong&gt; Docs/presentation quality mattered almost as much as code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Course areas that shaped me the most
&lt;/h2&gt;

&lt;p&gt;Full Sail’s titles shifted over time and instructors ran things differently, so grouping by area is more honest than listing exact course names.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Course area&lt;/th&gt;
&lt;th&gt;Key deliverable&lt;/th&gt;
&lt;th&gt;Skills reinforced&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full-stack project cycles (Project &amp;amp; Portfolio)&lt;/td&gt;
&lt;td&gt;Building and iterating on a React + Node app each month&lt;/td&gt;
&lt;td&gt;Iteration, planning, accepting critique, demoing unfinished work with confidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side development&lt;/td&gt;
&lt;td&gt;REST APIs, templating, session-based auth in Node/PHP&lt;/td&gt;
&lt;td&gt;Routing, state handling, error patterns, readable backend structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud and application deployment&lt;/td&gt;
&lt;td&gt;AWS Academy labs with services like Elastic Beanstalk, RDS, CloudWatch (sandbox depth)&lt;/td&gt;
&lt;td&gt;Basic cloud mental models, logging, monitoring, cost awareness, rollback habits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Systems and configuration basics&lt;/td&gt;
&lt;td&gt;Linux permissions, basic Nginx concepts, small automation scripts&lt;/td&gt;
&lt;td&gt;Ops hygiene, troubleshooting steps, repeatable checklists, scripting discipline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human-Computer Interaction &amp;amp; UX&lt;/td&gt;
&lt;td&gt;Usability testing, accessibility checks, persona-driven design exercises&lt;/td&gt;
&lt;td&gt;UX empathy, accessibility awareness, clearer communication with non-technical people&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Signature projects &amp;amp; evidence
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Capstone: Car-Match (personal learning project)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; React, Node.js/Express, MongoDB Atlas, Render (backend), GitHub Pages (frontend)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reality:&lt;/strong&gt; End-to-end matching prototype I built myself. Handles auth, profiles, uploads, scoring, and real-time updates once the backend wakes up. Runs on free-tier infra, so I classify it as a learning project—not production.
&lt;/li&gt;
&lt;li&gt;Repo + demo: &lt;a href="https://github.com/BradleyMatera/car-match" rel="noopener noreferrer"&gt;https://github.com/BradleyMatera/car-match&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasards36hw0gvhodir49.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasards36hw0gvhodir49.gif" alt="Debugging late nights" width="400" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Other projects that shaped my learning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Pokédex:&lt;/strong&gt; API-driven search, cards, error states, responsive layout. Demo: &lt;a href="https://bradleymatera.github.io/Interactive-Pokedex/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/Interactive-Pokedex/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AnimalSounds:&lt;/strong&gt; Small UI/UX experiment for sound triggers and mobile-first interaction. Demo: &lt;a href="https://bradleymatera.github.io/AnimalSounds/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/AnimalSounds/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional Portfolio Website:&lt;/strong&gt; Hand-built portfolio (no template). Demo: &lt;a href="https://bradleymatera.github.io/Professional-Portfolio-Website/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/Professional-Portfolio-Website/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CheeseMath (Jest Tests):&lt;/strong&gt; Tiny math utility to learn unit testing/mocking/CI. Demo: &lt;a href="https://bradleymatera.github.io/CheeseMath-Jest-Tests/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/CheeseMath-Jest-Tests/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triangle WebGPU Demo:&lt;/strong&gt; First graphics experiment; learned the pipeline and debugging GPU errors. Demo: &lt;a href="https://bradleymatera.github.io/TriangleDemo/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/TriangleDemo/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ethics Engine Frontend Demo:&lt;/strong&gt; Rule-based decision UI prototype. Demo: &lt;a href="https://bradleymatera.github.io/EthicsFrontEndDemo/" rel="noopener noreferrer"&gt;https://bradleymatera.github.io/EthicsFrontEndDemo/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Server Management Lab
&lt;/h3&gt;

&lt;p&gt;Covered Linux hardening, Nginx basics, and bash automation. I didn’t build full AWS pipelines there; most of my ops habits came later from personal projects and the AWS internship.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication touchpoints
&lt;/h3&gt;

&lt;p&gt;This was a remote program. I didn’t do weekly stand-ups with classmates. Most “comms practice” came from Tech Talk (an after-class group) and occasional Q&amp;amp;A with instructors. The status-report style in my repos is a personal habit, not from formal stand-ups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habits I carried forward
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sprint rhythm:&lt;/strong&gt; Intake → prototype → critique → iterate → deliver.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs before code:&lt;/strong&gt; Clarity, diagrams, tests, deploy notes, retro—no “done” without docs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback resilience:&lt;/strong&gt; Frequent scope pivots desensitized me to change.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honesty logs:&lt;/strong&gt; Every project tracks what’s done, broken, and next.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnmrhbeb8ey4sq9ehtbw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnmrhbeb8ey4sq9ehtbw.gif" alt="Cloud labs" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond coursework
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Cloud Support Internship:&lt;/strong&gt; Concepts at school; reality at AWS—log hunting, broken infra diagnosis under time pressure.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community involvement:&lt;/strong&gt; CIRIS docs, Tech Talk Club, alumni Q&amp;amp;A, small OSS fixes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal experiments:&lt;/strong&gt; WebGPU shaders and Zig parsers filled curriculum gaps and showed where academics stop and the real world begins.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the program didn’t cover (well)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deep CS theory (algorithms, data structures beyond basics).
&lt;/li&gt;
&lt;li&gt;Production-scale DevOps (multi-account AWS, Terraform modules, blast radius).
&lt;/li&gt;
&lt;li&gt;Real on-call culture—no paging, SLAs, or incident triage.
&lt;/li&gt;
&lt;li&gt;System design beyond small apps.
&lt;/li&gt;
&lt;li&gt;I compensate with LeetCode, cloud labs, ACloudGuru, personal projects, and the internship.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A week-in-the-life during a sprint
&lt;/h2&gt;

&lt;p&gt;There was no single “normal week.” Each course had its own rhythm. The consistent anchors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weekly project due Sunday&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If discussions existed:&lt;/strong&gt; initial post Thursday, two replies Sunday&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else moved. Some weeks felt like lightweight labs; others like a four-week hackathon squeezed into six days. Rubrics sometimes contradicted themselves. The real skill was adjusting, interpreting, and self-organizing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early-week orientation:&lt;/strong&gt; Rubric drops, announcements, decoding expectations (every instructor interpreted rubrics differently).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mid-week chaos (or silence):&lt;/strong&gt; Could be UI flows, backend logic, DB schema, AWS lab, accessibility review, or waiting for clarifications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Late-week push (Thu–Sun):&lt;/strong&gt; Partners available, critiques posted, requirements clarified—prototypes became real builds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sunday crunch:&lt;/strong&gt; Final packaging, retros, last-second fixes, demos, screenshots, README tweaks. Most submissions landed in a 6–10 hour window before 11:59 PM ET.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvfxqc9jir5gjjlmxr3t.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvfxqc9jir5gjjlmxr3t.gif" alt="Sunday crunch energy" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bottom line: no ritual Monday–Friday—only adaptation, deadlines, and evidence. That forced me to build my own systems for consistency and delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes I made (and fixed) — the real list
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Building the whole idea instead of the assignment:&lt;/strong&gt; I’d architect like it was a startup app and chase features no one graded. Fix: work backward from the rubric and ship faster.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-researching instead of starting:&lt;/strong&gt; I’d read docs, overthink tooling, and delay writing code. Fix: prototype early, even if rough—speed doubled once something existed.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Light Git/GitHub use early on:&lt;/strong&gt; Forgot to commit/branch and lost work. Fix: proper commits/branches became natural once projects grew (Car-Match).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Letting vague rubrics stall me:&lt;/strong&gt; I’d wait for clarification and lose days. Fix: make assumptions, document them, and move.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Underestimating “simple” tasks:&lt;/strong&gt; UI, APIs, deploys, and auth always took longer. Fix: pad time and treat “simple” as “unknown.”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not testing on real devices:&lt;/strong&gt; Early projects broke on phones/tablets. Fix: test on mobile and use dev tools for responsiveness.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploying last-minute:&lt;/strong&gt; Sunday-night deploys failed (cold starts, cache, env vars). Fix: deploy early/often—never first deploy on Sunday.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working solo by default:&lt;/strong&gt; In groups I’d carry too much. Fix: delegate by rubric items, set boundaries.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not documenting decisions:&lt;/strong&gt; Forgetting my own reasoning led to rework. Fix: write decisions while coding.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perfection before done:&lt;/strong&gt; Polished UI and rewrote working code needlessly. Fix: Done → Working → Better.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding “boring” topics:&lt;/strong&gt; Accessibility, testing, comments, error messages, validation. Fix: school and Car-Match forced me to care.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trying to learn everything at once:&lt;/strong&gt; Spread too thin across front/back/cloud/devops/design. Fix: narrow focus to 1–2 skills per month and rotate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h3xvx3wtzqfdl0xldc0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h3xvx3wtzqfdl0xldc0.gif" alt="Checklists and retros" width="480" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I present this to employers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This degree gave me &lt;strong&gt;reps&lt;/strong&gt;, not production.
&lt;/li&gt;
&lt;li&gt;I pair each course with a link + one-sentence takeaway.
&lt;/li&gt;
&lt;li&gt;I’m explicit about gaps and how I’m closing them.
&lt;/li&gt;
&lt;li&gt;I show projects, runbooks, evidence, retros—not hype.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advice to future Full Sail students
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Treat rubrics like user stories—finish with evidence.
&lt;/li&gt;
&lt;li&gt;Keep a parking-lot list so you don’t chase stretch ideas mid-sprint.
&lt;/li&gt;
&lt;li&gt;Record Looms weekly; they save presentations.
&lt;/li&gt;
&lt;li&gt;Build one anchor project outside class to unify skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Metrics and receipts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;~20 projects shipped.
&lt;/li&gt;
&lt;li&gt;Every sprint: at least two critique loops.
&lt;/li&gt;
&lt;li&gt;GPA ~3.8; strongest in docs/presentations.
&lt;/li&gt;
&lt;li&gt;Post-grad: weekly code reviews with peers to keep cadence alive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Artifacts &amp;amp; links
&lt;/h2&gt;

&lt;p&gt;Most portfolio/GitHub repos come from Full Sail work, but syllabi, rubrics, and runbooks are private or lost. If you want specific artifacts, I can share what I have privately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Formal education gave me structure, accountability, and reps presenting/defending work.
&lt;/li&gt;
&lt;li&gt;Side projects and internships are essential to stress-test those skills.
&lt;/li&gt;
&lt;li&gt;Full Sail drilled an honesty mindset: document what’s done, what’s broken, and what’s next—no fluff.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>careerdevelopment</category>
    </item>
    <item>
      <title>How to Sell Your Skills with a Small Project</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Thu, 20 Nov 2025 22:34:12 +0000</pubDate>
      <link>https://forem.com/bradleymatera/how-to-sell-your-skills-with-a-small-project-1h0p</link>
      <guid>https://forem.com/bradleymatera/how-to-sell-your-skills-with-a-small-project-1h0p</guid>
      <description>&lt;h3&gt;
  
  
  A Guide for Developers Who Feel Like They Don’t Have Enough Experience
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh8mtyh6cbv98y6swcrs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh8mtyh6cbv98y6swcrs.gif" alt="overwhelmed" width="480" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lot of people hold themselves back because they think they need a massive full-stack application to prove they can code. The truth is — a basic web demo can show more than enough skill &lt;strong&gt;if you build it intentionally&lt;/strong&gt; and &lt;strong&gt;explain it the right way&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide is about taking something small — literally &lt;strong&gt;three files&lt;/strong&gt; — and turning it into something you can confidently put on a résumé, in a portfolio, or discuss in interviews without exaggerating your abilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Your Project Can Be Small — Just Make It Real
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73buycrhna666nrezjaf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73buycrhna666nrezjaf.gif" alt="determined" width="500" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don’t need a full SaaS app. You don’t need authentication systems and complex APIs.&lt;br&gt;&lt;br&gt;
For most junior roles, a realistic demo looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.html
style.css
script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be your entire codebase, hosted on GitHub Pages, and it can still prove you know what you’re doing — if you treat it like a real product.&lt;/p&gt;

&lt;p&gt;The key isn’t size — it’s intention. Every file should serve a purpose, and every purpose can be explained as real engineering work.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Step 2: What Skills Can You Show?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhjbc01d3kndr3k0yprh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhjbc01d3kndr3k0yprh.gif" alt="problem-solving" width="370" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what a recruiter or engineer sees when they look at even a simple demo site — IF you structure it well and document it clearly.&lt;/p&gt;

&lt;p&gt;Frontend Thinking&lt;/p&gt;

&lt;p&gt;If your layout makes sense and responds well to different screens, that’s frontend engineering.&lt;br&gt;
If you explain why something goes where it goes — that’s UX/UI understanding.&lt;br&gt;
If you use CSS tokens or variables — that shows planning and scalability.&lt;/p&gt;

&lt;p&gt;State &amp;amp; Data Handling&lt;/p&gt;

&lt;p&gt;If your site uses localStorage, sessionStorage, or even a simple JSON file — you’re showing backend logic and data flow understanding.&lt;br&gt;
If you handle user input with validation — that’s real logic, not just visuals.&lt;/p&gt;

&lt;p&gt;Deploying It Live&lt;/p&gt;

&lt;p&gt;If it’s on GitHub Pages, Netlify, Vercel, or any real host — then you’ve already touched DevOps:&lt;br&gt;
    • version control&lt;br&gt;
    • build settings&lt;br&gt;
    • deploy logs&lt;br&gt;
    • environment setup&lt;br&gt;
    • troubleshooting live errors&lt;/p&gt;

&lt;p&gt;That alone puts you ahead of people who only code locally.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Step 3: Make the README Do Half the Work for You&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68v92v82fh2886n5xez7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68v92v82fh2886n5xez7.gif" alt="writing" width="498" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your README is where you sell yourself without lying.&lt;br&gt;
You explain what the project is, why you built it, what problem it solves, what decisions you made, and what you’d improve later.&lt;/p&gt;

&lt;p&gt;That shows growth, and growth is what recruiters actually look for in junior devs.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Step 4: Add One Detail That Makes It Stand Out&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c57baasypnx0iz2wizx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c57baasypnx0iz2wizx.gif" alt="lightbulb" width="480" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To turn a basic demo into real proof of skill:&lt;br&gt;
Pick one feature and build it well.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
    • A theme toggle with JavaScript and localStorage&lt;br&gt;
    • Live form validation&lt;br&gt;
    • Simple data filtering and sorting&lt;br&gt;
    • A dynamic card system (like a product grid)&lt;br&gt;
    • A user settings panel that remembers choices&lt;/p&gt;

&lt;p&gt;Something small, but intentional.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Step 5: Talk About the Project Like an Engineer&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibkw49yxiijz0pdf0jvj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibkw49yxiijz0pdf0jvj.gif" alt="confident-presentation" width="320" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In interviews or your portfolio, never say:&lt;/p&gt;

&lt;p&gt;“It’s just a small demo.”&lt;/p&gt;

&lt;p&gt;Say this instead:&lt;/p&gt;

&lt;p&gt;“I built a small frontend project to show responsive design, basic data handling, and deployment. I focused on user flow, accessibility tags, and real interaction. If I had more time, I’d expand it with a backend and user system.”&lt;/p&gt;

&lt;p&gt;You didn’t lie.&lt;br&gt;
You didn’t exaggerate.&lt;br&gt;
But you framed it like someone who thinks in systems — which is what engineers do.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Final Message to Anyone Who Feels Behind&lt;br&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nkxg1h1570fe84do6ow.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nkxg1h1570fe84do6ow.gif" alt="hopeful" width="400" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your project doesn’t have to be huge. It just has to have a reason.&lt;br&gt;
If it runs, if you can explain it, and if you can improve it — that counts.&lt;/p&gt;

&lt;p&gt;Three files can become a job interview.&lt;br&gt;
A GitHub Page can become your first portfolio piece.&lt;br&gt;
One small idea can start everything.&lt;/p&gt;

&lt;p&gt;Build it small.&lt;br&gt;
Learn from it honestly.&lt;br&gt;
Deploy it anyway.&lt;br&gt;
Let it represent you — until you build the next one.&lt;/p&gt;

&lt;p&gt;That’s how you sell your skills without lying — and without feeling like a fraud.&lt;/p&gt;




</description>
      <category>portfolio</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Job hunting is poopie</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Thu, 20 Nov 2025 20:53:37 +0000</pubDate>
      <link>https://forem.com/bradleymatera/what-it-feels-like-to-start-tech-at-33-and-get-ignored-3b07</link>
      <guid>https://forem.com/bradleymatera/what-it-feels-like-to-start-tech-at-33-and-get-ignored-3b07</guid>
      <description>&lt;h2&gt;
  
  
  Not a Success Story. Just the Truth About Trying.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zvwivyn8t2uin2yrs1b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zvwivyn8t2uin2yrs1b.gif" alt="overwhelmed" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did grow up around computers but i never took any AP computer science classes nor did i attend any robotics club. I spent most of my adult life doing work that had nothing to do with terminals, VS Code, or GitHub. I was a medic in the 82nd Airborne. I walked roofs with nail guns. I worked security at night. I dealt with overdoses and addiction when I worked case management. I cleaned cat cages at a rescue shelter for years. None of that pointed toward writing software for a living. And for most of my life, I didn’t think tech was even an option for someone like me.&lt;/p&gt;

&lt;p&gt;When I finally opened a terminal for the first time, it didn’t feel intimidating — but it also didn’t feel normal. Basic commands felt like learning a new language. Learning what a for loop was felt like being introduced to a logic system I had never used before. And learning React felt like someone pulled the rug halfway under me — just enough for me to stand but not enough to feel fully steady.&lt;/p&gt;

&lt;p&gt;My degree at Full Sail moved so fast that memory didn’t really stick. Each class lasted one month — then it was gone, and the next topic took its place. HTML, CSS, JavaScript, SQL, UX, Python, AWS basics, testing, deployment — all in separate months. I didn’t have time to master any one subject, but weirdly, momentum started forming. I didn’t remember everything, but repetition slowly built foundation. Not perfect, not deep — but enough.&lt;/p&gt;

&lt;p&gt;And something clicked anyway. Even when I didn’t remember the syntax — I still liked this work. I liked that you could build something real and click on it. I liked reading error logs and figuring out why something broke. I liked seeing things appear in the browser and knowing I made that happen. It felt like work where effort actually turned into skill. I never had that feeling before. Not in construction. Not in security. Not even in the army. This field felt different. It felt like I finally found work that didn’t just drain me — it built me.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding Where My Knowledge Really Sits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6n4s3e2dx60dp1nltwxz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6n4s3e2dx60dp1nltwxz.gif" alt="thinking" width="500" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I graduated one month ago. I completed dozens of projects across school and landed a 12-week AWS internship at Amazon. Inside that short window, I passed two AWS certifications — Solutions Architect Associate and AI Practitioner — and operated inside real cloud environments without shortcuts. I had to study, read documentation, and follow real runbooks like everyone else. No one spoon-fed me anything. That experience helped me more than any class.&lt;/p&gt;

&lt;p&gt;But graduating didn’t mean everything suddenly fell into place. What I really have right now is &lt;em&gt;practical skill, but not perfect foundations&lt;/em&gt;. I can read JavaScript, React, HTML, CSS, and Python code and understand what it’s doing. I can follow data through a full stack app once it exists. I can deploy things to AWS or static hosting. I can debug real errors using logs, terminal output, CloudWatch dashboards, DevTools, and trial and error. I can get things working &lt;em&gt;eventually&lt;/em&gt; — not because I know everything, but because I don’t stop until I find the right pattern.&lt;/p&gt;

&lt;p&gt;What I can’t do yet is whiteboard complex algorithms from memory. I don’t claim to be able to solve medium LeetCode under pressure. But I can read code, understand it, adjust it, and ship working systems. I feel like I am exactly in the middle — past beginner but not “senior” anything. And honestly, that middle space is probably where most people actually live — even if social media makes it seem like everyone can build full systems straight from their head.&lt;/p&gt;

&lt;p&gt;There is a huge difference between writing code from nothing and steering a working system forward. Right now, I am better at the second one. And at least that gives me direction.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I’ve Learned About the Tech Industry So Far
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kkjtqd939ymm45r8y5d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kkjtqd939ymm45r8y5d.gif" alt="industry-challenge" width="650" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Hard Work Does Not Guarantee Anything&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgl5n7mr3ytd3ey18592h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgl5n7mr3ytd3ey18592h.gif" alt="trying" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the past year, I have applied to more companies than I can count. Startups. Big tech. Small dev shops. Contract roles. “Entry-level” positions requiring five years of experience. Recruiter submissions. LinkedIn postings. Indeed. Company portals. Referrals. Networking messages. All of it. Most applications go silent. Some bounce back instantly with automated rejections. A few move forward, then disappear entirely. You keep trying. You keep submitting. But eventually you start to realize — &lt;strong&gt;there is no guaranteed point where effort turns into opportunity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some roles were clearly fake — posted but already filled so the company could meet some hiring policy. Some roles were meant for internal candidates but listed publicly for legal reasons. Some wanted someone’s nephew. Some wanted data structure mastery as a barrier even when the role didn’t require it. Some just wanted content writers, not engineers. You start realizing that “job hunting” in tech is really just trying to figure out which pathways are actually real and which are dead ends before you waste months chasing them.&lt;/p&gt;

&lt;p&gt;That doesn’t mean giving up. It means being honest about what you’re actually facing. This field rewards persistence — but not always immediately &lt;em&gt;and not always the way you’d expect&lt;/em&gt;. Sometimes skill gets ignored. Sometimes impressive projects don’t mean anything. Sometimes it has nothing to do with you at all.&lt;/p&gt;

&lt;p&gt;It took me time to accept that working hard does not guarantee anything — but &lt;em&gt;not working hard guarantees nothing&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. Tech Is Merit-Based — and Also Not Merit-Based at All&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo81glot1foe51thf6wkq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo81glot1foe51thf6wkq.gif" alt="duality" width="256" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;two systems&lt;/strong&gt; running at the same time, and both are real:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;What It Rewards&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Classic Merit System&lt;/td&gt;
&lt;td&gt;People with very strong foundations — DSA, algorithms, system design, math — especially those who can explain logic cleanly without references. These are the top ~1–5% who can operate with abstract thinking. That group will &lt;em&gt;always&lt;/em&gt; find work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-World System&lt;/td&gt;
&lt;td&gt;People with connections. People who know someone inside. People who get referred. People who are already trusted. Sometimes, people who just happen to be in the right place at the right time.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most new grads probably do &lt;strong&gt;not&lt;/strong&gt; have the first category mastered — especially if their education moved fast like mine. You come out able to build things and deploy things — but maybe not solve everything on a whiteboard from scratch. That doesn’t make you bad — it just puts you in category two, where getting seen usually requires personal connections, projects people can click on, or someone vouching for your ability.&lt;/p&gt;

&lt;p&gt;People online often pretend it’s all merit-based or all nepotism — but that’s just online posturing. The truth is quieter:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;it’s both. And it depends which door you’re trying to walk through.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. Connections Change Everything — And They Don’t Come Easy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddwd73300mawddy8fu7y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddwd73300mawddy8fu7y.gif" alt="connections" width="330" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I was younger, I thought “knowing people” meant cheating. Now I understand that in industries flooded with applicants, referrals are the only way a lot of hiring even functions. It isn’t always malicious — sometimes companies literally cannot review thousands of applications fairly. That means conversations become more valuable than resumes. When engineers vouch for you, momentum starts. When no one knows you, you often stay invisible, even if your work is good.&lt;/p&gt;

&lt;p&gt;That doesn’t mean people get hired for doing nothing. It means most people need someone to open the door first so their work can actually be seen. And that is difficult when you are coming from outside the field. It takes longer. It takes more follow-ups. More messages. More rejection. More willingness to reach out when every instinct tells you not to bother.&lt;/p&gt;

&lt;p&gt;Good work matters — but trust moves faster than GitHub links.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Notes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fap10ltjka02a9w5r7hjt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fap10ltjka02a9w5r7hjt.gif" alt="hopeful-again" width="500" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am not writing this as a success story or a lesson in perseverance. Right now, it just feels like I have come too far to walk away without at least finishing what I started. I spent years learning how to build things that actually work — not perfect, but real. I proved I can build and deploy working systems. That should matter somewhere, but so far it hasn’t moved anything.&lt;/p&gt;

&lt;p&gt;I know the system is uneven. I know luck and connections move people ahead faster than effort. I know some roles are already filled before the posting even goes live. I know real skill often never gets seen. And I know none of that changes just because I work hard.&lt;/p&gt;

&lt;p&gt;So I am not saying “I’ll make it.” I do not know that. I’m saying I am still here because right now I don’t see a better option. I keep building because stopping would make everything I already did feel pointless. I keep learning because forgetting what I’ve learned would make the past few years feel wasted. I keep trying because I don’t know what else someone in my position is supposed to do.&lt;/p&gt;

&lt;p&gt;I am not looking for motivation. I am looking for an opening.&lt;/p&gt;

&lt;p&gt;Until one shows up, I’ll keep moving — not because I believe in the system, but because turning everything off would feel worse than trying again tomorrow.&lt;/p&gt;

&lt;p&gt;-Thank you for reading my vent&lt;/p&gt;

&lt;p&gt;PS. i know this sounds like an edgy emo kid rant, thats cause im an edgy emo kid at heart.&lt;/p&gt;

</description>
      <category>hiring</category>
      <category>career</category>
      <category>whoishiring</category>
      <category>leadership</category>
    </item>
    <item>
      <title>My Real AI Development Setup</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 17:11:27 +0000</pubDate>
      <link>https://forem.com/bradleymatera/how-i-actually-use-agentic-ai-tools-in-vs-code-webflow-and-aws-2kad</link>
      <guid>https://forem.com/bradleymatera/how-i-actually-use-agentic-ai-tools-in-vs-code-webflow-and-aws-2kad</guid>
      <description>&lt;h1&gt;
  
  
  My Actual AI Development Setup
&lt;/h1&gt;

&lt;p&gt;Using AI tools has become part of my normal workflow because they help me stay productive when I get stuck. None of the tools I use solve everything on their own, and each one fills a different gap. VS Code is the main place where most hands-on editing happens, but only one of the agent tools actually runs inside it. Everything else is opened separately depending on what the project needs. This setup works because the tools support the work rather than replace it, and it allows progress even when the project moves into areas that are unfamiliar.&lt;/p&gt;




&lt;h2&gt;
  
  
  How VS Code Fits Into the Setup
&lt;/h2&gt;

&lt;p&gt;VS Code is the editor where almost all file editing takes place. Cline is the extension that actually interacts with the environment. It can read the project tree, open files, modify them, run commands, react to errors, and propose patches that fit the structure of the repo. Having an agent inside the editor turns small tasks into manageable steps instead of long guesswork loops. It does not handle everything, but it reduces friction when a project involves a lot of moving parts.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Ollama and Qwen Help With Daily Coding
&lt;/h2&gt;

&lt;p&gt;Ollama runs locally and hosts the models that handle most of the routine reasoning. Qwen models run quickly, do not require tokens, and work without an internet connection, which makes them useful for day-to-day coding. Local models like Qwen help clean up components, fix TypeScript or JavaScript issues, reorganize files, adjust imports, and write small helpers. Since they run inside Cline, they can read the actual project structure and respond based on the files instead of guessing. This makes local models useful for steady incremental progress.&lt;/p&gt;




&lt;h2&gt;
  
  
  When the Workflow Switches to Claude Models
&lt;/h2&gt;

&lt;p&gt;Sometimes local models run into problems that require better reasoning or a clearer explanation. In those cases, the model used by Cline gets switched to a Claude model. Claude is useful for situations when logic spans multiple files, when a messy section needs to be rewritten, when build problems become confusing, or when WebGPU code needs a deeper breakdown. Claude handles larger context better, and Cline carries out the edits. This combination works well when the project moves beyond small isolated fixes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Cursor Fits In
&lt;/h2&gt;

&lt;p&gt;Cursor is a separate AI IDE and it is not part of the VS Code setup. It gets opened when the project needs larger structural adjustments. Cursor helps when a React codebase becomes disorganized, when a feature touches too many files to fix in small patches, or when a Webflow-related feature needs cleaner output. It is not used constantly. It is used when the shape of the project needs to be fixed rather than the individual lines of code.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Kiro Fits Into AWS Work
&lt;/h2&gt;

&lt;p&gt;Kiro is another standalone AI IDE and only becomes relevant when a project involves AWS. It handles tasks like diagnosing IAM issues, adjusting S3 bucket policies, checking CloudWatch logs, fixing AWS CLI errors, or reviewing configuration problems. Kiro reacts to real AWS output instead of generating architecture from scratch, which makes it helpful when deployments hit AWS-specific problems. It stays closed unless the work involves infrastructure tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Copilot’s Small Role in the Workflow
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot runs quietly in the background. It handles small things like JSX completion, basic patterns, tiny helper functions, or quick loops. It does not make architectural decisions and it does not interact with the larger structure of the project. It operates like autocomplete. It saves time on typing but does not influence bigger parts of the workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Markdown Files Matter
&lt;/h2&gt;

&lt;p&gt;Markdown files act as the stable memory that all tools rely on. They hold the architecture notes, naming conventions, TODO lists, route summaries, design notes, and deployment instructions. These files get opened before making changes so agents understand the direction of the project, and they get updated when large edits are made. This helps avoid drift, keeps everything aligned, and makes sure the project maintains a clear structure even when multiple tools are involved.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Real Session Feels Like
&lt;/h2&gt;

&lt;p&gt;A normal session begins by opening VS Code with Cline running and a local model active through Ollama. A small task gets described, Cline inspects the relevant files, and it proposes changes. Those changes get reviewed and either accepted or rejected. The app is run to see what happens. Errors show up, the error output gets pasted into the tool, and Cline attempts to fix the issue. If the reasoning needs to be stronger, Claude is switched in. Once everything works locally, the work is committed and pushed. When deployment breaks, debugging happens with logs, browser tools, or AWS dashboards. If AWS becomes the blocker, Kiro is opened to diagnose the issue.&lt;/p&gt;

&lt;p&gt;This loop repeats until the feature is complete. The setup does not automate the process, but it reduces the amount of time spent hunting for solutions in the dark. It keeps the project moving forward even when knowledge gaps show up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Notes
&lt;/h2&gt;

&lt;p&gt;The mix of tools in this setup is not about trying to appear advanced or creating an automated pipeline. It is simply a practical way to keep working through projects, especially during parts that would normally slow everything down. Each tool handles a specific type of problem, and switching between them depending on the situation makes it easier to finish features and learn at the same time. The tools do not replace development. They support it so progress continues even when the work gets complicated.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Launch AWS Stacks for Free — And What Happens When the Free Tier Ends</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 15:58:55 +0000</pubDate>
      <link>https://forem.com/bradleymatera/how-to-launch-aws-stacks-for-free-and-what-happens-when-the-free-tier-ends-41of</link>
      <guid>https://forem.com/bradleymatera/how-to-launch-aws-stacks-for-free-and-what-happens-when-the-free-tier-ends-41of</guid>
      <description>&lt;h2&gt;
  
  
  An honest guide to running cloud infrastructure without surprise bills
&lt;/h2&gt;

&lt;p&gt;When I started building projects that hit the cloud, one of the biggest doubts was: “Can I really launch this stuff for free?” The short answer: yes, you can launch on AWS for free — or at least extremely low cost — but the longer and more honest answer is that you need to understand exactly how the free tier works, what the limits are, and when you’ll cross into paying territory. This post walks through how I spin up full stacks on AWS, what free means in practice, where the hidden traps are, and how much things cost when the free buffer disappears.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the AWS Free Tier
&lt;/h2&gt;

&lt;p&gt;When you sign up for AWS as a new account, you get access to a Free Tier. According to AWS:&lt;br&gt;&lt;br&gt;
“Gain free, hands-on experience … with select services” as part of the Free Tier.&lt;/p&gt;

&lt;p&gt;The Free Tier breaks down into three categories:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. 12-Month Free Tier&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many core services (like EC2 micro instances, RDS micro DBs, S3 storage) are free for up to &lt;strong&gt;12 months&lt;/strong&gt; from account creation, within certain usage limits.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Always Free&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Some services or usage levels remain free even after the 12 months, but with limited quotas (Lambda requests, DynamoDB storage, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Short-Term Trials&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Occasionally specific services get temporary trials.&lt;/p&gt;

&lt;p&gt;One of the biggest parts of the Free Tier: 750 hours/month of a &lt;strong&gt;t2.micro or t3.micro EC2 instance&lt;/strong&gt; (enough to run 1 instance 24/7) during the first 12 months.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Use It To Launch a Stack
&lt;/h2&gt;

&lt;p&gt;Here’s how I actually spin up a full AWS stack for free or very close to free.&lt;/p&gt;

&lt;p&gt;I start by defining what I actually need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a micro EC2 instance (or Lambda + API Gateway)&lt;/li&gt;
&lt;li&gt;an S3 bucket for static assets&lt;/li&gt;
&lt;li&gt;maybe a small RDS micro DB&lt;/li&gt;
&lt;li&gt;IAM roles&lt;/li&gt;
&lt;li&gt;CloudWatch logs&lt;/li&gt;
&lt;li&gt;security groups and basic networking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I check whether each part is Free Tier eligible, and whether I’m still within the 12-month window.&lt;/p&gt;

&lt;p&gt;I deploy the smallest possible instance sizes, choose the cheapest region, and I aggressively clean up anything I’m not using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;terminate EC2 instances
&lt;/li&gt;
&lt;li&gt;delete EBS volumes
&lt;/li&gt;
&lt;li&gt;empty and delete buckets
&lt;/li&gt;
&lt;li&gt;remove unused IPs
&lt;/li&gt;
&lt;li&gt;remove snapshots
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free is not automatic. If you forget resources, they run up costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hidden Traps: How “Free” Becomes “I Just Got Billed”
&lt;/h2&gt;

&lt;p&gt;I’ve been hit by random charges for dumb reasons. These are the traps most people fall into:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Idle EC2 instances / leftover volumes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Free Tier covers &lt;em&gt;compute hours&lt;/em&gt;, but &lt;strong&gt;EBS storage still costs money&lt;/strong&gt; if you leave volumes behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Data transfer, snapshots, cross-region mistakes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Free Tier doesn’t usually cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inter-region traffic
&lt;/li&gt;
&lt;li&gt;snapshot storage
&lt;/li&gt;
&lt;li&gt;elastic IPs not attached to running instances
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Multi-region deployments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Free Tier quotas apply per account, &lt;em&gt;not&lt;/em&gt; per region.&lt;br&gt;&lt;br&gt;
If you deploy in two regions, you burn double the hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;CloudWatch logs piling up&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Logs accumulate endlessly unless you set retention rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Free doesn’t mean forever&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once your 12 months run out, you pay normal pricing across the board.&lt;/p&gt;

&lt;p&gt;If you don’t monitor, “free” can turn into a surprise $50–200 bill very quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Actual Cost Breakdown (Hourly, Daily, Weekly, Monthly, Yearly)
&lt;/h2&gt;

&lt;p&gt;Below are realistic numbers based on common AWS services.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;EC2 t2.micro or t3.micro (after free tier ends)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;On-demand cost in us-east-1 is around &lt;strong&gt;$0.0116/hr&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hourly: ~$0.0116
&lt;/li&gt;
&lt;li&gt;Daily: ~$0.28
&lt;/li&gt;
&lt;li&gt;Weekly: ~$1.96
&lt;/li&gt;
&lt;li&gt;Monthly: ~$8.40
&lt;/li&gt;
&lt;li&gt;Year: ~$102
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two forgotten micro instances?&lt;br&gt;&lt;br&gt;
Double it: ~$200/year.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;S3 Standard Storage (after free tier 5GB)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;S3 Standard costs about &lt;strong&gt;$0.023/GB/mo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example: 50GB stored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50 × $0.023 = &lt;strong&gt;$1.15/month&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Yearly: $13.80
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But PUT/GET requests and transfer can add to that.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;CloudWatch Logs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;CloudWatch has free ingestion + free Live Tail minutes, but if you exceed:&lt;/p&gt;

&lt;p&gt;Example: 18,200 billable minutes&lt;br&gt;&lt;br&gt;
→ 18,200 × $0.01 = &lt;strong&gt;$182/month&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
just for log viewing.&lt;/p&gt;

&lt;p&gt;This happens fast if you don’t set retention.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;If you’re disciplined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$0/month&lt;/strong&gt; is totally realistic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you exceed limits a little:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$10–$20/month&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you forget resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$50–$200/month&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you forget &lt;em&gt;everything&lt;/em&gt; for a year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$600–$2,400&lt;/strong&gt; depending on what’s running.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  My Workflow for Keeping AWS Actually Free
&lt;/h2&gt;

&lt;p&gt;This is how I avoid bills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch the minimum necessary resources
&lt;/li&gt;
&lt;li&gt;Use micro instances only
&lt;/li&gt;
&lt;li&gt;Prefer S3 + CloudFront static hosting
&lt;/li&gt;
&lt;li&gt;Turn off or delete unused resources immediately
&lt;/li&gt;
&lt;li&gt;Add deletion-lifecycle policies for logs
&lt;/li&gt;
&lt;li&gt;Add AWS Budgets alerts (I set $5/month alarms)
&lt;/li&gt;
&lt;li&gt;Use tools like Lambda and DynamoDB which have Always Free quotas
&lt;/li&gt;
&lt;li&gt;Tag resources so I know what everything is for
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best rule I use is simple:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;If I’m not actively using it, I delete it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changes After the Free Tier Ends
&lt;/h2&gt;

&lt;p&gt;After the 12-month period:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 charges fully
&lt;/li&gt;
&lt;li&gt;RDS charges fully
&lt;/li&gt;
&lt;li&gt;S3 beyond Always Free charges fully
&lt;/li&gt;
&lt;li&gt;CloudWatch logs charge based on storage and ingestion
&lt;/li&gt;
&lt;li&gt;AWS will not shut down anything automatically
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You graduate from the sandbox into pay-as-you-go.&lt;/p&gt;

&lt;p&gt;It’s still powerful.&lt;br&gt;&lt;br&gt;
It’s just not free anymore.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Launching on AWS for free is absolutely possible — I’ve done it countless times. But you need to treat “free” as a strategic window, not a permanent state. The moment you stop watching usage, you can rack up very real bills.&lt;/p&gt;

&lt;p&gt;For prototypes, portfolios, student work, and small tools: AWS Free Tier is perfect.&lt;/p&gt;

&lt;p&gt;For production without cost controls: it becomes expensive fast.&lt;/p&gt;

&lt;p&gt;Stay curious. Watch your resources. And always check your bill before AWS checks it for you.&lt;/p&gt;

&lt;p&gt;— &lt;strong&gt;Bradley Matera&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
(bradleysgatsbyblog.netlify.app)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How I Actually Build Full End To End Projects Using AI</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 15:37:08 +0000</pubDate>
      <link>https://forem.com/bradleymatera/how-i-actually-build-full-end-to-end-projects-using-ai-42do</link>
      <guid>https://forem.com/bradleymatera/how-i-actually-build-full-end-to-end-projects-using-ai-42do</guid>
      <description>&lt;p&gt;I build a lot of projects. Full stacks, dashboards, demos, WebGPU stuff, AWS deployments, Docker setups, GitHub Actions pipelines, authentication flows, routing, UI components, all of it. On paper it looks like I am some senior engineer cranking out production apps. I am not. What I am is someone who learned how to use AI extremely well, who understands enough about web development to steer a project, and who has built so many things that the repetition turned into a weird practical skillset. This is how I actually build things end to end with my current knowledge. No hype. No fake humility. Just what really happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where My Knowledge Actually Sits
&lt;/h2&gt;

&lt;p&gt;I have a B.S. in Web Development from Full Sail University. That program moves fast, one class a month and then it is gone. We switched topics constantly and you do not really get the luxury of living inside one subject long enough for everything to sink in.&lt;/p&gt;

&lt;p&gt;What I got from school was basic HTML, CSS, and JavaScript, some React, some Python and SQL, some UX and layout fundamentals, some cloud concepts, some testing ideas. Enough to not be lost, but not enough to feel like a classic engineer.&lt;/p&gt;

&lt;p&gt;On the flip side, things I do not have include any real data structures background, no algorithms training, no serious math foundation, no whiteboard experience, and I absolutely cannot sit down and write a full solution from a blank file with no references.&lt;/p&gt;

&lt;p&gt;What I can do is read JavaScript, React, HTML, CSS, and Python code and understand what it is doing, follow how a full stack app behaves once it exists, describe exactly what I want in plain language, steer AI toward what I am actually trying to build, debug broken systems until they behave, and deploy almost anything if you give me time, logs, and a terminal.&lt;/p&gt;

&lt;p&gt;My AWS internship helped a lot because it made me comfortable with AWS consoles, the CLI, EC2, S3, RDS, IAM basics, CloudWatch dashboards and alarms, and runbooks and troubleshooting workflows. It did not turn me into a principal cloud engineer, but AWS stopped feeling like some sacred scary thing and turned into a normal toolbox. That is my actual starting point. Everything else comes from building and breaking things in public.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Start Projects (Even When I Don’t Know Enough)
&lt;/h2&gt;

&lt;p&gt;Most real engineers can open an empty folder, run npm init, and start coding from their head. I cannot. So I start in a different way.&lt;/p&gt;

&lt;p&gt;I describe the project like I am talking to a friend. I do not open with architecture or design patterns. I open with vibes and behavior.&lt;/p&gt;

&lt;p&gt;My first messages to AI look like:&lt;/p&gt;

&lt;p&gt;“I want a full stack app where users can sign up, log in, and post stuff to a feed,”&lt;br&gt;&lt;br&gt;
“I want a clean WebGPU page that renders a triangle and maybe a cube I can flip between,”&lt;br&gt;&lt;br&gt;
“I want a simple Node backend that handles authentication and a React front end that consumes it,”&lt;br&gt;&lt;br&gt;
“I want a static portfolio with a blog and project cards that link to my real work.”&lt;/p&gt;

&lt;p&gt;I never start with words like microservices or hexagonal architecture. I talk like a normal person and AI fills in the technical details. I correct it if it goes too wild. The point is that I anchor the idea in behavior, not implementation.&lt;/p&gt;

&lt;p&gt;After the idea is clear, I let AI propose the first structure. I ask things like “show me the folder structure you would use for this,” or “where would you put pages, components, API routes, and config,” or “which files should I create first.” AI gives me a tree. Sometimes it's bloated and sometimes it’s too minimal. I tweak it until it feels like something I can actually navigate. I am not optimizing for textbook best practices. I am optimizing for “will my brain understand this when I come back in three days.”&lt;/p&gt;

&lt;p&gt;Then I ask for the first file instead of the whole app. I never say “write the full app.” I say things like “give me the entry file and a single route that returns hello world,” or “give me a React page that renders a placeholder layout,” or “give me the WebGPU init function that just clears the screen to a color.”&lt;/p&gt;

&lt;p&gt;Then I paste it in, install dependencies, and try to run it. It almost never works the first time. That is fine. I send AI the error and we start the real work.&lt;/p&gt;

&lt;p&gt;From there I let the project teach me what it needs next. If I need authentication, I ask for that. If I need a Dockerfile, I ask for that. If I need a GitHub Actions workflow, I ask for that. If the layout is ugly, I fix it. I do not sit down and architect everything up front. I build until there is friction and then I deal with the friction. The system slowly reveals its shape over time. I do not architect from theory. I architect from pain and repetition.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AI Helps and Where It Breaks Everything
&lt;/h2&gt;

&lt;p&gt;AI is basically my pair programmer, except it has no idea where any of the files really live and it lies sometimes.&lt;/p&gt;

&lt;p&gt;It is good at generating boilerplate quickly, filling in syntax I cannot remember, wiring up simple React components, writing repetitive CRUD routes, creating example tests once I describe what needs to be tested, translating my plain language idea into a first-pass implementation, and even giving me rough AWS diagrams or CloudFormation ideas based on a description.&lt;/p&gt;

&lt;p&gt;But it is terrible at remembering my exact file paths, sticking to one pattern instead of switching styles mid project, generating security-safe code unless I constantly force it to, not hallucinating older versions of APIs or tools, randomly inventing config options that do not exist, messing with service workers and caches without warning, and it absolutely cannot handle WebGPU unless I spoon-feed it context from my own files.&lt;/p&gt;

&lt;p&gt;My workflow always ends up looking like this:&lt;/p&gt;

&lt;p&gt;I ask for a piece of code, AI gives me version one, I run it, something breaks, I paste the error back, AI adjusts, I run it again, something else breaks or behaves weird, and this repeats until it finally works.&lt;/p&gt;

&lt;p&gt;People on social media love to claim “AI is doing everything,” but that completely ignores the part where I am the one deciding when the answer is nonsense, gluing all the pieces together, tracking the overall shape, dealing with the real world behavior, and connecting project to deploy instead of just code to code. AI is the engine. I am the driver and the mechanic.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Bring That AI Cannot
&lt;/h2&gt;

&lt;p&gt;There is a lot AI cannot see and cannot touch, and that is where I come in.&lt;/p&gt;

&lt;p&gt;My biggest strength is that I understand the system once it exists. I can read through a codebase, trace a request from entry to response, follow state through the frontend, understand what the API is doing, understand where the data goes, and make sense of how the folders and files map to the mental model of the app.&lt;/p&gt;

&lt;p&gt;I debug in the real environment, which AI cannot do. I open DevTools, inspect the network tab, check request and response bodies, read console logs, tail logs in Docker, look at GitHub Actions logs and artifacts, curl endpoints and diff them against local, inspect service workers, clear caches, and poke at CDN behavior. AI only sees what I paste in. I see absolutely everything.&lt;/p&gt;

&lt;p&gt;I also make the real decisions. AI does not know that I am deploying to GitHub Pages or that I want a static export instead of server rendering or that I want to keep the stack simple instead of over engineered. I know what I am aiming for. That means I choose when to flatten the file structure, when to split a file, when something needs Docker, when to keep state management simple, when to use Next.js versus plain React, and what makes the project maintainable for me. AI outputs code, but I define the boundaries and the shape.&lt;/p&gt;

&lt;p&gt;And when it comes time to actually ship a project, AI is nowhere near helpful. AI cannot log into AWS. AI cannot configure IAM. AI cannot fix DNS. AI cannot deal with real SSL errors. I am the one setting environment variables, mapping domains, fixing path issues in static exports, clearing stale caches and stuck service workers, and rerunning builds. Deployment is not “hit the AI button.” Deployment is me in a terminal, a dashboard, and a browser making everything behave.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the AWS Internship Changed For Me
&lt;/h2&gt;

&lt;p&gt;The AWS internship changed a lot for me because it showed me that I can survive in real technical environments.&lt;/p&gt;

&lt;p&gt;I got two certifications, AWS Solutions Architect Associate and AWS AI Practitioner, during a 12-week internship window, both passed by week 7 without AI. It was real studying and real labs.&lt;/p&gt;

&lt;p&gt;That gave me comfort navigating AWS consoles and docs, understanding alarms, runbooks, and escalation paths, and familiarity with EC2, S3, RDS, IAM, and CloudWatch in actual workflows. I got a sense of what “normal” looks like when systems are healthy and how big companies design reference architectures.&lt;/p&gt;

&lt;p&gt;When you mix that with my AI-heavy building style, you get a weird combination where AI writes a lot of code, my AWS background keeps me from being scared of the infrastructure, and my debugging brain glues it all together. I am not walking around acting like a principal architect, but I am also not lost when someone says “we need to deploy this to AWS.”&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Cycle Behind Every Project I Build
&lt;/h2&gt;

&lt;p&gt;If you zoom out and look at every project I do, the pattern is simple even if it is messy.&lt;/p&gt;

&lt;p&gt;I describe what I want in plain language, AI gives me a structure and some starter files, I wire it up and try to run it, it fails, I debug with AI and my own eyes, it eventually works locally, I set up a build and deploy target, the deploy fails in some new way, I debug that using logs and DevTools and trial and error, it finally works in production, I polish the UI and text so it looks intentional, I document it enough that people can understand what it does, and then I move on to the next idea.&lt;/p&gt;

&lt;p&gt;There is no magic. Just a lot of cycles.&lt;/p&gt;




&lt;h2&gt;
  
  
  I Don’t Start With Structure — I Grow Into It
&lt;/h2&gt;

&lt;p&gt;I do not start with structure the way traditional engineers do. I grow into it. I start with how the product should feel and a couple behaviors I care about, and then I let the system evolve until the structure becomes obvious.&lt;/p&gt;

&lt;p&gt;The project keeps telling me when a page is doing too much, when logic is duplicated, when a folder is chaotic, or when a route belongs somewhere else.&lt;/p&gt;

&lt;p&gt;Structure is not planned up front. It emerges from friction. Pain is the signal.&lt;/p&gt;

&lt;p&gt;If something is hard to find, I move it.&lt;br&gt;&lt;br&gt;
If something breaks too often, I isolate it.&lt;br&gt;&lt;br&gt;
If something is confusing to name, I rethink what it actually is.  &lt;/p&gt;

&lt;p&gt;It is slower and messier than perfect architecture, but it fits how my brain works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging Is the Education
&lt;/h2&gt;

&lt;p&gt;Debugging is not a side effect for me. It is the education.&lt;/p&gt;

&lt;p&gt;I do not learn by memorizing theory. I learn because something breaks. A runtime error, a layout issue, a failed deploy, a permissions problem, a cache bug, undefined data, missing files, broken WebGPU behavior — these are what force me to form real understanding.&lt;/p&gt;

&lt;p&gt;When something is broken, suddenly I have an actual question to chase.&lt;/p&gt;

&lt;p&gt;Why is this undefined here but not there?&lt;br&gt;&lt;br&gt;
Why is this page loading old assets?&lt;br&gt;&lt;br&gt;
Why does this route work locally but 404 in production?&lt;br&gt;&lt;br&gt;
Why does this WebGPU demo run on Chrome but not Safari?&lt;/p&gt;

&lt;p&gt;Chasing these questions is what makes knowledge stick.&lt;/p&gt;




&lt;h2&gt;
  
  
  How My Background Shapes This Whole Approach
&lt;/h2&gt;

&lt;p&gt;My background as a medic in the 82nd Airborne plays into this too.&lt;/p&gt;

&lt;p&gt;In that world you rarely get perfect information. You get symptoms, pressure, and a small window to act. You stabilize, triage, move, reassess, and repeat.&lt;/p&gt;

&lt;p&gt;Web projects obviously are not life or death, but the mindset carries over. I do not freeze because I don’t know everything. I move based on what I can see: logs, browser errors, CLI output, network behavior, AWS console states, and feedback from the environment.&lt;/p&gt;

&lt;p&gt;AI works extremely well in this loop because it gives me something to react to fast. I take that and push the system forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This All Adds Up To
&lt;/h2&gt;

&lt;p&gt;All of this, when you strip away the noise, adds up to real skills.&lt;/p&gt;

&lt;p&gt;I have practical literacy in modern web stacks.&lt;br&gt;&lt;br&gt;
I can read and understand code I did not write.&lt;br&gt;&lt;br&gt;
I know how to steer AI toward working systems instead of random snippets.&lt;br&gt;&lt;br&gt;
I have real debugging experience from real deployments.&lt;br&gt;&lt;br&gt;
I have enough AWS experience to not drown in cloud workflows.&lt;br&gt;&lt;br&gt;
I am comfortable with containers, pipelines, and static hosting.&lt;br&gt;&lt;br&gt;
And I have shipped a lot of projects that prove I am not just talking.&lt;/p&gt;

&lt;p&gt;Things I do not have include low-level systems programming knowledge, advanced algorithms, leetcode skills, or the ability to write everything from scratch without leaning on tools.&lt;/p&gt;

&lt;p&gt;What I do have is the ability to build real working systems — systems people can click on, systems that deploy cleanly, systems that are understandable, systems that&lt;br&gt;
 behave.&lt;/p&gt;

&lt;p&gt;If a company wants deep algorithmic knowledge, hardcore math, systems programming, or whiteboard-from-scratch engineering, that is not me.&lt;/p&gt;

&lt;p&gt;But if a company wants someone who can work inside an existing stack, understand the codebase, use AI as a multiplier, ship features end to end with support, debug weird real world behavior, and actually deploy things users can touch, that is where I fit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;AI is how I write a lot of my code. Debugging is how I learn. My AWS internship and my degree gave me enough of a foundation to not drown. My projects are where everything actually came together.&lt;/p&gt;

&lt;p&gt;I am not a textbook software engineer. I am a practical builder who uses AI heavily, learns through friction, and ships things anyway.&lt;/p&gt;

&lt;p&gt;You do not need perfect background or deep theory to build real systems. You need a problem, a tool, a feedback loop, and enough stubbornness to keep going until the thing in your head exists in the browser.&lt;/p&gt;

&lt;p&gt;That is how I work right now. Honestly.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>The Day I Learned How Confusing GitHub Pages Deployments Can Get</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 03:44:22 +0000</pubDate>
      <link>https://forem.com/bradleymatera/the-day-i-learned-how-confusing-github-pages-deployments-can-get-4ff9</link>
      <guid>https://forem.com/bradleymatera/the-day-i-learned-how-confusing-github-pages-deployments-can-get-4ff9</guid>
      <description>&lt;p&gt;I always thought GitHub Pages was simple. You build your project, push the static export, and the site updates. That is what the docs say and that is how everyone on Reddit and StackOverflow talks about it. So when my site refused to update and kept serving old HTML from some random folder I forgot existed, I figured I just messed up a command.&lt;/p&gt;

&lt;p&gt;Turns out this was one of those problems that teaches you way more about the platform than you ever wanted to know.&lt;/p&gt;

&lt;p&gt;This whole thing started because my repo had multiple deployments in it over time. I had old folders, old builds, old static exports, and GitHub Pages settings that I never checked after the very first time I set the repo up. It was the perfect storm of confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where things started breaking
&lt;/h2&gt;

&lt;p&gt;My project had gone through a few iterations. I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an older site that used a &lt;code&gt;/docs&lt;/code&gt; folder
&lt;/li&gt;
&lt;li&gt;a later version that output to &lt;code&gt;/dist&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;some leftover static files inside the root
&lt;/li&gt;
&lt;li&gt;GitHub Actions workflows I copied from older repos
&lt;/li&gt;
&lt;li&gt;Pages pointed at a folder I forgot even existed
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first none of this mattered because I was not rebuilding the repo often. But when I pushed a brand new version of the site, the Pages server kept pulling from that ancient &lt;code&gt;/docs&lt;/code&gt; folder instead of the new static export.&lt;/p&gt;

&lt;p&gt;I did not even remember creating &lt;code&gt;/docs&lt;/code&gt;. It was from a build system I used months before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptoms
&lt;/h2&gt;

&lt;p&gt;I would deploy and the site would show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;old CSS
&lt;/li&gt;
&lt;li&gt;old JavaScript
&lt;/li&gt;
&lt;li&gt;old HTML
&lt;/li&gt;
&lt;li&gt;broken layout
&lt;/li&gt;
&lt;li&gt;missing assets
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I checked the code and everything in my repo was up to date. The build artifact looked correct. The static export was correct. The workflow logs were clean.&lt;/p&gt;

&lt;p&gt;Meanwhile the live site looked like it was living three timelines behind my repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment I realized the issue
&lt;/h2&gt;

&lt;p&gt;At one point I opened GitHub Pages settings and it hit me immediately.&lt;/p&gt;

&lt;p&gt;The Pages source was set to:&lt;/p&gt;

&lt;p&gt;/docs&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;p&gt;/dist&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;p&gt;/build&lt;/p&gt;

&lt;p&gt;Not anything modern.&lt;/p&gt;

&lt;p&gt;Just the old folder I did not delete because I assumed it did not matter.&lt;/p&gt;

&lt;p&gt;That small detail caused the entire deployment to serve stale content. Pages was not reading my new build at all. It was faithfully serving whatever was in &lt;code&gt;/docs&lt;/code&gt; because I had told it to do that a long time ago and then forgot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning it up
&lt;/h2&gt;

&lt;p&gt;Once I figured that out, the fix was straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Delete the old &lt;code&gt;/docs&lt;/code&gt; folder completely.
&lt;/li&gt;
&lt;li&gt;Update the Pages deployment settings to point to the correct build output.
&lt;/li&gt;
&lt;li&gt;Clean the repo of leftover static files.
&lt;/li&gt;
&lt;li&gt;Commit a fresh static export from Bun or Next.js.
&lt;/li&gt;
&lt;li&gt;Trigger a clean GitHub Pages build.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second I deleted &lt;code&gt;/docs&lt;/code&gt; and pointed GitHub Pages to the actual build directory, everything snapped back to normal. The new layout loaded. The CSS updated. The site finally reflected the code I was actually writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the problem really taught me
&lt;/h2&gt;

&lt;p&gt;This was not a bug. It was user error plus how GitHub Pages is designed.&lt;/p&gt;

&lt;p&gt;Pages keeps serving whatever folder you told it to serve until you explicitly change it. It does not auto detect changes. It does not switch to a new build folder because it looks “more correct.” It sticks to the literal path you set.&lt;/p&gt;

&lt;p&gt;If you point Pages at &lt;code&gt;/docs&lt;/code&gt;, it will die on that hill until you fix it.&lt;/p&gt;

&lt;p&gt;That is both a feature and a trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to avoid this mess
&lt;/h2&gt;

&lt;p&gt;If your GitHub Pages site serves old content even though your build is correct, check this list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look at the Pages source folder.
&lt;/li&gt;
&lt;li&gt;Make sure your static export path matches that folder exactly.
&lt;/li&gt;
&lt;li&gt;Delete any old build folders you are not using.
&lt;/li&gt;
&lt;li&gt;Clean out orphaned HTML files in the root.
&lt;/li&gt;
&lt;li&gt;Make sure your workflow artifacts match your Pages directory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It takes five minutes to check, but if you forget how the repo was originally configured, you can lose hours trying to debug something that is not actually broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This taught me to treat deployment folders like infrastructure. They matter. They carry history. And if you do not clean them up, they can bite you months later when you least expect it.&lt;/p&gt;

&lt;p&gt;Now I check my Pages settings before every new repo upgrade. Not because I am paranoid, but because I now understand exactly how easy it is to break a Pages deployment by accident.&lt;/p&gt;

&lt;p&gt;And how annoying it is when GitHub is faithfully serving the wrong folder while you blame everything else.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>github</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Why I Rebuilt My WebGPU Triangle Demo From Scratch</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 03:41:55 +0000</pubDate>
      <link>https://forem.com/bradleymatera/rebuilding-my-webgpu-triangle-demo-after-realizing-i-couldnt-trust-the-code-anymore-47hk</link>
      <guid>https://forem.com/bradleymatera/rebuilding-my-webgpu-triangle-demo-after-realizing-i-couldnt-trust-the-code-anymore-47hk</guid>
      <description>&lt;p&gt;I built my Triangle Demo because I wanted a clean WebGPU study lab that made sense for how I learn. I originally forked a public WebGPU project that showed what was possible, and it gave me the push to start exploring how triangle rendering works. The original project was great, but it had a completely different purpose and long-term direction. What I wanted was something smaller, simpler, and focused only on the “hello triangle” and “textured cube” fundamentals.&lt;/p&gt;

&lt;p&gt;So instead of trying to bend something bigger into a study tool, I decided to rebuild my own version from the ground up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I needed my own structure
&lt;/h2&gt;

&lt;p&gt;Once I started exploring WebGPU, I realized I learn best when everything in a project is built by me, for me, and matches what I’m trying to study. I needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a minimal layout
&lt;/li&gt;
&lt;li&gt;no extra abstraction layers
&lt;/li&gt;
&lt;li&gt;short TypeScript files I could read in one sitting
&lt;/li&gt;
&lt;li&gt;a UI shell I understood
&lt;/li&gt;
&lt;li&gt;a direct mapping from code to canvas
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not because anything else was wrong, but because I wanted a space where every file existed for one reason — to help me understand the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building it clean
&lt;/h2&gt;

&lt;p&gt;I rebuilt the entire demo using tools I already use daily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16&lt;/strong&gt; for the UI
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NextUI&lt;/strong&gt; for the layout
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bun&lt;/strong&gt; for scripts and static exports
&lt;/li&gt;
&lt;li&gt;a single &lt;code&gt;/lib/webgpu&lt;/code&gt; folder that holds the render loop logic
&lt;/li&gt;
&lt;li&gt;compact TypeScript files for the triangle and cube demos
&lt;/li&gt;
&lt;li&gt;simple WGSL shaders with no extra complexity
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote my own initialization steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;request the adapter
&lt;/li&gt;
&lt;li&gt;request the device
&lt;/li&gt;
&lt;li&gt;configure the canvas
&lt;/li&gt;
&lt;li&gt;create buffers
&lt;/li&gt;
&lt;li&gt;load WGSL
&lt;/li&gt;
&lt;li&gt;submit draws
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With everything written by me from scratch, I could finally see exactly how each piece of the pipeline fits together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the rebuild gave me
&lt;/h2&gt;

&lt;p&gt;This rebuild wasn’t about fixing anything. It was about &lt;strong&gt;clarity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The new setup gives me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a WebGPU project I fully understand
&lt;/li&gt;
&lt;li&gt;a clean space to tweak shaders
&lt;/li&gt;
&lt;li&gt;a simple path to experiment with buffers, attributes, and color outputs
&lt;/li&gt;
&lt;li&gt;direct connection between the code and what I see on the canvas
&lt;/li&gt;
&lt;li&gt;a predictable structure I can keep expanding as I learn
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of navigating around a larger ecosystem with its own goals, I now have a focused lab designed specifically for learning WebGPU fundamentals. That alone made the rebuild worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Rebuilding this demo taught me more than I expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how the adapter/device negotiation really works
&lt;/li&gt;
&lt;li&gt;how pipelines, buffers, and shaders interact
&lt;/li&gt;
&lt;li&gt;how the render loop lives and breathes
&lt;/li&gt;
&lt;li&gt;how small changes in WGSL show up instantly on the canvas
&lt;/li&gt;
&lt;li&gt;how much easier learning is when the project matches your learning style
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project is not an engine. Not a framework. Not a competitor to anything.&lt;br&gt;&lt;br&gt;
It’s just a compact, personal study lab that helps me understand the basics without distractions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;The new Triangle Demo is clean, simple, and built entirely around learning. It keeps the triangle and the textured cube close at hand so I can focus on the actual WebGPU pipeline instead of navigating around unrelated features.&lt;/p&gt;

&lt;p&gt;It’s the version that finally made WebGPU click for me, and it gives me a foundation to keep experimenting as the API evolves.&lt;/p&gt;

</description>
      <category>webgpu</category>
      <category>webdev</category>
      <category>learning</category>
      <category>webgl</category>
    </item>
    <item>
      <title>The Day My Gatsby Nav Bar Made Me Question Reality</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Fri, 14 Nov 2025 03:38:57 +0000</pubDate>
      <link>https://forem.com/bradleymatera/the-day-my-gatsby-nav-bar-made-me-question-reality-1b0i</link>
      <guid>https://forem.com/bradleymatera/the-day-my-gatsby-nav-bar-made-me-question-reality-1b0i</guid>
      <description>&lt;p&gt;When I rebuilt my portfolio with Gatsby, I expected normal front end issues like spacing or a missing import. What I did not expect was the nav bar fighting me like it had a mind of its own. On desktop it looked fine at first glance. On mobile and certain screen sizes it turned into something between a glitch and a crime scene. The spacing was wrong, the padding drifted depending on the browser, and random items would shift like they were trying to escape the layout.&lt;/p&gt;

&lt;p&gt;At first I thought it was just sloppy CSS on my part, but the deeper I went the stranger it got. I fixed a margin on one breakpoint and it broke the layout on another. I aligned the logo and it pushed the entire menu off screen. It felt like fighting a ghost that would fix itself when I looked away and then break again when I touched literally anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first sign something was off
&lt;/h2&gt;

&lt;p&gt;I started noticing weird inconsistencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on desktop the nav looked clean
&lt;/li&gt;
&lt;li&gt;on iPhone it stacked wrong
&lt;/li&gt;
&lt;li&gt;on an Android tablet one of the links slipped down a few pixels
&lt;/li&gt;
&lt;li&gt;in Chrome responsive mode the entire thing bounced when resizing
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It made zero sense. The code was simple. Normal React components. Normal Gatsby layout. Normal styled components. But the nav acted like it was built out of jello.&lt;/p&gt;

&lt;p&gt;The worst part was that every person who looked at it gave different feedback. One guy said the spacing looked fine. Another sent me screenshots where the text looked like it was orbiting the logo. I had no idea which version was real.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first round of fixes that went nowhere
&lt;/h2&gt;

&lt;p&gt;I tried everything that made sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tightened padding
&lt;/li&gt;
&lt;li&gt;deleted margin rules
&lt;/li&gt;
&lt;li&gt;replaced flexbox with grid
&lt;/li&gt;
&lt;li&gt;replaced grid with flexbox again
&lt;/li&gt;
&lt;li&gt;normalized line height
&lt;/li&gt;
&lt;li&gt;used gap utilities
&lt;/li&gt;
&lt;li&gt;tried a CSS reset
&lt;/li&gt;
&lt;li&gt;rebuilt the component from scratch
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing solved it across every viewport. Every fix created a new problem. At one point the mobile menu icon drifted so far off the screen it looked like it was trying to run away from my codebase. I knew I was missing something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the root cause
&lt;/h2&gt;

&lt;p&gt;When I finally slowed down and treated the nav like an actual debugging problem instead of a quick CSS annoyance, I noticed the real issue: the structure of the component itself was messy. Not broken, just built in a way that made every style rule interfere with something else.&lt;/p&gt;

&lt;p&gt;Here were the real issues hiding underneath:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nested containers fighting for space
&lt;/li&gt;
&lt;li&gt;padding declared on both parent and child elements
&lt;/li&gt;
&lt;li&gt;flexbox alignment rules that canceled each other out
&lt;/li&gt;
&lt;li&gt;inconsistent font sizes causing invisible height changes
&lt;/li&gt;
&lt;li&gt;Gatsby theme defaults adding margins I never set
&lt;/li&gt;
&lt;li&gt;no global spacing system
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually these things seemed small but together they created a death spiral. There was no single source of truth. The nav bar was balancing itself on invisible calculations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The move that finally fixed everything
&lt;/h2&gt;

&lt;p&gt;Instead of duct taping the layout, I tore the whole thing down and rebuilt it with actual intent. Clean, simple, and predictable. I created a real spacing system. I gave the nav its own dedicated wrapper. I made sure no child element used padding unless it had a reason. And I kept the font sizes consistent so they did not secretly affect vertical alignment.&lt;/p&gt;

&lt;p&gt;The final structure looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"site-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Bradley Matera&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-links"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/projects"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Projects&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blogs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Blog&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Predictable. No unnecessary wrappers. No random spacing rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it worked
&lt;/h2&gt;

&lt;p&gt;Once the structure was clean, fixing the padding and alignment became normal work again. Responsive breakpoints were actually responsive. The mobile menu icon stayed where it was supposed to. The logo stopped drifting like it was floating in space.&lt;/p&gt;

&lt;p&gt;The layout finally behaved because nothing was fighting behind the scenes. No inherited margins. No double padding. No default Gatsby theme styles sneaking in. Everything had one clear job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;This entire mess taught me something simple:&lt;/p&gt;

&lt;p&gt;If the layout keeps breaking in random ways, the structure is probably wrong.&lt;/p&gt;

&lt;p&gt;Bad structure means every style rule becomes a gamble. You can fix a small thing and accidentally break something two components down because everything is chained together in ways you cannot see.&lt;/p&gt;

&lt;p&gt;Rebuilding the nav from scratch took less time than all the hours I spent firefighting random alignment bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Front end bugs are loud when the problem is small and quiet when the problem is structural. The loud stuff distracts you, but the quiet stuff hurts you.&lt;/p&gt;

&lt;p&gt;Once I cleaned up the skeleton of the component, the nav bar stopped acting haunted and started acting like a normal layout again.&lt;/p&gt;

&lt;p&gt;Sometimes the fix is not more CSS. Sometimes the fix is admitting the component needs to be rebuilt instead of patched.&lt;/p&gt;

&lt;p&gt;The new nav bar works everywhere and finally matches what I had in my head from the start.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>css</category>
      <category>tailwindcss</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
