Cuentos de bichos: Estrategia de gestión de errores

En entradas anteriores te comenté el origen de los errores de software y realicé una pequeña y divertida clasificación. Hoy sigo con la temática bichos para recomendarte una aproximación interesante al modo de gestionar aquellos errores que, en ocasiones, puedan aparecer en tu código. Hay cuatro preguntas fundamentales que deberías hacerte a ti mismo para definir tu estrategia en lo referente a la gestión de cada casuística de error en tu desarrollo:

1. ¿Voy a mostrar estos errores?

Si bien es cierto que en un entorno de desarrollo esto es más que necesario hacerlo, en producción, el hecho de mostrar los errores de nuestra aplicación con toda la información que pueden facilitar es, cuando menos, una invitación a hackearla. Añade a esto que tu desarrollo parecerá mal diseñado y poco profesional a ojos de los usuarios y clientes. Es fundamental, por tanto, que puedas manejar la visibilidad de las notificaciones de error de tu aplicación según el entorno en el que se esté ejecutando, y que nunca se muestren en producción.

2. ¿Voy a registrar estos errores?

Anotar las notificaciones de error en un registro donde poder consultarlas más tarde es un modo excepcional para rastrear posteriormente sus causas. También disponemos de la posibilidad de, por ejemplo mediante syslog, realizar esta gestión a través del sistema operativo.

3. ¿Voy a ignorar estos errores?

Pueden darse errores que no resulten críticos para tu ampliación, como puede ser el intento de lectura de un archivo de configuración inexistente. En este caso, la función de lectura podría lanzar un error crítico que detuviera la ejecución de tu aplicación, sin que el usuario haya recibido ningún tipo de información sobre dicha interrupción. En este caso puede ser interesante ignorar el error para preservar la ejecución.

4. ¿Voy a actuar frente a estos errores?

Seguimos con el caso anterior. Al ignorar el error has evitado un cierre inesperado de la aplicación. Con el fin de facilitar un poco más de información a tu usuario, una vez echo esto, hay que comprobar si disponemos del archivo y podemos hacer uso de él. En el caso que comentamos, no es así, pero ahora podemos informar al usuario de que no ha sido posible disponer del archivo de configuración, informar de posibles causas y soluciones y, a continuación, cerrar nosotros mismos la aplicación de un modo elegante.

La combinación de respuestas frente a estas cuatro preguntas te ayudarán a determinar, de un modo sencillo, tu estrategia de gestión para cada casuística de error.

Cuentos de bichos: Bestiario

Heisenbug

Fisonomía

 Toma su nombre del físico especializado en mecánica cuántica Werner Heisenberg, quien dedujo que el mero hecho de observar un sistema de una manera determinada altera el estado de éste. Cuando se usan herramientas durante el proceso de depuración para localizar y eliminar bichos, se producen pequeñas diferencias respecto al entorno de producción, es decir, con respecto al entorno final en el cual deberá funcionar nuestro dispositivo de software. El Heisenbug es especialista en aprovechar cualquiera de estas leves diferencias para mostrar comportamientos distintos que confundan al programador o para simplemente desaparecer.

Habilidad principal

 Su principal fortaleza consiste en la capacidad de mutar o desaparecer cuando se siente amenazado por un depurador.

Capacidad de destrucción

 Es especialmente destructivo con respecto a los compromisos de entrega de software, pues puede elevar muchísimo los tiempos de depuración. Se conocen casos de programadores que, víctimas de la desesperación, han propuesto depurar en el entorno de producción para localizar y destruir a este esquivo bicho.

Bohrbug

Fisonomía

 Debe su nombre al modelo atómico que desarrolló el físico Danés Niels Bohr para explicar, entre otros hechos, la estabilidad de la materia. El Bohrbug puede atormentar amargamente al cerebro lógico de un desarrollador, pues tan lógico seso no comprenderá como dicho bug sigue mostrándose una y otra vez, impasible, ante las innumerables correcciones realizadas en el código con el ánimo de destruirlo.

