February 2013 - Posts
Gracias a la organización del Microsoft User Group de Argentina, y al apoyo en el lugar del bueno de @mcomparetto, pude dar un curso de un día en Rosario, Santa Fé, acá en Argentina. Quisiera enumerar rápidamente el material que usamos.
En primer lugar, la presentación la pueden ver en https://skydrive.live.com/redir?resid=9F903F3D6DB0C176!5904
Nos descargamos Node.js desde http://nodejs.org/
No lo usamos mucho, pero si quieren pueden usar el Git que se baja desde https://github.com/ajlopez/NodeSamples
Los ejemplos que usamos al principio estan en mi GitHub:
https://github.com/ajlopez/NodeSamples
Vimos de ahí los del subdirectorio Simple, desde un Hello World, un servidor Web, hasta un simple chat con Socket.io, como ir viendo en qué es bueno Node.js.
Discutimos cómo hacer un módulo, cómo usar algo de TDD. No fue “full TDD”, pero el ejemplo quedó en https://github.com/ajlopez/NodeSamples/tree/master/TDD.
Fue muy importante el ver el uso de require. Ahí apareció el manejador de paquetes NPM. Vimos cómo es un archivo package.json, cómo sirve para instalar las dependencias, dónde se buscan los módulos cuando se hace require, cómo se emplea “npm test”, cómo se puede publicar un módulo.
Para ver cómo se puede hacer un web server y sitio “a mano”, de los ejemplos de arriba vimos el directorio MathWizard, donde vimos cómo se puede implementar un cálculo en forma asincrónica. El tema de asincronía con callbacks fue algo que traté de repetir durante todo el curso, para que quede claro cuál es el precio a pagar para programar en Node.js.
Luego de ver cómo es armar un sitio a mano, discutimos el middleware de Connect, y luego Express. Ver:
http://expressjs.com/
Mostré cómo armar nuestro primer sitio web Express desde la línea de comando (ver la presentación). Quedó en https://github.com/ajlopez/NodeSamples/tree/master/Express/MyApp
Para pasar a un sitio con base de datos, instalamos MongoDb, ver http://www.mongodb.org/. Vimos el ejemplo de https://github.com/ajlopez/NodeSamples/tree/master/Express/Blog basado en el ejemplo original de http://howtonode.org/express-mongodb
Levantamos entonces el ejemplo https://github.com/ccoenraets/nodecellar ver los posts:
http://coenraets.org/blog/2012/10/nodecellar-sample-application-with-backbone-js-twitter-bootstrap-node-js-express-and-mongodb/
http://coenraets.org/blog/2012/10/real-time-web-analytics-with-node-js-and-socket-io/
http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/
Pasamos a ver Socket.io http://socket.io/ Usamos los ejemplos
https://github.com/ajlopez/NodeSamples/tree/master/SocketIO
https://github.com/ajlopez/NodeSamples/tree/master/SocketIO/Canvas
https://github.com/ajlopez/NodeSamples/tree/master/SocketIO/TicTacToe
y los ejemplos distribuidos de algoritmos genéticos de:
https://github.com/ajlopez/SimpleGA
https://github.com/ajlopez/SimpleGA/tree/master/samples
Finalmente, volvimos al nodecellar y lo modificamos para poder tener un “dashboard” de visitas en tiempo real, usando Socket.IO.
No se puede ver todo Node.js en un día, pero espero que las primeras horas hayan servido para tener una idea de cuáles son los primeros pasos, y que la segunda parte, a la tarde, haya servido entonces para tener un panorama rápido de cosas que se pueden hacer en tiempo real, que podrían ser complejas de implementar en otras tecnologías.
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Veamos hoy un tema que pone en perspectiva ¿para qué sirve TDD? O por lo menos, trata de responder en gran parte esa pregunta.
Todos conocemos lo que es programar en Java o en .NET. Escribimos el programa, posiblemente usando una IDE (Eclipse, Visual Studio.NET), y llegado el momento, compilamos. Los lenguajes .NET (VB.NET, C#, otros) y Java, son lenguajes tipados. El compilador nos dice cuándo nos equivocamos, ANTES de ejecutar nuestro programa. Por ejemplo, nos dice que nos equivocamos en el nombre de un método, o que escribimos mal el nombre de una clase, o que está mal el tipo del parámetro que tenemos que pasar a una función.
Eso ha sido útil por décadas. Y entonces, es fácil confundir esa solución (detectar en compilación errores), con el problema inicial (que nuestra aplicación funcione como esperamos).
Cuando pasamos a lenguajes dinámicos, como Ruby o Python o JavaScript, algunos se resienten: hey! No tenemos compilador! No podemos asegurarnos que lo que escribimos esté bien. Sólo nos damos cuenta si lo ejecutamos. Esto parece inclinar la balanza de nuestras preferencias a los lenguajes tipados con compilación.
Pero no es así. Todos los compiladores del mundo NO PUEDEN ASEGURARNOS que lo que escribimos esté bien. No pueden asegurarnos, al compilar, QUE NUESTRO SOFTWARE HAGA LO QUE ESPERAMOS QUE HAGA.
Veamos un ejemplo en concreto. Si tenemos un método llamado “incrementar” que recibe un entero, un compilador de Java o de .NET nos va a avisar sin lo llamamos con un nombre incorrecto, o si le estamos pasando un valor real o texto en lugar de un entero. Y eso es útil. PERO NO NOS AVISA NADA sobre si el método “incrementar” cumple con lo que esperamos de él. Bien podríamos tener en ese método código que en vez de incrementar una variable interna se dedica a formatear el disco C: o a borrar todo lo que tengamos en /usr/bin. EL COMPILADOR NO NOS SIRVE para afirmar que el método hace lo que esperamos que haga.
En cambio, TDD, al escribir los tests de lo que esperamos de nuestro método “incrementar” NOS AVISA cuándo las expectativas que tenemos no se cumplen. Entonces, no hay mucha diferencia entre escribir Ruby sin compilar y sin TDD y escribir C# sin compilar y sin TDD: de las dos formas, no sabemos si lo que escribimos HACE LO QUE ESPERAMOS QUE HAGA.
Es por todo eso que veo a TDD como la próxima generación de compiladores: es lo que nos asegura que lo que escribimos esté bien, NO EN SINTAXIS, sino en lo que podemos nombrar como SEMANTICA: lo que escribimos cumple con la conducta esperada.
Accesorio: por eso no tomo tanto en cuenta a los que critican a Ruby, Python o JavaScript por no ser tipados y no poder detectar errores en “compilación”. Si escribimos siguiendo TDD, no importa tanto el lenguaje que usemos: cada línea de código que agregamos está respaldada por un test, y cada test es una condición que cumplir. Cuando TDD nos avise que un test está en rojo, es como cuando el compilador nos avisa “el método inkrementar no existe”. Es más: yo diría que nos das avisos más importantes que lo que nos da cualquier compilador.
Escribir código de producción sin TDD, es como escribir un programa ejecutable, usando un editor hexadecimal sobre el archivo compilado: nada nos asegura que lo que estamos haciendo esté bien. Si quieren escribir código de producción sin TDD, bien, tengo unos folletos para jugar ruleta rusa, si les interesa ;-)
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Ya he escrito bastante en mis anteriores posts, sobre cuánto uso modelos en memoria al desarrollar un sistema. Pero ¿qué pasa cuando tenemos una base de datos? Ya sea porque llegamos al punto de necesitar usarla, o porque la base de datos ya está desde el principio del desarrollo.
Lo que he encontrado que me ha servido en esos casos es tener los tests de TDD como siempre, pero el modelo con persistencia en una base de datos local, del desarrollador. En el repositorio común al equipo debería estar claros los pasos para instalar esa base de datos (por ejemplo, un script de creación e inserción de datos iniciales). Puede que esa misma base de datos la usemos localmente para hacer pruebas manuales y demostraciones. Pero la cuestión es que los tests de TDD debería poder ejecutarse en cualquier momento, una vez o varias veces, sin verse afectado por la base de datos. Entonces, hay varias soluciones (que se pueden combinar):
- Un comando de línea que ponga a la base de datos de TDD en un estado conocido, la “well-known database”
- Tener una base de datos para TDD y otra, también local, para las demostraciones
- En los tests, una vez, al principio, tener una tarea que ponga a la base de datos de TDD en un estado conocido
- Cada test, envolverlo en una transacción y nunca hacer el commit
Con esto, se reduce la fricción de correr los tests locales.
En un servidor de integración continua, seguramente se creará la base y se cargará con los datos iniciales antes de correr los tests (de TDD u otros)
Yendo un poco más en detalle. Supongamos que nuestro sistema debe calcular la retención del impuesto a las ganancias cuando hay que pagar a un proveedor. En Argentina, puede que las reglas sean algo complejas para calcular. No sé el estado actual del tema, pero en su tiempo podía depender del servicio dado por el proveedor, de si el servicio abarcaba varias provincias (por ejemplo, un flete que comenzaba en una provincia y terminaba en otra), de lo que nos había facturado en el último mes, de si el proveedor tenía domicilio en una zona de promoción industrial o no, etc. Sea así o no ahora, me sirve como idea de base.
¿Cómo se encararía programar eso con TDD, y base de datos?
Como siempre, paso a paso, “baby steps”. Seguramente atacaríamos primero algunos casos sencillos y luego otros casos más complicados. Cuando se llegue a estos casos (por ejemplo el proveedor con promoción industrial) ponemos en la base de datos bien conocida, un proveedor X que cumpla con lo que necesitamos para el test que estamos desarrollando. Es decir, a medida que resolvemos los test, va quedando en la base (en scripts de creación con datos iniciales) los escenarios que vamos necesitando. Probablemente, un test solamente necesite crear al proveedor (en la etapa de Arrange). Si lo necesitamos a ese proveedor para varios tests, habrá refactor del test para que haya una rutina que lo cree. Pero cuando ya lo necesitamos para varias situaciones, migrará su existencia directamente a la base de datos bien conocida.
Cada desarrollador del equipo, cuando traer el último código del repositorio, podrá ver si alguien modificó los scripts de creación de la base. Y aún si no se da cuenta, al ejecutar los tests de TDD, seguramente alguno quedará en rojo, adviertiendo que algo de base ha cambiado. Toda esta forma de trabajo también sirve cuando en el desarrollo se va cambiando la estructura de la base. Y les sirve para no tener que adoptar mi consejo de modelo en memoria, si aún no se animan a esa forma de trabajo.
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Es tiempo de escribir un post explicando mi interés personal en algunos temas, como lenguajes de programación, mensajería, computación distribuida e inteligencia artificial. Soy varios temas, espero poder transmitir algunas ideas sobre ellos.
Muchos de nosotros estamos interesados en esos temas. Son interesantes por sí mismos, y estudiarlos y explorarlos es divertido e interesante. Como desarrolladores de software, nos gusta jugar con ellos: escribir un nuevo lenguaje de programación, implementar uno existente, armar aplicaciones distribuidas, etc.
Pero en mi caso, hay algo más, una base común a todos estos temas. Por ejemplo, tomemos los lenguajes de programación. Los actuales lenguajes pueden ser extendidos para soportar, con menos fricción, la serialización de objetos simples (sin conducta, simples mensajes) para usarlos en aplicaciones distribuidas. Hay dos formas de hacerlo, en principio: extender los lenguajes con nueva sintaxis para soportar la distribución del trabajo, o agregando nuevas librerías. Ver como ejemplo Scala o Akka. Así que, para tener un mejor entendimiento de lo que se necesita, escribí mis propios proyectos personales: mi lenguaje interpretado (AjSharp), extención de Smalltalk (AjTalk) para ejecutar objetos distribuidos, escribir agentes y demos de actores (AjAgents, y agentes en AjSharp), mensajes distribuidos (en AjFabriq) y en los últimos tiempos, explorando JavaScript con Node.js (SimpleMessages, SimpleQueue, MultiNodes, SimpleRemote, SimpleActors… ), todo esto para tener las piezas necesarias para escribir y ejecutar aplicaciones distribuidas. Claro que hay multitud de proyectos ya existentes que podría usar. Pero escribir mis propias implementaciones me entrena, me hace practicar y obtener un mejor entendimiendo de los problemas y soluciones a implementar. De paso, es muy divertido :-)
Pero ¿por qué computación distribuida? Estoy convencido que es el camino a explorar para implementar una nueva clase de aplicaciones. Fundamentalmente, aplicaciones que resuelvan problemas complicados, que puedan ser abordados usando computación en paralelo y escalabilidad horizontal. No solamente para procesamiento de Big Data. Hay vida más allá de analizar tweets en tiempo real. La idea es abordar problemas de inteligencia artificial, usando computación distribuida y hardware existente.
Esta es, entonces, el gran fondo de mi escenario de desarrollo: lenguajes de programación fexibles; mensajería para soportar programación distribuida; y aplicaciones distribuidas para la siguiente generacièn de problemas a resolver.
Sí, la próxima frontera. Donde jamás hemos llegado ;-)
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Es tiempo de revisar mis resoluciones de Enero:
- Empezar SimpleScript [completo] ver repo
- Empezar SimpleBoard [completo] ver repo
- Empezar SimpleChess [completo] ver repo
- Empezar SimpleGo [completo] ver repo
- Empezar y publicar una versión de SimpleMapReduce, con ejemplo local y distribuido [parcial] ver repo (hay ejemplo local, y un incipiente ejemplo distribuido)
- Empezar y publicar una versión de SimpleFunc, serialización de funciones en objetos [completo] ver repo
- Empezar Memolap, una librería tipo OLAP multidimensional en memoria, escrita en C#, con ejemplo [parcial] ver repo (el ejemplo es Work in Progress)
- Empezar SimpleMemolap, lo mismo que Memolap, pero en JavaScript/Node.js, con ejemplo [completo] ver repo
- Empezar SimpleRules, un motor de reglas con encadenamiento hacia adelante, que compila a JavaScript [completo] ver repo
Adicionalmente estuve trabajando en:
- Actualizar AjConsorSite [completo] ver repo
- Actualizar Inmob [completo] ver repo
- Empezar SimpleKeeper, un servidor tipo Zookeeper [completo] ver repo
- Actualizar y publicar la primera versión de MultiNodes [completo] ver repo
- Actualizar SimpleStorm, publicar nueva versión que usa SimpleQueue 0.0.2 [completo] ver repo
- Actualizar SimpleQueue publicar nueva versión [completo] ver repo
- Actualizar SimpleRemote publicar nueva versión usando SimpleMessages SimpleMessages 0.0.3, y métodos asincrónicos [completo] ver repo
- Publicar la primera versión de AjFabriqNode [completo] ver repo
- Empezar y publicar la primera versión de NodeDelicious [completo] ver repo
- Refactorear SimpleBroadcast para que use SimpleMessages 0.0.3 [completo] ver repo
- Publicar nueva versión SimpleMessages 0.0.3 [completo] ver repo
- Empezar y publicar primera versión de MProc, una capa de encadenamiento de middleware de proceso de mensajes en Node.js, [completo] ver repo
- Empezar y publicar primera versión SimpleTags, motor para manjear items con datos arbitrarios asociados a tags [completo] ver repo
- Empezar y publicar primera versión ObjectStream, stream de objetos, unidireccional y bidireccional, para Node.js [completo] ver repo
- Empezar y publicar primera versión de SimplePipes, otra librería de flujo de datos en Node.js [completo] ver repo
- Empezar y publicar la primera versión de SimpleSudoku, resuelve sudoku en JavaScript/Node.js [completo] ver repo
- Empezar y publicar la primera versión de SimplePermissions, permisos por Sujeto, Rol, Contexto, con modelo en memoria [completo] ver repo
- Empezar y publicar primera versión de SimpleGlobals, inspirado por Mumps Globals [completo] ver repo
- Empezar y publicar la primera versión de SimpleInvoke, invocación encadenada de funciones con callbacks, para JavaScript/NodeJs [completo] ver repo
Para este nuevo mes, me propongo:
- Empezar SimpleDatabase
- Actualizar SimplePermissions
- Actualizar SimpleStorm (implementar ack, puede que integrarlo con MultiNodes)
- Actualizar SimpleMapReduce
- Actualizar SimpleKeeper, agregar nodo líder, ejemplo distribuido
- Actualizar AjFabriqNode, para que use el nuevo SimpleMessages, quizás integrarlo con MultiNodes
- Actualizar MultiNodes
- Actualizar AjGenesisNode, para que use comandos globales y tareas
También voy a dar un seminario de todo un día sobre Node.js en Rosario, Argentina
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez