<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bradley Matera</title>
    <description>The latest articles on DEV Community by Bradley Matera (@bradleymatera).</description>
    <link>https://dev.to/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>DEV Community: Bradley Matera</title>
      <link>https://dev.to/bradleymatera</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bradleymatera"/>
    <language>en</language>
    <item>
      <title>The Developer Pay Paradox: Are Junior Devs, Staff Engineers and Most Developers Over- or Under-paid?</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Sun, 10 May 2026 00:11:39 +0000</pubDate>
      <link>https://dev.to/bradleymatera/the-developer-pay-paradox-are-junior-devs-staff-engineers-and-most-developers-over-or-under-paid-oid</link>
      <guid>https://dev.to/bradleymatera/the-developer-pay-paradox-are-junior-devs-staff-engineers-and-most-developers-over-or-under-paid-oid</guid>
      <description>&lt;p&gt;The software salary debate usually turns into two groups yelling past each other. One side sees a junior developer making $90k or $100k and says tech is overpaid, while the other side sees a staff engineer keeping a giant system alive and says developers are underpaid compared to the money they help companies make. Both sides can be right depending on what kind of developer they are talking about, but the conversation usually falls apart because people use one job title to describe a bunch of completely different jobs.&lt;/p&gt;

&lt;p&gt;A junior dev building admin screens, a mid-level dev fixing production bugs, a staff engineer designing systems across teams, and an AI engineer working near model infrastructure are all technically “developers,” but they are not living in the same labor market. Some of that work is closer to skilled trade work with a keyboard, some of it is business automation work, some of it is infrastructure work, and some of it is high-scale technical decision-making where one bad call can cost a company a lot of money.&lt;/p&gt;

&lt;p&gt;I also do not like when developers act like software is the only hard work that exists. I have been a roofer, I was a medic in the Army, I worked private security, and I have done warehouse-style work loading roofing materials onto job sites, so it is hard for me to listen to someone act like fixing a React bug is automatically harder than climbing a roof, treating people under pressure, standing a post all night, or throwing heavy material around in bad weather for less than $20 an hour.&lt;/p&gt;

&lt;p&gt;At the same time, I do not like fake arguments that pretend software work is easy just because it is not physically brutal. A job can be easier on the body and still be valuable to a company, because the company is not paying based on how much your back hurts. The company is paying based on leverage, replacement cost, scalability, risk, and how close the work sits to money.&lt;/p&gt;

&lt;p&gt;That is the uncomfortable part. A junior developer can do work that looks simple, like fixing a form or wiring an API call, and still get paid more than someone doing harder physical work. That does not mean the junior developer is tougher or more useful to society. It means software sits inside a business model where one small piece of work can be reused, deployed, copied, and sold again and again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Real Question&lt;/li&gt;
&lt;li&gt;Why I’m Comparing These Jobs At All&lt;/li&gt;
&lt;li&gt;The Pay Numbers That Start The Argument&lt;/li&gt;
&lt;li&gt;Salary Comparison Graphic&lt;/li&gt;
&lt;li&gt;Why A Junior Dev Can Make More Than People Doing Harder Work&lt;/li&gt;
&lt;li&gt;Roofing Compared To Software Development&lt;/li&gt;
&lt;li&gt;Army Medic Work Compared To Software Development&lt;/li&gt;
&lt;li&gt;Private Security Compared To Software Development&lt;/li&gt;
&lt;li&gt;Warehouse And Manual Labor Compared To Software Development&lt;/li&gt;
&lt;li&gt;Teaching Compared To Software Development&lt;/li&gt;
&lt;li&gt;Do Most Developers Even Do DSA?&lt;/li&gt;
&lt;li&gt;Is Web Development Skilled Trade Work With A Keyboard?&lt;/li&gt;
&lt;li&gt;Are Junior Developers Overpaid?&lt;/li&gt;
&lt;li&gt;Are Mid-Level Developers Fairly Paid?&lt;/li&gt;
&lt;li&gt;Are Staff Engineers Overpaid?&lt;/li&gt;
&lt;li&gt;Where AI Changes The Pay Conversation&lt;/li&gt;
&lt;li&gt;The Three Different Developer Economies&lt;/li&gt;
&lt;li&gt;The Honest Answer&lt;/li&gt;
&lt;li&gt;Sources&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Real Question &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The real question is not “are developers overpaid?” because that question is too broad to be useful. A better question is, “overpaid compared to what, for what type of work, at what company, and under what business model?” Without those details, the argument turns into people comparing a junior web developer at a small company to a staff engineer at Google like those are the same thing.&lt;/p&gt;

&lt;p&gt;If we compare developers to the national median worker, developers are paid a lot. If we compare developers to roofers, EMTs, paramedics, security guards, warehouse workers, construction laborers, or teachers, software pay can look insane, especially when the software job is remote and the other job is physically dangerous, emotionally heavy, or socially necessary.&lt;/p&gt;

&lt;p&gt;If we compare developers to the money their work can generate, the answer changes. A developer working on a SaaS product, payment system, cloud platform, AI tool, ad system, internal dashboard, or automation flow can touch systems that scale to thousands, millions, or even billions of interactions. That kind of scale is why the salary conversation gets weird fast.&lt;/p&gt;

&lt;p&gt;That is the part people miss when they only compare effort. The labor market does not pay only based on pain, danger, stress, intelligence, or how noble the job is. It mostly pays based on leverage, scarcity, replacement cost, company margins, and how close the work is to revenue.&lt;/p&gt;

&lt;p&gt;This is why the argument feels morally wrong but economically explainable. A medic can do more socially important work than a junior web developer and still make less, because medical labor is often trapped inside public budgets, insurance structures, military pay tables, local contracts, or staffing models. Software work, especially inside product companies, can sit closer to high-margin revenue.&lt;/p&gt;

&lt;p&gt;That does not mean the market is fair. It means the market is not built around fairness. It is built around money, risk, supply, demand, and who has the power to negotiate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I’m Comparing These Jobs At All &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I am not comparing software to roofing, Army medic work, private security, warehouse-style labor, and case management because I think they are all the same job. I am comparing them because I have lived enough of those worlds to know that “hard work” and “high pay” are not the same thing, and pretending they are is one of the reasons the developer pay debate gets so fake.&lt;/p&gt;

&lt;p&gt;My own work history did not start in tech. I served as a Healthcare Specialist in the Army from 2011 to 2014, including training environments and combat-zone medical support, where the work involved triage, emergency response, medical readiness, supplies, physical exams, medication administration, and staying calm when things were unpredictable. After that, I worked roofing and roofing supply roles from 2017 to 2020, including general contracting, tear-off, shingle work, site prep, cleanup, and roof loading heavy materials onto job sites in bad weather and under tight schedules. I also worked private security, and later worked in case management with Veterans Court, Drug Court, and Mental Health Court, where documentation, communication, crisis intervention, and keeping people on track mattered every day.&lt;/p&gt;

&lt;p&gt;I also worked at Mason County Kitten Rescue from 2020 to 2022, which was not high-paying tech work, but it taught organization, intake, care routines, training volunteers, watching for signs of distress, and doing important daily work that does not become more profitable just because it matters. Then I started moving seriously into software, contributing as a Junior Frontend Developer with CIRIS Ethical AI in 2024 by running the project locally, improving onboarding and setup documentation, adding small code changes, improving token-verification logging, fixing lint issues, improving error messages, and opening GitHub Issues to keep larger ideas tracked. In 2025, I completed an on-site AWS Cloud Support Engineer internship in Seattle, where the work included guided support rotations in training environments with no customer data, guided Juniper and Junos troubleshooting labs in Jupyter Notebooks, and a capstone serverless metadata extraction workflow using Lambda, DynamoDB, S3, and an accessible frontend deployed on AWS Amplify.&lt;/p&gt;

&lt;p&gt;The reason that timeline matters is because none of the earlier physical or service-heavy jobs paid me over $20 an hour at the time, but they still demanded discipline, pressure management, communication, safety, documentation, and the ability to keep moving when things were not comfortable. Then tech came along and suddenly the pay ceiling was completely different, not because the work became morally superior, but because the business model changed. Software is not automatically harder than those jobs, but it can be attached to systems where the output scales in a way those jobs usually cannot.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pay Numbers That Start The Argument &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The U.S. Bureau of Labor Statistics listed the median annual wage for software developers at &lt;strong&gt;$133,080&lt;/strong&gt; in May 2024. The same BLS page says the lowest 10 percent earned less than &lt;strong&gt;$79,850&lt;/strong&gt;, while the highest 10 percent earned more than &lt;strong&gt;$211,450&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That number is already high compared to normal American wages. BLS listed the median annual wage for all workers at &lt;strong&gt;$49,500&lt;/strong&gt; in May 2024, which means the median software developer made about 2.7 times the median worker.&lt;/p&gt;

&lt;p&gt;The comparison gets uncomfortable when software is placed next to jobs that are clearly hard, risky, or socially important. BLS listed roofers at &lt;strong&gt;$50,970&lt;/strong&gt;, EMTs at &lt;strong&gt;$41,340&lt;/strong&gt;, paramedics at &lt;strong&gt;$58,410&lt;/strong&gt;, security guards at &lt;strong&gt;$38,370&lt;/strong&gt;, construction laborers and helpers at &lt;strong&gt;$46,050&lt;/strong&gt;, hand laborers and material movers at &lt;strong&gt;$37,680&lt;/strong&gt;, and high school teachers at &lt;strong&gt;$64,580&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Those numbers explain why people outside tech get annoyed when developers complain about pay. A junior developer can make more than a roofer, medic, security guard, teacher, construction laborer, or warehouse worker before that junior developer is even fully useful to the team.&lt;/p&gt;

&lt;p&gt;Levels.fyi shows even larger numbers because it tracks total compensation, not just base salary. In May 2026, Levels.fyi listed U.S. software engineer median total compensation around &lt;strong&gt;$191,000&lt;/strong&gt;, with the 25th percentile around &lt;strong&gt;$135,000&lt;/strong&gt;, the 75th percentile around &lt;strong&gt;$276,100&lt;/strong&gt;, and the 90th percentile around &lt;strong&gt;$380,000&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;BuiltIn shows a lower junior number than Levels.fyi, which makes sense because BuiltIn pulls from a broader mix of companies. BuiltIn lists U.S. junior software engineer average base salary around &lt;strong&gt;$89,847&lt;/strong&gt;, average additional cash compensation around &lt;strong&gt;$10,590&lt;/strong&gt;, and average total compensation around &lt;strong&gt;$100,437&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role Or Group&lt;/th&gt;
&lt;th&gt;Recent Pay Data&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;All U.S. workers&lt;/td&gt;
&lt;td&gt;$49,500 median wage&lt;/td&gt;
&lt;td&gt;This is the broad baseline for the whole labor market.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roofers&lt;/td&gt;
&lt;td&gt;$50,970 median wage&lt;/td&gt;
&lt;td&gt;This is skilled, physical, dangerous work, but the pay is close to the national median.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EMTs&lt;/td&gt;
&lt;td&gt;$41,340 median wage&lt;/td&gt;
&lt;td&gt;This is life-safety work, but the labor market pays it far below software.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paramedics&lt;/td&gt;
&lt;td&gt;$58,410 median wage&lt;/td&gt;
&lt;td&gt;This pays more than EMT work, but still far below the median developer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security guards&lt;/td&gt;
&lt;td&gt;$38,370 median wage&lt;/td&gt;
&lt;td&gt;This is common risk-bearing work, but it pays far below software.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Construction laborers and helpers&lt;/td&gt;
&lt;td&gt;$46,050 median wage&lt;/td&gt;
&lt;td&gt;This is hard physical work that often pays less than many junior tech jobs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand laborers and material movers&lt;/td&gt;
&lt;td&gt;$37,680 median wage&lt;/td&gt;
&lt;td&gt;This covers a lot of warehouse-style physical labor and shows how low that work often pays.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High school teachers&lt;/td&gt;
&lt;td&gt;$64,580 median wage&lt;/td&gt;
&lt;td&gt;This requires education, responsibility, and social value, but it is still below junior software pay in many cases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software developers&lt;/td&gt;
&lt;td&gt;$133,080 median wage&lt;/td&gt;
&lt;td&gt;This is where the comparison starts looking unfair to people outside tech.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U.S. software engineers on Levels.fyi&lt;/td&gt;
&lt;td&gt;$191,000 median total comp&lt;/td&gt;
&lt;td&gt;This includes bonus and equity, so it shows the higher end of tech more clearly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Junior software engineers on BuiltIn&lt;/td&gt;
&lt;td&gt;$100,437 average total comp&lt;/td&gt;
&lt;td&gt;This is one reason people ask whether junior developers are overpaid.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is not saying developers have easy lives or that every developer is rich. It is showing why the discussion gets tense, because the pay gap is real and the explanation is not as simple as “developers are smarter” or “developers work harder.”&lt;/p&gt;

&lt;p&gt;The market is not judging pay by soreness, danger, or public good. It is judging pay by how much money the company has, how scalable the output is, how hard the role is to fill, and how expensive it is when the work is done badly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Salary Comparison Graphic &lt;a&gt;&lt;/a&gt;
&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%2Fq2c5nt9jndbfdinm30ys.jpg" 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%2Fq2c5nt9jndbfdinm30ys.jpg" alt="Salary comparison chart showing median annual pay for security guards, warehouse-style material movers, EMTs, construction laborers, all U.S. workers, roofers, paramedics, teachers, junior software engineers, software developers, and Levels.fyi software engineers" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

A salary comparison using recent BLS wage data, BuiltIn junior software engineer compensation, and Levels.fyi software engineer total compensation. The point is not that software is always harder. The point is that software sits closer to scalable business leverage, which changes how companies pay for the work.







&lt;h2&gt;
  
  
  Why A Junior Dev Can Make More Than People Doing Harder Work &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This is the question people are really asking. Why is a junior developer who barely knows the codebase getting paid more than somebody climbing roofs, treating casualties, standing security posts, moving freight, or managing a classroom?&lt;/p&gt;

&lt;p&gt;The answer is not that junior devs are tougher than roofers, medics, teachers, or security guards. A junior dev sitting at a desk with a laptop is not taking the same physical beating as a roofer, and they are not carrying the same kind of immediate life-and-death pressure as a medic.&lt;/p&gt;

&lt;p&gt;The answer is also not that every junior developer is doing genius-level computer science all day. Most junior developers are not writing compilers, designing databases, or inventing new algorithms. Most are fixing bugs, building components, writing API calls, updating forms, handling validation, reading existing code, asking questions, and trying not to break the build.&lt;/p&gt;

&lt;p&gt;The reason junior developers can still get paid more is leverage. A junior dev working on the right product can ship a small feature that thousands of customers touch, while a roofer can only roof the house, building, or section physically in front of them.&lt;/p&gt;

&lt;p&gt;That does not make the roofer less skilled, and it does not make the medic less important. It means software output can be copied, deployed, reused, sold, and scaled in a way physical labor usually cannot.&lt;/p&gt;

&lt;p&gt;A roofer finishes a roof and that roof exists in one place. A developer finishes a login flow, billing screen, internal automation, or API endpoint, and that work might run all day for every user the company has.&lt;/p&gt;

&lt;p&gt;A medic treats the patient in front of them, and that work matters in a direct human way. A developer builds a system that might remove manual steps for a whole department, process thousands of payments, or prevent support tickets before they exist.&lt;/p&gt;

&lt;p&gt;A security guard protects a site, handles access, watches patterns, and responds to incidents in one location. A developer who builds access controls, audit logs, or monitoring systems might affect every user and every employee at the company.&lt;/p&gt;

&lt;p&gt;That is why software salaries feel disconnected from effort. The pay is not really for typing code. The pay is for building and maintaining systems that can scale past one person’s physical output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Roofing Compared To Software Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Roofing is one of the easiest jobs for people to underestimate because the final product looks simple. A roof keeps water out, but anyone who has actually done the work knows that a roof is only simple when you ignore everything that makes it fail.&lt;/p&gt;

&lt;p&gt;When I think about roofing, there are about 10 things you have to actually learn before you are useful and safe. You need to understand tear-off, decking, underlayment, flashing, shingles, fasteners, ventilation, valleys, measurements, and job-site safety.&lt;/p&gt;

&lt;p&gt;Tear-off is not just ripping old material off the roof. It is removing layers without destroying the deck, managing debris, watching for rot, keeping the site clean enough to work, and not creating a bigger problem before the new material even goes on.&lt;/p&gt;

&lt;p&gt;Decking matters because the roof is only as good as what it is attached to. In software, this is like discovering the data model, old architecture, or legacy service is rotten underneath the feature request.&lt;/p&gt;

&lt;p&gt;Underlayment, ice barrier, and water protection are the hidden layers most homeowners never think about. In software, those are like validation, auth checks, error handling, logging, and safe defaults, because nobody praises them when they work but everybody notices when they fail.&lt;/p&gt;

&lt;p&gt;Flashing is where a lot of bad roofs lose. In software, the equivalent is integrations, permission boundaries, third-party APIs, weird browser behavior, and all the places where one clean system meets another messy system.&lt;/p&gt;

&lt;p&gt;Shingles look easy from the ground, but alignment, overlap, nailing pattern, starter strips, and sequence all matter. In software, that is the repeatable pattern work, because a component, endpoint, or service should fit the system instead of being random every time.&lt;/p&gt;

&lt;p&gt;Fasteners matter because using the wrong nail, wrong placement, or wrong pressure creates future failure. In code, that is like using the wrong dependency, weak typing, fragile state management, a bad query, or a shortcut that only works until the system changes.&lt;/p&gt;

&lt;p&gt;Ventilation is one of those things that makes a roof fail slowly. In software, performance, caching, queues, background jobs, and infrastructure limits are the same kind of hidden system health work.&lt;/p&gt;

&lt;p&gt;Valleys, edges, vents, chimneys, and walls are where the easy middle stops being easy. In software, the happy path is usually simple, but the edge cases, weird inputs, expired sessions, duplicate requests, broken permissions, and production-only bugs are where the real work shows up.&lt;/p&gt;

&lt;p&gt;Measurement and material planning matter because waste costs money and bad estimates kill jobs. In software, bad estimates create missed deadlines, half-built features, rushed testing, and pressure that usually lands on the people doing the work.&lt;/p&gt;

&lt;p&gt;Safety matters because roofing can hurt or kill you fast. Software usually will not do that to your body, but it can hurt customers, leak data, break billing, stop operations, or create business damage if the system is important enough.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Roofing Work&lt;/th&gt;
&lt;th&gt;Software Equivalent&lt;/th&gt;
&lt;th&gt;Why The Comparison Makes Sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tear off the old roof without damaging the deck&lt;/td&gt;
&lt;td&gt;Refactor old code without breaking production&lt;/td&gt;
&lt;td&gt;Both jobs start by removing bad or outdated layers carefully.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect problem areas before quoting the job&lt;/td&gt;
&lt;td&gt;Read requirements, logs, errors, and existing code before coding&lt;/td&gt;
&lt;td&gt;Both jobs punish people who start swinging before understanding the problem.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Measure the roof and calculate material&lt;/td&gt;
&lt;td&gt;Scope the feature, data model, and implementation work&lt;/td&gt;
&lt;td&gt;Both jobs need estimating, waste control, and planning before execution.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace rotten plywood or damaged joists&lt;/td&gt;
&lt;td&gt;Fix bad architecture, bad data, or broken dependencies&lt;/td&gt;
&lt;td&gt;Both jobs reveal hidden problems once the surface layer comes off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install underlayment and water protection&lt;/td&gt;
&lt;td&gt;Add validation, auth, error handling, and security checks&lt;/td&gt;
&lt;td&gt;Both jobs need invisible protection that the customer may never notice until it fails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flash chimneys, walls, valleys, and vents&lt;/td&gt;
&lt;td&gt;Handle edge cases around integrations, permissions, and weird states&lt;/td&gt;
&lt;td&gt;Both jobs usually fail at the edges, not in the big flat middle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lay shingles with proper overlap and alignment&lt;/td&gt;
&lt;td&gt;Build UI and API flows with consistent patterns&lt;/td&gt;
&lt;td&gt;Both jobs need repeatable patterns, not random improvisation every few feet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cut materials around vents, walls, and valleys&lt;/td&gt;
&lt;td&gt;Adapt code around browser quirks, API limits, and product exceptions&lt;/td&gt;
&lt;td&gt;Both jobs require custom fitting while still following a system.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install ventilation correctly&lt;/td&gt;
&lt;td&gt;Design performance, caching, and operational flow&lt;/td&gt;
&lt;td&gt;Both jobs can look fine at first and fail later if system flow is wrong.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Work safely on ladders, slopes, heat, wind, and job sites&lt;/td&gt;
&lt;td&gt;Work safely around production data, secrets, deployments, and user impact&lt;/td&gt;
&lt;td&gt;Both jobs have risk, but the kind of risk is different.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is why I do not buy the argument that software work is always intellectually superior to trade work. A lot of software development is applied craft, pattern recognition, troubleshooting, repetition, and learning how to avoid known failures.&lt;/p&gt;

&lt;p&gt;The difference is that software companies can sell the same work again and again. A roofing company cannot install the same roof on 100,000 houses with one deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Army Medic Work Compared To Software Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Medic work is another comparison that makes software pay feel strange. As a medic, especially in the Army, the job is not just knowing medical facts. It is applying training under stress, around chain of command, with imperfect information, limited time, and real consequences.&lt;/p&gt;

&lt;p&gt;The Army describes the 68W Combat Medic Specialist role as assessing injuries, stabilizing patients, making critical medical decisions under extreme conditions, training other soldiers in first aid, and providing emergency medical treatment. That is a lot of responsibility for a role that often does not pay anywhere near what a developer makes.&lt;/p&gt;

&lt;p&gt;Civilian pay shows the gap clearly too. BLS lists EMTs at a median annual wage of &lt;strong&gt;$41,340&lt;/strong&gt; and paramedics at &lt;strong&gt;$58,410&lt;/strong&gt;, which means a junior software developer can easily make more than someone doing emergency medicine work.&lt;/p&gt;

&lt;p&gt;This is not because the junior developer has more immediate responsibility than a medic. A junior dev might break a page or slow down a sprint, while a medic can be involved in decisions where minutes matter.&lt;/p&gt;

&lt;p&gt;The software comparison is not about physical danger or emotional pressure. It is about decision-making inside a system, because medics and developers both work with incomplete information and need to decide what matters first.&lt;/p&gt;

&lt;p&gt;A medic has to assess the patient, control bleeding, protect the airway, manage shock, communicate with the team, prepare evacuation, document care, and keep working under pressure. A developer has to assess the bug, isolate the failure, protect production, communicate with the team, prepare a fix, document the change, and keep working under pressure.&lt;/p&gt;

&lt;p&gt;Those are not equal jobs. The human stakes are not the same. But the pattern is similar because both involve triage, prioritization, systems thinking, and knowing when the wrong action is worse than taking a moment to understand the problem.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Medic Work&lt;/th&gt;
&lt;th&gt;Software Equivalent&lt;/th&gt;
&lt;th&gt;Why The Comparison Makes Sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Triage multiple problems under pressure&lt;/td&gt;
&lt;td&gt;Prioritize incidents, bugs, and outages&lt;/td&gt;
&lt;td&gt;Both jobs require deciding what matters first.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop bleeding before treating smaller injuries&lt;/td&gt;
&lt;td&gt;Fix the production-breaking issue before cosmetic bugs&lt;/td&gt;
&lt;td&gt;Both jobs need damage control before polish.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintain airway, breathing, and circulation&lt;/td&gt;
&lt;td&gt;Protect uptime, data flow, and core system health&lt;/td&gt;
&lt;td&gt;Both jobs depend on keeping the main system alive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Work with limited information&lt;/td&gt;
&lt;td&gt;Debug with incomplete logs or unclear reports&lt;/td&gt;
&lt;td&gt;Both jobs rarely start with perfect information.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communicate with chain of command or evacuation teams&lt;/td&gt;
&lt;td&gt;Communicate with managers, product, support, and engineers&lt;/td&gt;
&lt;td&gt;Both jobs fail when communication fails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Track treatment and patient status&lt;/td&gt;
&lt;td&gt;Document incident notes, fixes, and follow-up work&lt;/td&gt;
&lt;td&gt;Both jobs need records so the next person is not blind.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Train others in basic first aid&lt;/td&gt;
&lt;td&gt;Mentor juniors and write operational docs&lt;/td&gt;
&lt;td&gt;Both jobs scale knowledge through training.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stay calm when people panic&lt;/td&gt;
&lt;td&gt;Stay calm during production issues&lt;/td&gt;
&lt;td&gt;Both jobs punish panic and reward process.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is why I do not like when developers exaggerate how hard coding is compared to everything else. Medic work can be more stressful, more direct, more personal, and more consequential in the moment.&lt;/p&gt;

&lt;p&gt;The reason software pays more is not because society values medics correctly. Software pays more because companies can turn working software into repeatable revenue, while emergency medical work is often limited by public budgets, contracts, insurance systems, military pay structures, and staffing models that do not reward the worker based on the actual human value of the work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Private Security Compared To Software Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Private security is another job people underestimate because they picture someone just standing around. Sometimes that is what it looks like from the outside, but the actual job is staying alert when nothing is happening, noticing when something changes, handling people without escalating the situation, and being the first person blamed when something goes wrong.&lt;/p&gt;

&lt;p&gt;BLS lists security guards at a median annual wage of &lt;strong&gt;$38,370&lt;/strong&gt; in May 2024. That is about &lt;strong&gt;$18.45/hour&lt;/strong&gt;, and it is still far below what many junior developers make.&lt;/p&gt;

&lt;p&gt;When I worked private security, the job was not technically complex the same way software is complex, but it required discipline, awareness, patience, and judgment. You had to watch access points, control entry, write incident reports, handle tense people, stay awake, stay professional, and understand when to call for help.&lt;/p&gt;

&lt;p&gt;Software has a security version of that same thinking. A lot of development work is boring monitoring, access control, logging, reviewing permissions, checking systems, and making sure the wrong person does not get into the wrong place.&lt;/p&gt;

&lt;p&gt;The pay difference is not because the private security worker has no value. The pay difference is because private security is often treated as a cost center, while software is often treated as a product engine or revenue multiplier.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Private Security Work&lt;/th&gt;
&lt;th&gt;Software Equivalent&lt;/th&gt;
&lt;th&gt;Why The Comparison Makes Sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control access to a site&lt;/td&gt;
&lt;td&gt;Build authentication and authorization&lt;/td&gt;
&lt;td&gt;Both jobs decide who gets in and what they can touch.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watch cameras, doors, lots, and patterns&lt;/td&gt;
&lt;td&gt;Monitor logs, dashboards, errors, and metrics&lt;/td&gt;
&lt;td&gt;Both jobs require noticing abnormal behavior.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write incident reports&lt;/td&gt;
&lt;td&gt;Write bug reports, incident notes, and postmortems&lt;/td&gt;
&lt;td&gt;Both jobs need clear records after something happens.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;De-escalate tense people&lt;/td&gt;
&lt;td&gt;Handle support escalations and production pressure calmly&lt;/td&gt;
&lt;td&gt;Both jobs need communication under stress.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow post orders&lt;/td&gt;
&lt;td&gt;Follow runbooks, deployment process, and security policy&lt;/td&gt;
&lt;td&gt;Both jobs depend on process because memory is not enough.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patrol and inspect areas&lt;/td&gt;
&lt;td&gt;Review systems, endpoints, configs, and permissions&lt;/td&gt;
&lt;td&gt;Both jobs look for problems before they become incidents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Respond when something changes&lt;/td&gt;
&lt;td&gt;Respond to alerts, outages, and suspicious activity&lt;/td&gt;
&lt;td&gt;Both jobs can be quiet for hours and then serious fast.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The unfair part is that security workers are paid like replaceable labor even though bad security can cost a company a lot. Software developers are paid better because their work is closer to scalable revenue and because companies believe replacing a developer is harder than replacing a guard.&lt;/p&gt;

&lt;p&gt;That does not mean the market is morally correct. It means the market rewards leverage more than responsibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Warehouse And Manual Labor Compared To Software Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Warehouse work is another comparison that matters because a lot of people in tech have never had to do repetitive physical work for a paycheck. BLS lists hand laborers and material movers at a median annual wage of &lt;strong&gt;$37,680&lt;/strong&gt;, which shows how low that work often pays compared to software.&lt;/p&gt;

&lt;p&gt;Warehouse work can look simple if you only describe it as “moving boxes.” Software can also look simple if you only describe it as “typing code,” which is why bad descriptions are useless.&lt;/p&gt;

&lt;p&gt;Warehouse work requires speed, accuracy, memory, scanning, staging, loading, safety, endurance, and not making mistakes that slow down everyone behind you. A bad pick, bad label, bad count, bad pallet, or bad load can create real downstream problems.&lt;/p&gt;

&lt;p&gt;Software has the same kind of flow problem, just in a different form. A bad data migration, wrong config, bad deploy, missed environment variable, or broken API contract can hold up the whole team or create customer issues.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Warehouse Work&lt;/th&gt;
&lt;th&gt;Software Equivalent&lt;/th&gt;
&lt;th&gt;Why The Comparison Makes Sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pick the right item&lt;/td&gt;
&lt;td&gt;Pull the right data or dependency&lt;/td&gt;
&lt;td&gt;Both jobs fail when the wrong thing moves through the system.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Label and scan correctly&lt;/td&gt;
&lt;td&gt;Name, type, and log data correctly&lt;/td&gt;
&lt;td&gt;Both jobs need traceability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stage items in the right place&lt;/td&gt;
&lt;td&gt;Prepare code, branches, builds, and environments correctly&lt;/td&gt;
&lt;td&gt;Both jobs depend on sequence and organization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load without damaging product&lt;/td&gt;
&lt;td&gt;Deploy without damaging production&lt;/td&gt;
&lt;td&gt;Both jobs involve moving work safely from one state to another.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keep pace without losing accuracy&lt;/td&gt;
&lt;td&gt;Ship quickly without breaking quality&lt;/td&gt;
&lt;td&gt;Both jobs punish sloppy speed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow safety and workflow rules&lt;/td&gt;
&lt;td&gt;Follow code review, testing, and deployment rules&lt;/td&gt;
&lt;td&gt;Both jobs use process to reduce mistakes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The difference is not that software is always harder. The difference is that software work can automate the warehouse workflow itself, reduce headcount, improve routing, change inventory systems, or improve company-wide efficiency.&lt;/p&gt;

&lt;p&gt;That is why a developer who has never done warehouse work might make more than the warehouse worker. It is not because the developer is automatically tougher, it is because the developer may be building the system that changes how 500 warehouse workers operate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Teaching Compared To Software Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Teaching is one of the clearest examples of how pay does not equal social value. BLS lists high school teachers at a median annual wage of &lt;strong&gt;$64,580&lt;/strong&gt;, which is above the national median but still far below software developer pay and below many junior tech offers.&lt;/p&gt;

&lt;p&gt;A good teacher has to understand the subject, manage a room, communicate clearly, adjust to different students, track progress, deal with parents and administrators, follow standards, grade work, and keep showing up even when the system is not built to make the job easy.&lt;/p&gt;

&lt;p&gt;That sounds a lot like developer mentorship in some ways. A senior developer who cannot explain anything clearly is less useful than a senior developer who can teach patterns, review code well, write docs, and help juniors become productive.&lt;/p&gt;

&lt;p&gt;The difference is that teaching usually sits inside public budgets, district funding, local taxes, political fights, and credential systems. Software sits inside companies that can sell products repeatedly and use technical work to increase margins.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Teaching Work&lt;/th&gt;
&lt;th&gt;Software Equivalent&lt;/th&gt;
&lt;th&gt;Why The Comparison Makes Sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Break down hard concepts&lt;/td&gt;
&lt;td&gt;Explain systems, code, and architecture&lt;/td&gt;
&lt;td&gt;Both jobs require turning complexity into something another person can use.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manage different skill levels&lt;/td&gt;
&lt;td&gt;Mentor juniors and collaborate across teams&lt;/td&gt;
&lt;td&gt;Both jobs involve uneven experience levels.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grade and give feedback&lt;/td&gt;
&lt;td&gt;Review code and give actionable comments&lt;/td&gt;
&lt;td&gt;Both jobs need feedback that improves the person, not just the output.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow curriculum and standards&lt;/td&gt;
&lt;td&gt;Follow product requirements, security standards, and engineering process&lt;/td&gt;
&lt;td&gt;Both jobs work inside constraints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Track progress over time&lt;/td&gt;
&lt;td&gt;Track technical debt, sprint work, and developer growth&lt;/td&gt;
&lt;td&gt;Both jobs require long-term attention.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handle classroom pressure&lt;/td&gt;
&lt;td&gt;Handle meetings, incidents, and team pressure&lt;/td&gt;
&lt;td&gt;Both jobs require communication when things get messy.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is why the “developers are paid because they are smarter” argument falls apart. Teachers need skill, judgment, patience, communication, and subject knowledge, but their labor does not scale the same way software does.&lt;/p&gt;

&lt;p&gt;A teacher teaches the students in front of them. A developer builds a feature once and the company can put it in front of every customer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Do Most Developers Even Do DSA? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Most developers do not spend their normal workday implementing red-black trees, writing graph algorithms from scratch, or solving LeetCode-style dynamic programming problems. Most business software work is much more ordinary than the interview process makes it look.&lt;/p&gt;

&lt;p&gt;That does not mean data structures and algorithms are useless. It means there is a difference between the theory that helps you think and the daily work most developers are paid to do.&lt;/p&gt;

&lt;p&gt;Most web developers spend more time reading existing code, changing components, writing endpoints, shaping data, handling errors, fixing tests, wiring third-party services, working with databases, and pushing changes through a deployment process. That work still uses data structures, but usually in the form of arrays, objects, maps, JSON, query results, collections, queues, and state.&lt;/p&gt;

&lt;p&gt;A roofer does not calculate structural engineering formulas all day either. That does not mean roofing has no skill. It means the job is mostly applied field knowledge, judgment, tool use, sequence, safety, and knowing what failure looks like before it happens.&lt;/p&gt;

&lt;p&gt;A medic does not write a medical textbook during every patient interaction either. They apply training, assess the current situation, follow protocol, make decisions, communicate, and act before the situation gets worse.&lt;/p&gt;

&lt;p&gt;A security guard is not doing legal theory all night either. They follow post orders, watch patterns, control access, de-escalate, document, and call the right people when something crosses the line.&lt;/p&gt;

&lt;p&gt;Software is similar for most developers. The job is less “solve a puzzle from scratch” and more “change a living system without making it worse.”&lt;/p&gt;

&lt;p&gt;The reason DSA still matters is that some jobs really do need it. Search, ranking, distributed systems, graphics, compilers, databases, high-frequency trading, AI infrastructure, embedded systems, and large-scale platform work can absolutely require deeper computer science.&lt;/p&gt;

&lt;p&gt;The problem is that the hiring process often treats every web developer like they are applying to build a search engine. That creates a fake picture of the job, because plenty of developers make solid money doing CRUD, integrations, infrastructure, UI, testing, debugging, and maintenance.&lt;/p&gt;

&lt;p&gt;This is part of why salary conversations get weird. A person outside tech hears that developers make six figures and assumes they must be doing advanced math all day. A person inside tech knows plenty of developers are mostly moving data from one place to another, validating it, displaying it, storing it, and making sure it does not break.&lt;/p&gt;

&lt;p&gt;That work still matters, but it is not always the mythical version of software engineering people imagine. Most companies pay for working systems, not for how many algorithm problems someone can solve on a whiteboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Is Web Development Skilled Trade Work With A Keyboard? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A lot of normal software work is closer to skilled trade work than developers want to admit. Most business developers are not doing advanced algorithm research, because they are building, fixing, connecting, deploying, documenting, and maintaining systems.&lt;/p&gt;

&lt;p&gt;That does not make the job fake or easy. Roofing is also “just putting materials on a roof” if someone wants to describe it badly, but anyone who has done it knows that a bad roof can look fine for a little while before the leak exposes every shortcut.&lt;/p&gt;

&lt;p&gt;Software is the same way. Bad code can look fine in the demo, pass the happy path, and still fail when users hit weird inputs, network errors, bad permissions, slow queries, expired sessions, broken environment variables, or real production load.&lt;/p&gt;

&lt;p&gt;This is where the trade comparison gets useful. A lot of web development is not elite math, but it is still skilled production work where experience matters because the edge cases are what punish you.&lt;/p&gt;

&lt;p&gt;The same pattern shows up across roofing, medic work, security, warehouse work, teaching, and software. The public sees the visible output, but the worker knows the job is mostly about preventing the failure that nobody notices if you did it right.&lt;/p&gt;

&lt;p&gt;In roofing, a customer might only see shingles. In software, a product manager might only see a button. The worker sees the layers under it, the ways it can fail, the shortcuts that were taken before, and the cleanup nobody budgeted time for.&lt;/p&gt;

&lt;p&gt;That is why I think “easy job” is the wrong phrase. Some development work is physically easy, and some tickets are technically simple, but the job becomes valuable because the work lives inside a larger system with users, data, revenue, and future maintenance attached to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Are Junior Developers Overpaid? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Compared to roofers, EMTs, teachers, security guards, warehouse workers, construction laborers, and the national median worker, junior developers are usually overpaid in the plain social comparison sense. A junior developer making $90k to $120k while still learning the job is making more than many people who carry more physical risk, more public responsibility, or more immediate consequences.&lt;/p&gt;

&lt;p&gt;Compared to the business model they work inside, juniors are not always overpaid. A junior who can ship small production improvements, automate annoying internal work, fix customer-facing bugs, improve documentation, and grow into a mid-level developer is not just being paid for today’s output.&lt;/p&gt;

&lt;p&gt;The company is paying for the pipeline. Hiring a junior is partly a bet that the person will become useful enough to retain, promote, or use as a cheaper alternative to hiring only seniors.&lt;/p&gt;

&lt;p&gt;This is also why junior hiring gets ugly when the market tightens. If companies stop wanting to invest in training, juniors suddenly look expensive because they need mentorship before they become reliably productive.&lt;/p&gt;

&lt;p&gt;That is where the “easy job” complaint has some truth but not the whole truth. A lot of junior tickets are easy compared to roofing, medic work, or private security, but the junior is still learning how to work inside a system where small changes can create bigger problems.&lt;/p&gt;

&lt;p&gt;So yes, juniors can be overpaid if the company expects them to be productive immediately and they are mostly being carried. But juniors can be underpaid if they are doing real production work, learning fast, getting little support, and still being treated like replaceable cheap labor.&lt;/p&gt;

&lt;p&gt;The more honest answer is that junior pay is not about whether the current ticket is easy. It is about whether the company believes the person can become valuable before the cost of training them becomes a loss.&lt;/p&gt;




&lt;h2&gt;
  
  
  Are Mid-Level Developers Fairly Paid? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Mid-level developers are probably the closest thing to fairly paid in normal software work. They usually know enough to ship, debug, communicate, review code, understand production basics, and ask for help before they create a disaster.&lt;/p&gt;

&lt;p&gt;They are not usually responsible for company-wide technical direction. They also are not usually helpless, which makes them valuable without making them as expensive as staff or principal engineers.&lt;/p&gt;

&lt;p&gt;This level is where software starts looking most like skilled trade work. A solid mid-level developer knows the tools, knows the common failure points, knows how to estimate better than a junior, and knows when a “small change” is not actually small.&lt;/p&gt;

&lt;p&gt;A solid roofer with a few years in the field is the same kind of person. They may not own the company or design the whole job, but they can look at a roof, understand the next steps, avoid obvious mistakes, and keep the job moving.&lt;/p&gt;

&lt;p&gt;A solid medic is also that kind of person. They may not be the doctor, but they know how to assess the situation, act within scope, document, communicate, and keep the patient moving through the system.&lt;/p&gt;

&lt;p&gt;A reliable security worker fits the same pattern too. They may not be writing policy, but they know the post, notice what is off, document what happened, and understand when a situation needs to move up the chain.&lt;/p&gt;

&lt;p&gt;That is why mid-level dev compensation makes the most sense to me. They are expensive, but they are usually expensive in the same way any reliable skilled worker is expensive, with the added difference that software output can scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  Are Staff Engineers Overpaid? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Staff engineers are where the conversation becomes almost impossible because the numbers get absurd. A Google L6 staff engineer around $580k, a Meta E6 staff engineer around $775k, and Netflix senior staff compensation near or above $1M sounds fake if you compare it to normal jobs.&lt;/p&gt;

&lt;p&gt;But staff engineers at companies like that are not being paid to close Jira tickets. They are paid to reduce risk, set technical direction, unblock teams, review architecture, avoid expensive mistakes, and make decisions that affect systems with huge numbers of users.&lt;/p&gt;

&lt;p&gt;That is why revenue per employee matters. NVIDIA reportedly generated around $4.4 million in revenue per employee, and Netflix was reported around $4.15 million per employee, which changes how a $700k engineer looks on a spreadsheet.&lt;/p&gt;

&lt;p&gt;That does not mean every staff engineer deserves $700k. Some people have inflated titles, some companies hand out titles loosely, and some senior people become expensive bottlenecks instead of force multipliers.&lt;/p&gt;

&lt;p&gt;But a real staff engineer at scale is not just a better coder. They are closer to a technical foreman, architect, incident preventer, reviewer, teacher, and risk manager combined.&lt;/p&gt;

&lt;p&gt;That kind of work can be underpaid if it prevents huge losses. It can also be overpaid if the person mostly attends meetings, writes vague docs, and creates no real technical leverage.&lt;/p&gt;

&lt;p&gt;The title alone does not answer the question. The value depends on the actual scope, the systems involved, and whether the person makes many other engineers and systems better.&lt;/p&gt;

&lt;p&gt;This is the part that normal salary comparisons miss. A staff engineer at a small company and a staff engineer at a global platform can have the same title, but one might be improving internal tooling for 80 employees while the other is making architecture decisions that affect millions of users.&lt;/p&gt;

&lt;p&gt;That is why staff pay looks fake from the outside. Sometimes it is inflated, sometimes it is justified, and sometimes it is still cheaper than the damage the wrong technical decision would cause.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AI Changes The Pay Conversation &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;AI makes this debate even harder because it lowers the floor and raises the ceiling at the same time. A junior with AI tools can ship more than a junior could a few years ago, but a weak junior can also create a bigger mess faster than before.&lt;/p&gt;

&lt;p&gt;The boring tasks are becoming cheaper. Boilerplate, simple components, basic scripts, basic CRUD, documentation drafts, test scaffolds, and quick debugging help are all easier with tools like ChatGPT, Claude, Cursor, and Copilot.&lt;/p&gt;

&lt;p&gt;That means companies may eventually pay less for people who only know how to produce basic code. The value is moving toward people who can understand the system, verify AI output, debug bad suggestions, protect production, think through risk, and connect technical work to business goals.&lt;/p&gt;

&lt;p&gt;This is where staff engineers and strong mid-level developers may become even more valuable. If a company has ten juniors using AI and nobody experienced reviewing the architecture, the company did not get faster, it just created problems at higher speed.&lt;/p&gt;

&lt;p&gt;AI does not remove the need for judgment. It makes judgment more important because the cost of producing code went down, but the cost of understanding whether that code is correct did not disappear.&lt;/p&gt;

&lt;p&gt;This is also why junior dev pay is going to be a rough topic for a while. If a junior can use AI to ship useful work and they can explain what they are doing, their value goes up. If they use AI to produce code they cannot understand, their risk goes up.&lt;/p&gt;

&lt;p&gt;The same thing happened in other work when tools improved. Better nail guns did not remove the need for someone who understands roofing. Better medical equipment did not remove the need for someone who can assess the patient. Better cameras did not remove the need for security judgment.&lt;/p&gt;

&lt;p&gt;Better coding tools will not remove the need for developers who understand systems. They will probably remove some tolerance for people who only copy output and hope it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Different Developer Economies &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The software industry is not one labor market anymore. It is at least three different economies pretending to be one because all the job titles use the word developer or engineer.&lt;/p&gt;

&lt;p&gt;The first economy is normal software work. These are the developers at small companies, local businesses, agencies, internal IT teams, healthcare companies, manufacturing companies, insurance companies, and non-tech companies where software supports the business instead of being the whole business.&lt;/p&gt;

&lt;p&gt;The second economy is high-scale tech. These are developers at Big Tech, AI labs, high-frequency trading firms, cloud infrastructure companies, fintech platforms, and product companies where one technical decision can affect millions of users or billions of dollars in market value.&lt;/p&gt;

&lt;p&gt;The third economy is underpaid software work. These are developers maintaining legacy systems, handling frontend, backend, support, infrastructure, deployments, and documentation while making $60k, $80k, or maybe $100k with little mentorship and no real path upward.&lt;/p&gt;

&lt;p&gt;This is why the argument goes nowhere. Someone talking about a junior web developer at a small local company and someone talking about an L6 engineer at Google are not talking about the same job.&lt;/p&gt;

&lt;p&gt;Both people can be telling the truth. They are just describing different worlds.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Developer Economy&lt;/th&gt;
&lt;th&gt;Typical Work&lt;/th&gt;
&lt;th&gt;Typical Pay Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Normal software work&lt;/td&gt;
&lt;td&gt;CRUD, internal tools, websites, APIs, integrations, support, maintenance&lt;/td&gt;
&lt;td&gt;Often $70k to $180k depending on region and company.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-scale tech&lt;/td&gt;
&lt;td&gt;Infrastructure, platforms, AI, distributed systems, revenue-critical products&lt;/td&gt;
&lt;td&gt;Can reach $300k to $1M+ because the leverage is massive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Underpaid software work&lt;/td&gt;
&lt;td&gt;Legacy maintenance, too many hats, little support, low-budget companies&lt;/td&gt;
&lt;td&gt;Can pay closer to $50k to $100k while still demanding broad responsibility.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This split explains why developers argue past each other. One person is talking about people making $500k and another person is talking about someone doing full-stack work for $70k at a non-tech company.&lt;/p&gt;

&lt;p&gt;The title alone does not tell you enough. You need to know the company, the market, the revenue model, the level, the scope, the risk, and whether the person is actually creating leverage or just carrying a fancy title.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Answer &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Developers are overpaid if the comparison is physical danger, social value, or visible effort. A junior developer working from home can make more than a roofer, medic, teacher, security guard, warehouse worker, or construction laborer, and I do not think developers should pretend that feels normal.&lt;/p&gt;

&lt;p&gt;Developers are not always overpaid if the comparison is business leverage. A developer who ships a feature used by thousands of customers, prevents outages, improves performance, secures customer data, or automates expensive work can easily create more value than their salary.&lt;/p&gt;

&lt;p&gt;Most normal developers are not doing elite computer science all day. They are doing applied software trade work, which means building, fixing, connecting, testing, deploying, documenting, and maintaining systems that break in weird ways.&lt;/p&gt;

&lt;p&gt;That work is not magic. It is not always harder than roofing, medic work, construction, warehouse work, teaching, or security work, but it exists inside a business model where output can scale.&lt;/p&gt;

&lt;p&gt;The cleanest answer is this: junior devs can be socially overpaid and economically reasonable at the same time, mid-level devs are often the most fairly paid group, and real staff engineers at scale can look wildly overpaid while still being underpaid compared to the money and risk they manage.&lt;/p&gt;

&lt;p&gt;The thing I do not buy anymore is the idea that pay equals difficulty. Pay equals leverage, scarcity, company margins, negotiation power, and how close your work is to money.&lt;/p&gt;

&lt;p&gt;That is why the junior dev making a React form can out-earn a roofer, medic, guard, teacher, or warehouse worker. It is not because the junior dev is tougher, and it is not because the other jobs are easy. It is because the software company can scale the result in a way most physical or public-service work cannot.&lt;/p&gt;

&lt;p&gt;That does not make the market morally correct. It just explains why the numbers look broken.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm" rel="noopener noreferrer"&gt;BLS, Software Developers, Quality Assurance Analysts, and Testers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/construction-and-extraction/roofers.htm" rel="noopener noreferrer"&gt;BLS, Roofers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/healthcare/emts-and-paramedics.htm" rel="noopener noreferrer"&gt;BLS, EMTs and Paramedics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/protective-service/security-guards.htm" rel="noopener noreferrer"&gt;BLS, Security Guards and Gambling Surveillance Officers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/education-training-and-library/high-school-teachers.htm" rel="noopener noreferrer"&gt;BLS, High School Teachers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/construction-and-extraction/construction-laborers-and-helpers.htm" rel="noopener noreferrer"&gt;BLS, Construction Laborers and Helpers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/ooh/transportation-and-material-moving/hand-laborers-and-material-movers.htm" rel="noopener noreferrer"&gt;BLS, Hand Laborers and Material Movers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.bls.gov/charts/census-of-fatal-occupational-injuries/rate-and-number-of-fatal-work-injuries-in-selected-occupations.htm" rel="noopener noreferrer"&gt;BLS, Fatal Work Injury Rates, 2024&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.goarmy.com/careers-and-jobs/science-medicine/intensive-care/68w-combat-medic-specialist" rel="noopener noreferrer"&gt;U.S. Army, 68W Combat Medic Specialist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cool.osd.mil/army/moc/index.html?moc=68w" rel="noopener noreferrer"&gt;Army COOL, 68W Combat Medic Specialist MOS Overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.dfas.mil/MilitaryMembers/payentitlements/Pay-Tables/" rel="noopener noreferrer"&gt;DFAS, Military Pay Tables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.levels.fyi/t/software-engineer" rel="noopener noreferrer"&gt;Levels.fyi, Software Engineer Salary&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://builtin.com/salaries/us/junior-software-engineer" rel="noopener noreferrer"&gt;BuiltIn, Junior Software Engineer Salary in US&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.adpresearch.com/research/the-rise-and-fall-of-the-software-developer" rel="noopener noreferrer"&gt;ADP Research, The Rise and Fall of the Software Developer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.library.hbs.edu/working-knowledge/remote-work-or-more-pay-what-tech-workers-value-in-one-chart" rel="noopener noreferrer"&gt;Harvard Business School, Remote Work or More Pay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ondeck.com/resources/revenue-per-employee" rel="noopener noreferrer"&gt;OnDeck, Revenue Per Employee Rankings&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>careerdevelopment</category>
      <category>ai</category>
      <category>development</category>
    </item>
    <item>
      <title>AI Policy Is Becoming the New Entry-Level Gatekeeping</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:37:55 +0000</pubDate>
      <link>https://dev.to/bradleymatera/ai-policy-is-becoming-the-new-entry-level-gatekeeping-1d4o</link>
      <guid>https://dev.to/bradleymatera/ai-policy-is-becoming-the-new-entry-level-gatekeeping-1d4o</guid>
      <description>&lt;p&gt;AI policy is becoming a new entry-level gate.&lt;/p&gt;

&lt;p&gt;Not because companies have mature rules. Because many do not.&lt;/p&gt;

&lt;p&gt;They want juniors who are AI-literate, fast, current, and able to use modern tools.&lt;/p&gt;

&lt;p&gt;They also distrust AI-assisted work, punish unclear disclosure, and often fail to explain which tools are allowed.&lt;/p&gt;

&lt;p&gt;That contradiction creates the trap:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use AI and risk looking dependent. Avoid AI and risk looking behind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not a junior developer problem. It is a leadership problem.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/afinitiai-ai-intelligence-artificial-Fs4Fh8g3KxM3PEoGIB" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExZXh4enU4NjUybnl4ODFtcG03YnBmNDN6anN3dnM3dDg3dnduMnQxcCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FFs4Fh8g3KxM3PEoGIB%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/afinitiai-ai-intelligence-artificial-Fs4Fh8g3KxM3PEoGIB" rel="noopener noreferrer" class="c-link"&gt;
            Winning Artificial Intelligence GIF by Afiniti - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Winning Artificial Intelligence GIF by Afiniti with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The market already moved
&lt;/h2&gt;

&lt;p&gt;AI is not a fringe developer tool anymore.&lt;/p&gt;

