Sé liberal en lo que aceptas ... ¿o no?

45

[Descargo de responsabilidad: esta pregunta es subjetiva, pero preferiría obtener respuestas respaldadas por hechos y / o reflexiones]

Creo que todos conocen el Principio de Robustez , generalmente resumido por la Ley de Postel:

Sea conservador en lo que envía; sé liberal en lo que aceptas.

Estoy de acuerdo en que para el diseño de un protocolo de comunicación generalizado esto puede tener sentido (con el objetivo de permitir una extensión fácil), sin embargo, siempre he pensado que su aplicación a HTML / CSS fue un fracaso total, cada navegador implementa su propio ajuste silencioso detección / comportamiento, por lo que es casi imposible obtener una representación coherente en varios navegadores.

Sin embargo, me doy cuenta de que allí el RFC del protocolo TCP considera aceptable la "falla silenciosa" a menos que se especifique lo contrario ... lo cual es un comportamiento interesante, por decir lo menos.

Hay otros ejemplos de la aplicación de este principio en todo el comercio de software que aparecen regularmente porque han mordido a los desarrolladores, desde lo más alto de mi cabeza:

  • Inserción de punto y coma de Javascript
  • Conversiones incorporadas C (silenciosas) (que no serían tan malas si no se truncaran ...)

y hay herramientas para ayudar a implementar el comportamiento "inteligente":

Sin embargo, encuentro que este enfoque, aunque puede ser útil cuando se trata con usuarios no técnicos o para ayudar a los usuarios en el proceso de recuperación de errores, tiene algunos inconvenientes cuando se aplica al diseño de la interfaz de biblioteca / clases:

  • es algo subjetivo si el algoritmo adivina "correcto", y por lo tanto puede ir en contra del Principio de Menos Asombro
  • hace que la implementación sea más difícil, por lo tanto, más posibilidades de introducir errores (¿violación de YAGNI ?)
  • hace que el comportamiento sea más susceptible a cambios, ya que cualquier modificación de la rutina "adivinar" puede romper los programas antiguos, casi excluyendo las posibilidades de refactorización ... ¡desde el principio!

Y esto es lo que me llevó a la siguiente pregunta:

Al diseñar una interfaz (biblioteca, clase, mensaje), ¿se inclina hacia el principio de robustez o no?

Yo mismo tiendo a ser bastante estricto, usando una extensa validación de entrada en mis interfaces, y me preguntaba si quizás era demasiado estricto.

Matthieu M.
fuente
Me pregunto cuál es la diferencia entre HTML y datos generales. El principio de robustez se trata de la comunicación. Uno escribe, uno lee. ¿Por qué la comunicación de red es diferente a la visual o API? Tengo un ejemplo de API donde el principio de ser liberal en lo que aceptamos simplifica la vida de los usuarios que son programadores , reduce el tamaño del código y, por lo tanto, mejora el rendimiento + elimina los errores. Mire stackoverflow.com/questions/18576849
Val
@Val: en realidad, su ejemplo no coincide. "ser liberal en lo que acepta" no es solo una cuestión de base / derivada, va más allá de eso y también acepta (e interpreta) entradas ligeramente erróneas.
Matthieu M.
¿Cómo mostrar un caso no muestra ese caso?
Val

Respuestas:

34

Diría robustez cuando no introduce ambigüedades .

Por ejemplo: al analizar una lista separada por comas, si hay un espacio antes / después de la coma no cambia el significado semántico.

Al analizar un guid de cadena, debe aceptar cualquier número de formatos comunes (con o sin guiones, con o sin llaves).

La mayoría de los lenguajes de programación son robustos con el uso de espacios en blanco. Específicamente en todas partes que no afecta el significado del código. Incluso en Python, donde el espacio en blanco es relevante, sigue siendo flexible cuando estás dentro de una lista o declaración de diccionario.

Definitivamente estoy de acuerdo en que si algo se puede interpretar de varias maneras o si no está 100% claro lo que significaba, entonces demasiada robustez puede terminar siendo un dolor, pero hay mucho espacio para la robustez sin ser ambiguo.