Habilidad principal

 Es conocido por su capacidad de permanecer inalterable ante cualquier acción de depuración.

Capacidad de destrucción

 Como suele presentarse en etapas tempranas, y se detecta con facilidad en pruebas y depuraciones, a lo que ataca principalmente es al orgullo y a la paciencia de los programadores.

Mandelbug

Fisonomía

 El conjunto fractal descubierto por Benoit Mandelbrot, un monstruo matemático de gran complejidad, inspiró el nombre de este bicho. Su modo de operar consiste en cimentar su existencia en causas tan complejas que sea difícil comprenderlas y atacarlas. Debido a esto, su comportamiento parece caótico, pues tras cada solución aplicada en el código, únicamente se conseguirá que el bicho actúe de un modo distinto, pero no quedará eliminado.

Habilidad principal

 Es capaz de formarse a sí mismo a partir de una combinación de pequeños detalles en muchísimas porciones de código aparentemente inconexas. Dar con la combinación que lo sustenta puede llegar a ser una ardua tarea de ingeniería inversa.

Capacidad de destrucción

 No es un bicho que se muestre en las últimas fases del desarrollo, así que se detecta a tiempo para depurarlo, pero es ahí donde radica su máximo poder. Destruir un Mandelbug puede ocasionar que se deba corregir muchas porciones de código, creando otros tipos de bugs distintos y alterando la arquitectura y la lógica de la aplicación. Puede, por tanto, herir gravemente e incluso malograr un proyecto a la mitad de su desarrollo.

Schroedinbug

Fisonomía

 Schrödinger describió una paradoja según la cual, teniendo un gato en una caja, no podemos saber si está vivo o muerto hasta abrir dicha caja, y por lo tanto se considera que se encuentra vivo y muerto a la vez hasta que la abramos. Esta paradoja aplica a la perfección a los Schrodinbugs, pues dichos bichos no se manifiestan hasta que alguien, leyendo el código o usando el programa de un modo poco habitual, descubre que nunca debería haber funcionado. ¡Desde ese momento, la caja queda abierta, y en el programa se muestra una y otra vez el bug que parecía no haber existido nunca!

Habilidad principal

 Su capacidad de permanecer invisible el mayor tiempo posible y su omnipresencia una vez determinada la certeza de sus existencia.

Capacidad de destrucción

 Depende de la parte que ataque de nuestra aplicación, pero el principal peligro que acarrea este tipo de bichos es la dificultad de una detección prematura, lo cual lo hace muy peligroso.

Stotle

Fisonomía

 Es más que un simple bicho, es la idea de bicho atormentando la mente de un desarrollador que ha sido engañado, confundido. Se trata de introducir, sin ser conscientes, datos incorrectos en la entrada del programa. Al percibir que la salida no es correcta, y estando convencidos de que la entrada si lo era, comenzamos a buscar un bicho que no existe, y que ocupará durante un buen rato nuestro tiempo y nuestra mente. Es como si teclearas en una calculadora la multiplicación de dos por tres, cuando realmente quisiste teclear la suma de estos números. Al ver el resultado de seis en lugar de cinco dudarás del correcto funcionamiento del artilugio, e intentarás arreglar algo que no estaba roto. Su nombre deriva de Aristóteles (Aristotle) porque del mismo modo que Aristóteles no era cuestionado antiguamente, y se asumía que debía estar en lo cierto, el programador no cuestiona la entrada de datos, asumiendo que hay un bicho en el programa.

Habilidad principal

 Hacer creer a los programadores que existe.

Capacidad de destrucción

  Dado que no es más que una idea de bug, no existe, no es peligroso para el proyecto en sí. No obstante, puede desquiciar a algún desarrollador.

Bugs de fase lunar

Fisonomía

 Son aquellos bichos que se muestran por los motivos más aleatorios o esotéricos que se puedan imaginar. Son fallos en el programa que únicamente suceden cuando la lluvia cae sobre los cristales de las ventanas de la oficina, cuando la chica rubia de recursos humanos pasa por delante de la puerta del despacho donde trabaja el equipo de desarrollo, cuando el aire acondicionado está a veinticuatro grados...

Habilidad principal

 No pertenecen al mundo lógico y racional del desarrollo de software.

Capacidad de destrucción

   Mientras no exista dentro del endémico grupo de probadores o depuradores una especialización en exorcismos de dispositivos de software, o algo similar, estos bichos harán estragos allá donde quieran pulular.

Fantasmas en el código

Fisonomía

   Estos bichitos suelen ocultarse en rutinas o subprogramas que se usan en raras ocasiones y, a diferencia del Schroedinbug, no es necesario detectarlos para que se materialicen. Son muy difíciles de descubrir en las fases de desarrollo o pruebas.

Habilidad principal

    Se mostrarán motu proprio en el peor momento posible, ya sea cuando estemos presentando el proyecto finalizado a nuestro cliente o cuando lo hayamos puesto en producción.

Capacidad de destrucción

   Debido a su habilidad para ocultarse y aparecerse en el momento más inconveniente, pueden herir principalmente la imagen del equipo de desarrollo.

Cuentos de bichos: Mariposas en el código

 La polilla, una de esas pequeñas mariposas nocturnas que se sienten atraídas por la luz y cuya larva destruye la materia donde anida, es un lepidóptero. En fin, que es un bicho. En telegrafía, y en las primeras compañías telefónicas, era habitual usar la expresión "bichos en el cable de teléfono" para referirse al ruido y las interferencias en la comunicación. Si bien es cierto que la palabra inglesa «bug» ya fue usada para indicar un defecto industrial, y que el mismísimo Thomas Edison dispuso de ella con esta finalidad, es probable que fuera Grace Murray Hopper quien la aplicó por vez primera al ámbito de la informática. Ésta licenciada en física trabajaba como programadora en el Mark II, uno de esos primeros ordenadores que estaba formado por componentes electrónicos y electromecánicos, cuando investigando la causa de un fallo en el mastodóntico computador de IBM, halló una polilla bloqueando el relé 70 del panel F. El hecho se documentó de modo metódico, y el insecto quedó inmortalizado en una foto junto a un texto que rezaba "primera vez que se encuentra (en un ordenador) un «bug» de verdad". Así comenzó la leyenda del primer bug informático conocido.

 En la historia del sofware han sido muchos, y de muy diversa índole, los bichos que han querido alcanzar la fama que ostenta en el mundo de la ingeniería informática la polilla del relé 70. Los bichos han procurado realizar incursiones en los desarrollos de software desde la primera línea escrita de código, no discriminan ninguna posibilidad. Procuran infectar todo tipo de proyectos, tanto aquellos en los cuales apenas tienen el potencial de provocar pequeños inconvenientes, como eso proyectos susceptibles de costar tres billones de dolares a una empresa de automoción; o como aquel caso, en el que uno de esos malévolos bichos pudo haber desencadenado la tercera guerra mundial: En 1983 el sistema de alerta temprana de la Unión Soviética había detectado el lanzamiento de cinco misiles balísticos, el «bug» que se había colado dentro de aquel sistema hizo que éste confundiera el reflejo del sol sobre unas nubes con unos amenazantes proyectiles. El oficial soviético que se encontraba al mando en ese momento dedujo fríamente que, siendo real el ataque, el número de venablos a cohete superaría cinco con creces. De no ser por su acertada decisión de no reaccionar ante la señal de alerta, el ficticio ataque habría recibido una represalia difícil de explicar a la comunidad internacional.

 Para realizar estas correrías los «bugs» aprovechan cualquier resquicio: falta de conocimientos, poca experiencia, descuidos, momentos de baja concentración... Si bien es cierto que hay quien define que la expresión "sofware libre de «bugs»" es un oxímoron, y que desarrollar sin cometer ningún error que les abra la puerta a estos pequeños enemigos es utópico, hay métodos para combatirlos y reducir su presencia lo máximo posible. Llegados a este punto, es obligatorio nombrar a aquellos que defienden el uso de la programación funcional como modo de evitar los estados mutables (especialmente cuando el proyecto tiende a una explosión combinatoria), reduciendo drásticamente la presencia de «bugs», pero lo que realmente viene a la cabeza al pensar en un modo de desarrollar evitando bugs son los modelos de desarrollo. Uno de los primeros modelos que se nombra cuando se toca este tema es el desarrollo guiado por pruebas (TDD por sus siglas en inglés), en el cual se describen las pruebas de que el código funciona sin errores antes que el propio código. Las técnicas y principios del TDD fueron combinadas posteriormente con los análisis y diseños propios de la programación orientación a objetos (OOP) y el diseño guiado por dominios (DDD) para dar lugar al desarrollo guiado por comportamientos (BDD), el cual es, con casi toda seguridad, el más extremo y completo método de desarrollo de software en lo que a evitar «bugs» se refiere. Este modelo de desarrollo exige un fuerte apoyo en herramientas como, por ejemplo, Cucumber, lo cual puede conllevar un gasto económico extra que, sumado al inevitable aumento del tiempo de desarrollo, hace pensar que no es apto para todos los proyectos.

 Aunque hay proyectos que exigen un aumento del nivel de atención a la gestión de posibles «bugs», éste siempre debe ser, por defecto, lo más elevado posible. A modo de símil, es obvio que no es necesario el mismo nivel de asepsia en el entorno en el se cura una rozadura que en el que se opera a corazón abierto; no obstante, en el caso más laxo de los dos, es indiscutible que también se toman unas precauciones mínimas de higiene. No es necesario usar el mismo modelo de desarrollo para añadir un módulo personalizado a un blog en Worpress y para poner en funcionamiento la transitada tienda web de una empresa de ropa deportiva, la cual conlleva un elevado número de transacciones económicas y no es un proyecto tan inocuo como el primero, pero el nivel mínimo de prevención de «bugs», desde el cual partiremos en ambos casos, ha de ser suficientemente elevado; el error imperdonable, y que nunca se ha de cometer, es rebajar nuestra cota de intolerancia a los «bugs» en pos de la productividad. Una buena conclusión a todo lo expuesto sería la que sigue: En el momento de iniciar un proyecto debemos determinar cuanto es necesario aumentar nuestro estándar de intransigencia a los «bugs» para evitar mariposas en el código.

Sin documentos no hay hockey

En su libro “Advanced PHP programming”, George Schlossnagle hace la siguiente afirmación:
En mi empresa, el código producido para los clientes no se considera completo hasta que toda su interfaz externa de programación de la aplicación (API) y cualquier idiosincrasia interna están totalmente documentadas.
Esta declaración de Schlossnagle es una buena señal de lo importante que puede llegar a ser la gestión de la documentación del código fuente dentro de un proyecto de desarrollo de software.

Antes de proseguir, habría que discernir entre la documentación del proyecto y la documentación del código.
La primera puede contener requerimientos, casos de uso, diagramas y otros tipos de documentos cuya finalidad es definir el producto que se desea obtener y el modo de hacerlo. Sin embargo, la documentación del código, que es la que se trata en este breve texto, forma parte del producto final como se puede deducir de la frase de Schlossnagle.
Además, este mismo autor divide la documentación del código en dos tipos: Los comentarios que los desarrolladores escriben junto a sus líneas de código explicando cómo funciona y los documentos donde se detalla que es lo que hace nuestro código. Haciendo un símil con la documentación de un aparato electrónico, el primer tipo descrito representaría el manual de reparaciones para los empleados del soporte técnico o datasheet, y el segundo tipo coincidiría con las instrucciones de uso para el usuario.

Un ingeniero en Electrónica, con toda seguridad, es capaz de desarticular un aparato electrónico y, descifrando el modo en el que se ha diseñado que sus componentes interactúen, entender cómo consigue realizar la función para la que dicho aparato fué fabricado. A esta acción de deducir como fue fabricado un producto y qué lo hace funcionar se le llama ingeniería inversa, y es un proceso difícil y muy laborioso. Nuestro ingeniero también sería capaz de realizar modificaciones en el artilugio para mejorarlo o personalizarlo según nuestras necesidades, pero si le facilitamos un datasheet, una documentación técnica, el tiempo que necesitará para hacerlo disminuiría obstensiblemente.

Si en nuestros desarrollos de software nos aseguramos de que todo el equipo gestiona el primer tipo de documentación de código que mencionábamos, a saber, la documentación técnica sobre cómo funciona, vamos a obtener beneficios de rendimiento, pues las revisiones de código y la depuración de errores se realizarán de un modo ágil. Estos comentarios dentro del mismo código son equiparables al mencionado datasheet de un producto electrónico, y nos ayudarán a recordar rápidamente el modo en el que habíamos ideado un código antiguo si necesitamos ojearlo más tarde para hacer mejoras en él. Definitivamente, facilita la compresión del código sin necesidad de hacer una durísima ingeniería inversa, independientemente de que el código fuera escrito por nosotros o por otro desarrollador.

Para ejecutar un desarrollo de sofware de calidad, especialmente cuando lo queremos dotar de una API externa, también es indispensable una documentación donde se pueda acceder a la información sobre qué trabajo realiza cada elemento, y sobre qué es lo que necesita para realizarlo; es decir, necesitamos poder comprender el uso y el funcionamiento de los componentes programados sin necesidad de ojear su código fuente. Gestionar la documentación API, el manual de instrucciones de uso, es también una ayuda en el momento del desarrollo: en ocasiones, documentando clases de código recién escritas, he descubierto que la lógica usada no era buena, y he podido rehacer mi trabajo a tiempo para mejorarlo. El hecho de que una tecnología como Java incorpore el sistema de documentación automática JavaDoc, y que dicho sistema haya sido imitado para otros lenguajes de programación, nos muestra la importancia de esta documentación tanto para el desarrollo como para el uso de nuestro producto final.

Imaginemos ahora que adquirimos un robot aspirador automático, uno de esos aparatos que pasean solos por nuestra casa recogiendo la suciedad del suelo mientras nosotros nos podemos dedicar a cualquier otra tarea. Seguro que el pequeño barrendero electrónico dispone de una gran cantidad de parámetros para poder configurar la tarea de limpieza: programar la hora de inicio, la intensidad, la eficiencia, la hora de apagado, etcétera. ¿Cuál sería tu impresión si, al sacarlo de su caja nuevecito y listo para estrenar, no pudieras localizar en el aparato ningún botón o interruptor y comprobaras, además, que no dispone de manual de instrucciones? Recibir un producto software con una API externa sin documentar es algo muy parecido a que te regalen un enorme puck de hockey con la promesa de que limpiará tu hogar.

Tabular blandito

Pues eso, que me gusta tabular blandito. Seguro que coincides conmigo en que sangrar el código, es decir, comenzar ciertos renglones más a la derecha que otros, es un modo más que efectivo de organizar y facilitar su lectura. Tanto es así, que esta técnica forma parte de la sintaxis del lenguaje de programación Phyton.

La tecla tabulador de las antiguas máquinas de escribir, al ser pulsada, introducía automáticamente una cantidad determinada de espacios. Actualmente, con el uso de las computadoras, en prácticamente todos los editores de texto podemos elegir entre tabular duro o blando. La primera opción imita el funcionamiento de las antiguas máquinas de escribir: introducir una cantidad determinada de espacios. Esto quiere decir que tabular en cuatro caracteres es lo mismo que pulsar la barra de espacio cuatro veces. En el segundo caso, con la tabulación dura, el espacio sangrado funciona como un bloque indivisible de cuatro espacios. Aunque visualmente nos van a resultar idénticos voy a mostrate a continuación que no lo son y, por este motivo, la elección del tipo de tabulación es importante en los desarrollos de software.

Un código sangrado con tabulación dura dispone de la ventaja de poder ser leído de un modo más flexible. Aunque originalmente fuera escrito con tabulaciones de hasta cuatro caracteres de longitud, si prefieres que tengan el tamaño de ocho, pues lo ajustas en la configuración de tu editor de texto y listo. Será el propio editor quien se encargue de convertir todas las tabulaciones duras para que se vean con una longitud de ocho caracteres. Las tabulaciones blandas, como realmente son espacios, pues no se verán afectadas.

¿Qué por qué me gusta tabular blandito? Pues porque en los desarrollos de software se combina habitualmente tabulaciones y espacios, y mediante la tabulación blanda, el look and feel del código permanece inalterado independientemente del editor usado por cada desarrollador y sus preferencias.

¿Cual es el problema que estoy resolviendo?

Durante el proceso de diseño de una arquitectura software, la principal pregunta que necesitas hacerte es la misma que titula este texto: ¿Cual es el problema que estoy resolviendo?. Esta afirmación tan sencilla es realmente poderosa, y no imaginas la cantidad de ocasiones que se obvia, causando estancamientos posteriores en nuestros desarrollos.

Un buen modo de evitarlo es dividiendo el problema en cuatro atributos principales:
  1. La forma. Define el problema, su entorno y su desencadenante. Es importante que definas igualmente, conjuntamente con tu cliente, que es lo que determinará que el problema está resuelto.
  2. Las soluciones. Describe todas las soluciones propuestas para el problema, y como se ajustan al entorno descrito anteriormente, las tecnologías disponibles, etcétera.
  3. El coste. No te estanques en el coste económico o la cantidad de tiempo necesario para extinguir el problema. Una solución puede comprometer, por ejemplo, la escalabilidad de tu software, y este coste debe ser tenido en cuenta junto a los demás en el momento de decantarse por una de las posibles soluciones.
  4. Tiempo. No me refiero aquí al tiempo que tardarás en implementar la solución elegida, esto ya lo hemos sopesado en el punto anterior. Define como podría cambiar el problema en el futuro. Te aseguro que hacer esto trae a flote aspectos que, muy posiblemente, no se han tenido anteriormente en cuenta, y esto sin duda te ayudará a mejorar tu solución.

Código andamio

Te presento una técnica bastante extendida entre los programadores anglosajones de lenguaje C, y que se podría traducir como código andamio. Consiste en definir, mediante una directiva del preprocesador, una constante durante el código fuente. En el caso que nos ocupa se le suele nombrar DEBUG y el valor puede ser, por ejemplo, 1.

#define DEBUG 1


A partir de ahora, puedes crear tus propios puntos de testeo del siguiente modo.


#ifdef DEBUG
  print("valor_de_variable_testeada= ");
  print(variable_testeada);
#endif

 

 Puedes usar la siguiente directiva para desactivar los condicionales anteriores en aquellas partes del código que ya estén testeadas y corregidas.

#undef DEBUG


 Y, por último, una vez testeado y corregido todo el código, pues quitamos el andamio. Es decir, eliminamos #define DEBUG 1 y en los archivos objeto no quedará ni rastro.

Interruptores hardware en Arduino

 Piensa en tu placa Arduino ejecutando alegremente y ad libitum el bloque Loop que le ordenaste. En un momento dado necesitas que lo deje todo y realice una acción concreta. Por ejemplo, un láser que al ser interrumpido activa una alarma. Bien, pues para conseguir esto disponemos de un tipo de función avanzada que se llama ISP (Rutina de interrupción de servicio).

Vayamos por partes. Lo primero que necesitamos es adjuntar un interruptor a nuestro código. Para ello usamos la función attachInterrupt(interruptor, función, modo). En arduino Uno podemos usar los pines 2 y 3 para conectar el hardware que ordenará la ejecución de nuestra ISP. En el primer parámetro esta función, el parámetro interruptor, debemos aclarar de que interruptor estamos hablando, por tanto escribe 0 si tu láser está conectado en el pin 2, o escribe 1 si lo está en el pin 3.
 El parámetro función espera que le indiquemos la función que debe ejecutarse cuando el interruptor hardware (nuestro laser) así lo indique. Para nuestro ejemplo habremos preparado la función activar_alarma(), la cual habremos definido en otro momento.
Vamos con el parámetro modo. Podemos elegir que activar_alarma() se ejecute mientras no recibimos señal en nuestro pin (LOW), cuando la señal cambie de bajo a alto (RISING), cuando cambie en el sentido contrario (FALLING), o simplemente cuando cambie, independientemente de la dirección (CHANGE). Visto todo esto, nos queda así la función: 

 attachInterrupt(0, activar_alarma (), RISING);

 Si más adelante en tu código necesitas desactivar este interruptor de servicio, puedes usar la función detachInterrupt(interruptor), que sólo necesita como parámetro el pin donde está conectado nuestro interruptor hardware. En nuestro caso quedaría así:

 detachInterrupt(0);

 ¡y alarma desactivada!

Función constrain() para arduino

 Cuando recibimos los diferentes niveles de intensidad eléctrica de un sensor en uno de nuestros pines analógicos, el Analogic to digital converter (modificador de analógico a digital) de nuestro microcontrolador transforma esa intensidad en un dato digital almacenado en 10 bits. Por tanto, tenemos una escala de valores posibles desde 0 hasta 1023, donde 0 equivale a 0 voltios y 1023 equivale a 5 voltios (o el valor máximo establecido con la función  analogReference()).

 Al igual que tu paleta de pádel, los sensores suelen disponer de un punto dulce. Imagina un sensor de temperatura que nunca baja de una lectura de 20, haga el frio que haga, y que cuando se encuentra en el infierno no pasa casi nunca del valor 900. Ahí es donde nos interesa asegurarnos de que todos los valores obtenidos estarán en el punto dulce de nuestro sensor, y para ello usaremos una línea de código como la que sigue:

 constrain(valor_del_sensor, 20, 900);

 Con esta función nos aseguraremos de que todos los valores devueltos por el sensor estarán dentro de ese rango, pues una lectura ocasional de 18 quedará en 20 y una lectura ocasional de 901 quedará en 900. Es muy útil para, más tarde, mapear los valores de nuestro sensor a un pin digital y mostrarlos a través de, por ejemplo, una  pantalla LCD.

Usando la etiqueta de enlace como botón

Al usar una etiqueta para crear un enlace en HTML y hacerlo funcionar como un botón, serás capaz de observar que el área donde el usuario puede cliquear coincide con la altura y ancho del texto del enlace. Esto se debe a que esta etiqueta se visualiza en línea de forma predeterminada, pero es posible modificarla para darle un diseño más atractivo de cara al usuario cambiando el tipo de visualización, en el código CSS del enlace, al tipo bloque:

a {display: block}

A menos que especifiques un ancho específico con la propiedad width, la transformación del enlace en un elemento de tipo bloque hace que éste abarque todo el ancho del elemento en el que se encuentra contenido. Esta modificación lo hace idóneo para los enlaces ubicados en una barra lateral o para los enlaces de un menú desplegable.

Para terminar, como la conversión que hemos hecho al enlace sólo afecta a su comportamiento y su ancho, termina añadiendo un buen relleno con la propiedad padding. Haciendo esto consigues que la altura del botón sea más adecuada a su contenido y el elemento respirará, es decir, no dará una sensación claustrofóbica respecto al texto visible en su interior.

Realiza pruebas y combina estas ideas, seguro que te ayudarán a encontrar un estilo propio. Yo te añado aquí abajo una idea para que veas como puedes mejorar fácilmente el aspecto de este elemento.

<html>
    <head>
    </head>
    <body>
        <a href="./">Para pulsar</a>
        <br/><br/>
        <a style="color: white; display: block; padding: 6px; width: 70px;
        border: 1px solid black; box-shadow: 3px 3px 1px #888888;
        text-decoration:none; background-color: #088;" href="./">Para pulsar
        </a>
    </body>
</html>