Angel "Java" Lopez

NET, Java, PHP y Desarrollo de Software

This Blog

Syndication

Search

Tags

Community

Email Notifications

Archives

.NET

ASP.NET

Windows Form

VB.NET

C#

Sitios

Blogs

Introducción a Python, en Buenos Aires

Gracias a la gente del MUG (Microsoft User Group) de Argentina, el próximo 1ro. de Julio voy a dar una charla gratuita de introducción a Python, para programadores.

Más información, y registración, en:

http://www.mug.org.ar/Eventos/3907.aspx

La idea es similar a mi charla sobre Ruby: presentar el lenguaje Python, para los que saben programar pero no conocen Python. Vamos a visitar con ejemplos:

- Sintaxis básica
- Primeros comandos
- String y números
- Estructuras de control
- Clases y objetos
- Entrada y salida
- Paquetes, instalación, ecosistema
- Elementos de desarrollo web (espero comentar WSGI, Flask y Django, veremos cómo responde el tiempo)

Como otras veces, publicaré por acá el material (presentación, enlaces, ejemplos) utilizado.

Nos leemos!

Angel "Java" Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

 

Posted Tue, Jun 18 2013 16:45 by lopez | with no comments

ObOps: Operadores para Objetos

En varios de mis proyectos open source de intérpretes, uso una librería Microsoft.VisualBasic que tiene un namespace Microsoft.VisualBasic.CompilerServices con una clase Operators que implementa operaciones sobre objetos cualesquiera. Por ejemplo, puede sumar dos objetos, sin saber de antemano qué tipo tienen (enteros, dobles, strings) cada uno de los dos parámetros. La comencé a usar ya debe ser casi una década, y fue una de las razones para escribir AjGenesis directamente en Visual Basic.NET: me permite escribir

obj1 + obj2

sin saber los tipos de antemano. Como AjGenesis compilado en Windows, corre tal cual en Mono, me confié que los métodos de esa clase Operators estaban disponibles en otras plataformas. Así que escribí varios intérpretes usando esa clase.

Pero ahora que estoy escribiendo Mass, el bueno de @MartinSalias me cuenta por un mensaje de Twitter, que no hay Microsoft.VisualBasic.CompilerServices.Operators en Mono.

Leo en:

http://www.mono-project.com/FAQ:_Technical

With regards to languages, C# applications tend to be most portable. Visual Basic .NET applications are portable, but Mono's Microsoft.VisualBasic.dll implementation is incomplete. It is recommended to either avoid using this assembly in your own code, only use the portions that Mono has implemented, or to help implement the missing features. Additionally, you can set 'Option Strict On', which eliminates the implicit calls to the unimplemented Microsoft.VisualBasic.CompilerServices.ObjectType class. (Thanks to Jörg Rosenkranz.)

Así que no puede compilar la solución. En estos meses, estoy ocupado preparando tres charlas (dos ya las dí: Node.js, Ruby; ahora dentro de poco, viene la tercera, Python) con sus respectivos ejemplos y presentaciones. Pero igual pude hacerme un tiempo para comenzar a implementar algo en C# para subsanar la falencia:

https://github.com/ajlopez/Obops

Traté de implementar algún tipo de “double dispatch” o algo parecido, usando generics y demás, pero parece que no hay tu tía. Mi investigación en:

https://github.com/ajlopez/Obops#references

Así que comencé a implementar los operadores aritméticos binarios, uno a uno:

https://github.com/ajlopez/Obops/blob/master/Src/Obops/Operators.cs

Pero no crea que todo lo hice yo. Como vi que había una explosión de combinaciones, decidí pasar, luego de tener algunos casos implementados, a la generación automática de código. Pueden ver el modelo, las plantillas y tareas en:

https://github.com/ajlopez/Obops/tree/master/CodeGen

Tengo que explicar ahí más en detalle como lo consigo, pero es, teniendo AjGenesis bin en el PATH, cosa de hacer:

AjGenesis.Console Model.xml Operators.tpl Operators.cs Tests.tpl Tests.cs

Así de simple. Ya lo comencé a usar en Mass:

https://github.com/ajlopez/Mass

Pero falta:

- Implementar más operadores

- Habilitar la configuración por código desde afuera (por ejemplo, para sumar null + entero, usar tal función)

- Agregar tests que prueben el resultado contra la implementación original de Microsoft.VisualBasic

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sat, Jun 15 2013 15:30 by lopez | with no comments

Reuniones en Buenos Aires: Agiles, Java, Scala, Node.js, Amazon Web Services, Emprendedores, Dorkbot (y no, no hay Ruby)

Ya saben, lo mío es un apostolado ;-) y cumplo con avisar las reuniones que tenemos en Buenos Aires. Vienen moviditos estos días que viene en cuestión de reuniones.

Tenemos:

Conociendo Agile Inception

http://www.meetup.com/agiles-bsas/events/123502422/

Martes 11 de Junio, 19 a 20:30 hs

Startup Dating

http://www.meetup.com/Emprendedores-IT/events/118372702/

Jueves 13 de Junio, 19 a 22 hs.

Node.js y 0MQ (Zero MQ)

http://www.meetup.com/NodeJS-Argentina/events/122799652/

Viernes 14 de Junio, 19 a 20:30 hs (iba a darse el jueves, pero alguien sin familia la pidió correr para el viernes ;-)

What You Need to Now About Lambdas

http://www.meetup.com/jugargentina/events/123258102/

Lunes 17 de Junio, 18hs, en MuleSoft (acá seguro que hay cerveza!!!)

Efective Actors in Scala by Jamie Allen

http://www.meetup.com/play-argentina/events/123156232/

Martes 18 de Junio, 18:30 hs, en los Zauber Labs (habrá cerveza? ;-)

Real-World Akka Recipes

http://www.meetup.com/scala_ar/events/124498012/

Miércoles 19, 19 hs (en este parece que hay cerveza porque ya está todo cubierto ;-)

Amazon Web Services: Reunión Junio "Basta de intros, vamos a los papeles"

http://www.meetup.com/AWS-User-Group-Buenos-Aires/events/118799742/

Viernes 28 de Junio, 19 hs, Global NorthPark (que a mí me queda en la loma del c… ;-) bueno, es donde trabaja y vive @sbassi; puede que se jueguen y haya cerveza, como en otras reuniones de Globant

Dorkbot @ BsAs

http://tratadodeintegracion.cc/openmedialab/Dorkbot/DorkbotBa04

Sábado 29 de Junio

DSLs y Template Engines: Introducción e implementación de Handlebars.java

http://www.meetup.com/jugargentina/events/122234702/

Miércoles 3 de Julio, 18:30

Después no digan que no les avisé!

Pensando en todos Uds., pregunté y pregunté sobre meetup de Ruby:

https://groups.google.com/group/rubysur/browse_thread/thread/b50ad70ee5f7c4b7

pero recibí como respuesta: cri, cri, cri. Deben estar muy ocupados juntándola con pala haciendo sitios con Rails o Sinatra ;-)

Los de Python, por acá, no hacen reuniones cortas, sino mas bien, reuniones de uno (PyDay) o varios días (PyCamp). Vean algo del último PyDay en Rosario:

https://delicious.com/ajlopez/rosario+python

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Mon, Jun 10 2013 9:52 by lopez | with no comments

Un Buen Proyecto (3)

Anterior Post

En los anteriores posts quedó claro que, en mi postura, lo importante de un proyecto es que resuelva (o ayude a resolver) el problema del cliente.

Bien, ¿dónde queda todo lo que aprendemos de patrones, OOP, y demás?

Imaginemos que tenemos que desarrollar un sistema que nos diga cual es el número de la lotería de este sábado que viene. Nada más: el cliente nos lo pide, para solucionar el problema “No tengo dinero para encarar otros proyectos e ideas que tengo”. Hacemos el programa, funciona y resuelve el problema del cliente: la falta de dinero.

¿Acaso a alguien le importa los patrones, OOP, SOLID o lo que sea? NO. Solamente importan en dos circunstancias:

- Porque nos ayudan (a nosotros, no al cliente) en el desarrollo actual

- Porque van a ayudar a la gente que haga la versión 2.0 de lo que estamos haciendo

Los patrones son para los programadores. Si el sistema lo armamos de una vez, y funciona, a nadie en el planeta la importaran los patrones que usamos. Mientras nos de el número de la lotería que el cliente necesita, estará todo bien.

Solamente interesa YAGNI, DRY (Don’t Repeat Yourself) y demás en esas dos ocasiones:

- Para nosotros, cuando estamos desarrollando y queremos refactorizar algo.

- Para quien venga luego de nosotros, en la versión 2.0, a mejorar, extender, adaptar lo que armamos.

Ejemplo del primer caso: imaginemos que el algoritmo que estamos usando tiene código repetido. Aplicamos DRY y refactorizamos, sólo para seguir avanzando en el desarrollo. Sino, no hace falta refactorizar. Si así como está, la aplicación ya funciona, a nadie le importa los patrones o cualquier otro factor de diseño que se nos ocurra. “Make it works”, lo primero que hay que obtener.

Pero si vemos que todavía no alcanzamos el objetivo, podemos refactorizar y mejorar la implementación. Es una especie de “Make it right”. Al tener ordenado y “patronizado” lo que estamos armando, es más fácil, en general, irlo modificando.

Si no entendemos eso, no sirve de nada saber patrones. Los patrones se aplican EN CONTEXTO, y para resolver un PROBLEMA en particular. No porque son “cool” o es lo que dicen los librso.

Ejemplo del segundo caso: si nuestro sistema es un ERP, que solamente contemplaba algunos casos de uso, en la versión 2.0 es posible que necesite cubrir otros nuevos casos. Es ahí donde se ve el poder de haber “patronizado” la versión 1.0. El mantenimiento, la extensibilidad, la refactorización será más fácil para el que venga. Recuerden: hay que codificar como si el que vieniera luego de nosotros, sea un asesino serial que conoce el domicilio de nuestra familia ;-) Tenemos que facilitarle el trabajo.

Por supuesto, no todo es codificación en un proyecto. Hay comunicación, explicar lo que estamos haciendo, su adopción, despliegue, etc... Pero antes de proseguir sobre el tema “proyecto bueno”, quería hacer esa aclaración: muchas de las “best practices” que adoptamos son para encarar de forma efectiva la refactorización actual, o la modificación futura. Si no necesitáramos refactorizar ahora (por ejemplo, escribiendo todo bien desde el principio), o no se necesitara la modificación futura (sistemas “one shot”, como obtener el número de la lotería del sábado que viene y nada más), no tendríamos que preocuparnos por patrones o “best practices”.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sat, Jun 8 2013 18:30 by lopez | with no comments

Optimizando el modelo en memoria

Ya saben que soy partidario de explorar el tener el modelo de lo que estas armando en memoria. Luego viene la persistencia, y quizás esa persistencia vaya a una base de datos relacional. Pero no hay que estar desde el comienzo limitados a tener una base de datos a consultar con SQL o un ORM. Si trabajamos ágilmente también podemos diferir esas decisiones sin afectar al proyecto.

Lo que escribo hoy, se refiere a algo que encontre hace un tiempo, en un proyecto privado (así que no puedo dar mucho detalle). Y no era código de una aplicación, sino mas bien, de un utilitario de transformación de datos que se ejecuta diariamente (un ETL).

Lo que importa es que en el código me encuentro con un dominio en memoria (yo había recomendado tempranamente ese camino, no participé de la implementación inicial). Y con un for como (disfrazo el código, era paracido a éste):

for (var invoice in domain.Invoices)
    invoice.Customer = domain.Customers.Where(c => c.Id == invoice.CustomerId).FirstOrDefault();
    

En realidad eran dos, y repetidos en dos lugares distintos del código. Pero lo importante a ver es que lo de arriba funciona bien. El problema aparece cuando se ejecuta sobre datos reales. En el proceso que se ejecutaba diariamente, los clientes eran, digamos, 100000, y las facturas 600000. El ciclo de arriba TARDABA MAS DE UNA HORA: el Where se ejecutaba 600000 veces y cada evaluación del mismo recorría en promedio 50000 clientes.

Cuando llegó a mí el proyecto, en una de las revisiones, veo ese ciclo, y lo refactoricé a:

for (var invoice in domain.Invoices)
    if (domain.CustomersById.ContainsKey(invoice.CustomerId))
        invoice.Customer = domain.CustomersById[invoice.CustomerId];
            

Es decir, a mantener un diccionario por Id de los clientes. El proceso completo pasó a tardar menos de 10 minutos, y haces, menos de 5 minutos (y el ciclo de arriba es prácticamente “instantáneo” cuando antes duraba más de una hora). Se siguen recorriendo 600000 facturas, pero ahora hay un “lookup” rápido, en vez de un Where de LINQ.

¿Estaba mal el primer “approach”? NO, ESTA BIEN, funciona. Pero luego, no es lo suficientemente rápido para lo que necesitamos. El tener el proceso corriendo más de una hora afectaba a otros procesos. Y también afectaba algo de su lógico interna. La cuestión que se puede mejorar con el segundo “approach”, y así se hizo.

Siguiendo una frase atribuida a Kent Beck: "make it works, make it right, make it fast”. En este caso, lo de “fast” quedó para lo último. No hay que optimizar prematuramente. Pero cuando LUEGO DE MEDIR (no antes) se ve que algo no funciona como esperábamos, se puede plantear el refactor o reimplementación para mejorar velocidades.

En otro caso, tenía llamadas a una API REST, digamos con un dato a dar de alta. Como había que dar de alta a veces 20 relaciones, se llamaba a la API 20 veces. Cuando se vió (y se midió) que eso tenía su costo en tiempo, pude refactorizar a enviar 1,2 o 3 mensajes con más información, en vez de veinte mensajes. Pero esa refactorización tuvo su costo: hubo que programarla (con un algoritmo del que estoy particularmente orgulloso, agrupando dinámicamente datos ;-). Por fortuna, todo estaba escrito en este caso con TDD, así que sólo se tardó un par de horas (y un buen desayuno pensando el algoritmo ;-).

En cambio, la mejora de más arriba (el implementar un diccionario y cambiar el ciclo) no fue tan fácil. Si bien había tests en el proyecto, no fue armado TODO con TDD, donde cada línea de código de producción aparece por algún test que se haya escrito. Sólo una parte estaba con TDD, y el resto eran mas bien test unitarios con mocks que trataban casos con pocos datos. Por ejemplo, tuve que revisar donde agregar los clientes al diccionario, porque se agregaban clientes en varios lugares del código, en lugar de tener un domain.AddCustomer o algo similar (eso sería el “make it right” de Beck, pero nunca pude llegar a eso en este caso). Creo recordar que a propósito, implementé el ciclo mal, corrí los tests, y daban todos en verde. Nunca se había ejercitado esa parte del programa. Así que tuve que compilar, copiar a algún ambiente con datos, correr el programa, revisar el resultado, etc, etc…

Moraleja:

- Optimizar sólo cuando sea necesario

- Programen con TDD

- Programen con TDD

- Programen con TDD

- ;-)

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Fri, Jun 7 2013 10:38 by lopez | with no comments

Filed under: , ,

Aplicaciones Sociales y Dispositivos Móviles

Hace ya unos meses “se discutió” en la lista de HacksHackersBA la programación de uno de los proyectos presentados. Me temo que escribo “se discutió” porque si bien el tema era interesante, no parece que la programación sea uno de los temas de la lista, así que nos llamaron al orden (ver mensaje). Los mensajes de programación ahora no los encuentro, así que se los debo.

El proyecto presentado tampoco ahora está en línea, así que les cuento lo que recuerdo. Trataba de conseguir los precios de los supermercados (acá en Argentina), haciendo scraping de datos de las páginas de esas compañías. En la discusión en privado, yo sugerí:

Hacer que la gente pueda subir precio, producto, quizas foto, y el lugar

Sino, pasa que en tal super dicen que la leche esta a 2 pesos, pero a las 9:30am ya se agoto.

El problema de mi "approach", hay que conseguir masa de gente

Pero hay que ir pensando en aplicaciones DONDE LA PROPIA GENTE sea la generadora de contenidos

Alguien comentó: “es difícil conseguir tanta gente subiendo precios”. Yo sugerí:

un sistema de ciudad abierta:

- La gente informa que funciona o no funciona

Los precios serian una de las cosas

Podrian reportar baches, congestiones de transito por reparaciones (algo que el gobierno de Buenos Aires no parece publicar, te enteras cuando llegas), cortes, precios en super, escaleras mecanicas de subte que no andan, trenes atrasados, etc

Ahi abria un publico mas amplio.

Escribo en "voz alta" ;-)

Una en que la gente no tendria que actuar directamente, pero que se puede sumar:

- Informacion de GPS de una flota de vehiculos. Por algo de algoritmo, se puede ir detectando (por el movimiento o detencion) las zonas con congestion de transito

 

El gran tema es: que la gente participe. Si tiene un “smartphone” mejor, puede dar visibilidad por medio de fotos de lo que está pasando, por ciudad, por tema (precios, baches, subte (metro en Buenos Aires), etc…). Y que actuar sea fácil: tomar la foto, la subo, y “chau pinela” (#soytanviejo ;-). Autenticación via Twitter, Facebook, simple registración, y anónimo. La clasificación del tema (ciudad/baches, ciudad/precios, etc…) pienso que se puede encarar primero manualmente (del lado de administración, en servidor), luego comenzar a programar algo más inteligente. Seguir “make it works, make it right, make it fast”.

Luego, hace un mes, me propusieron armar algo similar, para un proyecto privado, pero con otras prestaciones. Estoy trabajando en eso, pero es privado, no puedo comentar detalles.

Y hace unos días aparece, en la lista de Python Argentina:

Mirar (tu smartphone) para cuidar
Hola Preciosa

con la idea de un proyecto para controlar los precios en Argentina. Pienso que la idea original tiene un sesgo hacia el gobierno actual ejecutivo, y que el control de precios no sirve para mucho. Pero es interesante que la gente participe para ir armando información para compartir. El proyecto es de código abierto en:

https://github.com/mgaitan/preciosa

No me había dado cuenta que desde el principio fuera Django (tal vez me hubiera gustado ver discusión sobre el tema, Flask? otra tecnología?). Pueden participar en la lista de correo:

https://groups.google.com/forum/?fromgroups#!forum/preciosa-devs

y participar ahí, aportando ideas, enlaces, poniendo issues en GitHub, o haciendo el clásico pull request. Personalmente, poco puedo aportar, apenas si conozco Python, y programar código de producción sin TDD, no sé, me da algo de “asquito” ;-)

Pienso que lo que hace falta, para no programar todo de nuevo, es clientes mobile que, por simple configuración (¿un request a un json en línea?), sirvan para cargar fotos y texto a distintos sitios. Así, podría programarse un cliente para Android, que según configuracion1.json, pueda subir fotos y datos a un sitio, y según configuracion2.json, pueda subir fotos y datos a otro sitio. Y lo mismo para otras plataformas móviles.

Después, el lado del servidor puede quedar librado a distintas tecnologías. Quiero escribir un ejemplo, código abierto, en Node.js + Express. Mis primeros pinitos/spikes en https://github.com/ajlopez/ExpressSamples. Veremos qué sale (aprovecho: no sé si vieron en mi cuenta de GitHub mis adelantos de fin de semana sobre generación de código desde un modelo…. si se perdieron eso, es que no entienden hacia dónde voy ;-)

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, Jun 4 2013 12:07 by lopez | with no comments

Resoluciones del Nuevo Mes: Junio 2013

Primero, revisión de mis resoluciones de Mayo:

- Actualizar Mass [completo] repo
- Actualizar RubySharp [completo repo
- Dar una charla de introducción a Ruby [completo] post, repo
- Actualizar AjGenesis [completo] Node.js version repo
- Actualizar ClojSharp [completo] repo
- Nuevos posts sobre Mass [completo] post, post, post
- Nuevos posts sobre Aplicaciones Distribuidas y Node.js [completo] post
- Nuevos post sobre TDD [completo] post, post, post

Additionalmente, estuve trabajando en:

- Empezar Eternity en JavaScript [completo] repo
- Empezar Aprendiendo Python [completo] repo
- Actualizar AjSharp [completo] repo
- Escribir la primera versión de SimpleJsonHtml [completo] repo

Resoluciones para este nuevo mes, Junio 2013:

- Actualizar Mass
- Actualizar RubySharp
- Actualizar PythonSharp
- Actualizar ClojSharp
- Actualizar AjSharp
- Más ejemplos de AjGenesis Node.js
- Actualizar Aprendiendo Ruby
- Actualizar Aprendiendo Python
- Escribir un ejemplo Node.js/Express/MongoDb
- Nuevos posts sobre RubySharp
- Nuevos posts sobre TDD
- Nuevos posts sobre Mass

Jeje… me diviegto como logco!…. ;-)

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, Jun 4 2013 10:51 by lopez | with no comments

RubySharp, implementando Ruby en C# (1)

Ya saben que todos los días hago commit en mi cuenta de GitHub:

https://github.com/ajlopez

para entrenarme en practicar programación, lenguajes y TDD (no se olviden de eso, hagan TDD!)

Desde hace unos tres meses, más o menos, estoy trabajando intermitentente en RubySharp:

https://github.com/ajlopez/RubySharp

un intérprete Ruby escrito en C# (como PythonSharp, ver posts). Hay dos soluciones, una con tests, y otra sin tests, para que puedan compilar con un Visual Studio Express (lo mío es un apostolado ;-). La solución con tests:

Vean que tengo comandos y expresiones. Voy a revisar esa separación, al igual que comentaba en otro post sobre el lenguaje Mass: en Ruby todo es un valor, y así los comandos son expresiones. Agrego algo: el lenguaje Mass derivó de una simplificación de este trabajo.

Como siempre, escribo con tests:

Y para que vean que no les “hago el verso” con lo de TDD, pueden siempre vigilar mis commits:

https://github.com/ajlopez/RubySharp/commits/master

Próximos posts: detalles de implementación, ejemplos de uso (especialmente para scripting sobre .NET).

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Mon, Jun 3 2013 10:48 by lopez | with no comments

Un Buen Proyecto (2)

Anterior Post 
Siguiente Post 

Ya tratamos el principal tema que nuestro proyecto tiene que cumplir para ser un buen proyecto: solucionar el problema al cliente. Puede que sea sólo un colaborador, entre otros proyectos, para llegar a esa solución. Por ejemplo, me pasa muchas veces que el proyecto que me toca es de programación de una aplicación, pero la solución total del problema implica su instalación, mantenimiento y adopción. Otras veces no: nuestro proyecto abarca toda su ciclo de vida, por lo menos de la primer versión.

Puede suceder algo que muchas veces se nos pasa por alto:

- No podemos estar seguros de que lo que entregamos es un buen proyecto al terminarlo y entregarlo.

Hay que ver si realmente funciona en el campo, en la vida real.

Pongamos un ejemplo. Sea nuestro cliente es una compañía de seguros y su problema es que está perdiendo clientes porque los productores de seguros tardan mucho en otorgarle una póliza o no. La solución evaluada es: poner una aplicación en línea que reduzca el tiempo de aceptación o rechazo de un día a quince minutos. Hacemos la aplicación, pero al llegar a desplegarse y ser usado se muere cada media hora por la presión de uso, y la causa es el código de nuestro proyecto. O peor, trabaja bien, soporta la carga, pero otorga aceptaciones a cualquier caso. En ambos casos, nuestro proyecto no habrá sido un “buen proyecto”.

