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
Opinión de Hacker News
Opinión sobre "tragarse los errores":
panicde Go es una buena forma de señalar con fuerza los errores del programador durante las pruebas.Opinión sobre la retrocompatibilidad:
Queja sobre el diseño de UI:
Señalamiento sobre la falta de aprendizaje de Microsoft:
Opinión sobre la falta de soporte de impresión en Xbox:
Consejo sobre el uso de API:
NotSupportedException.Sentimiento sobre la "obediencia maliciosa":
Opinión positiva sobre seguridad:
Reflexión sobre la estrategia de los navegadores:
Lo que los críticos malinterpretan sobre el manejo de excepciones:
Opiniones en Lobste.rs
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
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
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
Uno ya no sabe si la función desapareció o si quedó escondida en otra pantalla mientras tanto
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”
ifpara comprobar si algo es null. Cada vez que lo veo me acuerdo de este textoAsí 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