Boilerplate code: qué es el código repetitivo y cómo se reduce

En programación se llama boilerplate code, o simplemente boilerplate, al código que hay que escribir una y otra vez, casi sin cambios, para que un programa funcione: no aporta nada propio del problema que se resuelve, pero sin él el programa no compila o no arranca. En español se suele decir código repetitivo o código de plantilla.

Placa metálica de 1913 de la Reid Newfoundland Company, constructora de calderas
Una placa de fabricante de calderas de 1913. El nombre del boilerplate viene de este tipo de piezas de metal.

El nombre viene de la imprenta. A finales del siglo XIX, en Estados Unidos, las agencias enviaban a los periódicos pequeños textos ya compuestos en planchas de metal, listos para imprimir sin cambiar una coma: anuncios, columnas fijas, avisos legales. Aquellas planchas recordaban a las de acero con que se fabricaban las calderas, las boiler plates, y el nombre se quedó para cualquier texto que se reutiliza tal cual. Hoy se usa también en derecho, para las cláusulas que se copian de un contrato a otro, y en programación.

Ejemplos de boilerplate

Todos los lenguajes tienen su ración. Algunos de los ejemplos más conocidos:

  • El esqueleto de una página HTML: <!doctype html>, <html>, <head>, el charset y el viewport se repiten en cada página antes de escribir una sola línea de contenido.
  • El if __name__ == "__main__": de Python, que separa lo que se ejecuta al lanzar un archivo de lo que se ejecuta al importarlo.
  • El if err != nil { return err } de Go, que aparece después de casi cada llamada que puede fallar.
  • Las clases de datos en Java: constructor, métodos para leer cada campo, equals, hashCode y toString. Es el ejemplo clásico, y lo vemos ahora.

Esta clase solo guarda un nombre y una edad, y ocupa 29 líneas. Casi todas son boilerplate: si se añade un campo, hay que acordarse de tocar el constructor, el método de lectura, equals, hashCode y toString. Si se olvida uno, el error no salta al compilar.

import java.util.Objects;

public final class PersonaClasica {
    private final String nombre;
    private final int edad;

    public PersonaClasica(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }

    public String getNombre() { return nombre; }
    public int getEdad() { return edad; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof PersonaClasica p)) return false;
        return edad == p.edad && Objects.equals(nombre, p.nombre);
    }

    @Override
    public int hashCode() { return Objects.hash(nombre, edad); }

    @Override
    public String toString() {
        return "PersonaClasica[nombre=" + nombre + ", edad=" + edad + "]";
    }
}

Desde Java 16, un record hace lo mismo en una línea. El compilador genera el constructor, los métodos para leer los campos, equals, hashCode y toString:

public record Persona(String nombre, int edad) { }
public class Prueba {
    public static void main(String[] args) {
        var a = new PersonaClasica("Ana", 30);
        var b = new PersonaClasica("Ana", 30);
        System.out.println(a + " | iguales: " + a.equals(b));

        var c = new Persona("Ana", 30);
        var d = new Persona("Ana", 30);
        System.out.println(c + " | iguales: " + c.equals(d) + " | nombre: " + c.nombre());
    }
}
java PruebaPersonaClasica[nombre=Ana, edad=30] | iguales: true
Persona[nombre=Ana, edad=30] | iguales: true | nombre: Ana

Las dos versiones se comportan igual: las dos personas con el mismo nombre y edad son iguales, y se imprimen con todos sus campos. La diferencia es que en la segunda no hay nada que mantener a mano.

Cómo se reduce el boilerplate

  • El propio lenguaje. Es la mejor solución, porque no añade dependencias: los record de Java, las data class de Kotlin, las dataclass de Python o los #[derive(Debug, Clone, PartialEq)] de Rust generan el código repetitivo por ti.
  • Bibliotecas que generan código. En Java, Lombok añade getters, setters y constructores con anotaciones como @Data. Funciona, pero es una dependencia más, que además se mete en el proceso de compilación.
  • Frameworks. Spring Boot, Django o Ruby on Rails existen en buena parte para ahorrar boilerplate: configuran solos lo habitual y solo hay que escribir lo que se sale de lo normal.
  • Generadores y plantillas de proyecto. Herramientas como npm create, cargo new o Spring Initializr crean la estructura inicial completa con una orden.
  • El editor y la IA. Los IDE generan constructores y métodos con un atajo, y los asistentes de IA escriben el boilerplate en segundos. Es justo el tipo de código que mejor generan, porque lo han visto millones de veces.
Que lo escriba la IA no lo hace gratis. El boilerplate generado hay que leerlo, revisarlo y mantenerlo igual que el escrito a mano. Si un campo nuevo no se añade a equals, el error es el mismo lo haya escrito quien lo haya escrito. Por eso, cuando el lenguaje ofrece una forma de no tener que escribirlo, como un record, sigue siendo mejor opción que generarlo. Lo explicamos en qué lenguaje elegir cuando la IA escribe el código.

¿Es siempre malo?

No. Parte del boilerplate existe por buenas razones: el if err != nil de Go obliga a decidir qué hacer con cada error, en lugar de dejar que una excepción suba sin control, y declarar los tipos de forma explícita hace que el código se lea mejor meses después. El problema aparece cuando la repetición no aporta información y solo multiplica los sitios donde equivocarse. La regla práctica: si al leer un bloque no aprendes nada sobre lo que hace el programa, es boilerplate y conviene que lo genere el lenguaje, un framework o una herramienta.

Los ejemplos de Java se compilaron y ejecutaron con Java 25 (Eclipse Temurin 25.0.4). Más información: Boilerplate code en Wikipedia y JEP 395: Records.

Los gurús y el trabajo en equipo

Sin duda, siempre existen personas brillantes que se distinguen por su buen sentido común, curiosidad y capacidad para resolver problemas difíciles. Pero siempre he sospechado que la imagen del gurú está sobrevalorada.

Algunas malas experiencias me dicen que esto podría ser así.  En cierta ocasión, durante el desarrollo de un proyecto mas o menos grande y en una demostración de capacidades, el líder del equipo, que se sabía muy bueno en el desarrollo de software (el gurú), comenzó a utilizar una serie de tecnologías y frameworks de moda para impresionar al cliente y al administrador de proyecto.  Como resultado, los que tenían menos experiencia comenzaron a sufrir con la curva de aprendizaje y se enfocaron mas a conocer las nuevas tecnologías que al modelo de negocio. El desarrollo se terminó con una aplicación robusta tecnológicamente, pero poco amigable para el cliente y por supuesto en mas tiempo del que se esperaba. Un pequeño desastre.

En otras ocasiones, me he topado con el típico personaje que es capaz de resolver problemas difíciles, pero que cuando tienes que dar mantenimiento a su código o simplemente necesitas usarlo, este te parece tan desordenado que te dan ganas de hacerlo de nuevo.

Otro de los riesgos de tener a una persona que tiene todo el dominio sobre cierta tecnología, herramienta o el conocimiento mas crítico de un proyecto, es que puede simplemente irse, con el todo su conocimiento.

Me agradan mas los equipos de trabajo donde los problemas difíciles o algunas decisiones tecnológicas se resuelven entre varios.

Los gurús se equivocan como cualquier otro.

Además, cuando te autoproclamas gurú, puedes quedarte solo a la hora de resolver problemas difíciles.  Creo que no hay necesidad de que esto sea así, porque el criterio para resolver un problema crítico se reduce al de una sola persona y no creo que esto sea muy conveniente.

Cuando alguien te hace una pregunta complicada sobre algún problema o error, es probable que ella misma tenga mas capacidad para responderla, ya que conoce mejor el contexto del problema.  Por lo que mas que tratar de dar una solución es mejor dar un punto de vista o pistas sobre como resolver el problema.

El protagonismo es algo que nos puede seducir a todos, pero yo me lo pensaría mucho antes de adoptar una postura de este tipo. Sobre todo cuando de lo que se trata es hacer mas agradable y profesional tu trabajo.  Desde luego no estoy diciendo que todos los gurús son malos, de hecho también he conocido a algunos muy buenos. Pero son los menos.

Un hábito que recomiendo a todos es que cuando encuentras la solución a un problema difícil, la comentes a tus demás compañeros. Esto permite tener una base de conocimiento colectiva y evita tener que investigar demasiado sobre un problema que ya se ha sido resuelto con anterioridad.

Tómate con calma eso de ser gurú, puedes serlo sin hacer alarde.  🙂