How to Design Functions (HTDF)

La receta “How to Design Functions” es un método de diseño que permite el diseño sistemático de funciones. La usaremos a lo largo del período, aunque la mejoraremos a medida que encontremos problemas más complejos .

La receta HtDF consiste en los siguientes pasos:
- Signature, purpose and stub
- Define examples, wrap each in check-expect
- Template and inventory
- Code the function body
- Test and debug until correct

Nota:
Cada uno de estos pasos se construye con el paso que lo precede. signature ayuda a escribir purpose, stub, y check-expects; También ayuda a codificar el cuerpo (code the body). El purpose ayuda a escribir los check-expects y codificar el cuerpo (code the body). El stub ayuda a escribir los check-expects. Los check-expects ayudan a codificar el cuerpo como también ayudan a probar (test) el diseño completo.
Durante el proceso de HtDF asegurese de “run early and run often” (“correr temprano y frecuentemente”). Corra el programa tan pronto sea posible. Mientras más frecuentemente ejecute su programa más pronto encontrará los errores. Encontrar errores uno a la vez mucho más fácil que esperar hasta que se multipliquen y sean más confusos.

Signature, purpose and stub

Escribir la function signature, un purpose de una linea y el function stub

signature contiene el tipo de cada argumento, separado por espacios, seguidos por ->, seguidos por el tipo de resultado. Una función que consume una imagen y produce un número tendrá la siguiente signature:

Image -> Number

El stub es una definción de una función sintácticamente completa que produce un valor. Por convención si el tipo del valor es Number se usará 0, si es String “a” etc. El valor, en general, no coincidirá con el purpose. En el ejemplo el stub produce 0 que es un Number, pero solo coincide con el purpose cuando double es llamado usando 0.

;; Number -> Number
;; produces n times 2
(define (double n) 0) ; this is the stub

El sentido del stub es hacer posible ejecutar los ejemplos incluso antes de que el diseño esté terminado. Con el stub los check-expects pueden ejecutarse

definir ejemplos, envolverlos (cada uno) en check-expect

Escribir por lo menos un ejemplo de una llamada a la función y el resultado que se espera que produzca la función. Si no sabes como escribir un ejemplo puedes empezar con combinar la function signature y los data definitions.

El rol principal de los ejemplos es ayudar a entender lo que la función debería hacer. Si existen condiciones estás deben ser incluidas con un ejemplo. Si la función debe comportarse de varias formas (different behaviours) se debe incluir un ejemplo de cada uno:

;; (double 0) should produce 0 
;; (double 1) should produce 2
;; (double 2) should produce 4

Cuando se escriben los ejemplos es útil escribir además como es computado el resultado.

;; (double 0) should produce (* 0 2)
;; (double 1) should produce (* 1 2)
;; (double 2) should produce (* 2 2)

DrRacket nos ofrece una mejor forma para escribir nuestros ejemplos, mediante el uso de check-expect. Transforma los ejemplos en unit test:

;; Number -> Number
;; produces n times 2
(check-expect (double 0) (* 0 2))
(check-expect (double 1) (* 1 2))
(check-expect (double 3) (* 3 2))
(define (double n) 0) ; this is the stub

La existencia del stub nos permitirá ejecutar nuestros tests, que fallaran cuando se ejecuten por primera vez (en general).

Template e Inventory

Antes de empezar a codificar el cuerpo de la función resulta útil tener una idea acerca de con que trabajará la función. Las templates serán escritas de acuerdo a las reglas de How to Design Data Definitions (HtDD). Deberás copiar la template, renombrarla y escribir un comentario que diga de donde fue copiada.

Cuando se trata de Numbers, Strings e Images el cuerpo de la template es simplemente (… x) donde x es el nombre del parámetro.

Una vez que la template esté completada el stub se comentará (commented out):

;; Number -> Number
;; produces n times 2
(check-expect (double 0) (* 0 2))
(check-expect (double 1) (* 1 2))
(check-expect (double 3) (* 3 2))
;(define (double n) 0) ; this is the stub
(define (double n) ; this is the template
(… n))

Codificar el cuerpo de la función

Se completa el cuerpo de la función rellenando la template.

 — La signature indica el tipo de parámetro y el tipo de data que el cuerpo de la función debe producir.
 — El purpose describe que debe producir el cuerpo de la función en Inglés (o Español)
 — Los ejemplos proveen varios ejemplos concretos de lo que debe producir el cuerpo de la función
 — La template indica la materia prima con la que se debe trabajar

Se debe utilizar todo lo antes señalado para codificar el cuerpo de la función :

;; Number -> Number
;; produces n times 2
(check-expect (double 0) (* 0 2))
(check-expect (double 1) (* 1 2))
(check-expect (double 3) (* 3 2))
;(define (double n) 0) ; this is the stub
;(define (double n) ; this is the template
; (… n))
(define (double n)
(* n 2))

Test and debug hasta que funcione

Ejecutar el programa y depurarlo hasta que pase todos los tests.

[0] original:

https://courses.edx.org/courses/course-v1:UBCx+SPD1x+2T2016/77860a93562d40bda45e452ea064998b/

Like what you read? Give Diego Pérez a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.