Mostrando las entradas con la etiqueta agil. Mostrar todas las entradas
Mostrando las entradas con la etiqueta agil. Mostrar todas las entradas

2017/05/18

Programando tu propia comida

En un inicio, si alguien tenía una computadora era para programar algo que solucionara su problema en particular.

Habían recetas de soluciones que se compartían entre la gente que programaba.

Cuando mucha gente trabajaba sobre cierto programa, se iban estableciendo costumbres y estándares para facilitar la comunicación entre las personas.

Nuevas formas de programar fueron emergiendo para facilitar que más gente pudiera programar soluciones más complejas con más facilidad.

Poco a poco, ya no fue necesario conocer de electrónica, ni de cuestiones específicas del hardware de la computadora. Luego, no fue necesario usar siglas mnemotécnicas sino expresiones muy parecidas al inglés.

Entonces, en algún momento, alguien notó que una computadora podía tener usuarios que no programaran, sino que usaran interfaces simples para realizar acciones sin componer nuevos programas.

Más tarde, alguien más notó que esos programas con interfaces simples podrían ser vendidos. Y luego, que para asegurar la dependencia podían limitar la posibilidad de hacer nuevos programas.

El software comercial permite resolver muchos problemas. Pero cada nueva característica, cada mejora, depende de que el proveedor del programa lo incorpore en la siguiente versión, por la que tendremos que pagar.

El software libre aparece como una respuesta a esta situación. Al obligar a que el código fuente de cada programa este disponible y cada usuario tenga la libertad de modificarlo y redustribuirlo, ayudó a que quienes tuvieran el conocimiento técnico suficiente pudieran ayudar con la evolución del software.

Sin embargo, la barrera es muy alta. El software actual, comercial o libre, sigue el esquema de aplicaciones paquete de muy difícil manufactura. Se necesita avanzados conocimientos de programación para lograr algo así. Además, son productos de uso final que difícilmente se comunican entre sí y que prácticamente no se pueden desagregar ni componer para formar nuevas soluciones.

A fines de los '80, Apple, una empresa con el estilo de proveer productos de cómputo que los usuarios no pueden alterar ni extender, tuvo un producto llamado Hypercard, creado por Bill Atkinson, que permitía a los usuarios componer visualmente secuencias de acciones y expresar los detalles en el lenguaje Hypertalk, muy simple y fácil de leer y escribir. Es decir, creó un entorno que permitía que los usuarios finales pudieran hacer programas para solucionar sus problemas particulares. Como antes, apareció una comunidad que compartía sus recetas.

Por alguna razón, está iniciativa no recibió el apoyo adecuado. Las siguientes versiones del producto limitaban las capacidades de creación y buscaba colocar a Apple como intermediario, otra vez, de las soluciones que la comunidad de usuarios era capaz de realizar por si misma.

Cuando Steve Jobs (precisamente, uno de los primeros en notar cómo hacer negocios con el software) regresó a la dirección, uno de los proyectos que canceló fue el de Hypercard.

Cosas como Hypercard necesitan una comunidad de usuarios emponderados, capaces de crear soluciones cuya explotación no puedes controlar.

Hay proyectos que tomaron la posta de ciertas ideas de Hypercard. Como VisualBasic, con su interfaz visual. Pero parece que siempre orientados a programadores, no a un público laico.

Parece más probable que una iniciativa que herede el espíritu de Hypercard provenga del software libre que del software comercial.


Hoy, el software comercial ha logrado que prácticamente cada persona cuente con una computadora en la mano. Gracias a ella puede consumir los productos que les preparan. La barrera técnica para preparar esos productos es tan alta y los consumidores tan ávidos de soluciones que se ha vuelto notoria la falta de capacidad para cubrir esa demanda.

Es como si hubiera pocos restaurantes para muchos comensales.

La comunidad de programadores, que son como los cocineros, ha optado por buscar modos de mejorar su respuesta, optimizando la forma en que programan, automatizando procesos, etc.

Los gobiernos están promoviendo la enseñanza de programación para aumentar el número de programadores. Es como aumentar el número de chefs y restaurantes.

Y sigue el aumento de gente con nuevas ideas de aplicaciones. Son como comensales con nuevas ideas de platillos, buscando chefs que los entiendan, o incluso financiandose un pequeño restaurante para poder ofrecer al mundo ese platillo que imaginan.

Ellos necesitan programadores porque, a diferencia del mundo de los comensales que también pueden cocinar, en el mundo de las aplicaciones es tan alta la valla de entrada que es como si sólo existieran cocinas industriales y ollas gigantes y sólo ingredientes al por mayor. La poca gente que puede preparar sus alimentos son los que saben hacer sus propias hogueras y utensilios para cocinar. O las que comen sushi.

¿Qué podemos hacer en este escenario?

Además de los cocineros tratando de cocinar más rápido y de los gobiernos tratando de hacer más cocineros, hay otras iniciativas en curso.

Hay el equivalente a cocinas comunitarias, donde cocineros pueden alquilar un espacio.

Hay el equivalente a máquinas expendedoras, donde se pueden conseguir golosinas, cafe o sandwich. Administradores de contenido que te permiten combinar algunas opciones para armar un refrigerio.

Los avances en inteligencia artificial están permitiendo máquinas expendedoras capaces de preparar algunas comidas básicas. Es decir, acciones simples como encender las luces, monitorear el refrigerador, sintonizar la tv o hacer consultas en Google, obedeciendo comandos en el lenguaje del usuario.


Quizás a estas alturas ya hayas notado qué ha pasado y qué se podría hacer.

Es como si se hubiera convencido a todo el mundo que la única forma de comer decentemente es en un restaurante o comprando algo hecho por un cocinero profesional.

¿Qué vendría a ser Hypercard? Quizás algo así como una máquina expendedora pero no de comida, sino de pequeños utensilios para cocinar, o de partes modulares para armar esos utensilios, y de ingredientes al por menor.

El símil deja ver que así como todo el mundo puede cocinar aprendiendo unas pautas básicas, la programación podría ser algo más asequible también.

El poder de la inteligencia artificial también podría ayudar, si se le permitiera disgregar soluciones existentes y componerlas en nuevas soluciones y a la comunidad de usuarios compartirlas libremente.

La clave es una libertad efectiva para componer nuevos programas a partir de otros, y de poder compartirlos libremente.

