Construir software defensivo
· Matt Senter

Hace poco mi portátil se quedó sin batería y se apagó. Después de enchufarlo y reiniciarlo, Comoji dejó de funcionar. Escribía un atajo de emoji y no pasaba nada. Sin explicación, sin ninguna señal de que algo hubiera cambiado. Solo una app que funcionaba antes del apagado y que, al parecer, ya no funcionaba.
Comoji es mi pequeña app para Mac que te da autocompletado de emojis en los campos de texto que ya usas. Su trabajo es sencillo: reconocer un atajo, ofrecer los emojis que coinciden y quitarse de en medio. Cuando eso deja de ocurrir, no queda mucho producto con el que interactuar.
Salvo que Comoji en realidad no se había roto. Estaba respetando un límite de seguridad detrás del cual se había quedado atascada otra cosa en mi ordenador.
¿Por qué hacer lo correcto puede parecer no hacer nada?
macOS tiene una función llamada Secure Input (entrada segura) que protege la escritura sensible del teclado para que otros procesos no la intercepten. Eso es importante para una app como Comoji, que necesita reconocer lo que escribes para ofrecer el autocompletado. Una utilidad de emojis no tiene nada que hacer mirando cómo introduces una contraseña, así que Comoji se retira deliberadamente mientras Secure Input está activo.
En este caso, Chrome aparecía como el proceso que retenía Secure Input, aunque yo ya no estaba introduciendo ninguna contraseña. Maté Chrome esperando que eso lo arreglara. En lugar de eso, Secure Input siguió activo, y ahora estaba asociado al proceso de inicio de sesión de Apple. Fuera lo que fuera lo que se torció tras el reinicio, cerrar el navegador no había bastado para resolverlo.
Es una clase de problema que la propia Apple ha documentado. Una aplicación que deja Secure Input activado cuando ya no lo necesita puede interferir con otras aplicaciones que dependen de los eventos de teclado, incluso después de que la aplicación culpable pase a segundo plano. El mecanismo de seguridad sigue haciendo su trabajo, pero el software del resto de la máquina sufre las consecuencias.
Esa era la situación en la que estaba Comoji. Se negaba correctamente a operar mientras el sistema decía que la entrada del teclado necesitaba protección. Pero nada de eso era visible para mí. Yo había escrito la app, e incluso yo al principio solo vi que había dejado de funcionar.
Un usuario no debería tener que investigar el estado del sistema operativo para entender por qué sus atajos de emoji de repente no hacen nada.
¿Por qué «no es mi bug» no es una respuesta completa?
Es comprensible la tentación de dejar de investigar en cuanto estableces que un problema se origina fuera de tu código. Chrome retenía Secure Input. Luego estaba implicado el proceso de inicio de sesión de Apple. Comoji se comportaba exactamente como estaba previsto. Caso cerrado, ¿no?
No exactamente. Eso explica quién causó el problema, pero no ayuda a la persona que intenta usar mi app. Esa persona no está mirando quién es dueño de qué proceso ni decidiendo qué empresa merece un informe de error. Está mirando a Comoji y preguntándose por qué no funciona.
El problema de entrada subyacente estaba fuera de Comoji. La falta de una explicación era algo que yo sí podía arreglar.
Aquí es donde el desarrollo de software defensivo va más allá de comprobar argumentos inválidos y capturar excepciones. También tienes que pensar en qué aspecto tiene tu aplicación cuando el entorno que la rodea deja de comportarse correctamente. ¿Puede el usuario distinguir una pausa deliberada de un fallo? ¿Sabe qué está impidiendo que la app funcione? ¿Le has dado algún sitio útil al que acudir después?
Tener razón técnicamente sirve de poco consuelo cuando tu producto parece roto.
¿Qué cambié? Un pequeño candado en lugar de un misterio
Añadí un pequeño indicador de candado al icono de Comoji en la barra de menús siempre que Secure Input está activo. Ahora hay una razón visible para la ausencia del autocompletado: Comoji está en pausa porque la entrada del teclado está protegida. La app ya no presenta en silencio una función no disponible como si debiera estar funcionando.
También enlacé el menú de la bandeja con un artículo de ayuda que explica qué es Secure Input y por qué Comoji lo respeta. Quien se quede atascado puede llegar a esa explicación desde la propia app, en lugar de tener que adivinar los términos de búsqueda correctos o escribirme para descubrir que esta función del sistema existe.
Lo importante es lo que no intenté resolver. La respuesta no era saltarse la protección de contraseñas solo para que funcionara el autocompletado de emojis. Que Secure Input esté activo no es, en sí mismo, un error. Existe por una buena razón, y Apple advierte explícitamente de que activar la entrada segura por teclado puede afectar a otras apps que necesitan esas pulsaciones.
Por tanto, el candado comunica un estado, no una crisis. Durante la introducción normal de una contraseña, explica por qué Comoji no está disponible temporalmente. Cuando ese estado persiste de forma inesperada, le da al usuario un punto de partida para entender qué ha pasado.
No conseguí que Chrome o macOS fueran incapaces de atascarse. Hice que su atasco fuera menos confuso para quien usa Comoji, sin debilitar la protección que Comoji debía respetar.
¿Por qué las grandes empresas siguen siendo dependencias externas?
Hay algo irritante en blindar una utilidad diminuta contra problemas que involucran al navegador de Google y al sistema operativo de Apple. No son componentes oscuros que arrastré al proyecto sin pensar. Son productos de dos empresas tecnológicas enormes, y aun así su comportamiento logró que mi pequeña app pareciera defectuosa.
Pero su tamaño no cambia la decisión de ingeniería. No puedo construir Comoji sobre la suposición de que todo lo que produce una empresa más grande que la mía se comportará siempre correctamente. Tampoco puedo decirle a un usuario frustrado que el problema pertenece a una empresa suficientemente impresionante y dar mi trabajo por terminado.
No sé con qué frecuencia ocurre esta secuencia concreta. Puede que sea inusual. Pero yo la viví, y el resultado dejó al descubierto una distinción útil: Comoji ya gestionaba la condición de seguridad de forma segura; todavía no gestionaba bien la confusión resultante.
Eso no significa que cada fallo hipotético merezca un nuevo ajuste, un diálogo de advertencia o un subsistema de recuperación. En este caso, la respuesta fue pequeña y directamente relacionada con el problema. Un icono de candado hizo visible la condición. Un artículo de ayuda la hizo comprensible. Ninguno de los dos exigía fingir que podía reparar otra aplicación desde dentro de la mía.
Para mí, esa es una parte importante de construir software defensivo. Tu responsabilidad no termina en asegurarte de que tu código funciona cuando todo lo que lo rodea funciona. También tienes que decidir qué ocurre cuando no puede hacer su trabajo, incluso cuando la razón es un error de otro.
A veces el comportamiento correcto es detenerse. El buen software debería poder decirte por qué.