Eiffel es el lenguaje pionero en el diseño por contrato. Diseño por contrato es un concepto basado en la calidad del software.
Diseño por contrato es una metafora de como los objetos deben colaborar entre ellos. La metafora se puede explicar como un cliente que debe contratar un servicio; lo cual lo hace por medio de un contrato.
El proveedor debe proporcionar un producto determinado o servicio y tiene derecho a esperar hasta que el cliente pague.
El cliente debe pagar y tiene derecho a obtener el producto o servicio.
Ambas partes deben cumplir con ciertas obligaciones, tales como las leyes y reglamentos, aplicables a todos los contratos.
Las relaciones entre componentes de software estan definidas de forma formal por medio de los contratos, los cuales especifican las precondiciones, postcondiciones y invariantes.
La idea central de diseño por contrato como los componentes de software colaboran entre si, teniendo obligaciones y beneficios. Cuando definimos una función tenemos:
- Precondiciones: Son los requisitos que debe cumplir quien llama esta función.
- Postcondiciones: Es lo que debe hacer la función, es su obligación y un beneficio para el que llama a la función.
- Invariantes: Mantener una cierta propiedad, que garanticen que ante tal entrada se obtenga determinada salida.
Muchos Lenguajes que proveen la capacidad de hacer asserciones, pero en el diseño por contrato estas se escriben antes de escribir el código y estas son parte del diseño.
El diseño por contrato es central en eiffel. Eiffel provee la expresión require para las precondiciones, ensure para las poscondiciones y invariant para las invariantes.
Veamos como se declara una clase en eiffel:
indexing
description: "Simple bank accounts"
class
ACCOUNT
feature -- Access
balance: INTEGER
-- Current balance
deposit_count: INTEGER is
-- Number of deposits made since opening
do
… As before …
end
feature -- Element change
deposit (sum: INTEGER) is
-- Add sum to account.
require
non_negative: sum >= 0
do
… As before …
ensure
one_more_deposit:
deposit_count = old deposit_count + 1
updated: balance = old balance + sum
end
feature { NONE } -- Implementation
all_deposits: DEPOSIT_LIST
-- List of deposits since account's opening.
invariant
consistent_balance: (all_deposits /= Void) implies
(balance = all_deposits . total)
zero_if_no_deposits: (all_deposits = Void) implies
(balance = 0)
end -- class ACCOUNT
Por ejemplo en el método o característica deposit es requerido que el valor a sumar no sea negativo y se asegura que la cantidad de balances haya aumentado.
En Java existen diferentes framework que nos proveen el diseño por contrato iContract2, Contract4J, jContractor, Jcontract, C4J, Google CodePro Analytix, STclass, OVal con AspectJ, Java Modeling Language (JML), SpringContracts de Spring framework, Modern Jass.
Para satisfacer las necesidades de las aplicaciones a gran escala y misión crítica de hoy, el diseño por contrato puede ser una gran solución.
Dejo links: