Cuestión de rendimiento…

Recientemente he leído varios artículos sobre las ventajas de Windows 7, frente a los actuales XP y Windows Vista. Los problemas de rendimiento de Windows Vista en algunos aspectos como la copia de archivos y otros han hecho que los usuarios ni siquiera se planteen el cambio de sistema operativo, personalmente opino que Vista es bastante superior que XP, aun con estos problemas que después se solucionaron con el sp1. Pero esta situación ha llevado a que Microsoft haya tenido que dar marcha atrás en su política, y se ponga manos a la obra para mejorar su Sistema Operativo optimizándolo para mejorar su rendimiento y cambiar la imagen de su producto más importante.

En el caso de Office 2007, el cambio radical con la adopción del Ribbon ha provocado que muchos usuarios rehúsen a usar este producto debido a su coste, la curva de aprendizaje que requiere el cambio de aspecto, además de que las necesidades de la mayoría de los usuarios se encuentran cubiertas en las anteriores versiones, han provocado que el número de implantaciones de Office 2007 se encuentren lejos de sus versiones anteriores.

Creo que la velocidad a la que nos viene acostumbrando Microsoft muchas veces solo justificada por la idea de vender nuevos productos al mercado, está comenzando a cambiar la forma de pensar de muchos usuarios, se ha creado un clima, en el que muchos piensan «porque cambiar algo que ahora mismo funciona y que cumple con mis necesidades» y que además cuesta dinero.

En mi caso, como desarrollador llevo «trabajando sufriendo» con Visual Studio desde hace varios años, «digo sufriendo porque gran parte mi tiempo estoy esperando…», en mi opinión el diseño, su arquitectura y su integración con diferentes sistemas es excelente, pero arrastra desde las primeras versiones una serie de problemas que todos los días me hacen pensar si estoy utilizando la herramienta más adecuada, estoy harto de los tiempos de compilación, harto de los diseñadores de formularios lentos, por no hablar del diseño en Asp.net y Wpf  y de otros muchos aspectos relacionados con las pruebas unitarias y herramientas de calidad como FxCop que hacen que día a día pierda gran cantidad de tiempo, en esperar a que un proceso finalice. Si comparo mi actual proyecto con el anterior desarrollado en otro entorno también de Microsoft similar en cuanto a complejidad y funcionalidad, exceptuando por la calidad de código, entonces me dan ganas de llorar, un formulario normal con los mismos campos tarda en abrir decimas de segundo, la compilación con el doble de código y formularios se realiza en menos de 15 segundos, en cambio en Visual Studio puedo pasar hasta 10 minutos para que finalice el proceso, muchos pensaran quizás no deberías compilar tanto o ¿ Por qué no reduces el proyecto para que vaya más deprisa ?, optimizas tus clases, controles, etc. Creerme he hecho de todo desde optimizar, gestionar las builds, hasta utilizar discos SSD, pero hay veces que es necesario compilar a menudo y puedo afirmar que las diferencias de tiempo son abismales, sobre todo en lo que al diseño se refiere. El entorno de producción es increíblemente lento, la carga de los controles en el toolbar es desastrosa, en fin, hoy estaba estimando el tiempo que perdemos en estas tareas y la verdad, mejor no contarlo.

Espero que Microsoft tome nota de estas quejas que afectan todos los días a muchos programadores y que se comprometa tal y como predica, a realizar productos de calidad, en los que el rendimiento sobre todo en herramientas de desarrollo sea un aspecto fundamental, antes de sacar productos nuevos al mercado, estoy harto de los continuos cambios y nuevas tecnologías en las que solo funciona el 70 % de las cosas y que obligan a los desarrolladores a hacer verdaderas virguerías para poder desarrollar sus aplicaciones, estoy harto de escuchar frases como «eso se implementara en la siguiente versión», y ver pasar errores que nunca se corrigen y que consumen mucho de nuestro tiempo productivo.

No quiero generalizar, considero que Microsoft tiene una amplia gama de productos excelentes, desde Sql Server pasando por Office e incluyendo como no a Visual Studio con el que mantengo desde hace tiempo una relación amor-odio, pero hay aspectos con los que lucho todos los días, y que versión tras versión siguen arrastrando los mismos errores, me pregunto cómo es posible que hace 10 años mi entorno de desarrollo fuese infinitamente más rápido para realizar la misma funcionalidad y hoy en día para realizar tareas cotidianas me encuentre con un entorno tan lento. Pienso que tal y como parece que están haciendo con Windows 7, deben replantearse su política y apostar por mejorar el rendimiento de sus productos, creo que hay muchos usuarios hartos ya de tantas versiones e innovaciones y que esperan realizar su trabajo de una forma más efectiva.

Creo en la innovación, pero no en la innovación a costa de no corregir y mejorar aquello que tienes por detrás. Como dicen en el desarrollo, los errores y la optimización de los módulos que lo requieran deben ser aspectos prioritarios.Creo que Microsoft con algunos productos ha empezado a pagar ya, su decisión de sacar productos cada poco tiempo e innovar a toda costa, y que en los sucesivos años todavía lo hará más si no cambia de política radicalmente.

Pero esta es solo mi opinión, estoy seguro que muchos no estaréis de acuerdo con estas afirmaciones.

El poder de las expresiones regulares

Creo no conocer a ningún programador que no odie enfrentarse a las expresiones regulares, lo cierto es que tienen su complejidad, aunque si te habitúas a utilizarlas en más de una ocasión te pueden sacar de un apuro.

En nuestra aplicación detectamos un error procedente de un control muy utilizado en nuestros formularios, el caso es que eliminamos una propiedad pública que utilizábamos para su configuración, como era de esperar el “find usages”, nos decía que esta era utilizada por infinidad de formularios de la aplicación, aparecían unas 2000 referencias, después de eliminar varias recorde que en cierta ocasión había podido solucionar un problema similar utilizando expresiones regulares.

Tenia que eliminar de los formularios todas las líneas similares a

   1: ((System.ComponentModel.ISupportInitialize)(this.bPorcentaje7.Properties)).BeginInit();
   2: this.bPorcentaje7.Properties.MaxLength = 6;
   3: ((System.ComponentModel.ISupportInitialize)(this.bPorcentaje7.Properties)).EndInit();

Utilizando la herramienta find and replace del visual studio configure las siguientes expresiones:

image

   1: ^(.*){ComponentModel.ISupportInitialize}(.*){Porcentaje}(.*){Properties}(.*)
   2:  
   3: ^(.*){porcentaje}(.*){Properties}(.*){ MaxLength }(.*)

La primera expresión regular eliminaría dos líneas, la primera y la tercera correspondientes a BeginInit y EndInit y la segunda eliminaría la línea del maxlenght.

Su tradución seria así: Busca desde el principio de la línea una cadena que comience con cualquier carácter y que seguidamente tenga la cadena “ComponentModel.ISupportInitialize”, después cualquier cadena, seguido de la palabra “porcentaje” seguida de cualquier cadena, seguida de la palabra “properties” y que finalice con cualquier cadena.

Una vez escrito, solo bastaba reemplazar todas las cadenas, y voila, el trabajo de varias horas hecho en tan solo unos segundos.

Otro ejemplo interesante para sustituir un bloque determinado es este:

(.*)public void Copy(.*n)+?.*(})

Esta busca un metodo publico llamado copy y borra todo el contenido entre los dos corchetes, de esta forma podríamos eliminar un método completo.

La documentación de Visual Studio se encuentra disponible en http://msdn.microsoft.com/en-us/library/az24scfc(VS.80).aspx

Existen además varios generadores de expresiones regulares en la web y programas para ayudarnos a escribirlas.

Entity FrameWork – Metadata

Como sabéis la metadata se define como la información que se conoce sobre los propios datos, cuando hablamos de entity framework, esta contendrá información sobre las entidades, campos y relaciones. En este ejemplo estaba buscando la posibilidad de conocer el maxLength de un campo de una entidad determinada, de esta forma podria configurar algunos de mis controles en tiempo de ejecución.

Cuando configuramos un grid necesitamos configurar el maxLength de cada campo para impedir un desbordamiento en la actualización, para evitar establecer el valor de forma manual en cada columna, pues si en algún momento cambio este valor, estaría obligado a variar esta información en todos los controles de mi aplicación donde utilice este campo. La metadata puede proporcionar esta información para configurar los controles en tiempo de ejecución evitando cambiar estos datos si en el algún momento altero la estructura de mis tablas. De la misma forma podemos configurar la precisión y la escala en valores decimales, nombre de los campos para el databinding, aceptación de valores nulos, configuración de campos de solo lectura, etc.

La automatización de estos procesos a traves de los metadatos evitara numerosos errores y nos permitirá realizar cambios de una forma más eficaz.

En otras ocasiones esta información nos permitira generar sentencias Sql en tiempo de ejecución, generalizar consultas y funciones en nuestros proyectos.

En Entity framework la metadata esta almacenada en el archivo edmx en formato xml. En este ejemplo el archivo xml contiene información diversa en cada uno de los campos, maxlenght en los casos que utilizemos cadenas, precision y escala en los valores decimales.

   1: <Property Name="Empresa" Type="nvarchar" MaxLength="50" />
   2: <Property Name="Transporte_factor" Type="decimal" Nullable="false" Precision="6" Scale="2" />        

He desarrollado este pequeño programa que nos permitirá conocer el maxLength de cualquier campo de una entidad,

/// <summary>
/// Retorna el maxlenght de un campo de una entidad y un contexto determinados
/// </summary>
/// <param name="context">Contexto del que se quieren recuperar las entidades</param>
/// <param name="entity">Nombre de la entidad</param>
/// <param name="field">Nombre del campo</param>
/// <returns>Retorna la longitud de la entidad, en caso de no encontrarlo retorna -1</returns>
public static int GetMaxlenght(ObjectContext context, EntityObject entity, string field)
{
    if (context != null && entity != null && !string.IsNullOrEmpty(field))
    {
        EntityContainer container;
        if (context.MetadataWorkspace.TryGetEntityContainer(context.DefaultContainerName, DataSpace.CSpace, out container))
        {
            EntitySet entitySet;
            if (container.TryGetEntitySetByName(entity.ToString().Split('.')[1], false, out entitySet))
            {
                const string mlenght = "MaxLength";
                if (entitySet.ElementType.Members.Contains(field) && entitySet.ElementType.Members[field].TypeUsage.Facets.Contains(mlenght))
                {
                    object smaxlenght = entitySet.ElementType.Members[field].TypeUsage.Facets[mlenght].Value;
 
                    if (smaxlenght != null)
                    {
                        int maxlenght;
                        if (int.TryParse(smaxlenght.ToString(), out maxlenght))
                        {
                            return maxlenght;
                        }
                    }
                }
            }
        }
    }
    return -1;
}

El ejemplo de uso seria algo así:

   1: using (NorthwindEFEntities context = new NorthwindEFEntities())
   2: {
   3:     Employees employees = new Employees();
   4:     EdmTools.GetMaxlenght(context, employees, "FirstName");
   5: }

Si quisieramos conocer otro factor, tan solo tendriamos que alterar el valor de la constante definida en:

const string mlenght = "MaxLength"

Aunque para el ejemplo anterior quizás lo más lógico sería realizar un método extensor para acceder a este tipo de información para poder hacer algo asi:

int maxlenght = employess.GetMetadata(employess.FirstName, Attributes.Maxlenght);

Cuando lo desarrolle pondré este ejemplo.

Como veis en el depurador las facetas pueden proporcionarnos más información, default value, nullable, etc.

image

El siguiente ejemplo está basado en el mismo proceso y devuelve información a través de un array con el contenido del maxLength de todas las columnas:

   1: /// <summary>
   2: /// Retorna una colección de campos valor con el maxlenght de cada uno de los campos de una entidad
   3: /// </summary>
   4: /// <param name="context">Contexto del que se quieren recuperar las entidades</param>
   5: /// <param name="entity">Entidad</param>
   6: /// <returns>Retorna un diccionario campo valor con la longitud de cada uno de los campos, en caso de no encontrarlo retorna -1</returns>
   7: public static Dictionary<EdmMember, int> GetMaxlenght(ObjectContext context, EntityObject entity)
   8: {
   9:     Dictionary<EdmMember, int> edmFieldsMaxlenght = new Dictionary<EdmMember, int>();
  10:     if (context != null && entity != null)
  11:     {
  12:         EntityContainer container;
  13:         if (context.MetadataWorkspace.TryGetEntityContainer(context.DefaultContainerName, DataSpace.CSpace, out container))
  14:         {
  15:             EntitySet entitySet;
  16:             if (container.TryGetEntitySetByName(entity.ToString().Split('.')[1], false, out entitySet))
  17:             {
  18:                 foreach (EdmMember member in entitySet.ElementType.Members)
  19:                 {
  20:                     const string mlenght = "MaxLength";
  21:  
  22:                     if (entitySet.ElementType.Members.Contains(member.Name) && entitySet.ElementType.Members[member.Name].TypeUsage.Facets.Contains(mlenght))
  23:                     {
  24:                         object smaxlenght = entitySet.ElementType.Members[member.Name].TypeUsage.Facets[mlenght].Value;
  25:  
  26:                         if (smaxlenght != null)
  27:                         {
  28:                             int maxlenght;
  29:                             if (int.TryParse(smaxlenght.ToString(), out maxlenght))
  30:                             {
  31:                                 edmFieldsMaxlenght.Add(member, maxlenght);
  32:                             }
  33:                         }
  34:                     }
  35:                 }
  36:             }
  37:         }
  38:     }
  39:     return edmFieldsMaxlenght;
  40: }
Buscando información encontré este blog http://www.scip.be/index.php?Page=ArticlesNET24, en el que proponen otro ejemplo muy interesante. Solo que aquí no puede acceder al maxlengh, es curioso, únicamente a los valores por defecto, si es nullable, etc.

1:
var query = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
   2:                 .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
   3:             let m = (meta as EntityType)
   4:             let properties = m.Properties
   5:             select new
   6:             {
   7:  
   8:                 EntityName = m.Name,
   9:                 MembersCount = m.Members.Count,
  10:                 KeyMembersCount = m.KeyMembers.Count,
  11:                 PropertyNames = from p in properties
  12:                                 select new
  13:                                 {
  14:                                     p.Name,
  15:                                     p.Nullable,
  16:                                     p.DefaultValue,
  17:                 Documentation,
  18:                                     Type = p.TypeUsage.EdmType.Name
  19:                                 }
  20:             };

No he probado a leer los metadatos de una entidad heredada, aunque en este caso podriamos averiguar su base y realizar la consulta. Utilizando como base el ejemplo anterior podemos facilmente ver todas la entidades que están derivadas.

   1: public static IEnumerable GetEntityNamesBaseNames(ObjectContext context)
   2: {
   3:     var query = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
   4:                     .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
   5:                 let m = (meta as EntityType)
   6:                 where m.BaseType != null
   7:                 select new
   8:                 {
   9:                     m.Name,
  10:                     BaseTypeName = m.BaseType != null ? m.BaseType.Name : null,
  11:                 };
  12:     return query;
  13: }

Espero que os sirva…

Especialización vs Polivalencía

No hace mucho tiempo, pensaba que la única salida que teníamos los desarrolladores era la de especializarnos en una tecnología determinada para poder asegurar nuestro futuro. Los continuos cambios y las nuevas tecnologías hacen que cada vez sea mas difícil mantenernos «actualizados» para ser competitivos en el mercado que nos rodea. Esta es una pregunta que desde hace tiempo me quita el sueño y de la que no logro obtener una respuesta clara. Esta claro que ser un experto en una determinada tecnología, puede aportarnos muchas ventajas. Para las pequeñas empresas de desarrollo de software obtener personal especializado en una determinada área es prácticamente imposible, ya que, para ello deberíamos contar con medios y con multitud de personas para conformar un equipo de trabajo.

En mi empresa desde hace tiempo observo que cada vez se da mas importancia a la obtención de personas con perfiles polivalentes, que según las necesidades de esta normalmente delimitadas por las situaciones de un mercado cada vez mas dinámico, sean capaz de adaptarse y asumir roles diferentes a los que están habituados con el fin de conseguir que estas, sean mas competitivas, pero los trabajos son, relativamente mas sencillos, en ningún caso, comparables al desarrollo de software.

Un simple desarrollador en asp.net debe ser capaz de conocer diferentes tecnologías, desde xml, ado, html, servicios web, iis, conocimientos de seguridad, etc. Creo que, una de las características mas valiosa de las personas en el área del desarrollo es la «capacidad de adaptación», ser capaz de asumir una tecnología en poco tiempo y sacarla partido es algo cada vez mas importante en nuestro trabajo, para ello no basta con estar preparados, estudiar o realizar diferentes cursos, hay que tener un nivel de predisposición al cambio, y esto es algo que rara vez se encuentra en las personas, es lógico, cualquier cambio, por pequeño que sea, siempre traerá consigo un sinfín de problemas que debemos solucionar. Por otra parte, estas personas tendrán que renunciar a cierta especialización para ser mas polivalentes. En el área del desarrollo de software es cada vez mas difícil obtener perfiles polivalentes ya que llegar a dominar una sola de las tecnologías con las que trabajamos puede suponer años de estudio y experiencia.

Por otra parte, creo que muchas veces, olvidamos el verdadero sentido de nuestro trabajo, este no es el de realizar aplicaciones utilizando las últimas tendencias y tecnologías, sino el de dar una «solución» a un problema especifico. Desde luego la solución debe combinar muchas factores importantes entre los que destaco el «tiempo», en la mayoría de los casos la introducción de una nueva tecnología frente a una solución ya conocida tendrá inicialmente un coste superior que debemos valorar y que muchas veces olvidamos, para dotar a nuestras aplicaciones de una arquitectura mas moderna, versátil y adaptable, pero que requiere mucho mas tiempo de desarrollo. Uno de los mayores problemas que observo en los desarrolladores, y me incluyo, es que normalmente buscamos que nuestra aplicación sea lo mas perfecta posible, esto incluye la adopción de las mas modernas tecnologías.

Especializarnos en un determinado área pueda hacer que en determinados casos seamos mas competitivos además de ser los únicos capaces de solucionar determinados problemas. Hablando con Fernando Guerrero, me comentaba que su empresa se había especializado en ofrecer soluciones muy determinadas, por ejemplo le llamaban para dar solución a un cliente que tenia una pagina web y que recibía mas de un millón de visitas semanales y en puntas de acceso los servidores se colapsaban, desde luego dar una solución adecuada para un problema similar normalmente pasa por disponer dentro de la empresa a personas con perfiles muy especializados, comentaba que ellos se dedicaban a ofrecer soluciones de problemas muy determinados y que estos suponían un porcentaje ridículo dentro del ámbito del desarrollo de software, y me aseguraba que estaban saturados de trabajo. En este caso contar con perfiles especializados hacia que su empresa podía ofrecer soluciones que otras nunca podrían resolver en un corto periodo de tiempo.

Por otra parte, en mi trabajo, la necesidad de obtener perfiles polivalentes es cada vez mas importante, un simple desarrollador debe conocer diferentes tecnologías y llegar a conocer alguna de ellas en detalle puede llevar mucho tiempo. Ser capaz de conocer a fondo una sola de las tecnologías que utilizamos, por ejemplo «Sql Server», nos puede llevar años de trabajo.

El otro día Rodrigo Corral escribía un post hablando de la importancia de aprender a desarrollar en entornos con multiples procesadores para aprovechar las características del nuevo hardware, comentaba que si somos capaces de aprender y dominar estas nuevas tecnologías tendremos un mercado que nos permitirá marcar la diferencia frente a otros desarrolladores. Lo cierto es que incluso, asumir una nueva tecnología como de las que habla en su post, pasa por conocer muchas otras y que el nivel necesario para poder entender aspectos como la multitarea es algo que no todos están capacitados para realizar.

Quizás la decisión mas adecuada pase por escoger lo mejor de ambos mundos, dominar una o dos areas e intentar ser polivalentes estudiando otras tecnologías para ser capaces de asumir cambios con rapidez, aunque todo dependerá de las necesidades de la empresa para la que trabajemos, por otro lado la especialización en un determinada tecnologia podría ayudarnos en la búsqueda de un futuro profesional mejor.

Así que sigo preguntándome que será mejor: Especializarse o ser polivalente y saber un poco de todo. ¿ Son areas diferenciadas o se pueden  complementar ?… Espero con vuestras opiniones poder aproximarme a la solución mas adecuada. Como decía Malder, «La verdad esta ahí fuera…».

¿ Sabes jugar al pocker ?

keith-sexton-1 He leído varios comentarios, sobre la importancia del valor del equipo en los departamentos de desarrollo. En el ámbito de las empresas que conozco, normalmente el equipo viene conformado de antemano, a veces porque la empresa cuenta ya con personal, otras porque el proceso de selección se lo encargan a una empresa externa que lo unico que tiene es un perfil predeterminado, son muchos los factores impiden seleccionar al equipo mas adecuado.

Por otro lado, te puedes encontrar que alguna de las personas del grupo no cumple las expectativas esperadas. Llegados a este punto, muchos piensan «Si un desarrollador en un momento determinado no cumple las expectativas lo mejor es deshacerse de el lo antes posible», en este caso, la empresa tendrá un alto precio que pagar ya que normalmente habrá invertido en formación y recursos para mejorar la calidad de su personal y debe buscar a alguien capaz de asumir el trabajo. En el mundo en que nos movemos, si la empresa utiliza tecnologías de última generación o el conocimiento de los procesos internos es complejo, esto se puede convertir en algo sumamente complicado, además de asumir el coste de echar al empleado, debemos formar de nuevo a otra persona e introducirla en el ámbito laboral. Normalmente esta tarea no se realiza en periodos cortos de tiempo y corremos el riesgo de volver a encontrarnos con alguien que no cumple nuestras expectativas y vuelta a empezar….

Comparo algunos equipos de desarrollo con una partida de pocker por la singularidad de sus miembros, en este caso los jefes de proyecto aspiran a recibir una escalera real. 

Muchos son los motivos que hacen que una persona no desarrolle su trabajo de forma eficaz, cuando indagas un poco, descubres que algunos tienen problemas familiares,otros se consideran mal pagados y no estan dispuestos a esforzarse mas, en otros casos sus jefes no

Pocker1

saben delegar y se limitan a darles el trabajo basura… Podríamos escribir las causas utilizando los doce tomos de la biblia y nos quedaríamos cortos.

Creo que los responsables de un equipo cuentan con recursos para mejorar esta situación. Una palmadita en la espalda de vez en cuando, mostrar cierto interés hacia la persona, puede hacer que esta se sienta completamente motivada y valorada en su entorno. Ponernos de vez en cuando en el lugar de los demás es algo que debemos intentar para comprender mejor a las personas.

Como responsables de un equipo de trabajo, nuestro cometido pasa por conocer bien a las personas, debemos hacer de psicólogos para entender su comportamiento. Un responsable de equipo en cualquier ámbito debe ser capaz de escuchar, comunicar, delegar, incentivar, transmitir, compartir, enseñar, bromear, irse a tomar unas cervezas o a cenar de vez en cuando con su equipo….. , etc, etc. Después de leer esta frase, alguno en mi oficina se estará descojonando de la risa….. «capaz de escuchar,  motivar…. jajajajajaja….», también es importante asumir nuestros errores, limitaciones y debilidades para tratar de corregirlas, al fin y al cabo, nadie es perfecto.

Existen muchas técnicas para mejorar la relación en un equipo de trabajo, recuerdo tres en especial que me llamaron mucho la atención, la primera era algo así: «Tenemos un grupo de 5 personas, cuatro de las cuales realizan el trabajo de una forma correcta pero el quinto no hace mas que darnos problemas», el proceso de mejora consistía en aplicar dos reglas, primero explicar detalladamente al equipo las ventajas de realizar su trabajo de una forma determinada y la dependencia que tenían los unos de los otros para realizar su cometido y segundo, poner al mas problemático a cargo del equipo. Habitualmente se detectaba que este, cuando comprendía que su trabajo afectaba a los demás y asumía su nuevo Rol se convertía en la persona que mas aportaba cambiando su actitud de rechazo hacia el equipo.

La segunda es bastante conocida y esta basada en la rotación, de vez en cuando los roles del equipo se invertían, un operario pasaba a ser jefe de equipo y al contrario…

La tercera técnica la vi en el programa «el encantador de perros», que pasaba por introducir a un perro inadaptado en una manada estable, al cabo de una semana este abandonaba su actitud y pasaba a formar parte de la manada, haciendo lo mismo que los demás cuando otro perro en su misma situación llegaba. Desde luego contar con un buen equipo que camina en una única dirección hará que cualquier persona que se integre en el, se adapte mas fácilmente a sus reglas. Desgraciadamente algunos animales son mas inteligentes que los hombres.

El trabajo en equipo es una aptitud, independiente del nivel profesional que se pueda tener. Lo malo es que desde pequeños nos han educado a ser individualistas. Cuando vamos al colegio o a la universidad lo único que pensamos es en aprobar, muy pocos acuden con el único fin de aprender, tan solo es un proceso de selección que si pasamos, nos permitirá acceder a una vida mejor. Frases como «tienes que ser mejor que los demás o similares…» son las enseñanzas de la sociedad actual. Los trabajos en equipo desde el colegio, bachillerato pasando por la universidad brillan por su ausencia y claro, cuando nos incorporamos al mercado laboral desconocemos como trabajar con mas personas. Aprender algo basado en todo lo contrario a lo que nos han enseñado desde pequeños es muy complicado, y no seremos capaces de hacerlo si no tenemos plena confianza en el valor de las personas. Muchos responsables no creen en esto, porque jamás se lo han enseñado, así que lo tendrán muy difícil para conformar un buen equipo de trabajo.

Por otro lado, algunos de los genios mas grandes de la historia han ofrecido al mundo sus avances desde la soledad de su trabajo, he conocido personas brillantes que se adaptan muy mal a las reglas del trabajo en equipo o les resulta muy difícil relacionarse con los demás, estas logran su máxima capacidad productiva cuando no tienen reglas que acatar. Detectar a estas personas y dotarlas de capacidad de independencia puede llegar a ser una mejor práctica que obligarla a acatar todas las reglas de un equipo.

La mayoría de la gente no sabe trabajar en equipo simplemente porque nadie les a enseñado la forma de hacerlo, explicar el porque de las cosas, escuchar a todos los componentes, ayudarles y motivarles será el primer paso para transmitir las ventajas del trabajo en equipo. He descubierto a lo largo de mi experiencia, que conocer a las personas nos aporta una visión única, que nos permitirá corregir y mejorar determinados comportamientos, si optamos por la vía mas fácil cuando detectamos problemas, habremos fracasado en nuestro cometido, un jugador de pocker juega con las cartas que recibe.Los buenos jugadores de pocker no basan su juego en las cartas. Los buenos jugadores de pocker analizan la mesa, cada gesto, cada mirada, estudian sus probabilidades e intentan conocer al contrario, aunque contar con buenas cartas hace que sus probabilidades de ganar sean mayores.

Para los buenos jugadores de pocker, las cartas serán un factor importante, pero no determinante.

No puedo resistir dejaros esta foto, que nadie se lo tome a mal….

20080129poker-electoral

Pd. Recuerdo de la última partida, jejejeje…, gane…… lo siento Francisco, Victor, Garris,  jajajajajajaja……

Scrum – El valor esta en las personas

En mis primeros años de desarrollo estaba solo, habitualmente desarrollaba mis proyectos como quería, con el paso del tiempo y el aumento de las funcionalidades de los programas y de los avances en los lenguajes de programación, empecé a darme cuenta que pronto no iba a poder desarrollar sistemas de cierto nivel yo solo, en ese momento comencé un nuevo proyecto y me anime con unos amigos a conformar una pequeña empresa dedicada a ofrecer todo tipo de servicios informáticos, hacíamos de todo, desde vender equipos e instalarlos hasta desarrollar pequeñas aplicaciones y algunas páginas web, cuando la empresa fue prosperando necesitamos incorporar más gente al equipo de desarrollo, habitualmente cada uno se iba dedicando a un proyecto de forma individual, observaba a unos desarrolladores que les gustaba el trabajo que hacían y otros que solo trabajaban, digamos, para subsistir, los que verdaderamente aportaban valor eran aquellos que veían su trabajo como un hobbie, a partir de entonces, cuando seleccionaba a alguien, me importaba mas si verdaderamente le gustaba el trabajo que iba a realizar, que las titulaciones y los conocimientos técnicos que tenía. Para mi estaba claro, el valor estaba en las personas que tenían interés por su trabajo. Normalmente los programas no eran muy grandes, hacíamos pequeños análisis y desarrollábamos los proyectos, cuando procedíamos a su instalación el cliente nos hacia observaciones y correcciones, que de forma inmediata se iban resolviendo para adaptarlo completamente a sus especificaciones. El cliente no solamente se limitaba a hacerme correcciones, sino que me proporcionaba ideas para mejorar mis desarrollos, el problema era que esto normalmente lo hacia al final de la implantación y muchas veces tenia que rehacer gran parte de los proyectos asumiendo el coste originado. Habitualmente nos reuníamos con los desarrolladores y hablábamos de cómo realizar el trabajo, ellos proponían sus ideas y compartíamos diferentes puntos de vistas, como dice el refrán “dos ojos ven más que uno”, otras veces me sentaba con algún programador e intentábamos
corregir un error. Para gestionar los proyectos solíamos utilizar excel, project o la lista de tareas de outlook, estas se escribían y se iban tachando a medida que se iban completando.

Cuando comencé a trabajar en equipo, empezaron a aflorar una serie de problemas, los desarrolladores que tenían un nivel más bajo, demandaban de forma constante mi ayuda, y me interrumpían constantemente cuando trabajaba, observaba que dedicaba mucho tiempo a enseñar, corregir e indicar como tenían que realizarse los desarrollos, cuando me preguntaban ¿como vais?, yo estaba totalmente descolocado, en mi caso, conocía la velocidad del trabajo que realizaba, pero no sabía cuánto podrían tardar las personas que tenían otros conocimientos y habilidades. El número de tareas creció mucho mas y su gestión me llevaba mucho tiempo. Me encontraba perdido, porque mis estimaciones fallaban constantemente.

Buscando una solución para estos problemas y gracias a Miguel Jimenez comencé a interesarme por nuevas tendencias en el área del desarrollo de software, empecé a leer sobre desarrollo ágil, en concreto me gustaron las que hablaban de programación extrema o XP, en las que se hablaba de pruebas unitarias, programación en parejas, priorización en la corrección de errores, entregas frecuentes, refactorización, integración del cliente como parte fundamental del equipo, propiedad de código compartida y simplicidad, alguna de las prácticas que se recomendaban eran utilizadas por mi desde hacia tiempo, así que me gustaron especialmente y comencé a estudiarlas un poco más en detalle.

Fue en este momento cuando me tropecé con Scrum y CMMI, buscando información me encontré con el magnífico trabajo realizado en Navegapolis por Juan Palacio y por supuesto, con los post de Rodrigo Corral.

Cuando conocí Scrum, observe que alguno de los factores que me habían llevado a realizar proyectos exitosos estaban ahí, y que además, me proporcionaba una solución para aquellos problemas que estaba tratando de resolver, mejoras en la planificación y la estimación, evitar las constantes interrupciones, mejorar la comunicación con el equipo, involucrar más a las personas, etc.

Las constantes reuniones diarias son la base de la metodología y nos proporcionaban varias ventajas:

– Muchas veces ocurría que cuando hablabas con un desarrollador al cabo un tiempo observaba que llevaba unos días desarrollando de forma incorrecta algún modulo. La falta de comunicación hacia que los retrasos por estas causas aumentasen, con la reunión diaria evitabas enterarte de esto al cabo de un tiempo, reduciendo retrasos y errores en la planificación. Estos se identificaban al principio y permitían mantener el ritmo de desarrollo.

– Al realizar la reunión diaria podías atender todas las dudas y consultas del equipo de desarrollo en ese periodo, con lo que las constantes interrupciones se evitaban, cuando un desarrollador preguntaba algo, se le decía: «eso se atenderá en la reunión de Scrum.»

– El equipo tenía constancia del trabajo que realizaban los demás, redundando en un mejor conocimiento de la aplicación. Ocurría muchas veces que los desarrolladores que realizaban un determinado módulo desconocían el trabajo de los demás, cuando se intentaban enlazar dos módulos aparecían problemas que no se habían tenido en cuenta por falta de información.

– El equipo aporta valor, ya no era el único que resolvía las dudas o decía como tenían que realizarse las cosas, los propios integrantes del equipo ayudaban a sus compañeros a resolver sus problemas y a mí, aportándome ideas y otros puntos de vista sobre cómo llegar a soluciones más óptimas. Esto mejoraba la relación del equipo y el desarrollo del proyecto.

– Resultaba ser una eficaz herramienta de control, como sabéis en la reunión de Scrum se responde a tres preguntas.

      ¿Qué hicistes desde el último Scrum Diario respecto al proyecto?

      ¿Qué harás desde ahora y hasta el próximo Scrum Diario?

      ¿Qué te está impidiendo hacer tu trabajo lo mejor posible o que necesidades tienes para realizar el desarrollo?

La reunión permite conocer el trabajo de cada desarrollador, las dudas y los impedimentos que tienen para realizar su trabajo ademas de la evaluación continua de su trabajo diario. Es como cuando íbamos al colegio y nos preguntaban por la tarea del día anterior, desde luego no hacer la tarea es un riesgo, ya que todo el equipo sabe que nos has realizado tu cometido. Se mejora la productividad, al tener una presión inconsciente por el hecho de tener que pararse frente al resto del equipo y contar en lo que se estuvo trabajando.

Como sabéis en Scrum se planifican los llamados «sprints» que tienen una duración de entre 20-40 días, en ellos de definen las tareas que vamos a ser capaces de realizar en el periodo determinado. La planificación de cada uno marcaba una dirección clara para el equipo, todos conocen los objetivos y saben que van a obtener al final de cada sprint. En la conformación de los sprints cada miembro del equipo realiza la
estimación y gestión de sus tareas, ellos son los mejores conocedores
de su velocidad, esto hace que el control sea relativamente sencillo de
realizar. En un equipo realizar este proceso era muy complicado, ya que
los desarrolladores no tenían el mismo nivel, por otra parte, un
desarrollador no programa siempre igual, la adopción de nuevas
tecnologías, el progreso y las habilidades de cada uno, hacen que este
sea un factor muy cambiante. Es el desarrollador el que se impone la
tarea y el periodo determinado para desarrollarla, este hecho aporta
gran valor, pues solo se le exige aquello que se ha comprometido a
realizar. Aqui radica una de las premisas de Scrum, la confianza en las
personas es una de las bases de la metologia, si bien puedes ayudar en
las estimaciones al final el desarrollador es el que se compromete.

Posteriormente la evaluación en el sprint review nos permitía
corregir aquello que se había realizado mal en el sprint anterior
evitando incurrir en errores mas de una vez. 

Las constantes entregas permiten al cliente evaluar el trabajo realizado, como se intentan desarrollar módulos «independientes», estos se pueden comenzar a amortizar la aplicación mucho antes de finalizarla.

El feedback del cliente permite realizar cambios mucho mas temprano, evitando rehacer gran parte del proyecto.

Cuando analizaba procesos, comencé a darme cuenta de que la mayoría de los problemas que detectaba, habitualmente, estaban derivados directamente de las relaciones interpersonales, la mayor parte de los responsables desconocía cómo había que trabajar en equipo, esto derivaba en consecuencias verdaderamente catastróficas, normalmente acostumbraban a dar órdenes y eran los únicos que aglutinaban la información de cómo se debían ejecutar los procesos. Cuando hablabas con las personas que realizaban el trabajo, te dabas cuenta de que sus jefes carecían de mucha de la información que ellos manejaban y consecuentemente no podían tomar las decisiones adecuadas, si la comunicación no era fluida entre el responsable y su equipo de trabajo, nunca podrían llegar a mejorar los procesos en los cuales trabajaban. Esto generaba un malestar general entre el equipo que sentía como sus valoraciones no eran escuchadas y redundaba en la bajada de la autoestima y consecuentemente en su rendimiento. Desgraciadamente todavía son muchos, incluidos los jefes de proyecto y las empresas de desarrollo los que no ven a las “personas” como su principal valor. Piensan que las infraestructuras, las máquinas, los procesos y ciertas «certificaciones» son la base de sus negocios. Me cuesta entender que a día de hoy, una gran mayoría de empresas sigan aplicando el método dirigir y controlar o el de Economia 101 tal y como cuenta Joel Spolsky.

Por otra parte, cada día encuentro mas empresas que adoptan una metología simplemente por estrategia, para vender software a terceros que tienen esa exigencia o por disponer de una certificación que avala lo bien que trabajan, recuerdo cuando se puso de moda la Iso 9001…., no estoy diciendo que no aporten cierto valor, pero creo que tienen un precio muy alto que pagar.

Scrum proporciona un método sencillo para estimar, controlar y dirigir proyectos minimizando la burocracia, centrándose y adaptándose a las necesidades de cada momento. 

En Scrum se trabaja en equipo, todos tienen voz y voto, sus opiniones se toman en cuenta y pasan a formar parte del proyecto. Para todos aquellos que crean que su principal valor esta en las «personas», Scrum será una excelente metología.

Depurando, depurando y con el mazo dando…

image

Un día, un usuario me llama por el teléfono rojo, «oye Juan, resulta que estaba yo en tal formulario y de repente no se donde he pulsado y creo que se me ha borrado el texto en las observaciones….», incrédulo empiezo a pensar… ¿ lunes ?, este no sabe que ha pasado…. a saber que ha estado haciendo el fin de semana… por si acaso activo Defcon 1…

Después de un tiempo, me llama otro usuario y me dice: «Juan, resulta que estaba yo en tal formulario y de repente no se donde he pulsado y parece que se ha borrado el texto en las observaciones….», «Joder como me suena…. «, tendré que revisar el código… pasamos a Defcon 2….

Abro el formulario, empiezo a investigar, buscando las dichosas «observaciones», después de un tiempo nada, ninguna referencia…., lo dejo estar… ¿ será un virus o una rata que se ha comido un trozo de fibra?….

De nuevo otro día recibo la dichosa llamada. Decido activar todas las alarmas…. ¡¡¡¡señores!!!! estamos en !!!!!!!!!!!!!!!!! DEFCON 3 ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡

¿ Será un trigger que se activa por algún motivo ? Buscando en la base de datos nada, ni rastro…, continuo indagando y por fin veo en un menú una opción «Actualizar datos…», me pregunto ¿quien ha introducido esto aquí… ?, desde luego llama a un Store Procedure que actualiza las observaciones dejándolas en blanco, fue una opción que solicitaron años atrás cuando se traspasaron los datos de un sistema anterior, y claro seguía activa, muy cerca en el menú, de otra bastante utilizada, los usuarios a veces se equivocaban y pulsaban esta opción eliminando el texto, me digo: no la voy a eliminar, no vaya a ser que el usuario X la utilice algún día, introduciré un messagebox que le pregunte ¿ Si pulsa «si», las observaciones se irán al carajo…. ? y voila….

Al cabo de unos días me llama un usuario y me dice: «oye Juan, resulta que estaba yo en tal formulario y de repente, no se donde he pulsado, me ha salido un mensaje «no se que del carajo…», he dado enter, y resulta que me han desaparecido las observaciones. Pienso «arghghghghghghgh,  te vas a enterar….», entro al código, introduzco 10 messageBox mas, le añado una clave de encriptación basada en CuaimaCrypt y lo pongo en producción.

Después de cierto tiempo, me llama otro usuario y me dice: «oye Juan, resulta que estoy intentando borrar las observaciones con la utilidad que me hicistes y llevo pulsando no se cuantas veces al si para se vayan al carajo de una vez, después de media hora, me aparece una pantalla para que introduzca una clave de 200 dígitos alfanuméricos…, pero no me acuerdo del dígito 199, ¿era una z o una p?……. y nada, que no me deja eliminar las p%$tas…. observaciones estas…..». Con la soga al cuello y a punto de saltar por la ventana… decido utilizar el control usuarios, habilito la opción para el usuario que la utiliza, elimino los mensajes y la clave y deshabilito la opción para todos los demás, haciéndola invisible en el menú.

Este tipo de situaciones se dan a menudo en los procesos de depuración y desarrollo, a veces, cuando desarrollamos, nos centramos en realizar validaciones para evitar errores y no nos damos cuenta que es mucho mas fácil evitar el error eliminando la posibilidad de cometerlo. La utilización de una simple mascara evitara varias operaciones posteriores, validación, notificación al usuario de su error, limpiar el campo, situar de nuevo el foco en el control, etc.

Debemos centrarnos en evitar el error, no en controlarlo y sobre todo «utilizar el sentido común»….   desgraciadamente algunos carecemos de esto…

image

Por cierto…, deja de mirar a la chica y ponte a trabajar… que es lunes….

Maldivas Interfaces 1 – Sistemas de Búsqueda

Una de las funcionalidades mas importantes en la mayoría de los programas de gestión son las interfaces de búsqueda, un interface de búsqueda debe ser rápido y usarse con facilidad, de el depende en gran medida la versatilidad del programa. En Maldivas utilizamos varias formas diferentes de realizar búsquedas, el primero lo conocí en una Entidad Bancaria hace varios años y desde entonces siempre lo implemento en mis aplicaciones. La mayor parte de los interfaces de búsqueda que he visto, suelen partir de una lista de campos que permiten que el usuario seleccione uno de ellos, introduzca un valor y realice la búsqueda.

El sistema que presento aquí, es relativamente sencillo de implementar y aporta varias ventajas.

El primer paso cuando pulsamos sobre el botón de búsqueda, es situar el formulario en blanco. Quedaría mas o menos así:

image

Si el usuario introduce el valor en el campo identificativo, la búsqueda se realiza de forma automática, ya que este campo es único. En este caso, cuando introduzco el valor 23 en el código, el registro es buscado y mostrado de forma automática.

image

Cuando realizamos una búsqueda por otros campos podemos introducir información en varios de ellos, en el ejemplo siguiente introducimos varios valores. Utilizamos para activar el proceso dos teclas de función, F11 que realiza la búsqueda del primer registro coincidente y F12 que realiza la búsqueda de todos los registros que cumplan las condiciones determinadas por los valores introducidos. En este último caso, si el proceso encuentra un solo registro, este se muestra directamente en el formulario.

image

En este caso la búsqueda solo encuentra un registro que cumple las condiciones especificadas y lo muestra.

image

Si realizamos una búsqueda de las zonas que tengan el valor «Nacional» el sistema encuentra varios registros y los muestra en un formulario diferente.

image

En el, podemos seleccionar el registro que nos interese visualizar o realizar otras funciones como filtrar mas los resultados o imprimir el conjunto de registros seleccionados, para realizar este tipo de operaciones el sistema permite limitar los campos que se quieren imprimir, puesto que en un informe A4, seria difícil poder visualizar todos los campos, en el ejemplo limitaremos los campos al código, nombre y la zona_iva.

image

Después de esto, el formulario muestra las columnas seleccionadas.

image

A continuación podríamos exportarlos a PDF quedando el informe así:

image

Ventajas:

Este sistema permite realizar búsquedas complejas utilizando varios campos, con la ventaja de aprovechar posteriormente los resultados para realizar informes sencillos en varios formatos.

Al usuario le resulta muy cómodo de utilizar ya que habitualmente conoce la ubicación de los campos y no tiene que perder tiempo en buscarlos a través de una lista de campos.

Evitaremos tener que introducir los códigos que muchas veces desconocemos, en el siguiente ejemplo, vemos que será mas sencillo realizar la búsqueda a partir de la selección del valor de un combo que acordarnos del código de la forma de pago, en este caso «Compensación» que corresponde con el valor «0002», que es el utilizaríamos para realizar la búsqueda en otros sistemas.

image

 

¿ Como funciona ?

Si utilizamos una entidad, dataset o cualquier objeto enlazado al formulario debemos crear un nuevo objeto vacío y mostrarlo en el formulario. Una vez introducidos los datos el sistema, este debe comparar los valores del objeto con uno vacío para obtener aquellos campos y valores que han cambiado. Esta información conjuntamente a la información de los metadatos del objeto, permiten generar en tiempo de ejecución una sentencia Sql para realizar la búsqueda.

Si utilizáis un modelo basado en DataSet necesitareis la información de la clase para obtener los metadatos y el estado de las filas para realizar la comparación. Podéis encontrar mas información en:

http://msdn.microsoft.com/es-es/library/system.data.datarowstate(VS.80).aspx

Si vuestra intención es utilizar Entity FrameWork deberéis utilizar de los metadatos de la entidad y comparar los valores anteriores con los actuales. Podéis encontrar mas información en:

http://msdn.microsoft.com/en-us/library/system.data.objects.objectstateentry.aspx

En Maldivas utilizamos la técnica de reflexión para obtener la información de los metadatos y los valores de la clase para realizar la consulta. De esta forma podemos generar una sentencia sql en tiempo de ejecución en base a los campos que han cambiado similar a esta:

«SELECT * FROM Gestion.Interlocutores_zonas WHERE Nombre LIKE ‘%’ + @nombre+ ‘%’ AND Zona_iva LIKE ‘%’ + @zonaIva + ‘%’)»

Si os fijáis introducimos la cláusula like en los campos de tipo string, para buscar valores que se encuentren en cualquier parte del campo.

 

Busqueda Rápida

Otro de los sistemas de búsqueda que hemos incorporado es el que se observa en la barra de herramientas situada en la parte superior del formulario.

image

Este proceso nos permite realizar búsquedas de una forma mucho mas «rápida», en cuanto al trabajo por parte del usuario se refiere y funciona de la siguiente manera:

El usuario introduce cualquier valor, un número, una fecha, una cadena, etc, el sistema analiza los campos de la entidad que tienen el mismo tipo del valor buscado, en el caso por ejemplo de una fecha el sistema solo preguntara por aquellos campos que sean de tipo datetime, en este ejemplo vamos a introducir una cadena, «Interior«, vemos como el sistema realiza una búsqueda y obtiene un conjunto de registrosque tienen esta cadena en cualquiera de sus campos de tipo string.

image

La gran ventaja de este sistema es la facilidad de uso por parte del usuario, y la gran desventaja es que la velocidad de búsqueda es mas baja ya que la sentencia Sql que se genera tiene que evaluar todos los campos de tipos similares, para ver esto la consulta del ejemplo anterior seria algo como:

«SELECT * FROM Gestion.Interlocutores_zonas WHERE Codigo LIKE ‘%’ + @valor + ‘%’ OR Zona_iva LIKE ‘%’ + @valor + ‘%’ OR Zona_politica LIKE ‘%’ + @valor + ‘%’ OR Zona_tipo LIKE ‘%’ + @valor + ‘%’ OR Zona_cc LIKE ‘%’ + @valor + ‘%’ OR Nombre LIKE ‘%’ + @valor + ‘%’ )»

Por supuesto si la tabla tiene 100 campos, la sentencia que se puede generar es inmensa, aunque las pruebas que hemos realizados sobre tablas de unos 10000 registros con 200 campos se realiza en menos de tres segundos. Lógicamente esto dependerá de diferentes factores como Hardware del Servidor, Índices y otros factores.

Busqueda Sincronizada

Por último el sistema de búsqueda que nos proporciona el uso de los controles que utilizamos, de la marca Devexpress, en este caso el grid situado a la izquierda nos permite cambiar el orden y buscar sobre cualquier campo.

image

Al igual que en la cláusula like de Sql si eliminamos el símbolo % filtraría todos los registros que comiencen por el valor introducido

image

El control esta sincronizado con el formulario, de manera que si nos situamos en cualquiera de los registros del grid, el formulario muestra sus datos.

image

Otra de las ventajas de estos controles es que permiten visualizar y modificar las condiciones de filtrado en tiempo de ejecución:

image

Además de estas opciones de búsqueda, hemos implementado el sistema de desplazamiento de registros, ordenación y filtrado que permite al usuario trabajar con un conjunto de registros, hablare de ellos, en el próximo post sobre Interfaces.

Maldivas Arquitectura 2 – Entidades y Reflexión

Como he contestado en algún Post, Maldivas es un Framework que propone una solución concreta para un momento determinado, en que la tecnología de Microsoft solo permitía utilizar su modelo de datos basado casi exclusivamente en Dataset o tenias que utilizar frameworks de terceros como n-hibernate, nace de una necesidad en concreto para dar solución a un proyecto que comenzó al finales del año 2005, en ningún caso propongo este Framework para utilizar en otras aplicaciones. Este modelo está basado por completo en el Entity Relationship Model, que existe hace mas de 30 años y al que hemos dotado de funcionalidad adicional para minimizar el código requerido y dotarle de otras características.

Si tuviera que desarrollar de nuevo este proyecto, seguramente, utilizaría el Entity Framework, que se basa en un modelo de entidades similar al que presento aquí. En cualquier caso el proceso de reflexión se utiliza en gran parte del framework de .net y os puede servir para aplicarlo en algunos procesos de vuestros desarrollos, un ejemplo claro lo podéis ver cuando desarrolláis sobre Web Services en que la información de los contratos, serialización y otros se realiza en forma de atributos.

El primer proceso es el de representar en nuestro lenguaje, en este caso c#, las entidades correspondientes a cada una de las tablas, vistas, funciones y otros objetos de la base de datos con los que nos queramos interactuar, para que podamos trabajar con ellas desde nuestro lenguaje. En este caso cada clase que denominaremos «Entidad» es la representación de una tabla de nuestra base de datos. Partiremos de una entidad sencilla que almacena la información de una tabla de la base de datos, esta entidad compuesta de cuatro campos, está decorada con varios atributos que definen varios aspectos de la tabla a la que hace referencia. Es lo que habitualmente denominamos Metadatos. Como se observa en este ejemplo, la entidad es una clase en c# que representa una de las tablas de la base de datos.

using System;

using Maldivas.Entities.Attributes;

namespace Maldivas.Entities.Gestion

{

[Serializable]

[EntityStructure(DataBase = «Maldivas_oran», Schema = «Gestion», Name = «Articulos_embalajes_tipos», EntityType = «Table»)]

public class Articulos_embalajes_tipos : Entity, IEntities<Articulos_embalajes_tipos>

{

#region Fields enum

 public enum Fields

{

Codaux, Codigo, Descripcion, Observaciones,

}

#endregion

[EntityAttributes(FieldName = «Codaux», IdentityValue = 1, IdentityStep = 1, Lenght = 10, IsReadOnly = true)]

public int Codaux { get; set; }

[EntityAttributes(FieldName = «Codigo», PrimaryKey = 1, Lenght = 2)]

public string Codigo { get; set; }

[EntityAttributes(FieldName = «Descripcion», AllowNull = true, Lenght = 50)]

public string Descripcion { get; set; }

[EntityAttributes(FieldName = «Observaciones», AllowNull = true, Lenght = 8000)]

public string Observaciones { get; set; }

#region IEntities<Articulos_embalajes_tipos> Members

public virtual Articulos_embalajes_tipos Clone()

{

Articulos_embalajes_tipos articulos_embalajes_tipos = new Articulos_embalajes_tipos();

articulos_embalajes_tipos.Codaux = Codaux;

articulos_embalajes_tipos.Codigo = Codigo;

articulos_embalajes_tipos.Descripcion = Descripcion;

articulos_embalajes_tipos.Observaciones = Observaciones;

return articulos_embalajes_tipos;

}

 public virtual void Copy(Articulos_embalajes_tipos ent)

{

Codaux = ent.Codaux;

Codigo = ent.Codigo;

Descripcion = ent.Descripcion;

Observaciones = ent.Observaciones;

}

 #endregion

 public new static string ToString()

{

return «Articulos_embalajes_tipos»;

}

}

}

Existen dos tipos de atributos en la clase, el primero que decora la clase:

[EntityStructure(DataBase = «Maldivas_oran», Schema = «Gestion», Name = «Articulos_embalajes_tipos», EntityType = «Table»)]

Este atributo nos indica algunas propiedades de la base de datos como el Nombre de la base de datos el esquema, el nombre y el tipo de entidad» Tabla, Vista, Función, etc.

Y el segundo que decora cada columna de la tabla con un atributo similar a este:

[EntityAttributes(FieldName = «Codigo», PrimaryKey = 1, Lenght = 2)]

En el se indican las propiedades de cada columna, estas serán utilizadas a lo largo de toda la aplicación y nos permitirán obtener la información relativa a la configuración de cada campo en la tabla.

Hemos incluido dos métodos, el primero «Clone» nos permite realizar una copia de cualquier entidad en un nuevo objeto y el segundo «Copy», nos permite copiar la información de otra entidad en la actual, estos métodos son utilizados por diferentes secciones a lo largo del programa. Pensamos también incorporar el patrón Observer, pero al final lo descartamos ya que en principio, no nos iba a hacer falta.

Una de las primeras preguntas que nos hacemos es: ¿cómo podemos acceder a esta información que almacenamos en forma de atributos en una clase?, la respuesta seria utilizando reflexión. Reflexión es una tecnología que nos permitirá preguntar al ensamblado de una clase información acerca de esta, básicamente lo que hace es abrir el archivo del ensamblado y buscar la información del atributo con el que hemos decorado la clase. Para entender el proceso os voy a poner un ejemplo sencillo, uno que nos permita únicamente almacenar el nombre de la base de datos de una clase. El primer paso sería el de crear una clase que deriva de Attribute y nos permita almacenar la información que queramos. Para más información podeís ver en http://msdn.microsoft.com/es-es/library/z0w1kczw(VS.80).aspx

/// Creación del atributo

using System;

namespace Maldivas.Entities.Attributes

{

[Serializable, AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]

public sealed class EntityStructure : Attribute

{

/// <summary>

/// Permite configurar el nombre de la Base de datos

/// </summary>

/// <param name=»database»>Nombre de la Base de datos</param>

public EntityStructure(string databaseName)

{

DBName = databaseName;

}

/// <summary>

/// Propiedad que permite acceder y configurar al nombre de la tabla

/// </summary>

public string DBName { get; set; }

}

}

 

/// Creación de la clase que lo utiliza

[EntityStructure(«AdventureWorks»)]

public class Ejemplo

{

}

/// Creación de un metodo que nos permite leer el atributo de la clase

public class ReadDataBaseAttribute()

{

string DataBaseName = null;

Type type = typeof(Ejemplo);    

/// Aqui se realiza el proceso de reflexión

object[] oestructure = type.GetCustomAttributes(typeof(EntityStructure), false);

/// Comprueba que haya leido algún valor

if (oestructure != null && && oestructure.Length > 0)

{

EntityStructure es = oestructure[0] as EntityStructure;

if (es != null)

DataBaseName = es. DBName;

}

return DataBaseName;

}

De esta forma la variable DataBaseName obtendría su valor AdventureWorks.

Debido a que el proceso de reflexión tiene un alto coste, ya que hay que abrir el ensamblado y buscar la información, puede ser aconsejable cachear la información si la vamos a utilizar muchas veces, nosotros tenemos un proceso, en el que, cuando se solicita información de una entidad la primera vez, esta se almacena en cache, de esta forma minimizamos el coste del proceso.

Escribir una clase similar a la del primer ejemplo por cada una de las tablas que tengamos, puede ser un proceso muy costoso, para automatizar este proceso, desarrollamos un pequeño programa que automatiza la creación de los ficheros de entidades utilizando Codedom, del que intentare escribir un post en entradas posteriores, podéis ver un pequeño ejemplo aquí http://www.15seconds.com/issue/020917.htm , aunque existen otras formas de hacerlo, esta es la más adecuada, ya que nos permitirá generar código en diferentes lenguajes. El aspecto de nuestra herramienta es el siguiente:

De igual forma Entity Framework dispone de una herramienta para realizar este proceso de forma automática.

A petición de Eduardo Obregon, mi compañero de trabajo, que me preguntaba sobre cuánto es de costosa la reflexión y la ganancia que se obtiene cacheando datos, he adjuntado un archivo de test para realizar esta comprobación, en el equipo donde lo he probado, mis resultados son los siguientes. Para leer 10 millones de atributos de una entidad, el equivalente a 100000 tablas con unos 100 campos por tabla, el equipo ha tomado un tiempo aproximado de 40 segundos, cacheando se ha reducido a los 3 segundos, ya que el atributo solo ha sido leído una vez, en realidad el tiempo de cacheo será algo mayor ya que la inicialmente la lectura de los atributos a cachear siempre se tiene que realizar la primera vez. Despues del test creo que el cacheo no tiene mucho sentido. Cada uno que saque sus propias conclusiones.

Os dejo el fichero que contiene el ejemplo Test Atributos y Reflexión

 

¿Debemos cambiar la forma de vender Software?, continuación…

Acabo de recibir un comentario de Rafa en el post original, creo que es un resumen, en muchos aspectos, de lo que piensa la gran mayoría de la gente, por eso he decidió hablar un poco mas de este tema.

El post en concreto dice:

Hola Juan, es mi primer comentario en tu blog, pero no he podido resistirme al ver tu post y los comentarios.

He acudido a varios cursos de Rodrigo sobre administración de proyectos, metodologías agiles y demás. Con la experiencia que tengo en este mundo, ya van 11 años, mi opinión es que estas metodologías solo sirven para grandes o grandísimos proyectos en los que estén metidos asesores externos y personal técnico del cliente o para proyectos internos, es decir para los propios proyectos de empresas de software. ¿Por qué?, yo creo que primero el cliente no sabe lo que quiere, o mejor matizo, sabe perfectamente lo que quiere pero no sabe como plasmarlo en un desarrollo informático. El cliente solo paga cuando el trabajo está hecho, es muy bonito que el cliente vaya pagando según los módulos entregados, pero la verdad es que si el cliente no tiene todo, la típica frase es: «No tengo nada». La implicación del cliente o del máximo responsable de tu cliente la mayoría de las veces es escasa o más bien nula, y lo entiendo, esto es diferente a todo lo demás, yo si me compro un armario empotrado le digo lo que quiero al carpintero, pero no me va ensañando las baldas que va haciendo, si me compro un coche, pues no me voy a la fabrica, si me compro una casa, está en la mayoría de los casos es «estándar» como el software y cuando esta me la entregan no se adapta a mis necesidades (como dicen mis clientes con sus programas), pero lo único que puedo hacer es joderme y esto está asumido por la gente, no así en el caso del software. Realmente es un mundo y un tema para tesis doctoral, yo en este mega comentario no aporto nada, lo sé, pero es que no tengo ni idea de que aportar…. Esto sirve muchas veces de terapia, lo sé, los psicologos deben de tener sus consultas llenas de jefes de producto.

Hola Rafa, te agradezco tus comentarios, pero no comparto la mayoría de tus opiniones, en primer lugar te diré, que todos aportamos, de hecho y gracias a tu comentario me he animado a escribir otro post, tu opinión es tan válida como la de cualquier experto y además aprendemos los unos de los otros, ¿De eso se trata? no…. cada uno aporta en base a su experiencia y sus conocimientos, si lo compartes será enriquecedor para todos.

Sé que en el mercado en que nos movemos, muchos piensan que vender un proyecto de esta forma es como un «sueño», pero, depende de nosotros que podamos hacerlo realidad, si te fijas en otro tipo de proyectos, por ejemplo cuando un constructor realiza un edificio, o el gobierno encarga la realización de un tramo de autovía, los proyectos se comportan así por necesidad, es decir, se van realizando paulatinamente y las empresas van pagando según el trabajo que se va acometiendo, en estos casos la imposibilidad de hacer una obra de tal magnitud debido sobre todo al coste económico que supone, hace inviable que el coste se pueda asumir hasta el final, si en un momento dado la empresa no puede continuar el trabajo o el cliente no está satisfecho, siempre existirá otra que pueda terminarlo y el cliente habrá pagado por aquello que se ha realizado.

Lo que cuento en el post es sobre todo, parte de la experiencia que he tenido en mis proyectos, en ningún caso, lo que me han enseñado las metodologías, entiendo que las metodologías nacen para dar una «solución» a muchos de los problemas que se presentan en los proyectos como una necesidad para aquellos que buscan una solución para estos problemas, además han sido probadas con éxito en multitud de proyectos, si no, nadie las utilizaría, en este caso la metología que usamos se adapta perfectamente a esta problemática y surge precisamente para ofrecer una solución.

Desde luego no comparto en absoluto que este tipo de metologías estén pensadas solamente para proyectos grandes, la metología te asegura que realices el trabajo día a día, qué más da si el proyecto tiene una duración de 15 días o 5 años, al final hacemos lo mismo, solo que a la hora de estimarlo y venderlo nos resultara más sencillo.

Creo que los proyectos de desarrollo no son comparables a cuando encargamos un armario, en cualquier caso si te quieres asegurar de que el armario cumple tus expectativas, seguro que le echas un vistazo a las baldas.

El cliente es el que mejor conoce su problemática y por eso, para llevar a cabo cualquier proyecto debemos contar con él, tiene que formar parte indisoluble del equipo, creo que este es uno de los factores donde cometemos la mayoría de los errores, a veces creemos que nosotros sabemos más que él, otras que no sabe transmitirnos los que realmente quiere, en cualquier caso la culpa siempre se la echamos al «cliente». Yo creo que es nuestra obligación conocer en detalle toda la problemática del cliente, si esto no se cumple tenemos muy pocas posibilidades de que nuestro proyecto llegue a buen término. Los proyectos fracasan por diferentes motivos, a veces nos equivocamos al estimar el coste, otras el cliente no sabe muy bien lo que quiere y eso redunda de nuevo en el coste, en otros casos no entendemos lo que el cliente nos quiere transmitir, la mayor parte son causados por «una falta de comunicación». La solución que propongo pasa desde luego por convencer al cliente, si no somos capaces de convencer al cliente, tampoco seremos capaces de realizar un proyecto exitoso sin contar con su colaboración, entiendo que es complicado, sobre todo para empresas que no tienen claras las cosas o simplemente que han tenido experiencias negativas. En cualquier caso, somos nosotros quien marcamos las reglas, si de antemano sabemos que debemos acometer un proyecto y que no vamos a tener la colaboración del cliente, tenemos muchas posibilidades de fracasar, llegados a este punto quizás sea mejor no comenzarlo.

Creo que es importante reflexionar, en el sentido, de que somos nosotros los primeros que cometemos el error «No sabemos vender correctamente un proyecto ni marcar las reglas que regirán a lo largo del proceso». Inicialmente marcamos nuestras propias normas, la mayoría de las empresas suelen investigar al posible cliente para saber si es o no solvente, y exigir un pago antes de comenzar el proyecto. No conozco a ninguna empresa que comience un proyecto de desarrollo con un cliente desconocido, si antes no ha cobrado un porcentaje de su costo. Hacemos esto porque es una norma en la que creemos.

Somos nosotros los marcamos nuestras propias reglas, aunque para hacerlo hay que creer en que, lo que estamos haciendo es lo más adecuado. Dudamos de que esta sea la solución más adecuada, en algunos casos porque nunca lo hemos probado, otras veces porque no tenemos la suficiente disciplina para utilizar una metodología y la mayoría de las veces por que el «cambio» siempre suele significar mayor complejidad y solemos seleccionar el camino más fácil, «el que conocemos». Las implicaciones que tiene el poder realizar un proyecto con estas restricciones son importantes, debemos conocer la metodología y ser estrictos para llevarla a cabo, es el precio que debemos pagar, si queremos cambiar la forma de trabajar y sobre todo de realizar proyectos exitosos.

Sé que este puede ser el «sueño» de muchas empresas, y que existen muchos problemas para la realización de un proyecto tal y como lo expongo en el post, algunas nos vienen dadas por el departamento comercial o impuestas por empresas que llevan muchos años en el mercado. Pero si preguntamos a cualquier cliente, la realidad nos dice, que la mayoría no están satisfechos con sus proveedores, y esto es debido a que no hacemos las cosas bien.

Cuando vendemos un proyecto de software, algo completamente intangible, nuestras reglas conforman parte del producto en sí mismo. Si cambiamos estas en base, únicamente a las exigencias del cliente, estaríamos vendiendo un producto diferente en el cual no creemos. Si no estamos dispuestos a marcar nuestros límites no podremos tener éxito en nuestros proyectos.

Todos hemos oído frases similares a las siguientes, «es que el cliente no me atiende, ya verás cuando vayamos a implantarlo», «nadie sabe cómo funciona esto, no sé cómo solucionarlo.», «en el Dpto de contabilidad me dicen que haga esto, pero en el otro me dicen todo lo contrario….» Si no somos capaces a la hora de vender un desarrollo trasladar al cliente nuestra forma de trabajar y como hay que hacer para desarrollar un proyecto, difícilmente podremos llevarlo a cabo y esto es culpa nuestra, no de el cliente.

Si queremos mejorar, debemos cambiar nuestra forma de pensar y desde luego establecer nuestras propias reglas.