Es por eso que en nuestro proceso es importante las pruebas de carga y las pruebas funcionales. A lo que voy, es que muchas de las actividades que realizamos terminan teniendo su origen en la necesidad de cumplir con ser un buen proyecto. Un proyecto puede parecer “bueno”: tener todo “en regla”, haber sido programado con todos los patrones, ante las entradas correctas dar el resultado correcto, pero fracasar en su implementación porque no revisamos que, así como lo tenemos programado, no soporta más de diez usuarios simultáneos.

Aparece la cuestión de la calidad de nuestro entregable. Podemos discutir luego si la calidad es responsabilidad del equipo ágil, o si hace falta un equipo aparte de QA (Quality Assurance). Pero vemos que todo esto es motivado por la necesidad de cumplir con lo que espera el cliente: la solución de su problema.

Para poner un ejemplo “al revés”: al cliente no le importa que lo que entregamos sea escalable como Facebook, si su problema y solución (digamos, un sistema de compras) necesita solamente atender a veinte usuarios (los representantes de sus proveedores principales).

En próximos posts: si una solución es exitosa, hay que mantenerla; el aporte de TDD y el proceso de desarrollo.

Nota personal: lo de no poder ver si es un buen proyecto al terminarlo, me fue sugerido por Aristóteles. No encuentro la cita ahora, pero cuando habla de “eudamonia” en su “Etica a Nicómaco”, habla de lo que yo traduzco como “buena vida”, “con los dioses a favor”. Dice Aristóteles que muchas veces, un hombre al morir no puede estar seguro de haber llegado a la “buena vida”: puede que el resultado dependa de su influencia en otros hombres, aún luego de su muerte. (me temo que Aristóteles hablaba de “hombres”, ciudadanos con derechos, y no de “seres humanos”; mujeres abstenerse, era el Borat de los filósofos ;-).

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Thu, May 23 2013 12:02 by lopez | 1 comment(s)

Un Buen Proyecto (1)

Siguiente Post

En mis charlas de TDD (Test-Driven Development) comento algunas características de lo que tendría que ser un proyecto bien terminado. Algo ya comenté en TDD y Diseño de Implementación (1). Hoy quiero escribir (es decir, pasar en limpio, compartir, explicar un tema para ver si lo entiendo) sobre un tema más amplio: lo que considero un buen proyecto. Pensé inicialmente que bastaría un solo post, pero nones: éste va a ser el primero, y luego seguiré escribiendo.

Pongo algo de contexto. Voy a escribir sobre un proyecto:

- Profesional

- Con desarrollo ágil en equipo, con iteractiones, backlog, etc..

- Cliente externo, con un representante

- Para ejecutar en producción

Es decir, no necesariamente tiene que ser de código abierto (en mi caso en general no es), no es algo que armamos en nuestro tiempo libre (no, es un proyecto de nuestro trabajo de desarrollo de software), no es una demo, va a estar en producción y tendrá un ciclo de vida (no necesariamente apoyado por nosotros: el proyecto tiene una terminación y una entrega final). Igual admito que es difícil abarcar todos los proyectos profesionales. Pero creo que con lo que voy a describir varios proyectos serán incluidos en esta exposición.

Entonces, en este marco, ¿cuáles son las características que tendría que tener un proyecto terminado para que digamos: “es un buen proyecto”? En el sentido de sentir y pensar que lo que entregamos es bueno. Claro, depende de bueno ¿para quién? Como estamos en un proyecto profesional, lo principal es que sea bueno para el cliente (empresa) que nos contrata. Puede ser bueno para nosotros (“uy, aprendí un montón de MVC”), para el equipo (“nos integramos y conocimos”), para nuestra consultora (“uy, con lo que ganamos podemos comprar nuevas oficinas”, o “ahora podemos ser conocidos por haber trabajado en este gran proyecto”), para el mundo (“ahora hay un nuevo framework que todos podrían usar para ser más productivos, etc… “). Pero lo que importa es:

TIENE QUE SER BUENO PARA EL CLIENTE

Vean que más arriba escribí “cliente (empresa)”. Es decir, tiene que ser bueno para la empresa o sector de la empresa que nos contrata. No hay que medir (en principio) que sea “bueno para Charles”, por ser Charles nuestro contacto principal en la empresa. A no ser que sea Charles el que pague la factura, no es el “cliente”. Es un representante del cliente.

Para ponerlo en claro: no es QUE NO IMPORTA absolutamente que nosotros encontremos que el proyecto haya sido bueno para Charles, para el equipo, o para nosotros mismos. No, estoy tratando de encontrar cuál es lo MAS importante.

Pues bien, después de haber participado en este siglo en varios proyectos ágiles, y también viendo el resultado de otros varios más proyectos, con casos de éxitos y fracasos, lo mejor que puedo decir es:

Un proyecto es un buen proyecto terminado y entregado, SI SOLUCIONA EL PROBLEMA DEL CLIENTE

No nos piden simplemente “necesitamos el sistema X”, sino, “necesitamos el sistema X que solucione el problema P”. Otras veces, nos dan más libertad “necesitamos una solución S que solucione el problema P”, pero es menos frecuente el caso. Pero muchas veces (la mayoría de ellas) nos piden “necesitamos el sistema X” sin poner muy en claro el problema que tiene que solucionar.

Para poner un ejemplo. Supongamos que nos piden “Necesitamos un Sistema de Producción”. Puede ser que el contexto del cliente sea:

“Somos una empresa productora familiar, que en los últimos años, con la entrada de la tercera generación en la gerencia, ha podido expandir el mercado en el exterior”

Entonces, puede el problema a solucionar puede ser uno de éstos, entre tantos:

1 - “Se nos ha ido de las manos la producción, necesitamos un sistema que nos permita manejar mejor la asignación de las máquinas. Hoy las desaprovechamos”

2 - “Las máquinas las asignamos bien, pero tenemos problemas en el seguimiento de los insumos que necesitamos y cuándo los necesitamos. No queremos tener stock de esos insumos en estos tiempos de cambio”

3 - “Nuestros principales clientes del exterior nos piden trazabilidad norma (y aquí viene una sigla desconocida para nosotros) de acá a fin de año, sino perdemos nuestro principal contrato con China”

4 – etc

Vean que entendiendo el problema podemos poner distinto énfasis en lo que vamos a construir, y con el representante del cliente, podemos tener más en claro qué es lo que aporta más valor al cliente. En el caso 1, tendremos que poner mayor esfuerzo en un plan de asignación de máquinas, y no tanto en el stock de insumos. En el caso 2, es al contrario. Y en el caso 3, tendremos que estudiar qué es eso que piden de trazabilidad.

Pero vean a lo que voy: podemos entregar el mejor sistema de producción, que asigne con algoritmos de inteligencia artificial las máquinas de la mejor forma posible, escrito con todos los patrones encima, con la mejor UI para desktop, web, tablet, y hasta TV,  pero no es la solución del problema del cliente, si estamos en el caso 3.

ESO ES LO QUE HAY QUE ENTENDER PRIMERO.

A ver, de nuevo:

EL ENTREGABLE DEL PROYECTO DEBE SOLUCIONAR EL PROBLEMA DEL CLIENTE

Y acá entra la capacidad del representante del cliente para ponernos más en claro cuál es el problema real.

No quisiera terminar el post, sin comentar algo. Hay diferencia entre problema y solución. Como escribía arriba, muchas veces nos piden el sistema. Pero tenemos que esforzarnos, como profesionales, para ver si el sistema inicial pedido soluciona o no el problema, o si es el mejor camino para solucionar el problema. En general, eso ya se definió antes de llegar el proyecto a nuestro equipo. Pero igual deberíamos tenerlo en cuenta. Tal vez, en vez de hacer sistema S, podemos hacer sistema S’ que tenga algunas características sugeridas por nosotros que mejoren alcanzar la solución del problema.

Siempre recuerdo a Henry Ford, diciendo: “Si le hubiera preguntado a mis potenciales clientes qué querian, me hubieran pedido ‘caballos más rápidos’”.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Thu, May 16 2013 11:41 by lopez | 2 comment(s)

Aprendiendo Ruby

Como ya había anunciado, ayer dí una charla de introducción a Ruby, pueden ver y descargar la presentación en mi Skydrive.

En la presentación hay tres slides todavía en blanco, y slides al final de temas que quedaron expresamente afuera. Pero lean más abajo donde está toda la presentación explicada en detalle, y los ejemplos que usamos.

Para la instalación de Ruby, comenté:

http://www.ruby-lang.org/en/downloads/
En Windows http://rubyinstaller.org/
Dev Kit https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
Mingw, Minimalist GNU for Windows
http://www.mingw.org/

Para esta charla usé Ruby 2.0.0, y aclaré que lo más usado todavía es 1.9.x. Igual, los cambios son evolutivos, no hay grandes “roturas” en 2.0.0, pero como hay algunas gemas y frameworks que todavían corren solamente en 1.9.x, les conviene revisar cuál quieren usar. Al menos en Windows, se pueden instalar las dos versiones, y luego agregar al PATH cuál es directorio binario que queremos usar.

Estuvimos viendo temas de Ruby como lenguaje dinámico e interpretado, sintaxis básica, todo es un objeto, todo es un valor, módulos (comentando al pasar include, faltó extend), evaluación dinámica, su relación con Smalltalk, clases abiertas, ejemplo de Domain-Specific Language, y levantamos un sitio con tres páginas simples, con Sinatra y ERB.

Algunos temas más:

Mencioné que Sinatra usa WeBrick http://www.ruby-doc.org/stdlib-2.0/libdoc/webrick/rdoc/WEBrick.html incorporado desde hace un tiempo directamente en Ruby.

Mencioné Rack http://rack.github.io/ que habría que estudiar alguna vez para entender la infraestructura web de Sinatra y Ruby On Rails (no es necesario pero es intersante). Rack se inspira en trabajos anteriores, principalmente en Python ver http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface

Los ejemplos (tres páginas en Sinatra, y un DSL), quedaron en:

https://github.com/ajlopez/AprendiendoRuby/tree/master/ejemplos

El ejemplo de DSL fue una simple traducción a español del ejemplo de http://jroller.com/rolsen/entry/building_a_dsl_in_ruby

Si les interesa el tema DSL, estoy publicado enlaces en mi otro blog: http://ajlopez.wordpress.com/category/domain-specific-languages/

Y finalmente, la presentación me sirvió para ir escribiendo las primeras páginas de mi tutorial de Ruby en línea:

https://github.com/ajlopez/AprendiendoRuby#aprendiendo-ruby

Lo voy a ir completando con más capítulos, detalle, referencias, fuentes consultadas, ejercicios. También tengo que poner en línea lo que armé alguna vez en PHP: sitio con exámenes por preguntas y respuestas. Tengo también material (si recuerdan este blog, publicado hace ya un tiempo) de PHP y Java para poner en páginas GitHub. Algo más demandante sería escribir sobre Node.js, pero es candidato. Y sobre Clojure. Como mencioné en otro post, al explicar terminamos entendiendo ;-)

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, May 14 2013 12:46 by lopez | 1 comment(s)

Mass Lenguaje de Programación (4) Lexer y Parser

Anterior Post

En la implementación del lenguaje Mass, tengo una enumeración y una clase:

Un Token representa una palabra del código a procesar. El encargado de separar el código en palabras es el Lexer. Y con el Parser se transforma esa corriente de Tokens en expresiones y comandos:

El constructor de Lexer recibe un string:

public Lexer(string text)
{
    this.text = text;
}

Y ese string es procesado para separarlo en tokens. Vean que el Lexer distingue entre operadores (como +) y separadores (como los paréntesis). También toma en cuenta al fin de línea como token (en otros lenguajes, como C, un fin de línea se puede tomar como un espacio en blanco en muchas situaciones). El principal método de Lexer es NextToken, que devuelve el próximo Token del texto. En algunas pocas situaciones, se hace necesario devolver el Token consumido, y para eso está PushToken y varianes.

El Parser interamente maneja un Lexer. Le podemos pedir el próximo comando con ParseCommand, y la próxima expresión con ParseExpression. Cuando el texto en proceso se acaba, esos métodos devuelven null.

Voy a modificar el Lexer para consumir un stream de texto, para poder procesar, por ejemplo, entrada de consola

Tengo que seguir pensando si internamente, unifico comandos y expresiones, como pasa en Ruby, donde cada “comando” tiene un valor (en Mass también es así), y no solamente eso, sino que puede ser usado como expresión en el contexto de un comando.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sun, May 12 2013 9:40 by lopez | with no comments

Introducción a Ruby, en Buenos Aires

Gracias a la gente del Microsoft User Group de Argentina, el próximo lunes daré una charla sobre

Introducción a Ruby para Programadores .NET (o para programadores)

http://www.mug.org.ar/Eventos/3893.aspx

(vean de visitar la página porque hay que inscribirse)

El evento es gratuito, y es el lunes 13 de Mayo, desde las 18:30 hasta las 20:30. La idea es explicar algo de Ruby, introductorio, para programadores (sean de .NET o de otros lenguajes/tecnologías) que no sepan Ruby.

Los temas a visitar:

- Sintaxis básica
- Valores básicos: números, string, arreglos, hashes
- Comandos if, for, ciclos
- Clases y objetos
- Herencia
- Creación de objetos
- Variables de instancia y de clase
- Módulos
- Elementos de metaprogramación
- Definiendo DSL (Domain Specific Languages) internos en Ruby
- Gemas (paquetes de Ruby)
- Ecosistema de desarrollo
- Desarrollo Web, especialmente Sinatra, que usa Rack

Espero poder explicar en dos horas cuál es el panorama de desarrollo Ruby, para cualquier programador interesado en comenzar con este lenguaje.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Tue, May 7 2013 17:37 by lopez | 2 comment(s)

Resoluciones del Nuevo Mes: Mayo 2013

Primero, una revisión de mis resoluciones de Abril:

- Actualizar Mass [completo] ver repo
- Comenzar NodeAima [completo] ver repo
- Dar curso de un día de Node.js [completo]
- Actualizar AjGenesis [pendiente]
- Actualizar AjGenesisRuby [pendiente]
- Actualizar SimpleGo [pendiente]
- Actualizar RubySharp [completo] ver repo 
- Actualizar ClojSharp [pendiente]

Tambié estuve trabajando en:

- Actualizar AjFabriqNode [completo] ver repo
- Actualizar NodeSamples [completo] ver repo (ver Distributed Fractal)
- Actualizar SimpleStorm [completo] ver repo
- Actualizar SimpleBus [completo] ver repo
- Actualizar SimpleBroadcast [completo] ver repo
- Actualizar SimpleGA [completo] ver repo
- Comenzar SharpAima [completo] ver repo ver post Inteligencia Artificial en C# (1)
- Dar charla de Aplicaciones Distribuidas y Node.js [completo] ver post
- Actualizar AjErl, mi implementación de Erlang en C# [completo] ver repo

Mucho de ese trabajo adicional estuvo relacionado con el material que presenté en Aplicaciones Distribuidas y Node.js.

Ahora, las resoluciones para Mayo:

- Actualizar Mass
- Update RubySharp
- Dar una charla, Introducción a Ruby
- Actualizar AjGenesis
- Actualizar ClojSharp
- Nuevos posts sobre Mass
- Nuevos posts sobre Aplicaciones Distribuidas y Node.js
- Nuevos posts sobre TDD

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sun, May 5 2013 11:34 by lopez | 1 comment(s)

Aplicaciones Distribuidas y Node.js

Como ya lo había anunciado, el martes pasado estuve dando una charla de aplicaciones distribuidas y Node.js, gracias a la gente de Node.js Argentina,  en el auditorio del Microsoft User Group de Argentina, en Buenos Aires.

Pueden ver y bajarse la presentación desde mi Skydrive

La idea fue mostrar algunos conceptos, y experimentos que estuve haciendo con Node.js, convirtiendo anteriores trabajos en otras tecnologías. Y mostrar código con ejemplos concretos.

Primero, expliqué lo que era una aplicación distribuida en el contexto de esta charla. Una aplicación distribuida es una aplicación que se ejecuta en varias computadoras, conectadas en red, que interactúan para resolver un problema. Ver http://en.wikipedia.org/wiki/Distributed_computing

Es decir, va más allá del clásico cliente servidor. Podemos tener varias computadoras para hacer web crawling de un sitio, o resolviendo la renderización de escenas de una película 3d. Las computadores que intervienen en el trabajo no necesariamente tienen el mismo software o programa: puede que algunas se ocupen solamente de algún paso del problema. Tampoco tienen que tener la misma plataforma o lenguaje de programación.

Lo que quise destacar, entonces, en la charla, son las facilidades que nos da Node.js y JavaScript para construir este tipo de aplicaciones. Ya en otras charlas afirmé “JavaScript es una manteca”, para destacar su flexibilidad. Y ahora, en esta charla, tuve la oportunidad de mostrar un tópico donde Node.js brilla: tanto por su soporte de red en los módulos “built-in”, como por su ecosistema, como por la filosofía de combinar módulos (como en Unix, ver Unix philosophy and Node.js de @izs)

Mencioné una entrevista a Alan Kay (ver su Dynabook)


I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages

Until real software engineering is developed, the next best practice is to develop with a dynamic system that has extreme late binding in all aspects

The big idea is “messaging”

Es interensante que Kay mencionara células biológicas: nuestros nodos en ejecución pueden tomarse como células, que forman el organismo de nuestra aplicación distribuida. Como dice Kay, el gran tema es el “messaging”, el envío de mensajes entre las partes. Las aplicaciones distribuidas nos dan la oportunidad de olvidarnos del concepto de función/rutina a la que llamamos con parámetros y esperamos que termine de ejecutar para dar un resultado, y aún de una llamada con callback: un elemento de nuestra aplicación distribuida enviará un mensaje, desentendiéndose de obtener una respuesta.

También mencioné a Richard Feynman (algún post de mis enlaces), ver

http://boards.straightdope.com/sdmb/showthread.php?t=159936

Feynman was once asked by a Caltech faculty member to explain why spin 1/2 particles obey Fermi-Dirac statistics. He gauged his audience perfectly and said "I'll prepare a freshman lecture on it." But a few days later he returned and said, "You know, I couldn't do it. I couldn't reduce it to the freshman level. That means we really don't understand it."

Adaptando su frase a “si no lo podemos explicar, es que no lo entendemos” como motivación personal para dar charlas. Recordé su trabajo de estudio “por su cuenta” de la física cuántica según Feyman por Dyson, como justificación lejana a experimentar con un tema, en vez de tomar lo que ya está hecho directamente.

Pues lo que presenté luego, son experimentos sobre Node.js para aplicaciones distribuidas. Pero ¿por qué Node.js? En JavaScript, un mensaje puede ser un simple objeto serializable a JSON (un objeto sin ciclos, o sea, un árbol). Y para el transporte del mensaje podemos elegir multitud de módulos en el ecosistema de Node, como usar el require(‘net’) o require(‘http’) que vienen “built-it” en el núcleo de Node.js

Preguntas que tenemos que hacernos en cada caso de aplicación distribuida:

¿Qué elementos de nuestra aplicación producen mensajes?

¿Qué elementos consumen mensajes?

Un mensaje ¿es consumido por un solo elemento? ¿o puede ser procesado por varios elementos interesados?

Las máquinas y programas que ejecutan ¿están determinados desde el comienzo? ¿o pueden variar con el tiempo? Por ejemplo, me gustaría sumar a mi aplicación distribuida unas cuarenta máquinas que a la noche están ociosas. ¿Se puede hacer? ¿Necesitamos esta característica?

Un mensaje producido en un elemento de una máquina ¿se consume localmente? ¿o puede viajar a otra máquina? ¿quién decide eso? ¿el programador, el programa supervisor?

Y dado un mensaje que tiene que llegar a otra máquina ¿cómo llega? ¿con qué transporte?

Si un mensaje tiene que ser procesado remotamente ¿cómo se selecciona la máquina destino? ¿por programa? ¿por algún balanceo de carga?

Esas preguntas se contestarán diferente en cada experimento o ejemplo que tengamos.

Uno de los experimentos (repetido de distintas formas) es un web crawler, compuesto lógicamente (partes lógicas, luego a implementar de distinta forma según el ejemplo/experimento):

Cuando tengamos que recuperar las páginas de un sitio, primero enviamos una URL inicial a un elemento Resolver. Este elemento mantiene la lista de páginas ya visitadas. Si la URL es una página no procesada aún, se envía la URL a un elemento Downloader (elemento lógico que puede estar implementado en varias máquinas). Es el encargado de conseguir el contenido de la página. Luego le pasa ese dato al elemento Harvester, que extrae los enlaces que consigue encontrar en la nueva página. Los enlaces se envían al Resolver, que examina si corresponde o no procesar esas URLs.

Un módulo que escribí (no fue el primero, sino que surgió de refactor y extracción de otros casos de uso) es ObjectStream

https://github.com/ajlopez/ObjectStream
https://github.com/ajlopez/ObjectStream/tree/master/samples/broadcast

que me permite enviar un objeto JavaScript (serializable a JSON) a un Object Stream, un stream que recibe objetos. Este stream puede enviar ese objeto, ya serializado a texto, por otro stream. Y hay un Object Stream que toma esas líneas de texto y las reconstruye como objetos. Esto me permite usar, por ejemplo, un stream de socket para enviar objetos JavaScript de una máquina a otra. Vean en los enlaces de arriba el ejemplo de Broadcast que mostré en la charla.

Basado en ObjectStream, me animé luego a armar

https://github.com/ajlopez/SimpleMessages
https://github.com/ajlopez/SimpleMessages/tree/master/samples/Broadcast

Permite que dos procesos establezcan canales bidireccionales de envío de mensajes, que arrivan en cualquier momento. Desde el punto de vista del código, uno puede exponer un servidor (o varios) o crear clientes que se conectan a otros servidores. Pero luego de efectuada la conexión, el intercambio de mensajes es simétrico: cualquiera de las partes puede enviar un mensaje en cualquier momento. Ya con esto podemos entretenernos bastante, escribiendo aplicaciones distribudas basadas en mensajes.

Pero a veces, necesitamos más que enviar un simple mensaje. Por ejemplo, se nos puede presentar la necesidad de llamar a un objeto que está ejecutando en otra máquina. Podemos implementar un Remote Procedure Call. Lo hice en:

https://github.com/ajlopez/SimpleRemote

Basado en SimpleMessages, tanto el cliente como el servidor pueden exponer un objeto “hacia afuera”, y la otra parte lo puede invocar, como si fuera un objeto local. Solamente que como el retorno de la respuesta no es inmediato, el programador que llama al método agrega un callback para procesar la respuesta cuando ésta llegue.

Para alternativas pueden ver:

http://stackoverflow.com/questions/5010814/whats-the-best-way-to-make-one-node-js-server-talk-to-another
http://stackoverflow.com/questions/7986088/rpc-and-messagequeues-in-node-js
https://github.com/substack/dnode
https://github.com/Flotype/now
https://code.google.com/p/protobuf-for-node/
https://code.google.com/p/protobuf/
https://github.com/Frans-Willem/IPCNode

Vean dnode, cómo tienen clientes para distintos lenguajes. O vean también algo más agnóstico, http://en.wikipedia.org/wiki/JSON-RPC

Tuve un caso de uso donde necesitaba repartir mensajes, no solamente enviar un mensaje desde A hasta B. Entonces nació:

https://github.com/ajlopez/SimpleBroadcast
https://github.com/ajlopez/SimpleBroadcast/tree/master/samples/Broadcast

De esta manera, un cliente puede enviar un mensaje a un servidor, y éste repartirlo en los demas clientes conectados. Vean que el mensaje no se transmite al cliente que lo originó, sólo a los demás. Hasta puede haber una “estrella” de servidores, donde cada servidor atiende a sus clientes, y actúa como cliente de los otros servidores:

Esto permite la escalabilidad agregando servidores a la estrella. También tiene un concepto algo más sofisticado, el servidor repetidor (ver el código y tests). En este software tuve colaboración de Fernando Lores.

En otros casos de uso, en vez de enviar mensajes, necesité que los que iban a procesar mensajes los pidieran explícitamente. Como quería realizar todos estos experimentos en Node.js, sin depender de software externo, escribí:

https://github.com/ajlopez/SimpleQueue
https://github.com/ajlopez/SimpleQueue/tree/master/samples/DistributedProducerConsumer

Al principio, implementé una cola en memoria, local. Y luego la expuse hacia otras máquinas usando SimpleRemote.

Otro caso de uso con el que me encontré es: necesito publicar mensajes, pero no sé de antemano a quién le interesa. Es similar a los eventos de Node.js: uno emite un evento, pero no sabe quienes se suscribieron a ellos. Llevado eso a algo distribuido escribí:

https://github.com/ajlopez/SimpleBus
https://github.com/ajlopez/SimpleBus/tree/master/samples/Market

Tanto los que publican como los que se suscriben a mensajes pueden estar en máquinas distintas.

En el ejemplo de Market que mostré en la charla (ver el enlace de arriba) la suscripción a los mensajes se puede hacer dando un mensaje ejemplo: todos los mensajes que tengan las mismas propiedades que el ejemplo, serán tomados para procesar por el subscriptor. También puedo enviar un predicado, y notablemente, ese predicado puede “viajar” desde el suscriptor a la maquina que tiene el servidor de bus (que podrían ser varias máquinas en estrella usando SimpleBroadcast).

Muchos de estos casos de uso fueron motivados por implementaciones que tuve que escribir en otras tecnologías. El trabajo que más influyó es lo que hice cuando trabajé para @asehmi:

Ver Remember Fabriq.

Basado en su proyecto Fabriq, reescribí algo en AjFabriqNode:

https://github.com/ajlopez/AjFabriqNode
https://github.com/ajlopez/AjFabriqNode/tree/master/samples/WebCrawler

AjFabriq se basa en tener varios nodos ejecutándose, cada uno declara un árbol de procesadores de mensajes. En base al contenido del mensajem se determina qué procesador de mensaje puede atenderlo. Cada nodo se puede conectar a otro de la red, y entre varios se intercambian cuáles procesadores de mensajes tiene cada uno. Entonces, podemos tener un Web Crawler distribuido donde en un nodo tenemos el resolver, y en otros tenemos downloaders y harvesters.

Otros prefieren enviar los mensajes directamente a un elemento específico. Basado en la implementación de actores en Akka/Scala, ver:

http://doc.akka.io/docs/akka/snapshot/general/actor-systems.html
http://doc.akka.io/docs/akka/snapshot/general/actors.html
http://doc.akka.io/docs/akka/snapshot/general/addressing.html

implementé algo más simple:

https://github.com/ajlopez/SimpleActors
https://github.com/ajlopez/SimpleActors/tree/master/samples/DistributedWebCrawler

Pero vean que en Akka, un mensaje se envía en general a un actor, identificado por su dirección.

Hay un proyecto Java, Storm Project en:

http://storm-project.net/

donde se puede armar una topología con los elementos lógicos que van a recibir, procesar y emitir tuplas (lo que para esta charla es mensajes). Hay productores de mensajes, los Spout, y procesadores de mensajes, los Bolt. Luego cada elemento puede ejecutarse en varias máquinas. Así, podemos tener una topología de Web Crawler con Resolver, Downloader y Harvester. Pero luego poner 20 downloaders en 10 máquinas, y 5 harvesters en las mismas máquinas u otras.

Así que, ni lerdo ni perezoso, escribí algo simple en Node.js:

https://github.com/ajlopez/SimpleStorm
https://github.com/ajlopez/SimpleStorm/tree/master/samples/DistributedWebCrawler

Lo que ví en mis experimentos, es que muchas veces necesito levantar varias máquinas, indicarles qué hacer, que aplicaciones lógicas ejecutar (por ejemplo, el web crawler), y que puedan intercambiar mensajes entre ellos. Mostré:

https://github.com/ajlopez/MultiNodes
https://github.com/ajlopez/MultiNodes/tree/master/samples/collatz

Lo interesante es que un nuevo nodo que se incorpora a la red, puede ser instruido dinámicamente a ejecutar algo (como instalar y lanzar una nueva instancia del web crawler).

Dos ejemplos finales:

Una implementación de algoritmo genético distribuido:

https://github.com/ajlopez/SimpleGA
https://github.com/ajlopez/SimpleGA/tree/master/samples/tspdistr

Y un fractal que se puede calcular en el browser, o en un servidor Node.js/Express, solo o ayudado por nodos worker adicionales:

https://github.com/ajlopez/NodeSamples/tree/master/Fractal
https://github.com/ajlopez/NodeSamples/tree/master/Fractal/html
https://github.com/ajlopez/NodeSamples/tree/master/Fractal/server
https://github.com/ajlopez/NodeSamples/tree/master/Fractal/distributed

Al final, mencioné varias razones para investigar con aplicaciones distribuidas: desde lo interesante del tema, como lo práctico (para Big Data, cálculo distribuido y en paralelo, etc). Pero resalté que tenemos que seguir investigando sobre aplicaciones distribuidas e inteligencia artificial. Nuestro sistema nervioso funciona con varios nodos, surgiendo una aplicación distribuidas en neuronas (¿recuerdan a Alan Kay hablando de células con mensajes?)

Otro de los temas que me interesan es tener lenguajes dinámicos que puedan distribuirse fácilmente entre nodos distribuidos (de hecho, me gustó JavaScript con Node.js, porque me libera de implementar eso). Ver:

Lenguajes de Programación, Computación Distribuida, Inteligencia Artificial
Experimentos Distribuidos

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sat, May 4 2013 20:36 by lopez | 2 comment(s)

Mass Lenguaje de Programación (3) Comandos

Anterior Post  
Siguiente Post 

Veamos hoy cómo están implementados los comandos en Mass (ver repo). En el proyecto de librería de clases, tengo:

Hay comandos para if, while, for, for each, etc…. Todos implementan la interfaz ICommand:

public interface ICommand
{
    object Execute(Context context);
}

Vean que es muy parecido a IExpression. Igual quise mantener comandos y expresiones por separado, por lo menos en esta primera implementación, para tener un claro delineamiento de los conceptos de base del lenguaje.

Un ejemplo típico de comando es el WhileCommand (parte del código):

public class WhileCommand : ICommand
{
    private static int hashcode = typeof(WhileCommand).GetHashCode();

    private IExpression condition;
    private ICommand command;

    public WhileCommand(IExpression condition, ICommand command)
    {
        this.condition = condition;
        this.command = command;
    }

    public object Execute(Context context)
    {
        for (object value = this.condition.Evaluate(context); 
            value != null && !false.Equals(value);
            value = this.condition.Evaluate(context))
        {
            this.command.Execute(context);
            if (context.HasContinue())
                context.ClearContinue();
            if (context.HasBreak())
            {
                context.ClearBreak();
                break;
            }
        }

        return null;
    }
}

Para Mass: cualquier valor null o false es falso. Todo lo demás es verdadero. Un tema a refactorizar: poner un método IsFalse para se usado tanto en la implementación de While como de If.

Otro ejemplo es el ForEachCommand (parte del código):

public class ForEachCommand : ICommand
{
    private string name;
    private IExpression expression;
    private ICommand command;

    public ForEachCommand(string name, IExpression expression, ICommand command)
    {
        this.name = name;
        this.expression = expression;
        this.command = command;
    }

    public object Execute(Context context)
    {
        var values = (IEnumerable)this.expression.Evaluate(context);

        foreach (var value in values)
        {
            context.Set(this.name, value);
            this.command.Execute(context);
            if (context.HasContinue())
                context.ClearContinue();
            if (context.HasBreak())
            {
                context.ClearBreak();
                break;
            }
        }

        return null;
    }
}

Vean que para Mass, todo lo que sea IEnumerable se puede usar para ser consumido por este comando. Tuve que poner algunos datos en el contexto, para saber si se había hecho un break o un continue.

Y como siempre, todo esto desarrollado con TDD: pueden ver los commits del repo.

Próximos posts: Lexer y Parser, ejemplos de Mass para scripting.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sun, Apr 28 2013 12:24 by lopez | 1 comment(s)

Mass Lenguaje de Programación (2) Primeras Expresiones

Anterior Post  
Siguiente Post 

Antes de ver cómo usar el lenguaje Mass (ver repo), quisiera tratar algunos temas de implementación. Primero, una novedad: ahora hay una solución (en https://github.com/ajlopez/Mass/blob/master/Src/Mass.sln) que puede compilarse con algún Visual Studio C# Express, de libre bajada e instalación.

La solución Mass tiene un proyecto de librería de clases. Ahí hay un namespace dedicado a expresiones:

Una expresión es algo que cumple con IExpression:

  
public interface IExpression
{
	object Evaluate(Context context);
}
  

Un Context mantiene un diccionario de nombre/valor, para guardar las variables actuales:

  
public void Set(string name, object value)
{
	this.values[name] = value;
}

public object Get(string name)
{
	if (this.values.ContainsKey(name))
		return this.values[name];

	if (this.parent != null)
		return this.parent.Get(name);

	return null;
}
  

(vean de refilón, que soporta contextos anidados: cada contexto puede “heredar” de un contexto parent).

La expresión más simple es la que devuelve una constante, que puede ser cualquier valor/objecto .NET:

  
public class ConstantExpression : IExpression
{
	// ...

	private object value;

	public ConstantExpression(object value)
	{
		this.value = value;
	}

	public object Evaluate(Context context)
	{
		return this.value;
	}

	// ...
}
  

La siguiente expresión más simple es la evaluación de un nombre de variable en el contexto actual:

  
public class NameExpression : IExpression
{
	// ...
	
	private string name;

	public NameExpression(string name)
	{
		this.name = name;
	}

	public object Evaluate(Context context)
	{
		return context.Get(this.name);
	}
	
	// ...
}
  

Es necesario especificar el contexto (por ejemplo, el contexto de la función actual, de una clausura, del objeto actual, del módulo actual, etc), porque un mismo nombre puede tener distintas variables asociadas, como pasa en otros lenguajes.

Como siempre, cada una de estas clases (Expresiones, Contexto, …) fue armada usando el flujo de trabajo de TDD (ver el proyecto de tests, y la historia de commits del repo donde dejé evidencia de cómo fue el desarrollo en el tiempo).

Próximos posts: algunas expresiones adicionales, comandos, usando Mass para scripting, usando Mass desde nuestro programa .NET, etc..

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sat, Apr 27 2013 14:26 by lopez | 1 comment(s)

Node.js, Charlas en Buenos Aires: Aplicaciones Distribuidas; Introducción a ZMQ

La gente de Node.js Argentina prepara una nueva reunión para el próximo martes 30 de abril:

http://www.meetup.com/NodeJS-Argentina/events/112809892/

Revisen el horario, la idea era que fuera de 18:30 a 21hs en la zona de Congreso, Buenos Aires, cerca de subtes y multitud de colectivos.

Además de reunión, habrá dos charlas. Una de Fernando Alonso, sobre Introducción a ZMQ con Node, no tengo el temario en detalle. Y además, estaré dando otra charla, sobre uno de mis temas preferidos: aplicaciones distribuidas, en este caso con Node.js. Puede ver mis posts sobre aplicaciones distribuidas en general. Pero esta vez, trataré el tema desde Node.js, que me parece una plataforma excelente para experimentar y trabajar con este tipo de aplicaciones. Algo ya adelanté el año pasado en mi charla del Día del Programador:

Experimentos distribuidos

Ahí encontraran algunos enlaces sobre lo que estoy probando y armando. Algo más lateral, pero para explicar mi interés en el tema distribuido y su relación con otros temas que ven que trato frecuentemente por acá:

Lenguajes de Programación, Computación Distribuida, Inteligencia Artificial

Espero poder transmitir algo de todo esto en la charla del Node.js meetup. Recuerden de revisar la página del grupo, que se vienen más reuniones con otros temas (por ejemplo, la anterior fue sobre Node.js y Raspberry Pi).

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Wed, Apr 24 2013 11:16 by lopez | 1 comment(s)

Nuevo Podcast de 32minutos.net: Agilidad con Martín Salías

El sábado pasado apareció publicado un podcast en el que participé con @martinsalias, conversando sobre agilidad en general. Fue gracias a la gente de http://www.32minutos.net/, @roundcrisis, @dvilchez, @jorgegamba.

El podcast en:

07×03 Agile con Ángel Java López y Martín Salias

Hemos charlado de todo, los principales temas:

  • Disposición al cambio
  • Entrega continua
  • Retrasar la toma de decisiones
  • Product owner
  • Empresas y administración
  • Equipos
  • Stand up
  • Retrospectiva
  • Equipos remotos

 

Vean que Martín toco varios de esos temas, contando experiencias en proyectos y equipos reales. Yo continué sobre la facilidad que da lo ágil para abrazar el cambio, y tomar decisiones ALAP (“as late as possible”). Si tienen alguna duda, le preguntan a @martinsalias ;-)

Gracias a 32minutos!

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Mon, Apr 22 2013 11:21 by lopez | with no comments

Inteligencia Artifical en C# (1) Primeros Agentes

Ayer comencé a implementar ejemplos del libro Artificial Intelligence: A Modern Approach, de Stuart Russell y Peter Norvig. Ver el sitio del libro

http://aima.cs.berkeley.edu/

Hay implementaciones en distintos lenguajes:

http://aima.cs.berkeley.edu/code.html (hay en Python, Java, C#, Prolog, Lisp, … )

Mi implementación en

https://github.com/ajlopez/SharpAima

Quiero ir armándola con TDD. Por ahora me baso en la versión en Python, pero puede que también vea la versión en Java, debido a las diferencias de los lenguajes: C# y Java son lenguajes tipados.

La versión que presento hoy es la 0.0.1

https://github.com/ajlopez/SharpAima/tree/0.0.1

Por cada post iré “taggeando” una nueva versión. Mi primer código trata de implementar los primeros agentes descriptos en el capítulo 2. Me basé en el código de:

http://aima-python.googlecode.com/svn/trunk/agents.py

Tengo una solución con dos proyectos: uno de clases y otro de tests:

La idea es tener agentes en un ambiente:

(Adaptado de la figura 2.1 del libro)

El agente recibe percepciones y genera acciones. La primera implementación es:

public abstract class Agent<TLocation, TPerception, TAction>
{
	public TLocation Location { get; set; }

	public int Performance { get; set; }

	public abstract TAction GetAction(TPerception perception);
}

Y las implementaciones en concreto son de un agente robot máquina aspiradora (VacuumAgent y variantes).

Vean la historia del proyecto, cómo fue evolucionando desde TDD. Primero implementé un agente concreto, y luego fue surgiendo la abstracción de arriba. Noten que en C# tenemos que apelar a algo tipado, y de ahí el uso de tipos genéricos: un tipo de agente concreto se define dando el tipo de lugares (location) que maneja (por ejemplo, una posición X, Y, a implementar en la próxima versión), el tipo de percepciones que recibe (ej: “estoy en lugar A y el lugar está limpio”), y el tipo de acciones (“Limpiar”, “Ir a la Derecha”, … ). En Python es más simple, por no tener tipos.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted Sun, Apr 21 2013 10:04 by lopez | with no comments

More Posts Next page »