Aktores Implementando Akka Actor Model en C# (2) Un simple Ejemplo

Anterior Post

Veamos hoy un simple ejemplo que crea dos actores y les envía mensaje. El código completo está en:

https://github.com/ajlopez/Aktores/tree/master/Samples/PingPong

Como siempre, todo es “trabajo en progreso”, y puede cambiar en el futuro. Estoy siguiendo el flujo de trabajo de TDD (Test-Driven Development), así que alguna llamada a la API puede ir cambiado, o cambiar algún concepto de base, a medida que me planteo casos de uso cada vez más interesantes (ya llegué a implementar caso de uso distribuido, por ejemplo).

En este ejemplo, tenemos un actor:

using Aktores.Core;

public class PingActor : Actor
{
    private int messagecount;

    public int MessageCount { get { return this.messagecount; } }

    public override void Receive(object message)
    {
        messagecount++;
        this.Sender.Tell("ping", this.Self);
    }
}

Vean que un actor desciende de una clase base Actor. El gran método a implementar es el Receive, que recibe un mensaje enviado por alguien en el sistema (otro actor, otro objeto) a nuestra instancia. Aktores se asegura que los mensajes nos lleguen y se procesen de a uno por vez. En el actor de arriba, una vez recibido un mensaje, incrementa un contador y le responde al enviador del mensaje original con otro mensaje (el enviador está referenciado en this.Self, DURANTE el proceso de un mensaje; luego puede cambiar al llegar otro mensaje).


Otro actor similar:

using Aktores.Core;

public class PongActor : Actor
{
    private int messagecount;

    public int MessageCount { get { return this.messagecount; } }

    public override void Receive(object message)
    {
        messagecount++;
        this.Sender.Tell("pong", this.Self);
    }
}

El programa principal, lo que hace, es crear un sistema de actores, crear dos actores, uno del tipo Ping y otro del tipo Pong, y luego le envía mensajes a procesar:

public static void Main(string[] args)
{
    ActorSystem system = new ActorSystem(2);
    var pingactor = new PingActor();
    var pongactor = new PongActor();
    
    var ping = system.ActorOf(pingactor);
    var pong = system.ActorOf(pongactor);

    for (int k = 0; k < 10; k++)
    {
        ping.Tell("pong", pong);
        pong.Tell("ping", ping);
    }

    // ....
}

Tiene código adicional para medir la cantidad de mensajes que se procesan en el tiempo. El parámetro 2 en el constructor de ActorSystem indica que necesita DOS threads de trabajo interno para procesar mensajes. Deberé revisar si esa información queda ahí o de otra manera. Dos threads son suficientes porque no tenemos más que dos instancias de actores, pero podríamos poner otro número si usamos más actores.


Nos leemos!


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

Posted in .NET, Actor Model, Aktores, C, C#, Proyectos Open Source | Comments Off

SimpleLisp (2) Compilando Valores y Variables Lisp a JavaScript

Anterior Post

Veamos algo de la implementación del proyecto

https://github.com/ajlopez/SimpleLisp

el compilador de Lisp a JavaScript, escrito en JavaScript, siguiendo el flujo de trabajo de TDD (Test-Driven Development). Todo es “trabajo en progreso” así que lo explico hoy es la implementación actual, de este día, que puede ir cambiando a medida que se vayan implementando nuevos casos de uso.

Tomé la decisión de que cada símbolo de Lisp sea una variable de JavaScript. Así que la compilación de un símbolo queda expresada en este test:

exports['compile symbol'] = function (test) {
    test.equal(sl.compile('a'), 'a');
}


El sl es módulo SimpleLisp que ya tengo cargado con require, al principio de los tests. Este test de arriba lo tomé de test/compile.js


Un entero y un string se compilan a valores naturales en JavaScript:

exports['compile integer'] = function (test) {
    test.equal(sl.compile('42'), '42');
}

exports['compile string'] = function (test) {
    test.equal(sl.compile('"foo"'), '"foo"');
}

También se compilan a valores naturales sus valores “quoted”:

exports['compile quoted integer'] = function (test) {
    test.equal(sl.compile("'42"), '42');
}

exports['compile quoted string'] = function (test) {
    test.equal(sl.compile("'\"foo\""), '"foo"');
}

Decidí tratar a nil como el null de JavaScript. Los valores booleanos se compilan tal cual:

exports['compile nil'] = function (test) {
    test.equal(sl.compile('nil'), 'null');
}

exports['compile booleans'] = function (test) {
    test.strictEqual(sl.compile('false'), 'false');
    test.strictEqual(sl.compile('true'), 'true');
}

¿Pero qué pasa si hay que compilar una serie de expresiones Lisp? Armo una función anónima, la invoco sin parámetros, y devuelvo el valor de la última expresión:

exports['compile two symbols'] = function (test) {
    test.equal(sl.compile('a b'), '(function () { a; return b; })()');
}

Próximos temas: compilación de una lista y de valores quoted más complejos.


Nos leemos!


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

Posted in JavaScript, Lisp, NodeJs, Proyectos Open Source, SimpleLisp, Te, Test-Driven Development | Comments Off

Resoluciones del Nuevo Mes: Diciembre 2014

Es tiempo de revisar las resoluciones del mes pasado:

- Dar una charla sobre JavaScript e Inteligencia Artificial [completo] ver repo ver presentación leer post
- Ejemplo de Red Neuronal en JavaScript [completo] ver repo
- Ejemplos de Algoritmos Genéticos en JavaScript [completo] ver repo
- Más Generación de Código con AjGenesis para Node.js [pendiente]
- Basic Script Language para C# [pendiente]
- Mejorar SimpleScript para JavaScript [completo] ver repo

También estuve trabajando en:

- Mejorar SimpleLisp, compilador Lisp a JavaScript [completo] ver repo
- Mejorar RuScript, intérprete Ruby en JavaScript [completo] ver repo
- Mejorar RustScript, intérprete Rust (no tipado) en JavaScript [completo] ver repo
- Crear SimpleDT, un simple árbol de decisión en JavaScript [completo] ver repo
- Mejorar ClojSharp, un intérprete Clojure en C# [completo] ver repo
- Evaluación de Backgammon en página HTML [completo] ver repo

Las resoluciones para este nuevo mes de Diciembre:

- Agregar características distribuidas a AjElr, un Erlang interpretado en C#
- Mejorar ClojSharp, un Clojure en C#
- Mejorar SimpleLisp, compilador de Lisp a JavaScript, escrito en JavaScript
- Generación de código con with AjGenesis para Node
- Comezar Basic Script Language en C#

Nos leemos!

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

Posted in .NET, C#, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

JavaScript e Inteligencia Artificial (2)

Anterior Post

Gracias a la gente de JSConf Argentina 2014 por haberme dado la oportunidad de dar esta charla, ayer, en esa excelente conferencia. Para darle un formato dinámico, las charlas fueron de veinte minutos. Quisiera en esta serie de posts completar la exposición de lo que quería mostrar, comentando más en detalle algunos puntos, y presentando también otras demos y proyectos que quedaron fuera de la charla.

El tema de hoy es recomendarles EL libro que me sirvió de guía de estudio para un tema interminable, un clásico de la ciencia de la computación (el cuarto más citado en este siglo):

Artificial Intelligence, a Modern Approach
http://aima.cs.berkeley.edu/

de Stuart Russell y Peter Norvig. Para saber más sobre la tapa de la última edición, ver:

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

Hay alguna edición en español, y yo la habré conseguido en las librerías de Buenos Aires, ya hace unos años. Son algo más de mil páginas, en veintisiete capítulos y apéndices, donde se visita desde agentes inteligentes hasta redes neuronales, desde algoritmos de búsqueda y evaluación de árboles hasta robótica y temas filosóficos. Me parece muy interesante que cada capítulo esté acompañado de notas sobre la historia del tema, lo que siempre pienso que nos da perspectiva y mejor comprensión sobre los problemas y dificultades en un desarrollo. No hay que quedarse solamente con “lo que se sabe ahora”, sino también estudiar cuál fue el camino seguido para llegar al estado actual, lo que también puede servir para entender cuál es el futuro que podemos seguir.

Tienen el seudocódigo de los ejemplos en http://aima.cs.berkeley.edu/algorithms.pdf  y también en código Lisp, Python, Java en http://aima.cs.berkeley.edu/code.html

Es interminable también para investigar: AI on the web http://aima.cs.berkeley.edu/ai.html

En la edición que tengo, no aparece JavaScript como lenguaje de programación a usar. Es un buen ejercicio ir adaptando los ejemplos en seudocódigo a implementaciones en distintos lenguajes. Cada tanto, trato de implementar algo en el proyecto https://github.com/ajlopez/NodeAima. Notablemente, JavaScript debe ser el lenguaje más simple para implementar muchas de las ideas del libro. Implementaciones en lenguajes tipados y no dinámicos, como Java y C#, me parecen que tienen siempre algo de “convoluted” comparando con una implementación directa en JavaScript. Ver por ejemplo https://github.com/ajlopez/SharpAima

Nos leemos!

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

Posted in Charlas, Inteligencia Artificial, JavaScript, NodeJs | Comments Off

JavaScript e Inteligencia Artificial (1)

Siguiente Post

Gracias a la gente de JSConf Argentina 2014, hoy voy a estar dando una charla corta sobre JavaScript e Inteligencia Artificial. La idea es presentar rápidamente algunas ideas, algoritmos, demo de implementaciones, y cerrar con comentarios sobre lo que parece interesante seguir. Inteligencia Artificial es un término muy amplio, y que nació hace décadas. Desde entonces, ha ido acumulando definiciones, ambiciones, herramientas y aproximaciones a tratar de construir agentes inteligentes.

El repositorio de la charla en:

https://github.com/ajlopez/JavaScriptAI

donde hay enlaces a los proyectos presentados, demos, y recursos adicionales.

Los “fuentes” de la presentación de la charla en:

https://github.com/ajlopez/Talks/tree/master/JavaScriptAI

La presentación en línea en:

http://ajlopez.github.io/Talks/JavaScriptAI/index.html#/
http://ajlopez.github.io/Talks/

En la charla visito dos grandes temas: algoritmos genéticos, y redes neuronales. También hay un corto tiempo dedicado a explorar un árbol de juego de tablero. Y hay una demo de algoritmo genético aplicado a programación evolutiva. Quedó fuera de la charla el tema de crear árboles de decisiones, basados en datos. Pero ya lo voy a comentar en los próximos posts las ideas, demos y recursos que me interesaron, y los proyectos que estuve escribiendo.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Posted in Algoritmos Genéticos, Charlas, Inteligencia Artificial, JavaScript, NodeJs, Proyectos Open Source, Redes Neuronales | Comments Off

SimpleScript (3) El Parser, Expresiones y Comandos

Anterior Post

Veamos hoy parte del Parser, que es un módulo separado. Comienza con una declaración sencilla:

'use strict';

var lexer;

if (typeof lexer == 'undefined')
    lexer = require('./lexer');

var parser = (function () {
    var TokenType = lexer.TokenType;
    var binoperators = [ "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=" ];

Usa a lexer, y lo requiere. Luego hay definidos expresiones y comandos. Por ejemplo, esta es la expresión para un simple nombre (por ejemplo, foo):

function NameExpression(name) {
    this.isLeftValue = true;

    this.compile = function () {
        return name;
    };

    this.getName = function () {
        return name;
    }

    this.collectContext = function (context) {
        context.declare(name);
    }
}

Veremos en el próximo post cómo se detecta y construye esta expresión. Una expresión cualquiera tiene que implementar por lo menos dos métodos: compile, que devuelve la expresión compilada a un string de código JavaScript, y collectContext, que permite descubrir las variables declaradas en un programa. En este caso, la NameExpression declara a su nombre (por ejemplo, “foo”), como una variable declarada en el programa (esto es necesario para tener implementado el “hoisting” como en JavaScript).


Veamos una IndexedExpression: compuesta de una expresión y otra expresión para el índice (representaría expresiones como foo[42+1]):

function IndexedExpression(expr, indexpr) {
    this.isLeftValue = true;

    this.compile = function () {
        return expr.compile() + '[' + indexpr.compile() + ']';
    };

    this.collectContext = function (context) {
        expr.collectContext(context);
    }
}

Vean como ahora el collectContext se toma el trabajo de visitar la expresión interna (no vi que fuera necesario visitar y descubrir variables en la expresión de índice, pero puede que lo agregue; esa expresión en general es simple, pero bien podría tener usada una variable).


Pero también hay comandos. Puedo poner como ejemplo el IfCommand:

function IfCommand(cond, thencmd, elsecmd) {
    this.compile = function () {
        var code = 'if (' + cond.compile() + ') { ' + thencmd.compile() + ' }';
        if (elsecmd)
            code += ' else { ' + elsecmd.compile() + ' }';
        return code;
    };

    this.collectContext = function (context) {
        cond.collectContext(context);
        thencmd.collectContext(context);
        if (elsecmd)
            elsecmd.collectContext(context);
    }
}

La distinción entre comandos y expresiones es por ahora puramente formal. Vean que este comando tiene que implementar cómo se compila a JavaScript un if, dado la cond (expresión de la condición), el thencmd (el comando de la rama then), y el elsecmd (el comando de la rama else, que es opcional). Y el collectContext deriva a esas subpartes.


Como siempre, desarrollo paso a paso, usando el flujo de trabajo de TDD (Test-Driven Development). Ejemplo parcial:

exports['Compile string without quotes inside'] = function (test) {
    test.equal(compileExpression("'foo'", test), "'foo'");
    test.equal(compileExpression('"foo"', test), "'foo'");
}

exports['Compile name'] = function (test) {
    test.equal(compileExpression("foo", test), "foo");
}

exports['Qualified name'] = function (test) {
    test.equal(compileExpression("foo.bar", test), "foo.bar");
}

exports['Indexed term'] = function (test) {
    test.equal(compileExpression("foo[bar]", test), "foo[bar]");
}

Ya saben ;-) Sin TDD no hay paraíso!


Próximos temas: cómo se reconocen las expresiones y comandos.


Nos leemos!


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

Posted in JavaScript, NodeJs, Proyectos Open Source, SimpleScript, Test-Driven Development | Comments Off

SimpleLisp (1) Compilando Lisp a JavaScript

Siguiente Post

Ya varias veces implementé un intérprete Lisp, en C#, en Java, en JavaScript. Ver proyectos

https://github.com/ajlopez/AjLisp
https://github.com/ajlopez/AjLispJava
https://github.com/ajlopez/AjLispJs

Siempre es bueno implementar Lisp. Es un lenguaje simple, sencillo, poderoso, con funciones como ciudadanos de primera clase, y con el “twist” de implementar: algunas funciones que no evalúan de antemano sus argumentos, y macros.

Pero esta vez quiero implementar un compiladr Lisp. Es decir, algo que traslade al lenguaje anfitrión el programa Lisp. He elegido JavaScript como lenguaje anfitrión, y también como lenguaje de compilación: JavaScript mismo es el encargado de leer y traducir código Lisp a JavaScript. Pueden ver mi avance en

https://github.com/ajlopez/SimpleLisp

Como es costumbre, todo armado siguiendo el flujo de trabajo de TDD (Test-Driven Development), y sin tener todo el diseño de antemano, simplemente va surgiendo con los pequeños casos de uso que voy incorporando. Como es mi primer compilador Lisp, estoy aprendiendo nuevas formas de implementar el lenguaje. Algo vi en los últimos años al toparme con Clojure, que compila a Java, a CLR y a JavaScript. Lo que veo que tengo que implementar es:

Símbolos: identificadores por nombre, con valor asociado. Los estoy compilando a variables de JavaScript. En SimpleLisp, un símbolo puede quedar definido para el tope del programa, para un bloque let, o como argumento de una función. Entonces, depende del caso, lo paso a una variable tope de JavaScript (o al menos, tope en el módulo que estoy armando en compilación), a una variable local, o a un argumento con nombre.

Funciones: traducir una función normal de Lisp a una función normal de JavaScript. Lo único diferente es que las funciones de Lisp siempre devuelven en un valor, los “comandos” son siempre expresiones, como en Ruby. Una lista a evaluar en SimpleLisp la compilo a una llamada a función simple en JavaScript.

Special Forms: Su implementación es novedosa para mí. Ahora que tengo que compilar, no interpretar, cada vez que me topo con un una lista cuya cabeza es un if, un do, un let, etc…  voy y la compilo de forma especial a JavaScript. Un (if … ) de SimpleLisp queda transformado en un if de JavaScript (es un poco más complicado, porque el if de SimpleLisp tiene que devolver un valor, es una expresión, mientras que un if de JavaScript es un comando; ya veremos en futuro post la implementación que adopté).

Macros: De nuevo, al tener que compilar, puedo adoptar una implementación nueva: expandir la macro AL MOMENTO DE COMPILAR. Veremos hasta donde puedo llegar con este camino. Una consecuencia que veo: no puedo pasar una macro como valor funcional como argumento de otra función. Justamente, lo que pasa en Clojure: las macros no son valores funcionales, son “trucos” que se expande en tiempo de compilación.

Y como en otras implementaciones, agrego acceso a invocar JavaScript nativo desde SimpleLisp. Mi idea es poder escribir un sitio Node.js/Express con SimpleLisp.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Posted in JavaScript, Lenguajes de Programación, Lisp, NodeJs, Proyectos Open Source, SimpleLisp, Test-Driven Development | Comments Off

SimpleScript (2) El Lexer

Anterior Post
Siguiente Post

Sigo en estos días mejorando mi compilador de SimpleScript a JavaScript. Hoy quería comentar por encima la existencia e implementación de un Lexer. Ver el repo en

http://github.com/ajlopez/SimpleScript

El Lexer está ahora separado en un archivo lib/lexer.js, que establece un módulo, consumible desde Node.js y desde el browser cuando alguna vez lo necesite. Comienza definiendo los tipos de token que va a ir entregando:
var lexer = (function () {
    var TokenType = { 
        Name: 1, 
        Integer: 2, 
        Real: 3, 
        String: 4, 
        NewLine: 5, 
        Separator: 6, 
        Assignment: 7 };
        

Luego define algunos operadores, separadores y lo que sería un Token, con dos elementos: tipo y valor.
var separators = ".,()[]";
var assignments = ["=", "+=", "-=", "*=", "/="];
var operators = ["+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">="];

function Token(value, type) {
    this.value = value;
    this.type = type;
}

Y luego el gran trabajo lo realiza una “clase” interna Lexer, cuyo principal método es nextToken():
function Lexer(text) {
    var length = text ? text.length : 0;
    var position = 0;
    var next = [];

    this.nextToken = function () {
        if (next.length > 0)
            return next.pop();

        skipSpaces();

        var ch = nextChar();

        if (ch === null)
            return null;

        if (ch === '"' || ch === "'")
            return nextString(ch);

        if (ch === '\n')
            return new Token(ch, TokenType.NewLine);

        if (ch === '\r') {
            var ch2 = nextChar();

            if (ch2 === '\n')
                return new Token(ch + ch2, TokenType.NewLine);

            if (ch2)
                pushChar(ch2);

            return new Token(ch, TokenType.NewLine);
        }

        if (isAssignment(ch))
            return new Token(ch, TokenType.Assignment);

        if (isOperator(ch))
            return nextOperator(ch);

        if (isSeparator(ch))
            return new Token(ch, TokenType.Separator);

        if (isFirstCharOfName(ch))
            return nextName(ch);

        if (isDigit(ch))
            return nextInteger(ch);
    }

Finalmente el módulo expone hacia afuera una factoría de lexers, y la enumeración de los tipos de token:
return {
    lexer: function (text) { return new Lexer(text); },
    TokenType: TokenType
}

Finalmente, esto no estaría completo sin notar que hay un test/lexer.js que fue armado de pasos, junto con lib/lexer.js, siguiendo Test-Driven Development (con algunos refactors, hubo un tiempo que lib/lexer.js no estaba como archivo separado), fragmento:
function getToken(text, value, type, test) {
    var lexer = sslexer.lexer(text);
    var token = lexer.nextToken();
    test.ok(token);
    test.equal(token.value, value);
    test.equal(token.type, type);
    test.equal(lexer.nextToken(), null);
};

exports['Get names'] = function (test) {
    getToken('foo', 'foo', TokenType.Name, test);
    getToken('foo123', 'foo123', TokenType.Name, test);
    getToken('foo_123', 'foo_123', TokenType.Name, test);
    getToken('_foo', '_foo', TokenType.Name, test);
}

exports['Get integer'] = function (test) {
    getToken('123', '123', TokenType.Integer, test);
    getToken('1234567890', '1234567890', TokenType.Integer, test);
}

Recuerden: sin TDD no hay paraíso ;-)

Próximos temas: el parser, comandos, expresiones, compilación a JavaScript.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez
Posted in JavaScript, NodeJs, Proyectos Open Source, SimpleScript, Test-Driven Development | Comments Off

Arquitectura y Desarrollo Agil

Hace unos días apareció un hilo de discusión interesante en la lista foro-agiles sobre si la arquitectura emerge. Hubo varios aportes y distintas posturas, los invito a leer por ahí todo lo que se escribió y expuso.

Quisiera esta en mi blog, escribir algo sobre el tema. Primero, algo de contexto. Voy a escribir sobre:

- Proyecto profesional o personal
- Ejecutado por un equipo ágil o por uno mismo
- Proyecto donde el principal entregable es software

Al poner lo ágil en el contexto, estoy asumiendo que vamos a abrazar el cambio, uno de los pilares de lo ágil. Se ha visto que en el desarrollo de software es difícil basarse en algo fijo, sino que lo que se va desarrollando se va descubriendo, desplegando, y mejorando a medida que se va construyendo. Es también difícil tener todo definido de antemano. Otro de los puntos que voy a poner en claro, es que lo que necesitamos es basarnos en los casos de uso, por lo menos en gran parte. Escribí sobre el tema en TDD y Casos de Uso. Recuerdo de ahí alguna cita de @unclebobmartin:

The center of your application is not the database. Nor is it one or more of the frameworks you may be using. The center of your application are the use cases of your application.

It makes me crazy when I hear a software developer describe his system as a “Tomcat system using Spring and Hibernate using Oracle”. The very wording puts the frameworks and the database at the center.

What do you think the architecture of that system would look like? Do you think you’d find the use cases at the center of the design? Or would you find the source code arranged to fit nicely into the pattern of the frameworks? Would you find business objects that looked suspiciously like database rows? Would the schema and the frameworks pollute everything?

Here’s what an application should look like. The use cases should be the highest level and most visible architectural entities. The use cases are at the center. Always! Databases and frameworks are details! You don’t have to decide upon them up front. You can push them off until later, once you’ve got all the use cases and business rules figured out, written, and tested.

Amen!!! Si no tenemos en claro los casos de uso, no podemos tomar grandes decisiones, y menos de arquitectura. Sé que parece que en muchos sistemas los casos de uso parecen estar dados desde el principio, pero en mi experiencia profesional, no veo que haya sido así. Lo que uno presupone, por ejemplo, en un Sprint 0, no termina siendo el caso a las pocas semanas de desarrollo. Es por eso que la arquitectura no es algo que se pueda plantear convenientemente desde el principio, sino que es algo que tenemos que ir desplegando a medida que tengamos más masticados, digeridos, analizados, incorporados los casos de uso que vamos implementando.

“Arquitectura” es un término amplio. Veamos de poner algún ejemplo, para poner un contexto más definido. Supongo que tenemos que nuestro cliente es una petrolera, y tenemos que desarrollar un sistema que recibe mensajes de uno o dos sistemas, que luego pueden ser más, y necesitamos procesarlos, por ejemplo, dado un mensaje que indique que hay un nuevo pozo de perforación, entregar los nuevos datos a dos o tres sistemas que ya están funcionando, y prever que se pueda entregar a otros sistemas que vayan apareciendo. Uno podría verse tentado desde el comienzo: “Bien, es un caso para implementar con un Service Bus”. O “bien, es un caso para implementar usando Storm de Java”, o “acá hay que poner un BPM”. En mi experiencia, semenjante tipo de decisiones son tempranas, y hasta incorrectas o al menos, nos van a desviar de los casos de uso a implementar. Si tuviera que hacerlo yo solo, o si convenzo a mi equipo de la postura que estoy promoviendo en este post, lo haría: “Primero los casos de uso, simple proceso de mensajes, en un simple programa”. Solamente cuando tenga ya uno o varios casos de uso concretos implementados, podría ver cuál es la carga de mensajes (¿10 por día, 100000 por segundo?), la dificultad o facilidad de acceso a los sistemas finales ya existentes, la importancia (o no) de procesar un mensaje en menos de un minuto o en una semana, descubrir una “ley de Pareto”: el 80% de lo importante viene en el 20% de los mensajes, y se cubren con este y este otro caso de uso, etc… Sólo luego de haberse empapado de los casos de uso, y haber implementados algunos, podrá verse más en claro las necesidades de arquitectura que tenemos.

Pero alguien podrá decir ¿no es más trabajo? Así, parece que primero implementamos un caso de uso, y luego tenemos que reimplementarlo al cambiar la arquitectura. De nuevo, mi experiencia indica: la primera implementación es un “baby step” que sirve para ir aproximándonos al problema, sin “bajada de línea” previa. Y luego, seguimos mejorando la implementación, cambiando decisiones de arquitectura. Si realmente abrazamos lo ágil (por ejemplo, adoptando disciplinas como Test-Driven Development), los cambios no cuestan, y las decisiones diferidas no implican un costo, apenas algún esfuerzo. Y si luego vemos que una decisión de arquitectura no es la mejor, porque aparecen nuevos contextos, nuevos casos de uso, nuevas fuerzas, SI ABRAZAMOS LO AGIL, el cambio de implementación, y el cambio de decisión, tampoco debería tener un gran costo.

Eso es lo que veo que tiene que hacer el rol de arquitecto (hablo de rol, y no de puesto): saber diferir decisiones, y saber tomar decisiones diferidas que se puedan cambiar. Por más seguro que estemos “X es el camino a seguir (sea X BPM, MapReduce, Actor model, procesamiento distribuido usando colas… )” SI ABRAZAMOS LO AGIL debemos tomar decisiones CAMBIABLES y DIFERIBLES. Algunas de esas decisiones involucran lo que se llama (ampliamente, insisto) “arquitectura”.

Ahora bien, SI NO ABRAZAMOS lo ágil, y no adoptamos las disciplinas técnicas, duras y blandas que permiten encarar el cambio y el desarrollo evolutivo, entonces sí, vamos a tener problemas en la decisiones diferidas. Cada cambio nos va a costar, cosa que en el pasado “Waterfall” se quería evitar DEFINIENDO la mayor parte del sistema de antemano.

He visto sistemas, que por adoptar una decisión temprana, terminan perdiendo el rumbo. Todo el equipo queda con inercia, y todo caso de uso de uso lo quiere solucionar usando la decisión temprana, que se tomó como LA SOLUCION. Por ejemplo, si la decisión fue “vamos a usar Hadoop”, por más que los casos de uso que vengan clamen por otro tipo de solución, el equipo sigue mapeando todo problema a un Map Reduce distribuido.

Pero si diferimos las decisiones, tenemos más cintura. Ya el propio diferimiento permite que cuando se tome una decisión, el sistema no esté anquilosado, dirigido, congelado solamente a esa decisión. Aunque al final la decisión diferida sea la misma que nos dictaba nuestro “pequeño arquitecto yomelasetodas” desde el principio, el haber implementado gran parte de la solución sin haber tomado la decisión de arquitectura, permite armar un sistema más claro, más simple, donde elementos de arquitectura aparecen claramente por aparecer nuevas fuerzas que tenemos que tomar en cuenta, más que por sesudas ideas en general en el aire tomadas al comienzo. Y por lo que ví en estos años del tercer milenio, esa adopción diferida le da más calidad de “si surgen nuevas fuerzas o casos, podemos cambiar la decisión”, nos da un sistema más adaptable a cualquier cambio que aparezca en el futuro. Porque también eso es algo bueno para el rol de arquitecto: estar advertido que lo que estamos armando, si tiene éxito, va a evolucionar. En vez de hacerlo flexible desde el vamos, es mejor hacerlo cambiable, algo que veo que se va ejercitando con cada decisión diferida.

Imagen tomada de Swarm Intelligence. Me gustó la idea y la imagen, pero vean que abandono el adjetivo “emergente” en lo que escribí luego del primer párrafo, porque da a entender como que la arquitectura aparece sin intervención del equipo, por simple dinámica compleja.

Nos leemos!

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

Posted in Arquitectura de Software, Desarrollo Agil, Programacion, Test-Driven Development | Comments Off

Resoluciones del Nuevo Mes: Noviembre 2014

Tiempo de revisar las resoluciones del mes pasado:

- Dar una charla introductoria a Aktores [completo] ver repo see presentation
- AjErl distribuido [pendiente]
- Más ejemplos Express en AjTalkJs [completo] ver repo
- Explorar redes neuronales en JavaScript [completo] ver repo
- Explorar algoritmos genéticos en JavaScript [parcial] ver repo
- Explorar otros temas de inteligencia artificial en JavaScript [parcial]
- Más Aktores distribuidos [pendiente]
- Comenzar Smalltalk distribuido en AjTalkJs [completo] ver repo

Las resoluciones del nuevo mes:

- Dar una charla sobre JavaScript e Inteligencia Artificial
- Ejemplo de Red Neuronal en JavaScript
- Ejemplo de Algoritmo Genético en JavaScript
- Más Generación de Código con AjGenesis en NodeJs
- Basic Script Language en C#
- Mejorar SimpleScript para JavaScript

Nos leemos!

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

Posted in .NET, C#, JavaScript, NodeJs, Proyectos Open Source, Resoluciones | Leave a comment