&lt;p&gt;Stack Overflow's 2025 Developer Survey says 84% of respondents are using or planning to use AI tools in their development process. It also says 44% used AI-enabled tools to learn coding techniques or a new language. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;GitHub's Octoverse 2025 report says nearly 80% of new developers on GitHub used Copilot within their first week. [&lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Microsoft's 2025 Work Trend Index describes AI agents and AI-assisted work as part of the emerging workplace model. [&lt;a href="https://news.microsoft.com/annual-work-trend-index-2025/" rel="noopener noreferrer"&gt;Microsoft Work Trend Index 2025&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;OpenAI's 2025 enterprise AI report also frames coding workflows as one of the areas where frontier models are accelerating software development. [&lt;a href="https://openai.com/business/guides-and-resources/the-state-of-enterprise-ai-2025-report/" rel="noopener noreferrer"&gt;OpenAI enterprise AI report&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-47b0b04c-0435-4418-ae83-724f82e4eafa" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-47b0b04c-0435-4418-ae83-724f82e4eafa" alt="Chart: AI is already present across developer use, new GitHub developer onboarding, entry-level hiring expectations, and coding education" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt;, &lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;, and &lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake Class of 2026 AI economy research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The message is obvious: AI is already in the workflow. The rules are lagging behind the tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The entry-level contradiction
&lt;/h2&gt;

&lt;p&gt;Handshake's research on the Class of 2026 in the AI economy found that 70% of hiring leaders say AI will change entry-level role requirements. [&lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" alt="Chart: 70% of hiring leaders say AI will change entry-level role requirements" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake Class of 2026 AI economy research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That means companies expect entry-level candidates to understand AI's role in work.&lt;/p&gt;

&lt;p&gt;But many job descriptions still do not say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether AI tools are allowed&lt;/li&gt;
&lt;li&gt;which tools are approved&lt;/li&gt;
&lt;li&gt;whether generated code is allowed&lt;/li&gt;
&lt;li&gt;whether AI use must be disclosed&lt;/li&gt;
&lt;li&gt;whether candidates may use AI in take-home assignments&lt;/li&gt;
&lt;li&gt;whether company code can be pasted into tools&lt;/li&gt;
&lt;li&gt;whether AI is allowed for learning but not implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That ambiguity matters because juniors are the least powerful people in the hiring process.&lt;/p&gt;

&lt;p&gt;Ambiguous rules usually punish the least powerful person first.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Use AI, but not like that" is not a policy
&lt;/h2&gt;

&lt;p&gt;A lot of companies have a vibe instead of a policy.&lt;/p&gt;

&lt;p&gt;The vibe sounds like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We want people who use modern tools.&lt;/li&gt;
&lt;li&gt;We value productivity.&lt;/li&gt;
&lt;li&gt;We are exploring AI.&lt;/li&gt;
&lt;li&gt;Do not submit AI slop.&lt;/li&gt;
&lt;li&gt;Use common sense.&lt;/li&gt;
&lt;li&gt;We can tell when something is generated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not governance. That is a collection of future arguments.&lt;/p&gt;

&lt;p&gt;A real policy answers operational questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy area&lt;/th&gt;
&lt;th&gt;Clear answer needed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Approved tools&lt;/td&gt;
&lt;td&gt;Which tools can employees use?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data privacy&lt;/td&gt;
&lt;td&gt;What code, logs, tickets, or customer data may be pasted?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generated code&lt;/td&gt;
&lt;td&gt;Is generated implementation allowed?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning use&lt;/td&gt;
&lt;td&gt;Can AI explain code, docs, errors, and concepts?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disclosure&lt;/td&gt;
&lt;td&gt;When must AI assistance be mentioned in a PR?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;What extra review is required for risky code?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interviews&lt;/td&gt;
&lt;td&gt;Can candidates use AI during take-homes or live screens?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforcement&lt;/td&gt;
&lt;td&gt;What happens when rules are unclear or violated?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without that, companies are not evaluating judgment. They are evaluating whether candidates guessed the hidden rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do not trust the output blindly
&lt;/h2&gt;

&lt;p&gt;AI output should not be trusted blindly.&lt;/p&gt;

&lt;p&gt;Stack Overflow's 2025 survey says more developers distrust AI output accuracy than trust it: 46% versus 33%. The most common frustration is that AI solutions are "almost right, but not quite." [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" alt="Chart: Stack Overflow 2025 shows 46% distrust AI output accuracy, 33% trust it, and 66% cite almost-right answers as a frustration" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That warning matters. It does not justify lazy anti-AI rules.&lt;/p&gt;

&lt;p&gt;It supports a verification standard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can the developer explain the code?&lt;/li&gt;
&lt;li&gt;Did they test the risky behavior?&lt;/li&gt;
&lt;li&gt;Did they compare output against docs?&lt;/li&gt;
&lt;li&gt;Did they reject bad suggestions?&lt;/li&gt;
&lt;li&gt;Did they disclose meaningful assistance?&lt;/li&gt;
&lt;li&gt;Did they protect private data?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is better than:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No AI."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is also better than:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use AI to move faster, but we will punish you if we dislike the result."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hiring managers often do not know what they want
&lt;/h2&gt;

&lt;p&gt;Many hiring managers are trying to hire for a role they have not defined.&lt;/p&gt;

&lt;p&gt;They want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI-literate but not AI-dependent&lt;/li&gt;
&lt;li&gt;junior but production-ready&lt;/li&gt;
&lt;li&gt;independent but coachable&lt;/li&gt;
&lt;li&gt;full-stack but cheap&lt;/li&gt;
&lt;li&gt;fast but careful&lt;/li&gt;
&lt;li&gt;transparent but not risky&lt;/li&gt;
&lt;li&gt;modern but compliant with unstated policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not a candidate profile. It is unresolved leadership tension.&lt;/p&gt;

&lt;p&gt;The job description turns into a contradiction because the team has not decided what kind of developer it actually needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate AI use directly
&lt;/h2&gt;

&lt;p&gt;Companies should stop pretending candidates are not using AI. Evaluate how they use it.&lt;/p&gt;

&lt;p&gt;A good interview prompt could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here is a small function with a bug.
You may use AI as you normally would.
When you submit the fix, include:
- what you asked
- what the tool got wrong
- what you verified
- what tests you added
- what you would want reviewed before production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tests judgment, not theater. It also reflects how real work is increasingly done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad AI use versus professional AI use
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lazy AI use&lt;/th&gt;
&lt;th&gt;Professional AI use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Paste generated output&lt;/td&gt;
&lt;td&gt;Own the final code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust confident answers&lt;/td&gt;
&lt;td&gt;Verify against docs and tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hide tool use&lt;/td&gt;
&lt;td&gt;Disclose when required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ignore security and privacy&lt;/td&gt;
&lt;td&gt;Use approved tools and data rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skip fundamentals&lt;/td&gt;
&lt;td&gt;Use AI to strengthen fundamentals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Treat AI as authority&lt;/td&gt;
&lt;td&gt;Treat AI as a fallible assistant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is the distinction hiring should measure: not whether the candidate touched AI, but whether the candidate can use it without outsourcing judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The learning-resource problem is real
&lt;/h2&gt;

&lt;p&gt;AI is becoming the default learning layer partly because older learning paths are fragmented.&lt;/p&gt;

&lt;p&gt;The modern junior is trying to stitch together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;official docs&lt;/li&gt;
&lt;li&gt;old Stack Overflow answers&lt;/li&gt;
&lt;li&gt;framework changelogs&lt;/li&gt;
&lt;li&gt;YouTube tutorials&lt;/li&gt;
&lt;li&gt;Discord threads&lt;/li&gt;
&lt;li&gt;GitHub issues&lt;/li&gt;
&lt;li&gt;blog posts&lt;/li&gt;
&lt;li&gt;paid courses&lt;/li&gt;
&lt;li&gt;outdated examples&lt;/li&gt;
&lt;li&gt;internal docs if they are lucky&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI sits on top of that mess and gives a conversational way to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What changed between versions?&lt;/li&gt;
&lt;li&gt;Why does this error happen?&lt;/li&gt;
&lt;li&gt;What should I search next?&lt;/li&gt;
&lt;li&gt;Can you explain this code like I am new to the repo?&lt;/li&gt;
&lt;li&gt;What test cases should I consider?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not a replacement for learning. It is a learning interface.&lt;/p&gt;

&lt;p&gt;Companies that do not understand that will keep misreading AI use as laziness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The research points back to training
&lt;/h2&gt;

&lt;p&gt;The paper &lt;em&gt;The Widening Gap&lt;/em&gt; found that generative AI can help novice programmers, but weaker learners may accept incorrect suggestions more easily. [&lt;a href="https://arxiv.org/abs/2405.17739" rel="noopener noreferrer"&gt;The Widening Gap&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 systematic literature review on junior developers adopting LLMs found both positive and negative perceptions in most of the studies reviewed. [&lt;a href="https://arxiv.org/abs/2503.07556" rel="noopener noreferrer"&gt;Junior developers and LLMs SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That points back to training: AI literacy has to be taught, not assumed and not banned by reflex.&lt;/p&gt;

&lt;h2&gt;
  
  
  A policy that actually says something
&lt;/h2&gt;

&lt;p&gt;A serious AI policy for junior developers could say:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Approved tools only&lt;/td&gt;
&lt;td&gt;Prevents data leakage and tool sprawl.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No private code in unapproved tools&lt;/td&gt;
&lt;td&gt;Protects IP and customer data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disclosure for material assistance&lt;/td&gt;
&lt;td&gt;Keeps review honest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests required for generated logic&lt;/td&gt;
&lt;td&gt;Verifies behavior.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human review for risky domains&lt;/td&gt;
&lt;td&gt;Auth, payments, permissions, infrastructure, data access.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI allowed for learning&lt;/td&gt;
&lt;td&gt;Explanation, docs, debugging, practice tasks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer owns final output&lt;/td&gt;
&lt;td&gt;No hiding behind the model.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is not anti-AI. That is professional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;AI policy is now part of junior hiring. Companies can either define it clearly or keep using it as hidden gatekeeping.&lt;/p&gt;

&lt;p&gt;The serious path is obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allow learning&lt;/li&gt;
&lt;li&gt;protect private data&lt;/li&gt;
&lt;li&gt;require verification&lt;/li&gt;
&lt;li&gt;inspect the work&lt;/li&gt;
&lt;li&gt;teach the judgment&lt;/li&gt;
&lt;li&gt;stop pretending AI is not part of the modern developer stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Juniors do not need permission to be reckless. They need clear rules for being responsible.&lt;/p&gt;

&lt;p&gt;If companies cannot provide those rules, they should stop calling the confusion a candidate-quality problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/ai" class="crayons-btn crayons-btn--primary"&gt;Interested in AI tooling, junior developers, and hiring? Explore #ai on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>career</category>
      <category>careerdevelopment</category>
      <category>hiring</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Review the Logic, Not Whether the Junior Used AI</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:36:56 +0000</pubDate>
      <link>https://dev.to/bradleymatera/review-the-logic-not-whether-the-junior-used-ai-3f5j</link>
      <guid>https://dev.to/bradleymatera/review-the-logic-not-whether-the-junior-used-ai-3f5j</guid>
      <description>&lt;p&gt;Code review has a new lazy question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Did AI write this?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes that question matters.&lt;/p&gt;

&lt;p&gt;If private code was pasted into an unapproved tool, it matters.&lt;/p&gt;

&lt;p&gt;If generated code was shipped without understanding, it matters.&lt;/p&gt;

&lt;p&gt;If the team has a compliance policy, it matters.&lt;/p&gt;

&lt;p&gt;But as a review standard, that question is weak.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is this code correct, tested, maintainable, and owned by the person submitting it?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That standard catches bad AI code. It also catches bad human code.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/quixyofficial-coding-programming-programmer-XFwz7MTThaOVQ9RhB5" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExajQ4cWJtbHhxaDhwamtqYWRmM2NwYTVlYTZ2eGF3aXdpMXlubXdlYyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FXFwz7MTThaOVQ9RhB5%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/quixyofficial-coding-programming-programmer-XFwz7MTThaOVQ9RhB5" rel="noopener noreferrer" class="c-link"&gt;
            Coding Computer Science GIF by Quixy - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Coding Computer Science GIF by Quixy with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  AI panic can hide ordinary review failures
&lt;/h2&gt;

&lt;p&gt;Take a SQL example.&lt;/p&gt;

&lt;p&gt;A report needs to include analytics events even when the segment reference is missing, because missing references are part of the data-quality signal.&lt;/p&gt;

&lt;p&gt;The wrong query looks clean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segment_id&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;analytics_events&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleted_at&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is the &lt;code&gt;JOIN&lt;/code&gt;. It drops rows without matching segment records.&lt;/p&gt;

&lt;p&gt;If missing segment references are supposed to remain visible, the query needs a &lt;code&gt;LEFT JOIN&lt;/code&gt; and an explicit signal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;missing_segment&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;analytics_events&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;segment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleted_at&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That bug has nothing to do with whether AI was used.&lt;/p&gt;

&lt;p&gt;A human can make it. AI can make it. A rushed senior can make it. A junior can make it.&lt;/p&gt;

&lt;p&gt;The review should catch it either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code review is supposed to teach and protect
&lt;/h2&gt;

&lt;p&gt;Research on code review does not describe it as a rubber stamp.&lt;/p&gt;

&lt;p&gt;The 2013 paper &lt;a href="https://2013.icse-conferences.org/content/expectations-outcomes-and-challenges-modern-code-review.html" rel="noopener noreferrer"&gt;Expectations, Outcomes, and Challenges of Modern Code Review&lt;/a&gt; found that while defect finding remains a major motivation, code review also supports knowledge transfer, team awareness, and alternative solution discovery.&lt;/p&gt;

&lt;p&gt;Google's 2018 paper &lt;a href="https://research.google/pubs/pub47025/" rel="noopener noreferrer"&gt;Modern Code Review: A Case Study at Google&lt;/a&gt; describes review as serving readability, education, maintainability, and correctness goals.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-3ff08044-beeb-4510-bafa-2121814c757b" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-3ff08044-beeb-4510-bafa-2121814c757b" alt="Chart: Code review research from 2013 and 2018 frames review as knowledge transfer, education, maintainability, and correctness work" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://2013.icse-conferences.org/content/expectations-outcomes-and-challenges-modern-code-review.html" rel="noopener noreferrer"&gt;ICSE 2013 modern code review paper&lt;/a&gt; and &lt;a href="https://research.google/pubs/pub47025/" rel="noopener noreferrer"&gt;Google Modern Code Review case study&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That matters for juniors. If review only says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This looks AI-generated."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is not teaching anything useful.&lt;/p&gt;

&lt;p&gt;If review says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This join drops orphaned events. Add a fixture that proves missing segments stay visible."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That teaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask review questions that expose behavior
&lt;/h2&gt;

&lt;p&gt;Here is the shift teams need:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Weak review question&lt;/th&gt;
&lt;th&gt;Strong review question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Did AI write this?&lt;/td&gt;
&lt;td&gt;Can the author explain the logic?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is this generated?&lt;/td&gt;
&lt;td&gt;What behavior does this guarantee?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does it look clean?&lt;/td&gt;
&lt;td&gt;What data does it drop?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Did the junior follow policy?&lt;/td&gt;
&lt;td&gt;Did the reviewer verify the assumption?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is this allowed?&lt;/td&gt;
&lt;td&gt;What risk does this introduce?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can we reject it?&lt;/td&gt;
&lt;td&gt;What test would make it safe?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tool-origin question is not useless. It is just not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI disclosure should be boring
&lt;/h2&gt;

&lt;p&gt;Teams need policies that make disclosure normal.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI assistance:
- used AI to understand the existing SQL join behavior
- used AI to brainstorm edge cases
- final query was manually reviewed and tested

Validation:
- added fixture for missing segment reference
- verified deleted events are excluded
- verified active orphaned events remain visible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a reviewable note.&lt;/p&gt;

&lt;p&gt;It gives the reviewer a path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect the behavior&lt;/li&gt;
&lt;li&gt;inspect the test&lt;/li&gt;
&lt;li&gt;ask what was rejected&lt;/li&gt;
&lt;li&gt;verify the edge case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare that with the usual vague policy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use AI responsibly."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not a policy. That is a future argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests are where the tool debate gets real
&lt;/h2&gt;

&lt;p&gt;For the SQL example, a useful test fixture includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;event with valid segment&lt;/li&gt;
&lt;li&gt;event with missing segment&lt;/li&gt;
&lt;li&gt;deleted event&lt;/li&gt;
&lt;li&gt;expected output that preserves the missing-segment row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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;preserves active analytics events with missing segment references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;seedAnalyticsEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;segmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;known-segment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deletedAt&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;seedAnalyticsEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;segmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;missing-segment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deletedAt&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;seedAnalyticsEvent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;segmentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deleted-segment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;deletedAt&lt;/span&gt;&lt;span class="p"&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="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reportRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCampaignSegmentRows&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="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&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="nf"&gt;objectContaining&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;missing_segment&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="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;objectContaining&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;missing_segment&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That test does not care who wrote the query. It cares whether the business rule survives.&lt;/p&gt;

&lt;p&gt;That is the right level of discipline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developers already know AI is unreliable
&lt;/h2&gt;

&lt;p&gt;The common narrative is that juniors trust AI too much.&lt;/p&gt;

&lt;p&gt;Some do. But the broader developer population is not blindly confident either.&lt;/p&gt;

&lt;p&gt;Stack Overflow's 2025 Developer Survey says more developers distrust AI output accuracy than trust it: 46% versus 33%. It also says the biggest frustration is AI answers that are "almost right, but not quite." [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" alt="Chart: Stack Overflow 2025 shows 46% distrust AI output accuracy, 33% trust it, and 66% cite almost-right answers as a frustration" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That phrase should be printed above every code review tool:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;almost right, but not quite&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the danger zone. It applies to human code too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad AI use versus smart AI use
&lt;/h2&gt;

&lt;p&gt;Bad AI use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate code&lt;/li&gt;
&lt;li&gt;paste it&lt;/li&gt;
&lt;li&gt;cannot explain it&lt;/li&gt;
&lt;li&gt;no tests&lt;/li&gt;
&lt;li&gt;no docs&lt;/li&gt;
&lt;li&gt;no edge cases&lt;/li&gt;
&lt;li&gt;hide the tool use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Smart AI use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ask AI to explain unfamiliar code&lt;/li&gt;
&lt;li&gt;ask for edge cases&lt;/li&gt;
&lt;li&gt;compare with docs&lt;/li&gt;
&lt;li&gt;write or improve tests&lt;/li&gt;
&lt;li&gt;reject wrong suggestions&lt;/li&gt;
&lt;li&gt;disclose meaningful help&lt;/li&gt;
&lt;li&gt;own the final change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Teams should punish the first pattern and teach the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  The senior double standard
&lt;/h2&gt;

&lt;p&gt;The uncomfortable part is that many seniors have a double standard.&lt;/p&gt;

&lt;p&gt;They treat junior AI use as suspicious but treat senior intuition as trustworthy.&lt;/p&gt;

&lt;p&gt;That is not engineering. Engineering is evidence.&lt;/p&gt;

&lt;p&gt;A senior's hand-written code can still be wrong.&lt;/p&gt;

&lt;p&gt;A junior's AI-assisted code can still be correct.&lt;/p&gt;

&lt;p&gt;Neither gets a free pass.&lt;/p&gt;

&lt;p&gt;The standard should be:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Explain the code&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test risky behavior&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow privacy policy&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disclose required AI use&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept review&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own production impact&lt;/td&gt;
&lt;td&gt;Everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is how teams avoid turning AI policy into status politics.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hiring managers should ask
&lt;/h2&gt;

&lt;p&gt;If companies want AI-aware juniors, they should evaluate AI-aware review skills.&lt;/p&gt;

&lt;p&gt;Ask candidates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How would you verify AI-generated code?&lt;/li&gt;
&lt;li&gt;What makes an AI answer unsafe?&lt;/li&gt;
&lt;li&gt;When would you refuse to use generated output?&lt;/li&gt;
&lt;li&gt;How would you test this SQL query?&lt;/li&gt;
&lt;li&gt;What would you disclose in a PR?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is better than pretending AI does not exist. It is also better than rewarding candidates who hide their workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Review the logic. Review the tests. Review the assumptions. Review the data that disappears.&lt;/p&gt;

&lt;p&gt;Review the security boundary. Review the production risk.&lt;/p&gt;

&lt;p&gt;Yes, review AI usage too.&lt;/p&gt;

&lt;p&gt;But do not confuse tool suspicion with engineering rigor.&lt;/p&gt;

&lt;p&gt;The goal is not to keep AI out of the conversation. The goal is to keep bad code out of production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/code-review" class="crayons-btn crayons-btn--primary"&gt;Interested in code review, AI, and engineering culture? Explore #code-review on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sql</category>
      <category>hiring</category>
      <category>career</category>
    </item>
    <item>
      <title>Stop Hiring One Junior to Be the Whole Engineering Department</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:35:56 +0000</pubDate>
      <link>https://dev.to/bradleymatera/stop-hiring-one-junior-to-be-the-whole-engineering-department-koa</link>
      <guid>https://dev.to/bradleymatera/stop-hiring-one-junior-to-be-the-whole-engineering-department-koa</guid>
      <description>&lt;p&gt;One of the worst hiring patterns in tech is the "junior full-stack owner."&lt;/p&gt;

&lt;p&gt;The title says junior.&lt;/p&gt;

&lt;p&gt;The job says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build the UI&lt;/li&gt;
&lt;li&gt;write the API&lt;/li&gt;
&lt;li&gt;design the database&lt;/li&gt;
&lt;li&gt;deploy to cloud&lt;/li&gt;
&lt;li&gt;manage CI/CD&lt;/li&gt;
&lt;li&gt;write tests&lt;/li&gt;
&lt;li&gt;handle analytics&lt;/li&gt;
&lt;li&gt;debug production&lt;/li&gt;
&lt;li&gt;talk to support&lt;/li&gt;
&lt;li&gt;understand security&lt;/li&gt;
&lt;li&gt;use AI responsibly&lt;/li&gt;
&lt;li&gt;move fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not a junior role. It is an underfunded engineering department wearing a junior title.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/cc0studios-laptop-work-from-home-excited-on-6MnZfHwQ4anmIS08LG" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExdXV3a2RodWtrM2xhMDEyaWM3cTg5eDB0cnF2dnVvNTJ3a3VzYWVkeiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2F6MnZfHwQ4anmIS08LG%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/cc0studios-laptop-work-from-home-excited-on-6MnZfHwQ4anmIS08LG" rel="noopener noreferrer" class="c-link"&gt;
            Work From Home Leaf GIF by CC0 Studios - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Work From Home Leaf GIF by CC0 Studios with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Scope is the hidden hiring failure
&lt;/h2&gt;

&lt;p&gt;The industry talks a lot about skill gaps. It talks less about scope gaps.&lt;/p&gt;

&lt;p&gt;A junior can learn React. A junior can learn SQL. A junior can learn AWS basics. A junior can learn testing.&lt;/p&gt;

&lt;p&gt;But a junior cannot safely be the primary owner for every layer of a production system without support.&lt;/p&gt;

&lt;p&gt;That is not because juniors are weak. It is because production systems are multi-disciplinary.&lt;/p&gt;

&lt;p&gt;Frontend work requires accessibility, state management, browser behavior, design constraints, and product judgment.&lt;/p&gt;

&lt;p&gt;Backend work requires API design, data modeling, validation, concurrency, error handling, and performance awareness.&lt;/p&gt;

&lt;p&gt;Infrastructure work requires networking, secrets, deployment, observability, rollback, permissions, and cost control.&lt;/p&gt;

&lt;p&gt;Support work requires incident judgment, user empathy, logging, triage, and communication.&lt;/p&gt;

&lt;p&gt;Those are different skill families. Calling all of them "full-stack" does not make the scope reasonable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The market rewards impossible wish lists
&lt;/h2&gt;

&lt;p&gt;Indeed Hiring Lab reported that tech postings have shifted toward higher experience requirements, with the share asking for at least five years of experience rising from 37% to 42% between Q2 2022 and Q2 2025. [&lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" alt="Chart: Tech job postings asking for at least five years of experience rose from 37% in Q2 2022 to 42% in Q2 2025" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;NACE reports growing use of skills-based hiring for entry-level roles. [&lt;a href="https://www.naceweb.org/job-market/trends-and-predictions/employer-use-of-skills-based-hiring-practices-grows" rel="noopener noreferrer"&gt;NACE&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That combination can be useful if companies define the skills clearly.&lt;/p&gt;

&lt;p&gt;It becomes harmful when the skill list turns into:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Everything our team is missing."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bad hiring logic looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Business need&lt;/th&gt;
&lt;th&gt;Bad junior requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;We need a frontend fix&lt;/td&gt;
&lt;td&gt;Must know React, design systems, accessibility, analytics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;We need API work&lt;/td&gt;
&lt;td&gt;Must know Node, Python, SQL, auth, caching.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;We need deployment help&lt;/td&gt;
&lt;td&gt;Must know AWS, Docker, Kubernetes, Terraform.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;We need quality&lt;/td&gt;
&lt;td&gt;Must know unit, integration, E2E, and load testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;We need velocity&lt;/td&gt;
&lt;td&gt;Must know AI tools and ship independently.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;We need coverage&lt;/td&gt;
&lt;td&gt;Must join support rotation immediately.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is not skills-based hiring. That is panic-based hiring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production reliability is not a junior checkbox
&lt;/h2&gt;

&lt;p&gt;Reliability work is a good example.&lt;/p&gt;

&lt;p&gt;Companies often expect juniors to understand retry logic, circuit breakers, queues, dead-letter handling, monitoring, and incident response while never giving them a safe path to learn those concepts.&lt;/p&gt;

&lt;p&gt;Microsoft's Azure Architecture Center describes the &lt;a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker" rel="noopener noreferrer"&gt;Circuit Breaker pattern&lt;/a&gt; as a way to handle faults that may take time to recover from when an application connects to a remote service or resource.&lt;/p&gt;

&lt;p&gt;Google's SRE book chapter on &lt;a href="https://sre.google/sre-book/addressing-cascading-failures/" rel="noopener noreferrer"&gt;cascading failures&lt;/a&gt; explains how failures can amplify across systems, especially when retry behavior and overload are handled badly.&lt;/p&gt;

&lt;p&gt;Those are not beginner concepts. They are teachable concepts. There is a difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI can name the pattern. It cannot own the blast radius.
&lt;/h2&gt;

&lt;p&gt;AI is useful here.&lt;/p&gt;

&lt;p&gt;A junior can ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What pattern prevents one failing upstream service from taking down the whole ingestion pipeline?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer might point toward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;circuit breaker&lt;/li&gt;
&lt;li&gt;retry with backoff&lt;/li&gt;
&lt;li&gt;bulkhead isolation&lt;/li&gt;
&lt;li&gt;dead-letter queue&lt;/li&gt;
&lt;li&gt;schema validation&lt;/li&gt;
&lt;li&gt;graceful degradation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is valuable. But knowing the name of a pattern is not the same as owning production risk.&lt;/p&gt;

&lt;p&gt;The junior still needs help deciding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when the circuit opens&lt;/li&gt;
&lt;li&gt;when it closes&lt;/li&gt;
&lt;li&gt;what gets dropped&lt;/li&gt;
&lt;li&gt;what gets retried&lt;/li&gt;
&lt;li&gt;how operators are alerted&lt;/li&gt;
&lt;li&gt;what users see&lt;/li&gt;
&lt;li&gt;what metrics prove it worked&lt;/li&gt;
&lt;li&gt;how to remove or replace the mitigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where mentorship matters. AI can shorten discovery. It cannot replace operational judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  "No hacks" is often fake discipline
&lt;/h2&gt;

&lt;p&gt;Another leadership mistake is rejecting temporary mitigations because they sound messy.&lt;/p&gt;

&lt;p&gt;Teams say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We do not do hacks."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes that is discipline. Sometimes it is an excuse to avoid making a hard risk trade-off.&lt;/p&gt;

&lt;p&gt;There is a real difference between a sloppy patch and a responsible mitigation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sloppy patch&lt;/th&gt;
&lt;th&gt;Responsible mitigation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hidden behavior&lt;/td&gt;
&lt;td&gt;Documented behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No owner&lt;/td&gt;
&lt;td&gt;Named owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No tests&lt;/td&gt;
&lt;td&gt;Test for failure mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No observability&lt;/td&gt;
&lt;td&gt;Logs, metrics, alerting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No end date&lt;/td&gt;
&lt;td&gt;Removal or replacement condition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pretends to be final&lt;/td&gt;
&lt;td&gt;Explicitly buys time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Juniors should learn that distinction. Companies should teach it.&lt;/p&gt;

&lt;p&gt;Instead, many teams give juniors vague slogans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no hacks&lt;/li&gt;
&lt;li&gt;move fast&lt;/li&gt;
&lt;li&gt;own your work&lt;/li&gt;
&lt;li&gt;think like a senior&lt;/li&gt;
&lt;li&gt;use AI but be careful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are slogans, not operating instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  A realistic junior production path
&lt;/h2&gt;

&lt;p&gt;If companies want juniors to learn production work, they need staged exposure.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Good junior scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Observe&lt;/td&gt;
&lt;td&gt;Watch incident reviews and deployment rollbacks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pair&lt;/td&gt;
&lt;td&gt;Debug logs with a senior during low-risk issues.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implement&lt;/td&gt;
&lt;td&gt;Add tests, alerts, or small guardrails with review.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shadow&lt;/td&gt;
&lt;td&gt;Join support rotation without being primary.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own small surface&lt;/td&gt;
&lt;td&gt;Maintain a limited component with backup.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expand&lt;/td&gt;
&lt;td&gt;Take larger production ownership after evidence.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" alt="Chart: A realistic junior ramp grows scope from week one through month twelve instead of assigning full production ownership immediately" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: Author framework for staged junior onboarding.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is how production judgment develops. Not by throwing a junior into a multi-layer system and calling it "ownership."&lt;/p&gt;

&lt;h2&gt;
  
  
  AI adds another layer of pressure
&lt;/h2&gt;

&lt;p&gt;Stack Overflow's 2025 survey says AI use is widespread among developers, but trust is low. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Handshake reports that 70% of hiring leaders say AI will change entry-level role requirements. [&lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" alt="Chart: 70% of hiring leaders say AI will change entry-level role requirements" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake Class of 2026 AI economy research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That means juniors are now expected to know the tool and know when not to trust the tool. That is a sophisticated skill.&lt;/p&gt;

&lt;p&gt;If companies add AI to already bloated junior roles without training, they are not modernizing. They are increasing risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the role like you mean it
&lt;/h2&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Junior Full-Stack Developer
Must own frontend, backend, AWS deployments, testing, analytics, and production support.
Experience with AI coding tools preferred.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Junior Product Engineer
First 90 days focus on frontend bug fixes, API integration tasks, test coverage, and guided deployments.
Production support begins as shadowing only.
AI tools are allowed for learning and drafting, with disclosure and review rules.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second version is still ambitious. It is also honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Companies cannot complain that juniors are not production-ready while designing junior roles with production blast radius and no training path.&lt;/p&gt;

&lt;p&gt;If the role spans frontend, backend, cloud, DevOps, testing, analytics, support, and AI tooling, the candidate is not the problem.&lt;/p&gt;

&lt;p&gt;The scope is.&lt;/p&gt;

&lt;p&gt;A junior can grow into broad ownership. They should not be used as a cheap replacement for a missing team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/production" class="crayons-btn crayons-btn--primary"&gt;Interested in production engineering, hiring, and junior developer growth? Explore #production on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>careerdevelopment</category>
      <category>hiring</category>
    </item>
    <item>
      <title>Senior Engineers Complaining About Juniors Are Missing the Point</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:34:40 +0000</pubDate>
      <link>https://dev.to/bradleymatera/senior-engineers-complaining-about-juniors-are-missing-the-point-2ch6</link>
      <guid>https://dev.to/bradleymatera/senior-engineers-complaining-about-juniors-are-missing-the-point-2ch6</guid>
      <description>&lt;p&gt;Senior engineers love complaining about juniors.&lt;/p&gt;

&lt;p&gt;They complain juniors do not understand fundamentals.&lt;/p&gt;

&lt;p&gt;They complain juniors use AI too much.&lt;/p&gt;

&lt;p&gt;They complain juniors ask basic questions.&lt;/p&gt;

&lt;p&gt;They complain juniors cannot debug production systems.&lt;/p&gt;

&lt;p&gt;Some of those complaints are true. They are also incomplete.&lt;/p&gt;

&lt;p&gt;Because the same industry that complains about junior quality spent years weakening the systems that used to create it.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/dubsado-teamwork-WOTtToQqAArtvgBggf" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExbTA0bTU2Y2xoM25oMXFrODF0ZTJuNDZvOGMwM3VsbmNlcnI0c3l0aSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FWOTtToQqAArtvgBggf%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/dubsado-teamwork-WOTtToQqAArtvgBggf" rel="noopener noreferrer" class="c-link"&gt;
            Teamwork GIF by Dubsado - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Teamwork GIF by Dubsado with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Juniors are not supposed to arrive finished
&lt;/h2&gt;

&lt;p&gt;A junior developer is not a discounted senior.&lt;/p&gt;

&lt;p&gt;A junior is a developer with potential, fundamentals in progress, limited production context, and a real need for feedback.&lt;/p&gt;

&lt;p&gt;That should not be controversial. Many companies still act like it is.&lt;/p&gt;

&lt;p&gt;They hire a junior and expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;independent delivery&lt;/li&gt;
&lt;li&gt;production debugging&lt;/li&gt;
&lt;li&gt;architectural judgment&lt;/li&gt;
&lt;li&gt;stakeholder communication&lt;/li&gt;
&lt;li&gt;cloud deployment&lt;/li&gt;
&lt;li&gt;test strategy&lt;/li&gt;
&lt;li&gt;security intuition&lt;/li&gt;
&lt;li&gt;codebase navigation&lt;/li&gt;
&lt;li&gt;product sense&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are learned abilities, not personality traits.&lt;/p&gt;

&lt;p&gt;If the company does not teach them, the company should not be shocked when the junior learns from AI, YouTube, old docs, Stack Overflow, Discord, Reddit, and trial-and-error.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mentorship gap is not mysterious
&lt;/h2&gt;

&lt;p&gt;Good junior development requires slack in the system. Somebody has to have time to teach.&lt;/p&gt;

&lt;p&gt;Someone has to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explain the codebase&lt;/li&gt;
&lt;li&gt;review PRs with reasoning&lt;/li&gt;
&lt;li&gt;answer questions without making the junior feel stupid&lt;/li&gt;
&lt;li&gt;give scoped tasks&lt;/li&gt;
&lt;li&gt;connect bugs to system concepts&lt;/li&gt;
&lt;li&gt;show how production incidents are handled&lt;/li&gt;
&lt;li&gt;explain trade-offs&lt;/li&gt;
&lt;li&gt;model debugging&lt;/li&gt;
&lt;li&gt;call out risk before it becomes blame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That takes time. Companies cut that time first.&lt;/p&gt;

&lt;p&gt;Then they complain the pipeline is weak.&lt;/p&gt;

&lt;p&gt;That is not a junior problem. It is a resource allocation problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Psychological safety is not office decor
&lt;/h2&gt;

&lt;p&gt;The research on team learning has been clear for a long time.&lt;/p&gt;

&lt;p&gt;Amy Edmondson's 1999 paper, &lt;a href="https://journals.sagepub.com/doi/pdf/10.2307/2666999" rel="noopener noreferrer"&gt;Psychological Safety and Learning Behavior in Work Teams&lt;/a&gt;, studied 51 work teams and found psychological safety was associated with learning behavior.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-19b4fbd4-91f8-4612-8233-585c2bda17f8" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-19b4fbd4-91f8-4612-8233-585c2bda17f8" alt="Chart: Edmondson's psychological safety study examined 51 work teams" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://journals.sagepub.com/doi/pdf/10.2307/2666999" rel="noopener noreferrer"&gt;Psychological Safety and Learning Behavior in Work Teams&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That matters in engineering because juniors learn by taking small interpersonal risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I do not understand this code."&lt;/li&gt;
&lt;li&gt;"I think this bug is deeper than the UI."&lt;/li&gt;
&lt;li&gt;"I used AI to understand the error, but I want to verify it."&lt;/li&gt;
&lt;li&gt;"I do not know whether this is safe."&lt;/li&gt;
&lt;li&gt;"Can you explain why this pattern is preferred?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If asking those questions gets punished, juniors stop asking.&lt;/p&gt;

&lt;p&gt;Then seniors say juniors are quiet, passive, or not curious.&lt;/p&gt;

&lt;p&gt;That is the predictable result of a team that punishes learning out loud.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI fills the space mentorship left open
&lt;/h2&gt;

&lt;p&gt;Stack Overflow's 2025 Developer Survey says 44% of developers used AI-enabled tools to learn coding techniques or a new language. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;GitHub's Octoverse 2025 report says nearly 80% of new developers on GitHub used Copilot within their first week. [&lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" alt="Chart: Developer AI adoption and learning signals, including Stack Overflow AI learning use and GitHub Copilot first-week usage for new developers" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt; and &lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the part senior engineers need to take seriously: AI is not only being used to generate code.&lt;/p&gt;

&lt;p&gt;It is being used because juniors need explanations and often cannot get them from people.&lt;/p&gt;

&lt;p&gt;AI answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is this error?&lt;/li&gt;
&lt;li&gt;What does this SQL join do?&lt;/li&gt;
&lt;li&gt;Why is this React state stale?&lt;/li&gt;
&lt;li&gt;What is a race condition?&lt;/li&gt;
&lt;li&gt;How do I write a test for this?&lt;/li&gt;
&lt;li&gt;What should I ask in code review?&lt;/li&gt;
&lt;li&gt;What edge cases might I be missing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That does not make AI a mentor. It makes AI the thing juniors reach for when the actual mentor is unavailable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old learning culture had shortcuts too
&lt;/h2&gt;

&lt;p&gt;It is dishonest to act like older developers learned only through deep first-principles study.&lt;/p&gt;

&lt;p&gt;Previous generations used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack Overflow answers&lt;/li&gt;
&lt;li&gt;snippets from blogs&lt;/li&gt;
&lt;li&gt;copied config files&lt;/li&gt;
&lt;li&gt;starter templates&lt;/li&gt;
&lt;li&gt;WordPress themes&lt;/li&gt;
&lt;li&gt;Bootstrap examples&lt;/li&gt;
&lt;li&gt;jQuery plugins&lt;/li&gt;
&lt;li&gt;internal code copied from older services&lt;/li&gt;
&lt;li&gt;tutorials that skipped production concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some developers learned deeply through those shortcuts. Some cargo-culted them.&lt;/p&gt;

&lt;p&gt;That same distinction matters with AI.&lt;/p&gt;

&lt;p&gt;The question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the junior use outside help?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the junior build understanding?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Review the thinking, not just the diff
&lt;/h2&gt;

&lt;p&gt;A senior who wants better juniors should stop reviewing only the final diff. Review the thinking.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Review question&lt;/th&gt;
&lt;th&gt;What it teaches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What problem is this solving?&lt;/td&gt;
&lt;td&gt;Product framing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What did you try first?&lt;/td&gt;
&lt;td&gt;Debugging process.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What did AI suggest that you rejected?&lt;/td&gt;
&lt;td&gt;Judgment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What edge case worries you?&lt;/td&gt;
&lt;td&gt;Risk awareness.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What test proves this behavior?&lt;/td&gt;
&lt;td&gt;Verification.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What part of this system do you still not understand?&lt;/td&gt;
&lt;td&gt;Learning path.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is how review becomes mentorship.&lt;/p&gt;

&lt;p&gt;Without that, review becomes a gate. Gates do not create seniors. Mentorship does.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI dependence is a real risk
&lt;/h2&gt;

&lt;p&gt;There is a real danger in AI-assisted learning.&lt;/p&gt;

&lt;p&gt;The paper &lt;em&gt;The Widening Gap&lt;/em&gt; found that generative AI can help novice programmers, but weaker students may struggle more to ignore incorrect or unhelpful suggestions. [&lt;a href="https://arxiv.org/abs/2405.17739" rel="noopener noreferrer"&gt;The Widening Gap&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 systematic review on GenAI and code comprehension found that AI explanations can support comprehension, but can also be inaccurate or difficult for novices to evaluate. [&lt;a href="https://arxiv.org/abs/2510.17894" rel="noopener noreferrer"&gt;Code comprehension SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That means teams should not tell juniors:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Just use AI."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They should teach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to verify generated output&lt;/li&gt;
&lt;li&gt;how to compare against docs&lt;/li&gt;
&lt;li&gt;how to write tests&lt;/li&gt;
&lt;li&gt;how to reject confident wrong answers&lt;/li&gt;
&lt;li&gt;how to disclose meaningful AI assistance&lt;/li&gt;
&lt;li&gt;when to ask a human&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is modern mentorship. Not nostalgia. Not tool panic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The management failure nobody wants to own
&lt;/h2&gt;

&lt;p&gt;Many companies removed the apprenticeship layer and replaced it with vibes.&lt;/p&gt;

&lt;p&gt;They have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no onboarding map&lt;/li&gt;
&lt;li&gt;no junior-safe backlog&lt;/li&gt;
&lt;li&gt;no mentor capacity&lt;/li&gt;
&lt;li&gt;no documentation budget&lt;/li&gt;
&lt;li&gt;no pairing culture&lt;/li&gt;
&lt;li&gt;no AI policy&lt;/li&gt;
&lt;li&gt;no explicit progression rubric&lt;/li&gt;
&lt;li&gt;no time for seniors to teach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then they ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why are juniors not ready?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because nobody built readiness. That is the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real junior pipeline looks like
&lt;/h2&gt;

&lt;p&gt;A serious junior pipeline does not need to be fancy. It needs to be intentional.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Timeframe&lt;/th&gt;
&lt;th&gt;What should happen&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Week 1&lt;/td&gt;
&lt;td&gt;Environment setup, product overview, first docs fix, mentor assigned.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month 1&lt;/td&gt;
&lt;td&gt;Small bug fixes, guided PRs, test-writing practice, codebase map.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month 2&lt;/td&gt;
&lt;td&gt;Slightly larger feature work with review checkpoints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month 3&lt;/td&gt;
&lt;td&gt;Limited ownership of a small surface area.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month 6&lt;/td&gt;
&lt;td&gt;Participation in production support with shadowing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month 12&lt;/td&gt;
&lt;td&gt;Clear evaluation for mid-level readiness.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is not charity. That is workforce development.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" alt="Chart: A realistic junior ramp grows scope from week one through month twelve" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: Author framework for staged junior onboarding.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Senior engineers are allowed to expect rigor. They are not allowed to pretend rigor appears without teaching.&lt;/p&gt;

&lt;p&gt;If juniors use AI badly, correct the behavior.&lt;/p&gt;

&lt;p&gt;If juniors use AI to learn, review the learning.&lt;/p&gt;

&lt;p&gt;If juniors cannot explain their code, teach them how to explain it.&lt;/p&gt;

&lt;p&gt;But stop acting like the new generation failed a system that the old generation forgot to maintain.&lt;/p&gt;

&lt;p&gt;The next senior engineers will not appear by accident. Somebody has to build them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/career" class="crayons-btn crayons-btn--primary"&gt;Interested in mentorship, junior developers, and engineering culture? Explore #career on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hiring</category>
      <category>career</category>
      <category>mentorship</category>
    </item>
    <item>
      <title>Entry-Level Job Descriptions Are Becoming Broken Product Specs</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:33:15 +0000</pubDate>
      <link>https://dev.to/bradleymatera/entry-level-job-descriptions-are-becoming-broken-product-specs-hgc</link>
      <guid>https://dev.to/bradleymatera/entry-level-job-descriptions-are-becoming-broken-product-specs-hgc</guid>
      <description>&lt;p&gt;A lot of "entry-level developer" job descriptions are not entry-level.&lt;/p&gt;

&lt;p&gt;They are broken product specs.&lt;/p&gt;

&lt;p&gt;They ask for one person to build frontend features, debug backend APIs, write SQL, manage cloud infrastructure, understand CI/CD, test everything, talk to stakeholders, support production, know security basics, and somehow still be "junior."&lt;/p&gt;

&lt;p&gt;That is not an entry-level role.&lt;/p&gt;

&lt;p&gt;That is a company trying to buy a small engineering team at junior pricing.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/Biteable-biteable-biteableanimation-humanresources-KQzmhm1sowxyxU6e3v" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExenE3d2R5ajAzczdtbndxcnJ2czN4YnE0Y2Nsc2thdm1qOWtzMGt1YSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FKQzmhm1sowxyxU6e3v%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/Biteable-biteable-biteableanimation-humanresources-KQzmhm1sowxyxU6e3v" rel="noopener noreferrer" class="c-link"&gt;
            Animation Hiring GIF by Biteable - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Animation Hiring GIF by Biteable with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The market is saying two things at once
&lt;/h2&gt;

&lt;p&gt;The long-term outlook for software developers is still strong.&lt;/p&gt;

&lt;p&gt;The U.S. Bureau of Labor Statistics projects software developer employment to grow 15.8% from 2024 to 2034, adding 267,700 jobs. [&lt;a href="https://www.bls.gov/opub/mlr/2026/article/industry-and-occupational-employment-projections-overview.htm" rel="noopener noreferrer"&gt;BLS projections&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-e8590180-bec4-483b-b024-1505f77206c0" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-e8590180-bec4-483b-b024-1505f77206c0" alt="Chart: BLS projects software developer employment growing from about 1.69 million jobs in 2024 to about 1.96 million jobs in 2034" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.bls.gov/opub/mlr/2026/article/industry-and-occupational-employment-projections-overview.htm" rel="noopener noreferrer"&gt;BLS employment projections&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But the entry point is getting narrower.&lt;/p&gt;

&lt;p&gt;Indeed Hiring Lab reported that from Q2 2022 to Q2 2025, the share of tech job postings asking for at least five years of experience rose from 37% to 42%. The report specifically notes that the environment became more challenging for entry-level and early-career tech job seekers. [&lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" alt="Chart: Tech job postings asking for at least five years of experience rose from 37% in Q2 2022 to 42% in Q2 2025" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That creates a broken labor-market shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;software work is projected to grow&lt;/li&gt;
&lt;li&gt;companies still need engineers&lt;/li&gt;
&lt;li&gt;job postings increasingly favor experienced candidates&lt;/li&gt;
&lt;li&gt;juniors are told to "get experience" before anyone will give them experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not just a candidate-quality problem. It is a pipeline design problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The imaginary junior candidate
&lt;/h2&gt;

&lt;p&gt;Here is a common bad hiring pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Why it is a red flag for "junior"&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3-5 years of production experience&lt;/td&gt;
&lt;td&gt;That is not entry-level.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React, Node, Python, SQL, AWS, Docker, Kubernetes&lt;/td&gt;
&lt;td&gt;That is a platform surface, not a junior scope.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own features end to end&lt;/td&gt;
&lt;td&gt;Ownership requires support and context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build and maintain CI/CD&lt;/td&gt;
&lt;td&gt;That is DevOps/platform work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Understand security best practices&lt;/td&gt;
&lt;td&gt;Reasonable as learning goal, unrealistic as solo owner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Work independently from day one&lt;/td&gt;
&lt;td&gt;That means the company does not plan to mentor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Excellent UI/UX instincts&lt;/td&gt;
&lt;td&gt;That is a design skill, not automatically a dev skill.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support production incidents&lt;/td&gt;
&lt;td&gt;Fine with backup, reckless without it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is nothing wrong with wanting broad engineers.&lt;/p&gt;

&lt;p&gt;There is something wrong with calling that role "entry-level" while refusing to say what the company will teach.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-29a1f4cb-737d-4bd4-8005-2ab0e693ea0e" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-29a1f4cb-737d-4bd4-8005-2ab0e693ea0e" alt="Chart: Illustrative comparison showing how a bad junior posting can quietly imply three to five years of production experience" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: Illustrative role-scope comparison based on the job-description pattern discussed in this article, not a market-wide statistic.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills-based hiring can still be lazy
&lt;/h2&gt;

&lt;p&gt;NACE's Job Outlook 2026 data shows employer use of skills-based hiring is growing for entry-level roles. [&lt;a href="https://www.naceweb.org/job-market/trends-and-predictions/employer-use-of-skills-based-hiring-practices-grows" rel="noopener noreferrer"&gt;NACE&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;In theory, that is good. Skills-based hiring can reduce overreliance on degrees, school prestige, and GPA filters.&lt;/p&gt;

&lt;p&gt;But in practice, it can become a new version of the same problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Show us evidence you already performed the job we refuse to train you for."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A portfolio project is useful.&lt;/p&gt;

&lt;p&gt;A take-home project can be useful.&lt;/p&gt;

&lt;p&gt;A technical screen can be useful.&lt;/p&gt;

&lt;p&gt;But none of those prove a junior can safely own ambiguous production work without mentorship.&lt;/p&gt;

&lt;p&gt;They prove the candidate can complete an assessment under artificial constraints.&lt;/p&gt;

&lt;p&gt;Companies confuse those things constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI is now another requirement
&lt;/h2&gt;

&lt;p&gt;Handshake's research on the Class of 2026 in the AI economy found that 70% of hiring leaders say AI will change entry-level role requirements. [&lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" alt="Chart: 70% of hiring leaders say AI will change entry-level role requirements" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake Class of 2026 AI economy research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is probably true. It also raises the question companies keep dodging:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are companies teaching AI-assisted engineering, or are they just adding AI to the list of things juniors are supposed to magically know?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The industry already expects juniors to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;databases&lt;/li&gt;
&lt;li&gt;frontend frameworks&lt;/li&gt;
&lt;li&gt;deployment basics&lt;/li&gt;
&lt;li&gt;security basics&lt;/li&gt;
&lt;li&gt;agile workflow&lt;/li&gt;
&lt;li&gt;product communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompt literacy&lt;/li&gt;
&lt;li&gt;AI code review&lt;/li&gt;
&lt;li&gt;tool privacy&lt;/li&gt;
&lt;li&gt;generated-code risk&lt;/li&gt;
&lt;li&gt;model limitations&lt;/li&gt;
&lt;li&gt;agent workflows&lt;/li&gt;
&lt;li&gt;AI policy compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a real skill stack. It needs training.&lt;/p&gt;

&lt;h2&gt;
  
  
  Older developers used shortcuts too
&lt;/h2&gt;

&lt;p&gt;Older developers often criticize juniors for using AI as if previous generations learned from pure fundamentals alone.&lt;/p&gt;

&lt;p&gt;That is not what happened.&lt;/p&gt;

&lt;p&gt;Previous generations learned through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack Overflow answers&lt;/li&gt;
&lt;li&gt;blog snippets&lt;/li&gt;
&lt;li&gt;jQuery plugins&lt;/li&gt;
&lt;li&gt;Bootstrap templates&lt;/li&gt;
&lt;li&gt;WordPress themes&lt;/li&gt;
&lt;li&gt;forum posts&lt;/li&gt;
&lt;li&gt;copied config files&lt;/li&gt;
&lt;li&gt;outdated but useful tutorials&lt;/li&gt;
&lt;li&gt;internal code copied from another service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue was never "did the developer use outside help?"&lt;/p&gt;

&lt;p&gt;The issue was whether the developer understood the code before shipping it.&lt;/p&gt;

&lt;p&gt;That is still the standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart AI use is not laziness
&lt;/h2&gt;

&lt;p&gt;Stack Overflow's 2025 survey says 84% of respondents are using or planning to use AI tools, and 44% used AI-enabled tools to learn coding techniques or a new language. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;GitHub's Octoverse 2025 report says nearly 80% of new developers on GitHub used Copilot within their first week. [&lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" alt="Chart: Developer AI adoption and learning signals, including Stack Overflow AI use and GitHub Copilot first-week usage for new developers" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt; and &lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the world juniors are entering. Pretending otherwise is not discipline. It is denial.&lt;/p&gt;

&lt;p&gt;Lazy AI use looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paste the output&lt;/li&gt;
&lt;li&gt;do not read it&lt;/li&gt;
&lt;li&gt;do not test it&lt;/li&gt;
&lt;li&gt;do not understand failure cases&lt;/li&gt;
&lt;li&gt;hide the tool use&lt;/li&gt;
&lt;li&gt;ship confidence without comprehension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Smart AI-assisted learning looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ask for explanation&lt;/li&gt;
&lt;li&gt;compare with official docs&lt;/li&gt;
&lt;li&gt;generate test cases&lt;/li&gt;
&lt;li&gt;inspect edge cases&lt;/li&gt;
&lt;li&gt;rewrite in project style&lt;/li&gt;
&lt;li&gt;document assumptions&lt;/li&gt;
&lt;li&gt;ask a human for review where risk is high&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one deserves criticism. The second one deserves coaching.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real junior role has a smaller blast radius
&lt;/h2&gt;

&lt;p&gt;If companies want juniors to succeed, the job description should identify the first 90 days.&lt;/p&gt;

&lt;p&gt;Example of a bad junior scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Own the customer dashboard end-to-end across React, Node, PostgreSQL, AWS, CI/CD, analytics tracking, and production support.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of a better junior scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In the first 90 days, ship small product fixes in the React dashboard, write tests for touched behavior, pair on API changes, and learn the deployment process with a mentor before joining the support rotation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second version is still real work. It just does not pretend the junior is a full product team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the job post should actually say
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;What it should say&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Required skills&lt;/td&gt;
&lt;td&gt;The minimum needed on day one.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teachable skills&lt;/td&gt;
&lt;td&gt;What the company expects to train.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First 30 days&lt;/td&gt;
&lt;td&gt;Onboarding, repo setup, first small fixes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First 90 days&lt;/td&gt;
&lt;td&gt;Expected independent scope.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mentorship&lt;/td&gt;
&lt;td&gt;Who reviews work and how often.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI policy&lt;/td&gt;
&lt;td&gt;Approved tools, disclosure rules, privacy limits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support expectations&lt;/td&gt;
&lt;td&gt;Whether production support is shadowed or owned.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation&lt;/td&gt;
&lt;td&gt;How the junior will be judged.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is not extra paperwork. It is basic hiring clarity.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-34d7cb50-ab24-47cf-a36a-70f8d8d9f4db" alt="Chart: A realistic junior ramp grows scope from week one through month twelve instead of pretending day-one ownership is normal" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: Author framework for staged junior onboarding.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The leadership mistake
&lt;/h2&gt;

&lt;p&gt;Many leadership teams do not know whether they want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an apprentice&lt;/li&gt;
&lt;li&gt;a junior developer&lt;/li&gt;
&lt;li&gt;a mid-level developer&lt;/li&gt;
&lt;li&gt;a full-stack generalist&lt;/li&gt;
&lt;li&gt;a platform engineer&lt;/li&gt;
&lt;li&gt;a cheap senior&lt;/li&gt;
&lt;li&gt;a product engineer&lt;/li&gt;
&lt;li&gt;a support engineer who can code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So they write all of it into one job description, then complain about the candidate pool.&lt;/p&gt;

&lt;p&gt;That is backwards. Bad requirements create bad hiring signals.&lt;/p&gt;

&lt;p&gt;If the role is confused, the hiring process will be confused.&lt;/p&gt;

&lt;p&gt;If the hiring process is confused, the team will reject good juniors for not being imaginary candidates.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI does not magically fix the gap
&lt;/h2&gt;

&lt;p&gt;AI does not fix this.&lt;/p&gt;

&lt;p&gt;It can even make the gap worse.&lt;/p&gt;

&lt;p&gt;The paper &lt;em&gt;The Widening Gap&lt;/em&gt; found that generative AI can help novice programmers, but it can also widen differences between learners who can evaluate suggestions and learners who accept bad output too easily. [&lt;a href="https://arxiv.org/abs/2405.17739" rel="noopener noreferrer"&gt;The Widening Gap&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 systematic literature review on junior developers and LLMs found that most studies report both positive and negative perceptions of LLM adoption. [&lt;a href="https://arxiv.org/abs/2503.07556" rel="noopener noreferrer"&gt;Junior developers and LLMs SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That means AI can help juniors climb. It can also hide weak understanding.&lt;/p&gt;

&lt;p&gt;The difference is not moral character. The difference is training, review, and feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Entry-level hiring is broken when the job description asks for a junior title, a mid-level skillset, a senior ownership model, and no mentorship plan.&lt;/p&gt;

&lt;p&gt;Companies can keep blaming juniors.&lt;/p&gt;

&lt;p&gt;Or they can write honest roles.&lt;/p&gt;

&lt;p&gt;If a company wants junior talent, it has to define what the junior is expected to know, what the company will teach, and how AI-assisted learning will be reviewed.&lt;/p&gt;

&lt;p&gt;Anything else is just a broken product spec disguised as hiring.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/hiring" class="crayons-btn crayons-btn--primary"&gt;Interested in hiring, junior developers, and tech careers? Explore #hiring on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>hiring</category>
      <category>career</category>
    </item>
    <item>
      <title>AI Did Not Make Junior Developers Risky. Unreviewed Work Did.</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:31:42 +0000</pubDate>
      <link>https://dev.to/bradleymatera/ai-did-not-make-junior-developers-risky-unreviewed-work-did-51n1</link>
      <guid>https://dev.to/bradleymatera/ai-did-not-make-junior-developers-risky-unreviewed-work-did-51n1</guid>
      <description>&lt;p&gt;The industry talks about junior developers using AI like the junior is the main risk.&lt;/p&gt;

&lt;p&gt;That is too convenient.&lt;/p&gt;

&lt;p&gt;A junior can absolutely ship bad AI-generated code.&lt;/p&gt;

&lt;p&gt;So can a senior.&lt;/p&gt;

&lt;p&gt;So can a staff engineer under deadline pressure.&lt;/p&gt;

&lt;p&gt;So can a team with no tests, unclear ownership, and code review that nitpicks style while missing behavior.&lt;/p&gt;

&lt;p&gt;The problem is not that juniors use tools.&lt;/p&gt;

&lt;p&gt;The problem is companies letting risky work pass through weak systems, then blaming the lowest-status person when something breaks.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/hackerrehab-spamhaus-packettel-spoofed-scans-BBxHxdxHJTN4vYckCL" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExZnlpYXNubDJqbDA5dWZ4ZHJ3MWhpZXdlbWR4NzJuam1sZmI5cThobSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FBBxHxdxHJTN4vYckCL%2Fgiphy.webp" height="218" class="m-0" width="476"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/hackerrehab-spamhaus-packettel-spoofed-scans-BBxHxdxHJTN4vYckCL" rel="noopener noreferrer" class="c-link"&gt;
            Computer Code GIF by HACKER.REHAB - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Computer Code GIF by HACKER.REHAB with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Security shows the double standard
&lt;/h2&gt;

&lt;p&gt;Take a basic authentication example.&lt;/p&gt;

&lt;p&gt;A service verifies a JWT signature but forgets to validate issuer or audience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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 token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The missing checks are the boring part that matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iss&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedIssuer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized token issuer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aud&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expectedAudience&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unexpected token audience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not an "AI problem." It is an engineering-control problem.&lt;/p&gt;

&lt;p&gt;If a junior asks AI, "What claims should a JWT validation path check?" and then uses that answer to inspect the code, that can be a good learning move.&lt;/p&gt;

&lt;p&gt;If anyone copies generated auth code into production without tests or review, that is reckless.&lt;/p&gt;

&lt;p&gt;The difference is verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The risk is real
&lt;/h2&gt;

&lt;p&gt;Security concerns around AI-generated code are real.&lt;/p&gt;

&lt;p&gt;AI can suggest outdated libraries, miss authorization boundaries, invent safe-looking checks, or generate code that passes happy-path tests while failing under real attack scenarios.&lt;/p&gt;

&lt;p&gt;But security risk existed long before AI.&lt;/p&gt;

&lt;p&gt;OWASP's Top 10 lists &lt;a href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/" rel="noopener noreferrer"&gt;Broken Access Control&lt;/a&gt; as the number one 2021 web application security risk category. It also lists &lt;a href="https://owasp.org/Top10/2021/A07_2021-Identification_and_Authentication_Failures/" rel="noopener noreferrer"&gt;Identification and Authentication Failures&lt;/a&gt; as a major category.&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-cc27138d-dbbd-4392-88ac-ae9c0aabac86" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-cc27138d-dbbd-4392-88ac-ae9c0aabac86" alt="Chart: OWASP 2021 ranks Broken Access Control first and Identification and Authentication Failures seventh in the Top 10" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/" rel="noopener noreferrer"&gt;OWASP Broken Access Control&lt;/a&gt; and &lt;a href="https://owasp.org/Top10/2021/A07_2021-Identification_and_Authentication_Failures/" rel="noopener noreferrer"&gt;OWASP Identification and Authentication Failures&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Those are not "junior used ChatGPT" categories. They are systems failing to enforce trust boundaries.&lt;/p&gt;

&lt;p&gt;NIST's &lt;a href="https://csrc.nist.gov/pubs/sp/800/218/final" rel="noopener noreferrer"&gt;Secure Software Development Framework, SP 800-218&lt;/a&gt;, emphasizes secure practices across the software lifecycle, including defined roles, testing, vulnerability review, and risk response.&lt;/p&gt;

&lt;p&gt;Security is a lifecycle responsibility. It cannot be reduced to "did the junior use AI?"&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern that actually breaks teams
&lt;/h2&gt;

&lt;p&gt;Here is the pattern that should worry companies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Weak system&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No clear security checklist&lt;/td&gt;
&lt;td&gt;Review depends on memory and senior availability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No threat modeling&lt;/td&gt;
&lt;td&gt;Teams do not know which risks matter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No auth regression tests&lt;/td&gt;
&lt;td&gt;Small claim-check bugs survive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No AI usage policy&lt;/td&gt;
&lt;td&gt;Tool use becomes hidden or selectively punished.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No safe escalation path&lt;/td&gt;
&lt;td&gt;Juniors stop raising uncomfortable concerns.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No ownership of deferred risk&lt;/td&gt;
&lt;td&gt;"Later" becomes "never."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is how security bugs survive. Not because a junior asked an AI assistant to explain JWTs.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI can teach vocabulary, not judgment
&lt;/h2&gt;

&lt;p&gt;One underrated use of AI is vocabulary.&lt;/p&gt;

&lt;p&gt;Juniors often see a problem before they know how to name it.&lt;/p&gt;

&lt;p&gt;They might notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this token accepts too much&lt;/li&gt;
&lt;li&gt;this endpoint trusts a client field&lt;/li&gt;
&lt;li&gt;this query exposes another tenant's data&lt;/li&gt;
&lt;li&gt;this permission check happens only in the UI&lt;/li&gt;
&lt;li&gt;this webhook handler is not idempotent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI can help map those observations to terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;issuer validation&lt;/li&gt;
&lt;li&gt;audience validation&lt;/li&gt;
&lt;li&gt;broken access control&lt;/li&gt;
&lt;li&gt;authorization bypass&lt;/li&gt;
&lt;li&gt;tenant isolation&lt;/li&gt;
&lt;li&gt;idempotency&lt;/li&gt;
&lt;li&gt;replay risk&lt;/li&gt;
&lt;li&gt;least privilege&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That does not make AI a security reviewer. It makes AI a learning layer.&lt;/p&gt;

&lt;p&gt;The human process still has to verify the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data supports caution, not panic
&lt;/h2&gt;

&lt;p&gt;Stack Overflow's 2025 Developer Survey says AI use is widespread, but trust is low. More developers distrust AI output accuracy than trust it: 46% versus 33%. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" alt="Chart: Stack Overflow 2025 shows 46% distrust AI output accuracy, 33% trust it, and 66% cite almost-right answers as a frustration" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the right posture for security-sensitive work:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;useful, but not trusted blindly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The research on novice programmers is also cautious. &lt;em&gt;The Widening Gap&lt;/em&gt; found that GenAI can help novices complete tasks, but weaker learners may struggle to reject incorrect suggestions. [&lt;a href="https://arxiv.org/abs/2405.17739" rel="noopener noreferrer"&gt;The Widening Gap&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 systematic review on junior developers and LLMs found both positive and negative perceptions across the literature. [&lt;a href="https://arxiv.org/abs/2503.07556" rel="noopener noreferrer"&gt;Junior developers and LLMs SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That is not a ban argument. It is a governance argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review should follow the risk
&lt;/h2&gt;

&lt;p&gt;Teams need different review standards for different code.&lt;/p&gt;

&lt;p&gt;Changing button copy is not the same as changing authentication logic.&lt;/p&gt;

&lt;p&gt;A risk-based review model might look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code area&lt;/th&gt;
&lt;th&gt;AI assistance allowed?&lt;/th&gt;
&lt;th&gt;Review expectation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI copy&lt;/td&gt;
&lt;td&gt;Usually low risk&lt;/td&gt;
&lt;td&gt;Normal review.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Usually low risk&lt;/td&gt;
&lt;td&gt;Visual check.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business logic&lt;/td&gt;
&lt;td&gt;Allowed with validation&lt;/td&gt;
&lt;td&gt;Tests for behavior and edge cases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database migrations&lt;/td&gt;
&lt;td&gt;High caution&lt;/td&gt;
&lt;td&gt;Human review, rollback plan, test data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth and permissions&lt;/td&gt;
&lt;td&gt;High caution&lt;/td&gt;
&lt;td&gt;Security review, threat model, regression tests.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;High caution&lt;/td&gt;
&lt;td&gt;Lifecycle tests, idempotency, reconciliation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets and infrastructure&lt;/td&gt;
&lt;td&gt;High caution&lt;/td&gt;
&lt;td&gt;Approved tooling, least privilege, audit trail.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is stricter than yelling "no AI," and it is more useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bad leadership makes people hide tool use
&lt;/h2&gt;

&lt;p&gt;If leadership treats all AI use as suspicious, juniors will not stop using AI.&lt;/p&gt;

&lt;p&gt;They will stop disclosing it.&lt;/p&gt;

&lt;p&gt;That is worse than disclosure.&lt;/p&gt;

&lt;p&gt;The company loses visibility into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what tools are being used&lt;/li&gt;
&lt;li&gt;what code may have been generated&lt;/li&gt;
&lt;li&gt;what data may have been pasted&lt;/li&gt;
&lt;li&gt;which developers need coaching&lt;/li&gt;
&lt;li&gt;which patterns keep causing confusion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful AI policy should make disclosure normal, not humiliating.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI assistance:
- used for explanation, edge-case brainstorming, or draft code

Developer responsibility:
- author owns final code
- risky code requires tests and human review
- private code may only be used with approved tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives reviewers something concrete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seniors have to review better too
&lt;/h2&gt;

&lt;p&gt;Senior engineers cannot just complain that juniors do not know enough.&lt;/p&gt;

&lt;p&gt;They have to decide whether they are reviewers, mentors, or gatekeepers.&lt;/p&gt;

&lt;p&gt;A useful senior review asks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What behavior does this code guarantee?&lt;/li&gt;
&lt;li&gt;What cases are not covered?&lt;/li&gt;
&lt;li&gt;What did the AI suggest that you rejected?&lt;/li&gt;
&lt;li&gt;Which docs did you verify against?&lt;/li&gt;
&lt;li&gt;What would break if this assumption is wrong?&lt;/li&gt;
&lt;li&gt;How does the test prove the security boundary?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A weak senior review says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This looks AI-generated."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not enough.&lt;/p&gt;

&lt;p&gt;Maybe it is generated. So what?&lt;/p&gt;

&lt;p&gt;Is it correct? Is it tested? Is it safe? Is it maintainable? Does it respect the data boundary?&lt;/p&gt;

&lt;p&gt;Those are the questions that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: JWT validation checklist
&lt;/h2&gt;

&lt;p&gt;For security-sensitive code, teams should teach checklists.&lt;/p&gt;

&lt;p&gt;For JWT validation, a basic review checklist might include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Verify signature&lt;/td&gt;
&lt;td&gt;Confirms token integrity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate issuer&lt;/td&gt;
&lt;td&gt;Rejects tokens from unexpected authorities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate audience&lt;/td&gt;
&lt;td&gt;Ensures token is meant for this service.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate expiration&lt;/td&gt;
&lt;td&gt;Prevents stale token use.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate tenant mapping&lt;/td&gt;
&lt;td&gt;Prevents cross-customer access.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test failure cases&lt;/td&gt;
&lt;td&gt;Confirms invalid tokens are rejected.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log safely&lt;/td&gt;
&lt;td&gt;Helps investigation without leaking secrets.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That checklist is useful no matter who wrote the first draft.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;AI did not make junior developers risky.&lt;/p&gt;

&lt;p&gt;Unreviewed work is risky. Ambiguous ownership is risky. Security-sensitive code without tests is risky. Leadership that punishes disclosure is risky.&lt;/p&gt;

&lt;p&gt;If companies want safer software, they need review systems that inspect behavior, teach risk, and make AI use governable.&lt;/p&gt;

&lt;p&gt;Blaming juniors is easier. It is also weaker engineering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/security" class="crayons-btn crayons-btn--primary"&gt;Interested in security, AI, and engineering review culture? Explore #security on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>security</category>
      <category>auth</category>
      <category>ai</category>
      <category>review</category>
    </item>
    <item>
      <title>Companies Say There Are No Good Juniors. They Mean They Stopped Training Them"</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:23:55 +0000</pubDate>
      <link>https://dev.to/bradleymatera/companies-say-there-are-no-good-juniors-they-mean-they-stopped-training-them-l68</link>
      <guid>https://dev.to/bradleymatera/companies-say-there-are-no-good-juniors-they-mean-they-stopped-training-them-l68</guid>
      <description>&lt;p&gt;Tech has a lazy line it keeps repeating:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"There are no good junior developers anymore."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It sounds like a talent diagnosis.&lt;/p&gt;

&lt;p&gt;It is usually a management confession.&lt;/p&gt;

&lt;p&gt;The industry spent years cutting apprenticeships, thinning mentorship, compressing onboarding, outsourcing training to bootcamps and universities, and turning entry-level job descriptions into mid-level wish lists.&lt;/p&gt;

&lt;p&gt;Now the same companies look at juniors using AI to learn and act shocked.&lt;/p&gt;

&lt;p&gt;That is not serious.&lt;/p&gt;

&lt;p&gt;AI did not create the junior developer problem. It exposed it.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://giphy.com/gifs/clickup-teamwork-collaboration-productivity-qgTeviBmquASJZO08N" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExdndtNHVlY2hycjFoNWM3cmFmOW85OGd3ZjJ0a3Izb2YzYm96am84MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FqgTeviBmquASJZO08N%2Fgiphy.webp" height="270" class="m-0" width="480"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://giphy.com/gifs/clickup-teamwork-collaboration-productivity-qgTeviBmquASJZO08N" rel="noopener noreferrer" class="c-link"&gt;
            Team Teamwork GIF by ClickUp - Find &amp;amp; Share on GIPHY
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Discover &amp;amp; share this Team Teamwork GIF by ClickUp with everyone you know. GIPHY is how you search, share, discover, and create GIFs.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgiphy.com%2Fstatic%2Fimg%2Ffavicon.png" width="16" height="16"&gt;
          giphy.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  The pipeline is the problem
&lt;/h2&gt;

&lt;p&gt;Software is not a dying field.&lt;/p&gt;

&lt;p&gt;The U.S. Bureau of Labor Statistics projects employment for software developers to grow 15.8% from 2024 to 2034, adding 267,700 jobs. That is over five times faster than the all-occupation average in the same projection set. [&lt;a href="https://www.bls.gov/opub/mlr/2026/article/industry-and-occupational-employment-projections-overview.htm" rel="noopener noreferrer"&gt;BLS projections&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-e8590180-bec4-483b-b024-1505f77206c0" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-e8590180-bec4-483b-b024-1505f77206c0" alt="Chart: BLS projects software developer employment growing from about 1.69 million jobs in 2024 to about 1.96 million jobs in 2034" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.bls.gov/opub/mlr/2026/article/industry-and-occupational-employment-projections-overview.htm" rel="noopener noreferrer"&gt;BLS employment projections&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So no, the simple story is not "software is over."&lt;/p&gt;

&lt;p&gt;The problem is the pipeline.&lt;/p&gt;

&lt;p&gt;Companies still need software. They still need engineers. They still need future senior people.&lt;/p&gt;

&lt;p&gt;But many of them do not want to pay the cost of producing those senior people.&lt;/p&gt;

&lt;p&gt;They want developers who are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cheap enough to call junior&lt;/li&gt;
&lt;li&gt;experienced enough to ship like mid-levels&lt;/li&gt;
&lt;li&gt;broad enough to cover full-stack work&lt;/li&gt;
&lt;li&gt;mature enough to self-manage&lt;/li&gt;
&lt;li&gt;fast enough to justify headcount&lt;/li&gt;
&lt;li&gt;compliant enough not to challenge broken scope&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not a junior role.&lt;/p&gt;

&lt;p&gt;That is a budget fantasy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bar moved up
&lt;/h2&gt;

&lt;p&gt;The hiring market has been tightening around experience.&lt;/p&gt;

&lt;p&gt;Indeed Hiring Lab reported that between Q2 2022 and Q2 2025, the share of tech postings asking for at least five years of experience rose from 37% to 42%, while early-career candidates faced a harder environment after the tech posting decline. [&lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-fd6e909d-1f7f-4b4f-8a83-b33e07070c37" alt="Chart: Tech job postings asking for at least five years of experience rose from 37% in Q2 2022 to 42% in Q2 2025" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.hiringlab.org/2025/07/30/experience-requirements-have-tightened-amid-the-tech-hiring-freeze/" rel="noopener noreferrer"&gt;Indeed Hiring Lab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;NACE's Job Outlook 2026 data shows employers are increasing skills-based hiring for entry-level roles. That sounds good until you remember that "skills-based" can mean "prove you already did the job somewhere else." [&lt;a href="https://www.naceweb.org/job-market/trends-and-predictions/employer-use-of-skills-based-hiring-practices-grows" rel="noopener noreferrer"&gt;NACE skills-based hiring&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Handshake's research on the Class of 2026 in the AI economy found that 70% of hiring leaders say AI will change entry-level role requirements. [&lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-46c4a4ed-1f94-4084-bdb6-b06f85a267d5" alt="Chart: 70% of hiring leaders say AI will change entry-level role requirements" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://joinhandshake.com/blog/employers/what-does-ai-mean-for-early-talent-pipeline/" rel="noopener noreferrer"&gt;Handshake Class of 2026 AI economy research&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the entry-level contradiction in plain English:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company says&lt;/th&gt;
&lt;th&gt;Company often means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"We want entry-level talent"&lt;/td&gt;
&lt;td&gt;We want someone already productive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"We hire for skills"&lt;/td&gt;
&lt;td&gt;We want proof you have done production work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"AI is changing the role"&lt;/td&gt;
&lt;td&gt;We have not rewritten onboarding yet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"There are no good juniors"&lt;/td&gt;
&lt;td&gt;We stopped building junior pipelines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"We need ownership"&lt;/td&gt;
&lt;td&gt;We want low-management headcount.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is not a junior failure. It is hiring design failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old learning web is not enough anymore
&lt;/h2&gt;

&lt;p&gt;Older developers sometimes talk as if they learned in a cleaner era.&lt;/p&gt;

&lt;p&gt;They did not.&lt;/p&gt;

&lt;p&gt;They copied Stack Overflow answers. They pasted snippets from blogs. They modified WordPress themes. They followed YouTube tutorials. They used Bootstrap examples. They dropped in jQuery plugins. They learned from forums, old repos, templates, docs, and trial by fire.&lt;/p&gt;

&lt;p&gt;Some of that learning was deep.&lt;/p&gt;

&lt;p&gt;Some of it was shallow.&lt;/p&gt;

&lt;p&gt;That was always true.&lt;/p&gt;

&lt;p&gt;The difference now is that the old web is weaker as the main learning layer.&lt;/p&gt;

&lt;p&gt;Search results are noisier. Framework churn is faster. Tutorials age badly. Many of the most visible beginner resources for older tools are years old, while modern production expectations include testing, deployment, observability, security, accessibility, cloud platforms, CI/CD, API design, analytics, and AI tooling.&lt;/p&gt;

&lt;p&gt;The industry raised the floor while weakening the ladder.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI filled the hole
&lt;/h2&gt;

&lt;p&gt;Stack Overflow's 2025 Developer Survey says 84% of respondents are using or planning to use AI tools, up from 76% the year before. It also says 44% used AI-enabled tools to learn coding techniques or a new language. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;] [&lt;a href="https://stackoverflow.co/company/press/archive/stack-overflow-2025-developer-survey/" rel="noopener noreferrer"&gt;Stack Overflow press release&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-4abf537e-25cd-4472-ba99-d1df8df50aa2" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-4abf537e-25cd-4472-ba99-d1df8df50aa2" alt="Chart: Stack Overflow reported AI tool use or planned use rising from 76% in 2024 to 84% in 2025, while AI-enabled learning rose from 37% to 44%" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt; and &lt;a href="https://stackoverflow.co/company/press/archive/stack-overflow-2025-developer-survey/" rel="noopener noreferrer"&gt;Stack Overflow 2025 press release&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;GitHub's Octoverse 2025 report says nearly 80% of new developers on GitHub used GitHub Copilot within their first week. [&lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-2f39b837-f670-4a89-aff6-3bab69fe5190" alt="Chart: Developer AI adoption and learning signals, including Stack Overflow AI use and GitHub Copilot first-week usage for new developers" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt; and &lt;a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/" rel="noopener noreferrer"&gt;GitHub Octoverse 2025&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is not a weird side habit anymore. That is part of the learning surface.&lt;/p&gt;

&lt;p&gt;AI helps juniors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explain unfamiliar code&lt;/li&gt;
&lt;li&gt;generate practice tasks&lt;/li&gt;
&lt;li&gt;translate documentation into plain English&lt;/li&gt;
&lt;li&gt;compare implementation options&lt;/li&gt;
&lt;li&gt;debug error messages&lt;/li&gt;
&lt;li&gt;create test cases&lt;/li&gt;
&lt;li&gt;rehearse interviews&lt;/li&gt;
&lt;li&gt;review resumes&lt;/li&gt;
&lt;li&gt;understand unfamiliar libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that means the junior understands automatically.&lt;/p&gt;

&lt;p&gt;But it does mean AI is covering work teams used to handle through mentorship, pairing, code review, and onboarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The catch: AI is wrong a lot
&lt;/h2&gt;

&lt;p&gt;The answer is not "AI good, juniors right, seniors bad."&lt;/p&gt;

&lt;p&gt;That would be cheap.&lt;/p&gt;

&lt;p&gt;AI output is often wrong.&lt;/p&gt;

&lt;p&gt;Stack Overflow's 2025 survey says more developers distrust AI output accuracy than trust it: 46% distrust versus 33% trust. The biggest frustration is that answers are "almost right, but not quite," cited by 66% of respondents. [&lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow AI survey&lt;/a&gt;]&lt;/p&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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" 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%2Fquickchart.io%2Fchart%2Frender%2Fzf-0cb70d32-659d-4b1d-8407-981bc3a9d1ee" alt="Chart: Stack Overflow 2025 shows 46% distrust AI output accuracy, 33% trust it, and 66% cite almost-right answers as a frustration" width="2000" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow 2025 Developer Survey&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is why juniors need training, not shame.&lt;/p&gt;

&lt;p&gt;The strongest junior AI workflow is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Generate the code and ship it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use AI to understand the problem, then verify the answer with docs, tests, code review, and actual system behavior."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are not the same workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The research is not a slogan
&lt;/h2&gt;

&lt;p&gt;The education research does not support a simple anti-AI panic.&lt;/p&gt;

&lt;p&gt;It supports a more serious claim: AI helps some learners and hurts others depending on how they use it.&lt;/p&gt;

&lt;p&gt;The 2024 paper &lt;em&gt;The Widening Gap: The Benefits and Harms of Generative AI for Novice Programmers&lt;/em&gt; observed 21 novice programming lab sessions. The researchers found that GenAI could help students complete tasks, but weaker students were more vulnerable to accepting incorrect or unhelpful suggestions. [&lt;a href="https://arxiv.org/abs/2405.17739" rel="noopener noreferrer"&gt;The Widening Gap&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 systematic review on junior developers adopting LLMs found both positive and negative perceptions across most of the literature it reviewed. [&lt;a href="https://arxiv.org/abs/2503.07556" rel="noopener noreferrer"&gt;Junior developers and LLMs SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;A 2025 review on GenAI and code comprehension found that generated explanations can support learning, but can also be inaccurate, unclear, or hard for novices to evaluate. [&lt;a href="https://arxiv.org/abs/2510.17894" rel="noopener noreferrer"&gt;Code comprehension SLR&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;That is not an argument for banning AI. It is an argument for teaching AI literacy as part of engineering literacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is leadership work
&lt;/h2&gt;

&lt;p&gt;If a company hires juniors with no plan to teach them, it is not running a junior program. It is gambling.&lt;/p&gt;

&lt;p&gt;A real junior program needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scoped work&lt;/li&gt;
&lt;li&gt;named mentors&lt;/li&gt;
&lt;li&gt;clear review standards&lt;/li&gt;
&lt;li&gt;onboarding tasks tied to production concepts&lt;/li&gt;
&lt;li&gt;time for questions&lt;/li&gt;
&lt;li&gt;code review that teaches reasoning&lt;/li&gt;
&lt;li&gt;documentation that is not tribal memory&lt;/li&gt;
&lt;li&gt;a path from small fixes to system ownership&lt;/li&gt;
&lt;li&gt;explicit AI usage rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most companies do not need a 12-month academy.&lt;/p&gt;

&lt;p&gt;They do need to stop pretending a junior becomes production-ready by osmosis while seniors are booked 110% and managers ask for "ownership" on week two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask better questions
&lt;/h2&gt;

&lt;p&gt;Stop asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why are juniors worse now?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Better question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What do we expect a junior to know on day one?&lt;/td&gt;
&lt;td&gt;Prevents hidden mid-level expectations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What do we teach in the first 90 days?&lt;/td&gt;
&lt;td&gt;Turns hiring into development.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who reviews their work and how?&lt;/td&gt;
&lt;td&gt;Creates accountability for mentorship.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which tasks are junior-safe but still real?&lt;/td&gt;
&lt;td&gt;Avoids fake work and impossible work.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What AI use is allowed?&lt;/td&gt;
&lt;td&gt;Prevents inconsistent punishment.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do we test understanding?&lt;/td&gt;
&lt;td&gt;Separates learning from blind copying.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is how companies get better juniors. Complaining on LinkedIn is not a training plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;There are juniors. There are motivated graduates. There are self-taught developers doing the work.&lt;/p&gt;

&lt;p&gt;Many of them use AI because the modern learning stack is fragmented, outdated, noisy, and incomplete without it.&lt;/p&gt;

&lt;p&gt;The shortage is not curiosity. The shortage is serious training.&lt;/p&gt;

&lt;p&gt;If companies want senior engineers in five years, they need to build juniors now.&lt;/p&gt;

&lt;p&gt;If they refuse, they should stop blaming the generation that showed up after the ladder was already pulled up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/career" class="crayons-btn crayons-btn--primary"&gt;Interested in junior developer hiring, AI, and tech careers? Explore #career on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hiring</category>
      <category>bestofdev</category>
      <category>career</category>
    </item>
    <item>
      <title>The Orphaned ID Bug from My First Job (And What It Taught Me About Being a Junior Dev)</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Tue, 28 Apr 2026 05:20:55 +0000</pubDate>
      <link>https://dev.to/bradleymatera/the-orphaned-id-bug-from-my-first-job-and-what-it-taught-me-about-being-a-junior-dev-2ojb</link>
      <guid>https://dev.to/bradleymatera/the-orphaned-id-bug-from-my-first-job-and-what-it-taught-me-about-being-a-junior-dev-2ojb</guid>
      <description>&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%2F4sb8uo1cuumu9p7h0anf.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%2F4sb8uo1cuumu9p7h0anf.gif" alt="frustrated" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About two weeks into my first web-dev job, I had a Trello card that said the LMS was sometimes leaving orphaned IDs behind when assigned trainings were finished or deleted.&lt;/p&gt;

&lt;p&gt;The app was a corporate LMS for a global manufacturer that made machine protection, chip and coolant management systems, and facility safety products.&lt;/p&gt;

&lt;p&gt;This was not a small internal team tool. It was the training system for the whole company, and they wanted every training assignment for anyone to go through this broken LMS.&lt;/p&gt;

&lt;p&gt;The frontend was simple: jQuery dialogs, table rows, and AJAX calls.&lt;/p&gt;

&lt;p&gt;The bug was not a dramatic React failure. It was a row-based edge case in a table view.&lt;/p&gt;

&lt;p&gt;Sometimes the AJAX response would arrive and the data would be missing. Sometimes the table would render, but an empty row would appear where an assignment should have been.&lt;/p&gt;

&lt;p&gt;That was enough for the card to hit the board and for me to start investigating.&lt;/p&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%2Fkavp99b0qps56ulua2tz.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%2Fkavp99b0qps56ulua2tz.gif" alt="bug report" width="540" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the bug was more than a blank row
&lt;/h2&gt;

&lt;p&gt;At first, it was easy to dismiss this as a rendering issue.&lt;/p&gt;

&lt;p&gt;Maybe the list component was failing to fill the template. Maybe the CSS was swallowing the text. Maybe the client was accidentally rendering an empty object.&lt;/p&gt;

&lt;p&gt;Then I opened the network tab.&lt;/p&gt;

&lt;p&gt;The API was returning assignment objects. Some of them had &lt;code&gt;training_id&lt;/code&gt;, some of them had &lt;code&gt;completed_at&lt;/code&gt;, and some of them had fields set to &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The client never filtered those out. It rendered every row it received.&lt;/p&gt;

&lt;p&gt;That meant the bug was not just on the page. It was in the data the page was given.&lt;/p&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%2Fyl98527j67un33ptn0ni.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%2Fyl98527j67un33ptn0ni.gif" alt="empty table row" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was told
&lt;/h2&gt;

&lt;p&gt;When I asked my senior for more context, the answer was basically, “Figure it out without AI.”&lt;/p&gt;

&lt;p&gt;That line was a punch in the face, because this was the same team that had told me they liked that I understood AI. The same team that had hired me after I talked about how I used free tools to speed up small fixes and keep my commits focused.&lt;/p&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%2Fzdrxyomzaxibexghyxtm.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%2Fzdrxyomzaxibexghyxtm.gif" alt="AI feedback" width="420" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was not being asked to build a feature. I was being asked to debug a failure in a system I did not own.&lt;/p&gt;

&lt;p&gt;I was not given:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the schema for &lt;code&gt;assigned_trainings&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the intended lifecycle of a completed assignment&lt;/li&gt;
&lt;li&gt;whether deletes were supposed to cascade&lt;/li&gt;
&lt;li&gt;whether &lt;code&gt;completed_trainings&lt;/code&gt; was supposed to be a source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was only given the symptom and an expectation.&lt;/p&gt;

&lt;p&gt;That is a very common junior-dev situation: the problem is clear, but the contract is not.&lt;/p&gt;

&lt;p&gt;It got worse after I was fired.&lt;/p&gt;

&lt;p&gt;The official reason was that I used AI too much. I had spent one month on the job, made forty small commits, and the only real problem I had found was one that was creating blank rows in the UI.&lt;/p&gt;

&lt;p&gt;The contradiction stung. They paid for the work, accepted the fixes, and then told me they did not want my process. It left me angry, confused, and more than a little ashamed.&lt;/p&gt;

&lt;p&gt;That was the context I brought to the bug: a team that liked the results but disliked the tool, a junior dev who felt stuck between expectations and execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following the data trail like a junior detective
&lt;/h2&gt;

&lt;p&gt;Once I stopped looking at the UI and started looking at the database, the problem became more concrete.&lt;/p&gt;

&lt;p&gt;The symptoms were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blank rows appeared after delete or completion&lt;/li&gt;
&lt;li&gt;the user record still existed&lt;/li&gt;
&lt;li&gt;the training record still existed in some form&lt;/li&gt;
&lt;li&gt;the list view did not know which rows were stale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In plain English: the UI was still receiving references to assignments that had lost their parent record.&lt;/p&gt;

&lt;p&gt;That usually means one of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the database is missing a foreign key constraint, or&lt;/li&gt;
&lt;li&gt;code that cleans up stale assignments is not running consistently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I began checking the tables in the order the app was likely using them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assigned_trainings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;completed_trainings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;users&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trainings&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was looking for rows that should have been gone but were still visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SQL I wrote to prove the orphan
&lt;/h2&gt;

&lt;p&gt;I did not have a polished schema diagram. I had a terminal and a query editor.&lt;/p&gt;

&lt;p&gt;The first query I used was a simple orphan finder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;training_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assigned_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_id&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;assigned_trainings&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;completed_trainings&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;training_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;training_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That returned assignment rows that had no matching completion row.&lt;/p&gt;

&lt;p&gt;Then I extended it to catch assignments that referenced missing training metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;training_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;training_title&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;assigned_trainings&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;trainings&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;training_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those queries were not meant to be elegant. They were meant to answer one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is there data in the system that should not still be shown?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer was yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the SQL mattered more than the frontend
&lt;/h2&gt;

&lt;p&gt;This bug was not a broken component. It was stale data flowing through the app.&lt;/p&gt;

&lt;p&gt;The frontend code was basically doing this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fetch assignment rows&lt;/li&gt;
&lt;li&gt;render each row&lt;/li&gt;
&lt;li&gt;assume each row was valid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was not validating status, it was not filtering by &lt;code&gt;deleted_at&lt;/code&gt;, and it was not checking whether the associated training still existed.&lt;/p&gt;

&lt;p&gt;That made the UI brittle.&lt;/p&gt;

&lt;p&gt;So I shifted the fix to the place where the contract belonged: the database.&lt;/p&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%2Fz0m54v96k1nerbtflem8.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%2Fz0m54v96k1nerbtflem8.gif" alt="debugging" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The cleanup fix I shipped
&lt;/h2&gt;

&lt;p&gt;I did not have enough confidence to rewrite the whole lifecycle.&lt;/p&gt;

&lt;p&gt;What I had enough confidence to do was this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify stale assignment rows with SQL&lt;/li&gt;
&lt;li&gt;Delete them in a controlled cleanup operation&lt;/li&gt;
&lt;li&gt;Confirm the UI stopped showing blank rows&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The frontend trigger was tiny:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cleanup-orphans&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deleted orphans&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deletedCount&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;The backend controller looked like this in rough form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cleanup-orphans&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;orphanIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
    SELECT a.id
    FROM assigned_trainings a
    LEFT JOIN completed_trainings c
      ON a.user_id = c.user_id
      AND a.training_id = c.training_id
    WHERE c.id IS NULL
  `&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;deleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE FROM assigned_trainings WHERE id = ANY($1)&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="nx"&gt;orphanIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;deletedCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;deleted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&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;I also added a small log statement so I could see the number of deleted rows in the server output.&lt;/p&gt;

&lt;p&gt;This was not a permanent fix.&lt;/p&gt;

&lt;p&gt;It was a controlled cleanup that removed the broken rows and let the UI go back to behaving.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this taught me about junior work
&lt;/h2&gt;

&lt;p&gt;There are two kinds of fixes in a codebase like that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quick patches that make the symptoms disappear&lt;/li&gt;
&lt;li&gt;deeper fixes that make the system enforce the invariant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A junior developer is often asked to deliver the first one while learning the second.&lt;/p&gt;

&lt;p&gt;This bug mattered because it exposed a gap in the system’s contract.&lt;/p&gt;

&lt;p&gt;The frontend expected valid assignment rows. The database did not guarantee them.&lt;/p&gt;

&lt;p&gt;Until that was fixed, the app was fragile.&lt;/p&gt;

&lt;p&gt;It also mattered because I was not just fixing a bug for a product. I was fixing a bug while trying to prove that I belonged in that role.&lt;/p&gt;

&lt;p&gt;After the firing, the problem became more than technical. It became personal.&lt;/p&gt;

&lt;p&gt;I was unemployed again. I had a recruiter apologizing on the phone. I had a wife and kids depending on me. I felt worthless for a day, then angry, then confused.&lt;/p&gt;

&lt;p&gt;That is what made the lack of guidance especially painful. I was being measured on results, but I was not given the information that would have led to a better result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I wish someone had said
&lt;/h2&gt;

&lt;p&gt;If my senior had said any of the following, the work would have been clearer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“This looks like a data integrity problem, not a UI bug.”&lt;/li&gt;
&lt;li&gt;“We need to know whether assignment rows should be deleted, archived, or left as history.”&lt;/li&gt;
&lt;li&gt;“Check if the &lt;code&gt;assigned_trainings&lt;/code&gt; table has a foreign key on &lt;code&gt;user_id&lt;/code&gt;.”&lt;/li&gt;
&lt;li&gt;“Find out whether &lt;code&gt;completed_trainings&lt;/code&gt; is the source of truth.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead I got, “Figure it out.”&lt;/p&gt;

&lt;p&gt;That is a useful outcome sometimes, but it is not a substitute for explaining the problem domain.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blank rows are usually a data problem, not a render problem.&lt;/strong&gt;&lt;br&gt;
The UI can only show what it receives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A query is a debugger.&lt;/strong&gt;&lt;br&gt;
SQL is a powerful way to prove whether the data actually exists.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CRUD is not enough without constraints.&lt;/strong&gt;&lt;br&gt;
Adding a row is easy. Making sure it is still valid later is the hard part.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ask for the contract.&lt;/strong&gt;&lt;br&gt;
If you are told to fix something, ask what the data model is supposed to guarantee.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Patches are not the same as system fixes.&lt;/strong&gt;&lt;br&gt;
A cleanup endpoint can make the app behave, but the real fix is enforcing the invariant at the source.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  If I did the bug again today
&lt;/h2&gt;

&lt;p&gt;I would still start with the same questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What exactly should a completed assignment look like?&lt;/li&gt;
&lt;li&gt;Which table is the source of truth for assignment status?&lt;/li&gt;
&lt;li&gt;Should deletes remove the row, or should the row stay marked as completed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would also look for missing constraints and missing cleanup paths.&lt;/p&gt;

&lt;p&gt;In a better design, the database can help.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;assigned_trainings&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;fk_user&lt;/span&gt;
&lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would cause the database to delete assignments automatically when the user is deleted.&lt;/p&gt;

&lt;p&gt;But even that is not always the right answer.&lt;/p&gt;

&lt;p&gt;If the business needs a record of completed training for audits, a history row is the right fix, not a cascade delete.&lt;/p&gt;

&lt;p&gt;That is why the first job of a debugging session is always: ask what the data should mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaways
&lt;/h2&gt;

&lt;p&gt;This story is not about one query or one jQuery call.&lt;/p&gt;

&lt;p&gt;It is about the way junior developer work often happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you are handed a symptom&lt;/li&gt;
&lt;li&gt;you are expected to turn it into a fix&lt;/li&gt;
&lt;li&gt;you may not be told what the system is supposed to enforce&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I fixed this bug with SQL, with a cleanup endpoint, and with enough caution to avoid deleting something live.&lt;/p&gt;

&lt;p&gt;It was not the perfect design.&lt;/p&gt;

&lt;p&gt;It was the right fix for the moment.&lt;/p&gt;

&lt;p&gt;The bigger lesson was not the query itself. It was how much the work depended on context.&lt;/p&gt;

&lt;p&gt;If I had been told whether this was supposed to be a one-time cleanup or a permanent contract, the answer could have looked very different.&lt;/p&gt;

&lt;p&gt;The code I wrote was useful. The team knowledge I did not get was the thing that would have made it better.&lt;/p&gt;

&lt;p&gt;If you are a junior dev, learn to ask for the data contract.&lt;/p&gt;

&lt;p&gt;If you are a senior dev, help the junior dev understand whether the fix is temporary or permanent.&lt;/p&gt;

&lt;p&gt;If you are a team, document your schema and your data assumptions before the blank rows appear.&lt;/p&gt;

&lt;p&gt;That is what separates a band-aid from a reliable system.&lt;/p&gt;

&lt;p&gt;This story is not just about a blank row in an LMS. It is about how much more fragile a junior engineer feels when the rules keep changing.&lt;/p&gt;

&lt;p&gt;A team can survive one fired junior dev if the work is real and the feedback is honest. It becomes a different problem when the team refuses to say what the contract is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/tags/junior-dev" class="crayons-btn crayons-btn--primary"&gt;Want other junior dev stories? Explore #junior-dev on DEV.&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>jquery</category>
      <category>php</category>
      <category>ajax</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Testing Bifrost CLI and Code Mode: What Worked, What Broke, and What I Verified</title>
      <dc:creator>Bradley Matera</dc:creator>
      <pubDate>Mon, 27 Apr 2026 04:40:01 +0000</pubDate>
      <link>https://dev.to/bradleymatera/testing-bifrost-cli-and-code-mode-what-worked-what-broke-and-what-i-verified-7c3</link>
      <guid>https://dev.to/bradleymatera/testing-bifrost-cli-and-code-mode-what-worked-what-broke-and-what-i-verified-7c3</guid>
      <description>&lt;div class="ltag-slides ltag-slides--carousel"&gt;
  &lt;div class="ltag-slides__track"&gt;
    &lt;div class="ltag-slide"&gt;
      &lt;img class="ltag-slide__image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmaximhq%2Fbifrost%2Fmain%2Fdocs%2Fmedia%2Fgetting-started.png" alt="Bifrost quick start screenshot from the official repository" width="799" height="315"&gt;
      &lt;div class="ltag-slide__title"&gt;Bifrost Quick Start&lt;/div&gt;
&lt;/div&gt;


&lt;div class="ltag-slide"&gt;
      &lt;img class="ltag-slide__image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmaximhq%2Fbifrost%2Fmain%2F.github%2Fassets%2Ffeatures.png" alt="Bifrost feature overview from the official repository" width="800" height="331"&gt;
      &lt;div class="ltag-slide__title"&gt;Bifrost Features&lt;/div&gt;
&lt;/div&gt;



  &lt;/div&gt;
    ‹
    ›
    &lt;div class="ltag-slides__dots"&gt;&lt;/div&gt;
    
      (function() {
        var container = document.currentScript.closest('.ltag-slides--carousel');
        var track = container.querySelector('.ltag-slides__track');
        var slides = track.querySelectorAll('.ltag-slide');
        var prevBtn = container.querySelector('.ltag-slides__nav--prev');
        var nextBtn = container.querySelector('.ltag-slides__nav--next');
        var dotsContainer = container.querySelector('.ltag-slides__dots');
        var current = 0;
        var total = slides.length;

        for (var i = 0; i &amp;lt; total; i++) {
          var dot = document.createElement('button');
          dot.className = 'ltag-slides__dot' + (i === 0 ? ' ltag-slides__dot--active' : '');
          dot.setAttribute('aria-label', 'Go to slide ' + (i + 1));
          dot.dataset.index = i;
          dot.addEventListener('click', function() { goTo(parseInt(this.dataset.index)); });
          dotsContainer.appendChild(dot);
        }

        function goTo(index) {
          current = ((index % total) + total) % total;
          track.style.transform = 'translateX(-' + (current * 100) + '%)';
          var dots = dotsContainer.querySelectorAll('.ltag-slides__dot');
          for (var i = 0; i &amp;lt; dots.length; i++) {
            dots[i].classList.toggle('ltag-slides__dot--active', i === current);
          }
        }

        prevBtn.addEventListener('click', function() { goTo(current - 1); });
        nextBtn.addEventListener('click', function() { goTo(current + 1); });
      })();
    
&lt;/div&gt;


&lt;p&gt;I spend a lot of time wiring AI coding tools together: VS Code, Copilot, Claude Code, Codex-style flows, local agents, and MCP servers.&lt;/p&gt;

&lt;p&gt;The problem is not the model anymore. It is the plumbing.&lt;/p&gt;

&lt;p&gt;Every new provider needs a key. Every MCP server adds another tool catalog. Every tool adds schema, API shapes, and prompt context.&lt;/p&gt;

&lt;p&gt;That is where Bifrost caught my attention.&lt;/p&gt;

&lt;p&gt;Bifrost is an open-source gateway from Maxim AI. It is not meant to replace models or agents. It is meant to sit between them and make the whole system easier to inspect and control.&lt;/p&gt;

&lt;p&gt;This test had a simple goal: start the gateway, route real model traffic through it, attach a filesystem MCP server, enable Code Mode, and see whether a coding agent could actually work through that stack.&lt;/p&gt;

&lt;p&gt;I also wanted practical answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which key did this agent use?&lt;/li&gt;
&lt;li&gt;Which model did it call?&lt;/li&gt;
&lt;li&gt;Which tools could it reach?&lt;/li&gt;
&lt;li&gt;What did the run cost?&lt;/li&gt;
&lt;li&gt;Where could I inspect the logs?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the thread through this post. It is not a marketing summary. It is a field test of the local gateway, the CLI, provider routing, MCP setup, Code Mode, and a real coding-agent launch.&lt;/p&gt;

&lt;p&gt;Repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/maximhq" rel="noopener noreferrer"&gt;
        maximhq
      &lt;/a&gt; / &lt;a href="https://github.com/maximhq/bifrost" rel="noopener noreferrer"&gt;
        bifrost
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fastest enterprise AI gateway (50x faster than LiteLLM) with adaptive load balancer, cluster mode, guardrails, 1000+ models support &amp;amp; &amp;lt;100 µs overhead at 5k RPS.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Bifrost AI Gateway&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://goreportcard.com/report/github.com/maximhq/bifrost/core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7f7e70df9fdaaf4f485f59ca6bc0b5cbbf134d03dd5721da4e31f90f618fc304/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f6d6178696d68712f626966726f73742f636f7265" alt="Go Report Card"&gt;&lt;/a&gt;
&lt;a href="https://discord.gg/exN5KAydbU" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/282b7719f04b28f5959f5e1e17aee806d65f8eea3b862b57af350df0ab57be6f/68747470733a2f2f646362616467652e6c696d65732e70696e6b2f6170692f7365727665722f68747470733a2f2f646973636f72642e67672f65784e354b41796462553f7374796c653d666c6174" alt="Discord badge"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/maximhq/bifrost" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8bc2db302c566210d14c09b278639a3f63f07def5fc635a8869e59c996b3100f/68747470733a2f2f636f6465636f762e696f2f67682f6d6178696d68712f626966726f73742f6272616e63682f6d61696e2f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b0899925aadfed8626116707178a4015d8cf4aaa0b80acb632cb4782c6dc7272/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6d6178696d68712f626966726f7374"&gt;&lt;img src="https://camo.githubusercontent.com/b0899925aadfed8626116707178a4015d8cf4aaa0b80acb632cb4782c6dc7272/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6d6178696d68712f626966726f7374" alt="Docker Pulls"&gt;&lt;/a&gt;
&lt;a href="https://app.getpostman.com/run-collection/31642484-2ba0e658-4dcd-49f4-845a-0c7ed745b916?action=collection%2Ffork&amp;amp;source=rip_markdown&amp;amp;collection-url=entityId%3D31642484-2ba0e658-4dcd-49f4-845a-0c7ed745b916%26entityType%3Dcollection%26workspaceId%3D63e853c8-9aec-477f-909c-7f02f543150e" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/82ccefddb001e2caf9d399f1153fdda561cf3da341bb270e18644d516906bc64/68747470733a2f2f72756e2e7073746d6e2e696f2f627574746f6e2e737667" alt="Run In Postman"&gt;&lt;/a&gt;
&lt;a href="https://artifacthub.io/packages/search?repo=bifrost" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a6a3c734d6bd57fa8e1d508ac0cdba555bdbcd9191b29b32cf37a964b86b9c67/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f61727469666163746875622e696f2f62616467652f7265706f7369746f72792f626966726f7374" alt="Artifact Hub"&gt;&lt;/a&gt;
&lt;a href="https://github.com/maximhq/bifrost/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3cb44c15a532770a066ba8e61bf11506ad5400e5c61d48f6b639101e442bee79/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6d6178696d68712f626966726f7374" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The fastest way to build AI applications that never go down&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Bifrost is a high-performance AI gateway that unifies access to 23+ providers (OpenAI, Anthropic, AWS Bedrock, Google Vertex, and more) through a single OpenAI-compatible API. Deploy in seconds with zero configuration and get automatic failover, load balancing, semantic caching, and enterprise-grade features.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/maximhq/bifrost/./docs/media/getting-started.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmaximhq%2Fbifrost%2FHEAD%2F.%2Fdocs%2Fmedia%2Fgetting-started.png" alt="Get started"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Go from zero to production-ready AI gateway in under a minute.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Start Bifrost Gateway&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install and run locally&lt;/span&gt;
npx -y @maximhq/bifrost

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Or use Docker&lt;/span&gt;
docker run -p 8080:8080 maximhq/bifrost&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Configure via Web UI&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Open the built-in web interface&lt;/span&gt;
open http://localhost:8080&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Make your first API call&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;curl -X POST http://localhost:8080/v1/chat/completions \
  -H &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Content-Type: application/json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; \
  -d &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;{&lt;/span&gt;
&lt;span class="pl-s"&gt;    "model": "openai/gpt-4o-mini",&lt;/span&gt;
&lt;span class="pl-s"&gt;    "messages": [{"role": "user", "content": "Hello, Bifrost!"}]&lt;/span&gt;
&lt;span class="pl-s"&gt;  }&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;That's it!&lt;/strong&gt; Your AI gateway is running with a web interface for visual configuration…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/maximhq/bifrost" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Official setup docs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.getbifrost.ai/quickstart/gateway/setting-up" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Open the official Bifrost gateway setup guide.&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was actually testing
&lt;/h2&gt;

&lt;p&gt;MCP is useful because it gives AI agents a standard way to call tools. Those tools can be filesystem access, search, databases, internal APIs, browser automation, or anything else exposed through an MCP server.&lt;/p&gt;

&lt;p&gt;That sounds good until your tool list gets large.&lt;/p&gt;

&lt;p&gt;Classic MCP can put a big tool catalog into the model's context. With a few servers that is okay. With many servers, the model spends tokens just reading what tools exist.&lt;/p&gt;

&lt;p&gt;That is the problem I want to avoid.&lt;/p&gt;

&lt;p&gt;I do not want my coding agent spending context on every possible tool every time. I want it to discover what it needs and keep the prompt smaller.&lt;/p&gt;

&lt;p&gt;Bifrost's Code Mode is designed for that issue.&lt;/p&gt;

&lt;p&gt;So the question was not "does Bifrost look useful?" The question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can I install it, wire it into a real project, and see the tool-control layer work end to end?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why the Bifrost CLI matters
&lt;/h2&gt;

&lt;p&gt;The gateway routes providers. The CLI is what makes the setup usable for coding agents.&lt;/p&gt;

&lt;p&gt;I wanted to avoid hand-editing agent config every time I switched models or providers.&lt;/p&gt;

&lt;p&gt;The workflow I tested was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;launch the gateway&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;bifrost-cli&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;pick a harness&lt;/li&gt;
&lt;li&gt;pick a model&lt;/li&gt;
&lt;li&gt;launch the agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI stores state under &lt;code&gt;~/.bifrost/&lt;/code&gt;, including gateway URL, selected model, and harness.&lt;/p&gt;

&lt;p&gt;That matters because it keeps the gateway and agent shared in one place instead of every agent maintaining a separate, brittle config.&lt;/p&gt;

&lt;p&gt;Supported harnesses in the docs included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code&lt;/li&gt;
&lt;li&gt;Codex CLI&lt;/li&gt;
&lt;li&gt;Gemini CLI&lt;/li&gt;
&lt;li&gt;Opencode&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation and integration
&lt;/h2&gt;

&lt;p&gt;I tested both ways to run the gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local NPX
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @maximhq/bifrost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data:/app/data maximhq/bifrost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That gives you a dashboard at:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I always start there. If the dashboard does not respond, nothing else matters.&lt;/p&gt;
&lt;h3&gt;
  
  
  First smoke test
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once the gateway was up, the next step was provider setup, MCP setup, and CLI testing.&lt;/p&gt;
&lt;h3&gt;
  
  
  First model request
&lt;/h3&gt;

&lt;p&gt;A basic OpenAI-compatible request looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "openai/gpt-4o-mini",
    "messages": [
      { "role": "user", "content": "Hello, Bifrost!" }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I did not use RunKit here because RunKit cannot reach &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Add an MCP client and enable Code Mode
&lt;/h3&gt;

&lt;p&gt;The Bifrost path is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dashboard → MCP Gateway → add client → choose STDIO, HTTP, or SSE → configure command or URL → choose tool permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For this test, I used a STDIO filesystem MCP server scoped to the &lt;code&gt;donotpush&lt;/code&gt; draft folder.&lt;/p&gt;

&lt;p&gt;That scope matters. A gateway should not become an excuse to give every agent access to the whole machine.&lt;/p&gt;

&lt;p&gt;Once the MCP client exists, Code Mode can be enabled for that client. When Code Mode is on, the model does not get the full tool catalog directly. It gets four meta-tools first, then inspects and executes only what it needs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where Code Mode fits in
&lt;/h2&gt;

&lt;p&gt;This was the part I cared about most.&lt;/p&gt;

&lt;p&gt;Classic MCP can work fine. It can also force the model to carry a lot of extra tool metadata.&lt;/p&gt;

&lt;p&gt;Code Mode is meant to change that.&lt;/p&gt;

&lt;p&gt;Bifrost exposes these four meta-tools:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;listToolFiles
readToolFile
getToolDocs
executeToolCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That means the model can ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what tool files are available?&lt;/li&gt;
&lt;li&gt;what is in this stub?&lt;/li&gt;
&lt;li&gt;what are the docs for this tool?&lt;/li&gt;
&lt;li&gt;execute this code against the tool binding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is to give the model an index instead of a giant binder.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Code Mode exists
&lt;/h3&gt;

&lt;p&gt;The problem is context bloat. In a small MCP setup, every tool definition may be fine. In a larger setup, it becomes waste.&lt;/p&gt;

&lt;p&gt;Bifrost's docs use an example with five MCP servers and around 100 tools. In the classic flow, the model carries that catalog across multiple turns. In Code Mode, it carries only four meta-tools and then loads the specific stubs it needs.&lt;/p&gt;

&lt;p&gt;This is why Code Mode uses code instead of a long chain of individual tool calls. The model can orchestrate the workflow in a constrained Starlark interpreter, and intermediate results do not have to get pushed back through the model.&lt;/p&gt;
&lt;h3&gt;
  
  
  Performance and cost claims
&lt;/h3&gt;

&lt;p&gt;Bifrost's docs claim that for about 100 tools across five MCP servers, Code Mode can cut the interaction shape from six LLM turns with a full catalog to three or four turns with about 50 tool-definition tokens.&lt;/p&gt;

&lt;p&gt;Their published benchmark goes further: 55.7% lower estimated cost with 96 tools, 83.4% with 251 tools, and 92.2% with 508 tools.&lt;/p&gt;

&lt;p&gt;Those are vendor claims. I am including them here because they explain why the feature is worth testing, not because my one-server filesystem test reproduced them.&lt;/p&gt;
&lt;h3&gt;
  
  
  When I would enable it
&lt;/h3&gt;

&lt;p&gt;My rule of thumb after this pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep classic MCP for one or two small servers&lt;/li&gt;
&lt;li&gt;enable Code Mode when you have three or more MCP servers&lt;/li&gt;
&lt;li&gt;enable it for heavier servers like filesystem, search, docs, databases, CRM, or internal APIs&lt;/li&gt;
&lt;li&gt;use tool-level binding when one server has many tools or big schemas&lt;/li&gt;
&lt;li&gt;keep the allowed tool list tight either way&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;Code Mode exposes MCP tools as virtual &lt;code&gt;.pyi&lt;/code&gt; stub files. There are two binding levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;server-level binding: one stub file per MCP server&lt;/li&gt;
&lt;li&gt;tool-level binding: one stub file per tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Server-level binding is simpler when a server has a small tool set. Tool-level binding is better when a server has many tools or large schemas.&lt;/p&gt;

&lt;p&gt;The code runs in Starlark, a deterministic Python-like runtime. Bifrost's docs describe it as intentionally constrained: no imports, no file I/O, no network access, just allowed tool calls and basic Python-like logic. That constraint is what makes Code Mode interesting for agent workflows.&lt;/p&gt;

&lt;p&gt;
  "Classic MCP vs Code Mode in plain English"
  &lt;br&gt;
Classic MCP is like handing someone a giant binder full of every tool manual before every task.

&lt;p&gt;Code Mode is more like giving them a small index first. They look up the exact tool they need, read only that tool's instructions, then run the task.&lt;/p&gt;

&lt;p&gt;That matters when the number of tools grows.&lt;br&gt;
&lt;/p&gt;

&lt;/p&gt;
&lt;h2&gt;
  
  
  Why that matters for coding agents
&lt;/h2&gt;

&lt;p&gt;Coding agents already use a lot of context.&lt;/p&gt;

&lt;p&gt;They read files, inspect diffs, look at errors, review stack traces, and sometimes pull in project history. If they also carry every connected MCP tool definition on every request, the context gets noisy fast.&lt;/p&gt;

&lt;p&gt;That can hurt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cost&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;tool selection&lt;/li&gt;
&lt;li&gt;reliability&lt;/li&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For small setups, this may not matter. If you only have one or two MCP servers with a few tools, classic MCP can be fine.&lt;/p&gt;

&lt;p&gt;But once you start connecting heavier tools, Code Mode makes more sense.&lt;/p&gt;

&lt;p&gt;That is why I tested the flow directly instead of only repeating the docs.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I tested
&lt;/h2&gt;

&lt;p&gt;My test setup used the tools I actually work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;Bifrost gateway&lt;/li&gt;
&lt;li&gt;Bifrost CLI&lt;/li&gt;
&lt;li&gt;Codex CLI and OpenCode&lt;/li&gt;
&lt;li&gt;one filesystem MCP server&lt;/li&gt;
&lt;li&gt;a real local project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test needed to answer one practical question: can the gateway sit between the agent, the provider, and the MCP server without turning the workflow into a black box?&lt;/p&gt;

&lt;p&gt;The flow looked 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;Start Bifrost gateway
↓
Open Bifrost dashboard
↓
Configure provider
↓
Start Bifrost CLI
↓
Launch coding agent through Bifrost
↓
Run a small repo task
↓
Compare classic MCP flow vs Code Mode flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The task was intentionally small. I did not want a fake benchmark. I wanted enough proof to answer this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I route a coding agent through Bifrost, expose MCP tools, turn on Code Mode, and see the control layer working?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Everything after this point is evidence for that question.&lt;/p&gt;
&lt;h2&gt;
  
  
  The small agent task
&lt;/h2&gt;

&lt;p&gt;For the coding-agent check, I used a deliberately small prompt:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do not edit files. Reply with exactly: opencode through bifrost ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That prompt is boring on purpose. It does not prove the agent can solve every repo task. It proves the path: agent starts, uses the configured Bifrost provider, calls the model through the gateway, and returns a response.&lt;/p&gt;

&lt;p&gt;Then I split the MCP behavior into two questions:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Classic MCP:
- Did the model see the direct filesystem tools?
- Did it produce a normal MCP tool call?
- Could I execute that tool call through Bifrost?

Code Mode:
- Could I enable Code Mode on the MCP client?
- Did the four meta-tools work?
- Could executeToolCode call the underlying filesystem server?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  What I am not claiming
&lt;/h2&gt;

&lt;p&gt;This is not a benchmark.&lt;/p&gt;

&lt;p&gt;Bifrost publishes token-savings numbers for Code Mode. My test did not try to reproduce those claims.&lt;/p&gt;

&lt;p&gt;I only used one filesystem MCP server. With one server, there is not enough tool sprawl to make a serious token-savings claim. The useful result is narrower:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gateway&lt;/li&gt;
&lt;li&gt;provider route&lt;/li&gt;
&lt;li&gt;local Ollama&lt;/li&gt;
&lt;li&gt;Ollama cloud&lt;/li&gt;
&lt;li&gt;MCP server&lt;/li&gt;
&lt;li&gt;Code Mode meta-tools&lt;/li&gt;
&lt;li&gt;coding agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the difference between "I read the docs" and "I ran the workflow."&lt;/p&gt;
&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;I also have Ollama installed locally, with both local models and Ollama cloud variants available. That let me test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local Ollama model routing&lt;/li&gt;
&lt;li&gt;Ollama cloud model routing&lt;/li&gt;
&lt;li&gt;Bifrost provider behavior&lt;/li&gt;
&lt;li&gt;MCP tool discovery&lt;/li&gt;
&lt;li&gt;Code Mode meta-tool behavior&lt;/li&gt;
&lt;li&gt;one coding-agent launch through Bifrost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the checklist from the hands-on pass:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install/setup:
- [x] NPX start cleanly
- [x] Docker start cleanly
- [x] Dashboard available at localhost:8080
- [x] Provider setup persists
- [x] OpenAI config bootstrap tested
- [ ] OpenAI provider request blocked by missing OPENAI_API_KEY

CLI:
- [x] Bifrost CLI detects the gateway
- [x] Bifrost CLI asks for the expected config
- [x] Bifrost CLI shows Codex CLI as installed
- [x] Bifrost CLI lets me set the gateway URL and model
- [x] Config is stored in ~/.bifrost/config.json and ~/.bifrost/state.json
- [x] Bifrost CLI launches Codex CLI
- [x] Bifrost CLI prints the MCP server URL for Codex CLI
- [x] Codex CLI launch works
- [ ] Codex CLI request blocked because current Codex expects Responses API for this route

MCP:
- [x] Add at least one MCP server
- [x] Gateway can see the tools
- [x] Model can produce a classic MCP tool call
- [x] Classic MCP tool call works
- [x] Enable Code Mode
- [x] Code Mode exposes the four meta-tools
- [x] Run the same "list allowed directories" task with classic MCP and Code Mode
- [x] Route local Ollama models through Bifrost
- [x] Route Ollama cloud models through Bifrost

Agent workflow:
- [x] Complete a minimal coding-agent request through Bifrost with OpenCode
- [x] Keep the response understandable
- [x] Confirm tool-governed filesystem access through MCP
- [ ] OpenAI-vs-Ollama provider fallback blocked by missing OpenAI key
- [out of scope] Prove token savings with a large multi-server setup

Cost/context:
- [out of scope] Fewer tokens used in a realistic multi-server setup
- [x] Latency is acceptable for small local tests
- [x] Workflow is inspectable from one gateway dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the evidence I care about more than a marketing number: what launched, what routed, what exposed tools, what returned output, and what failed.&lt;/p&gt;

&lt;p&gt;The unresolved items were clear: OpenAI fallback needs a real key, Codex needs a Responses-compatible route, and a larger multi-server setup is required for any real token-savings claim.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands-on results
&lt;/h2&gt;

&lt;p&gt;The first thing I verified was the gateway.&lt;/p&gt;

&lt;p&gt;I started the local gateway and confirmed &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; was alive.&lt;/p&gt;

&lt;p&gt;The dashboard loaded cleanly.&lt;/p&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%2Fk7am4r8ixzrmoeo6pe0u.png" 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%2Fk7am4r8ixzrmoeo6pe0u.png" alt="Bifrost dashboard after local requests" width="800" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That dashboard is useful because it gives a second source of truth. It shows request volume, token usage, model usage, latency, cache state, and cost.&lt;/p&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%2Fzvyuygjhdxnr06fnm6zk.png" 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%2Fzvyuygjhdxnr06fnm6zk.png" alt="Bifrost dashboard main observability grid" width="800" height="915"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the panels were meaningful for this test.&lt;/p&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%2F1bi7qk479kyuqahsn1b3.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%2F1bi7qk479kyuqahsn1b3.gif" alt="Bifrost dashboard tour through request volume, token usage, cache, model usage, and latency" width="800" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that working, I moved to provider wiring.&lt;/p&gt;

&lt;p&gt;The Bifrost CLI defaulted to &lt;code&gt;Codex CLI&lt;/code&gt;. I chose &lt;code&gt;openai-ollama2/gpt-oss:20b-cloud&lt;/code&gt; after confirming the custom provider could route Ollama cloud requests.&lt;/p&gt;

&lt;p&gt;On disk, the CLI state was exactly where I expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.bifrost/config.json&lt;/code&gt; pointed at &lt;code&gt;http://localhost:8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.bifrost/state.json&lt;/code&gt; stored the selected harness and model&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./bifrost-data/config.db&lt;/code&gt; had the usual config tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also checked the repo &lt;code&gt;.env&lt;/code&gt;. It had project secrets, but not an OpenAI key for Bifrost.&lt;/p&gt;

&lt;p&gt;So I did one more bootstrap test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;created &lt;code&gt;bifrost-temp/config.json&lt;/code&gt; with &lt;code&gt;providers.openai.keys[0].value = "env.OPENAI_API_KEY"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;launched Bifrost on &lt;code&gt;http://127.0.0.1:8081&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the gateway started and wrote state to &lt;code&gt;./config.db&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the provider row existed, but Bifrost reported "no valid keys found for provider: openai"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was the exact failure mode: the key was missing from the shell.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ollama routing worked
&lt;/h2&gt;

&lt;p&gt;With OpenAI blocked by a missing secret, I tested the local provider I could fully verify: Ollama.&lt;/p&gt;

&lt;p&gt;I started &lt;code&gt;ollama serve&lt;/code&gt; on &lt;code&gt;http://127.0.0.1:11434&lt;/code&gt; and confirmed the API exposed models such as &lt;code&gt;gemma3:1b&lt;/code&gt;, &lt;code&gt;qwen3-coder:30b&lt;/code&gt;, &lt;code&gt;tinyllama:latest&lt;/code&gt;, and &lt;code&gt;mistral:latest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I configured a custom Bifrost provider through &lt;code&gt;/api/providers&lt;/code&gt;. The right pattern for Ollama was a key with an empty &lt;code&gt;models&lt;/code&gt; list, which allows all models through.&lt;/p&gt;

&lt;p&gt;The provider config looked like this:&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;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai-ollama2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"keys"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai-ollama2-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dummy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"models"&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;"weight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&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;span class="nl"&gt;"network_config"&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;"base_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:11434"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_request_timeout_in_seconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&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;"custom_provider_config"&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;"base_provider_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowed_requests"&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;"chat_completion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"chat_completion_stream"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;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;With that in place, Bifrost routed both local Ollama and Ollama cloud requests.&lt;/p&gt;

&lt;p&gt;The request volume panel captured the setup process honestly: successful checks and tuning failures.&lt;/p&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%2Fm0ypstaorfh0k38axpvm.png" 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%2Fm0ypstaorfh0k38axpvm.png" alt="Bifrost request volume panel showing successful and failed local test requests" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The token usage panel was not a benchmark, but it gave me a baseline.&lt;/p&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%2Frdwmiz4vvml43dz9enet.png" 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%2Frdwmiz4vvml43dz9enet.png" alt="Bifrost token usage panel after local and cloud Ollama requests" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model usage panel confirmed the requests were hitting the models I expected.&lt;/p&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%2Fp140pz0e844qnqz9c08a.png" 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%2Fp140pz0e844qnqz9c08a.png" alt="Bifrost model usage panel showing gemma3 and another routed model" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Latency was uneven, which is no surprise for mixed local/cloud routing.&lt;/p&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%2F3j6m4o36krj2v7lkgp6g.png" 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%2F3j6m4o36krj2v7lkgp6g.png" alt="Bifrost latency panel after gateway requests" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cache was effectively unused in this small test.&lt;/p&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%2Fq9gt24lv8lo17hy0v6ee.png" 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%2Fq9gt24lv8lo17hy0v6ee.png" alt="Bifrost cache hit rate panel showing no cached input tokens in this small test" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also verified the Docker path on &lt;code&gt;http://127.0.0.1:8082&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8082:8080 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/bifrost-temp:/app/data maximhq/bifrost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That instance also responded.&lt;/p&gt;

&lt;p&gt;At that point the provider layer was proven enough to move on.&lt;/p&gt;
&lt;h2&gt;
  
  
  Classic MCP versus Code Mode
&lt;/h2&gt;

&lt;p&gt;Next, I added a filesystem MCP server scoped to the &lt;code&gt;donotpush&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:8080/api/mcp/client &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "filesystem_blog",
    "connection_type": "stdio",
    "stdio_config": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/bradleymatera/Desktop/gatsby-starter-minimal-blog/donotpush"
      ],
      "envs": ["HOME", "PATH"]
    },
    "tools_to_execute": ["*"],
    "is_ping_available": false
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Bifrost discovered 14 tools from that server.&lt;/p&gt;

&lt;p&gt;In classic MCP mode, the model produced a direct tool call:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem_blog-list_allowed_directories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I executed it through Bifrost:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:8080/v1/mcp/tool/execute &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "id": "call_pjlop9a3",
    "type": "function",
    "function": {
      "name": "filesystem_blog-list_allowed_directories",
      "arguments": "{}"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Allowed directories:
/Users/bradleymatera/Desktop/gatsby-starter-minimal-blog/donotpush
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is the governance point in miniature: the server only saw one draft folder.&lt;/p&gt;

&lt;p&gt;Then I flipped the same client into Code Mode.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT http://127.0.0.1:8080/api/mcp/client/f771c023-8a16-4b34-b03f-ffbfffd34e4b &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "filesystem_blog",
    "connection_type": "stdio",
    "stdio_config": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/bradleymatera/Desktop/gatsby-starter-minimal-blog/donotpush"
      ],
      "envs": ["HOME", "PATH"]
    },
    "tools_to_execute": ["*"],
    "is_ping_available": false,
    "is_code_mode_client": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The four Code Mode meta-tools worked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;listToolFiles&lt;/code&gt; returned:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;servers/
  filesystem_blog.pyi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;readToolFile&lt;/code&gt; returned a compact stub with signatures like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def read_text_file(path: str, head: float = None, tail: float = None) -&amp;gt; dict
def list_allowed_directories() -&amp;gt; dict
def list_directory(path: str) -&amp;gt; dict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;getToolDocs&lt;/code&gt; returned docs for a specific function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;executeToolCode&lt;/code&gt; ran the filesystem server from inside the Code Mode layer:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Execution completed successfully.
Return value: "Allowed directories:\n/Users/bradleymatera/Desktop/gatsby-starter-minimal-blog/donotpush"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the behavior matched the docs. The model saw a small tool-file surface first, then executed the specific tool binding it needed.&lt;/p&gt;

&lt;p&gt;The task was the same in both modes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List the allowed filesystem directory.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Classic MCP exposed the filesystem tools directly. Code Mode exposed a smaller meta-tool surface.&lt;/p&gt;

&lt;p&gt;On this setup, I am not claiming savings. I am claiming behavior verification.&lt;/p&gt;
&lt;h2&gt;
  
  
  Coding agent results
&lt;/h2&gt;

&lt;p&gt;The final step was the coding-agent launch.&lt;/p&gt;

&lt;p&gt;Bifrost CLI launched Codex CLI and showed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Harness       Codex CLI (codex-cli 0.125.0)
Model         openai-ollama2/gpt-oss:20b-cloud
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It also printed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCP: Codex CLI has no native auto-attach yet. Use server URL: http://localhost:8080/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the launch path worked.&lt;/p&gt;

&lt;p&gt;But the actual Codex request did not complete. Codex expects the Responses API, while my Ollama route was using chat completions.&lt;/p&gt;

&lt;p&gt;Codex reported:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error loading config.toml: `wire_api = "chat"` is no longer supported.
How to fix: set `wire_api = "responses"` in your provider config.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is a real provider compatibility issue, not a gateway failure.&lt;/p&gt;

&lt;p&gt;For the working agent test, I used OpenCode, which supports OpenAI-compatible chat completions.&lt;/p&gt;

&lt;p&gt;The config was:&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;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://opencode.ai/config.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bifrost/openai-ollama2/gpt-oss:20b-cloud"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&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;"bifrost"&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;"npm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@ai-sdk/openai-compatible"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bifrost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&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;"baseURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dummy"&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;"models"&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;"openai-ollama2/gpt-oss:20b-cloud"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ollama cloud through Bifrost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"limit"&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;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&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;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="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;Then I ran:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OPENCODE_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/bifrost-opencode.json opencode run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dir&lt;/span&gt; /Users/bradleymatera/Desktop/gatsby-starter-minimal-blog &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; bifrost/openai-ollama2/gpt-oss:20b-cloud &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'Do not edit files. Reply with exactly: opencode through bifrost ok'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opencode through bifrost ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Usage reported:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17154 total tokens
17100 input tokens
54 output tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That was the first real coding-agent request through Bifrost in this test.&lt;/p&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%2Fc00e5lwxuq3prp5hq836.png" 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%2Fc00e5lwxuq3prp5hq836.png" alt="Bifrost terminal results for provider routing, MCP, Code Mode, and OpenCode" width="800" height="1109"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why governance matters here
&lt;/h2&gt;

&lt;p&gt;This setup is not just about making a request succeed.&lt;/p&gt;

&lt;p&gt;It is about making the request visible and controllable.&lt;/p&gt;

&lt;p&gt;A gateway lets you answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which virtual key was used?&lt;/li&gt;
&lt;li&gt;which provider routed the request?&lt;/li&gt;
&lt;li&gt;which MCP server was available?&lt;/li&gt;
&lt;li&gt;what did the dashboard record?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters more than one successful completion.&lt;/p&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%2Fke1uzqt147p7ucgd22op.png" 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%2Fke1uzqt147p7ucgd22op.png" alt="Bifrost control plane sidebar showing observability, models, MCP gateway, governance, and guardrails" width="760" height="3833"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bifrost also surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;virtual keys&lt;/li&gt;
&lt;li&gt;budget controls&lt;/li&gt;
&lt;li&gt;provider routing&lt;/li&gt;
&lt;li&gt;MCP tool governance&lt;/li&gt;
&lt;li&gt;audit logs&lt;/li&gt;
&lt;li&gt;cost tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not only enterprise language. Even for solo projects, it is useful to know what key is being used, what model is being called, and what tools the agent can reach.&lt;/p&gt;

&lt;p&gt;If I am running multiple demos or experiments, I want separate keys, usage tracking, and some protection against accidental spending.&lt;/p&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%2Fbztb7otrdquyj40j8han.png" 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%2Fbztb7otrdquyj40j8han.png" alt="Bifrost governance navigation showing virtual keys, users, teams, roles, audit logs, and guardrails" width="760" height="2227"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Bifrost as the control plane
&lt;/h2&gt;

&lt;p&gt;Without Bifrost, the setup 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;Agent → Provider
Agent → MCP server
Agent → another provider
Agent → another tool config
Agent → another local config file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With Bifrost:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent → Bifrost → Providers
              → MCP tools
              → routing
              → governance
              → logs
              → cost tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That second layout is easier to reason about.&lt;/p&gt;

&lt;p&gt;It does not make agents perfect, but it does make the system easier to inspect.&lt;/p&gt;
&lt;h2&gt;
  
  
  Benefits and limitations
&lt;/h2&gt;

&lt;p&gt;What was clear from this pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the gateway is easy to start with NPX or Docker&lt;/li&gt;
&lt;li&gt;the dashboard makes traffic, latency, tokens, and errors visible&lt;/li&gt;
&lt;li&gt;the CLI reduces per-agent setup work&lt;/li&gt;
&lt;li&gt;the CLI can switch between supported agents without hand-editing every config&lt;/li&gt;
&lt;li&gt;virtual keys, audit logs, and budget controls add governance&lt;/li&gt;
&lt;li&gt;Code Mode turns the MCP surface into a smaller discovery-and-execute flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What was also clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code Mode is not a magic switch. It is worth validating in every environment.&lt;/li&gt;
&lt;li&gt;Classic MCP can still be the better choice for very small setups.&lt;/li&gt;
&lt;li&gt;Provider compatibility matters. One OpenAI-compatible route is not the same as another.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My local dashboard was on &lt;code&gt;v1.4.24&lt;/code&gt;. The docs call out Code Mode from &lt;code&gt;v1.4.0-prerelease1&lt;/code&gt;. That is a good reminder: verify the exact version where you run this.&lt;/p&gt;

&lt;p&gt;The provider-specific limitation was real. OpenCode worked through Bifrost + Ollama. Codex CLI launched, but the request failed because the route needed Responses compatibility.&lt;/p&gt;

&lt;p&gt;That is not a reason to discard the setup. It is a reason to test each agent/provider pair instead of assuming every OpenAI-compatible route behaves identically.&lt;/p&gt;
&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;p&gt;Bifrost GitHub repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/maximhq" rel="noopener noreferrer"&gt;
        maximhq
      &lt;/a&gt; / &lt;a href="https://github.com/maximhq/bifrost" rel="noopener noreferrer"&gt;
        bifrost
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fastest enterprise AI gateway (50x faster than LiteLLM) with adaptive load balancer, cluster mode, guardrails, 1000+ models support &amp;amp; &amp;lt;100 µs overhead at 5k RPS.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Bifrost AI Gateway&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://goreportcard.com/report/github.com/maximhq/bifrost/core" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7f7e70df9fdaaf4f485f59ca6bc0b5cbbf134d03dd5721da4e31f90f618fc304/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f6d6178696d68712f626966726f73742f636f7265" alt="Go Report Card"&gt;&lt;/a&gt;
&lt;a href="https://discord.gg/exN5KAydbU" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/282b7719f04b28f5959f5e1e17aee806d65f8eea3b862b57af350df0ab57be6f/68747470733a2f2f646362616467652e6c696d65732e70696e6b2f6170692f7365727665722f68747470733a2f2f646973636f72642e67672f65784e354b41796462553f7374796c653d666c6174" alt="Discord badge"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/maximhq/bifrost" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8bc2db302c566210d14c09b278639a3f63f07def5fc635a8869e59c996b3100f/68747470733a2f2f636f6465636f762e696f2f67682f6d6178696d68712f626966726f73742f6272616e63682f6d61696e2f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b0899925aadfed8626116707178a4015d8cf4aaa0b80acb632cb4782c6dc7272/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6d6178696d68712f626966726f7374"&gt;&lt;img src="https://camo.githubusercontent.com/b0899925aadfed8626116707178a4015d8cf4aaa0b80acb632cb4782c6dc7272/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6d6178696d68712f626966726f7374" alt="Docker Pulls"&gt;&lt;/a&gt;
&lt;a href="https://app.getpostman.com/run-collection/31642484-2ba0e658-4dcd-49f4-845a-0c7ed745b916?action=collection%2Ffork&amp;amp;source=rip_markdown&amp;amp;collection-url=entityId%3D31642484-2ba0e658-4dcd-49f4-845a-0c7ed745b916%26entityType%3Dcollection%26workspaceId%3D63e853c8-9aec-477f-909c-7f02f543150e" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/82ccefddb001e2caf9d399f1153fdda561cf3da341bb270e18644d516906bc64/68747470733a2f2f72756e2e7073746d6e2e696f2f627574746f6e2e737667" alt="Run In Postman"&gt;&lt;/a&gt;
&lt;a href="https://artifacthub.io/packages/search?repo=bifrost" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a6a3c734d6bd57fa8e1d508ac0cdba555bdbcd9191b29b32cf37a964b86b9c67/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f61727469666163746875622e696f2f62616467652f7265706f7369746f72792f626966726f7374" alt="Artifact Hub"&gt;&lt;/a&gt;
&lt;a href="https://github.com/maximhq/bifrost/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3cb44c15a532770a066ba8e61bf11506ad5400e5c61d48f6b639101e442bee79/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6d6178696d68712f626966726f7374" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The fastest way to build AI applications that never go down&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Bifrost is a high-performance AI gateway that unifies access to 23+ providers (OpenAI, Anthropic, AWS Bedrock, Google Vertex, and more) through a single OpenAI-compatible API. Deploy in seconds with zero configuration and get automatic failover, load balancing, semantic caching, and enterprise-grade features.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/maximhq/bifrost/./docs/media/getting-started.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fmaximhq%2Fbifrost%2FHEAD%2F.%2Fdocs%2Fmedia%2Fgetting-started.png" alt="Get started"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Go from zero to production-ready AI gateway in under a minute.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Start Bifrost Gateway&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install and run locally&lt;/span&gt;
npx -y @maximhq/bifrost

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Or use Docker&lt;/span&gt;
docker run -p 8080:8080 maximhq/bifrost&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Configure via Web UI&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Open the built-in web interface&lt;/span&gt;
open http://localhost:8080&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Make your first API call&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;curl -X POST http://localhost:8080/v1/chat/completions \
  -H &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Content-Type: application/json&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; \
  -d &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;{&lt;/span&gt;
&lt;span class="pl-s"&gt;    "model": "openai/gpt-4o-mini",&lt;/span&gt;
&lt;span class="pl-s"&gt;    "messages": [{"role": "user", "content": "Hello, Bifrost!"}]&lt;/span&gt;
&lt;span class="pl-s"&gt;  }&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;That's it!&lt;/strong&gt; Your AI gateway is running with a web interface for visual configuration…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/maximhq/bifrost" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Bifrost CLI article:&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/anthonymax/bifrost-cli-codex-cli-one-command-to-set-up-openais-coding-agent-with-any-model-caa" class="crayons-story__hidden-navigation-link"&gt;Bifrost CLI + Codex CLI: One Command to Set Up OpenAI's Coding Agent with Any Model&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/anthonymax" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F2103048%2F716988a5-9c51-49bf-acef-191bc6dd2fee.jpeg" alt="anthonymax profile" class="crayons-avatar__image" width="400" height="400"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/anthonymax" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Anthony Max
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Anthony Max
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png" width="166" height="102"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3369445" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/anthonymax" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F2103048%2F716988a5-9c51-49bf-acef-191bc6dd2fee.jpeg" class="crayons-avatar__image" alt="" width="400" height="400"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Anthony Max&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/anthonymax/bifrost-cli-codex-cli-one-command-to-set-up-openais-coding-agent-with-any-model-caa" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 19&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/anthonymax/bifrost-cli-codex-cli-one-command-to-set-up-openais-coding-agent-with-any-model-caa" id="article-link-3369445"&gt;
          Bifrost CLI + Codex CLI: One Command to Set Up OpenAI's Coding Agent with Any Model
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/anthonymax/bifrost-cli-codex-cli-one-command-to-set-up-openais-coding-agent-with-any-model-caa" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;111&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/anthonymax/bifrost-cli-codex-cli-one-command-to-set-up-openais-coding-agent-with-any-model-caa#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              5&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Bifrost MCP Gateway and Code Mode article:&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hadil/how-bifrosts-mcp-gateway-and-code-mode-power-production-grade-llm-gateways-235i" class="crayons-story__hidden-navigation-link"&gt;How Bifrost’s MCP Gateway and Code Mode Power Production-Grade LLM Gateways&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hadil" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1209000%2Fb29d37d8-2efe-4391-9796-a6f8a483f1bd.png" alt="hadil profile" class="crayons-avatar__image" width="768" height="1376"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hadil" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Hadil Ben Abdallah
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Hadil Ben Abdallah
                
              
              &lt;div id="story-author-preview-content-3202891" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hadil" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1209000%2Fb29d37d8-2efe-4391-9796-a6f8a483f1bd.png" class="crayons-avatar__image" alt="" width="768" height="1376"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Hadil Ben Abdallah&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hadil/how-bifrosts-mcp-gateway-and-code-mode-power-production-grade-llm-gateways-235i" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 29&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hadil/how-bifrosts-mcp-gateway-and-code-mode-power-production-grade-llm-gateways-235i" id="article-link-3202891"&gt;
          How Bifrost’s MCP Gateway and Code Mode Power Production-Grade LLM Gateways
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/llm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;llm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hadil/how-bifrosts-mcp-gateway-and-code-mode-power-production-grade-llm-gateways-235i" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;97&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hadil/how-bifrosts-mcp-gateway-and-code-mode-power-production-grade-llm-gateways-235i#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              16&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Official Bifrost setup article on Medium:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://medium.com/@kuldeep.paul08/how-to-set-up-bifrost-your-llm-gateway-in-30-seconds-3b152fd9b7a3" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;medium.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Final status
&lt;/h2&gt;

&lt;p&gt;Here is the final state of the test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Install Bifrost locally with NPX&lt;/li&gt;
&lt;li&gt;[x] Install Bifrost locally with Docker&lt;/li&gt;
&lt;li&gt;[x] Open the dashboard and confirm the UI works&lt;/li&gt;
&lt;li&gt;[x] Configure at least one provider (Ollama)&lt;/li&gt;
&lt;li&gt;[ ] Configure OpenAI provider request blocked by missing secret&lt;/li&gt;
&lt;li&gt;[x] Start Bifrost CLI&lt;/li&gt;
&lt;li&gt;[x] Confirm Bifrost CLI asks for the right config&lt;/li&gt;
&lt;li&gt;[x] Confirm Bifrost CLI config storage&lt;/li&gt;
&lt;li&gt;[x] Launch Codex CLI through Bifrost CLI&lt;/li&gt;
&lt;li&gt;[x] Record the Codex limitation with this route&lt;/li&gt;
&lt;li&gt;[x] Launch one working coding agent through Bifrost with OpenCode&lt;/li&gt;
&lt;li&gt;[x] Add at least one MCP server&lt;/li&gt;
&lt;li&gt;[x] Verify the tool surface&lt;/li&gt;
&lt;li&gt;[x] Verify classic MCP tool execution&lt;/li&gt;
&lt;li&gt;[x] Enable Code Mode&lt;/li&gt;
&lt;li&gt;[x] Verify the Code Mode meta-tools&lt;/li&gt;
&lt;li&gt;[x] Run the same small MCP task with and without Code Mode&lt;/li&gt;
&lt;li&gt;[x] Verify local Ollama routing through Bifrost&lt;/li&gt;
&lt;li&gt;[x] Verify Ollama cloud routing through Bifrost&lt;/li&gt;
&lt;li&gt;[ ] Check provider selection and fallback path blocked by missing OpenAI key&lt;/li&gt;
&lt;li&gt;[x] Capture screenshots of the dashboard and terminal results&lt;/li&gt;
&lt;li&gt;[x] Record exact errors, fixes, and commands&lt;/li&gt;
&lt;li&gt;[out of scope] Replace vendor benchmark claims with my own benchmark for a one-server test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is still not a benchmark. It is a tested setup walkthrough and an initial MCP + Code Mode proof. I do not want to turn a one-server smoke test into a fake performance claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;I am not testing Bifrost because I need another AI tool.&lt;/p&gt;

&lt;p&gt;I am testing it because the wiring is getting messy.&lt;/p&gt;

&lt;p&gt;Every agent wants a config file. Every provider wants a key. Every MCP server adds tools. Every tool adds context.&lt;/p&gt;

&lt;p&gt;Bifrost does not solve all of that, but it does give you one place to inspect and control it.&lt;/p&gt;

&lt;p&gt;In this setup, the core pieces worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the gateway installed cleanly&lt;/li&gt;
&lt;li&gt;the dashboard gave me visibility&lt;/li&gt;
&lt;li&gt;Ollama routed through it&lt;/li&gt;
&lt;li&gt;MCP tools were governable&lt;/li&gt;
&lt;li&gt;Code Mode exposed the expected meta-tools&lt;/li&gt;
&lt;li&gt;OpenCode completed a request through the gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The limits are also clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI routing still needs a real &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Codex CLI launched, but the request path needs Responses compatibility&lt;/li&gt;
&lt;li&gt;the Code Mode savings claim still needs a larger multi-server test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My takeaway is practical: Bifrost can be a useful control layer for local agent experiments, but the value depends on provider wiring, MCP scoping, and agent-specific testing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <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://dev.to/bradleymatera/testing-that-i-actually-run-a-small-pyramid-pmk</link>
      <guid>https://dev.to/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://dev.to/bradleymatera/aws-vs-azure-vs-google-cloud-the-ultimate-free-tier-battle-survival-guide-2fam</link>
      <guid>https://dev.to/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>
  </channel>
</rss>
