Sunday, March 29, 2026

El libro que llevo 25 años intentando no tener que escribir

"Hoy, cuando la última moda es el AI-assisted coding, sonrío pensando que los principios que aprendí hace diez años siguen siendo los mismos." — del prólogo, por una ingeniera que trabajó en el equipo

Durante más de dos décadas he explicado las mismas ideas a los mismos tipos de equipos. Equipos distintos, empresas distintas, contextos distintos. Y sin embargo, el patrón se repetía con una regularidad que ya no puedo ignorar.

Equipos talentosos. Equipos capaces. Tecnología razonable. Y aun así: la sensación de correr cada vez más fuerte para avanzar cada vez menos.

Lewis Carroll lo describió mejor que yo en A través del espejo: "Aquí, como ves, se requiere correr todo cuanto se pueda para permanecer en el mismo sitio." Durante años pensé que esa metáfora era exagerada. Ya no.

Parte del problema es cómo pensamos sobre el software. Decimos que lo "construimos", como si fuera algo que se termina y queda ahí. Pero el software no se construye. Se cultiva. Es un sistema vivo que crece, cambia y se degrada. Y los sistemas vivos necesitan atención continua, no solo construcción.

He llegado a la conclusión de que lo más honesto que podía hacer era escribirlo.

De qué va el libro

"Menos software, más impacto" tiene un subtítulo que no deja mucho a la imaginación: Cómo evitar que tu equipo colapse bajo el peso de su propio código.

La tesis central es incómoda: el mayor problema de la mayoría de los equipos no es que escriban código malo. Es que escriben código de más.

El software existente consume recursos continuamente, lo uses o no. Cada funcionalidad añadida, cada integración, cada decisión de diseño que se acumula sin revisión tiene un coste que no aparece en ningún roadmap pero que aparece cada día. Lo llamo el coste basal del software, en analogía al metabolismo basal de un organismo: el gasto mínimo para seguir funcionando. Y como el metabolismo, si no se gestiona, crece hasta consumir toda la energía disponible.

El libro recorre cuatro grandes bloques:

  • Fundamentos: qué es el Lean Software Development y por qué el coste basal es el concepto central que lo conecta todo
  • Los cinco principios: eliminar desperdicios, amplificar el aprendizaje, decidir en el último momento responsable, entregar lo antes posible, empoderar al equipo
  • Calidad sostenible: por qué la calidad no es el enemigo de la velocidad sino su única base duradera
  • Pensamiento sistémico: optimizar el todo, integrar Lean con XP y mentalidad de producto, y qué pasa si no haces nada

Son 192 páginas. Basadas en más de 25 años de experiencia en equipos reales: Alea Soluciones, The Motion, Nextail, Clarity AI. Con casos concretos, conflictos reales y errores propios reconocidos. El libro incluye también las perspectivas de ocho profesionales que han vivido estas transformaciones desde dentro, en distintos roles y contextos.

Para quién es (y para quién no es)

Este no es un libro para quien quiere mejorar su código de forma individual. Hay libros excelentes para eso y este no es uno de ellos.

Es para quien toma decisiones sobre qué se construye, qué no se construye y qué se elimina. Engineering Managers, Tech Leads, Product Managers, CTOs. Cualquier persona con responsabilidad directa sobre la capacidad de un equipo a seis meses, un año, tres años vista.

Si tu día a día es decidir prioridades, gestionar capacidad y negociar alcance, lo que viene en el libro te va a resultar familiar. Y probablemente incómodo. Esa es la intención.

Por qué ahora

Hay mucha literatura sobre Lean, XP y Agile en inglés. En español, menos de la que debería haber. Y casi ninguna que combine los tres enfoques de forma integrada, con casos reales de equipos que conozco de primera mano.

Además, el contexto actual lo hace más urgente. La aceleración que trae la IA hace que las decisiones sobre qué construir y qué no construir sean más importantes, no menos. Amplificar la capacidad de un equipo que ya construye demasiado no resuelve el problema. Lo acelera.

El borrador está completo. Ahora viene la revisión, la edición y la preparación para publicación. Si te interesa estar entre los primeros en leerlo, escríbeme: eferro@eferro.net

Sunday, March 01, 2026

Encoding Experience into AI Skills

I'd been tweaking my augmented coding setup for months - adjusting CLAUDE.md rules, adding instructions for testing discipline, complexity management, incremental delivery. Things I've repeated to every team I've worked with, now repeated to AI agents. It worked, but it felt like writing the same email over and over.

Then I found Lada Kesseler's skill-factory.


What Skills Are (And Why They Matter)

If you use Claude Code, you already know about CLAUDE.md - a file where you put instructions that the agent reads at the start of every conversation. It works. But it has a problem: everything is always loaded. Your TDD guidelines, your Docker best practices, your refactoring workflow - all of it competing for the agent's limited context window, whether it's relevant or not.

Skills solve this differently. They're packaged knowledge that activates only when relevant. You type /mutation-testing and the agent gains deep expertise about finding weak tests through mutation analysis. You type /complexity-review and it becomes a technical reviewer that challenges your proposals against 30 dimensions of complexity. The rest of the time, that knowledge stays out of the way.

Think of it as progressive disclosure for AI context. The agent gets what it needs, when it needs it.

The Discovery: Lada Kesseler's Skill Factory

Lada Kesseler built the skill-factory - a repository with 315 commits of carefully crafted skills covering serious engineering ground: TDD, Nullables (James Shore's pattern for testing without mocks), approval tests, refactoring (using Llewellyn Falco's approach), hexagonal architecture, event modeling, collaborative design, and more.

These aren't toy prompts. The Nullables skill alone includes reference material for infrastructure wrappers, embedded stubs, output tracking, and three different architectural patterns. The approval-tests skill covers Java, Python, and Node.js with scrubbers, reporters, and inline patterns. This is deep, carefully structured knowledge.

Lada also co-created augmented-coding-patterns - a catalog of 43 patterns, 14 obstacles, and 9 anti-patterns for working effectively with AI coding tools. It's a collaboration between Lada Kesseler, Ivett Ordog, and Nitsan Avni. If you're doing augmented coding and haven't seen it, stop reading this and go look.

What I found wasn't just a collection of skills. It was an approach to sharing engineering knowledge with AI agents that I hadn't seen anywhere else.

The Fork as Extension

The natural next step wasn't to start from scratch - it was to fork and extend. Lada's skills already covered testing fundamentals, design patterns, and AI-specific workflows. What I noticed missing were the practices I kept explaining repeatedly: how to manage complexity, how to deliver incrementally, how to make sure tests actually catch bugs.

So I added 11 skills. Not because 16 wasn't enough, but because my particular set of problems needed particular solutions.

You can find my extended fork at github.com/eferro/skill-factory with all 27 skills ready to use.

Testing rigor

test-desiderata - Kent Beck's 12 properties that make tests valuable. Not "does this test pass?" but "is this test isolated? composable? predictive? inspiring?" I was tired of AI generating tests that had coverage but no diagnostic power. This skill makes the agent evaluate tests against each property and suggest concrete improvements.

mutation-testing - The question code coverage can't answer: "Would my tests catch this bug?" Coverage tells you what your tests execute. Mutation testing tells you what they'd detect. I'd already written a blog post about this - now it's a reusable skill. The examples are in Python and JavaScript, but I'm also using it successfully with Go.

Delivering incrementally and managing complexity

This is where the skills chain together, and where things get interesting.

story-splitting - Detects linguistic red flags in requirements ("and", "or", "manage", "handle", "including") and applies splitting heuristics. It's the first pass: is this story actually three stories wearing a trenchcoat?

hamburger-method - When a story doesn't have obvious split points but still feels too big, this skill applies Gojko Adzic's Hamburger Method: slice the feature into layers, generate 4-5 implementation options per layer, then compose the thinnest possible vertical slices.

small-safe-steps - The implementation planner. Takes any piece of work and breaks it into 1-3 hour increments using the expand-contract pattern for migrations, schema changes, API changes. Core belief: risk grows faster than the size of the change.

complexity-review - My inner skeptic, encoded. Reviews technical proposals against 30 dimensions of complexity across 6 categories (data volume, interaction frequency, consistency requirements, resilience, team topology, operational burden). Pushes for the simplest viable approach. Use it when someone says "Kafka" and you want to ask "why not a queue?"

code-simplifier - Reduces complexity in existing code without changing behavior. The cleanup crew after a feature is done.

These five skills work as a pipeline: story-splitting -> hamburger-method -> small-safe-steps for delivery planning, with complexity-review as a gate before implementation and code-simplifier as a sweep after.

Practical tools and team workflows

thinkies - Kent Beck's creative thinking habits, turned into a skill. When you're stuck, it applies patterns like "What would I do if I had infinite resources?", "What's the opposite of my current approach?", "What would make this problem trivial?" It's less about code and more about unsticking your thinking.

traductor-bilingue - Technical translation between English and Spanish that keeps terms like "deploy", "pull request", "pipeline", and "staging" in English (because that's how Spanish-speaking dev teams actually talk). Small thing, but it saves constant corrections.

dockerfile-review - Reviews Dockerfiles for build performance, image size, and security issues.

modern-cli-design - Principles for building scalable CLIs: object-command architecture (noun-verb), LLM-optimized help text, JSON output, concurrency patterns.

A Skill in Action

To make this concrete, here's what the delivery planning pipeline looks like in practice.

Say you have a story: "As a user, I want to manage my notification preferences including email, SMS, and push notifications with scheduling and quiet hours."

Step 1 - You invoke /story-splitting. The agent immediately flags "manage", "including", and the conjunction "and" joining three notification types plus scheduling. It suggests splitting into at least 4 stories: one per notification channel plus quiet hours as a separate slice.

Step 2 - You take the first slice ("email notification preferences") and invoke /hamburger-method. It breaks the feature into layers (UI, API, business logic, persistence) and generates options for each. For the UI layer: (a) full settings page, (b) single toggle, (c) link to email with confirmation, (d) inline in profile. It composes the thinnest vertical slice: a single toggle with an API endpoint and a database flag.

Step 3 - You invoke /small-safe-steps on that thin slice. It produces a sequence of 1-3 hour steps: add the database column with a migration, add the API endpoint with tests, add the UI toggle, wire it together. Each step deployable independently.

No single skill does everything. They compose. That's the point.

How to Get Started

If you want to try these:

  1. Fork the repo: github.com/eferro/skill-factory (my extended fork with 11 additional skills for complexity management and incremental delivery) or the original by Lada Kesseler
  2. Install skills: The repo includes a skills CLI tool. Run ./skills toggle to browse and select which skills to install into your Claude Code setup.
  3. Use them: Type /skill-name in Claude Code. /mutation-testing to check your tests. /complexity-review to challenge a design. /small-safe-steps to plan your next implementation.
  4. Make your own: The repo includes documentation and tooling for creating new skills. Fork it, add what you need, share it back.

Standing on Shoulders

The total is 329 commits, 27 skills across 6 categories. But the number that matters most is that Lada built 315 of those commits. I added 14. The original structure, the skill manager, the testing and design skills that form the foundation - that's all her work. What I did was extend it with the practices I personally find myself repeating.

This is how open source has always worked: someone builds something good, others extend it, and the whole thing becomes more useful than any individual could make it. With AI skills, the effect compounds differently - every skill that gets shared becomes available to every person using it, making good practices almost free.

Lada's augmented-coding-patterns site (with Ivett Ordog and Nitsan Avni) takes this even further - it's not just tooling but a shared vocabulary for how we work with AI. Skills, patterns, obstacles, anti-patterns: a growing body of community knowledge.

What knowledge do you find yourself repeating to your AI agents? What practices would you encode as skills?

The barrier to sharing isn't technical anymore. It's deciding to do it.

References

Sunday, February 22, 2026

Podcast: AI as an Amplifier. Why Engineering Practices Matter More Than Ever

Vasco Duarte invited me to be part of the Scrum Master Toolbox Podcast's AI Assisted Coding series, and I couldn't pass up the chance to talk about something I've been living and thinking about intensely for the past several months.

The conversation builds directly on the experiment I documented in Fast Feedback, Fast Features: My AI Development Experiment: 424 commits over 11 weeks, where for every unit of effort I put into new features, I invested four times more in refactoring, cleanup, tests, and simplification. And yet, globally, I think I more or less doubled my pace of work.

In the episode, we dig into several things I've been exploring:

Vibe coding vs production AI development. Both are valid—but they require different mindsets. Vibe coding is flow-driven, exploration-focused, great for prototypes and discovery. Production AI coding demands architectural thinking, security analysis, and sustainability practices. Even vibe coding benefits from engineering discipline as soon as experiments grow beyond a weekend hack.

The positive spiral of code removal. One of the most powerful patterns I've discovered is using AI to accelerate deletion. Connect product analytics to identify unused features, use AI to remove them efficiently, and you trigger a cycle: simpler code makes architecture changes cheaper, cheaper architecture changes enable faster feature delivery, which creates more opportunities for simplification. Humans historically avoided this because removal was as expensive as creation. That excuse is gone.

Preparing the system before introducing change. Rather than asking "implement this feature," I've been asking "how should I change my system to make this feature trivial to introduce?" AI makes that preparation cheap enough to do routinely. The result: systems that evolve cleanly rather than accumulating debt with each addition.

AI as an amplifier—the double-edged sword. This is the central idea. AI doesn't replace engineering judgment; it magnifies its presence or absence. Strong teams will see accelerated improvement. Teams without good practices will generate technical debt faster than ever. The path to excellence in modern software development lies in the seamless integration of a high-performance engineering culture, lean-agile product strategies, and an evolutionary approach to architecture. AI makes that path wider—but you still have to choose to walk it.

🎙️ Listen to the episode: AI as an Amplifier—Why Engineering Practices Matter More Than Ever

Sunday, January 18, 2026

Fast Feedback, Fast Features: My AI Development Experiment

What happens when you use AI not to ship faster, but to build better? I tracked 424 commits over 11 weeks to find out.

The Experiment

Context first: I'm an engineering manager, not a full-time developer. These 424 commits happened in the time I could carve out between meetings, planning, and leadership work. The applications are production internal systems (monitoring dashboards, inventory management, CLI tools, chatbot backends) used by real teams, but not high-criticality systems where a bug directly impacts external customers or revenue.

Important nuance: I also act as Product Manager for the Platform team that owns these applications. This means I'm defining the problems and implementing the solutions. There's no friction or information loss between problem definition and implementation that typically exists in stream-aligned teams where PM and developers are separate roles. This setup favors faster iteration and tighter feedback loops (though it's worth noting this isn't representative of how most teams operate).

From November 2025 to January 2026, I wrote 424 commits across 6 repositories, spanning 44 active days (with Christmas holidays in the middle). Every single line of code was written with AI assistance: Cursor, Claude Code, the works. These weren't toy projects or weekend experiments. These were real systems evolving under active use.

The repositories varied wildly in maturity: from a 13-day-old Go service to a 5.6-year-old Python system with over 12,000 commits in its history. Half were greenfield projects under 6 months old; half were mature codebases years into their lifecycle. Combined, they represent ~107,000 lines of production code. These are small-to-medium projects. That's how our platform team works: we prefer composable systems over monoliths.

The period was intense: 9.6 commits per day average, almost double my historical pace. But AI didn't just make me faster at writing code. It fundamentally changed what kind of code I wrote.

I tracked everything. Every commit was categorized using a combination of commit message analysis, file change patterns, and manual review. Claude Sonnet 4.5 helped automate the initial categorization, which I then validated. And when I analyzed the data, I found something I wasn't expecting.

The Balance

For every hour I spent on new features, I spent over four hours on tests, documentation, refactoring, security improvements, and cleanup.

22.7% functionality. 98.3% sustainability.

Yes, that adds up to more than 100%. That's not an error: it's the reality of how development actually works. When I develop a feature, the same commit often includes tests, documentation updates, and code cleanup. The numbers reflect that commits are multidimensional, not mutually exclusive categories.

The ratio: 0.23:1 (Functionality:Sustainability)

This wasn't accidental. This was a deliberate experiment in sustainable velocity. And AI made it possible.

Breaking Down the 98.3%

8-Dimensional Commit Categorization

When I say "sustainability," I mean 8 specific, measurable categories:

  • Tests: 30.7%: The largest single category
  • Documentation: 19.0%: READMEs, API docs, inline comments
  • Cleanup: 13.8%: Removing dead code, unused features, simplification
  • Infrastructure: 12.0%: CI/CD, scripts, tooling improvements
  • Refactoring: 11.5%: Structural improvements, better abstractions
  • Configuration: 8.1%: Environment variables, settings, build configs
  • Security: 3.2%: Vulnerability fixes, security audits, input validation

These aren't "nice-to-haves." They're the foundation that makes the 22.7% of new functionality actually sustainable.

What Changed (And What Didn't)

Here's what I learned: tests and feedback loops were always important. Good engineers always knew this. The barrier wasn't understanding, it was economics and time.

What was true before AI:

  • Fast feedback loops were critical for velocity
  • Comprehensive tests enabled confident iteration
  • Documentation reduced knowledge silos
  • Some teams invested in this, many didn't grasp that sustainable software requires sustained investment in technical practices

What changed with AI:

  • The barrier to entry dropped dramatically
  • Building that feedback infrastructure became fast
  • Maintaining quality became economically viable for small teams
  • The excuse of "not enough time" largely disappeared

What didn't change:

  • Discipline is still our responsibility
  • The choice to balance features vs sustainability is still ours
  • AI doesn't automatically make us write tests: we have to choose to
  • The default behavior is still "ship more features faster" until technical debt forces a halt

The insight: AI removed the last excuse. Now it's about discipline, not capability.

For me, as a manager who codes in limited time, this changed everything. I can afford to build the feedback infrastructure that lets me iterate fast. The 0.23 ratio isn't a constraint, it's what enables the velocity I'm experiencing.

Negative Code: Simplification as a Feature

Here's another data point: 55,407 lines deleted out of 135,485 total lines changed.

That's 40.9% deletions. For every 3 lines I wrote, I deleted 2.

Some deletions were refactoring: replacing 100 lines of messy code with 20 clean ones. But many were something else: removing features that didn't provide enough value.

One repository, chatcommands, has net negative growth: the codebase got smaller despite active development. It's not alone. ctool also shrank during this period.

This connects to two concepts I've written about before:

Basal Cost of Software: Every line of code has an inherent maintenance cost. It needs to be understood, tested, debugged, and updated. The best way to reduce basal cost is to have less code.

Radical Detachment: Software is a liability to minimize, not an asset to maximize. The goal isn't more code, it's the right amount of code to solve the problem.

Before AI, deleting features was expensive:

  • Understanding old code took hours (documentation outdated)
  • Tracing dependencies was manual and error-prone
  • Verifying nothing broke required incomplete test suites
  • Updating docs and configs was tedious

Features became immortal. Once added, they never left, even at zero usage.

With AI, deletion becomes viable:

  • Trace dependencies in minutes, not hours
  • Comprehensive tests catch breaking changes immediately
  • Documentation updates happen alongside code changes
  • The entire deletion commit includes proper cleanup

The 13.8% cleanup category isn't just removing dead imports. It's removing dead features. Entire endpoints. Unused UI components. Configuration options nobody sets.

I call this Negative Velocity: making the codebase smaller, simpler, and faster, not just adding more.

This aligns with lean thinking about waste elimination. Every unused feature is waste: it increases build times, slows down tests, complicates mental models, and raises the basal cost of the system. Each line of code creates drag on everything else. By deleting features, we're not just cleaning up: we're reducing the ongoing cost of ownership. Fewer features means faster comprehension, simpler debugging, easier onboarding, and less surface area for bugs.

I'd deleted code before, but AI reduced the friction enough to make it routine instead of occasional. Deletion went from expensive to viable. We can finally afford to minimize the liability at the pace it deserves.

The best code is no code. Now we can actually afford to delete it.

The Metrics at a Glance

The key numbers:

  • 424 total commits across 44 active days (November 2025 - January 2026)
  • 9.6 commits per day average: nearly double typical velocity
  • Ratio Func:Sust = 0.23:1 (1 hour features, >4 hours sustainability)
  • Average Functionality: 22.7% per commit
  • Average Sustainability: 98.3% per commit (multidimensional, not mutually exclusive)
  • 135,485 total lines changed (80,078 insertions, 55,407 deletions)
  • 40.9% deletion ratio: for every 3 lines written, 2 deleted

These aren't aspirational numbers. These are the actual patterns from an intensive 11-week period of AI-assisted development in production repositories.

Different Projects, Different Profiles

Not every project should have the same ratio. Context matters.

  • inventory: 0.42:1 ratio: More feature-focused, greenfield project in active development
  • plt-mon: 0.25:1 ratio: Test-heavy, mature monitoring system needing reliability
  • ctool-cli: 0.16:1 ratio: CLI tool with emphasis on tests and robustness
  • chatcommands: 0.15:1 ratio: Maintenance-focused, net negative code growth (-1,809 lines)
  • ctool: 0.09:1 ratio: Minimal feature work, heavy focus on infrastructure and cleanup
  • cagent: 0.13:1 ratio: New project with emphasis on quality from day one

The chatcommands profile is particularly interesting: 31.5% of effort went to cleanup, and the repository actually shrank by 1,809 lines over this period. This isn't a dying project, it's a maturing one. Features were removed intentionally because they weren't providing value. The codebase got simpler, faster, and more maintainable.

The plt-mon repository maintains a 1.15:1 test-to-feature ratio: tests slightly outpace features. This is a production monitoring system where reliability matters, and the balance reflects steady feature growth with corresponding test coverage.

The ratio should reflect the project's phase and needs. AI makes all of these profiles viable without sacrificing quality or velocity.

What I Learned

After 11 weeks and 424 commits, here's what I've discovered:

Real velocity comes from fast feedback loops. Not from writing code faster, but from being able to iterate confidently and quickly. The 98.3% investment in sustainability isn't overhead, it's what enables speed.

AI changed what became economically viable. Before, building comprehensive test coverage as a manager with limited coding time would have been impossible. Now I can afford to build both the features and the safety net at sustainable pace. The barrier dropped; the discipline remains my responsibility.

Speed ≠ Velocity. Speed is how fast you move. Velocity is speed in the right direction. A team shipping 10 features per week with zero tests is moving fast toward a rewrite. A team shipping 3 features per week with comprehensive test coverage is moving fast toward sustainability.

What you optimize for gets amplified. My hypothesis: AI amplifies our choices. If you optimize for feature velocity, you'll accumulate technical debt faster. If you optimize for sustainable velocity (balancing features with quality infrastructure) you'll build healthier systems faster. I've seen this play out in my own work, though I don't claim this is universal.

Deletion is a feature. With lower barriers to understanding and changing code, we can finally afford to make codebases smaller. Net negative growth isn't stagnation, it's maturity.

The right ratio depends on context. My 0.23:1 ratio works for internal systems with moderate criticality, developed by a manager in limited time. Your context is different. The point isn't to copy my numbers, it's to be intentional about the balance.

This is still an experiment. I don't know if this approach scales to all teams or all types of systems. What I do know: for my context, over these 11 weeks, this balance produced the fastest sustainable velocity I've experienced in my career.

The shift wasn't learning new practices—I'd practiced TDD and built for sustainability for years. But as a manager coding in limited time, I always had to compromise. I wrote tests, but not as many as I wanted. I refactored, but not as thoroughly. I documented, but not as completely. AI didn't change what I valued—it changed what I could afford to do. The discipline I'd always practiced could finally match the standard I'd always wanted.

Your Turn

I don't have universal answers. But I do have a suggestion:

Measure your balance. Be intentional about it.

Track your next month of commits. Categorize them honestly. Calculate your Functionality:Sustainability ratio.

The number itself matters less than the awareness. Are you making conscious choices about where AI velocity goes? Are you building the feedback infrastructure that enables sustainable speed? Are you just shipping faster, or are you building better systems faster?

For me, the answer has been clear: investing heavily in tests, documentation, and simplification has made me faster, not slower. The 98.3% isn't overhead, it's the engine.

Your mileage may vary. Your context is different. But the question is worth asking:

What kind of engineering does AI make viable for you that wasn't before?

Related Posts

Saturday, January 03, 2026

Stop Building Software. Start Cultivating It

There's a pervasive anxiety in the software industry. It's the feeling of never being good enough, of working late with the constant worry that what you just shipped will explode in production. It's the pressure to go faster, even when you know you're sacrificing quality. It's the frustration of feeling unprofessional, of never quite reaching a state of sustainable, high-impact work. Many of us have been there, living with this constant, low-grade stress.

But there is a better way. There is a path to professional tranquility that also delivers greater business impact. It doesn't come from a new framework or the latest methodology, but from a fundamental shift in how we think about our work. After nearly three decades in this industry, I've come to rely on five counter-intuitive but powerful mindset shifts.

1. Stop "Building" Software. Start Cultivating It.

One of the most damaging ideas I've encountered in our industry is the metaphor of software development as construction. We talk about "building" applications like we build houses. This metaphor is flawed, and it is the root cause of immense dysfunction.

It's harmful because it implies a static, finished product. A house, once built, is largely done. This mindset separates the "building" phase from a supposedly smaller "maintenance" phase. It leads to the absurd but common belief that software must be thrown away and completely rebuilt every few years.

We need a new metaphor: software as something that evolves, like a garden or a living system. It must be cultivated and guided. The single greatest advantage of software is its malleability, its ability to change. The construction metaphor negates this core strength. We are not masons laying permanent bricks; we are gardeners tending to a system that must constantly adapt to its environment.

If we saw the nature of software as something more evolutionary, as something that is alive, as a system that we are modifying all the time... that metaphor seems to me to be much more in line with the real nature of software development.

2. Your Most Valuable Contribution Might Be the Code You Didn't Write

Our industry often rewards the wrong things. Résumés are filled with lists of technologies used and massive projects "built." Productivity is mistakenly measured by the quantity of code written. More features, more complexity, and more lines of code are seen as signs of progress.

The truth is that true impact often comes from simplification. The most valuable work an engineer can do is often invisible. It's achieving an 80/20 solution that delivers most of the value with a fraction of the effort. It's proposing a simpler path that avoids a six-month project. It's having the courage to delete a feature that adds more cost than value.

Every feature, every line of code, has a "basal cost", an ongoing tax on the system. It adds to the cognitive load for new developers, increases maintenance, and creates friction that slows down all future innovation. The best engineers are masters of preventing unnecessary complexity. Their biggest wins, a disastrous project averted, a legacy system retired, will never appear on a performance review, but they are immensely valuable.

3. Agility Is a Strict Discipline, Not a Free-for-All

The word "Agile" has been misinterpreted to the point of becoming meaningless in many organizations. Teams use "delivering value" as an excuse for shipping shoddy work at high speed. For others, "being agile" has come to mean "anything goes", no documentation, no planning, no rigor.

This interpretation is a complete departure from the concept's original intent. True agility is a difficult and demanding discipline. It is not a shortcut or an excuse for chaos. It is a rigorous commitment to practices that enable sustainable speed and responsiveness.

In my head, agility is equivalent to a discipline, and a difficult one at that... a discipline of "Hey, I'm going to write the test first, then I'll do the implementation, then I'll refactor, I'll even eliminate functionalities that aren't useful." It's actually a tough discipline.

This discipline is embodied in concrete, systematic practices. On the technical side, it means Test-Driven Development (TDD) as the foundation for design and quality, Continuous Integration (CI) and Continuous Delivery (CD) to enable rapid, safe deployment, and continuous refactoring to keep the codebase simple and maintainable. On the product side, it means applying Lean Product Development principles to validate ideas before committing to full implementation, running experiments to test hypotheses, and ruthlessly prioritizing based on real user feedback.

But as the above highlights, it's not just about additive practices. It's also a discipline of subtraction, of proactively controlling technical debt before it becomes a crisis, of simplifying systems even when they're "working," and of removing features that don't add value. The goal is to maintain agility, both from a technical perspective (the codebase remains easy to change) and from a product perspective (the team can pivot based on what they learn).

These are not optional extras; they are the very foundation of agility. They require an uncompromising commitment to quality, because it is only through high quality that we can earn the ability to move fast, adapt, and innovate sustainably over the long term.

4. Individual Performance Metrics Are a Trap

There is a growing and dangerous trend of trying to measure individual developer productivity with simplistic metrics like the number of commits, pull requests, or story points completed. This approach is devastating. In 2023, McKinsey published an article proposing a framework to measure individual developer productivity using metrics like "contribution analysis" and "inner/outer loop time spent." The response from the software engineering community was swift and unequivocal. Kent Beck, creator of Extreme Programming, called it "absurdly naive," while Kent Beck and Gergely Orosz wrote a detailed rebuttal explaining why such frameworks do far more harm than good.

The problem isn't just with McKinsey's specific approach. It's with the entire premise of measuring individuals in a collaborative discipline. This is a direct application of Taylorism, the management philosophy developed by Frederick Winslow Taylor in the early 1900s for factory work. Taylorism treats people as interchangeable resources to be optimized locally, decomposing work into specialized tasks and measuring each person's individual output. It took manufacturing 50 years to move past this thinking. Yet in software development, a creative, knowledge-based discipline where these ideas are least effective, we continue to apply them universally.

When you incentivize local optimization through individual metrics, the negative results are entirely predictable. As W. Edwards Deming taught, over 90% of an organization's performance is a result of the system, not the individuals within it. But individual metrics create perverse incentives that optimize for the wrong things. We reward behaviors that are easy to measure but destructive to the whole: a high number of commits (encouraging smaller, more frequent check-ins regardless of value), celebrating people for "being 100% busy" (even if they're blocking others), or lionizing "heroes" who constantly put out fires (often of their own making). These incentives inevitably lead to chronic bottlenecks, constant rework, and a toxic hero culture where knowledge is hoarded and collaboration is discouraged.

It is devastating because it promotes individualism in a profession that is fundamentally about collaborative problem-solving. It discourages essential practices like pair programming because it makes it harder to assign "credit." It optimizes for busy-ness (output) instead of actual business results (impact). As Beck and Orosz point out, measuring effort and output is easy, but it changes developer behavior in ways that work against the outcomes that actually matter.

Software development is a team sport centered on learning. The true measure of performance is the impact and health of the team. The most valuable person on a team would often score terribly on these individual metrics. They might be the "glue" that holds everyone together, the mentor who elevates the skills of others, the person who prevents bad code from ever being written, or the engineer who just deleted 10,000 lines of obsolete code, making the system simpler for everyone. Their contribution is profound, yet these metrics would render them invisible or, worse, label them a poor performer.

5. Don't Ask for Permission to Be a Professional

Too many engineers wait for permission to do their job properly. They see quality practices like writing automated tests as something they need to negotiate or justify to management. This is a fundamental mistake.

You don't ask your manager for permission to use a for loop or a recursive function; you use the right tool for the job because you are a professional. Writing tests is the same. It is a non-negotiable, foundational part of professional software development, not an optional feature you need to bargain for.

This responsibility extends beyond just testing. Your job is not merely to execute instructions. It is to solve problems. That means taking the initiative to understand the "why" behind a feature, respectfully challenging requirements that don't make sense, and proposing simpler, better solutions. This isn't overstepping; it is the very core of engineering. By taking this professional responsibility, you build trust, earn autonomy, and position yourself to make a real, lasting impact.

Conclusion: A More Sustainable Future

The key to a more sustainable, impactful, and professionally satisfying career is to abandon the "construction" mindset. When we stop thinking of ourselves as builders of static artifacts and start seeing ourselves as cultivators of living, evolving systems, everything changes.

This single shift in perspective is the thread that connects all five of these principles. It leads us to value subtraction over addition, to embrace discipline over chaos, to measure team impact over individual output, and to take ownership of our professional standards. It is the path away from anxiety and toward durable, meaningful work.

The arrival of AI does not invalidate these principles; it reinforces them. If anything is going to change, it's that these mindset shifts will become more critical, not less. When we can generate code faster than ever, distinguishing between building and cultivating becomes more important than ever. When AI can produce features at unprecedented speed, knowing what NOT to build becomes the differentiating skill. The tools evolve, the disciplines adapt, but the goal remains constant: sustainable impact over time, real value delivered, and complexity kept under control. Now we have new tools and evolving disciplines, but they're still pursuing the same fundamental objective.

What is one "construction" habit you can challenge in your team this week to start cultivating your software instead?

References

  • Stop Building Waste: 6 Principles for High-Impact Engineering Teams Eduardo Ferro (2025)
    eferro.net/stop-building-waste
    A complementary piece exploring how to maximize outcomes while minimizing software complexity.
  • Perverse Incentives, Predictable Results: When Your System Sabotages Your Teams Eduardo Ferro (2025)
    eferro.net/perverse-incentives
    Explores how Taylorist thinking creates perverse incentives in software development and offers systemic solutions.
  • Measuring developer productivity? A response to McKinsey Kent Beck and Gergely Orosz (2023)
    Kent Beck's version | Gergely Orosz's version
    A detailed rebuttal to McKinsey's framework, explaining why measuring effort and output damages engineering culture.
  • Yes, you can measure software developer productivity McKinsey (2023)
    mckinsey.com
    The original McKinsey article proposing individual developer productivity metrics.
  • Basal Cost of Software Eduardo Ferro (2021)
    eferro.net/basal-cost-of-software
    Introduces the concept of ongoing cognitive and maintenance costs each feature adds to a system.
  • Extreme Programming Explained: Embrace Change Kent Beck (1999, 2nd Ed. 2004), Addison-Wesley
  • Software has diseconomies of scale – not economies of scale Allan Kelly (2015, revised 2024)
    allankelly.net/archives/472
  • The Most Important Thing Marty Cagan (2020), Silicon Valley Product Group
    svpg.com/the-most-important-thing

Tuesday, December 30, 2025

New Site: eferro-talks

I've created a dedicated site to collect all my talks and presentations: eferro-talks

It's a cleaner way to find conference material, with filters by year, language, and core talks.

This joins the rest of my projects at eferro.github.io, where you can also find web apps, custom GPTs, curated resources, and development tools.

The goal is to consolidate scattered material into a single access point while keeping each project with its own identity.