Davy8
fuente
1
Estoy de acuerdo, la robustez cuando no cuesta mucho vale la pena.
Matthieu M.
2
Incluso la lista separada por comas causa problemas, algo así como: el motor javascript de Chrome y Firefox parece aceptar {"key": "value",}como válido, IE no. A menudo me topé con este problema en particular hasta que mejoré mi proceso de compilación con JSlint.
keppla
2
@keppla es un problema con la implementación en lugar del diseño. No estoy seguro de si eso es legal según las especificaciones de JavaScript e IE no lo sigue, o si esa es una "buena característica" que FF y Chrome agregaron, pero en Python se especifica que es válida e implementada como tal. Si se especifica como válido y no funciona, entonces es una implementación defectuosa. Si no se especifica, entonces no debería confiarse en él (aunque, por razones prácticas, si no funciona en un navegador importante, también podría considerarse que no está en la especificación si no controla al usuario)
Davy8
77
@ Davy8: la coma final parece ser ilegal ( stackoverflow.com/questions/5139205/… ). No quiero confiar en esto, mi punto es que cuando suficientes personas aceptan la entrada, se convierte en un estándar de facto (porque uno no nota que es un error), lo que lleva a algo que encontramos en HTML: que los errores se vuelve tan común que ya no puedes ignorarlos como una mala entrada.
keppla
1
@keppla, eso debería estar fallando en moz y Chrome. Como principalmente desarrollador de JS, me molesta que no lo haga (solía hacerlo en Moz al menos). Hace que la depuración sea más difícil, no más fácil. IE está haciendo lo que se supone que debe hacer. Fail @ bad code. HTML es una cosa. No necesitamos esta basura en un lenguaje de script. Es un ejemplo de aplicación horrible del principio Robusto, que es algo en lo que se destacan los proveedores de navegadores.
Erik Reppen
15

Definitivamente no. Las técnicas como la programación defensiva ocultan los errores, lo que hace que su apariencia sea menos probable y más aleatoria, lo que dificulta su detección, lo que hace que aislarlos sea más difícil.

El código sólido de escritura, ampliamente subestimado, fue tremendo al enfatizar repetidamente la necesidad y las técnicas de hacer que los errores sean tan difíciles de introducir u ocultar. Mediante la aplicación de sus principios como "Eliminar el comportamiento aleatorio. Forzar errores para que sean reproducibles". y, "Siempre busque y elimine defectos en sus interfaces". los desarrolladores mejorarán enormemente la calidad de su software al eliminar la ambigüedad y los efectos secundarios no controlados que son responsables de una gran cantidad de errores.

Huperniketes
fuente
9

La aplicación excesiva de robustez te lleva a adivinar lo que el usuario quería, lo cual está bien hasta que te equivocas. También requiere la fe completamente equivocada de que sus clientes no abusarán de su confianza y crearán galimatías aleatorias que simplemente funcionan, pero que no podrá soportar en la versión 2.

La aplicación excesiva de la corrección hace que usted niegue a sus clientes el derecho a cometer errores menores, lo cual está bien hasta que se quejan de que sus cosas funcionan bien en el producto de su competencia y le dicen qué puede hacer con su estándar de 5,000 páginas que tiene la palabra "BORRADOR" todavía garabateado en la portada en crayón, y al menos 3 expertos afirman que es fundamentalmente defectuoso, y 200 expertos más honestos dicen que no entienden completamente.

Mi solución personal siempre ha sido la depreciación. Los apoyas, pero les dices que lo están haciendo mal y (si es posible) el camino más fácil hacia la corrección. De esa manera, cuando apaga la función de error 10 años más adelante, al menos tiene el rastro de papel para afirmar que "le advertimos que esto podría suceder".

deworde
fuente
+1 por desaprobación , de hecho es un concepto importante y me sorprende que se haya pasado por alto hasta ahora.
Matthieu M.
9

Lamentablemente, el llamado "principio de robustez" no conduce a la robustez. Toma HTML como ejemplo. Se podrían haber evitado muchos problemas, lágrimas, pérdida de tiempo y energía si los navegadores hubieran analizado estrictamente HTML desde el principio en lugar de tratar de adivinar el significado del contenido con formato incorrecto.

El navegador simplemente debería haber mostrado un mensaje de error en lugar de intentar arreglarlo debajo de las cubiertas. Eso habría obligado a todos los bunglers a arreglar su desastre.

ThomasX
fuente
Citando a mí mismo (debe estar envejeciendo): "sin embargo, siempre he pensado que su aplicación a HTML / CSS fue un fracaso total"
Matthieu M.
3
Es cierto, pero la misma tolerancia a fallas también ayudó a que la web fuera tan popular.
Marzo
Los vendedores del navegador fallaron en ese. Con doctypes teníamos la capacidad de hacer nuestra propia elección en este sentido, pero al final de su día, todo terminó comportándose de la misma manera, siempre y cuando haya declarado cualquier doctype. ¿Ahora piensan que la solución es un conjunto hiper-complejo de reglas exigentes a seguir con respecto a cómo lidiar con el fracaso? Creo que no logran identificar el problema.
Erik Reppen el
Usted está diciendo que la falla rápida, que es opuesta a "robusta", es más eficiente.
Val
@MaR: ¿Es así? Muy discutible, mucho más probable que las características fueran importantes.
Deduplicador el
6

Divido las interfaces en varios grupos (agregue más si lo desea):

  1. los que están bajo su control deben ser estrictos (clases típicamente)
  2. API de biblioteca, que también deberían ser estrictas, pero se recomienda una validación adicional
  3. interfaces públicas que deben manejar todo tipo de abuso que entra (típicamente protocolos, entradas de usuarios, etc.). Aquí la solidez de la entrada realmente vale la pena, no puede esperar que todos arreglen sus cosas. Y recuerde para el usuario que será culpa suya si la aplicación no funciona, no la parte que envió una basura mal formateada.

La salida siempre debe ser estricta.

Mar
fuente
5

Creo que HTML y la World Wide Web han proporcionado una prueba a gran escala del Principio de Robustez en el mundo real y han demostrado que es un fracaso masivo. Es directamente responsable del desorden confuso de los casi estándares HTML competitivos que hacen la vida miserable para los desarrolladores web (y sus usuarios) y empeora con cada nueva versión de Internet Explorer.

Hemos sabido desde la década de 1950 cómo validar el código correctamente. Ejecútelo a través de un analizador estricto y si algo no es sintácticamente correcto, arroje un error y cancele. No pase, no recolecte $ 200, y por amor a todo lo que es binario, ¡no permita que algún programa de computadora intente leer la mente del codificador si cometió un error!

HTML y JavaScript nos han mostrado exactamente qué sucede cuando se ignoran esos principios. El mejor curso de acción es aprender de sus errores y no repetirlos.

Mason Wheeler
fuente
44
@ChaosPandion: creo que el problema no radica en Internet Explorer en sí, sino en todas las páginas web no estándar que fueron aceptadas por versiones anteriores y con las que ahora todos tienen que vivir ... e intentar acomodarse con más o menos éxito.
Matthieu M.
55
De hecho, creo que el equipo de IE está en la peor posición posible de todos los desarrolladores de navegadores. Joel resume mis pensamientos muy bien .
Dean Harding
3
Puede que haya hecho la vida miserable para los desarrolladores y diseñadores, pero entonces estaríamos atrapados con un estándar estático y de evolución muy lenta. Dudo que la web sea como ahora. Los verdaderos ganadores han sido las personas que navegan por la web y al final del día son las personas que cuentan.
FinnNk
44
Además, si bien el principio de robustez puede dificultarles la vida a los desarrolladores web, es difícil llamar a la World Wide Web (ahora una parte integral de casi todas las principales instituciones del planeta) una falla masiva .
deworde
3
"Hemos sabido desde la década de 1950 cómo validar el código correctamente. Ejecútelo a través de un analizador estricto y, si algo no es sintácticamente correcto, arroje un error y cancele". Para aplicar esto a un escenario del mundo real: si he estropeado un solo ícono en el extremo derecho de mi página, justo debajo del corte, renunciar en toda la página es una muy buena manera de enviar a alguien a otro lado, debido problema que ni siquiera habrían notado. Sí, puedes argumentar que no debería haber cometido el error. Pero eso presupone que aún no he acudido a su competidor más robusto y ya no atiendo sus llamadas.
deworde
3

Como contrapunto al ejemplo de Mason, mi experiencia con el Protocolo de inicio de sesión fue que, si bien las diferentes pilas interpretarían los RFC relevantes de manera diferente (y sospecho que esto sucede con cada estándar jamás escrito), ser (moderadamente) liberal en lo que acepta significa que usted en realidad puede hacer llamadas entre dos dispositivos. Debido a que estos dispositivos son elementos físicos habituales en lugar de piezas de software en una computadora de escritorio, simplemente debe ser liberal en lo que acepta, o su teléfono no puede llamar a otro teléfono de una marca en particular. ¡Eso no hace que su teléfono se vea bien!

Pero si está escribiendo una biblioteca, probablemente no tenga el problema de que varias partes interpreten un estándar común de maneras mutuamente incompatibles. En ese caso, diría que sea estricto en lo que acepta, porque elimina las ambigüedades.

The Jargon File también tiene una historia de terror sobre "adivinar" la intención de un usuario.

Frank Shearar
fuente
Historia muy divertida :) Me doy cuenta de que es posible que necesites más libertad cuando intentas interactuar con los sistemas existentes, ya que si no funciona, te culparán.
Matthieu M.
De hecho, si su teléfono no funciona con la mayoría de los otros teléfonos, su teléfono es malo .
SamB
1
@SamB: Reemplazar mal por roto .
deworde
3

Tienes razón, la regla se aplica a los protocolos y no a la programación. Si comete un error tipográfico mientras programa, recibirá un error tan pronto como compile (o ejecute, si es uno de esos tipos dinámicos). No se gana nada dejando que la computadora adivine por usted. A diferencia de la gente común, somos ingenieros y somos capaces de decir exactamente lo que quiero decir. ;)

Entonces, al diseñar una API, yo diría que no sigas el Principio de Robustez. Si el desarrollador comete un error, debe averiguarlo de inmediato. Por supuesto, si su API utiliza datos de una fuente externa, como un archivo, debe ser indulgente. El usuario de su biblioteca debe conocer sus propios errores, pero no los de nadie más.

Por otro lado, supongo que se permite una "falla silenciosa" en el protocolo TCP porque de lo contrario, si las personas le arrojaran paquetes malformados, sería bombardeado con mensajes de error. Eso es simple protección DoS allí mismo.

Nota para uno mismo - piense en un nombre
fuente
1
"Si comete un error tipográfico mientras programa, recibirá un error tan pronto como compile". Le presento los millones de ADVERTENCIAS del compilador que escupirá un compilador estándar, mientras produce tareas perfectamente ejecutables.
deworde
1

En mi opinión, la robustez es un lado de una compensación de diseño, no un principio de "preferencia". Como muchos han señalado, nada apesta como pasar cuatro horas tratando de averiguar dónde se equivocó su JS solo para descubrir que el verdadero problema era que solo un navegador hizo lo correcto con XHTML Strict. Dejó que la página se hiciera pedazos cuando una parte del HTML servido fue un completo desastre.

Por otro lado, ¿quién quiere buscar documentación para un método que toma 20 argumentos e insiste en que estén exactamente en el mismo orden con marcadores de posición de valor vacío o nulo para los que desea omitir? La manera igualmente horrible y robusta de lidiar con ese método sería verificar cada argumento y tratar de adivinar cuál era en función de las posiciones y tipos relativos y luego fallar en silencio o tratar de "compensar" con argumentos sin sentido.

O puede incorporar flexibilidad en el proceso al pasar una lista de pares de objeto / diccionario / clave-valor de objeto y manejar la existencia de cada argumento a medida que llega a él. Para la muy pequeña compensación de rendimiento, eso es un pastel y comérselo también.

La sobrecarga de argumentos de manera inteligente y coherente con la interfaz es una forma inteligente de ser robusto sobre las cosas. Entonces, la redundancia se está convirtiendo en un sistema en el que se supone que la entrega de paquetes no se entregará regularmente en una red enormemente complicada, propiedad y administrada por todos en un campo emergente de tecnología con una amplia variedad de posibles medios de transmisión.

Sin embargo, tolerar el fracaso absoluto, especialmente dentro de un sistema que controlas, nunca es una buena compensación. Por ejemplo, tuve que tomar un respiro para evitar lanzar un ataque de silbido en otra pregunta sobre cómo colocar JS en la parte superior o inferior de la página. Varias personas insistieron en que era mejor poner a JS en la parte superior porque si la página no se cargaba por completo, aún podría tener alguna funcionalidad. Las páginas de medio trabajo son peores que los bustos completos. En el mejor de los casos, generan más visitantes a su sitio con la suposición correcta de que usted es incompetente antes de que se entere que si la página rota simplemente se devuelve a una página de error al fallar su propia verificación de validación seguida de un correo electrónico automatizado para alguien que pueda hacer algo al respecto.

Intentar ofrecer la funcionalidad de 2010 en un navegador de 1999 cuando podría entregar una página de tecnología más baja es otro ejemplo de un compromiso de diseño imprudente. Las oportunidades desperdiciadas y el dinero que he visto desperdiciado en el tiempo de los desarrolladores dedicados a soluciones temporales llenas de errores solo para obtener esquinas redondeadas en un elemento que se cierne sobre un fondo degradado! @ # $ Ing, por ejemplo, me han impresionado por completo. ¿Y para qué? Para entregar páginas de alta tecnología que tengan un rendimiento deficiente a tecnófobos probados mientras limitan sus opciones en navegadores de gama alta.

Para que sea la elección correcta, la elección de manejar la entrada de manera robusta siempre debería facilitar la vida en ambos lados del problema, en el corto y largo plazo de la OMI.

Erik Reppen
fuente
44
"para un método que requiere 20 argumentos"> no es necesario buscar más, después de 5/6 el método es incorrecto . Gracias por la respuesta aunque :)
Matthieu M.
1

Nunca falles en silencio . Aparte de eso, tratar de adivinar lo que quería el usuario de una API / biblioteca, no parece una mala idea. Sin embargo, no lo seguiría; Tener un requisito estricto, puede exponer errores en el código de llamada y / o malas interpretaciones sobre su API / biblioteca.

Además, como ya se ha señalado, depende de lo difícil que sea adivinar lo que el usuario esperaba. Si es muy fácil, entonces tienes dos casos:

  1. Su biblioteca debe estar diseñada de manera un poco diferente (cambie el nombre de alguna función o divídala en dos), para que el usuario pueda esperar lo que realmente proporciona.
  2. Si cree que su biblioteca está diseñada correctamente, lo que significa un nombre claro / directo, puede intentar inferir lo que el usuario pretendía.

En cualquier caso, no es 100% obvio y determinista, que una entrada se convierta en otra, no debe hacer las conversiones, por una serie de razones ya mencionadas (romper la compatibilidad en la refactorización, menos asombro de los usuarios).

Al tratar con un usuario final, tratar de corregir su entrada / suposición es muy bienvenido. Se espera que ingrese información no válida; Este caso es completamente excepcional. Sin embargo, otro desarrollador no es un simple usuario no técnico. Tiene la experiencia para comprender un error, y el error puede tener importancia / ser beneficioso para él. Por lo tanto, estoy de acuerdo con usted en el diseño de API estrictas, mientras que, por supuesto, la rigurosidad va acompañada de claridad y simplicidad.

Le recomendaría que lea esta pregunta mía , de un caso similar.

K. Gkinis
fuente