design - ¿El diseño por contrato funciona para usted?
design-by-contract (10)
¿Utiliza Diseño por contrato profesionalmente? ¿Es algo que tienes que hacer desde el comienzo de un proyecto, o puedes cambiar de marcha y comenzar a incorporarlo en tu ciclo de desarrollo de software? ¿Cuáles crees que son los pros / contras del enfoque de diseño?
Me encontré con el enfoque de Diseño por contrato en un curso de posgrado. En el ámbito académico, parecía ser una técnica bastante útil. Pero actualmente no utilizo Design by Contract de forma profesional, y no conozco a otros desarrolladores que lo estén usando. Sería bueno escuchar acerca de su uso real de la multitud SO.
En lugar de sistemas de tipo más expresivo, usaría diseño por contrato en proyectos de grado militar.
Para los idiomas débilmente tipados o idiomas con alcance dinámico (PHP, JavaScript), los contratos funcionales también son muy útiles.
Para todo lo demás, lo descartaría y confiaría en los probadores beta y las pruebas unitarias.
Gaius : el tiempo de ejecución arroja automáticamente una excepción de puntero nulo, no hay beneficio para probar eso en el prólogo de la función. Si está más interesado en la documentación, entonces usaría anotaciones que pueden usarse con analizadores estáticos y similares (para asegurarse de que el código no esté rompiendo sus anotaciones, por ejemplo).
Un sistema tipo más fuerte junto con Design by Contract parece ser el camino a seguir. Eche un vistazo a Spec# para ver un ejemplo:
El lenguaje de programación Spec #. Spec # es una extensión del lenguaje orientado a objetos C #. Extiende el sistema de tipos para incluir tipos no nulos y excepciones marcadas. Proporciona contratos de método en forma de condiciones previas y posteriores, así como invariantes de objetos.
En realidad, no uso Design by Contract todos los días. Sí, sé que se ha incorporado al lenguaje D , como parte del lenguaje.
Es absolutamente absurdo no diseñar por contrato cuando se hace algo en un ámbito de SOA, y siempre es útil si se trabaja en cualquier tipo de trabajo modular, donde los bits y piezas pueden intercambiarse más adelante, especialmente si se trata de un recuadro negro. .
Lo encuentro diciendo que el lenguaje de programación Go no tiene construcciones que hagan posible el diseño por contrato. pánico / aplazar / recuperar no son exactamente eso, ya que la lógica de posponer y recuperar permite ignorar el pánico, IOW ignora el contrato roto. Lo que se necesita al menos es alguna forma de pánico irrecuperable, que es afirmar realmente. O, en el mejor de los casos, soporte de lenguaje directo del diseño mediante construcciones de contrato (condiciones previas y posteriores, implementaciones e invariantes de clase). Pero dada la firmeza de los puristas del lenguaje al mando de Go ship, doy un pequeño cambio en todo esto.
Se puede implementar un comportamiento de afirmación comprobando el error de aserción especial en la última función de aplazamiento en la función de pánico y llamando a runtime.Breakpoint () para volcar la pila durante la recuperación. Para ser afirmativo, al igual que el comportamiento debe ser condicional. Por supuesto, este enfoque se desmorona cuando se agrega una nueva función de aplazamiento después de hacer una afirmación. Lo cual sucederá en un gran proyecto exactamente en el momento equivocado, lo que resultará en errores perdidos.
Lo que quiero decir es que esa afirmación es útil de muchas maneras, y que bailar alrededor de ella puede ser un dolor de cabeza.
No puedo recomendarlo lo suficiente. Es particularmente bueno si tiene un conjunto de aplicaciones que toma las especificaciones del contrato de documentación en línea, como las siguientes:
// @returns null iff x = 0
public foo(int x) {
...
}
y los convierte en pruebas unitarias generadas, así:
public test_foo_returns_null_iff_x_equals_0() {
assertNull foo(0);
}
De esta forma, puedes ver las pruebas que estás ejecutando, pero se generan automáticamente. Por cierto, las pruebas generadas no se deben verificar en el control de la fuente.
Realmente aprecias diseño por contrato cuando tienes una interfaz entre aplicaciones que tienen que hablar entre ellas.
Sin contratos, esta situación se convierte rápidamente en un juego de culpar al tenis. Los equipos siguen tirando acusaciones de un lado a otro y se desperdician grandes cantidades de tiempo.
Con un contrato, la culpa es clara.
¿Satisface la persona que llama las condiciones previas? Si no es así, el equipo del cliente debe arreglarlo.
Dada una solicitud válida, ¿el receptor satisfizo las condiciones del puesto? Si no, el equipo del servidor necesita arreglar eso.
¿Ambas partes se adhirieron al contrato, pero el resultado es insatisfactorio? El contrato es insuficiente y el problema debe ser escalado.
Para esto no necesita tener los contratos implementados en forma de afirmaciones, solo necesita asegurarse de que estén documentadas y aceptadas por todas las partes.
Sí, lo hace! En realidad, hace unos años, diseñé un pequeño marco para la Validación de Argumentos. Estaba haciendo un proyecto SOA, en el que el sistema de back-end diferente, hizo todo tipo de validación y comprobación. Pero para aumentar los tiempos de respuesta (en los casos en que la entrada no era válida y para reducir la carga de esos sistemas de fondo), comenzamos a validar los parámetros de entrada de los servicios proporcionados. No solo para Not Null, sino también para los patrones String. O valores de dentro de conjuntos. Y también los casos donde los parámetros tenían dependencias entre ellos.
Ahora me doy cuenta de que implementamos en ese momento un pequeño diseño por contrato marco :)
Aquí está el enlace para aquellos que estén interesados en el pequeño marco de validación de argumentos de Java . Que se implementa como una solución Java simple.
Si observa STL, boost, MFC, ATL y muchos proyectos de código abierto, puede ver que hay tantas declaraciones ASSERTION y que hace que el proyecto vaya más allá de forma más segura.
¡Diseño por contrato! Realmente funciona en producto real.
Tanto la prueba unitaria como el diseño por contrato son valiosos enfoques de prueba en mi experiencia.
He intentado usar Diseño por contrato en un marco de prueba automática del sistema y mi experiencia es que ofrece una flexibilidad y posibilidades que no se obtienen fácilmente mediante pruebas unitarias. Por ejemplo, es posible ejecutar una secuencia más larga y verificar que los tiempos de respuesta estén dentro de los límites cada vez que se ejecuta una acción.
Al observar las presentaciones en InfoQ, parece que el diseño por contrato es una valiosa adición a las pruebas unitarias convencionales en la fase de integración de los componentes. Por ejemplo, es posible crear una interfaz simulada primero y luego usar el componente después o cuando se lanza una nueva versión de un componente.
No he encontrado un kit de herramientas que cubra todos mis requisitos de diseño para diseñar mediante pruebas de contrato en la plataforma .Net / Microsoft.
Frank Krueger escribe:
Gaius: el tiempo de ejecución arroja automáticamente una excepción de puntero nulo, no hay beneficio para probar eso en el prólogo de la función.
Tengo dos respuestas a esto:
Null fue solo un ejemplo. Para square (x), me gustaría probar que la raíz cuadrada del resultado es (aproximadamente) el valor del parámetro. Para los instaladores, me gustaría probar que el valor realmente cambió. Para las operaciones atómicas, me gustaría comprobar que todas las operaciones de componentes tuvieron éxito o que todas fallaron (en realidad, una prueba para el éxito yn pruebas para la falla). Para los métodos de fábrica en lenguajes de tipo débil, quiero verificar que se devuelva el tipo correcto de objeto. La lista sigue y sigue. Básicamente, todo lo que se puede probar en una línea de código es un candidato muy bueno para un contrato de código en un comentario de prólogo.
No estoy de acuerdo con que no deba probar cosas porque generan excepciones de tiempo de ejecución. En todo caso, debe probar cosas que puedan generar excepciones de tiempo de ejecución. Me gustan las excepciones de tiempo de ejecución porque hacen que el sistema falle rápido , lo que ayuda a la depuración. Pero el
null
en el ejemplo fue un valor de resultado para alguna entrada posible. Hay un argumento para nunca devolvernull
, pero si vas a hacerlo, deberías probarlo.