técnicas y herramientas para que la computadora haga más y el programador menos

109
Técnicas y Herramientas para que la Computadora haga más y el Programador menos Lic. Hernán A. Wilkinson

Upload: hernan-wilkinson

Post on 16-Jan-2017

73 views

Category:

Software


0 download

TRANSCRIPT

Técnicas y Herramientas para que la Computadora haga más y el Programador menos

Lic. Hernán A. Wilkinson

Gerente de Desarrollo en Mercap

Docente en UBA y UCA

¿Por qué ese Título?¿Qué significa?

4

Se nos ocurrieron otros títulos atractivos cómo…

¡Tips & Tricks de la Programación!

6

¡El futuro de la programación!

7

¡La solución a todos sus problemas!

8

Algo más real…Técnicas y Herramientas…

9

Desarrolladas y mejoradas por Mercap

En Mercap desarrollamos Productos (dominio financiero)

Tiempo de vida > 15 años Muy importante la calidad Muy importante la funcionalidad diferencial

XTrade

12700 clases 710800 LOC Smalltalk

Equivale a 3 mill. Java aprox

¿Problemas Principales?

Nuevos Requerimientos Funcionales Mejoras en el Diseño/Implementación Actual Rotación de Personal

Peter Naur Programming as a Theory Building NO QUEREMOS QUE SEA UN PROBLEMA

Evolución de Código

No veremos problemas de

Performance

Espacio

¿Qué significa que la “Computadora haga más y el programador menos”?

14

Como programadores…¿no tienen que hacer tareas…?

15

¿Repetitivas?

16

¿Tediosas?

17

¿Tareas que son siempre lo mismo…?

18

Tareas muy importantes que nunca se hacen por falta de tiempo…

19

¿Cómo podemos salir de este embrollo?

20

¡Lograr que la computadora trabaje por nosotros!

Para eso están… para hacer el trabajo “automatizable”

¿Cómo detectamos qué tareas son?

Douglas Hofstadter

23

podemos “salir del sistema”

24

Somos inteligentes porque

“reflexionar” sobre él

25

Konrad Lorenz (nobel 1973)

26

En su libro “Los ocho pecados mortales de la humanidad

civilizada”

“si no reflexinamos…”

“viviremos una eterna niñez…”

27

Alan Kay (Turing Award 2003)

28

Pero debemos hacerlos con “threshold above normal”

“no reinventar la rueda pinchada”

29

¡Debemos hacerlo conociendo nuestras raíces, nuestra historia!

LISP – ¡50 años!

Para no cometer los mismos errores, para estar por arriba de la media

Paremos la pelota

¿Qué tareas puedo automatizar?

¿Qué tareas son repetitivas, propensas a error, etc?

Qué vamos a ver

Testing Automatizado Objetos Auto-Defendibles Automatización de Inspección de Código Automatización de Excepciones a la regla Asegurar Calidad en Puntos Críticos Integrar Código Automáticamente Migrar Datos (objetos) Automáticamente

Test Driven Development

Seguro que todos lo conocen…

¡¡¡16100 Tests!!!

Corren en 7 minutos aprox

¿Para qué sirve?

Ayuda a tener confianza sobre los cambios a realizar

Delega en la computadora la verificación de lo que estamos haciendo

Los test son especificaciones de cómo debe funcionar el código

Ayuda a…

Entender el problema a partir de ejemplos concretos

Concentrarse en el problema real Minimizar Acoplamiento

Vamos a dar unos pasos más…

38

Objetos Auto Defendibles, Reificación de Código y

Automatización de Inspección de Código

Transacción de Compra

miCuenta (from) cuentaDelOtro (to)

Transacción de Venta

miCuenta (to) cuentaDelOtro (from)

¿Cómo lo representamos?

aTransac

anAccount

anotherAcc

10 pesos

from

to

amount

¿Cómo sabemos si la transacción es una compra o venta?

¿Cómo sabemos el “tipo”?

¿Como sabemos el “tipo”?

aTransac

aOwnAcc

aThirdAcc

10 pesos

from

to

amount

aTransacaOwnAcc

aThirdAcc

10 pesos

from

to

amount

Compra Venta

typetype

44

Solución: ¡Usemos un If!

Típica implementación usando If

Transaction>>type

(fromAccount isThirdAccount and: [toAccount isOwnAccount ]) ifTrue: [^’Sell'].(fromAccount isOwnAccount and: [toAccount isThirdAccount]) ifTrue: [^’Buy'].