Si no puedes cocinar, dependes de alguien más para algo que debería ser una libertad básica.

No digo que no haya restaurantes. Tampoco que atendamos restaurantes usando expendedoras. Digo que no debe ser prohibitivo cocinar uno mismo.

Cada persona debe tener la libertad, y el poder, de resolver sus propios problemas, sin intermediarios.

Programar debe ser una actividad al alcance de cualquier persona.

Porque cada cambio en el mundo nace de una persona, no de un rebaño.

Y el mundo está necesitando cambios significativos más rápido de lo que se le puede proveer.

Necesitamos herramientas de programación más asequibles. El equivalente a una cocina de hogar o una hornilla. Ollas pequeñas y personales. Ingredientes al por menor. Recetas familiares.

Necesitamos liberar la creatividad de las personas para descubrir nuevas experiencias y soluciones... nuevos sabores.

2017/01/21

La importancia de solucionar algo

Amazing Grace

A Grace Hopper se le dio el encargo de elaborar el manual de instrucciones de una de las primeras computadoras creadas en los Estados Unidos.

A la Marina, le interesaba averiguar de qué modo podría aprovechar el potencial de la nueva máquina Mark I.

No era común que una mujer perteneciera a la armada, y tampoco tenía los estándares de peso y talla, pero sus habilidades matemáticas le ayudaron a ser admitida y abrirse camino.

Ella propuso organizar bajo nombres más asequibles las rutinas que había coleccionado con su equipo, y un esquema para reutilizarlas con más facilidad y automatizar la generación de las secuencias binarias que eran la forma normal de programar las computadoras en aquella época.

Normalmente, para programar la solución de un problema, había que enfrentarse con el hardware y los interruptores necesarios para implementar el programa. Era como tener que atravesar continuamente una bruma mental para distinguir lo que se quería conseguir.

En cambio, usar un compilador de código tenía la ventaja de permitr pensar con más claridad en el problema que se quería resolver.

Sin embargo, su propuesta fue desechada porque el código binario generado de ese modo era más largo y menos eficiente.

Grace persisitió en ello como un proyecto personal. Desarrollando lo que vendría a ser conocido como lenguaje ensamblador, o Assembler.

Uno de sus amigos, que había estado meses con un equipo tratando de programar la solución de un problema especialmente difícil, logró hacerlo en unas horas usando Assembler.

Poco a poco, el uso del Assembler se fue extendiendo.

Años después, creó COBOL, el primer lenguaje de programación, que permitía expresar un programa en algo parecido a sentencias en inglés.

Menos eficiente pero más eficaz

Hoy en día, prácticamente toda la programación se hace con ayuda de compiladores y los lenguajes de alto nivel que aparecieron luego del COBOL. De ese modo, los problemas no solo se resuelven con más rapidez, sino también con menos errores. Y si los hubiera, son mucho más fáciles de localizar.

La propuesta de Grace de usar lenguajes de más alto nivel para solucionar problemas encontró resistencia en otros programadores que desdeñaban el código binario repetitivo, largo e ineficiente que se producía de ese modo. Ellos podían hacerlo más simple, más elegante, del "modo correcto".

Los programadores que podían programar directamente en binario no eran muchos y quizás se sentían un poco como sumos sacerdotes. Los intermediarios exclusivos entre la gente y las máquinas todopoderosas.

Los lenguajes de alto nivel tuvieron la virtud de hacer la programación de computadoras accesible a más personas.

Sigue siendo cierta la observación de que el código binario producido por los compiladores es más repetitivo, largo y menos eficiente que el que se podría producir directamente. Sin embargo, con la mejora de la velocidad de procesamiento, la programación directa en binario ya es muy poco práctica.

Es más importante llegar primero a la solución de un problema. La eficiencia del resultado se podría ir mejorando luego de eso (finalmente reemplazando código por assembler y luego por binario si el rendimiento fuera algo vital).

Algo hecho es mejor que lo perfecto

¿Qué es mejor, una solución perfecta que tarda tanto que nunca llega, o una solución que funcione?

"Done is better than perfect" es una famosa frase acuñada por la gente de Facebook.

La comunidad hacker tiene además "Primero que funcione, luego optimizas".

Y Donald Knuth, la famosa "La optimización prematura es la raíz de todo lo malo".

No son opiniones. Expresan un hecho, comprobado una y otra vez en la experiencia de los programadores y los equipos de programadores y los proyectos de programación.

Aún así, de cuando en cuando encontrarás a otros programadores o desarrolladores de software insistiendo en buscar la perfección o hacer optimizaciones durante la solución.

Es la optimización mal entendida.

Optimizar algo está bien, pero su momento es después que haya una solución.

Solo puedes mejorar algo que tienes, si no, la optimización es una falacia (y las falacias son peligrosas porque suelen tener ese aire de verdad que hace que uno las acepte si no se anda con cuidado)

Código limpio

A la computadora le da igual si el código está limpio o no.

El código limpio es una optimización orientada a los programadores para facilitar el mantenimiento del programa.

Pero, igual que toda optimización, su momento es después que tengas una solución, no antes.

Hay que disfrutar garabateando con código, esbozando algoritmos, en el proceso de concretar una solución.

Pretender escribir código limpio durante el proceso de solución es tan contraproducente como pretender pintar la versión final de un retrato directamente sobre un lienzo en blanco.

Cómo odio a los haters :-)

Hay programadores que automáticamente tienen actitudes hostiles o de desdén hacia ciertos lenguajes de programación, ciertos frameworks o ciertas librerías.

"PHP es el peor lenguaje de programación jamás inventado"

"Javascript es un lenguaje de juguete que no se puede tomar en serio"

"Todos esos frameworks son basura que complica las cosas"

Pero minimizar lo que nos disgusta no hace que nuestras soluciones sean mejores. De hecho, impide ver las soluciones de otros.

PHP es un lenguaje que ha ayudado mucho a democratizar la programación en Internet. La valla es más baja y mucha más gente puede entrar y cometer errores que hacen sonreir con desdén a ciertos académicos y profesionales. Pero ha permitido que muchas ideas geniales vean la luz. Más de la mitad de los blogs en Internet están hechos en WordPress, que es un administrador de contenidos escrito en PHP. Wikipedia está escrita en PHP. La base de Facebook también estuvo escrita en PHP.

Javascript ha evolucionado. No es solo para hacer efectos especiales en una página web. Permite crear interfaces complejas. Y en el lado del servidor, facilita el desarrollo de soluciones ligeras, asíncronas y sin bloqueos. Paypal usa Javascript en el backend. Hay quienes consideran que actualmente Javascript tiene uno de los más completos ecosistemas de desarrollo web.

Los frameworks son herramientas para resolver problemas. Como un martillo, o una sierra. Puede tomar su tiempo conseguir maestría en su uso. Muchos dedos golpeados, cortes accidentales. Y puede que no sean para todo tipo de problemas. Quizás haya herramientas más sofisticadas, o más ligeras, pero posiblemente te enfrentarás a más problemas si intentas hacer carpintería con una piedra, un cuchillo, o una navaja suiza.

Creo que siempre es más constructivo tratar de ver las buenas partes, usar esas buenas partes y evitar las otras.

También aquí es cuestión de ver el vaso medio lleno.

Referencias

2016/10/04

Proyectos felices


Internet y las nuevas tecnologías están ayudando a que la gente imagine formas nuevas de hacer las cosas y resuelva problemas.

La gente imagina soluciones y trata de implementarlas. A veces con éxito, a veces no tanto.

Y es que la forma de implementar una solución es también algo que tendríamos que mejorar.

Muchos provenimos de instituciones educativas que nos han formado con hábitos que no suelen ser los mejores. Una tendencia a establecer relaciones jerarquicas, en lugar de colaborativas. A competir, en lugar de cooperar. A proteger, en lugar de compartir. A culpar a las personas, en lugar de enfrentar los hechos. Y así.

Así que a la hora de realizar un proyecto con el que intentamos resolver cierto problema, encontramos un meta problema, que es la forma cómo nos organizamos.

Lo que puede hacer la diferencia no es cuánto dinero tenemos, ni qué tecnología usamos, sino cómo estamos organizados. ¿Es un organismo sano, sabemos cuándo algo le duele, sabemos curarlo, podemos caminar de modo sostenible?

Hay propuestas, como la de las metodologías agiles, que dan cierta luz en ese camino oscuro por el que siempre hemos venido transitando sin darnos cuenta.

Estas son algunas de las cosas que me parece se toman en cuenta en proyectos felices.

  • Lo más importante es la gente
    • El dinero es solo una herramienta
    • La gente no es una herramienta ni un recurso
    • Permite cultivar los verdaderos talentos, no los que necesitas.
      (la gente que encuentra su pasión es la que mejora el mundo)
    • Cuestiona los hechos, no a las personas
    • Cultiva una comunidad
    • Cada problema es de la comunidad
    • Cada victoria es de la comunidad
      (las clásicas recompensas individuales no hacen bien a la larga)
  • Disfrutar el camino
    • Cultiva la autonomía, la maestría, y el hacer algo por un propósito superior
    • Trabaja por objetivos, no por turnos
    • Reunirse cada día, para mirar cómo vamos
    • Reunirse cada semana, para mirar cómo lo hicimos
    • Preguntarse que salió bien y qué se puede mejorar
    • Celebra aquello que quieres que perdure
    • Equivocarse es parte de aprender
    • Un paso completo, aunque sea pequeño, es una victoria
    • Cada victoria te da energía para el siguiente paso
  • Honestidad
    • Saber decir que no
    • Mostrar con claridad y explícitamente el estado de las cosas
    • Debe haber un por qué para cada cosa que se quiere incluir en el proyecto

Muchas veces se desarrollan proyectos sin tener en cuenta casi ninguna de estas cosas. Es decir, sin tener en cuenta a la gente, con quienes finalmente tienes que contar para lograrlo.

Hay varias preguntas y retos al tratar de hacer estas cosas. ¿Por qué no funcionan las recompensas?, ¿Cómo se deben distribuir la ganancias?, etc. Algunas pueden parecer contra intuitivas, pero están apoyadas por evidencia objetiva y estudios en comportamiento humano (a diferencia de muchas cosas que hacemos simplemente porque siempre se ha hecho así). Algunas pueden parecer imposibles, pero ya hay organizaciones en el mundo moviéndose bajo principios como estos.

Quizás sea porque nuestros padres no sabían hacerlo y tampoco nos lo enseñaron. Pero es algo importante que pienso debemos aprender a hacer para prosperar en esta nueva era.

2016/07/09

Vistas esquemáticas

En el diseño gráfico, la vista de alambre ayuda a abstraerse de los detalles y concentrarse en la estructura. Sería demasiado complicado e incómodo tener que trabajar todo el tiempo con la vista final. Además de innecesariamente costoso.

Sin embargo, muchas veces desarrollamos software trabajando todo el tiempo con la vista final.

Sería util poder contar con una especie de vista de alambre, además de a vista final. Esa vista esquemática pueda ayudar a abstraernos de los detalles estéticos de la interfaz y permitir apreciar mejor la estructura de la aplicación, o el flujo de solicitudes y respuestas.

El desarrollo de una vista de alambre podría ayudar también a construir un mejor software.


2016/03/12

#NoEstimates

   

https://oikosofy.safechkout.net/NoEstimates-Book  

Un desarrollador (o su representante) conversa con el cliente (o su representante):

- ¿Qué es lo que se necesita hacer?
- ABC, ¿cuánto tiempo te tomará?
- x

Luego de x tiempo:

- Ya pasó x, ¿cómo vamos?
- Aún en la tarea
- Vamos retrasados

Finalmente:

- Ya está listo ABC
- Ok, pasa la prueba. Pero se atrasaron y%
- Ok, trataremos de hacerlo mejor

Situaciones de ese tipo se presentan durante el desarrollo de un producto y nos parecen normales. Sin embargo, expresan una serie de supuestos que no son necesariamente ciertos. Ni siquiera relevantes.

¿Qué es lo se necesita hacer?
Supone que el cliente (o su representante) saben lo que se necesita hacer. Casi siempre no es así, y determinar lo que se necesita hacer es algo que habrá que resolver. ¿Qué es lo que quieres resolver? suele ser una mejor pregunta.  

¿Cuánto tiempo te tomará?
¿Cuánto tiempo toma hacer algo? Si has hecho algo similar varias veces, puedes tener una idea. Pero como programador habrás experimentado que muchas veces hacer exactamente lo mismo, con la misma gente, toma un tiempo diferente. Algunas razones:
  • La programación es una actividad creativa
  • Las actividades creativas requieren una buena conexión con el subconciente
  • La conexión con el subconciente es sensible al humor, el stress, etc
  • Los equipos de trabajo están conformados por personas
Y, si nunca has hecho algo similar, quizás sientas que debas importar la respuesta que otro desarrollador similar, de otro equipo similar, para un cliente similar. Pero eso no es correcto por algunas razones:
  • El trabajo no lo va a realizar ese desarrollador ni ese equipo para tu cliente en tu contexto. Cada equipo es distinto y el rendimiento de un equipo es sensible al contexto.
  • En realidad, no estás seguro de que lo que hay que hacer sea similar a lo que ellos hicieron.
Cuando nunca has hecho algo similar, es necesario empezar a hacer y ver qué tal lo vas haciendo, antes de poder ofrecer alguna estimación sincera.

Vamos atrasados
Supone que la estimación fue correcta. Si hubieras dicho una cifra mayor estarías a salvo. Algo como el doble más el 10% más el número que pensaste. De hecho, muchos desarroladores, o sus representantes, usan ese tipo de tácticas para estar tranquilos; pero el cliente, o su reprepresentante, saben que puede pasar y entonces se produce un regateo de tiempos estimados.

Cualquier supuesto atraso o adelanto es irreal si la estimación no es correcta. ¿Es correcta la estimación? Ya vimos que no es posible que lo sea.

Imagina que un entrenador se acerca te mira y te dice 'mmm tu debes estar saltando unos 150 cm'. 'Sí señor', respondes, mientras le ayudas a colocar la valla. Tomas tu distancia, corres y saltas, llevándote la valla de encuentro. 'Qué mal' dice el entrenador. 'Sí señor', respondes. Si hubieran puesto la vaya a 60 cm hubiera sido 'Qué bien, excelente'. Así de absurda es la situación.

Sería mejor aprender a aceptar las capacidades reales de la gente y trabajar con eso, en lugar de intentar hacer pronósticos y calificaciones arbitrarias.

Además, considerar que, tanto para el clima como para los humanos, todos los pronósticos pueden fallar.

Aprendiendo a programar

Aunque términos como ingeniería de software y ciencias de la computación dan la impresión de que hay un dominio del tema, en realidad estamos aprendiendo a programar.

Quizás no se trata tanto de algoritmos óptimos, sino de encontrar un proceso sostenible que permita desarrollar sistemas también sostenibles. Lo óptimo será alcanzado eventualmente.

Persiguiendo la ilusión del óptimo inmediato es que se suele perder el camino, del mismo modo que un artista principiante que trata de hacer un cuadro trabajando perfectamente cada centímetro cuadrado, para lograr un resultado que no cuadra porque las partes no siguen un bosquejo que nunca trazó.

Encontramos buenas prácticas en programación imperativa. Pero el retorno de la programación funcional parece indicar que son soluciones creadas para problemas generados por usar el modelo imperativo en primer lugar. 

Así, estamos en camino de aprender el oficio de programar.

Programación mental

En los años 70, cuando los ciclos computacionales eran muy caros, nadie podía imaginar usar las computadoras para diseñar software. El software era diseñado en papel, para luego ser codificado por programadores y funcionara a la primera, si era posible.

En las escuelas de programación se incentivaba a la gente hacer todo en papel antes de escribir una línea de código. Correr una línea de código en una computadora era más caro que correrlas en la cabeza, así que los programadores usaban sus cabezas, y mucho papel, como simuladores de computadoras.

En los años 80, con el ascenso de la computación personal, hacer software se volvió una actividad comercial importante. Así que la industria y las universidades impulsaron más la creación de productos de software. Como venían haciendo, tratando de usar la experiencia que tenían en desarrollar otros tipos de productos. Sin embargo, la ejecución de los proyectos de desarrollo de software empezó a mostrar que había cosas importantes que funcionaban de modo diferente.

En los años 90, cuando los ciclos computacionales ya no costaban lo que antes, los programadores se dieron cuenta que tenía más sentido usar la misma computadora para explorar con ella las cosas que quisieramos que ejecute, en lugar de seguir intentando que nuestros cerebros traten de imitar ese proceso.

Considerar los icebergs y los andamios

Lo que se quiere desarrollar se puede representar con algo como:

No es cierto que alguien pueda desarrollar una versión final directamente. Similar a un iceberg, las 9/10 partes de lo que se tiene que hacer queda debajo de las aguas.


Los andamios son necesarios para levantar y producir lo que se verá. Es la infraestructura util que sin embargo será removida y descartada luego. La construcción de andamios también es parte de la producción de software.


Aprovechar la computadora para explorar

El software de hoy es más complejo que el de los 70s, cuando era normal instar a resolver el diseño primero en papel y simulando mentalmente los procesos que realizaría la computadora.

Hoy es mejor aprovechar la potencia computacional disponible.

TDD (Test Driven Development) es una técnica que construye cajas de prueba que determinan cuando el software está cumpliendo lo que se requiere. TDD promueve un proceso de descubrimiento para diseñar software.

Hay partes del diseño que se puede realizar con más flexibilidad mentalmente, pero hay otras donde es más razonable usar la computadora. Permitirse codear, fallando y acertando, explorando, ayuda a tener una mejor estimación. 

¿Es necesario estimar?

Los manejadores de proyectos han sido entrenados a resolver problemas con contextos definidos, desempeños uniformes y destinos determinados.

Por otro lado, la mayor parte del desarrollo de sistemas consiste en adaptarse a un contexto cambiante y manejar los desempeños irregulares hacia destinos inciertos.

Y es insistir en usar buenas herramientas en un contexto equivocado lo que conduce a muchos de los problemas en el desarrollo de software.

El uso de estimaciones es un ejemplo de eso. No es muy util tratar de estimar algo en un contexto con tanta variabilidad. Se convierte en una tarea ingrata que solo produce halagos o llamadas de atención completamente arbitrarias. Sin embargo, es algo que se sigue haciendo.

#NoEstimates, de Vasco Duarte, es un libro que habla sobre eso.

En el video, Vasco explica como las estadísticas de story points muestran un comportamiento irregular sobre el que es inútil tratar de hacer estimaciones.

En cambio, el número de historias que puede resolver un equipo por periodo muestra un comportamiento más regular.

Es decir, es irrelevante tratar de asignar puntos de dificultad a las historias.

Y parece ser que las estimaciones en desarrollo de software vendrían a ser un error metodológico.





2014/06/07

Git: Un Cuento de Tres árboles

Hoy vi una presentación muy iluminadora sobre git, Un Cuento de Tres árboles, por Scott Chacon:

ARCHIVOS: Es el árbol donde hacemos nuestros cambios
STAGE: Es el árbol intermedio, nuestro futuro commit
HEAD: Es el árbol del commit más reciente

Hacer

vim file.txt
  creo file.txt en ARCHIVOS

git add file.txt
  agrega file.txt al STAGE

git commit
  crea un nuevo commit con lo que esté en STAGE y lo hace HEAD

Deshacer

git reset --soft HEAD~
  deshace el último movimiento del HEAD

git reset HEAD~
  deshace el último movimiento del HEAD y copia el commit apuntado al STAGE

git reset --hard HEAD~
  deshace el último movimiento del HEAD, copia el commit apuntado al STAGE y también a ARCHIVOS

Diferencias

git diff
  muestra las diferencias de ARCHIVOS con STAGE

git diff HEAD
  muestra las diferencias de ARCHIVOS con HEAD

git diff --cached
  muestra las diferencias de STAGE con HEAD

Ver

cat file.txt
  muestra el contenido del archivo en ARCHIVOS

git show :0:file.txt
  muestra el contenido del archivo en STAGE

git show HEAD:file.txt
  muestra el contenido del archivo en HEAD

Fuente original: http://akcaprendiendo.blogspot.com/2014/06/git-un-cuento-de-tres-arboles.html

2014/01/23

Kanbiando con Kanban


Hace unos días, en mi trabajo, hicimos una actividad interesante.

Se propuso a los miembros del equipo un problema de programación no muy complejo. Se eligió un lenguaje de programación y una sola computadora, cuya pantalla se reflejaba en un televisor para todos, donde cada uno trataba de avanzar lo que pudiera durante 5 minutos.

Excepto el jefe, que debía mantenerse al margen haciendo intervenciones ocasionales, nadie más que quien estaba en su turno podía hablar, contando a los demás que iba haciendo y por qué lo hacía.

Además podía buscar en Google, y modificar o borrar el código previo.

Se sucedieron varias rondas y paso un par de horas sin que lográramos escribir una solución funcional.

Entendíamos la solución a la que queríamos llegar, y probablemente todos hubieran podido escribirla trabajando solos durante quince minutos o media hora. Pero, por alguna razón, no la lográbamos alcanzar.

Cuando terminó la jornada, me retire, pero el problema continuaba en manos que quienes podían quedarse.

Me sentía frustrado, pero, conforme pasaba el tiempo me iba sintiendo además instruido. Un problema simple y solucionable se había vuelto prácticamente irresoluble debido a las condiciones de trabajo impuestas.

Estas condiciones fueron tales que prácticamente anulaban la comunicación. Eso inhabilitaba el trabajo en equipo. Al menos, él trabajo en equipo usual.

Reflexionando, me di cuenta que, al inicio, nadie asumió el reto como un trabajo en equipo. Cada uno quería, de ser posible, terminar el problema en su turno.

Luego, cuando las primeras rondas iban mostrando que no sería tan fácil, apareció gente que prefirió hacer explícita una estrategia en lugar de programar. Entonces, el trabajo de todos empezó a encauzarse y parecía que se resolvería pronto. Nos estábamos adaptando.

Es allí donde el jefe cambió de pronto las reglas. Dijo que estaba clara la solución y que el reto sería ahora tratar de escribirla una sola persona, desde cero, en 5 minutos.

Además de transformar el problema en una competencia de tipeo, de entrada, eso destruía la comunicación incipiente que había surgido espontáneamente. Fue entonces cuando me retiré.

Camino a casa iba pensando que pasaría si esa prueba se repitiera cada semana. Creo que iniciaríamos sacrificando tiempo de programación para establecer mejor primero un marco de trabajo y luego la estrategia para resolver el problema. Y luego recién empezaríamos a codear.

Me pregunte luego cuántos proyectos habrá así en la vida real. Con gente competente y sin embargo sin avances significativos. Y todo por una organización contraproducente.

Deming, el padre de la mejora continua de la calidad, decía que el 95% del resultado éxito o fracaso se debía a la organización y solo 5% a la gente.

Pero no es obvio. Mucha gente tiende a culpar a la gente y lanzarse a tomar medidas correctivas en ese sentido. Llamadas de atención, recorte de privilegios, castigos, en el peor de los casos. Capacitaciones y coaching en el mejor de los casos.

Pero, si la causa es la organización, no se solucionará nada. A menos que se empondere a la gente para que la pueda mejorar.


Un par de días después, asistimos a un seminario sobre Kanban (la metodología de visualización de flujo de trabajo inspirada en las prácticas de Toyota).

Resulta que es una herramienta muy simple y poderosa para visualizar el estado del flujo de trabajo en una organización. Y para hacer evidentes sus virtudes y defectos.

Siendo evidentes los defectos, es más fácil proponer cambios de políticas e ir gradualmente cambiando la organización.

Yo pensaba que venía utilizando Kanban, al menos en mis proyectos personales. Descubrí que lo estaba haciendo de modo incompleto. Para que Kanban haga su magia, es necesario hacer hacer explícitos los límites de trabajo en progreso (WIP, por sus siglas en inglés) y las políticas de aceptación de tareas.

Ahora estoy leyendo y aprendiendo más al respecto. Un libro que me parece sumamente útil y fácil de leer es "Scrum y Kanban: Usando lo mejor de ambos", de Henrik Knigerg y Mattias Skarin.

Estoy viendo que podría usarlo también para mejorar mi forma de estudiar... y hasta para procesar con más eficacia las montones de cosas que quiero hacer en la vida (Personal Kanban)

Una gran virtud de Kanban es que te permite iniciar como eres ahora, con lo que tienes ahora.

Viva Kanban \(^_^)/

2014/01/06

Justo a Tiempo

Just In Time (Justo a Tiempo), JIT, es una filosofía de producción.

Sus principios se basan en los que empleaba Toyota en los 1970, pero adecuados a occidente.

En el libro "Justo a Tiempo", de Edward J. Hay, mencionan que algo principal en JIT es la eliminación de desperdicio.

Los japoneses definen desperdicio como "todo lo que sea distinto de la cantidad mínima de equipo, materiales, piezas y tiempo laboral absolutamente esenciales para la producción".

A Hay le parece que determinar lo que es absolutamente esencial es subjetivo y redefine el desperdicio como "todo lo que sea distinto de los recursos mínimos absolutos de materiales, máquinas y mano de obra necesarios para agregar valor al producto".

Estoy leyendo sobre JIT y otros temas de metodologías ágiles porque estoy interesado en hallar mejores formas de desarrollar software en equipo.

En mi caso, la definición original de desperdicio, como aquello que no es el mínimo esencial para producir algo sí tiene mucho sentido.

En TDD, se va escalando sobre mínimos necesarios para producir algo. Cada escalón debe ser trivial respecto al anterior. Nada de considerar posibles mejoras por adelantado. Nada de generalizaciones antes de tiempo. Nada de de optimizaciones prematuras. Primero, lo mínimo necesario para que funcione. Las optimizaciones llegan a través de reflexión y refactorizaciones.

La definición japonesa de desperdicio la entiendo muy bien en ese contexto.

En cambio, la definición de Hay, como aquello que no agrega valor al producto, me parece contraproducente. Y realmente subjetivo, al menos desde el punto de vista de TDD.

Porque no faltarán clientes, jefes de producto o jefes de equipo que insistan en incluir por adelantado una funcionalidad X porque opinan que eso agrega valor al producto (y no están pensando en el producto actual sino el que está dos ciclos adelante, o incluso el final, o más allá...).

En cambio con la definición original uno está a salvo: ¿es absolutamente necesario para que funcione ahora? No. Entonces lo anotamos en la lista de deseos, pero la implementaremos cuando sea su momento, no antes.

Bueno, eso esta es una nota en el camino... continuaré leyendo el libro...  :-)




2013/11/06

El lenguaje de programación correcto

"Las especies que sobreviven no son las más fuertes, sino las que se adaptan mejor al cambio"
-- Darwin

En internet, parece ocurrir algo similar. No prosperan los lenguajes de programación que te hagan más fuerte, sino los que te permitan adaptarte mejor al cambio... en cierto ambiente.

Por ejemplo, php es popular en proyectos educativos y sociales. Java es popular en proyectos empresariales. C es popular en proyectos técnicos. Otras alternativas importantes son Python, Ruby, etc.

Muchas personas tienen sus preferencias y a veces tienden a tomar posiciones, pero es importante ver más allá y recordar cuál es la razón por la que programamos.

Cada lenguaje existe por alguna razón. Porque de algún modo es la mejor respuesta para cierto problema. Porque es la mejor especie en cierto ambiente.

Pienso que no hay una solución "correcta" ni una manera "correcta" de hacer las cosas universalmente. Cada problema contiene su solución, y es importante estar atento a la solución que te está cantando el problema, en lugar de pretender que escuche la que nos gusta cantar.

Así podemos aprender nuevas canciones :-)

¿Cuánto puede mejorar tu software? ¿Qué tan clara es la especificación? A más ciclos de desarrollo, más probabilidad de acercarse al ideal.

¿Cuántos ciclos de desarrollo puedes realizar? ¿Qué tan sencillo es de iterar o incrementar? A más contribuyentes, más probabilidad de encontrar excelentes contribuciones.

¿Cuántos contribuyentes puedes encontrar? ¿Qué tan sencillo es comunicarse? Hay más probabilidad de encontrarlos si los lenguajes son más atractivos, los entornos de desarrollo más asequibles, el camino de inicio más motivador.

Quizás por eso un lenguaje de programación no tan fuerte puede a veces llegar tan lejos. Es importante tener en cuenta el ambiente para prosperar.

2012/01/20

En el Dojo

Hoy asistí a un dojo de programación. Me ha parecido una experiencia muy enriquecedora.

Un dojo de programación trata de seguir la idea de un dojo de artes marciales en cuanto a formar un ambiente donde podamos ejercitarnos fuera de la contienda real (que viene a ser el día a día con los proyectos que desarrollamos).

La práctica se trató esta vez de usar TDD y una especie de Pair Programming para resolver el problema de convertir números arábigos, los que usamos normalmente, a la notación romana.

TDD son las iniciales de Test Driven Development, Desarrollo Guiado por Pruebas. Pablo Tortorella, quien nos guiaba, dijo que le parecía mejor pensar en Desarrollo Guiado por Ejemplos, ya que una prueba es en realidad un caso particular que ponemos como ejemplo para que el programa que hacemos lo intente resolver. Un ambiente de pruebas toma la prueba y la lleva a cabo a ver si el programa la pasa. Entonces, en TDD: 1) definimos una prueba simple 2) corremos la prueba (incluso sin tener ningún programa; es importante ver que falla) 3) se enfoca uno en implementar en el programa lo mínimo necesario hasta lograr pasar la prueba 4) si se nota que algo puede refactorizarse (simplificar, eliminar duplicaciones o dependencias innecesarias), hacerlo, luego pasar al paso 1) e ir repitiendo el ciclo, con pasitos de bebe, dejando que el programa evolucione hasta el nivel que deseemos.

Para alguien habituado a programar al estilo tradicional, donde se pretende resolver todo el problema en la fase de diseño, antes incluso de empezar a programar, puede costar un poco enfocarse en pequeños pasos y no intentar codificar toda la solución de una vez. Pero el estilo tradicional realmente tiene problemas. Precisamente en respuesta a esos problemas surgieron cosas como la eXtreme Programming, TDD y Agile.

En el caso del problema de la conversión a números romanos, probablemente uno imagine ahora, sin necesidad de programar, una manera de resolver el problema y podría programarla en un rato. Pero, deténgase y trate de hacerlo en pequeños pasos, ideando una prueba simple y trivial cada vez, para ver a dónde va conduciendo.

Con el dojo me di cuenta que, conforme avanzan las iteraciones, van apareciendo patrones que van sugiriendo la solución. El tiempo de la práctica se acabó, pero creo que eventualmente llegaríamos a solucionar el problema.

Camino de regreso, recordaba la forma en que el código iba proponiéndose y refactorizándose. Había cierto algoritmo en eso. Me pregunto si sería posible programar a una computadora para que halle esa solución evolutiva usando TDD. Quizás sí. Entonces, me pregunto si sería posible que una computadora, o un conjunto de computadoras, realizando pequeños pasos de bebe, resolviendo casos triviales, puedan resolver cualquier tipo de problema de programación, simplemente por evolución, usando TDD. Me pregunto si será ese el futuro.

Crédito de la imagen: CIO Dojo

2010/09/08

Ágiles 2010: 3ras Jornadas Latinoamericanas sobre Metodologías Ágiles

Ágiles 2010 es una excelente oportunidad para encontrase con
profesionales de IT de la región, interesados en compartir sus
experiencias, debatir y capacitarse en temas relacionados con el
desarrollo de software a través del uso de metodologías ágiles.

Esta tercera edición, con sede en la ciudad de Lima, Perú, contará
con la presencia de especialistas locales e internacionales, quienes
compartirán su conocimiento durante los cuatro días que durará el
evento.

El programa incluye distintos tipos de actividades: presentaciones,
sesiones interactivas, talleres y espacios abiertos de debate.

Entre los invitados internacionales se encuentran los keynote
speakers Lee Devin y Joshua Kerievsky, que también estarán brindando
cursos durante el evento.


¡Inscríbete y se parte de Ágiles 2010!

2010/04/18

Un esquema para desarrollo

Lo empírico y lo convencional

He observado que, cuando hay una solicitud para hacer un sistema, mucha gente se esmera por seguir lo mejor posible cierto modelo de desarrollo. Pero se suele perder en el bosque, porque caminar con ahinco no garantiza que la dirección sea la correcta.

Cuando algo va mal, casi siempre es posible culpar a la gente. Que no se aplicó el modelo como debía ser. Cómo rebatir eso. Sin embargo, algo hay que hacer. Consideremos que el modelo de desarrollo pueda no ser tan bueno como pensamos. Y probemos.

En la forma empírica, uno empezaba directamente programando, y adaptando el código poco a poco. Se siente bien recibir el feedback de la computadora con cada paso.

Cuando uno estudia, le enseñan que es mejor determinar cuál es el problema y modelar cuál es la solución, antes de empezar a programar.

Si le preguntan a un desarrollador profesional típico, dirá que es mejor la segunda forma, la forma convencional. Yo no estoy completamente de acuerdo. Ni tampoco completamente en desacuerdo.

La forma convencional está bastante influenciada por la necesidad académica de poder evaluar a los estudiantes. Es más fácil hacerlo cuando explicas de antemano qué es lo que pretendes hacer antes de hacerlo. La solución se puede documentar, evaluar, optimizar, etc.

Esto también le es util al mundo. Cuando una empresa solicita un sistema, la forma convencional permite estimar el costo de antemano. Con esta venia, la forma convencional queda santificada en la currícula. Después de algunos años de ser condicionados haciéndolo de ese modo, también acabamos santificándolo nosotros.

Es un poco difícil cambiar las cosas santificadas, pero a veces hay que considerar los hechos.

En el mundo real, la conocida frase 'el cliente no sabe lo que quiere' refleja el hecho de que a menudo es muy difícil precisar el problema de antemano. Y, debido a eso, aún cuando el modelado fuera perfecto, nada garantiza que el producto final sea satisfactorio.

La mayoría de proyectos de desarrollo de software fallan. Se exceden en el tiempo, no satisfacen al cliente, o ambas cosas. Si la forma convencional estuviera en lo cierto, eso significaría que la mayoría de la gente no lo aplica bien, y no creo que ese sea el caso.

Pienso que no es culpa del cliente, ni de quien reune sus requerimientos. Sino que la causa es que no tenemos aún un método que permita precisar de antemano problemas que excedan cierta complejidad.

Cuando los problemas son relativamente sencillos, o han sido ampliamente recorridos, puede funcionar la forma convencional, pero no cuando los requerimientos son imprecisos y deban descubrirse sobre la marcha. Lo cual ocurre en prácticamente todos los desarrollos (quizás deberíamos reflexionar en el desfase académico sobre esta cuestión).

La prueba que guía

Cuando uno programa, hace pruebas para estar seguro que lo que se acaba de hacer hace lo que se espera. Es relativamente sencillo probar una función o módulo y más complicado probar un caso y aún toda la aplicación. Sin embargo, es necesario, si se quiere minimizar el número de errores que puedan llegar a la versión que probará el usuario.

Las pruebas unitarias permiten usar la computadora para probar una función. Diseñando y agrupando convenientemente las pruebas se pueden probar módulos, casos y hasta la aplicación completa. Esto hace más llevadero el proceso, hasta el punto en que se pueden usar como guía para el desarrollo.

Usar las pruebas como guía para el desarrollo, o Test Driven Development (TDD), es desarrollar primero la prueba que debe pasar el producto, y recién después el producto.

Las pruebas se van implementando según se van determinando los casos de uso.

La primera vez que se corra la prueba, sin ningún producto desarrollado, aparecerá una señal roja. Entonces el desarrollo se convierte en el juego de descubrir el camino más corto, lo mínimo necesario, para que la señal se vuelva verde. Así, el producto reflejará lo que la prueba requiera. La prueba sirve como guía para el desarrollo.

Modelar es optimizar

Con TDD, la optimización se posterga todo lo que sea posible, ya que la optimización prematura fácilmente conduce a compromisos y enredos innecesarios.

Cuando un producto pasa las pruebas, se puede refactorizar con seguridad. Es decir, se puede intentar ya sea cambiar el nombre de una función, extraer un fragmento de código para formar una función, reagrupar funciones en nuevas clases, etc. Si todo va bien, las pruebas continuarán mostrando la señal verde. Y si la señal es roja, no hay problema, podemos usar un sistema de control de versiones para deshacer los cambios y volver al último punto donde todo era verde.

Así, es más natural que el modelado vaya apareciendo en este punto. Si el modelado está bien, las pruebas lo dirán. En TDD, la principal guía del modelado es evitar las repeticiones y los acoples de código. Las repeticiones son código que se nota se puede factorizar (una idea similar al del álgebra, que extrae aparte los términos comunes), usando funciones, clases, o herencia. Los acoples ocurren cuando hay una dependencia innecesaria entre dos fragmentos de código. Es mejor cuando cada fragmento de código se pueda reemplazar sin peligro de efectos inesperados en otra parte.

Un esquema para desarrollo

En la forma de desarrollo empírica se sentía bien el feedback que daba la computadora en cada paso. TDD tiene algo de eso.

El modelado previo de la solución, aunque quizás correcto académicamente, no funciona demasiado bien en el mundo real. Y tiene, además, el efecto de contenernos las ganas. No soltamos el corcel hasta que tenemos listo el arado. Pero, entonces, ya no es divertido salir a correr si hay que arrastrar un arado al mismo tiempo. Es mejor ir ligeros desde el principio, aceptar los hechos, ser prácticos, y actuar en consecuencia.

Parece que desarrollar un sistema con requerimientos imprecisos es algo que necesariamente debe resolverse sobre la marcha, en un proceso de prueba y ajuste.

El siguiente es un esquema que toma varias ideas de Scrum y otras metodologías:

  • El proceso es de prueba y ajuste. El equipo de desarrollo y el cliente deben estar abiertos al cambio, a  probar, equivocarse y corregir. El ambiente debe aceptar los errores como parte del proceso.
  • El punto de vista del cliente debe estar presente en el desarrollo. Como a menudo es difícil que pueda participar, se designa un intermediario. Puede ser una persona o un conjunto de personas, pero con una sola cabeza para la comunicación y la asignación de responsabilidades.
  • Se elije cuanto tiempo debe durar la etapa. Es más o menos al azar la primera vez. Entre 2 y 4 semanas.
  • Basado en el punto de vista del cliente, se obtiene un conjunto de requerimientos que podría esperarse estuvieran listos en esa etapa. Es más o menos al azar en la primera etapa. Los requerimientos parten de deseos del cliente. Finalmente cada uno se expresa como algo que cierto rol usa para realizar cierta tarea.
    Cada requerimiento tiene un por qué, que a su vez tiene una justificación, y así sucesivamente. La cadena se puede seguir hasta un conjunto de principios más o menos estables que constituyen la necesidad que justifica el desarrollo.
    Conforme avance el desarrollo estos principios y la jerarquía de justificaciones se irá haciendo más clara.
    Luego, habrán requerimientos que no se admitirán porque no encajan en ese orden y, del mismo modo, podrán descubrirse requerimientos que inicialmente no se consideraron pero que son necesarios.
  • Basado en los requerimientos, el equipo hace una lista general de las tareas que estos requerimientos implicaría. Es una lista libre, donde cada uno puede anotar sin censura. Es además una lista abierta, que admitirá nuevos ingresos en cualquier lugar de la etapa. La lista debe ser visible, de libre acceso y fácil de mantener.
  • Antes de procesar la lista, el equipo reunido hace una lectura rápida de todas las tareas, simplemente para informarse de cuales son, y las agrupa en páginas de cierto tamaño. Esto es más o menos arbitrario. Puede ser un número entre 10 y 30 items por página.
  • Para procesar la lista, se hace un repaso tarea por tarea. Cuando uno o más miembros del equipo sienten que pueden atender una tarea, se pone a trabajar en ella durante el tiempo que consideren conveniente.
    Si la tarea se completa, se tacha de la lista y se continúa el repaso hasta interesarse en alguna tarea. Si la tarea no se completa, se la vuelve a anotar al final de la última página, luego se tacha la anotación original y se continúa el repaso de tareas a partir de esa posición.
    Al llegar al final de la página, se vuelve al comienzo.
    Si se hace un repaso y ninguna tarea pendiente parece interesante de atender, todas ellas se resaltan y se coloca una X en una esquina de la página, antes de pasar a la siguiente página.
    Al llegar al final de todas las páginas, se vuelve a la primera.
    Puede ser ninguna de las tareas pendientes, que ahora estan resaltadas, sea interesante, porque no son realmente necesarias en ese momento. Si es así, la X se encierra en un círculo, para facilitar saltearse esas páginas la siguiente vez.
    Las tareas urgentes se anotan al final de la lista y se procesan en dirección inversa, empezando desde el final.
  • La optimización se retrasa todo lo que sea posible. El código optimizado frecuentemente se hace más difícil de entender y reutilizar. Es conveniente que las abstracciones, simplificaciones, y generalizaciones se hagan lo más tarde posible. Y es en la optimización del modelo donde recién entraría a participar el arquitecto. Viendolo bien, un modelado apriori, como en la forma convencional, en realidad "contamina" la lista de requerimientos del cliente con la lista de requerimientos del arquitecto. En cambio, al hacerlo durante la refactorización del código, se hace sobre cosas que realmente se necesitan.
  • Para saber quién atiende cada tarea, y cuál es el estado actual del proceso, se pueden colocar marcadores removibles sobre los items de la lista.
  • Al inicio de cada semana, el responsable del equipo de desarrollo se reune en privado con cada persona para tener una visión de cómo está cada una y qué está haciendo. Hay cosas que se expresan mejor sin la presión del grupo.
  • Al inicio de cada día, el equipo dedida unos minutos en contar a todos que hicieron ayer, que harán hoy, y si tienen alguna dificultad. Hay cosas que es necesario que todos conozcan.
  • Al final de cada etapa se hace una evaluación de ese periodo. Ver qué cosas funcionaron bien y qué cosas podrían mejorarse.
  • En cada nueva etapa, se ajusta la duración del periodo y el tamaño de las páginas de la lista de tareas. También se borran todas X de las páginas con tareas pendientes, para incorporarlas nuevamente al proceso.

Cómo funciona

La forma de procesar la lista de tareas está basada en el sistema Autofocus, de Mark Foster.

La idea de dejar que el equipo atienda las tareas que les resultan interesantes es permitir que se desarrolle un inconsciente colectivo que ayude a determinar cuáles son realmente necesarias.

El sistema funciona como un ambiente que sólo deja sobrevivir aquellas tareas realmente necesarias para determinar el sistema. Es decir, el sistema se determina de modo evolutivo. Por eso, se da la libertad de anotar en la lista lo que sea, porque si no vale la pena hacerlo nadie lo hará, y si es necesario, tarde o temprano sucederá.

No es necesario gastar tiempo discutiendo cuales son las tareas, en qué orden hacerlas y quién las atenderá. El sistema facilita que estas cosas se resuelvan espontáneamente.

Ahora, a probar.

Enlaces: