Recientemente me topé con el marco de Microsoft para contratos de código.
Leí un poco de documentación y me encontré constantemente preguntando: "¿Por qué querría hacer esto, ya que no y a menudo no puede realizar un análisis estático?".
Ahora, ya tengo una especie de estilo de programación defensiva, con excepciones como esta:
if(var == null) { throw new NullArgumentException(); }
También estoy usando mucho NullObject Pattern y rara vez tengo problemas. Agregue pruebas unitarias y estará listo.
Nunca he usado afirmaciones y nunca las extrañé. Todo lo contrario. Realmente odio el código que tiene muchas afirmaciones sin sentido, lo cual es solo ruido para mí y me distrae de lo que realmente quiero ver. Los contratos de código, al menos a la manera de Microsoft, son muy parecidos, y aún peor. Añaden mucho ruido y complejidad al código. En el 99%, se lanzará una excepción de todos modos, por lo que no me importa si es por la afirmación / contrato o el problema real. Solo quedan muy pocos casos en los que los estados del programa realmente se corrompan.
Francamente, ¿cuál es el beneficio de usar contratos de código? ¿Hay alguna? Si ya usa pruebas unitarias y codifica a la defensiva, creo que la introducción de contratos simplemente no vale la pena y pone ruido en su código que un responsable maldecirá cuando actualice ese método, al igual que yo cuando no puedo ver lo que está haciendo el código debido a afirmaciones inútiles. Todavía tengo que ver una buena razón para pagar ese precio.
fuente
Respuestas:
También podría haber preguntado cuándo la escritura estática es mejor que la escritura dinámica. Un debate que se ha desatado durante años sin un final a la vista. Así que eche un vistazo a preguntas como estudios de idiomas dinámicamente vs estáticamente escritos
Pero el argumento básico sería el potencial para descubrir y solucionar problemas en tiempo de compilación que de otro modo podrían haberse deslizado a la producción.
Contratos contra guardias
Incluso con guardias y excepciones, aún enfrenta el problema de que el sistema no podrá realizar su tarea prevista en algún caso. Posiblemente una instancia en la que será bastante crítico y costoso fallar.
Contratos versus pruebas unitarias
El argumento habitual en este caso es que las pruebas prueban la presencia de errores, mientras que los tipos (contratos) prueban la ausencia. F.ex. usando un tipo que sabe que ninguna ruta en el programa podría proporcionar una entrada no válida, mientras que una prueba solo podría decirle que la ruta cubierta sí proporcionó la entrada correcta.
Contratos contra patrón de objeto nulo
Ahora esto es al menos en el mismo parque de pelota. Idiomas como Scala y Haskell han tenido un gran éxito con este enfoque para eliminar referencias nulas por completo de los programas. (Incluso si Scala permite nulos formalmente, la convención es nunca usarlos)
Si ya emplea este patrón para eliminar las NRE, básicamente ha eliminado la mayor fuente de fallas en tiempo de ejecución que existe básicamente en la forma en que los contratos le permiten hacerlo.
La diferencia podría ser que los contratos tienen una opción para requerir automáticamente todo su código para evitar nulos, y así obligarlo a usar este patrón en más lugares para pasar la compilación.
Además de eso, los contratos también te dan la flexibilidad para apuntar a cosas más allá de lo nulo. Entonces, si ya no ve ninguna NRE en sus errores, es posible que desee usar contratos para estrangular el siguiente problema más común que pueda tener. ¿A la una? Índice fuera de rango?
Pero...
Todo eso dicho. Estoy de acuerdo en que el ruido sintáctico (e incluso el ruido estructural) que los contratos agregan al código es bastante sustancial y el impacto que el análisis tiene en su tiempo de construcción no debe subestimarse. Por lo tanto, si decide agregar contratos a su sistema, probablemente sea aconsejable hacerlo con mucho cuidado y con un enfoque limitado en qué clase de errores se intenta solucionar.
fuente
No sé de dónde viene la afirmación de que "a menudo no se puede realizar un análisis estático". La primera parte de la afirmación es claramente errónea. El segundo depende de lo que quiere decir con "a menudo". Prefiero decir que a menudo realiza análisis estáticos, y rara vez falla. En la aplicación comercial ordinaria, rara vez se acerca mucho más que nunca .
Así que aquí viene, el primer beneficio:
Ventaja 1: análisis estático
Las afirmaciones ordinarias y la comprobación de argumentos tienen un inconveniente: se posponen hasta que se ejecuta el código. Por otro lado, los contratos de código se manifiestan a un nivel mucho más temprano, ya sea en el paso de codificación o al compilar la aplicación. Cuanto antes detecte un error, menos costoso será solucionarlo.
Beneficio 2: tipo de documentación siempre actualizada
Los contratos de código también proporcionan una especie de documentación que siempre está actualizada. Si el comentario XML del método
SetProductPrice(int newPrice)
indica quenewPrice
debe ser superior o igual a cero, puede esperar que la documentación esté actualizada, pero también puede descubrir que alguien cambió el método para quenewPrice = 0
arroje un documentoArgumentOutOfRangeException
, pero nunca cambió la documentación correspondiente. Dada la correlación entre los contratos de código y el código en sí, no tiene el problema de documentación fuera de sincronización.El tipo de documentación proporcionada por los contratos de código también es valioso de una manera que a menudo, los comentarios XML no explican bien los valores aceptables. ¿Cuántas veces me preguntaba si era
null
ostring.Empty
o\r\n
es un valor autorizado para un método y comentarios XML guardaron silencio en eso!En conclusión, sin contratos de código, muchos códigos son así:
Con los contratos de código, se convierte en:
Ventaja 3: contratos de interfaces
Un tercer beneficio es que los contratos de código potencian las interfaces. Digamos que tienes algo como:
¿Cómo podría, utilizando solo afirmaciones y excepciones, garantizar que solo
CommitChanges
se puede llamar cuandoPendingChanges
no está vacío? ¿Cómo garantizarías quePendingChanges
nunca es asínull
?Beneficio 4: hacer cumplir los resultados de un método
Finalmente, el cuarto beneficio es poder obtener
Contract.Ensure
los resultados. ¿Qué pasa si, al escribir un método que devuelve un número entero, quiero estar seguro de que el valor nunca es inferior o igual a cero? ¿Incluso cinco años después, después de sufrir muchos cambios de muchos desarrolladores? Tan pronto como un método tiene múltiples puntos de retorno, seAssert
convierte en una pesadilla de mantenimiento para eso.Considere los contratos de código no solo como un medio de corrección de su código, sino como una forma más estricta de escribir código. De manera similar, una persona que usaba lenguajes dinámicos exclusivamente puede preguntar por qué impondría los tipos a nivel de lenguaje, mientras que puede hacer lo mismo en afirmaciones cuando sea necesario. Puede hacerlo, pero la escritura estática es más fácil de usar, menos propensa a errores en comparación con un montón de aserciones y la autodocumentación.
La diferencia entre la escritura dinámica y la escritura estática es extremadamente cercana a la diferencia entre la programación ordinaria y la programación por contratos.
fuente
Sé que esto es un poco tarde para la pregunta, pero hay otro beneficio para Code Contracts que vale la pena mencionar
Los contratos se verifican fuera del método
Cuando tenemos condiciones de protección dentro de nuestro método, ese es el lugar donde se realiza la verificación y donde se informan los errores. Entonces podríamos tener que investigar el seguimiento de la pila para descubrir dónde está la fuente real del error.
Los contratos de código se encuentran dentro del método, pero las condiciones previas se verifican fuera del método cuando algo intenta llamar a ese método. Los contratos se convierten en parte del método y determina si se puede invocar o no. Eso significa que recibimos un error informado mucho más cerca de la fuente real del problema.
Si tiene un método protegido por contrato que se requiere para muchos lugares, esto puede ser un beneficio real.
fuente
Dos cosas realmente:
fuente