¿Para qué sirve el “tipo”?

Transacciones

Contador

Impresora

47

journalEntry

transaction type = ‘Buy’ ifTrue: [ ^self buyJournalEntry ]. transaction type = ‘Sell’ ifTrue: [ ^self sellJournalEntry ].

voucher

transaction type = ‘Buy’ ifTrue: [ ^self buyVoucher]. transaction type = ‘Sell’ ifTrue: [ ^self sellVoucher].

Típico uso del “tipo” con if

¿Qué pasa si agregamos otro “tipo”?

Transferencia

type

(fromAccount isThirdAccount and: [toAccount isOwnAccount ]) ifTrue: [^’Sell'].(fromAccount isOwnAccount and: [toAccount isThirdAccount]) ifTrue: [^’Buy'].(fromAccount isOwnAccount and: [toAccount isOwnAccount ]) ifTrue: [^‘Transfer'].

Agrego el nuevo caso

Típica implementación usando If

voucher

transaction type = ‘Buy’ ifTrue: [ ^self buyVoucher]. transaction type = ‘Sell’ ifTrue: [ ^self sellVoucher].

50

journalEntry

transaction type = ‘Buy’ ifTrue: [ ^self buyJournalEntry ]. transaction type = ‘Sell’ ifTrue: [ ^self sellJournalEntry ]. transaction type = ‘Transfer’ ifTrue: [ ^self transferJournalEntry ].

¡En algún lugar nos vamos a olvidar de agregar el if!

Típico uso del “nuevo tipo” con if

¿Cuál es el Problema del if?

La computadora no decide ¡Lo hacemos nosotros! No hay Meta-Información

(información sobre las decisiones de diseño)

¿Qué tal si hacemos que los objetos lo resuelvan?

que la computadora haga más…y el programador menos

Modelemos los Tipos de Transacciones

TransactionType-accepts: aTransaction -canHandle: aTransaction-typeOf: aTransaction

Buy-accepts: aTransaction -canHandle: aTransaction

Sell-accepts: aTransaction -canHandle: aTransaction

Implementación usando Objetos

Transaction>>type

^TransactionType typeOf: self

Transaction>>type

(fromAccount isThirdAccount and: [toAccount isOwnAccount ]) ifTrue: [^’Sell'].(fromAccount isOwnAccount and: [toAccount isThirdAccount]) ifTrue: [^’Buy'].

Sell>>canHandle: aTrx

^aTrx fromAccount isThirdAccount and: [aTrx toAccount isOwnAccount ]

Buy>>canHandle: aTrx

^aTrx fromAccount isOwnAccount and: [aTrx toAccount isThirdAccount ]

Usando el “tipo” con Objetos

Buy-accepts: aTransaction -canHandle: aTransaction

Sell-accepts: aTransaction -canHandle: aTransaction

canHandle: aTransaction canHandle: aTransaction

TransactionType-accepts: aTransaction -canHandle: aTransaction-typeOf: aTransaction

typeOf: aTransaction^aSell

^false ^true

56

journalEntry

^transaction type accept: self

Usando el “tipo” con ObjetosjournalEntry

transaction type = ‘Buy’ ifTrue: [ ^self buyJournalEntry ]. transaction type = ‘Sell’ ifTrue: [ ^self sellJournalEntry ].

visitBuy

^self buyJournalEntry

visitSell

^self sellJournalEntry

57

Usando el “tipo” con Objetos

journalEntry

aTrx

type^aSell

aSell

accept: selfvisitSell

^aSellJournalEntry voucher

aTrx

type^aSell

aBuy

accept: selfvisitBuy

^aBuyVoucher¡Son Visitors!

¿Qué ganamos?

¡No hay más If!

¡Los tipos no son Strings, son Objetos!

¿Qué pasa ahora si agregamos Transferencia?

TransactionType-accepts: aTransaction -canHandle: aTransaction-typeOf: aTransaction

Buy-accepts: aTransaction -canHandle: aTransaction

Sell-accepts: aTransaction -canHandle: aTransaction

Transfer-accepts: aTransaction -canHandle: aTransaction

61

Agregemos Transferencia

journalEntry

aTrx

type^aTransfer

aTransfer

accept: selfvisitTransfer

^aTransferJournalEntry

journalEntry

aTrx

type^aSell

aTransf

accept: selfvisitTransfer

^aTransferVoucher

¿Nos podemos olvidar de implementar visitTransfer?

¡NO!

Lo avisa la Revisión Automática de Código

para Visitors

Tests de Visitors

Inspecciones Automáticas de Código

Naming conventions: Ortografía, Nombre de módulos, Nombre de Clases, etc.

Diseño: Clases abstractas sin variables de instancia

Arquitectura: Clases de test en aplicaciones de test, mock objects en

aplicaciones de test, inexistencia de referencias desde aplicaciones del modelo a aplicaciones de test, etc.

Implementación: Comentarios de código según convención, categorización de

mensajes, dónde debe estar implementado un mensaje, de dónde se debe enviar un mensaje, etc.

Inspecciones Automáticas de Código

Implementación de Patrones Correcta implementación de Singleton y Visitor

Ambiente de Desarrollo Que todos estén usando los mismos directorios, los mismos

settings del ambiente, etc. Uso correcto de Frameworks

SUnit: Recursos que no referencien a tests, que los tests hagan assert, recursos no cíclicos, etc.

Dependecy Injection: Que todas las dependencias sean iniciliazadas correctamente

Code Coverage: Definición correcta de los métodos a excluir ETC…

Inspecciónes automática de Código

Evita errores comúnes Ayuda a mantener consistente el modelo Controla los errores de programadores

nuevos Asegura calidad de

código

Lo importante

Automatizar la auditoría de todas las desiciones que se tomenDiseño ImplementaciónArquitecturaNomenclaturaUso de otros modelosEtc…

340 chequeos

Implementación de typeOf:Transaction>>type

^TransactionType typeOf: self

TransactionType >>typeOf: aTransaction

^self subclasses detect: [ :aClass | aClass canHandle: aTransaction ]

Reflexionemos un poco…

Reflexionemos un poco…typeOf: aTransaction

^self subclasses detect: [ :aClass | aClass canHandle: aTransaction ]

typeOf: aTransaction | posibleTypes | posibleTypes := self subclasses select: [ :aClass | aClass canHandle: aTransaction ]. posibleTypes isEmpty ifTrue: [ self error: ‘Error de programación’ ].

^posibleTypes first

¿Qué pasa si más de un tipo corresponde a la transacción?

¿Qué pasa si ningún tipo corresponde a la transacción?

posibleTypes size >1 ifTrue: [ self error: ‘Error de programación ].

Self Defense Objects

Los objetos se aseguran de ser utilizados correctamente

Reflexionemos un poco más…

¿Hay que escribir siempre lo mismo?¿No es el mismo problema?

¿Necesitaremos hacer esto para otros casos?

typeOf: aTransaction | posibleTypes | posibleTypes := self subclasses select: [ :aClass | aClass canHandle: aTransaction ]. posibleTypes isEmpty ifTrue: [ self error: ‘Error de programación’ ]. posibleTypes size >1 ifTrue: [ self error: ‘Error de programación ].

^posibleTypes first for: aTransaction

¡Reificar el código!typeOf: aTransaction | posibleTypes | posibleTypes := self subclasses select: [ :aClass | aClass canHandle: aTransaction ]. posibleTypes isEmpty ifTrue: [ self error: ‘Error de programación’ ]. posibleTypes size >1 ifTrue: [ self error: ‘Error de programación ].

^posibleTypes first for: aTransaction

SuitableClassSelector-value -for: aSuperClass

Reflexionemos un poco más…

typeOf: aTransaction ^(SuitableClassSelector for: self) value for: aTransaction

typeOf: aMovie ^(SuitableClassSelector for: self) value for: aMovie

typeOf: aCar

^(SuitableClassSelector for: self) value for: aCar

TransactionType:

MovieType:

CarType:

etc…

Usando el “tipo” con ObjetosBuy

-accepts: aTransaction -canHandle: aTransaction Sell

-accepts: aTransaction -canHandle: aTransaction

aSuitableClassFinder

value

aTransaction(sell)

canHandle: aTransaction canHandle: aTransaction

^Sell

TransactionType-accepts: aTransaction -canHandle: aTransaction-typeOf: aTransaction

typeOf: aTransaction^aSell

Transfer-accepts: aTransaction -canHandle: aTransaction

canHandle: aTransaction

^false ^true

^false

¿Qué logramos?

Creamos una nueva construcción “sintáctica” No puede haber “errores” al agregar nuevos

casos puesto que la computadora se encarga de verificarlo

Son objetos (meta), no texto. Podemos ver: Donde se usa Cuanto casos hay Testearlo una sola vez Etc.

Recapitulemos

TDD Self Defense Objects Reificación de

Construciones Sintácticas Inspección Automática de

Código

Automatizar las Excepciones a las Reglas de Validación de

Código

Falsos Positivos

isEmpty

^self size = 0

Warning: No se debe usar “size = 0” sino “isEmpty”

¡Pero se está implementando “isEmpty”!

Se marca como “error esperado” y se puede seguir usando la herramienta

Ejemplo (modelo open source)

expectedSmallLintFailures ^Array with: ( MCPExpectedSmallLintFailure unoptimizedToDoFailedClass: self failedMethod: 'initializeConnectors' asSymbol reasonDescription: 'No funciona bien con el #to:do: optimizado, ver comentarios en el metodo' definedBy: 'diegof')

expectedSmallLintFailures ^Array with: ( MCPExpectedSmallLintFailure utilityMethodsFailedClass: self failedMethod: #factorForSameYearFrom:to: reasonDescription: 'Por factorizacion‘ definedBy: 'hernan')

Hay un test que verifica que el usuario es válido!

¿Qué ganamos?

Evitar Falsos Positivos constantes que desalientan el uso de la automatización de inspección de código

Se debe asegurar que no haya “errores esperados” que no aplican

Asegurar Calidad en Puntos Críticos

¿Cómo?

Asegurar 100% de cobertura de test

Asegurar que no hayan “errores”

Módulo Estable

Módulo Estable

Depende de Depende de

Módulo Estable Módulo Estable

¡100 % de Cobertura!¡No hay errores!

Módulo No Estable Módulo No Estable

¿Qué ganamos?

Test que aseguran que los modulos estables tienen un 100 % de cobertura

No hay errores (detectables automáticamente) Aseguramos calidad para los módulos core Delegar en la computadora dicha verificación

Integración de Código

Integración Manual

¡Integración Automática!

Ejemplo

¿Qué ganamos?

Proceso automático No hay posibilidad de errorEs más rápido que hacerlo manualmente

Pasamos de estas varios días integrando a hacerlo en menos de media hora

¿Qué pasa con los refactorings?

ClassA ClassB

m1^ClassA new

Renombra

Error de Integración

Tesis de Diego Tubello para integrar refactorings

automáticamente

Linea Base

Linea A

Linea B

Migración de Datos

Versión inicial de Stock

Stock (versión 1)

acindar ‘acindar’name

Segunda Versión de Stock

Stock (versión 1)

acindar ‘acindar’name

Stock (versión 2)

acindar ‘acindar’name

dollar

issueCurrency

¿Por qué hay que migrar datos?

¿Por qué cambia el tipo de un campo? ¿Por qué cambia la estructura de una

tabla? ¿Por qué se agregan nuevas tablas?

¡¡POR QUE EVOLUCIONA EL CÓDIGO!! Migrar código y datos!

Migración de Objetos(en vez de migración de datos)

No sería bueno una herramienta que…

Nos avise cuando agregamos/sacamos una variable de instancia?

Nos diga cuando cambia una jerarquía? Modifique el código de una nueva

versión? ¿No sería bueno que la computadora se

encarge de resolver este problema?

¿Para qué?

Única línea de Producto

¿Qúe ganamos?

Cambio automatizado de versiones Nos permite tener una única línea de

productos Permite que los clientes tengan la última

versión

98

¡Conclusiones!

99

Camino recorrido Testing automatizado Código auto defendible Inspecciones automátizadas Reificación de Código Excepciones a la regla Asegurar la calidad de puntos críticos Integración de Código Migración de Objetos

100

Porque en Mercap tenemos…

¿Por qué lo logramos?

101

Podemos “Salir del Sistema” y Reflexionar (como dice Hofstadter)

102

Se generó un ambiente “adulto” gracias al “Feedback”

(como propone Lorenz)

103

Porque usamos Herramientas

estables, maduras

que permiten hacer Meta-programación(como propone Alan

Kay)

Ideas de Tesis… Change Model para Objetos Mejor modelo de Migración de Objetos Interfaz de Usuario declarativa …además de las que ya se están haciendo

cómoRefactorings de TraitsSmallLint para TraitsReificación de Meta-Ejecución

13-15 Noviembre Gratis! M. Oca 745 - UAI

Queremos agredecer a la competencia de esta charla…

Una lástima no haber consegido los sponsors…

108

Preguntas y Comentarios

Email: [email protected]: http://objectmodels.blogspot.com/

109