miércoles, 28 de julio de 2010

Configurando un nuevo entorno de desarrollo

Estoy empezando un nuevo trabajo y esta semana le estuve dedicando un poco de tiempo a configurar mi nueva laptop. Este es siempre un proceso importante para nosotros los programadores, ya que pasamos muchas horas por día usando nuestras máquinas y por lo tanto todo lo que haga más confortable el entorno de trabajo influye mucho en nuestra productividad.

En esta oportunidad decidí llevar un log del proceso de instalación, por un lado para que me quede como documentación si necesito volver a instalar pero principalmente para compartirlo aquí y recibir feedback sobre herramientas o configuraciones utilizadas por otras personas.

Como voy a estar desarrollando aplicaciones que corren en Ubuntu decidí instalar ese sistema operativo. Además (y sin querer entrar en una guerra religiosa), me parece un entorno mucho más productivo para un desarrollador.

La instalación de Ubuntu 10.4 sobre mi Dell Vostro 1320 fue bastante fácil, solo tuve que tomar en cuenta algunos detalles. Por un lado hay que realizar la instalación conectado vía cable (no wireless) a Internet, para que se baje ciertas actualizaciones claves sin las cuales no funciona bien. Por otro lado, si bien los drivers propietarios de Dell funcionan correctamente, hay que eliminar uno de ellos que se instala por default y que causa problemas en el manejo del switch de la red wireless. Para hacerlo hay que agregar la siguiente linea al archivo /etc/modprobe.d/blacklist.conf.

blacklist dell_laptop

A continuación, y ya con la laptop andando correctamente en Ubuntu, me puse a instalar las herramientas que normalmente utilizo. Por supuesto, empecé con gvim (la instalación standard de ubuntu incluye la versión de consola de vim, pero yo uso también la version con interfaz gráfica).

sudo apt-get install vim-gnome

En seguida instalé vimwiki. Esta herramienta es un wiki personal que funciona como un plugin de vim. La función de un wiki personal es organizar nuestra información de la misma manera que haríamos en un wiki de un grupo o proyecto. Personalmente yo lo uso para tomar notas de las cosas que voy aprendiendo o quiero recordar más adelante (por ejemplo estoy armando este artículo en bases a las notas que tomé en vimwiki mientras realizaba la instalación). También me resulta muy útil para ir llevando un diario que me permita saber a que le dediqué mi tiempo cada día y para mantener una lista de las cosas que tengo pendientes de hacer. Más allá de la herramienta que se use (hay muchas versiones diferentes de Wikis personales), me ha resultado una práctica muy útil.

Instalar vimwiki es muy sencillo siguiendo las instrucciones del sitio. Solo hay que tener en cuenta que se necesita agregar las siguientes lineas al archivo ~/.vimrc

set nocompatible filetype plugin on syntax on

Una vez instalado gvim, me dediqué a la configuración del interpreté de linea de comando (bash en mi caso, tengo ganas de probar zsh algún día). En primer lugar lo configuré para poder utilizar los comandos de vi en la edición, agregando las siguientes dos líneas al archivo ~/.inputrc :

set editing-mode vi set keymap vi

Después hice que la historia de comandos del shell fuera prácticamente infinita (lo que suele ser muy útil cuando uno quiere encontrar tareas para automatizar). Para eso agregué al archivo ~/.bashrc las siguientes líneas:

HISTFILESIZE=1000000000 HISTSIZE=1000000

De manera que el shell va a recordar el último millón de comandos que ejecuté!

A continuación me dediqué a configurar el teclado. La distribución de teclado latinoamericano que tiene mi Dell anda perfecto, pero hay un par de teclas que siempre me interesa reconfigurar. En primer lugar, desactivé la tecla de bloqueo de mayúsculas (Caps Lock). Nunca la uso y a veces la toco por error causando algunos problemas (sobre todo en vi, que es *muy* case sensitive). Lo que hice fue transformarla en otra tecla Alt-gr, para lo cual agregué las siguientes dos lineas al archivo ~/.Xmodmap.

remove Lock = Caps_Lock keysym Caps_Lock = ISO_Level3_Shift

La otra modificación que hice al teclado fue habilitar la tecla de Windows, para poder usarla en combinaciones de hotkeys. Para eso agregué las siguientes tres lineas al archivo ~/.xstartup

xmodmap -e "remove mod4 = F13" xmodmap -e "keycode 115 = Super_L" xmodmap -e "add mod4 = Super_L"

Una vez hecha esta modificación podemos utilizar las combinaciones básicas de windows (Windows + L para lockear la máquina, por ejemplo) siguiendo estas instrucciones. Además instalé tres plugins para Firefox: Firebug (fundamental para desarrollo Web), Down them all (un muy cómodo manejador de downloads) y Vimperator (que configura Firefox para poder navegar utilizando los comandos de Vim!! Creo que mi relación con Vim está dejando de ser saludable :) ). Finalmente, para poder utilizar algunos programas de Windows (fundamentalmente Windows Live Writer, para el cual no conseguí un equivalente Ubuntu), instalé VirtualBox, la máquina virtual de Sun y cree una maquina virtual Windows.

Esta fue mi customización básica de Ubuntu. A medida que pasen los días, seguramente voy a ir instalando algunas cosas nuevas y ajustando Ubuntu para automatizar todas las tareas repetitivas que pueda, algo que se facilita por ser Linux un sistema operativo muy amigable para los desarrolladores. Como decía un viejo chiste , no es que Unix no sea user-friendly, solo que es muy selectivo con quienes considera sus amigos.

jueves, 22 de julio de 2010

¿Cuántos libros técnicos leiste este año?

"Tenes que leer este libro y presentarlo"

El primer libro técnico que leí por motivos laborales fue "Code Complete", de Steve McConnell, en el año 1996. En el trabajo en que estaba en ese entonces me dieron la asignación de leer el libro y presentar partes de el a mis compañeros. Empecé la tarea con pocas ganas, pero pronto me di cuenta de que la lectura de este libro iba a cambiar mi vida profesional para siempre. La posibilidad de "pararme en los hombros de un gigante" al aprender de alguien con tanta experiencia como McConnell me fascinó y a partir de ese momento he intentado siempre leer la mayor cantidad de libros técnicos posible.

Libros y capacitación

Un libro es probablemente la manera más económica de capacitarse. "The Pragmatic Programmer" de Andy Hunt y Dave Thomas (un libro excelente, si van a leer un sólo libro este año, lean este) cuesta 40 dolares en Amazon. Tomando en cuenta el envío probablemente el costo total debe rondar los 200-250 pesos. ¿Qué curso se puede tomar por ese precio, aun suponiendo que fuera posible encontrar uno que valga la pena?. Si se comparan las versiones electrónicas de los libros los costos son aún menores, ya que cuestan menos y además no hay que pagar envío.

Por lo tanto para una empresa que le de importancia a la capacitación, es posible lograr muy buenos resultados invirtiendo unos $1000 por mes. Por supuesto hay que tomar en cuanta que con sólo comprar los libros no alcanza y que hay que buscar maneras de lograr que los libros sean realmente leídos y aplicados. Una práctica que da muy buenos resultados es que los miembros de un equipo se compromentan a leer un libro y armar almuerzos quincenales o mensuales donde todos puedan discutir algunos capítulos o armar presentaciones y resúmenes.

¿Sigue valiendo la pena invertir en libros con toda la informacion disponible en la Web?

Depende del tipo de libro. Los libros de referencia probablemente no sean una buena inversión: es mucho más sencillo usar Google (y más barato, una vez compramos un libro de referencia sobre Java, llamado "Java Bible", fue muy útil....como soporte de la pata de una mesa). Sin embargo los libros que tratan sobre un tema desde una perspectiva más completa, si lo son. Por poner un ejemplo, no tiene sentido buscar como hacer paginación en Rails en otro lado que no sea Google (o Bing!, ;) pero si uno quiere entender realmente como funciona Rails solo lo va a poder hacer desde un libro, donde los conceptos van a estar presentados de una manera mucho más integral (y al respecto recomiendo el excelente "The Rails Way"). Esto tiene que ver con lo que contábamos en "cargo cult programming": para buscar una solución rápida a un problema probablemente el mejor recurso es la Web pero para entender realmente por qué funciona esa solución lo mejor es un libro (o un curso, claro que tomar un curso en EEUU o Europa no es para cualquiera).

Spik in inglish?

Una dificultad adicional que tenemos en países donde no se habla inglés es el idioma. El porcentaje de buenos libros técnicos traducidos al castellano es muy bajo y la calidad de las traducciones es muy mala (nunca voy a olvidar la traducción de buffers como "tampones de memoria" en un libro de redes de la época de la facultad). Esto hace que la incapacidad de leer correctamente inglés sea un escollo insalvable para ser un buen profesional. Si alguien que no sepa este idioma quiere dedicarse al desarrollo de software su mejor inversión (mejor que aprender cualquier tecnología) va a ser dedicarse a aprenderlo.

cuanto$?

Los programadores somos trabajadores intelectuales y por lo tanto nuestros conocimientos constituyen nuestro capital. Si dejamos de actualizarnos nos descapitalizamos y perdemos la posibilidad de conseguir mejores trabajos y ganar más dinero. Dedicar una pequeña parte de nuestro tiempo a leer libros es una manera de aumentar nuestro valor en el mercado y mejorar a la vez profesionalmente.

Entonces, ¿Cuántos libros técnicos leiste este año?

lunes, 19 de julio de 2010

POO - Ejemplos de la ley de Demeter

Para dar un poco más de sustancia y aclaración al posteo del otro día sobre leyes y principios de Programacion Orientada a Objetos vamos a ir armando pequeños ejemplos de aplicación de los mismos.

Seguro no tenemos la menos necesidad de repetir porque Toooodoos recuerdan la ley de Demeter que decia:

 Un método m, de una clase C, solo debe invocar métodos:

  1. De la misma clase C (métodos privados)
  2. De un objeto creado en m (Variable local)
  3. De un parámetro, pasado como argumento a m (parámetros)
  4. De una variable de instancia de C. (Variables de instancia de la clase

En otras palabras, un objeto no debe conocer la estructura interna de los objetos directamente relacionados con él, ni obtener a través de ellos a otros objetos para manipularlos o enviarles mensajes.

Para ser no-innovadores vamos a usar un ejemplo clásico de la ley de Demeter, conocido como el ejemplo del chico-Diariero (PaperBoy). La clase en nuestro ejemplo la nombramos simplemente Diariero. El ejemplo se basa en la relación entre El Diariero y el Cliente del diario en el momento en que se quiere cobrar tan solo un diario entregado.

Una posible implementación que viola el principio de Demeter (y que la hemos visto utilizada en código de proyectos reales, con ligeras variaciones, una y otra vez) es :

 
 
public class Diariero 
{
private static final 
double COSTO_DIARIO = 3.5;
 
  public Money cobrarDiario(Cliente cliente) {
    return cliente.getBilletera().extraer(COSTO_DIARIO);
  }
}

Es decir, la clase Diariero usa al parametro Cliente, le pide su billetera y extrae de ahi directamente el costo del Diario (el cual, para simplificar aún mas es una constante).

Aqui se puede ver fácilmente porque se viola el principio de Demeter de una manera bastante gráfica. El diariero está literalmente "metiendole la mano en el bolsillo" al cliente, y sacandole la plata. De una manera coloquial a esto es exactamente lo que apunta a evitar el principio. Que los objetos no "violen" los limites de las responsabilidades asignadas ni generen acoplamientos innecesarios. Que pasaría en este ejemplo si el cliente nos quiege pagar con algún otro medio de pago, por ejemplo, con Cheques? Habría que modificar ambas clases, Cliente y Diariero (y quizás algunas más).

Es interesante ver que el uso de getters tipo getBilletera es muy común y no causa sospechas en nadie (de hecho muchas ides tienen forma de generarlos automáticamente), pero que si en vez de usar un getter usáramos variables de instancia públicas tendríamos inmediatamente a la policía de los Objetos pidiendo nuestra captura. Sin embargo, el acoplamiento causado por este uso de los getters es casi el mismo que si usáramos variables públicas (y ni hablar cuando no solo tenemos getters sino que también tenemos setters!).

Veamos por otro lado una implementación que respeta la ley de Demeter :

 
public class Diariero {
   private static final double  COSTO_DIARIO = 3.5;
 
   public Money cobrarDiario(Cliente cliente) {
     return cliente.cobrar(COSTO_DIARIO);
   }
}
 
public class Cliente {
   private Billetera billetera;
 
  private Billetera getBilletera() {
     return billetera;
  }
 
  public Money cobrar(double costoDiario) {
      return getBilletera().extraer(costoDiario);
  }
 
}

Notar que en este ejemplo, el método getBilletera permanece privado (es algo privado justamente de cada Cliente), y no es accedido directamente. El diariero le pide al cliente que le dé el dinero a través del método cobrar. Luego este método es el que resuelve como obtener el dinero, por ahora extrayéndolo de la billetera, pero si quisiera podria devolver un cheque (deberia ser una subclase de Money, quizás) o algún otro medio de pago, sin necesidad de modificar la lógica de la clase Diariero.

En general se debe seguir la Ley de Demeter pero hay que tener cuidado con hacerlo demasiado al pie de la letra. Demeter apunta a reducir las llamadas del estilo a.b().c().d() (los clásicos "choques de trenes") , que claramente indican un problema, pero también hay que tener cuidado con llenar las clases de métodos que solo funcionan como intermediarios entre objetos. Al respecto Martin Fowler dice que estaría más correcto llamar a esta regla la Sugestion de Demeter, ya que no es algo absoluto.

miércoles, 14 de julio de 2010

Como conviene tratar a los trabajadores intelectuales

Mary Poppendieck (una de las mas importantes propulsoras de Lean Software Development) envió un mail a la lista de lean development de Yahoo sobre las diferencias en las maneras de conseguir más productividad en trabajadores manuales y trabajadores "intelectuales". La idea principal es que los trabajadores intelectuales son mucho más productivos cuando se los trata como voluntarios y no como obreros en una línea de montaje (software factories les suena?). El post y la discusión subsiguiente son muy interesantes y se pueden seguir acá. Un comentario más: actualmente tenemos la suerte de poder seguir lo que piensan gigantes de nuestra industria a traves de blogs, listas de mails, Tweeter, etc. Es un gran recurso que debemos aprovechar para aprender nuevas cosas.

lunes, 12 de julio de 2010

Código mas mantenible (I) - Legibilidad

Es asombroso como con un poco de cuidado y esfuerzo logramos que nuestro código sea mucho más legible. También es asombroso la poca importancia que le damos en general a este tema. Siempre, a veces por culpa de la complejidad innecesaria o por presión de fechas de entrega cercanas, perdemos el norte y solo nos importa que el código funcione, sin tener en cuenta que si no se entiende será inmantenible, incluso, y sobre todo, para nosotros mismos, cuando tengamos que venir a modificarlo...mañana.

La legibilidad de un código fuente se logra básicamente cuando se cumplen las siguientes propiedades:


  1. El código es claro y fácil de leer.
  2. La intención detrás de cada sentencia es obvia.
  3. La longitud del código es minimal.

Veamos cada una en detalle:

1 - Claro y fácil de leer

Para que un código sea claro y fácil de leer debe tener principalmente nombres específicos y descriptivos, tanto de funciones, constructores como de variables y clases.

No se puede dejar de subrayar la importancia de este punto. Una correcta elección de nombres implica además que el programador conoce el tema sobre el cual esta trabajando, por otro lado no poder encontrar un término especifico a menudo implica que el programador no sabe que tiene que hacer exactamente o no termina de entender la relación con el problema.

A veces es dificil encontrar un nombre adecuado y exige tiempo, pero es tiempo bien invertido porque se están definiendo al nombrarlos a los conceptos centrales del sistema en desarrollo.

En la primera versión de XP existía una práctica llamada Metáfora (que fue dejada de lado en XP 2nd edition, de Kent Beck) que trataba de encontrar un concepto globalizador de todo el sistema. Justamente, una metáfora, que sirviera para describir el sistema como un todo con un concepto tomado desde un significado distinto o de un contexto diferente. Bueno, esta práctica facilitaba grandemente la elección de nombres porque implicaba elegir un pequeño sub-mundo de la realidad, un contexto con su vocabulario especifico y relacionarlo conceptualmente con la solución del sistema en cuestión.
Así, por ejemplo, si estamos creando un sistema de inventario de mercaderías y aplicamos una metafora de Hotel, cada habitación se corresponde con un deposito y en ese caso las materias que se almacenan en el depósito serían los "pasajeros", de ahi extraeriamos los nombres, por ejemplo para decir que una mercaderia sale podriamos usar: mercaderia.checkout() y asi.

2 - Intencion Obvia

Un escritor de novelas o cuentos escribe de manera obvia cuando su intención es revelada sin vueltas, sin ninguna indirección o bifurcación de logica, ni frases agregadas, y sobre todo, sin complejidad innecesaria.

Un punto importante a aclarar es la audiencia para la cual la intención tiene que ser obvia. Esto debe quedar bien claro:

"Trabajamos para hacer mantenible el sistema para el siguiente programador que tendrá que programar modificaciones sobre este código."

Nuestra audiencia es, por lo tanto, técnica y pensando en ellos debemos programar, no para que el código sea entendido por un funcional, un usuario final o nuestro gerente.

Debemos desarrollar código cuya intención sea clara y obvia para un programador, por ello está perfectamente bien utilizar términos técnicos para nombrar una variable o agregar datos de un Pattern especifico que estamos implementando en el nombre de la clase.


Ej: SyntaxCorrectorVisitor, CustomerSearchCommand

3 - Longitud de código es minimal

El concepto es que sea la menor cantidad de código posible que permita solucionar el problema respetando a la vez el punto 1 y 2.

Si la longitud del código es demasiado larga, aun cuando los nombres estén bien elegidos y cada sentencia en si sea corta y obvia su intención, será difícil de leer. Esto es asi porque es bien sabido que no podemos prestar atención a varias cosas a la vez, y tener que comprender un texto largo es mucho más complejo que varios pequeños textos cortos.

Además, una cadena larga de sentencias casi seguro conlleva mezclar sentencias de distinto nivel de abstracción, poniendo juntos conceptos abstractos con detalles muy específicos. Es como si un escritor en medio de una frase en una novela de acción sobre la guerra divagara de todo el proceso de como fabricar un arma, desde crear la aleacion de metal del arma hasta como construir la bala.

Por último, un código extenso aumenta la probabilidad de que dupliquemos parte del código casi sin darnos cuenta y hace mucho más difícil encontrar errores, debuggear y armar tests de unidad (hay que testear demasiadas cosas y hasta el tests más pequeño va a necesitar de mucha configuración y código de startup).

En sintesis, vale la pena hacer el esfuerzo de que nuestro código sea más legible, sobre todo porque, como deciamos más arriba, el siguiente programador que tendrá que leerlo será.....nosotros mismos.

lunes, 5 de julio de 2010

La ley de Demetrio y otras yerbas OO

Demeter: Diosa Griega de la agricultura, "Madre de la distribucion", fue elegida como nombre de una ley que tiene que ver con el Desarrollo de software. Es mencionada principalmente dentro del paradigma de la orientación a objetos, si bien no aplica exclusivamente a este paradigma y puede ser expresada de una manera genérica. El significado surgió dentro de una filosofía de programación botton-up como parte de un proyecto de desarrollo de la universidad Northeastern (Boston, Massachusetts).

Llendonos justamente para el lado de la tragedia Griega, es casi una tragedia que muy pocos programadores que trabajan con lenguajes orientados a objetos conozcan y apliquen la Ley de Demeter (lo de Demetrio es en chiste) y otros principios (o leyes) que asisten en el día a día a un programador para poder desarrollar un sistema mucho más mantenible (y sí, también un poco más reusable, ver Mantenibilidad vs Reusabilidad)

Pasemos a darle una revisada a los mismos.

Ley de Demeter (1987, Northeastern University) La ley de Demeter aplicada a objetos dice que:

Un método m, de una clase C, solo debe invocar métodos: 1 - De la misma clase C (métodos privados)
2 - De un objeto creado en m (Variable local)
3 - De un parámetro, pasado como argumento a m (parámetros)
4 - De una variable de instancia de C. (Variables de instancia de la clase)

En otras palabras, un objeto no debe conocer la estructura interna de los objetos directamente relacionados con él (sean variables de instancia de la clase, parámetros o objetos creados localmente), ni obtener a través de ellos a otros objetos para manipularlos o enviarles mensajes.

En un ejemplo abstracto, si tengo el método m1 de una clase C : public void m1(parametro1, parametro2) { parametro1.metodoA() // No viola principio de Demeter parametro2.getObjetoB().metodoDeB() // VIOLA el principio! }

Un truco nemotécnico para recordar la ley: "Habla con amigos, no con extraños", (Talk to friends, not to Strangers").

Notar que interesante que en general, un patrón tan utilizado como los Beans, en java, permite e incluso facilita (en principio, ya que hay que ver bien siempre el contexto en el que ocurre) la violación de este principio.

Que es lo que produce la violación de este principio? Si, lo adivinaron, un mayor acoplamiento!

Principio abierto/Cerrado - Open Closed Principle (Bertrand Meyer, 1988)

Las entidades de software (clases, módulos, métodos y funciones) deben ser abiertas para extensión y cerradas para modificación.

Es decir, uno no debería tener que modificar clases o código existente para hacer frente a un nuevo pedido o cambio de funcionalidad. Estos cambios o nueva funcionalidad deben ser agregados o bien extendiendo clases a través de la herencia o reusando código existente a través de la delegación.

En la práctica esto no siempre sucede así y hay situaciones en las que no queda otra alternativa que cambiar código existente pero incluso en estos casos, si uno utiliza TDD y refactoring, el cambio en realidad será un refactoring que, como efecto colateral, dejará al código más cerca de respetar el principio al cual nos estamos refiriendo.

Una clara indicación de que no se ha respetado este principio es cuando un solo cambio en un módulo de un programa implica una cascadas de cambios en otros módulos dependientes.

Principio de Única Responsabilidad - Single Responsability Principle (SRP)

No debe haber más de un único motivo para que una clase cambie. Cada clase debe tener una única responsabilidad.

El motivo del que se habla en la definición se refiere a las causas para que una clase cambie. Debe haber una única fuente de posibles cambios de una Clase. Esto es lo mismo que decir que una clase tenga una única responsabilidad. Cada responsabilidad implica un eje de cambio.

Cuando un requerimiento cambia se manifiesta como cambios en las responsabilidades de las clases y si una clase asume más de una responsabilidad entonces habrá múltiples motivos de cambio que es lo que intenta evitar este principio.

El SRP es en nuestra opinión uno de los principios centrales y más importantes para el desarrollo de software de calidad. Se relaciona profundamente con los beneficios que se producen al aplicar Tests de unidad, refactoring y TDD.

Respecto a los tests de unidad, justamente cuando una clase no respeta SRP y tiene 2 o más responsabilidades marcadas de manera difusa se dificulta grandemente la escritura de los tests de unidad, y esto es una clara indicación de que hay problemas de asignación de responsabilidades en la clase. Lo cual nos lleva a la necesidad de aplicar Refactoring.
Varias de las reglas de refactoring llevan justamente a tratar de identificar la responsabilidad de una clase si la misma se encuentra mezclada de manera difusa con otras responsabilidades en el código y refactorizarla para que justamente quede más cerca de cumplir este principio.
Por ejemplo, si un método no tiene que ver con la responsabilidad principal de una clase C1 es candidato a ser trasladado (refactor Move) a la clase C2 en la cual lo que esta haciendo este más cerca de la responsabilidad de C2.

Y si uno desarrollo usando TDD (Test Driven Development) uno de los beneficios, si no el principal, es que las clases que surgen de esta práctica tienden a quedar respetando SRP.

Esta lista de principios y reglas no quiere ser extensiva ni mucho menos, y hay muchisima más "teoría" en la programación orientad a objetos por estudiar, pero si queremos resaltar la importancia de estos tres como piedras fundacionales de la Programación Orientada a Objetos.

Para terminar, y que quede bien claro, como con los Patrones de Diseño (GOF) u otras reglas y principios, nosotros opinamos que no sirve de nada saberlos de memoria, sino aprenderlos e internalizarlos. Para ello el único camino que conocemos es a través de usarlos una y otra vez, es decir, a través de la experimentación y la práctica, en otras palabras, programando.

Si bien al principio uno debe releerlos a menudo y tratar de aplicarlos "por libro", después de un tiempo al internalizarlos la aplicación de los mismos es automática y uno se olvida del enunciado formal, simplemente son parte de la forma en que uno piensa.

En próximos posteos la idea es ir mostrando ejemplos de aplicación de estos principios.

Para terminar queremos compartir un texto japonés llamado "el camino del aprendizaje SHU-HA-RI", perdonen la traducción (desde el inglés aclaramos).

(La progresión Shu-Ha-Ri )
Nivel 1

Aprender una técnica que "funcione"
El éxito reside en seguir la técnica fielmente y obtener el resultado esperado.


Nivel 2

Aprender los límites de la técnica
El éxito esta en cambiar de una técnica a otra, la que aplique mejor.


Nivel 3

Nivel de Maestría "Fluido" - Cambia las herramientas y las combina momento a momento.
Uno es incapaz de distinguir las técnicas aplicadas.