2 puntos por GN⁺ 2024-02-17 | 2 comentarios | Compartir por WhatsApp

Cuando una API no hace nada, hacerlo correctamente

  • Cuando una API no debe hacer nada, es importante que ese nada ocurra de la manera correcta.
  • Por ejemplo, Windows tiene una enorme infraestructura de impresión, pero Xbox no cuenta con una infraestructura así.
  • Cuando una app intenta imprimir en Xbox, lanzar una NotSupportedException es la forma incorrecta de manejarlo.
  • Como la app probablemente se probó sobre todo en PC, puede que no tenga manejo de excepciones al ejecutarse en Xbox y termine fallando.
  • Un mejor diseño para "soportar" la impresión en Xbox es que la función de impresión tenga éxito, pero informe que no hay impresoras instaladas.
  • Cuando el usuario intenta imprimir, se le pide elegir una impresora, pero la lista está vacía, así que entiende que "no hay impresoras" y cancela la solicitud de impresión.
  • Para las apps que intentan instalar una impresora, la función de instalación puede devolver de inmediato un código de resultado que indique "el usuario canceló la operación".
  • El objetivo es comportarse como si la función de impresión estuviera totalmente soportada, pero en realidad actuar como si simplemente no hubiera impresoras.
  • En sistemas donde la impresión no funciona en absoluto, se puede agregar una función para comprobar si se puede imprimir y así ocultar el botón de impresión en la UI.
  • A este comportamiento se le llama "inerte".
  • La superficie de la API sigue existiendo y sigue funcionando según la especificación, pero en la práctica no hace nada.
  • Lo importante es no hacer nada de una forma coherente con lo documentado, minimizando los problemas con el código existente.

Ejemplo de desactivación de una API

  • Hay un ejemplo de cómo desactivar una API que incluye varias funciones para crear handles de widget, funciones que reciben handles de widget y funciones para cerrar esos handles.
  • El equipo propuso inicialmente desactivar la API haciendo que CreateWidget tuviera éxito pero devolviera un puntero nulo.
  • Sin embargo, ese enfoque puede confundir a las apps: "¿la llamada fue exitosa pero no recibí un handle válido?"
  • También puede generar confusión que EnableWidget devuelva "handle no válido".
  • En la documentación existente encontraron un valor de retorno llamado ERROR_CANCELLED, que significa que la creación del widget fue cancelada por el usuario.
  • Así que, cada vez que una app intente crear un widget, es posible responder: "No, el usuario lo canceló".

La opinión de GN⁺

  • Lo más importante de este artículo es que, cuando una API no hace nada, debe hacerlo de una forma que no dañe la experiencia del usuario y que mantenga la compatibilidad con el código existente.
  • Este enfoque destaca para los desarrolladores la importancia del diseño de APIs y contribuye a ofrecer una experiencia de software amigable para el usuario.
  • El artículo muestra un aspecto minucioso de la ingeniería de software y ofrece un caso interesante sobre cómo una app puede fallar con elegancia incluso en entornos inesperados.

2 comentarios

 
GN⁺ 2024-02-17
Opinión de Hacker News
  • Opinión sobre "tragarse los errores":

    • Ocultar los errores es una mala práctica.
    • Dificulta más encontrar bugs y hacer pruebas al ocultar fallas del software en lugar de resolver el problema.
    • El panic de Go es una buena forma de señalar con fuerza los errores del programador durante las pruebas.
    • Si los actores dentro del sistema intentan ocultar sus propias fallas, se vuelve mucho más difícil identificar y resolver el problema.
  • Opinión sobre la retrocompatibilidad:

    • La retrocompatibilidad siempre es un trabajo desordenado, y la elección es entre hacer algo imperfecto o no hacerlo en absoluto.
    • Por eso, si haces clic en un archivo de Word '97 o en un juego para MS-DOS, todavía se abre como esperas en una computadora actual.
  • Queja sobre el diseño de UI:

    • Una UI que sugiere dispositivos que podrían existir es extremadamente frustrante.
    • Hace que pierdas tiempo descubriendo dispositivos que en realidad no son compatibles.
  • Señalamiento sobre la falta de aprendizaje de Microsoft:

    • Microsoft sigue repitiendo los mismos errores incluso después de 30 años.
    • Mostrar una lista vacía cuando una app intenta encontrar una impresora es repetir problemas del pasado.
  • Opinión sobre la falta de soporte de impresión en Xbox:

    • Xbox no soporta impresión porque Microsoft lo definió así.
    • A nivel de hardware, tiene la misma capacidad de impresión que otros dispositivos Windows.
    • Esta "solución" es un problema causado por una decisión irracional de Microsoft.
  • Consejo sobre el uso de API:

    • Es cierto que el componente debería enfrentar el problema antes que el usuario, pero no se puede estar de acuerdo con la forma en que lo expresa el autor.
    • No está mal que una función de impresión lance NotSupported­Exception.
    • Lo que describe el autor es un hack para dar soporte a clientes defectuosos.
  • Sentimiento sobre la "obediencia maliciosa":

    • Les gusta y no les gusta la manera en que se aborda el problema.
    • Pero si el objetivo es permitir que más usuarios ejecuten más software en la plataforma, este método es bueno.
  • Opinión positiva sobre seguridad:

    • Ignorar correctamente una llamada de API evita que el programa realice comportamientos más dañinos.
  • Reflexión sobre la estrategia de los navegadores:

    • La estrategia de intentar mostrar una página lo mejor posible aunque haya errores en el código HTML alguna vez se consideró una buena estrategia.
    • Los usuarios no quieren errores, y se debió haber aprendido de esa experiencia.
  • Lo que los críticos malinterpretan sobre el manejo de excepciones:

    • Hay un punto que los críticos están pasando por alto en situaciones donde no hace falta lanzar excepciones.
    • Si el dispositivo (la impresora) no está conectado, la app debería manejar esa situación limpiamente y no debería fallar.
 
GN⁺ 4 일 전
Opiniones en Lobste.rs
  • Lo que se dice aquí es que las funciones de impresión se comportan de forma consistente como si la impresión estuviera totalmente soportada, pero curiosamente nunca habrá una impresora real para imprimir, y eso explica muchas cosas
    Bromas aparte, no estoy de acuerdo con este tipo de programación excesivamente defensiva ni con esa experiencia de usuario. Así, el software deja de cumplir su función sin que nadie sepa por qué, y además no hay forma de averiguarlo. La app debería capturar el error y, si es posible, mostrar un mensaje amigable para el usuario, o al menos enseñarle el mensaje de error original. Si es una tarea en segundo plano, debería haber un registro de errores
    Admito que este texto está escrito desde la perspectiva de un desarrollador de API, no de un desarrollador de aplicaciones. Así que hay que documentar los errores de la API y ofrecer mensajes de error sobre los que quien la invoca pueda actuar
    Tampoco me gusta que se oculten botones en la UI solo porque no se tienen permisos de acceso. Si el espacio lo permite, me parece mejor mostrar el botón pero desactivado, y cuando el usuario pase el mouse por encima, mostrar un mensaje que explique cómo puede habilitarlo
    • También hay que considerar que este texto no está escrito desde la perspectiva de un simple desarrollador de API, sino de un desarrollador de la API de Windows. La postura histórica de Microsoft es que la API de Windows no debe romper compatibilidad aunque cambie la versión
    • Esta es una discusión típica sobre la ley de Postel / principio de robustez. A estas alturas todos sabemos que el principio de robustez ya envejeció mal y que dio origen a monstruos como HTML o enormes protocolos y formatos de archivo en los que es difícil escribir analizadores correctos
      En general, es mejor exigir corrección. Pero si ya tienes mil millones de usuarios existentes, es muy sensato evitar romper las cosas tanto como sea posible, y desde la perspectiva del usuario eso genera un valor real a nivel de sistema porque simplemente funciona. Al final, la actitud debería ser fallar rápido, pero no provocar fallos masivos
    • En este caso, probablemente uno de los API existentes no tiene errores documentados, así que es posible que desde el inicio no haya manejo de errores. Si no quieres romper todo el software existente, tienes que decir una mentira piadosa
      Esto se parece más a estabilidad de ABI que de API. En Windows, incluso el software compilado hace 15 años debe seguir funcionando en un sistema operativo nuevo siempre que sea posible. Como no puedes cambiar la firma de la función, si quieres que incluso una API que ya no tiene sentido siga funcionando, tienes que recurrir a mentiras piadosas
      Por ejemplo, la API todavía finge que Active Desktop existe. La alternativa sería romper en masa software heredado antiguo
    • Totalmente de acuerdo. Hay pocas cosas más frustrantes que perder tiempo buscando un botón que por alguna razón no aparece en mi pantalla, pero sí en la explicación de alguien al lado o en un tutorial
      Uno ya no sabe si la función desapareció o si quedó escondida en otra pantalla mientras tanto
    • Sí, la app debería capturar el error y mostrárselo al usuario.
      Pero si la app no lo hace, la gente que usa esa app culpa a Windows. Culpan a Windows, no a la app, e incluso pasa lo mismo cuando la app se cae
      Por eso Microsoft crea soluciones alternativas. Es mucho más fácil dejar que el trabajo de impresión simplemente desaparezca, y así el usuario se queda pensando un momento y luego lo acepta con un “ah, claro, no había impresora”
  • Si una función de instalación de impresora puede devolver el control de inmediato y retornar como código de resultado el usuario canceló la operación, desde el punto de vista del soporte de aplicaciones eso casi con certeza llevará a un comportamiento no deseado mucho más difícil de manejar que si la API de impresión lanzara una excepción desde el principio
  • Últimamente hago bastante programación asistida por IA, y veo que los agentes suelen meter con frecuencia verificaciones if para comprobar si algo es null. Cada vez que lo veo me acuerdo de este texto
    Así que les indiqué a los agentes que no repitan verificaciones de null, que usen funciones inocuas, y que validen una sola vez al momento de la declaración que el valor nunca será null