Cultura y comportamiento laboral

Cómo dar y recibir feedback técnico constructivo en revisiones de código

Ingeniero de Software / Revisor Técnico de Código (Peer Reviewer)

Google Code Review Guidelines / Conventional Comments Specification

  • Lectura y comprensión de código fuente ajeno
  • Análisis de pruebas unitarias y de integración
  • Manejo de herramientas de control de versiones y revisión (Git, Gerrit, Pull Requests)
  • Evaluación de diseño y arquitectura de software
  • Comunicación asertiva y formulación de comentarios no confrontativos
  • Separación del ego profesional y apertura a la crítica técnica
  • Mentoría técnica y pedagogía en el desarrollo de software
  • Capacidad de negociación y toma de decisiones orientada a hechos
  • Plataformas de Code Review (GitHub, GitLab, Gerrit, Code Collaborator)
  • Herramientas de análisis estático y linters integrados
  • Plantillas de formato basadas en Conventional Comments
  • IEEE Certified Software Development Professional (CSDP)
  • Certificaciones en prácticas DevOps y CI/CD (e.g., GitHub Actions, GitLab CI)

La revisión de código —conocida en inglés como code review— es hoy uno de los rituales más extendidos y a la vez más mal gestionados de la ingeniería de software. Se practica a diario en equipos de todo el mundo hispanohablante, desde startups en Ciudad de México y Bogotá hasta bancos en Madrid y equipos remotos que trabajan para empresas de Silicon Valley, pero rara vez se enseña de forma explícita cómo hacerlo bien. El resultado son fricciones evitables: comentarios que se leen como ataques personales, autores que se ponen a la defensiva y revisores que confunden preferencia de estilo con corrección técnica. Este artículo documenta, con base en investigación académica y en las guías de ingeniería de empresas como Google, cómo convertir la revisión de código en una herramienta de mejora continua y no en un campo de batalla de egos.

I. Introducción y propósito de la revisión moderna de código

A. De las inspecciones formales a los flujos ligeros y asíncronos

La revisión de código no nació con GitHub. Sus raíces se remontan a las inspecciones formales de código de los años setenta y ochenta, procesos pesados, presenciales y altamente estructurados. Lo que hoy se conoce como Modern Code Review (MCR) es una evolución radicalmente distinta: informal, basada en herramientas, asíncrona y centrada en cambios de código discretos en lugar de en el sistema completo [4]. Este giro se consolidó en la última década como una pieza central del ciclo de vida DevOps, adoptada tanto en proyectos de código abierto como en ecosistemas industriales de gran escala [1].

El caso de Google, documentado en un estudio con doce entrevistas, una encuesta a 44 desarrolladores y el análisis de nueve millones de cambios revisados, ilustra bien esta transición: la compañía introdujo la revisión de código de forma temprana y la fue refinando durante décadas hasta convertirla en un proceso ligero, basado en herramientas y con expectativas claramente definidas para autores y revisores [3][4].

B. Objetivos esenciales: calidad, salud del código y transferencia de conocimiento

Existe evidencia empírica sólida de que la revisión reduce defectos: los commits que no pasan por revisión tienen el doble de probabilidad de introducir errores que los que sí lo hacen [1]. Sin embargo, reducir la revisión de código a una simple cacería de bugs es un error de enfoque. Un estudio de referencia realizado en Microsoft, basado en la observación, entrevista y encuesta de desarrolladores y en la clasificación manual de cientos de comentarios de revisión, encontró que encontrar defectos sigue siendo la motivación principal declarada, pero en la práctica las revisiones giran menos en torno a los defectos de lo esperado y aportan beneficios adicionales: transferencia de conocimiento, aumento de la conciencia de equipo y generación de soluciones alternativas a los problemas [2].

Ese mismo estudio identifica que la comprensión del cambio y del código es el aspecto clave de la revisión, y que las herramientas actuales todavía no cubren adecuadamente esa necesidad de comprensión [2]. En Google, el análisis de la práctica interna confirma que, más allá de detectar errores, la revisión cumple efectos normativos —dar consistencia a la base de código—, efectos educativos —asegurar que más de una persona conozca el código—, mejora la calidad de las pruebas, previene accidentes y sirve como control de acceso (gatekeeping) para proteger bases de código de otros equipos [4]. Este último punto conecta directamente con la importancia de un buen proceso de onboarding técnico, ya que la revisión de código es, en la práctica, uno de los principales vehículos de aprendizaje para quien se incorpora a un equipo.

II. El factor humano: separación del ego y psicología del desarrollo

A. Los fundamentos de la programación sin ego

Mucho antes de que existieran los pull requests, el investigador Gerald M. Weinberg planteó en su obra clásica sobre la psicología de la programación de computadoras el concepto de «programación sin ego» (egoless programming): la idea de que un desarrollador no debe identificarse personalmente con el código que escribe, precisamente para poder someterlo a escrutinio ajeno sin experimentarlo como un ataque a su valía profesional [6]. Esta separación entre la persona y su producto de trabajo es, décadas después, uno de los pilares conceptuales sobre los que se sostienen las guías modernas de revisión de código.

En la práctica, esto significa dos cosas simultáneas. Para el autor del cambio, implica aceptar que un comentario sobre una función o una decisión de diseño no es un juicio sobre su inteligencia o su valor como profesional. Para el revisor, implica formular observaciones centradas en el código y sus consecuencias, no en la persona que lo escribió. Esta disciplina psicológica es la base sin la cual ninguna técnica de comunicación —por sofisticada que sea— logrará su propósito.

B. Hechos y datos técnicos por encima de opiniones subjetivas

Las guías de revisión de código de Google formalizan este principio con una regla explícita: los hechos y datos técnicos prevalecen sobre las opiniones y preferencias personales [7]. En materia de estilo, la autoridad absoluta es la guía de estilo del equipo; cualquier punto de estilo puro que no esté recogido en ella queda como preferencia personal, y en ausencia de un estilo previo establecido, se acepta el del autor [7]. Es una distinción crucial: el diseño de software casi nunca es una cuestión de estilo o gusto personal, sino que responde a principios de ingeniería subyacentes que deben evaluarse en esos términos y no mediante la opinión particular del revisor [7]. Cuando existen varias soluciones igualmente válidas —algo que el autor puede demostrar con datos o principios sólidos de ingeniería—, el criterio que debe prevalecer es el del autor [7].

Esta jerarquía de criterios evita buena parte de los conflictos que surgen en la revisión: obliga a ambas partes a argumentar desde la evidencia técnica y no desde la autoridad percibida o la antigüedad en el equipo, algo especialmente relevante para quienes están construyendo su perfil como desarrolladores backend y aprenden a defender sus decisiones de diseño con argumentos técnicos sólidos.

III. Comunicación asertiva y estructuración del feedback

A. El estándar Conventional Comments

Uno de los mayores avances prácticos en la comunicación durante la revisión de código es la especificación Conventional Comments, un estándar de formato que se puede aplicar a cualquier proceso de revisión —revisión de código, revisión por pares, edición de textos o solicitudes de comentarios (RFC)— [8]. Su premisa es sencilla pero poderosa: un comentario del tipo «Esto no está redactado correctamente» resulta poco útil y suena a reproche; basta con anteponerle una etiqueta —por ejemplo, «sugerencia:»— para que la intención quede clara y el tono cambie radicalmente [8].

El formato propuesto es el siguiente:

<etiqueta> [decoraciones]: <asunto>
[discusión]

Donde la etiqueta indica el tipo de comentario, el asunto es el mensaje principal, las decoraciones (opcionales, entre paréntesis) matizan la etiqueta, y la discusión (opcional) añade contexto, razonamiento y los pasos a seguir para resolver el comentario [8]. Entre las etiquetas más recomendadas están «praise» (elogio, para reconocer sinceramente algo positivo), «nitpick» (una petición trivial basada en preferencia, siempre no bloqueante por naturaleza), «suggestion» (una propuesta de mejora, que debe explicitar qué se sugiere y por qué constituye una mejora) y «question» (una petición de aclaración) [8][9].

La utilidad de este estándar ha sido documentada también fuera del propio sitio de la especificación: analistas que lo han adoptado en sus equipos señalan que reduce la fricción y la confusión, obliga a poner más cuidado en cada comentario —lo que eleva la calidad de la revisión en su conjunto— y acelera el proceso al eliminar la ambigüedad sobre si un comentario exige una acción concreta o no [9]. Un beneficio adicional, casi técnico, es que estos comentarios estructurados son analizables de forma automática: un equipo puede auditar cuántos comentarios de tipo «nitpick» se generan para decidir si ajustar el linter, o cuántos «issue» aparecen para revisar si el problema es de comprensión de requisitos antes del desarrollo [8][9].

B. Diferenciar lo bloqueante de lo menor: el prefijo «Nit:»

Una de las fuentes de fricción más comunes en la revisión de código es que el autor no sabe si un comentario es una condición para la aprobación o simplemente una opinión de pulido. Las guías de Google resuelven esta ambigüedad con una regla explícita: si el revisor considera que algo podría mejorarse pero no es muy importante, debe anteponer el prefijo «Nit:» para que el autor sepa que es solo un punto de pulido que puede optar por ignorar [7]. La especificación Conventional Comments formaliza esta misma idea con la etiqueta «nitpick» y con decoraciones como «(non-blocking)», que se pueden combinar con cualquier otra etiqueta —por ejemplo, «issue (non-blocking):» o «suggestion (blocking):»— para dejar explícito si el cambio debe resolverse antes de aprobar o si puede abordarse después [8][9].

Esta categorización explícita —bloqueante, no bloqueante, menor— no es un detalle cosmético: es la diferencia entre una revisión que fluye y una que se estanca en discusiones interminables sobre puntos irrelevantes.

C. El feedback como herramienta de mentoría sin frenar la entrega

La revisión de código puede y debe cumplir una función pedagógica: es perfectamente válido dejar comentarios que ayuden a un desarrollador a aprender algo nuevo sobre un lenguaje, un framework o principios generales de diseño de software, porque compartir conocimiento forma parte de mejorar la salud del código a lo largo del tiempo [7]. La clave está en no confundir la enseñanza con el bloqueo: si un comentario es puramente educativo pero no crítico para cumplir con el estándar exigido, debe marcarse como «Nit:» o señalarse de alguna forma como no obligatorio para que el autor lo resuelva en ese cambio concreto [7]. Este equilibrio es especialmente relevante para quienes diseñan procesos de onboarding técnico, donde la revisión de código de los primeros cambios de un nuevo integrante suele ser el principal vehículo de transmisión de normas y convenciones del equipo [4].

IV. Optimización del flujo y dimensionamiento del cambio

A. Cambios pequeños, defectos detectados

Uno de los hallazgos empíricos más citados sobre la eficacia de la revisión de código proviene del estudio conjunto entre Smart Bear Software y el grupo de desarrollo MeetingPlace de Cisco Systems, considerado en su momento el mayor estudio de caso jamás realizado sobre un proceso de revisión ligero de código, con datos recogidos a lo largo de diez meses [5]. Entre sus conclusiones más relevantes: las revisiones tuvieron una densidad promedio de 32 defectos por cada mil líneas de código, aunque el 61 % de las revisiones no detectó ningún defecto y, en el resto, la densidad osciló entre 10 y 130 defectos por cada mil líneas [5].

El dato más operativo del estudio, sin embargo, es este: los cambios de menos de 200 líneas producen una tasa de detección de defectos relativamente alta, a menudo varias veces superior al promedio [5]. En otras palabras, existe un punto óptimo de tamaño de revisión; más allá de él, la eficacia cae de forma pronunciada. El estudio también documentó una relación entre la velocidad de revisión y su eficacia: los revisores más lentos que 400 líneas por hora estaban por encima del promedio en su capacidad de detectar defectos, mientras que al superar las 450 líneas por hora la densidad de defectos detectados quedaba por debajo del promedio en el 87 % de los casos [5]. La recomendación práctica que se desprende es clara: mantener los cambios en torno a las 200 líneas, tomarse el tiempo necesario, pero sin exceder aproximadamente una hora de revisión continua, ya que la efectividad cae de forma marcada a partir de ese punto [5].

El estudio añade un matiz interesante: cuando el autor anota su propio código antes de someterlo a revisión —explicando cómo está estructurado el cambio y por qué se tomaron ciertas decisiones—, la densidad de defectos nunca supera los 30 por cada mil líneas, y el caso más frecuente es que no se encuentre ningún defecto en absoluto; en cambio, las revisiones sin comentarios previos del autor muestran una variabilidad mucho mayor [5]. Esta práctica de autopreparación es, en esencia, una extensión de la buena documentación que también resulta clave a la hora de comunicar decisiones técnicas de forma clara y verificable, una habilidad que también se valora en procesos de contratación.

B. Rapidez en la primera respuesta y asignación de revisores

El estudio sobre la práctica de Google en revisión de código identifica varios rasgos distintivos frente a otros procesos —de código abierto, de Microsoft o de otras organizaciones—: los primeros comentarios de revisión llegan rápido, los cambios son de menor tamaño, habitualmente interviene un solo revisor (frente a los dos habituales en otros procesos), las expectativas del proceso están claramente definidas, y la propia herramienta recomienda la elección del revisor en función de la propiedad del código, la carga de revisión existente y la disponibilidad [4]. Esta combinación de factores reduce los cuellos de botella tanto cognitivos —revisores que deben procesar cambios enormes y complejos— como operativos —colas de revisión que se acumulan por asignaciones mal balanceadas—.

El roadmap más reciente sobre revisión moderna de código, que consolida más de una década de investigación entre 2013 y 2025, confirma que este ha sido un cornerstone del aseguramiento de calidad del software y un canal vital de transferencia de conocimiento dentro de los equipos de desarrollo, si bien advierte que la inspección manual de sistemas cada vez más complejos sigue siendo una actividad exigente cognitivamente y costosa en recursos, lo que a menudo provoca cuellos de botella significativos en el flujo de trabajo [1]. Este mismo trabajo distingue entre técnicas de mejora —orientadas a la optimización técnica y automatización de las tareas de revisión— y estudios de comprensión, centrados en los mecanismos socio-técnicos que subyacen al proceso [1], una distinción útil para entender que la revisión de código combina siempre una dimensión de herramienta y una dimensión humana.

V. Estándar de entrega y mejora continua vs. perfeccionismo

A. El principio senior de aprobación

Quizás la formulación más influyente sobre cuándo aprobar un cambio proviene directamente de las guías de ingeniería de Google, que la describen como «el principio senior entre todas las directrices de revisión de código» [7]. Su enunciado es el siguiente: en general, los revisores deben favorecer la aprobación de un cambio una vez que este se encuentra en un estado que mejora de forma definitiva la salud general del código del sistema en el que se trabaja, incluso si el cambio no es perfecto [7].

Detrás de esta regla hay un equilibrio de compromisos cuidadosamente sopesado. Por un lado, los desarrolladores necesitan poder avanzar en sus tareas: si nunca se aprueba una mejora, la base de código nunca mejora, y si un revisor dificulta en exceso que cualquier cambio se integre, desincentiva a los desarrolladores a proponer mejoras en el futuro [7]. Por otro lado, es responsabilidad del revisor asegurar que cada cambio mantenga la calidad del sistema, algo especialmente delicado porque las bases de código suelen degradarse mediante pequeñas concesiones cuando los equipos están bajo presión de tiempo y sienten que deben tomar atajos [7]. La guía es explícita en un punto: no existe el código «perfecto», solo existe código mejor; el revisor no debe exigir que se pula cada detalle antes de otorgar la aprobación, sino buscar la mejora continua [7]. Ahora bien, esto no habilita en ningún caso integrar cambios que empeoren claramente la salud del sistema; la única excepción contemplada es una situación de emergencia genuina [7].

B. Responsabilidades compartidas entre autor y revisor

El revisor tiene, además, una responsabilidad de propiedad sobre el código que revisa: debe velar por que la base se mantenga consistente, mantenible y alineada con los demás criterios de calidad esperados [7]. Cuando surge un conflicto —por ejemplo, sobre si una determinada decisión de diseño es aceptable—, el primer paso siempre debe ser que autor y revisor intenten llegar a un consenso basado en los principios documentados del equipo; si la dificultad persiste, puede ayudar una conversación cara a cara o por videollamada en lugar de continuar el desacuerdo únicamente a través de comentarios escritos, dejando constancia posterior del resultado de esa conversación en el propio cambio para referencia futura [7].

Esta responsabilidad compartida —el autor debe estar dispuesto a incorporar feedback sin tomarlo como algo personal, y el revisor debe formular ese feedback de manera constructiva, priorizada y basada en hechos— es, en el fondo, la síntesis de todo lo expuesto en este artículo: la revisión de código funciona cuando se trata como una conversación técnica entre profesionales que comparten un objetivo común, no como un examen que unos aprueban y otros reprueban. Dominar esta dinámica es, cada vez más, una competencia tan relevante como el manejo de los lenguajes de programación backend más utilizados en la industria, y forma parte del perfil que hoy buscan los equipos de ingeniería más maduros.

Fuentes Oficiales y Referencias Consultadas