Está en la página 1de 10

Tema 8 - Diseño por contrato (DCA)

Antonio-M. Corbí Bellot


Tema 8 - Diseño por contrato (DCA) II

HISTORIAL DE REVISIONES

NÚMERO FECHA MODIFICACIONES NOMBRE


Tema 8 - Diseño por contrato (DCA) III

Índice

1. Preliminares (I) 1

2. Preliminares (II) 1

3. Precondiciones 1

4. Postcondiciones 2

5. Invariantes 2

6. Lenguaje Eiffel 2

7. Casos de uso: Eiffel (I): 2

8. Casos de uso: Eiffel (II): 3

9. Lenguaje D (I) 3

10. Lenguaje D (II) 4

11. Casos de uso: Lenguaje D (I) 4

12. Casos de uso: Lenguaje D (II) 5

13. Caso de Uso: Vala 5

14. Caso de Uso: mi lenguaje no soporta DbC 5

15. Contracts Reading List 6

16. Prácticas 6

17. Aclaraciones 7
Tema 8 - Diseño por contrato (DCA) 1/7

Tema 8 - Diseño por contrato


Curso 2021-2022

1. Preliminares (I)

El Diseño por Contrato es una metodología de diseño de software. También se la conoce como Programación por Contrato.
Trata de aplicar el concepto de las condiciones y obligaciones (a ambas partes) de un "contrato de negocios" a la implementa-
ción de un diseño de software.
Un contrato es la especificación de las propiedades de un elemento software que afecta a su uso por parte de clientes potencia-
les.
Para ello se dota al programador de una serie de nuevos elementos que permite llevar a cabo esta especificación: precondicio-
nes, postcondiciones e invariantes.

2. Preliminares (II)

El término "Diseño por Contrato" fue usado por primera vez por Bertrand Meyer al crear el lenguaje de programación Eiffel.
Posteriormente registraron comercialmente dicho término ( DbC ).
Está basado en la verificación y especificación formal de código, o también en la derivación de programas.
Nosotros no vamos a entrar en la parte teórica de estos conceptos, sino que vamos a ir directamente a la práctica.

3. Precondiciones

Son un elemento del "contrato".


Se representan mediante una condición que al ser evaluada produce un valor Verdadero o Falso.
Es una propiedad que un método o función "impone" a todos sus clientes.

Un método o función puede tener varias precondiciones.


Es responsabilidad de un cliente de este método o función asegurar que se satisfacen todas sus precondiciones cuando lo llama.
Por tanto, para los clientes del método sus precondiciones son una obligación, mientras que para el método llamado representan
lo que éste espera de los clientes que lo llaman.

Son útiles cuando estamos depurando. Si no se cumple una precondición. . . el fallo está en el cliente del método que la ha
definido.
Tema 8 - Diseño por contrato (DCA) 2/7

4. Postcondiciones

Son otro de los elementos del "contrato".


Representan lo que obtendrán los clientes del método actual cuando este acabe. . .
Evidentemente. . . si han cumplido las precondiciones del mismo.

Son, por tanto, una obligación para el método actual que la define.
Es este método el que debe asegurar que al terminar. . . todas sus postcondiciones se cumplen.
Son útiles cuando estamos depurando. Si no se cumple una postcondición. . . el fallo está en el método que la ha definido.

5. Invariantes

Son el último de los elementos del "contrato".


Precondiciones y postcondiciones son propiedades lógicas que están asociadas con un método o función particular.
Hay ocasiones donde queremos asociar una de estas propiedades lógicas con una "clase".

A estas propiedades se las conoce como "Invariantes de clase". Una clase puede tener varios invariantes.
Estos invariantes se deben cumplir nada más crear un objeto de la clase y antes y después de ejecutar cualquier método de
la misma.

6. Lenguaje Eiffel

Eiffel es un lenguaje de programación orientado a objetos.

Diseñado por Bertrand Meyer. Basado en el cumplimiento de ciertos principios: design by contract, command-query separa-
tion, uniform-access principle, single-choice principle, open-closed principle, option-operand separation.
Soporta herencia, herencia múltiple, genericidad, genericidad restringida, recolección de basura, etc. . .
Disponemos del IDE EiffelStudio en plataformas Windows, como software libre disponemos de tecomp: The Eiffel Compiler.

7. Casos de uso: Eiffel (I):

Precondiciones, postcondiciones e invariantes:


1 class DATE
2 create make
3 feature {NONE} -- Initialization
4 make (a_day: INTEGER; a_hour: INTEGER)
5 -- Initialize `Current' with `a_day' and `a_hour'.
6 require
7 valid_day: 1 <= a_day and a_day <= 31
8 valid_hour: 0 <= a_hour and a_hour <= 23
9 do
10 day := a_day
11 hour := a_hour
12 ensure
13 day_set: day = a_day
14 hour_set: hour = a_hour
15 end
Tema 8 - Diseño por contrato (DCA) 3/7

16 ...
17 invariant
18 valid_day: 1 <= day and day <= 31
19 valid_hour: 0 <= hour and hour <= 23
20 end

8. Casos de uso: Eiffel (II):

1 class
2 Account
3

4 feature -- Access
5 balance: INTEGER -- Current balance
6

7 feature -- Element change


8 deposit (sum: INTEGER)
9 -- Add `sum' to account.
10 require
11 non_negative: sum >= 0
12 do
13 ... As before ...
14 ensure
15 one_more_deposit: deposit_count = old deposit_count + 1
16 updated: balance = old balance + sum
17 end

9. Lenguaje D (I)

Es un lenguaje de la familia de C, trata de ser lo que C++ no ha podido ofrecer por su intento de compatibilidad con C:

"Can the power and capability of C++ be extracted, redesigned,


and recast into a language that is simple, orthogonal, and
practical? Can it all be put into a package that is easy for
compiler writers to correctly implement, and which enables
compilers to efficiently generate aggressively optimized code?

— http://dlang.org/overview.html

La versión del lenguaje a emplear es la 2, puedes encontrar compiladores para la versión 1, pero no se recomienda su uso.
Su página web oficial la tienes en dlang.org.
Características
Puedes descargar el compilador de referencia desde aquí.

Dispones de un tutorial recomendado además de este tour.


Dispone de análisis de cobertura del código y soporte de tests unitarios, además de compilación condicional y depuración
llevadas un paso más allá de lo que estamos acostumbrados. Documentación generada a partir de comentarios.
Tema 8 - Diseño por contrato (DCA) 4/7

10. Lenguaje D (II)

C ONCEPTOS CLAVE EN EL DISEÑO DE D:

1. Make it easier to write code that is portable from compiler to compiler, machine to machine, and operating system to
operating system. Eliminate undefined and implementation defined behaviors as much as practical.
2. Provide syntactic and semantic constructs that eliminate or at least reduce common mistakes. Reduce or even eliminate the
need for third party static code checkers.
3. Support memory safe programming.
4. Support multi-paradigm programming, i.e. at a minimum support imperative, structured, object oriented, generic and even
functional programming paradigms.
5. Make doing things the right way easier than the wrong way.
6. Have a short learning curve for programmers comfortable with programming in C, C++ or Java.
7. Provide low level bare metal access as required. Provide a means for the advanced programmer to escape checking as
necessary.
8. Be compatible with the local C application binary interface.
9. Where D code looks the same as C code, have it either behave the same or issue an error.
10. Have a context-free grammar. Successful parsing must not require semantic analysis.
11. Easily support writing internationalized applications.
12. Incorporate Contract Programming and unit testing methodology.
13. Be able to build lightweight, standalone programs.
14. Reduce the costs of creating documentation.
15. Provide sufficient semantics to enable advances in compiler optimization technology.
16. Cater to the needs of numerical analysis programmers.
17. Obviously, sometimes these goals will conflict. Resolution will be in favor of usability.

11. Casos de uso: Lenguaje D (I)

Precondiciones y postcondiciones:
1 import std.math;
2

3 long square_root_old_syntax(long x)
4 in { assert(x >= 0); }
5 out (result) {
6 assert((result * result) <= x && (result+1) * (result+1) >= x);
7 }
8 body {
9 return cast(long)std.math.sqrt(cast(real)x);
10 }
11

12 long square_root_new_syntax(long x)
13 in (x >= 0)
14 out (result; (result * result) <= x && (result+1) * (result+1) >= x)
15 { // O tambien: do {
16 return cast(long)std.math.sqrt(cast(real)x);
17 }
Tema 8 - Diseño por contrato (DCA) 5/7

12. Casos de uso: Lenguaje D (II)

Invariantes
1 class Date
2 {
3 int day;
4 int hour;
5

6 invariant() {
7 assert(1 <= day && day <= 31);
8 assert(0 <= hour && hour < 24);
9 }
10 }

Lenguaje D
Versiones recientes del compilador de "D" han simplificado la sintáxis de pre/post-condiciones e invariantes
(p.e. body ya no es una palabra reservada y en su lugar se emplea do en las funciones y métodos que tienen
pre/postcondiciones). Puedes verlo aquí.
De momento se soportan los dos tipos de sintáxis. Esto podría cambiar en un futuro.

13. Caso de Uso: Vala

Vala soporta precondiciones y postcondiciones, pero no invariantes de clase.

1 double method_name(int x, double d)


2 requires (x > 0 && x < 10)
3 requires (d >= 0.0 && d <= 1.0)
4 ensures (result >= 0.0 && result <= 10.0)
5 {
6 return d * x;
7 }

Destacar la variable result que podemos ver en la postcondición.

14. Caso de Uso: mi lenguaje no soporta DbC

Usa la construcción más parecida al assert de C, C++, Java etc. . . que tenga el lenguaje de programación que empleas.
Utiliza las llamadas a assert al principio y al final de tus funciones:

1 double f(int x, double d) {


2 assert( x != 0 );
3 ....
4 double result = ....
5 assert(result > 0.0);
6 return result;
7 }

En el caso de poo y clases, añade un método privado llamado p.e. ‘invariant’ (o como quieras) y recuerda llamarlo al principio
y final de cada método de la clase correspondiente:
Tema 8 - Diseño por contrato (DCA) 6/7

1 class Tree {
2 private:
3 void invariant() {
4 assert(...);
5 assert(...);
6 }
7 public:
8 double grow(int x, double d) {
9 invariant();
10

11 assert( x != 0 );
12 ....
13 double result = ....
14 assert(result > 0.0);
15

16 invariant();
17 return result;
18 }
19 }

15. Contracts Reading List

En el siguiente enlace puedes encontrar más información sobre diseño por contrato en diferentes lenguajes de programación.

16. Prácticas

G RUPO

Existe otro tipo de invariantes, son los llamados invariantes de bucles. Investigad para qué sirven, de qué manera se pueden
emplear en la verificación formal de programas y buscad ejemplos de lenguajes de programación con soporte sintáctico para
ellos.

Individuales Lenguajes D y Vala:


L ENGUAJE D

En una carpeta realiza una aplicación sencilla en Lenguaje-D que cree una o varias clases y haga uso de pre y postcondiciones
en sus métodos, además de hacer uso de un invariante de clase.

• Comprueba qué ocurre cuando no se cumplen ni precondiciones ni postcondiciones ni invariante de clase.


• ¿Qué ocurre cuando un método no-final de una clase base no tiene precondiciones y cuando lo redefinimos en una clase
derivada se las añadimos?

El compilador de "D" puedes instalarlo facilmente para cualquier SO desde aquí.

• DMD es el compilador oficial de D, sólo genera código x86 y x86_64.


• GDC es el compilador oficial de D basado en GCC.
• LDC es el compilador oficial de D basado en LLVM.

Lenguaje Vala En otra carpeta haz lo mismo con el Lenguaje Vala, evidentemente sin los invariantes de clase.
Tema 8 - Diseño por contrato (DCA) 7/7

Lenguaje Vala

Recuerda que el compilador de Vala se llama "valac". Tambien puedes


usar una version concreta del mismo como "valac-0.30", "valac-0.40",
etc...

E NTREGA :

La práctica o prácticas se entregará/n en (y sólo en) pracdlsi en las fechas y condiciones allí indicadas.

Entrega ambas carpetas dentro de otra y comprime ésta última en un tgz.

17. Aclaraciones

E N NINGÚN CASO ESTAS TRANSPARENCIAS SON LA BIBLIOGRAFÍA DE LA ASIGNATURA .

Debes estudiar, aclarar y ampliar los conceptos que en ellas encuentres empleando los enlaces web y bibliografía recomendada
que puedes consultar en la página web de la ficha de la asignatura y en la web propia de la asignatura.

También podría gustarte