惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V2EX - 技术
V2EX - 技术
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
S
Securelist
P
Privacy & Cybersecurity Law Blog
Scott Helme
Scott Helme
T
Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
量子位
博客园 - Franky
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Latest news
Latest news
T
Troy Hunt's Blog
N
News | PayPal Newsroom
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
N
Netflix TechBlog - Medium
小众软件
小众软件
P
Palo Alto Networks Blog
Spread Privacy
Spread Privacy
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
WordPress大学
WordPress大学
L
Lohrmann on Cybersecurity
L
LINUX DO - 最新话题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Last Watchdog
The Last Watchdog
S
Security @ Cisco Blogs
P
Privacy International News Feed
Last Week in AI
Last Week in AI
Microsoft Security Blog
Microsoft Security Blog
T
Tailwind CSS Blog
博客园_首页
云风的 BLOG
云风的 BLOG
V
Vulnerabilities – Threatpost
D
DataBreaches.Net
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
罗磊的独立博客
Engineering at Meta
Engineering at Meta
Forbes - Security
Forbes - Security
T
Tenable Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Lessons from three months of vibe coding (and a complexity score of 53)
Max Kryvych · 2026-05-18 · via DEV Community

TL;DR — I spent three months vibe-coding a side project with an AI agent. It felt fast and productive until I opened a file and saw 3000 lines, functions that should have been one helper but were copy-pasted ten times, and a cyclomatic complexity score of 58 in one of them. The agent wasn't the problem. The missing feedback loop was. This is what I should have set up on day one — and what I now consider non-negotiable when working with AI agents.

uv run complexipy . --top 10
./rounds/views.py
    current_state 58 (last: 52, Δ = +6)  ❌ FAILED
    host_advance_post_round 45 (last: 9, Δ = +36)  ❌ FAILED
    host_rewind_round 37 (new, Δ = +37)  ❌ FAILED
    audience_panel 34 (last: 35, Δ = -1)  ❌ FAILED
    debate_vote_results 18  ❌ FAILED
    host_create_game 16  ❌ FAILED
    _debate_winner_details 12  ✅ PASSED
    audience_prompt_submitted 11  ✅ PASSED
    host_select_vote_winner 11  ✅ PASSED
    preview_screen 11  ✅ PASSED

Failed functions:
 - ./rounds/views.py: audience_panel, current_state, debate_vote_results, host_advance_post_round, host_create_game,
host_rewind_round

Enter fullscreen mode Exit fullscreen mode

The moment it clicked

I wasn't running a tool. I wasn't reviewing a PR. I was just poking around the repo to remind myself where something lived, and I opened a file that had grown past 3000 lines.

Inside, I found functions that should have been one shared helper, copy-pasted with one or two lines different each time. Every time I'd asked the agent to add a feature that was "similar but slightly different," it had just duplicated the whole thing and tweaked the bits that varied.

I ran radon out of curiosity. One function clocked in at cyclomatic complexity 58. Fifty-three branches in a single function. That was the moment I realized I had a problem I couldn't easily fix.

How I got there

I want to be honest about how this started, because I think it's the most common path.

It was a small idea — a Django side project. I knew how to code; this wasn't me learning Python from scratch. But I was learning how to work with an AI agent. I didn't know the workflows, the tooling around agents, what good guardrails looked like, or how other people were structuring this kind of work. So I was figuring it out as I went.

I told myself I was doing spec-driven development. I'd write a description of what I wanted, hand it to the agent, and review the output. In reality, I was vibe coding. I wasn't actually reading the diffs. I was checking that the feature worked — does the endpoint return the right thing? does the test pass? — and moving on. The agent shipped, I accepted, repeat.

For weeks it felt great. Features landed. Tests were green. I had momentum.

The slow collapse

The problem wasn't a single bad commit. The problem was a thousand small, locally rational choices.

Every time I asked for a feature that was "like the last one but with a small change," the agent didn't extract a shared helper — it copied the previous implementation and edited it. That's the safest move for the agent in any given turn: copying working code is less likely to break than refactoring. Without anything pushing back, copying wins every time.

The if/elif chains kept growing. New cases got appended, not refactored into a dispatch table or a strategy. Branches piled on branches. One function ended up at CC 58.

The CSS — same story. New components got their own styles, copy-pasted from the previous component, slightly tweaked. There was no design system, no shared tokens, no enforced layering. It just sprawled.

By the time I noticed, two things were true at once:

  1. The codebase was big enough that I couldn't hold it in my head anymore.
  2. I was afraid to touch it myself. Not because I didn't know how — because any change risked breaking something I couldn't reason about. The agent had become the only entity that could navigate the mess, and it was the one that had created the mess.

That's the worst place to be. The point of using an AI agent is to amplify what you can do. If you end up unable to refactor your own code without the agent, you haven't amplified anything. You've outsourced something you can't take back.

The actual lesson

Here's what I missed: the agent has no perception of whether code is good or bad. None. It doesn't know your conventions, your architecture, your standards. It doesn't get tired. It doesn't refactor unless something tells it to.

I thought I was giving it feedback. I wasn't. "Make it cleaner" is not feedback an agent can act on. "Reduce complexity" is not feedback either. The agent needs feedback that is specific, machine-readable, and automatic — the kind you get from a linter, a type checker, an architectural test.

When I had no feedback loop, the agent did exactly what an unsupervised junior dev would do under pressure: it solved each problem in the easiest local way. Copy-paste. Append a branch. Skip the refactor. Each move was rational on its own. The aggregate was slop.

The reframe that finally landed for me: the agent behaved correctly given the environment I gave it. The environment was the bug, not the agent.

Why quality gates are non-negotiable now

Quality gates — linters, type checks, complexity limits, architectural fitness functions, duplication detectors — were a "good engineering practice" before AI. They were nice to have. You could ship without them.

With AI-assisted development, that changes. Here's why:

  • The rate of code production is now far higher than your rate of code comprehension. Your mental context window didn't grow when you started using an agent. The codebase's growth rate did.
  • The agent has no memory of your conventions across sessions. Anything you don't encode in tooling will drift.
  • The agent has no incentive to refactor. Refactoring increases diff size and risk. Copying is cheaper. Without a gate, entropy wins.
  • "Just review it carefully" doesn't scale. That defeats the entire point of using an agent. If every diff needs a human read for style and complexity, you've lost the speedup.

So gates aren't optional anymore. They're prerequisites. You set them up before the agent writes a line, not after. The time you spend configuring them up front is the rule of our job now — it's not overhead, it's the work.

Matt Pocock frames this as "outrunning your headlights": AI generates code faster than you can verify it, and the only way to stay inside the beam is the same discipline that always kept engineers honest — incremental delivery, test-first, and structures you can reason about. The gates are what put the headlights back on.

When the agent produces something that violates a gate, the failure is automatic, specific, and machine-readable. You feed it back to the agent, the agent fixes it, you move on. That is the feedback loop I was missing for three months.

The checklist I wish I'd had on day one

I'm building this in tiers. Pick the tier that matches the project's lifespan.

Tier 0 — Bare minimum (any project, even a weekend hack)

Set up before the agent writes a single line.

  • pyproject.toml with ruff for lint + format. Enable complexity rules (C901, max-complexity around 10), bugbear (B), simplify (SIM), pyupgrade (UP), and a sensible subset of pylint (PL).
  • Strict type checking with mypy or pyright in strict mode for your own modules.
  • Pre-commit hooks wired to both, so violations can't even land in a commit.
  • A task runner like mise (or a Makefile / justfile) with check, test, fix tasks. One obvious command for the agent to run.
  • A short CONTRIBUTING.md, AGENTS.md, or .cursorrules stating: max function length, max complexity, layering rules (router → service → repository), no business logic in routers, no SQL outside repositories, no copy-paste — extract a function or ask.
  • A skill library that encodes your architecture decisions as agent-readable workflows, not just rules. Rules tell the agent what not to do; skills tell it what to reach for. superpowers, get-shit-done, and mattpocock/skills are good starting points — or write framework-specific ones: "when building a FastAPI endpoint, always layer router → use case → repository, never skip levels."

Tier 1 — Recommended for anything you'll touch in a month

  • pytest with coverage gated at a real number (60–80%, not 100%).
  • A duplication detector (pylint --enable=duplicate-code, or jscpd).
  • bandit for security smells.
  • CI that runs all of this on every PR and blocks merge.
  • A single integration test that boots the app and hits /health. This alone catches most "the agent broke imports" failures.

Tier 2 — Production-grade

  • Architectural tests — Python lets anything import anything; you need to enforce lanes explicitly. Three options depending on taste: import-linter (contract-based, closest to config), pytest-archon (same idea expressed as pytest tests — easier for complex rules), deply (layer-based, closer to ArchUnit if you're coming from Java). Good writeups: roman.pt, dev.to/vashkatsi.
  • Mutation testing on critical modules (mutmut). Agents love writing tests that pass without testing anything.
  • Dependency scanning (pip-audit).
  • Complexity tracked over time with radon or xenon in CI — fail on regressions, not just absolute thresholds.
  • Contract tests against your OpenAPI spec (schemathesis). Free coverage given you're on FastAPI.

How to give the agent useful feedback

This is the part that changed my workflow most.

Don't say: "this code is messy, clean it up."
Do say: "here is the output of ruff check app/services/user_service.py. Fix every finding without using # noqa. If a fix changes a function signature, list the call sites first and propose the change."

Don't say: "reduce complexity."
Do say: "this function dispatches on event_type with a 58-branch if/elif chain. Replace it with a dict mapping event_type to handler functions, one handler per branch, each unit-tested."

The pattern: specific, mechanical, verifiable. Name the refactor. Cite the tool output. Constrain the solution. That's how you get a refactor instead of a rename.

The tooling in my reference project

After the Django project, I started a separate FastAPI reference project specifically to encode what I'd learned. Different framework, but the principles are framework-agnostic. The point isn't FastAPI vs. Django — the point is what the setup looks like before any feature code lands.

You can find it here: github.com/maxkrivich/fast-api-reference-project

A quick note before the tool list: you don't need enterprise tooling for this. SonarQube, Codacy, Snyk, and if your company already pays for them, use them. But every gate I'm about to list is open source and free, and the entire point — feeding structured failures back to an agent — works just as well with ruff and mypy as it does with a commercial SaaS. Don't let "we don't have SonarQube" be the reason you skip the gates.

Here's what's in the repo, briefly:

  • ruff — single tool for lint + format, fast enough to run on save. Complexity is gated at max-complexity = 10 — a threshold that would have caught my CC=58 immediately. Config lives in ruff.toml.
  • ty in strict mode — Astral's new type checker. Catches a huge class of agent mistakes (wrong types, missing returns, unhandled Optional) before they reach runtime.
  • prek — Rust-based git hooks manager (same idea as pre-commit, but faster and no Python dependency). Runs ruff, bandit, import-linter, pylint, gitleaks, and hadolint on every commit. Config in prek.toml.
  • mise — one entry point for tasks and tool versions. The agent runs a single command (mise run full-ci-check) and gets a structured report it can act on. Config in mise.toml.
  • pytest + coverage — the baseline. Gated at a real number, not aspirational.
  • bandit — security smells. Catches agent moves like subprocess.run(..., shell=True) with user input.
  • pip-audit — dependency CVEs, run as uv audit in CI. Agents will happily pin a vulnerable version if you don't check.
  • import-linter — enforces hexagonal architecture via import contracts. Seven contracts defined in pyproject.toml that make the build fail if a router imports a SQLAlchemy session directly, or a domain model touches an HTTP adapter. Python lets anything import anything — this is how you enforce the lanes.
  • pylint (duplicate-code only) — runs on every commit via prek, flagging copy-paste before it accumulates. The exact failure mode that wrecked my Django project.
  • radon / xenon — complexity tracking. In dev deps for local inspection; the plan is to wire xenon into CI to fail on regressions, not just absolute thresholds.
  • CI via GitHub Actions — every PR runs the full gate set; nothing merges that hasn't passed. Workflows live in .github/workflows/.

What gates won't catch

Honest disclaimer, because I don't want to oversell this.

Gates catch mechanical slop — complexity, duplication, style, types, surface-level security. They don't catch architectural slop — wrong abstractions, leaky boundaries, anemic domain models, a service that should have been three services. They don't catch a bad data model. They don't catch a missing concept.

What gates do is reclaim your attention. Once mechanical quality is automated, your code reviews shift from "is this clean?" to "is this the right shape?" That's a much better use of human attention, and it's the only kind of review that's actually worth your time when working with an agent.

You still have to think. The gates just stop you from drowning while you do it.

Where I'm at now

The project that hit CC 58 is at a point where I think it's easier to rewrite than refactor. That's a hard thing to admit, but it's where I am. The next version starts with the checklist in place before any feature lands.

If there's one thing I'd want you to take from this: set up the gates first. Not after the first feature. Not after the first refactor. First. The hour you spend configuring ruff and pre-commit on day one is the hour that prevents the month you'd otherwise spend untangling slop on day ninety.

The agent is not the problem. The environment we give it is.


If you've been through something similar, or have tooling I missed, I'd genuinely like to hear it — leave a comment or ping me on GitHub.