In software engineering, development workflows have long prioritized frictionless shipping, aiming to minimize the barriers between a developer's keyboard and production.
However, at the AI Engineer Europe conference, Armin Ronacher (creator of Flask and co-founder of Aerendil) and Cristina Poncela Cubeiro (Native AI Engineer at Aerendil) suggested a different perspective: engineering teams need to intentionally reintroduce friction into their development cycles. [1]
The push for complete agent autonomy can create unintended architectural challenges. Removing all friction from code creation often eliminates the human judgment necessary to maintain a healthy codebase.
1. The Psychological Trap: The Efficiency Illusion
The transition into AI-assisted development typically moves through three distinct phases:
- Phase 1: The Unlock: AI tools are adopted as helpful productivity shortcuts.
- Phase 2: The Mainstream: Widespread adoption turns the initial productivity gains into the new baseline.
- Phase 3: The Pressure: Expectations rise, creating pressure to ship code faster with less time allocated for system design.
When developers watch hundreds of lines of code generate in seconds, it creates an illusion of high efficiency. This has led to a practice sometimes called "vibe coding"—where a developer provides a high-level prompt, accepts the authoritative-looking output, and merges it without fully understanding its long-term impact.
An extreme example of this trend occurred during Spotify’s Q4 2025 earnings call, where leadership noted that some experienced developers were deploying features via mobile devices using internal automated tools without manually writing the underlying code. [3] When code is merged without thorough human review or architectural design, overall accountability drops.
2. The Data: The Rise of Code Entropy
This decline in development intentionality is reflected in recent repository data. Codebases are accumulating technical debt faster than manual teams can address it. A study by GitClear, which analyzed over 211 million lines of code across enterprise repositories, highlighted several key trends: [4]
- Decline in Refactoring: Code reuse and structural refactoring fell significantly between 2021 and 2025. AI models tend to append new code rather than restructuring existing repositories into reusable modules.
- Increased Code Duplication: Semantic duplication and copied blocks grew between four and eight times over.
- Higher Short-Term Churn: Code that is rewritten or deleted within 30 days of being committed has risen sharply, indicating that AI-generated code frequently requires immediate correction after deployment. [2, 4]
Writing for The Pragmatic Engineer, developer Mario Zechner describes this as a capacity mismatch. [2] Even if an AI agent generates code with a low error rate, the sheer volume of code generated introduces a high absolute number of bugs. Because human review capacity does not scale at the same rate as automated text generation, teams risk "rubber-stamping" massive pull requests without a proper review. [1, 2]
3. The Technical Challenge: Local Progress vs. Global Architecture
AI models often struggle to maintain large applications due to the structural differences between building a library versus building a product: [1]
- Libraries (High AI Performance): Libraries generally have tight constraints, minimal external dependencies, and a small, well-defined API surface area. This makes them easier for an AI to reason about.
- Products (Low AI Performance): Products involve complex, intertwined states, including UIs, API responses, user permissions, billing systems, and feature flags.
Because a complex product cannot fit entirely into an LLM's context window, an agent may write code that works perfectly in isolation but violates the broader system architecture.
Furthermore, agents do not experience the professional caution that prevents a human engineer from taking shortcuts, such as using an overly broad error handler. Automated systems are optimized to pass immediate local tests and make progress, which can inadvertently mask systemic failures—such as an application loading incorrect default values into a live database instead of failing safely. [1]
4. Designing an "Agent-Legible" Codebase
To mitigate code quality degradation, repositories should be structured so that automated tools can read and modify them without introducing errors. The presenters outline several guidelines for building an agent-legible codebase: [1]
Mechanical Enforcement Via Linting
- No Bare Catch-Alls: Prevent the application from swallowing errors silently by forcing explicit error handling.
- Unified Query Interfaces: Restrict database operations to a single interface so the agent does not scatter ad-hoc queries throughout the repository.
- Primitive UI Libraries: Enforce the use of a pre-existing component library rather than allowing raw, inline UI styling to ensure visual consistency.
- Unique Function Names: Use globally unique function names to improve token efficiency. This allows the agent to locate specific features instantly without duplicating logic.
- Erasable Syntax TypeScript: Use type configurations that sit clearly on top of pure JavaScript. This ensures a single source of truth between the code and the compiler, eliminating translation confusion for the AI.
5. Reintroducing Deliberate Friction
A critical step in managing automated development is separating repetitive mechanical tasks from architectural oversight. To achieve this, workflows can implement a two-track pull request review system, similar to the "PI" extension framework used at Arendelle: [1, 2]
Track 1: Automated Agent Loop
The agent manages style violations, minor syntax bugs, and linter rule corrections automatically. If a mechanical rule is broken, the issue is routed back to the AI for automated fixes without human intervention.
Track 2: Intentional Human Friction
The agent is explicitly blocked when attempting high-stakes operations. A human engineer must manually review and approve changes involving:
- Database migrations (assessing lock risks and data volume).
- Authentication, security, and permission changes.
- The addition of new third-party dependencies.
This framework forces human intervention at critical junctures, ensuring that structural decisions receive appropriate scrutiny.
Conclusion: Velocity Requires Control
High-velocity code generation is highly effective for isolated tasks, such as creating reproduction cases for bugs or building short-lived prototypes. However, long-term software sustainability requires human understanding and consistency.
In physical systems, friction is the mechanism that allows for steering and control. Software development requires a similar balancing force. Velocity should not be the sole metric of engineering success; teams must actively maintain control over their system architecture to ensure codebases remain maintainable over time.
Sources & Further Reading
- [1] Ronacher, A. & Poncela Cubeiro, C. (2026). "The Friction Is Your Judgment." AI Engineer Europe. Talk Presentation Transcript & Materials.
- [2] Zechner, M. (2026). "AI Coding Agents Are Producing 'Garbage' — and the Industry Needs to Slow Down." As reported on The Pragmatic Engineer / BigGo Finance. Article Link.
- [3] NineTwoThree Blog. (2026). "Why AI-Generated Code Quality Is Worse Than You Think: Spotify's Vibe Coding Paradigm." Analysis on Spotify Q4 2025 Earnings Call.
- [4] GitClear Research Report. (2025/2026). "AI Copilot Code Quality: Look Back at 12 Months of Data." GitClear Whitepaper.
