Corrección de errores extraños y estrategias de depuración probadas con el tiempo



¿Recuerda la última vez que se encontró con un error en la interfaz de usuario que le llevó horas y horas solucionar? Quizás este error ocurrió periódicamente, sin motivo aparente. ¿Quizás apareció bajo ciertas condiciones (podría depender del dispositivo, sistema operativo, navegador o acciones del usuario) o estaba escondido en algún lugar en las profundidades de una de las muchas tecnologías de front-end que forman parte del lado del cliente del proyecto web?



Recientemente tuve que recordar cuán confusas pueden ser las causas de los errores de la interfaz de usuario. Es decir, estamos hablando de corregir un error interesante que afecta la salida de imágenes SVG en el navegador Safari. Este error ocurrió sin ningún sistema específico y sin una razón obvia. Cuando me enfrentaba a un problema, traté de encontrar casos similares, esperando que las descripciones de tales casos me dieran una pista de lo que estaba sucediendo. Pero no he podido encontrar nada útil. Es cierto que, a pesar de todos los obstáculos frente a mí, pude hacer frente a este error.



He analizado el problema utilizando algunas de las estrategias de depuración que voy a cubrir en este artículo. Después de deshacerme del error, recordé el consejo.que Chris Coyer dio a sus lectores de Twitter hace unos años. Este consejo es el siguiente: "Escriba el artículo que le gustaría encontrar cuando visite un motor de búsqueda". De hecho, eso es lo que hice.



Resumen del problema



En un proyecto en el que estaba trabajando, en un sitio en vivo, encontré un error, cuya manifestación grabé en este video. Así es como se ve el botón en su estado normal.





Botón en estado normal



Y aquí está el mismo botón después de un problema.





Parte del botón está cortado.



He reproducido este error en varias situaciones, provocando que se vuelva a dibujar la página. Por ejemplo, ocurrió cuando se cambió el tamaño de la ventana del navegador.



Para demostrar el problema, creé un ejemplo en CodePen . Lo discutiremos con más detalle a continuación. Pero puedes experimentar con este ejemplo tú mismo. Es decir, estamos hablando del hecho de que si abre este ejemplo en el navegador Safari, cuando se cargue la página, los botones se verán como se esperaba. Pero si hace clic en uno de los dos botones más grandes, el error asoma su fea cabeza.





¿Por qué se recorta la imagen SVG?



Cada vez que ocurre el eventopaint, las imágenes SVG utilizadas en los botones más grandes no se muestran correctamente. Estas imágenes simplemente se recortan. Esto puede suceder, sin motivo aparente, al cargar la página. Esto puede suceder incluso cuando se cambia el tamaño de la ventana. En general, el error aparece en una variedad de situaciones.



Una descripción general del proyecto en el que se produjo el error



Creo que al hablar del error, será bueno revelar detalles sobre el proyecto y las condiciones en las que ocurre.



  • El proyecto usa React (pero el lector de este artículo no necesita conocer React para entenderlo).
  • Las imágenes SVG se importan al proyecto como componentes de React y se incrustan en HTML mediante webpack.
  • . .
  • CSS.
  • , , HTML- <button>.
  • Safari ( 13 ).




Veamos el error y consideremos si podemos hacer suposiciones sobre lo que está sucediendo. Las razones de tales errores generalmente no se encuentran en la superficie, por lo tanto, frente a tales errores, uno no puede decir inmediatamente con confianza lo que está sucediendo. En nuestro primer intento por comprender un problema, no tenemos que esforzarnos por identificar su causa con una precisión del 100%. Investigaremos el error paso a paso, formulando y probando hipótesis que nos ayudarán a acotar la lista de posibles causas de lo que está sucediendo.



Formular una hipótesis



A primera vista, lo que está sucediendo parece un error CSS. Quizás, cuando pasa el mouse sobre el botón, se le aplican algunos estilos que rompen el diseño. Quizás el atributo de overflowimagen SVG sea ​​el culpable . Además, existe la sensación de que el error se produce sin ningún sistema específico cuando la página se vuelve a dibujar por diversas razones (un evento paintcuando se cambia el tamaño de la ventana del navegador, cuando el puntero del mouse está sobre un botón, cuando se hace clic en él, etc.).



Comencemos con la suposición más simple y obvia. Digamos que el error está en el CSS. Podemos suponer que hay un error en el navegador Safari que da como resultado una salida SVG incorrecta cuando se aplican estilos específicos a elementos SVG. Por ejemplo, como los estilos utilizados para crear diseños flexibles.



Acabamos de formular una hipótesis. Nuestro siguiente paso es realizar una prueba que confirme o refute esta hipótesis. El resultado de cada prueba nos dará nueva información sobre el error y ayudará a formular las siguientes hipótesis.



Simplificando el problema



Usaremos una estrategia de depuración llamada "simplificar el problema". Esto nos permitirá identificar dónde ocurrió el error. En una conferencia sobre informática en la Universidad de Cornell, esta estrategia se describe como "un enfoque para deshacerse gradualmente del código que no está relacionado con el error".



Suponiendo que el error se encuentra en el CSS, eventualmente podemos encontrar la causa del error o excluir el CSS de la ecuación, lo que reducirá el número de posibles causas del error y reducirá la complejidad del problema.



Probemos nuestra hipótesis. Intentemos confirmarlo. En este caso, si desactiva temporalmente todos los estilos no estándar de la página, esto debería provocar que el error ya no aparezca.



Aquí está el código para incluir la hoja de estilo apropiada:



import 'css/app.css';


Creé este proyecto de CodePen para demostrar la salida de elementos sin CSS . En React, los gráficos SVG se importan al proyecto como un componente , luego el código correspondiente se incrusta en HTML usando webpack.





Vista de botones normal



Si abre el proyecto mencionado anteriormente en Safari y hace clic en uno de los botones grandes, resulta que el error no se ha ido a ninguna parte. También sucede cuando se carga la página, pero al usar CodePen, debe hacer clic en el botón para activar un error.





El error persistió incluso cuando CSS estaba deshabilitado (Safari 13)



Como resultado, podemos concluir que CSS no tiene nada que ver con eso. Sin embargo, podemos prestar atención al hecho de que, en tales condiciones, solo dos de los cinco botones se muestran incorrectamente. Recordemos esto y pasemos a la siguiente hipótesis.



Aislamiento de errores



Nuestra siguiente hipótesis es que Safari tiene un error al representar imágenes SVG dentro de elementos HTML <button>. Dado que el problema surge cuando se muestran los dos primeros botones, aislamos el primero de ellos y vemos qué sucede.



Sarah Drazner en estoEl material explica la importancia del aislamiento. Recomiendo encarecidamente leer este material a cualquier persona interesada en obtener más detalles sobre las herramientas de depuración y los diferentes enfoques para encontrar errores. Aquí hay una cita de ese material: “El aislamiento es quizás el principio básico más importante de depuración. El código que funciona en nuestros proyectos se puede distribuir en diferentes bibliotecas y marcos. Muchas personas pueden estar involucradas en el trabajo de los proyectos y algunos de los que contribuyeron al desarrollo de los proyectos ya no trabajan en ellos. Aislar el problema nos ayuda a cortar lentamente lo que no está causando que aparezca el error. Esto permite, al final, encontrar el origen del problema y concentrarse en él ".



El aislamiento de fallas a menudo se denomina " caso de prueba abreviado ".



Moví el botón a una página en blanco separada (creé una prueba separada para él). Es decir, este proyecto de CodePen se creó para investigar un botón de forma aislada. Si bien hemos llegado a la conclusión de que CSS no es la causa del problema, debemos dejar los estilos deshabilitados hasta que descubramos la causa real del problema. Esto nos permitirá simplificar el problema tanto como sea posible.





Una página con solo un botón



Si abre este proyecto en Safari, resulta que ya no podemos generar un error. Incluso después de hacer clic en el botón, la imagen no cambia. Pero esto no puede considerarse una solución aceptable al problema. Sin embargo, el código de este proyecto de CodePen nos brinda una base excelente para crear un ejemplo mínimo reproducible.



Ejemplo mínimo reproducible



La principal diferencia entre los dos proyectos anteriores de CodePen es la combinación de botones. Examinar todas las combinaciones posibles de botones nos permite concluir que el problema solo ocurre cuando ocurre un evento paintpara una imagen SVG más grande, junto a la cual se encuentra una imagen SVG más pequeña en la página.



Saber esto nos permitió crear un ejemplo mínimo reproducible que nos permitió reproducir el error y aún así deshacernos de cualquier elemento innecesario. Gracias a un ejemplo mínimo reproducible, podemos estudiar el problema con más profundidad y resaltar exactamente la parte del código que lo causa.



Aquí está el proyecto CodePen en cuestión.





Ejemplo mínimo reproducible



Si abrimos este proyecto en Safari y hacemos clic en el botón, nos enfrentamos nuevamente al problema. Esto nos permitirá formular una hipótesis de que los dos elementos SVG de alguna manera entran en conflicto entre sí. Si superpone la segunda imagen SVG encima de la primera, resulta que el tamaño de lo que queda del fondo de la primera imagen coincide exactamente con el tamaño de la imagen más pequeña.





Un dibujo en el que la segunda imagen se coloca encima de la primera, distorsionada como resultado de un error



Divide y vencerás



Pudimos reproducir el error utilizando la cantidad mínima de elementos representados por un par de imágenes SVG. Ahora vamos a reducir aún más el alcance del problema, reduciéndolo a la parte específica del código SVG que es la fuente del problema. Si entendemos el código SVG en términos generales y aún queremos encontrar la fuente del problema, entonces podemos usar una estrategia de búsqueda de árbol binario usando un enfoque de divide y vencerás. Aquí hay otro extracto de la conferencia.de Ciencias de la Computación de la Universidad de Cornell: “Por ejemplo, puede comenzar examinando un gran fragmento de código y colocar el código de validación en el medio del fragmento que está examinando. Si no ocurre un error aquí, significa que su fuente está en la segunda mitad del código. De lo contrario, su fuente está en la primera mitad del código ".



Al examinar el código SVG, puede intentar eliminar un elemento <filter>de la descripción de la primera imagen (y también <defs>, ya que de todos modos no hay nada en este bloque). Interesémonos en qué tipo de tareas resuelve el elemento <filter>. Puede encontrar una gran explicación para esto aquí . Es decir, estamos hablando de lo siguiente: “Para aplicar filtros a imágenes SVG, hay un elemento especial llamado<filter>... Básicamente se parece a elementos diseñados para trabajar con degradados lineales, máscaras, plantillas y otros efectos gráficos. El elemento <filter>nunca se muestra por sí solo. Solo se usa como algo a lo que se puede hacer referencia mediante un atributo filteren el código SVG o una función url()en CSS ".



En nuestra imagen SVG, se usa un filtro para agregar una pequeña sombra interior en la parte inferior de la imagen. Después de quitar el filtro del código de la primera imagen, esperamos a que esta sombra desaparezca. Si después de que los problemas persiste, entonces podemos concluir que algo está mal con el otro código para describir el elemento SVG.



Creé otro proyecto CodePen con el fin de demostrar los resultados de esta prueba.





Consecuencias de eliminar el elemento <filter>



El problema, como puede ver fácilmente, no ha desaparecido. Y la sombra interior continúa mostrándose incluso después de eliminar el código de filtro. Pero ahora, entre otras cosas, el problema aparece en todos los navegadores. Esto nos permite concluir que el error está en algún lugar del resto del código de descripción del botón. Si se quita el restoidde<g filter="url(#filter0_ii)">, a continuación, la sombra desaparece. ¿Que está pasando aqui?



Echemos otro vistazo a la definición anterior de un elemento<filter>y observemos las siguientes palabras: “Un elemento<filter>nunca se muestra por sí solo. Solo se usa como algo que se puede hacer referencia mediante un atributofilteren SVG ". (Destaqué un fragmento del texto).



Entonces, sabiendo esto, podemos concluir que la declaración de filtro de la segunda imagen SVG se aplica a la primera imagen SVG, lo que conduce al error.



Arreglo del fallo



Ahora sabemos que nuestro problema está relacionado con elementos <filter>. También sabemos que ambos SVG tienen este elemento, ya que el filtro se usa para crear una sombra interior circular. Comparemos el código de dos imágenes SVG y pensemos si podemos explicar el error y solucionarlo.



He simplificado el código de ambas imágenes para que puedas ver claramente lo que está sucediendo en ellas.



Aquí está el código de la primera imagen SVG:



<svg width="46" height="46" viewBox="0 0 46 46">
  <g filter="url(#filter0_ii)">
    <!-- ... -->
  </g>
  <!-- ... -->
  <defs>
    <filter id="filter0_ii" x="0" y="0" width="46" height="46">
      <!-- ... -->
    </filter>
  </defs>
</svg>


Aquí está el código de la segunda imagen:



<svg width="28" height="28" viewBox="0 0 28 28">
  <g filter="url(#filter0_ii)">
    <!-- ... -->
  </g>
  <!-- ... -->
  <defs>
    <filter id="filter0_ii" x="0" y="0" width="28" height="28">
      <!-- ... -->
    </filter>
  </defs>
</svg>


Al analizar estos dos fragmentos, puede observar que id=filter0_iise usa el mismo identificador en la construcción . Safari aplica la última definición de filtro analizada por el navegador a los elementos (en este caso, el filtro de la segunda imagen). Esto lleva al hecho de que se recorta la primera imagen. Su tamaño original es 48px, y después de aplicar el filtro, se corta un trozo del mismo 26px. La propiedad idDOM debe tener un valor único. Si hay varios idénticos en la página id, el navegador no puede determinar cuál necesita usar. Y dado que la propiedad se filteranula cuando ocurre cada eventopaint, luego, dependiendo de cuál de las definiciones estará lista primero (aquí ocurre algo así como una condición de carrera), el error aparece o no.



Intentemos asignar valores únicos iden el código de cada una de las imágenes y veamos los resultados. Aquí está el proyecto CodePen correspondiente.





La asignación de identificadores únicos resolvió el problema



Si ahora abre el proyecto en Safari y hace clic en el botón, puede estar seguro de que resolvimos el problema asignandoidfiltrosúnicosutilizados en las imágenes SVG. Si piensa en el hecho de que el proyecto tenía valores no únicos para un atributo comoid, lo llevará a la conclusión de que el problema debería haber aparecido en todos los navegadores, no solo en Safari. Pero por alguna razón, otros navegadores (incluidos Chrome y Firefox) parecen haber manejado esta situación inusual sin errores. Sin embargo, podría ser solo una coincidencia.



Salir



¡Fue otra aventura! Empezamos sabiendo solo que había algún tipo de error en el proyecto, que a veces aparece y luego no, y al final entendimos completamente las razones de lo que estaba pasando y afrontamos el problema. Depurar el código de la interfaz de usuario y averiguar por qué los gráficos están distorsionados puede ser complicado si no comprende lo que está sucediendo. Pero, afortunadamente, existen estrategias de depuración que pueden ayudarnos a encontrar la causa raíz de incluso los errores más confusos.



Primero, simplificamos el problema formulando hipótesis que nos permitieron eliminar componentes del proyecto que no estaban relacionados con el error (estilos, marcado, eventos dinámicos, etc.). Después de eso, aislamos el marcado y encontramos un ejemplo mínimo reproducible. Esto nos permitió concentrarnos en un pequeño fragmento de código. Y finalmente identificamos el problema usando una estrategia de divide y vencerás para deshacernos del error.



Gracias a todos los que se tomaron el tiempo de leer este artículo. Pero, antes de terminar la conversación, permítanme contarles sobre otra estrategia de depuración mencionada en las conferencias.Universidad de Cornell. El punto es que en el proceso de trabajo necesitas tomar descansos, descansar y liberar tu cabeza de todos los pensamientos: “Si lleva demasiado tiempo depurar, entonces el programador se cansa. Puede resultar que él, estando en tal estado, trabaje en vano. En una situación como esta, vale la pena tomar un descanso y tirar todo de la cabeza. Y después de un tiempo, debería intentar ver el problema desde un punto de vista diferente ".



¿Cómo se corrigen errores incomprensibles?






All Articles