[Languages] Mi lenguaje de programación (Parte I – Ideas)

Hace algún tiempo que vengo pensando y me vengo autoconvenciendo de que el nivel de abstracción que normalmente se utiliza en el desarrollo de aplicaciones dirigida por los datos no es el adecuado. Este tema ya lo toqué en otros post sobre Domain Specific Language y sobre Software Factories así le doy una vuelta más de rosca y presento mi lenguaje de programación.

Veamos como se desarrolla un software: Nos llegan los requerimientos de nuestro Program Manager/Team Leader y, después de las reuniones de rutina y una vez que tenemos las ideas y los documentos,  llega la hora de echarle mano al código y entonces comenzamos así:

C# Code
using System.IO;


public class Product
{
   private string productName;

   public string Name
   {
       get {...} 
       set {...} 
   }
}

La pregunta es: puede ser esta la manera más natural de especificar el comportamiento y las cualidades de un componente de catálogo de productos? No estaremos hilando demasiado fino? Es más, me atrevo a preguntar: no debería estar hecho ya por alguien más o es que acaso nadie nunca escribió un producto que trabajase con productos?. Está bien, acepto que para algo así falta mucho, que habria que estandarizar bloques de construcción y un montón de cosas más pero la pregunta inicial sigue en pie. Son los lenguajes de propósito general los adecuados para todos los casos particulares? Claro que no. Aquí es donde entran, entre otras cosas, los DSLs o Lenguajes específicos de un dominio.

A mi humilde entender, no es posible seguir construyendo software como lo venimos haciendo hasta ahora, reescribiendo bloques de código enteros, con un nivel de abstracción bajísimo y todavia muy lejos del lenguaje natural, tiempos largos, costos altos, impedancias de todo tipo (All vs. OOP); lo que resumiendo es calidad pobre. 

Pienso que una alternativa a todo esto es la generación automática de mucho (realmente  mucho) código y en este punto entran los DSL (Domain Specific Language), lenguajes especialmente diseñados para un propósito muy particular como SQL, HTML, UML, COBOL y otros (por favor no piensen en DSL Tools porque no estoy hablando de ellos, o al menos no solo de ellos).  

De repente hoy existen un gran número de lenguajes de propósito general con frameworks, paquetes, componentes, librerias para todo lo imaginable pero con un poder expresivo que no se compara con el de un lenguaje de propósito particular. Por ejemplo, en DBase III+, Clipper y Fox Pro podemos hacer cosas como esta:

USE CLIENTES
DISPLAY FOR CODIGO > 50000 TO PRINT

(imprimir el listado de todos los clientes cuyo campo codigo es mayor a 50.000)

El problema (y la ventaja) con los lenguajes de propósito general es que nos llevan a trabajar a un nivel de detalle que muchas veces es innecesario, al escribir una clase creamos un campo y debemos decidir si es int, float o double y luego crear la propiedad que muchas de las veces es un simple recibir y devolver el valor crudo del campo, innecesario!. Al pensar en una factura, todo el mundo piensa en un papel,  en un documento comercial, en un impuesto, en la agencia federal de ingresos públicos, mientras que los informáticos pensamos en una cabecera y un conjunto (colección, array, etc) de items con productos, un cliente, y un mapeo a la DB. Estamos acostumbrados a pensar en términos de las herramientas que utilizamos!

Como deberíamos codificar una factura? se me ocurre que de una manera algo mágica considerando «el estado actual del arte» podriamos declararla así:

XN Code
package Business 
{ 
    entity Factura persistent
    { 
        field readonly auto id ID;
        field options ('A' | 'B' | 'C') type; 
        field date operationDate;
        field numeric total;
        field numeric discount;
        field ref(Customer) customer;

        entity Item *
        {
             field numeric count;
             field numeric unitPrice;
             field numeric total;
             field ref(Product) product;

             init: count = 1;
             invariant: count > 0;
             invariant: unitPrice >= 0;
             invariant: total >= 0;
             let: total = count * unitPrice; 
        }

        init: operationDate = DateTime.Now;
        invariant: discount >= 0 and discount <= 100;
        invariant: Item.Length > 0;
        let: total = Item:{item| t+=item.total, return t; } * (100-discount)/100;
    } 
}

Este no es un pseudo código sino la visión de un lenguaje declarativos que estoy comenzando a definir. Como puede apreciarse, este es un lenguaje sencillo de un gran poder expresivo y que sirve principalmente para declarar la metadata para una posterior fase de compilación que generará código y sí, este es un lenguaje orientado a entidades o simplemente un DSL para el desarrollo de entidades de negocio. Este lenguaje mezcla el concepto de entidad con expresiones similares a OCL para la especificación de invariantes y otros constraints.

Alguna ideas sobre el lenguaje XN

  • Los generadores de código se nutren de medadatos para hacer su trabajo, por lo general, estos metadatos son los de las bases de datos, es decir, se genera código a partir de la estructura de una base de datos. Cuando se necesita reestructurar el sistema se debe modificar la estructura de la base de datos  y generar todo de nuevo perdiendo así parte de la lógica de negocios más elemental como los invariantes, los cálculos sencillos, las inicializaciones y los constraints. Todo esto no parece muy natural.
  • Las entidades se componen de otras entidades utilizando composición. Esto es, la entidad contenedora controla el ciclo de vida de la entidad contenida tanto en memoria como a nivel de base de datos. Cuando una entidad se elimina, todas las entidades contenidas por esta también se eliminan. Cuando una entidad se va a salvar en la base de datos, se inician transacciones para salvar también a las entidades contenidas, en otras palabras, una entidad es una unidad atómica.
    Solo se puede acceder a una entidad contenida a traves de su entidad contenedora.
  • La persistencia en la base de datos debe ser transparente al desarrollador. Parece una locura y puedo estar de acuerdo con todos aquellos que piensan distinto y que saben argumentar bien sus puntos de vista pero es hora de buscar una solución radical al problema y yo creo que esta es una opción: generar la base de datos junto con el código. Esta alternativa presentará problemas para extender las aplicaciones pero es muy factible generar automaticamente los scripts de migración ante un gran cambio en las entidades.
  • La estrategia de carga de las entidades debe ser inteligente. Ante la pregunta, Lazy load o no? cada cual tiene una respuesta como: «ver cada caso y estudiar en que puntos conviene y en cuales no», «yo nunca uso lazy load, cuando me hace falta algo lo cargo», «es muy bueno tener el modelo de objetos completo en memoria», «el muy lento, incrementa el tráfico en la red y casi siempre trae cosas que no vamos a necesitar», etc. Pienso que el sistema debería llevar estadísitcas de las consultas y actuar en concecuencia de manera inteligente y liberar al desarrollador para que piense en los requerimientos reales. 
  • No me agradan las siguientes cosas: ORMs, código legacy, One-off development, aplicaciones de negocios en lenguaje C, migraciones de aplicaciones, ni XML for all. Por otro lado, pocos desarrolladores son a su vez DBAs, expertos en .Net, Java, Python y PHP.
    Con un lenguaje declarativo como XN que genere código a partir de templates e integradas a entornos como VS2008 es posible mitigar algunas de estas limitaciones de gustos y/oo experiencias. 

Escribiré más sobre esto apenas tenga algo de código.

Lucas Ontivero

[Tips] Formatear variables nullables

Hace un par de dias un amigo me hizo una consulta al paso, «Sabes bien como se formatea un decimal nullable?». La verdad es que me molestó no tener la respuesta y me sorprendió que él tampoco lo supiera y que me consultara a mi en vez de googlear!. 

Claro, por ser nullable no tiene el método ToString(), así que vamos a compartir las dos soluciones encontradas que, aunque muchos pueden conocerlas, muchos no.

La clase genérica Nullable<T> posee dos método:

C# Code
public T GetValueOrDefault()
{
    return this.value;
}

y,

C# Code
public T GetValueOrDefault(T defaultValue)
{
    if (!this.HasValue)
    {
        return defaultValue;
    }
    return this.value;
}

También contamos con el operador ?? como sigue:

C# Code
(decimalNullable ?? 0).ToString("$ 0###.####");

 

El siguiente segmento de código muestra lasformas de hacer lo mismo:

C# Code
namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal? decimalNullable = null;
            string formated;

            formated = decimalNullable.GetValueOrDefault().ToString("$ 0###.####");
            formated = decimalNullable.GetValueOrDefault(0).ToString("$ 0###.####");
            formated = (decimalNullable ?? 0).ToString("$ 0###.####");

            // Esta linea lanza una exception InvalidOperationException
            formated = decimalNullable.Value.ToString("$ 0###.####");
        }
    }
}

Lucas Ontivero

[Arquitectura] Como construir un sistema de Plug-ins (Parte 1)

En esta serie voy a explicar todo lo referente a la creación de sistemas de plug-ins, pasando por su arquitectura, aspectos de isolation, seguridad, etc.

Introducción

No hace falta que explique aquí que es un plug-in, ¿verdad?. Así que comenzaré planteando un ejemplo y listando algunas características que todo sistema que soporte plugins debe tener.

Un ejemplo

Para esta entrada he creado un servicio de windows el cual vigila un directorio específico a la espera de cualquien cambio en él, como por ejemplo, la creación de un nuevo archivo, la eliminación de uno existente, renombrado de archivos, cambios en sus propiedades, tamaños, fechas de último acceso o escritura, etc.

Este servicio es sumamente útil para tareas de integración de aplicaciones, al mejor estilo Biztalk Server. La idea es que una vez detectado un cambio en un archivo del directorio que hemos especificado, este servicio recorra la lista de plugins instalados y les comunique el evento de modo que cada uno de ellos realizen la acción para la que fueron desarrollados. Estas acciones podrían ser:

  • Mediante EventLogger, mantener un tracking de los cambios en los archivos,
  • Enviar un email con el contenido del archivo (si es de texto claro),
  • Implementar una segunda papelera de reciclaje,
  • Mantener versiones de los archivos,
  • Organizar los archivos que bajamos de interner en subcarpetas según ciertos criterios,
  • Salvar el contenido de un nuevo archivo en una base de datos o desencadenar algún otro proceso,
  • Hacer de demonio de impresión,
  • etc.

El código de ejemplo se encuentra aquí: FileSystemWatcherService.zip

Características

Todo software que soporte plug-ins debe considerar os siguientes puntos importantes:

  • Isolation: cada plugin debe cargarse y correr en un AppDomain separado. El plugin no debe tener acceso al host o debe estar bien planeado, en el ejemplo FileSystemWatcherService.zip la comunicación es unidireccional HOST->PLUGIN.
  • Tolerancia o manejo de fallos: cuando un plugin no funciona o lanza excepciones no esperadas debe descargarse.
  • Seguridad: el plugin debe tener los mínimos privilegios necesarios para correr. Estos privilegios varian según el tipo de aplicación que estamos haciendo, por ejemplo, si en este ejemplo los plugins corrieran bajo un Internet Security Zone, ninguno de las tareas que arriba listo podrían realizarse pero lo cierto es que la mayoria de los plugins no deberían tener más que esos privilegios y en su defecto solo permitirles ejecutarse y nada más.
  • Detección de nuevos plugins o nuevas versiones de los instalados: no es buena idea tener que reiniciar una aplicación o un servicio para instalar un nuevo plugin. En muchos casos, como el de ejemplo nuestro ejemplo, la instalción de nuevos plugins se hace vigilando un directorio «Plugins» para detectar cambios e los archivos «.dll» que contiene. Cuando detecta algún cambio simplemente descarga los plugins instalados y los carga de nuevo. Esto evita además el tener que realizar cambios en los archivos de configuración o en el registro de windows. Esta es a mi manera de entender, la mejor opción para manejar la carga de plugins. Otros productos trabajan de igual manera como LiveWriter y Notepad++.

 

Arquitectura

Isolation

Como dijimos arriba, es importante que cada plugin corra en un AppDomain propio separado del AppDomain del Host. Para desacoplar dos partes de un sistema, ambas deben conocer y respetar ciertos contratos, es decir que las dos partes deben compartir un conjunto de interfaces. Este patrón se llama Service Interface cuyos componentes se pueden ver en la figura de abajo.

ServiceInteface 
Tomado de MSDN->MSDN Library->Servers and Enterprise Devepment->Enterprise Architecture, Patterns and Practices->Microsoft patterns and practices->Guides->Enterprise Solution Patterns Using Mricrosoft .NET->Service Patterns

Para decirlo de manera facil, tanto el Consumer como el Provider comparten al menos un assembly con las interfaces (contratos). En la figura de arriba también podemos ver un Service Gateway que implementa la cumunicacion desde el Customer hacia el Provider. A diferencia de como se implementa en la página a la que hago referencia, mediante WS, en el ejemplo que proveo lo hago mediante una clase Gateway que hereda de MarshalByRefObject en el assembly compartido FileSystemWatcherService.Interfaces.dll.

Básicamente existe una interface que debe implementar todo plugin, la interface IPlugin la cual posee un método Execute(IMessage message). El código:

C# Code
namespace FileSystemWatcherService.Interfaces
{
    public interface IPlugin
    {
        bool Execute(IWatchMessage message);
    }
}

Mientras que el Gateway se implementa mediante una clase «Gateway» que hereda de MarshalByRefObject para poder cruzar los límites del AppDomain. Esta clase contiene solo un método LoadPlugin que dado el nombre de un assembly, lo carga y mediante reflection busca un tipo que implemente la interface IPlugin y que esté decorado con el atributo PluginAttribute. Si encuentra un tipo que satisfaga estas condiciones, crea una instancia de este y retorna un objeto PluginInfo que contendrá una referencia al plugin e información del mismo que se detalla mediante el PluginAttribute.

C# Code
using System;
using System.Reflection;

namespace FileSystemWatcherService.Interfaces
{
    public sealed class Gateway : MarshalByRefObject
    {
        public PluginInfo LoadPlugin(string assemblyFilename)
        {
            Assembly dynamic = Assembly.LoadFrom(assemblyFilename);
            Type typeofIPlugin = typeof(IPlugin);
            foreach (Type type in dynamic.GetExportedTypes())
            {
                if (typeofIPlugin.IsAssignableFrom(type))
                {
                    PluginAttribute pluginAttr = null;
                    foreach (Attribute attr in type.GetCustomAttributes(false))
                    {
                        pluginAttr = attr as PluginAttribute;
                        if (pluginAttr != null) break;
                    }

                    if (pluginAttr == null) 
                        throw new PluginInformationMissing();
                    
                    ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
                    if (constructor != null)
                    {
                        IPlugin instance = (IPlugin)constructor.Invoke(null);
                        return new PluginInfo(instance, pluginAttr); 
                    }
                }
            }
            return null;
        }
    }
}

El Plugin

por ejemplo, aquí va un plugin sencillo que mantiene un registro de los archivos txt que han cambiado en el registro de eventos de windows.

C# Code
using System;
using System.Diagnostics;
using FileSystemWatcherService.Interfaces;

namespace Logger.Plugins
{
    [Serializable]
    [PluginAttribute("Logger", Mask="*.txt", Description="Log *.txt file changes ")]
    public class Logger : IPlugin
    {
        private readonly EventLog eventLogger;

        public Logger()
        {
            eventLogger = new EventLog();
            eventLogger.Log = "Logger plugin";
            eventLogger.Source = "LoggerPlugin Events";      
        }

        public bool Execute(IWatchMessage message)
        {
            try
            {
                eventLogger.WriteEntry(
                    string.Format("El archivo '{0}' fue tocado", message.FileName), EventLogEntryType.Information, 0, 0);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}

Esto es todo lo relevante en cuanto al Provider y al Service Interface. Ahora veamos un poco la arquitectura necesaria del lado del Consumer.

La aplicación cliente

Esta es la parte más interesante!. Y se compone de las siguientes clases que implementan funcionalidades necesarias. Aunque existen, como siempre, muchas formas de implementar los mismo, yo propongo la siguiente.

Las clases y sus funcionalidades:

Clases Responsabilidades
PluginLoader Un singleton encargado de realizar la primera carga de los assemblies (plugins) y de vigilar los eventos sobre la carpeta «Plugins» y cuando detecta un cambio descargar los plugins y los cargalos de nuevo. Esta clase mantiene una instancia de PluginsContainer.
PluginsContainer Es una colección de PluginControllers que se encarga de mantener la lista de plugins cargados, registrar y desregistrar/descargar plugins.  Este es el encargado de recorrer la lista de plugin controllers y pedirles que invoquen a los plugins.
PluginController Mantiene una referencia al plugin como así también información sobre el nombre del assembly que lo contiene y el AppDomain en donde se cargó. Esta clase también es la encargada de invocar al método Execute() del plugin con el mensaje adecuado y debería ser capaz (no lo es en este ejemplo) de controlar el tiempo de ejecución del mismo. Controla también que el Plugin no dispare una excepción y si lo hace simplemente descarga el AppDomain en el que se encuentra el Plugin.

El resto de las clases son de soporte. Como ConfigurationSectionHandler  para leer el archivo de configuración, DebugHelpers helpers para depurar principalmente para vigilar que la aplicación no cargue los assemblies en el AppDomain del Host, FileMaskHelper  para chequear si el archivo que cambió concuerda con la máscara que puede manejar un plugin, y Program es el entry point de la aplicación.

En el siguiente código hay que notar que luego de crear el AppDomain se obtiene un proxy trnsparente de la clase Gateway mediante:
CreateInstanceAndUnwrap(«FileSystemWatcherService.Interfaces», «FileSystemWatcherService.Interfaces.Gateway»);

Para más información (aunque no mucha) vea la documentación de este método. Lo único que hay que resaltar es la siguiente nota encontrada en la documentación:

Note:

If you make an early-bound call to a method M of an object of type T1 that was returned by CreateInstanceAndUnwrap, and that method makes an early-bound call to a method of an object of type T2 in an assembly C other than the current assembly or the assembly containing T1, assembly C is loaded into the current application domain. This loading occurs even if the early-bound call to T1.M() was made in the body of a DynamicMethod, or in other dynamically generated code. If the current domain is the default domain, assembly C cannot be unloaded until the process ends. If the current domain later attempts to load assembly C, the load might fail.

 

C# Code
        private static PluginController LoadAssembly(string assemblyName)
        {
            AppDomain pluginAppDomain = null;
            try
            {
                pluginAppDomain = AppDomain.CreateDomain(assemblyName);
                DebugHelpers.AssembliesInAppDomain("Before create AuxiliaryDomain");
                Gateway gateway = (Gateway)pluginAppDomain.CreateInstanceAndUnwrap("FileSystemWatcherService.Interfaces", "FileSystemWatcherService.Interfaces.Gateway");
                PluginInfo pluginInfo = gateway.LoadPlugin(assemblyName);
                DebugHelpers.AssembliesInAppDomain("After AuxiliaryDomain was created");
                return new PluginController(pluginInfo, pluginAppDomain, assemblyName);
            }
            catch(Exception)
            {
                DebugHelpers.AssembliesInAppDomain("After exception");
                if (pluginAppDomain != null) AppDomain.Unload(pluginAppDomain);
                return null;
            }
        }

Faltan resolver algunos problemas como el de determinar el conjunto de permisos con los cuales deben correr los plugins, controlar el tiempo de ejecución de los plugins para poder descargarlos si por ejemplo entran en un bucle infinito, resolver el problema de que el FileSystemWatcher de vez en cuando lanza varias veces el mismo evento lo que puede hacer que los plugins se descarguen y carguen muchas veces. También hay que refinar el catcheo de las excepciones pero este es solo un ejemplo 🙂

Continuará….

Lucas Ontivero

[Patterns] Chain Of Responsibilites Pattern

Introducción

Continuo aquí la serie «Patterns» que comencé hace algún tiempo. Esta serie se compone de las entradas anteriores:

Antes de comenzar les dejo dejo esta imagen:
TablaDeElementos
Extraido de http://www.vincehuston.org/dp/

Volviendo al tema, ahora nos toca el «Chain Of Responsibilities Pattern». Este es un patrón muy sencillo y muy usado. Chain Of Responsibilities permite desacoplar al objeto que realiza una petición de aquellos quienes pueden tratarla. Es decir, cuando un objeto necesita que se realice alguna acción como, por ejemplo, aprobar una rendición de viaticos, el objeto solicitante (el que requiere que se apruebe la solicitud) no necesita conocer la mecánica de las aprobaciones de viaticos sino que solo necesita invocar a la cadena de responsabilidades y solicitarle que maneje la aprobación solicitada. En la cadena pueden existir múltiples objetos responsables de aprobar o rechazar las rendiciones de viaticos según ciertos criterios e incluso es posible agregar nuevos responsables y/o quitar alguno(s) existente(s).

Veamos el diagrama de clases de este patrón:

CoR
Como puede verse, existe una clase abstracta «Handler» (puede implamantarse también mediante una interface «IHandler» ya que practicamente no contiene códido) la cual mantiene una referencia a otro Handler por medio de la propiedad «Next». Así, es claro que estamos ante una «lista enlazada» de Handlers. Luego, encontramos ‘n’ implementaciones concretas de Handler (o IHandler) como ConcreteHandler1 y ConcreteHandler2 las que sobreescriben el método «HandlerRequest()» y por lo tanto, en cada eslabón de la cadena encontraremos distintos handlers que manejarán cada uno una petición según se cumpla alguna condición específica.

En el ejemplo que mencionaba más arriba, y acotando el ejemplo a nuestra industria, podremos encontrar que la condición para la aprobación de una rendición de viaticos podría tener relación con el monto total rendido. Y podríamos imaginar el siguiente procedimiento:

  • Si el monto total rendido es menor a $1000, lo aprobará el Project Leader,
  • Si el monto total rendido es mayor o igual a $1000 y menor a $5000, lo aprobará el Program Manager y,
  • Si el monto total rendido es mayor o igual a $5000, lo deberá aprobar el Director del Centro.

En este caso, la cadena de responsabilidades para la aprobación de viaticos se compondrá de 3 responsables: una instancia de ProjectLeader, una de ProgramManager y una de Director.

El objeto solicitante deberá conocer al primer responsable (después veremos como mejorar esta situación) y solicitarle la aprobación como sigue:

public void ToApprove(Accountability acc)
{
    ProjectLeader.HandleRequest(acc);
}
En este caso, imaginemos que se rindieron $1700. Entonces, el primer handler, que es una instancia de ProjectLeader, evauará la condición «if (request.Sum < 1000)» para ver si es él quien debe manejar esta petición pero como el monto lo supera ($1700) le pasará la responsabilidad al segundo en la cadena, al Program Manager. El ProgramManager si es el responsable y por lo tanto se encargará de aprobar la solicitud y allí terminará la cadena. Es decir, el Director no intervendrá.
Abajo muestro un pequeño fragmento de código de estos tres Handlers:
 
public class ProjectLeader : Handler
{
    public override void HandleRequest(Accountability request)
    {
        if (request.Sum < 1000)
            System.Console.WriteLine("Aprobado por el Project Leader");
        else
            base.HandleRequest(request);
    }
}


public class ProgramManager : Handler
{
    public override void HandleRequest(Accountability request)
    {
        if (request.Sum >= 1000 && request.Sum < 5000)
            System.Console.WriteLine("Aprobado por el Program Manager");
        else
            base.HandleRequest(request);
    }
}


public class Director : Handler
{
    public override void HandleRequest(Accountability request)
    {
        if (request.Sum >= 5000)
            System.Console.WriteLine("Aprobado por el Director");
        else
            base.HandleRequest(request);
    }
}
En el ejemplo que acabo de dar es muy importante observar que los resposables deben estar ordenados en la cadena de menor a mayor porque si el Director fuese el primero, entonces todas las aprobaciones serian resueltas por él.  También hay que notar que aquí solo existe un responsable por cada tipo (según el monto) de rendiciones y que apenas uno la maneja, corta la cadena. Pero esto no tiene por que ser así, incluso una petición bien podría ir pasando por todos los elementos de la cadena de responsabilidades y que cada responsable se encargase de hacer algo con ella. Para los amantes del ObjectBuilder, su clase BuilderStrategyChain es una cadena de responsabilidades en la cual se alojan implementaciones concretas de IBuilderStaregy (ej: MethodExecutionStrategy y PropertySetterStrategy ) las que se encargan de realizar distintas acciones sobre los objetos como inyectarles valores a sus propiedades y ejecutarles ciertos métodos.
 
Otro aspecto relevante, aparte del orden de los handlers, es que el tratamiento de una solicitud no está garantizada. Una solicitud puede finalizar el recorrido de la cadena sin que ningún Handler la trate. Salvo en casos como en donde existe como último elemento de la cadena un Handler «Trata todo» el que provea de un tratamiento genérico por defecto para todas aquellas peticiones no manejadas por ninguno de los anteriores. Por ejemplo, podría existir un Handler del tipo LogguerHandler que escribiera una entrada en el event log diciendo que tal petición no fue manejada. 
 

Sistema de plug-in

La cadena de responsabilidades nos permite crear sistemas que soporten plugins de la siguiente manera: imaginemos que tenemos una aplicación que internamente mantiene información en un XmlDocument  que deseamos guardarlo en el disco bajo cierto nombre y extensión, como por ejemplo, archivo1.xml o informacion.doc. Es claro que según la extensión del archivo deberemos invocar a una clase que se encargue de las transformaciones necesaria, pero nosotros queremos dejar abierta la posibilidad de extender esto a otros tipos de archivos como hojas de calculo de MS Excel, PDF, JPG, TXT, etc. Queremos que cualquier desarrollador pueda desarrollar y extender esta característica de nuestro sistema mediante la registración de un plugin. La estrategia para resolver esto es mantener una CoR en la que cada Handler se encargue de manejar un tipo de archivo específico. La solicitud tendrá el XmlDocument, el nombre y la extensión del archivo y al ir recorriendo la cadena, cada handle preguntará si la extensión del archivo es la que él puede tratar, y de ser así, hará las transformaciones necesarias y lo guardará con el formato propio que él maneja. Como último eslabón puede registrarse un Handler que notifique al usuario de que ese tipo de archivo no puede ser manejado por el sistema.  

Mejora

El que el solicitante deba conocer al primer Handler es algo poco elegante, por eso la propuesta consiste en crear una clase ChainOfResponsibilities que se encargue de mantener una referencia al primer Handler como así también, de las tareas de dar el Kick off de las peticiones para que comience a recorrer la cadena como de agregar/quitar Handlers de/a la cadena.

En el ejemplo de abajo puede verse esta clase con las propiedades FirstHandler y los métodos Add y StartRequest. La propiedad LastHandler es privada y mantiene una referencia al último elemento de la cadena para hacer más rápido el agregado de nuevos Handlers ya que de esta manera nos evitamos el tener que recorrer la cadena para llegar al final.

Cuando se implementa como pipeline, puede que una petición haya sido tratada por uno más handlers hasta ue uno falla. En este caso muchas veces puede (y muchas no) implementarse un mecanizmo de Rollback implementando un método Reverse  en cada handler de manera que recorriendo la cadena en sentido contrario pueda volverse la petición a su estado original. Esto no es posible mediante una lista enlazada por lo que existe una alternativa.

Alternativas a la lista enlazada

Si bien este patrón se ideó como una lista enlazada, es posible implementarlo por medio de una lista de Handlers como List<IHandler> solo que en este caso, los handlers no conocerán a su sucesor sio que deberán solicitarle a la clase contenedora que pase la petición al próximo manejador.

Ejemplo

Para ejemplificar un poco más este patrón he creado un pequeño proyecto en el cual se implementa como una pipeline (el resultado de uno pasa al siguiente) para un sistema de Mobile Banking en el cual un cliente de un banco que cuenta con este servicio quiere enviarle dinero por medio de su celular a otra persona de quien conoce también su número de celular (movil).

En este caso, cuando llega una solicitud de envio de dinero, el sistema la pasa por una pipeline la que realiza las siguientes comprobaciones/acciones:

  • Verifica que exista un cliente registrado en el banco con ese número de celular. Si esto falla es porque alguien que no es cliente está haciendo peticiones al sistema.
  • Verifica que el cliente no haya sobrepasado su límite anual de transacciones. Anualmente cada cliente no puede hacer transferencias por más de un monto límite determinado para él.
  • Verifica que el cliente no haya transferido o intente transferir más dinero del que se le estableció como límite mensual y,
  • si todo lo anterior es correcto, realiza la transacción. Esta podría ser muy compleja.

El diagrama de clases para este ejemplo es el siguiente: 

CoRImpl

 

La pipeline 

pipeline

Notese que pueden agregarse y/o quitarse operaciones a esta pipeline.

Código de ejemplo ChainOfResponsibilitiesPatternExample.zip.
El código no es de un sistema real y es extremadamente sencillo. Lo hice solo para mostrar un poco de código y nada más que para eso.

Referencias y otros ejemplo

 

Continuará….

Lucas Ontivero

[MISC] La administración por objetivos

carrot_on_stick2 Como generarias desconfianza e incertidumbre en los empleados? como romperías la sinergia entre ellos? como incrementarías las rotación del personal? Como puedes agotarlos? Como generarias una psicosis generalizada en una empresa?


Escucho opiniones pero propongo una: administrar por objetivos.


La idea en si no es mala, pero muchas implementaciones si lo son. Se trata de un concepto que parece lógico, establecer una meta organizacional y trazar el camino mediante la declaración y persecución de objetivos a largo, mediano y corto plazo. Se espera que el logro sistemático de estos objetivos lleven a la empresa a cumplir su meta de sobrevivir. Claro, con esto no basta, es necesario que todos colabroren y se «alinien» para el cumplimiento de estos y por lo tanto surge la pregunta: ¿Como?. Facil, aquí en Argentina le llamamos «sistema de premios» y quizás muchos de Uds. en España lo conozcan como la porsión variable del salario, hace mucho me lo explicaron con una metáfora estúpida «Poner la zanahoria delante del caballo».


Tengo una teoria, cuando un empleado ingresa a una empresa desea siempre hacer lo mejor, sobresalir, ayudar con sus conocimientos y experiencias previas, aprender rápido y trabajar lo mejor posible. Lo veo a diario, siempre es así, apenas les dices «mirá esto» o «ayudame un poquito» enseguida pegan un salto de su asiento y vienen atentos a todo. Esto es motivación! Desgraciadamente al poco tiempo alguien les explica que no pierdan su tiempo con esta o aquella custión porque …. existe un sistema que los mide y que su salario depende de ello. Listo, nunca más los volvemos a ver como entonces. Pero eso se soluciona con un curso motivacional! o no?


Sucede que cuando se introduce la idea de que es posible manipular el salario de los empleados, estos reaccionan acorde a las nuevas reglas que gobiernan el sistema. He leido mucho sobre esto y he conversado miles de veces sobre lo mismo y no puedo resumir las conclusiones así que doy solo las mias:



  • Salvese quien pueda! Esto es lo primero. Ayudame? que es eso? si no llego a mis objetivos! esto nos lleva a la segunda conclusión,

  • Sinergia cero. «Nuestro equipo tiene que llegar a:….. No podemos perder el tiempo con ese problema» (no importa su gravedad). Empleado: «Pero vamos a perder el cliente!» – Supervisor: «No es nuestro, es de ellos (del equipo de al lado) así que serán ellos los que pierdan su bono a fin de mes!» quizás esto nos conduzca a la siguiente,

  • Insertidumbre y gestión por miedo. Familiar: «Cuanto cobras?» Empleado: «No se! si logro convencer a mi supervisor quizás saque $xxxx».  Y esto también provoca el

  • Malestar en el trabajo y el pensamiento a corto plazo.

Trabajé en dos empresas en donde esto se llevaba muy lejos y en una de ellas se notaba la psicosis que producía en muestros compañeros catalanes.


Existe en esto un error conceptual de lo que significa trabajar para que a la empresa le vaya mejor, la frase elegida es «alinear los objetivos individuales a los organizacionales» cuando en verdad debería ser «trabajar en pos/colabrorar TODOS JUNTOS para que la organización logre sus objetivos». No es lo mismo y aunque la diferencia parezca tonta el error está en tratar de idear un método sistemático para decirles a cada uno qué es lo que debe hacer y la trampa está en creer que porque «ellos mismos» se han fijado sus objetivos, estos han tenido la total libertad de escoger lo que consideran mejor para la empresa. Falso.


Mi experiencia en este tema es larga. En mi primer trabajo como desarrollador era muy feliz, hasta hoy nunca me volví a sentir mejor en un trabajo hasta el dia, por la insistencia y un poco de descontento por lo bajo de nuestros salario, nuestro supervisor nos vino con «una fabulosa idea» que después de una insignificante burocracia de pensar, planear, revisar, aprobar, seguir, cumplir y revisar el cumplimiento de los objetivos nos darían un premio! que compensaria más o menos nuestros salarios. Umm, peor es nada! en otras areas ya lo hacian y algunos pocos se habian vuelto un poco idiotas con el «para eso no tengo tiempo» hasta el punto que a todo respondian lo mismo; «tu señora estaba enferma no? como está?» – «Bien. Después te cuento. En este momento no tengo tiempo». Cuando se acercaba el fin del mes ya empezaba a planear como me iba a defender del descuento, las discuciones eran fuertes y me arruinaban toda una semana y sobre todo ese clima que me gustaba. Listo! al que no le gusta que se vaya y me fuí.


Me fuí al lugar que me juraron que eso allí no pasaba. Después de unos pocos meses llegó el scorecard! Un sistema de calificación por demás complejo que propiciaba las peores prácticas. Los supervisores estaban entre la espada y la pared, ellos debian hacer que eso cerrase. No solo era complejo sino que todas las conversaciones por razones de trabajo con nuestros compañeros de cataluña eran en lenguaje scorecard. Es que el sueldo depende de eso!. A ellos les causaba una psicosis real y un sálvese quien pueda total. Creo que nunca volveré a ver otro caso similar.


Tuve otro trabajo después, muy bueno y muy interesante. Trabajaba muchas veces un par de horas de más. A decir verdad, 3 o 4 dias a la semana trabajaba entre 1 y 3 horas de más. Pero el ambiente era genial, muchos tipos con mucha imaginación, buena onda, otros con mucha experiencia y muy colaborativos todos. De repente nos llegó el puntaje por mail (no lo recuerdo bien) «chicos, como somos los mejores del mundo (en todos lados les deben decir lo mismo) necesitamos mejorar constantemente. Nuestra puntuación actual es de 3 pts. y necesitamos llegar a 25 pts.». Ojo, aquí también se trataba de $ aunque de una manera un tanto indirecta.


Esta entrada la creé porque en mi nuevo lugar trabajo me han pedido que cargue mis objetivos (alineados claro está) para el siguiente año. Y la buena noticia es que aquí también hay una revisión, esta vez anual, para ver cuanto voy a cobrar el año que viene :). Pero aqu’i esos objetivos parecen no importarles a nadie. Pero, y entonces para que los ponen?


Existe otra teoria, la de Maslow y sus famosos hombre X (funcionan a látigo en mano) y los hombre Y (los que yo sostengo). Estos hombres buscan cosas distintas porque son distintos, pero como administrar es homogeneizar para poder multiplicar, entonces como se homogeneiza esto? (X+Y)/2 = AVG(MAN)? NO! es ridículo! Se debe propiciar la colaboración, la investigación, la sinergia y ayudar a cada quien para que ayude con sus pequeños esfuerzos diarios a mejorar todo lo que sea posible, alejarlos de los sistemas que los vuelven egoistas, cortoplacistas y miedoso, tratar de retenerlos y no de cansarlos o perderlos, no hay que motivarlos sino tratar de no desmotivarlos.


Veo una solución, «El liderazgo». No basta con cambiarle el nombre de capataz a lider, ni darle al capataz un curso de liderazgo. Sería como «ya no se llevarán más con el capataz! ahora odiarán a su lider!». El liderazgo real que hace falta es aquel centrado en una persona que pueda de por si (respaldado por la organización de cualquir manera sólida) movilizar a la gente para trabajar por ese TODOS que es la organización. Alguien sabe como se hace?


Lucas Ontvero

[Software Factories] Introducción (Parte 4)

Esta entrada es parte de la serie «Introducción a los conceptos de Software Factory» que hasta el momento se compone de las entradas anteriores:

En esta entrada voy a trara sobre el punto central al que aplica el concepto de SF, la linea de productos. Antes de esto debo aclarar que existe una clasificación de los SF la cual distingue entre SF horizontales, aquellos relacionados a una tecnología, plataforma, arquitectura, que pueden ser comunes tanto a un CRM, ERP, DMS como a cualquier otro (como son por ejemplo los casos de SCSF, WSSF, MCSF, etc.) y los verticales que son aquellos que se utilizan para la construcción de una familia de productos estrechamente relacionadas a un tipo de negocio como CRMs, ERPs, etc. Hoy contamos, gracias a Microsoft de SF horizontales pero a los SF verticales deberemos construirlos nosotros. A menos que alguien conozca una especie de Customer Relationships/Service Software factory 🙂

Volviendo al tema, una linea de productos se refiere a un tipo de aplicación que puede agruparse o identificarse como perteneciente a una familia de productos, como por ejemplo sistemas de CRM, software de seguros, software para entidades bancarias, de control aereo y cualquier otro. Es decir, pueden agruparse de distintas maneras, por segmento de negocios, tipo de soluciones, plataforma, etc. Lo importante es poder identificar aquellas características comunes, lo que mediante la reutilización de ciertos assets de alto nivel de granularidad, nos proporcionará la tan buscada economía de alcances.

Tanto los SF horizontales como verticales cumplen con el cometido de mejorar la calidad, productividad y tiempos de entrega, pero son los verticales los que pueden aportar «el gran salto» que una empresa necesita en estos sentidos.

Los pasos

Alcances: El primer aspecto importantes es analizar los alcances del SF a construir, es decir, que tipos de aplicaciones podremos crear con él. Este es sin dudas un tema esencial y dificil por cuanto mientras más tipos de aplicaciones querramos abarcar, mayor esfurzo requerirá en sus otros dos ejes (variabilidad y extensibilidad).

Supongamos que tenemos bien definido el alcance de nuestro SF. Algo así como:
«DMSSF (Document Manager System Software Factory) es un SF para la construcción de aplicaciones de uso de documentos como, expedientes, procedimientos, reclamos, comunicados, Bases de conocimientos, publicaciones en linea, reporte de errores y otros similares».
Bueno, debería ser mejor pero este es solo un blog :). Ahora, todos estos sistemas tienen características similares o al menos una muy evidente, son todo sistemas documentales.

En el libro «Practical Software Factories in .NET From Theory to Practice—A Primer, Reference, and Case Study«, que es el que estoy leyendo ahora, dice que el primer paso es redactar y comunicar la visión del SF y da el siguiente ejemplo para la empresa ficticia ISpySoft:
«Develop a Software Factory that enables efficient development and maintenance of
high-quality, modular, extensible applications for private investigator offices and field
agents, and that allows ISpySoft to also offer new services to its customers.
»

<opinion>La verdad es que a mi entender, estas declaraciones no sirven para nada y ponen a mucha gente a perder tiempo valioso en discuciones improductivas. Además suenan todas iguales.</opinion>

Variabilidad y extensibilidad: Una vez analizadas las similitudes (y extraerlas y documentarlas) debemos concentrarnos en las diferencia. Las diferencias podrian ser:

  • para expedientes y reclamos tenemos clientes mientras que para el resto no.
  • para expedientes, procedimientos, reclamos y reporte de errores tenemos un workflow mientras que para el resto no.
  • Algunos documentos necesitan un control de versiones y otros no.
  • Algunos pueden necesitar si o si de digitalización de documentos en papel y otros no.
  • Algunos necesitan autentificación, envios de emails, trabajo desconectado, integración con outlook, logueo en db, etc.

Aquí también deberian ser mejores.

Estas diferencias hacen al concepto de variabilidad y extensibilidad. Muchas veces se piensa que esto es una cuestión de configuración o parametrización de un producto complejo al que mediante opciones de parametrización se le pueda dar la funcionalidad requerida, algo así como configurar un sistema de control de transporte para que se comporte como un control de tráfico aereo o uno de tracking de ganado. Esta es la clásica visión de producto configurable que no se corresponde con la idea de software factory. Esto es parte del paradigma anterior 🙂

En la entrada [Software Factories] Introducción (Parte 2) explico estos dos conceptos así que no los repetiré aquí. Pero cual es la diferencia entre variabilidad y extensibilidad? (<include> o <extend>) La variabilidad se refiere a aquellas características o alcances que tenemos plenamente identificados y que por lo tanto están ya en el total conocimiento de quienes conocen el dominio. Estas son candidatas a ser fácilmente configurables por nuestras herramientas por ejemplo: usuarios integrados con LDAP u otro sistema nuestro, tenemos integración de clientes con otros sistemas o no, etc.

La extensibilidad, en cambio, hace a todos los aspectos que pueden pertenecer (tal vez no) a la penumbra de los requerimientos del cliente y que por lo tanto deben predecirse para dejar esas puertas abiertas.

Pasar de la visión de producto a la visión de linea de productos

Este es un tema muy dificil, sobre todo porque no encontré nada al respecto así que acá va un intento:

  • Convencer al concejo de ansianos (o al gran jefe) de las bondades del cambio. El concejo no entiende de c# ni Biztalk y dado que esta iniciativa se gestará en los niveles medios o administrativos, es primordial contar con el apoyo de la alta gerencia.
  • Converzar con todos los involucrados sobre la nueva manera de pensar y hacer software. Estos cambios siempre despiertan curiosidad y motivación en la gente por lo que abre las puestas para que se los involucre en las nuevas tareas. Además todo el mundo tendrá preguntas y sugerencias.
  • Reunir al equipo que desarrollará el SF. Este equipo ya está preseleccionado de antemano, todos saben quienes son, los mejores desarrolladores, el product manager, la gente de QA, los implementadores con mayor conocimiento del dominio del negocio y las necesidades habituales de los clientes, etc.
  • Armar el Software Factory Schema (introducción parte dos). Y factorizar el o los productos existentes y matchear los factores (producto de la factorización) con los viewpoints del SFS.
  • Comenzar a tailorizar EL proceso. Ya no tendremos UN proceso de desarrollo DE SOFTWARE sino un proceso de desarrollo de aplicaciones de administración de documentos web enabled.
  • Manos a la obra!
  • Hacer un piloto y cargar el feedback para mejorar el SF.

Indudablemente esto es mucho mas complejo y por cada item existen muchos aspectos que escapan al sentido original de esta entrada como «Análisis y diseño de SF».

Assets existentes

Para finalizar, tanto el resultado de la factorización de los productos (si los hubiera) como los assets existentes deben integrarse y acoplarse mediante, el proceso de desarrollo y el IDE de desarrollo.

Continuará…

Lucas Ontivero

[MISC] El mercado laboral está fuera de control

Hace más de 40 semanas que vengo analizando la tendencia del mercado laboral de mi ciudad (Córdoba – Argentina) para tratar de entender que está pasando, que perfiles se buscan, cuales faltan, cuanto se paga, cuantas empresas nuevas se forman o radican, cuantos ingenieros egresan, etc.

Luego de algún tiempo de intentar clasificar todos estos factores juntos lo abandoné porque me superaba pero seguí conservando y siguiendo algunos indicadores propios (entre ellos mi salario – el mas desalentador jajaja).

Aquí va un análisis muy simple de una sola fuente: http://www.computrabajo.com.ar
Este es el resultado de 34 semanas de ofertas de empleo sin categorizar, algo así como ofertas en bruto.

Para la estimación usé la función LINEALST de Excel y los Límites superior e inferior los calculo a partir del método de las 3 sigmas.

Como se puede observar, la demanda es creciente por lo que no muestra señales de formar parte de un sistema estable, a menos claro que se trate de factores estacinales que no se manifiesten en tan poco tiempo.

Semana Ofertas Media L.Sup Media L.Inf Est.Lineal
1 64 66,88 2,88 112,70 21,06 39,26
2 54 66,88 12,88 112,70 21,06 40,52
3 55 66,88 11,88 112,70 21,06 41,77
4 46 66,88 20,88 112,70 21,06 43,03
5 53 66,88 13,88 112,70 21,06 44,29
6 42 66,88 24,88 112,70 21,06 45,55
7 48 66,88 18,88 112,70 21,06 46,81
8 49 66,88 17,88 112,70 21,06 48,06
9 42 66,88 24,88 112,70 21,06 49,32
10 57 66,88 9,88 112,70 21,06 50,58
11 53 66,88 13,88 112,70 21,06 51,84
12 82 66,88 15,12 112,70 21,06 53,10
13 73 66,88 6,12 112,70 21,06 54,35
14 56 66,88 10,88 112,70 21,06 55,61
15 58 66,88 8,88 112,70 21,06 56,87
16 38 66,88 28,88 112,70 21,06 58,13
17 60 66,88 6,88 112,70 21,06 59,39
18 94 66,88 27,12 112,70 21,06 60,65
19 58 66,88 8,88 112,70 21,06 61,90
20 68 66,88 1,12 112,70 21,06 63,16
21 89 66,88 22,12 112,70 21,06 64,42
22 62 66,88 4,88 112,70 21,06 65,68
23 80 66,88 13,12 112,70 21,06 66,94
24 94 66,88 27,12 112,70 21,06 68,19
25 69 66,88 2,12 112,70 21,06 69,45
26 58 66,88 8,88 112,70 21,06 70,71
27 80 66,88 13,12 112,70 21,06 71,97
28 61 66,88 5,88 112,70 21,06 73,23
29 82 66,88 15,12 112,70 21,06 74,48
30 64 66,88 2,88 112,70 21,06 75,74
31 92 66,88 25,12 112,70 21,06 77,00
32 91 66,88 24,12 112,70 21,06 78,26
33 114 66,88 47,12 112,70 21,06 79,52
34 88 66,88 21,12 112,70 21,06 80,77
35 82,03
36 83,29
37 84,55

Aquí va la gráfica:

image

Nota: las tres semanas sin datos son solo para «estirar» la linea de tendencia. Las causas de los últimos puntos de crecida se deben a EDS, Gameloft, Motorola y el gran pico final se debe a que a estos tres se le ha sumado Santex y otros aleatorios.

Lucas Ontivero

[Software Factories] Introducción (Parte 3)

Voy a continuar aquí la serie «Introducción a los conceptos de Software Factory» que comencé en mi blog anterior con las entradas:

Me permito taer aquí un fragmento de un post anterior para definir el concepto:

<cita>

Software Factory

Si se le hubiese llamado de otra manera nos habriamos visto forzados a realizar un esfuerzo mental para averiguar y tratar de entender de que se trata este concepto pero desgraciadamente esta palabrita «Factory» nos habilita a pensar cualquier cosa. Las analogías que encontramos por todos lados con fabricas de zapatos, electrodomésticos y autmóviles terminan de confirmar nuestras fantasias mal fundadas. No son pocos los que creen que se trata de hacer software como si de automoviles se tratara, simplemente ensamblando algunas partes hechas en una linea de montaje y automatizando, robots mediantes, los detalles como el color de la pintura y otros. Bueno, no es así. (sic)

Distingamos entre Software Factory como paradigma y como instancia. Como paradigma, es una alternativa a los métodos actuales de construcción que intenta resolver los 5 problemas planteados en el post anterior ([Software Factories] Introducción (Parte 1)) cuando las aplicaciones a construir comparten características comunes. Como instancia (SCSF por ejemplo), un Software Factory es un conjunto de herramientas, procesos tailorizados, frameworks, patrones y modelos (por lo general embebidos en los frameworks y/o herramientas integradas del IDE) y otros contenidos que usan para trabajar sobre una Linea de Productos.

</cita>

En esta entrada intentaré echar un poco de luz sobre software factory como paradigma sin caer en la definición de paradigma. Como paradigma, software factory es una manera distinta de pensar, analizar, diseñar, organizar, construir y gestionar el desarrollo de software con el propósito de sortear las 5 razones del fracaso de los proyectos de software en la actualidad:

  • Razón 1 – One-off development
  • Razón 2 – Monolithic systems and increasing systems complexity
  • Razón 3 – Working at low levels of abstraction
  • Razón 4 – Process immaturity
  • Razón 5 – Rapidly growing demand for software systems

Desde este punto de vista, SF produce o mejor dicho propone, un cambio radical en la manera hacer las cosas. Que cosas? TODAS!

<opinion>

Puesto que todas las razones, salvo la razón 4 «Process immaturity», se producen en mayor o menor medida por un escazo nivel de reutilización de tangibles y que además se encuentran demasiadas analogías con industrias con foco en la «producción intensiva» y no en el «desarrollo intensivo», sumado a conceptos un poco futuristas como el de «Software Supply Chains» es que se cae en la creencia de que SF es solo reutilización de código en cualquiera de sus formas: fuentes y/o binarios como librerias, componentes, frameworks, application blocks, paquetes, assemblies, funciones traidas con copy/paste, ws o cualquier otra.

</opinion>

En cuanto al aspecto más cercano al código, este paradigma intenta cumplir con lo que la OOP nunca cumplió del todo: la reutilización!. Todavia me acuerdo de «las clases son totalmente reutilizables!!!» si claro, solo que son dependientes del contexto por lo que en realidad es el contexto lo realmente reutilizable por lo que se las agrupó en librerias, componentes, frameworks o llamense como quieran. Además de que solo aquellas que son de un uso muy genérico y muy granulares las que se pueden reutilizar en la actualidad, todavía sigo sin encontrar una clase factura, cliente, orden de pedido, reclamo y tantas otras que necesito para mis desarrollos que pueda reutilizar.

El encapsulamiento, la fina granularidad y muchos tipos de impedancias encontradas entre OOP y otros componentes también son atacados por este paradigma.

En cuanto al análisis, diseño, comunicación con los clientes y generación de código, SF toma lo mejor de MDA mientras que intenta solucionar mediante los reutilizables, DSLs y extensiones de los IDEs las falencias de CASE, acercando el análisis y el diseño a un contexto específico (determinado en gran medida por la linea de productos). No más diagramas genérico a validar por un cliente que no los termina de entender (a veces yo tampoco), ni más código genérico de mala calidad producido por herramientas CASE de terceros, basta de tanta libertad a los desarrolladores, basta de pensar y de hacer (de mil maneras distintas) todo de nuevo, desde los gráficos hasta el código.

En cuanto a la organización de los desarrolladores, o quizás de los conocimientos y habilidades, SF reconoce que no son todos iguales y distingue aquellos con mayor conocimiento técnico y del dominio del problema, quienes construyen los SF, de aquellos quienes lo utilizan y enriquecen con su feedback. 

Por último en este artículo, vuelvo sobre las metodologías. Aquí también SF plantea una alternativa y me cito de nuevo:

<cita>

(sic) el tema de las metodologias cuyo problema resumia como «o (son) muy formales o (son) muy ágiles». Greenfield  y Short  plantean (lo que a muchos nos parece obvio) que existen dos tendencias extremas con sus pros y contras. A diferencia de lo que uno podría esperar, Greenfield  y Short no creen que una metodología más formal sea más MADURA, por el contrario, entienden que son inmaduras por extremistas.

(sic)(sic)(sic)…(otros cuantos sic)…(sic)(sic)(sic)

La clave es preservar la agilidad mientras se mantiene la posibilidad de escalar la complejidad introducida por el tamaño y la distribución geográfica de los proyectos. Lo verdaderamente importantes es como esta posibilidad va tomando forma real mediante la implementación del paradigma de Software Factories.

Los autores siguen diciendo que el problema de las metodologias formales es que son demasiado abstractas en el sentido que para poder utilizarse deben ser tailorizadas a cada proyecto o necesidad particular. La idea detrás de esta crítica, que no lo es tal, es tailorizar los procesos a una familia de productos concreta.

Es decir, enfocar los procesos hacia las tareas puntuales de todo el ciclo de vida de una familia de productos (sic). Así, por ejemplo, debería por cada actividad facilitarse los recursos necesarios como wikis, links a documentación importante (sic), información de contactos, guias específicas (instructivos) sobre como realizar tarea, checklists aplicables a la tarea, estilos de codificación, detalles de cual/es es/son el/los próximo/s paso/s en el desarrollo, herramientas, políticas, (sic). Todo esto debería estar integrado al IDE y en lo posible automatizado.

</cita>

continuará…..

Lucas Ontivero

[MISC] El pensamiento Lineal

Nunca escribí sobre algo así y seguramente será la última vez que lo haga. Perdón a todos.

Este es un meta anti-patrón(?), el cual consiste en un intento por simplificar la realidad al extremo tratando de reducirla a conceptos matemáticos básicos. Este concepto tomado de la psicología, se presenta en todos los contextos de la vida pero aquí vamos a enfocarlo a las actividades de desarrollo de software. El pensamiento lineal es resultado del afán de tratar cuestiones o problemas complejos analizándolos sobre las bases de modelos sencillos en demasía y por lo tanto desprovistos de aspectos de importancia que en suma resultan determinantes.

Ante un problema complejo, el pensamiento lineal se enfoca en un aspecto determinado del problema, ya que los «detalles» han sido eliminados, probocando un análisis NO sistémico, aislando a la persona de un estudio y reflexión más completa que incluya el contexto en el que toma sus decisiones, haciendo de ellas decisiones aparentemente correctas y lógicas pero que al cabo terminan demostrando su inefectividad.

La dimensión de este problema toma su aspecto más negativo cuando se observa en sistemas sociales en donde el pensamiento lineal intenta homogeneizar a las personas para gestionarlas mediante técnicas de stock (un ejemplo, ver «El ‘pool’ de programadores» de Rodrigo Corral), valores de mercado, características, métricas, etc. 

Citando a Jaime Yanes Guzmán en su artículo «La Trampa del pensamiento lineal«:

«La trampa principal del pensamiento local radica en su efectividad operacional en la construcción del hacer, en su dinamismo en el fabricar, en su capacidad del diseño ingenieril. El pensamiento lineal es atractivo porque sólo pone atención a sus tremendas capacidades operacionales concretas, resaltando con ello la racionalidad causal local porque la ve como el único origen de la eficacia y efectividad del quehacer»

Aquí está, este es el contexto de nuestro meta anti-patrón(?). Este tipo de pensamiento, como todo antipatrón, promete resultados de manera sencilla con justificaciones matemáticas también simples lo que le confiere cierta lógica. Los pretextos son siempre los mismo, gestionar; y desde mi punto de vista, gestión facilista.

Citando ahora a Alfonso Cornejo Álvarez en su libro «Complejidad y Caos – Guía Para La Administración Del Siglo XXI«

«El Pensamiento lineal es otra de las variables que afectan a la toma de decisiones cotidiana en la organización. Cada evento o situación problemática es analizado de manera simplista y lineal, estableciendo para cada reacción una acción directa y bien identificable. Este modelo mental se permea a toda la organización y se traduce en análisis de situaciones que afectan a balances financieros, programación de producción, adquisición tecnológica, innovación de productos, evaluación de tendencias de mercado, etc. Desde el más simple hasta el mas complicado de los eventos que le toca vivir a la organización.
El modelo de causa-efecto de relación lineal cobra vida en cada inferencia provocada del análisis de lo cotidiano. Todo tiene su porqué y es plenamente identificable. Aunque este modelo de pensamiento no es atribuible al desarrollo de la burocracia, si ha favorecido el bajo desempeño organizacional y ha provocado efectos secundarios no previstos que maravillosamente se han disfrazado nuevamente de relaciones causales ante la mirada segura de los analistas.»

Ahora, trantando de despegarnos un poco del duro trabajo que es «el arte de criticar» y, intentando alejarnos de los análisis mezquinos producto de «nuestro» pensamiento lineal, analicemos la situación concreta de las decisiones administrativas de nuestra industria. El problema: debemos gestionar y obtener resultados beneficiosos para todos. La posible solución es: usar los conceptos de la administración clásica, homogeneizar (abstracción) todo llevandolo a números y gestionarlo entonces por medio de cifras. La solución definitiva: (?)

Edwards Deming en su libro «Calidad, Productividad y Competitividad – La salida de la crisis», que puede verse como un compendio de ejemplos y soluciones a los problemas del pensamiento lineal en la industria en general, lista enfermedades mortales de la industria entre las que señala:

  • Búsqueda de beneficios a corto plazo,
  • Evaluación del comportamiento, calificación por méritos, o revisión anual. (a alguien le suena esto? porque fue escrito hace más de 25 años)  y,
  • Dirigir basándose en las cifras.

Luego habla de los obstáculos (cada punto son 100 páginas) y propone sus famosos 14 puntos para la transformación de las empresas los cuales en conjunto forman un sistema increible pero… hoy se ven implementaciones customizadas de sus 14 puntos con la misma lógica infantil del 2+2 y poco ha cambiado o se a transformado en realidad (salvo los ISO 9001 y CMMI ooohhhh somos Deming compliance!!).

Entonces, no es posible escaparle al pensamiento lineal? a lo mejor una persona pueda pero un sistema social no, una organización no puede simplemente porque es resultado de factores educativos/cognitivos que han logrado resultados. Entonces el pensamiento lineal resulta, a falta de opciones, una herramienta impresindible para la administración. Sencillamente, así se administra(?).

Nota: el (?) significa duda. No afirmo que se trate de un antipatrón, solo lo planteo como posible.

Lucas Ontivero

[MISC] Houston, tenemos un Geek!!!

Bueno, esta es una entrada para paresentarme y saludarlos a todos. Mi nombre es Lucas como dice arriba y como la mayoria de ustedes comencé con esta profesión/hobbie/pasión desde muy chico, la semana pasada mi hermanito me preguntó: que hacias con usa porqueria con cassette que se conectaba al tele? y la verdad es que hacía lo mismo que ahora, me divierto.

Quiero también decirles que me siento muy feliz de formar parte de esta comunidad ya que desde hace bastante que sigo a varios miembros como a Rodrigo Corral por sus experiencias, El Bruno (uno de los que más leo aunque un poco rápido) y al que le he robado el formato de los títulos, Rafael Ontivero (no somos parientes) me encanta ese blog, Carlos Zanini, Jorge Serrano, Ezequiel Jadib, Mariano Converti y otros.

Mi blog anterior era http://lucasontivero.spaces.live.com para quienes quieran ver más o menos que es lo que escribo. En este momento estoy de luna de miel, y me pude escapar 10 minutos de mi señora para escribir esta entrada 🙂 , así que voy a estar un ratito más sin escribir.

Ahora sí, un saludo a todos.

Lucas Ontivero