Buenos cambios para el entorno DevOps en Microsoft

Guau.. vaya con las novedades de Connect 2015, bastantes cosas en desarrollo multiplataforma, cloud, Windows… pero centrémonos en lo que corresponde a nuestro interés como DevOps y entusiastas del ALM, asi que vamos con calma….

Adiós Visual Studio Online…. hola Visual Studio Team Services, si, un nombre puede ayudar mucho, y desde que Microsoft le dio el nombre oficial a lo que originalmente conociamos con Team Foundation Service me ha sido complicado explicar que VSO no es un IDE como Visual Studio pero en el browser, sino por el contrario una herramienta ALM (Scrum, repositorio, build…), ahora este cambio de nombre puede ayudar un poco mas a entender las cosas, así que repitamoslo una vez mas: Visual Studio Team Services (VSTS).

Preview de Release Management para VSTS, una gran noticia, quienes han seguido mis artículos sobre despliegue, se habrán percatado que el proceso de paso a entornos lo había configurado como un paso final del proceso de Build, pues bien… una etapa tan importante requiere una gestión por separado que facilite no solo colocar la aplicación en el primer entorno, sino también mover las versiones de la aplicación entre diversos entornos, y ese es el objetivo de RM que ha evolucionado de ser un producto separado a ser una parte integral del entorno de VSTS, permitiéndonos entre otras cosas establecer aprobadores manuales que decidan si una versión de nuestra aplicación ya esta lista para pasar al siguiente nivel, como detalle adicional es importante indicar que no es necesario que tu ciclo de Build lo hayas gestionado con VSTS sino que tu paquete también puede provenir de Jenkins, y claro… como era de esperar nuestro entorno destino no es solo Windows. En las próximas semanas iremos desgranando un poco estas facilidades.



 

Preview de Code Search en VSTS, una ayuda que nos permitirá ubicar el código deseado de manera potente a través de nuestros repositorios via web.

Soporte para Subversion en TFS y pronto en VSTS, hay que reconocerlo a pesar del crecimiento de Git, hay muchos desarrolladores en el mundo Java que se sienten muy cómodos con Subversión, así que en breve se tendrá como opción el que nuestros Team Projects se creen con Subversión como tipo de repositorio, la cosa es tener opciones ¿no?

A seguir poniéndonos al día!

 

Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (IV)

Pues si, como fue prometido, ya va tocando meternos con el modelo de Builds, pero antes de proseguir respondamos la pregunta que deje en el post anterior, ¿en que parte de la solución estoy grabando los parámetros de conexión a la BD? pues en el archivo PartsUnlimitedWebsite.pubxml ya que es ahí donde el wizard de deploy guardo los datos de la cadena de conexión a pesar de que al final no sobrescribió los valores del web.config, nos corresponde editar las secciones de dicho archivo a fin de que no persistan los valores dentro de nuestra solución.

Curiosamente, debemos agregar este archivo a nuestra solución, para lo cual hacemos clic derecho y ya formara parte de lo gestionado por VSO, ojo esto solo funciona si hemos editado adecuadamente nuestro archivo .gitignore como ya hemos explicado en el segundo post de esta serie.

Clipboard27
Bueno, ahora si, subamos el cambio y volvamos a nuestro Team Project en Visual Studio Online, dirigiéndonos a la zona de BUILD, de momento estará vacía.Clipboard28
Posicionados sobre la zona que dice “Build definitions” (nótese que aparte tenemos una zona correspondiente a las XAML definitions) y presionamos el “+”, nos saldrá la siguiente pantalla:Clipboard29
Finish Reading: Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (IV)

Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (III)

Bueno, luego de una pausa, proseguimos con esta serie de artículos para establecer un escenario completo de despliegue usando el nuevo modelo de Builds que traen tanto Visual Studio Online como Team Foundation Server 2015, ¡así que manos a la obra!

Para proseguir con el demo de Parts Unlimited, debemos mencionar que en este ejemplo se hace uso intensivo de los Resource Groups que ya conversamos anteriormente, esto permite automatizar la creación del entorno donde se desplegara nuestra aplicación, vale decir que reduciremos nuestras visitas al Portal de Azure para la creación de nuestros recursos.

Para facilitar esto debemos preparar a nuestra maquina para que sea capaz de provisionar directamente en Azure, para lo cual abrimos una ventana de PowerShell (con permisos de Administrador, claro esta) y escribimos Set-ExecutionPolicy RemoteSigned.

5554.image_thumb_6CC60E94

Bien, terminaron los preparativos así que ya con la aplicación cargada en Visual Studio (y bien conectada a VSO) vamos al proyecto PartsUnlimitedEnv, hacemos clic derecho y elegimos New Deployment… Finish Reading: Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (III)

Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (II)

Bueno, ya salimos de Fiestas Patrias y toca cumplir lo prometido, ir conociendo el nuevo modelo de Builds que ha sido introducido en Visual Studio Online y en Tean Foundation Server 2015 (que ya esta disponible en su versión final) y como comentabamos, se usara el ejemplo Parts Unlimited, que por tener ya las cosas hechas respecto a integración con BD nos servira para dar una visión integral del despliegue.

Los pasos que seguiremos seran los siguientes:

1) Descargar el código fuente de Github, crear nuestro repositorio en VSO y hacer las pruebas en local.

2) Preparar los Resource Group y todas los recursos Azure necesarios para el despliegue desde Visual Studio, de esta manera no tendremos que crear las cosas manualmente desde el Portal, salvo que sea estrictamente necesario.

3) Preparar la Build propiamente dicha y probarla.

Lo primero es crear un proyecto en Visual Studio Online, nótese que como siempre elegimos Scrum como plantilla y en este caso usaremos Git como modelo de repositorio.
Clipboard04

Luego de esto toca conectarse a dicho proyecto desde nuestro Visual Studio, y luego proceder a clonar el repositorio (que forma parte del proyecto de VSO), en este caso el repositorio aun estará vació (a menos que hayamos creado un readme desde el portal de nuestro proyecto), en mi caso particular edite la carpeta local donde se va a clonar el repositorio pues por defecto Visual Studio intenta crear los repositorios locales de Git en el disco C:

Clipboard05Ahora viene la parte interesante, Parts Unlimited es un proyecto muy interesante que si bien empezo con ASP.NET 4.x ahora están trabajando en una version basada en ASP.NET 5, pero para efectos de esta demo de Integración Continua nos basaremos en la versión 4.X para lo cual deberemos dirigirnos a este branch en GitHub, desde donde podremos bajarnos un Zip con todo el proyecto, lo descargamos luego de lo cual estaremos listos para integrarlo en nuestro repositorio Git de VSO. Finish Reading: Integración Continua con el nuevo modelo de Builds de VSO/TFS 2015 (II)

No todo tiene igual riesgo

Mucho se habla de gestión de riesgos, ya sea en metodologías ágiles como en, cof cof, waterfall, y claro, mucho se colocan tablas y con una mayor o menor pericia se indican los impactos y probabilidades respectivas, hasta ahí “lo normal”.

Lo usual es que por lo usual los criterios de experiencia que se toman están basados en el tipo de proyecto: ERP, almacén, web o desktop o también en el grado de complejidad del negocio, estado de las relaciones con el cliente, primera vez, time to market etc, nada fuera de lo habitual.

El problema es que muchas veces la visión “de negocio” logra opacar al criterio técnico en un factor muy importante: no todas las tecnologías tienen igual riesgo, y no, no me refiero al hecho de que por ejemplo un consultor de SAP cobre mas que un diseñador gráfico (llevándolo a extremos), sino que las diversas tecnologías tienen diferentes niveles de disponibilidad de recursos de aprendizaje, lo cual quieras que no, impacta en las previsiones que se requieren tomar para un proyecto.

En algunos casos es evidente que hay muchos mas recursos (ojo, en este blog nunca hablamos de personas como “recursos”, ¿ok?) para SQL Server y Oracle que para Informix o Sybase, por lo cual el tiempo en que un equipo puede llegar a ser productivo en un proyecto con estas dos tecnologías “raras” es mayor, pero mal que bien se puede solventar con la experiencia previa en otros motores de base de datos, así que tenemos un riesgo ligeramente mayor, pero justificable.

Visto a este contexto debemos pasar a un diferente tipo de escenario, los frameworks o soluciones “listas para usar”, productos que se espera que puedan ser usados directamente por un usuario final, “casi” sin necesidad de desarrollo, pero claro eventualmente terminan pidiendose personalizaciones y como la aplicación tiene una API en un lenguaje “conocido” como PHP, C# o Java pues se empieza el desarrollo tomando los mismo criterios que cualquier otro proyecto a medida y .. ahi empiezan los problemas.

En concreto estas aplicaciones (concretamente los CMS que son con los que he tenido experiencia) presentan dos problemas que los hacen “bestias” diferentes a cualquier desarrollo a medida:

  1. Esfuerzo extra para configurar los entornos, tanto de desarrollo, como de producción, en el caso de SharePoint por ejemplo era muy complicado, tan así que no se podía trabajar contra un servidor compartido sino que cada desarrollador debía de tener una Maquina Virtual para tener un entorno de trabajo, todo lo cual involucraba un esfuerzo que no era trivial.
  2. Cambio de paradigma respecto a como desarrollar y/o depurar, pues aquí no eres tu desarrollando una aplicación, estas intentando construir algo sobre los cimientos que alguien mas hizo, y que le puso reglas que pueden ser no usuales (y sobre todo contraintuitivas), pero necesarias para que el producto funcione, lo cual deriva en una necesidad de conocimiento (y tiempo de aprendizaje) mas allá de cuan experto uno crea ser en el lenguaje en cuestión.

Queda claro que estos dos factores tienen alta probabilidad de incidir sobre el tiempo que le puede tomar al equipo implementar la solución, por lo que seria un grave error asumir proyecciones sin tomar en cuenta el esfuerzo extra mencionado, si, es difícil acometer estas cosas que nos dejan productos como Magnolia, Vignette, o SharePoint, pero al final son retos técnicos que terminan siendo superados, a menos claro que la dirección asuma que “.net es .net” y no tome en cuenta detalles como estos en sus proyecciones, ahora que si a estas dos cosas, se le suma la poca experiencia local, o poca documentación actualizada en foros, asumimos grandes riesgos que no podemos dejar de informar de antemano, y créanme, en el caso de CMS (salvo que tengas miembros del equipo que actúen como pilares del resto) siempre pasa algo de lo mencionado, por lo que debemos estar alertas, regresando al titulo de este post, no todo tiene igual riesgo (técnico).

En defensa de Visual Basic.Net y las “buenas practicas”

Primero el Disclaimer: La herramienta a la que le tengo mas cariño y con la que he sido mas productivo es Borland Delphi (ahora Embarcadero, pero la que yo conocí era de Borland), dicho esto pasemos al grano.

El titulo del post proviene a razón de la ultima sesión de Mad.Nug en la que Jorge Serrano compartió su experiencia sobre las posibles acciones a tomar cuando se tienen aplicaciones en Visual Basic 6 y existe la necesidad/presion/requerimiento de migrarlas a .Net, la sesion fue muy explicativa, recordandonos cuales son los puntos donde hay mas incompatibilidades y las posibles opciones:

– Herramienta de migración automática
– Entorno mixto (Microsoft Interop Forms Toolkit 2.1 y wrappers)
– Empezar todo desde cero.

De acuerdo a su experiencia (corrígeme si te estoy referenciando mal, Jorge) debería procurarse por la ultima opción (en ese sentido Jorge facilito un buen enfoque para acometer esos proyectos), y estar alertas ante el riesgo de que una solución puntual como un entorno mixto crezca y pierdas el control.

Si bien comparto la idea de que hay casos en que no queda otra que proceder de esa manera, creo que esa decisión tiene que ser sopesada teniendo en cuenta criterios como: cantidad de lineas de código existente, dependencia de terceros, disponibilidad de conocimiento funcional, etc… en ese sentido se sintió la falta de cubrir posibles estrategias de cuando se ha decidido ir por el camino de la migración (que igual se hace para algunas aplicaciones, dejando el resto a un rehacer desde cero).

Bueno, a lo que iba, como parte del camino de un rehacer desde 0, Jorge planteo que había que procurar migrar hacia C# en lugar de hacia VB.Net, ¿por qué? es lo que nunca me queda claro, salvo por un hecho (mencionado en la reunión) que es la mayor disponibilidad de recursos en Internet para C# que para VB.Net, pero fuera de ello el acceso hacia el Framework de .Net es básicamente el mismo (salvo excepción que contare luego), por lo que también en la conversación con los asistentes se dejo caer que con C# se es mas ordenado y se encamina hacia las buenas practicas, por lo que ya entramos a un tema de preferencias y es a donde quería llegar.

Admitamoslo, por sus propias características en Visual Basic 6 era muy muy fácil desarrollar con malas practicas y que el código spaghetti generado sea muy difícil de mantener, pero si una cosa tiene Visual Basic .Net es que significo una ruptura sin pasos intermedios con respecto a VB6 a fin de volverlo OOP y compatible con el nuevo Framework (*), y por lo tanto mucha de la laxitud inherente al viejo VB6 ya no existe, es un buen lenguaje OOP y muy valido para aprovechar los conocimientos de sintaxis propios de Basic: Dim, as, Next, End…, el problema gordo es la herencia de mala imagen que lastra el lenguaje, asi que explicar a un manager que seria menos traumatico continuar con VB.Net en vez de C#…. complicado, triste realidad.

Siendo así creo que solo hay dos razones no personales para optar por desarrollar un proyecto en C#:
– Es muy critico contar con todos los recursos de documentación disponibles para un tema en concreto, que lamentablemente en su mayoría están en C# (p.ej. hay casi tres veces mas info para Generics en C# que para Visual Basic).
– Te ha tocado acceder a una parte del Framework que expone justamente un tipo de datos existente en C# pero no en Visual Basic.Net, eso me paso con la versión 1.1, no se si lo habrán solucionado, pero … queda como alerta.

En contraparte tengo algunas razones de productividad para seguir usando VB.Net siempre que puedo:
– Detección automática de algunos errores y de su corrección, esa potencia de mostrarte un subrayado en algunos errores de sintaxis es de veras de agradecerse, y lo mismo con el hecho de que si compilas y saltan errores no tienes que recompilar para ver si has corregido bien o no, conforme vas corrigiendo tu pila de errores se reduce.
– No sensible a las mayúsculas/minúsculas, esta característica va de la mano con lo anterior, si defines bien una variable (usando Camel y Pascal case adecuadamente) y luego la invocas, el hecho de que se te auto corrijan las mayúsculas y minúsculas es una señal inmediata de que no te has equivocado al invocar el nombre de dicha variable.
– Las instrucciones (begin..end..next..) son mas claras que las llaves ({}) para poder hacerse una idea del ámbito de un bloque de código.

Dicho esto, como desarrollador he venido a conocer ambos lenguajes, pero lo fundamental es el Framework, siendo que el saber C# me ha facilitado acceder a ciertos recursos no existentes para VB.Net, pero que luego a la hora de implementar no he vacilado en aplicarlos sobre proyectos en VB.Net, así que es bueno saber ambos, pero uno no debería de inhibirse y proponer el uso de VB.Net en los proyectos.

Pero algo se me quedo dando vueltas ya desde la sesión a propósito de eso de que C# te ayuda a ser mas ordenado (o algo así), y a esto se sumo el comentario de uno de los asistentes comento que ellos tenían una aplicación grande en VB6, basada en COM+/MTS, hecha según las recomendaciones que daba Microsoft por entonces para el desarrollo en COM, lo cual me hizo retroceder a la época en que este diagrama salia en toda presentación de arquitectura y diseño de aplicaciones alla por el final de los 90s:

Pongámonos en contexto, para el lanzamiento de Visual Basic 6, ya había un gran parque de aplicaciones en VB4 y VB5, pero la fama del “DLL Hell” ya era muy fuerte, así que Microsoft emprendió una campaña muy intensiva para explicar el concepto de desarrollo de aplicaciones distribuidas, las ventajas del multicapas en la mantenibilidad de las aplicaciones, etc etc… conceptos que ahora son el pan de cada día en los objetivos de los diversos proyectos actuales, fueron recien conocidos para muchos gracias a Microsoft, y la verdad es que en ese entonces Microsoft se preocupo mucho en hacer pedagogía de las buenas practicas, tan así que en los cursos de certificación se hacia énfasis en lo que hay detras de la instanciación de objetos en COM para de esa manera impulsar formas mas ordenadas de programar, y lo bueno de todo es que esa pedagogía era de manera no agresiva, planteándola como una evolución de las aplicaciones que habia en desarrollo entonces, a fin de que los programadores mejoraran sus practicas frente a la fama de caos, o sea se pugnaba (por entonces) un cambio evolutivo en las formas de hacer las cosas apoyándose en lo que los desarrolladores ya conocían, lo cual condujo a que los partners serios si que hicieran aplicaciones buenas y solidas usando VB6.

Para bien o para mal todo cambia con la introducción de .Net, que como ya hemos indicado en este y otros posts vino a ser un ruptura muy fuerte, en la que sobrevivía el que tenia mejor las bases de OOP y/o Windows DNA. Claro, ya lo peor paso (salvo las app VB6 que se resisten a morir) y la cosa esta mas o menos estabilizada, salvo por la nueva tendencia del famoso patron SOLID, sobre el cual ya comente que tenia mis dudas sobre si facilitaban la mantenibilidad de las aplicaciones, pero que en todo caso hay que entenderlas y saber como y cuando aplicarlas, siempre sin dogmatismos.

Y es justamente que ahora los dogmatismos se hacen presentes, pues en lugar de introducirnos progresivamente a las nuevas “buenas practicas” se nos pide que ya no usemos ni Windows Forms (aunque si, podríamos pasar a WPF) ni Windows Forms, diciendonos que “no es testeable” “no permite xxx principio” de buenas a primeras sin mostrar evolutivamente como mejorar el código que estamos desarrollando, de ahi a lo que dije en un twitt reciente: Si nos explicasen las pruebas unitarias con ejemplos basados en multicontroles, eventos y mantenimientos, igual las adoptariamos #digonomas (o este otro), digo eso porque la mayoría de las aplicaciones corporativas de uso interno (no portales de contenido) terminan siendo eso y no los clásicos ejemplos de calculadoras o números perfectos, así que seria bueno que los planteamientos de difusión sobre TDD o SOLID partan de un enfoque evolutivo y no rupturista (dando cobertura tanto a VB.Net como C#) a fin de lograr una mejor adopción.

A ver si no llega alguien por aquí diciendo que he “perdido el punto”… xD

(*) Y si, sigo creyendo que muchos traumas se hubieran evitado si al hacer .Net (y C#) se hubiera mirado lo que tenia VB6 a fin de hacer la ruptura menos dolorosa.

Pensando en estrategias de migración de VB6 a VB.Net

Casi a hilo de lo que comentaba en el anterior post, hace poco Jorge Serrano publico Cada vez que migras una línea de código de VB6 a .NET se muere un gatito en el mundo, interesantisimo post que vale la pena leer pues resume muy bien los dilemas, actitudes,creencias erróneas y decisiones que se acometen cuando se tienen aplicaciones en Visual Basic 6 y se piensa el migrar a .Net como una opción a considerar.

Me detendré poco en el tema de la discusión de si migrar si o migrar no, pero en mi modesta opinión creo que los criterios de discusión deberían girar alrededor de (entre otras) estas preguntas:
– ¿Qué tan diferente son los procesos de negocio de la organización de como eran cuando la aplicación fue construida?
– ¿Son los algoritmos técnicos de las aplicaciones aun validos para los procesos de datos?
– ¿El esfuerzo de “entender” la aplicación actual y documentar la especificación de la nueva es mayor que el de la “simple” migración? (Cuando no queda nadie del equipo original)

Llegados a nuestro escenario “pues si, necesitamos migrar esa aplicación pues ya cada vez es mas difícil mantenerla y vamos a migrar de plataforma….. ” hay que plantearse las cosas de como acometerla, no tanto desde el punto de vista técnico, que para eso hay suficiente información en Internet, sino mas bien de cuales serian los pasos razonables para lograr el objetivo de una migración exitosa.

Con esas miras puestas, la experiencia que he tenido recientemente me llevan a plantear dos pequeñas metas antes de la migración en si:
– Reducir todo lo que se pueda la cantidad de lineas a migrar.
– Reducir y aislar los comportamientos críticos no migrables.

Cuando hablo de reducir la cantidad de lineas a migrar, parto del hecho de que es mas que probable que la aplicación a migrar hay sufrido modificaciones durante su tiempo de vida, lo cual haya ocasionado que métodos o clases que antes eran invocados se hayan convertido en código muerto, y reducir ese código muerto antes de la migración deberá ser uno de los principales objetivos que debamos de plantearnos, puesto que es preferible saber de antemano que código ya no es invocado (y eliminarlo/comentarlo) que matarnos en hacer que funcione para luego saber que … sorpresa.. sorpresa… era código muerto.

El tema de los comportamientos de lenguaje no migrables (“As any”, redimensionamiento de arrays …) es complicado, por lo que creo que es conveniente, en la medida de lo posible tomar las acciones para reducirlos antes de la migración y si eso no es posible marcar dicho código como problemático.

Ahora bien, estos son objetivos loables, pero lamentablemente difíciles de conseguir con las herramientas de Microsoft “out of the box”, que si que el Code Analysis de VS .Net nos facilitara el encontrar las referencias “muertas”, pero lamentablemente el tener una información completa de este tipo solo sera posible cuando el código migrado compile sin errores, pero claro… volvemos a lo mismo podemos pasarnoslas divertidos corrigiendo código para luego descubrir que ese código no era invocado en ningún lugar.

Entonces queda claro que el análisis de dependencias es critico, y lamentablemente no queda sino recurrir a herramientas de terceros, concretamente he estado probando Project Analyzer con resultados muy interesantes pues ademas de encontrarme con la opción de encontrar todo el código muerto, me detecto todos las porciones de código que requerían migración manual.

Así pues, creo que el contar con una herramienta de ese estilo (he mencionado Project Analyzer, pero igual podría ser alguna otra) cobra un importancia muy especial en esta clase de proyectos, ya que permite cubrir los dos primeros objetivos señalados y llevando de rebote una ventaja adicional: darnos cuenta, mediante el análisis de dependencias de que porciones de código no compatible como llamadas a la API de Windows, podrían ser reemplazadas por código .Net.

Ese análisis e identificación de codigo critico seria un primer paso, de ahí vendrían los siguientes:
– Refactorización, si, se puede, y nos ayudara a tener nuestro código heredado mas legible.
– Preconversión de código no migrable a código migrable, donde sea posible y se sepa que se seguirá usando luego de la migración.
– Migración en si, ya sea usando Visual Studio o una herramienta de terceros, y de ahí las sucesivas iteraciones para estabilizar el producto hasta el nivel deseado (reemplazo de ADO por ADO.Net, eliminación de los Interop….)

Es obvio que este proceso iterativo por lo que no conviene dar un paso nuevo hasta que no se sepa que la nueva versión sigue haciendo lo que hacia antes, de ahí la importancia de tratar de acometer la mayoría de los cambios posibles antes de la migración en si.

¿Qué le hubieramos pedido a un hipotetico VB 6.5?

Pues si, ya han pasado poco mas de 10 años en que .NET fue anunciado (recordemos que antes era llamado NGWS), por lo que ya tendría poco sentido hablar de su predecesor, pero la experiencia de volver a tener que lidiar con VB6 me ha hecho volver a reflexionar algunas cosas…

Primero situémonos en el contexto, VB6 fue lanzado durante 1998 he incluía mejoras como: ADO 2.0 (un enésimo santo grial en la unificación de los modelos de acceso a datos), WebClasses, mejoras en el soporte a COM e integración con MTS; con todo no fue un modelo rupturista y las empresas entusiastamente dieron el salto desde VB5 (versión que por primera vez libero a VB del p-code permitiendo compilar en modo nativo).

Todo bien excepto algunos detalles…. como la herencia, lo cual le hacia ser denostado como un lenguaje no totalmente orientado a objetos, palideciendo en ese sentido ante sus rivales: Delphi y Java. Admitamoslo, durante buen tiempo los fans de VB actuaron con la política de la zorra y las uvas, diciendo que la herencia no era totalmente necesaria, y pregonando la potencia de las interfaces para lograr el polimorfismo. Aun así Microsoft decidio explorar por el lado de una OOP sin las complicaciones del C++, y el resultado fue Visual J++ 6.0 el cual tuvo problemas con Sun, por lo que el producto no tuvo tanto éxito, aunque si que me he topado con un cliente en el cual había herencia de su uso.

Visto ese escenario, para principios del 2000 se rumoreaba sobre lo que seria el inminente ASP+ y el NGWS (Next Generation Windows Services), pero Microsoft sorprendió al mundo cuando en Julio anuncio a .NET, C# y el hecho de como el nuevo VB.Net seria un lenguaje totalmente orientado a objetos, luego vendrian las primeras versiones beta de Visual Studio .Net, sobre cuyo primer contacto ya me he explayado.

Como ya he comentado mi adaptación como desarrollador al nuevo entorno fue fácil, gracias a la base OOP proveída por Delphi, así como a las buenas practicas de los cursos de certificación, pero eso no impedia que mantuviera un ojo en los problemas que se iban a presentar en la transición de VB6 a VB.NET….

Estos cambios venian dados por dos lados: cambios en el lenguaje y cambios en el Framework (de COM a .NET) y ambos eran muy agresivos, tan asi que dos respetados gurues de la época dieron su explicación (muy acalorada por cierto) de porque VB.Net era un nuevo lenguaje (para ellos peor) y no una evolución de VB6:

Karl E. Peterson: VB Fred, A Marketeer’s Worst Nightmare
Bruce McKinney: The End of Hardcore Visual Basic

Sugiero dar un vistazo a esos artículos y a los enlaces ahí contenido para entender la magnitud de los cambios, y si bien luego las cosas no fueron tal como se pintaban en la beta, los cambios si que son muy rupturistas e intentar asumir una migración es algo de veras intimidante.

He realizado migraciones de aplicaciones .NET de la version 1.0 a 1.1 y de la 1.1 a la 2.0 y se puede decir que el camino es mas o menos controlado, pues el lenguaje siempre es compatible hacia atrás, y si bien el Framework evoluciona, dejando algunas tecnologías obsoletas (como Remoting) siempre se puede recompilar en una versión superior, siendo que los potenciales problemas están por el lado de:

– Dependencia de una librería de terceros, cayendo en esta categoría el Enterprise Library, el cual si que tuvo cambios que obligaban a modificar el codigo, problema no presentado en una libreria comercial como Dundas.
– Necesidad de apuntar a una plataforma especifica (como x64 o Itanium), lo cual sumado a lo anterior da para pruebas y comprobación de entornos.
– Alguna cosa que compile, pero que en ejecución falle, son pocas pero las hay, aunque siempre se pueden controlar añadiendo un mayor control de excepciones.
– Cambio de estructura de proyectos, como en el caso de los Servicios Windows, pero se soluciona creando el proyecto desde cero e inyectando progresivamente las clases y métodos necesarios.

En resumidas cuentas, un camino que puede ser mas o menos pesado dependiendo de cuan complejo sea el proyecto, pero en el cual siempre hay vías de hacer que la migración funcione.

Planteemoslo de otra manera, ¿para 2002 habían en producción aplicaciones en VB5 o VB4? Lo dudo sinceramente, el punto de quiebre fue VB5 y como comentaba la migración de VB5 a VB6 era totalmente transparente, salvo (como de costumbre) en la dependencia de algún control de terceros.

Osea, que para migrar dentro de versiones de VB.NET o de Visual Basic “clasico” los caminos han estado mas o menos marcados y eran controlables, pero… para migrar de VB6 a VB.Net… ahi es otra cosa.

Como mencionaba lineas arriba los cambios vinieron por dos frentes: cambios traumaticos en el lenguaje y reemplazo del framework basado en COM por uno basado en .NET. (los dos primeros capitulos de este libro pueden dar una vision de los cambios), si le sumas esto al hecho de que cuando Anders Hejlsberg acometio el desarrollo de .Net, decidió crear un nuevo lenguaje C#, e hizo muchos de los diseños del CLR y el CLI sin tomar en cuenta las particularidades (ya muy usadas por los desarrolladores) de VB, esta claro que lidiar con los cambios seria una tarea harto compleja, cito el libro arriba mencionado:

The Decision to Break Compatibility

When did Microsoft decide to break compatibility with Visual Basic 6? It was actually in early December 1999, during the development of Visual Basic .NET. Until that time, Visual Basic .NET was being developed to support the notion of “Visual Basic 6 sourced” projects that allowed you to edit and compile Visual Basic 6 projects in Visual Basic .NET. These projects would have a compatibility switch turned on, meaning that the language would be backward compatible with Visual Basic 6 and would even have access to the old Visual Basic 6 forms package.
By the end of 1999, it was obvious that this strategy wasn’t working.
Little differences were slipping through: The old forms package could not be fully integrated into .NET, and the Visual Basic 6 sourced projects could not use some of the new features of the .NET platform. At that point Microsoft made the decision to break compatibility and instead concentrate on ensuring that people could upgrade their projects from Visual Basic 6 to Visual Basic .NET.

En fin, es cierto que muchos cambios (de lenguaje) eran inevitables y demandados por la comunidad de desarrolladores: soporte de herencia, excepciones y threading, pero esta claro que Microsoft pudo haberlo hecho mejor en algunos aspectos (de hecho, parte de las criticas de los gurus arriba citados van por el lado de que algunos cambios no eran necesarios para hacer a VB un lenguaje OOP) como la gestión de los arrays, no forzando a tener que hacerlos basados-en-zero y si por el contrario permitir que su gestión de limites sea equivalente a la de VB6.

Entonces esa es la situación a la que llegamos cuando sale al mercado Visual Studio .Net 1.0, el gap del Framework y el lenguaje es tan grande que solo proyectos triviales son susceptibles de ser migrados a .NET, para lo demás muchas veces es mejor hacer el proyecto desde 0, o sino… seguir manteniendo y parchando el código en VB6 hasta que se decida tomar la decisión de migrar (pues ya se sabe lo que dicen las gerencias “Si funciona ¿para que tocarlo?”, claro, es así como el COBOL no muere). La dura realidad es esa, que las organizaciones se han quedado con un parque de aplicaciones para un lenguaje/plataforma que ya no evoluciona y si bien ahora se cuenta con una buena herramienta como el Artinsoft Visual Basic Upgrade Companion, la verdad es que en todo proyecto complejo nos toparemos con situaciones como estas:

– Las inevitables llamadas a la API de Win32, ya no funcionan, y no hay forma directa de hacer un cambio que permitan la recompilacion.
– A revisar todos tus arrays para estar seguro de su comportamiento.
– Replantearte como gestiona el ciclo de vida de tus objetos.
– Los controles y clases tienen otras propiedades, no hay equivalente directo en .NET para algunas clases de terceros y la importación (wrapping) no siempre es segura.

Previo al lanzamiento de VS.Net, algunos articulistas pedían que saliera una ultima versión de VB basada en COM que facilitara la transición y/o introdujera algunas mejoras a VB6, la verdad es que mire de lejos esas peticiones, claro… estaba entusiasmado por el giro a OOP que no mire la complejidad que estoy narrando, pero ahora luego de estos 10 años de .Net (contando desde su primer anuncio y Beta) creo que si que Microsoft debió intentarlo y proveer esa herramienta a fines del 2000 o principios del 2001 a fin de que hubiera un punto intermedio en el camino desde VB6 hacia .Net, lo cual me lleva a la pregunta planteada como titulo de este post….

Personalmente yo hubiera excluido la herencia como caracteristica de un VB 6.5, implementarlo es complejo y el problema radica en como gestionar caracteristicas usadas en las aplicaciones hechas en VB 6 para que funcionen luego en .NET, siendo asi, VB 6.5 debería haber tenido (como anticipo al cambio en .Net):

– Soporte dual para arrays con limites libres y basados-en-zero. Si MS seguia terco en lo de no permitir los limites libres, la compilación debería permitirlo pero indicar que esa característica estaba “deprecada” y no soportada en futuras versiones.
– Fin de las propiedades por defecto de los objetos.
– Eliminación del tipo Variant.
– Cambio en el ámbito de la visibilidad de las variables.
– Uso obligado de paréntesis en las subrutinas.
– Ofrecer un mecanismo de llamadas a la API Win32 cercano al uso que luego tendria DLLImport, pero respetando (temporalmente) la mayoría de los hacks que se tuvieron que hacer para trabajar con dicha API.
– Opcional: soporte para try..catch..finally
– Únicos cambios en el IDE: Encontrar todas las referencias, herramienta imprescindible ahora para una adecuada inspección del código, y un compilador que devuelva una lista de errores y no uno por uno.

La idea de esto seria que los desarrolladores acometieran ciertos cambios sin retorno, sin todavía decirle adiós a COM, para de esta manera tener hechos los deberes en el grueso del lenguaje, quedando (en teoría) cambios menores en el lenguaje y “solo” adaptarse al .Net Framework.

Si Microsoft hubiera hecho esto, a estas altura no habria esas aplicaciones en VB6 que se resisten a morir, haciendo a VB6 el nuevo COBOL, pues eso es lo que esta pasando… un nicho de aplicaciones que persisten mas alla de su ciclo de vida.

Y tu ¿que característica le hubieras puesto a un VB 6.5 todavía basado en COM?.

¿Los nuevos patrones ayudan a la mantenibilidad de aplicaciones?

Si tuviera que decir que funcionalidad del Visual Studio (y de VB6 ya puestos) he estado usando mas ultimante, la respuesta seria “Go to Definition” (seguida de “Find All References”).

La razón de esto es debido a que ahora me corresponde estar en mantenimiento de aplicaciones, lo cual implica que cuando hay un error tratar de encontrar que metodo o clase fallo y ver que hacer para solucionar el error, y en otras ocasiones añadirle una funcionalidad a cualquiera de las aplicaciones ya existentes (en cuya creación yo no intervine).

Como ya explique anteriormente esta es una situación en la que no se empieza de cero, y se requiere tratar de entender de manera rápida el como esta montado todo a fin de encontrar la raiz del problema, por lo cual usualmente tengo dos caminos:

– Ubicar la aplicación e ir haciendo una “depuración sin ejecutar” mediante el “Go to definition” tratando de ubicar los puntos de paso críticos que hay durante la cascada de llamadas de los sucesivos métodos involucrados en la funcionalidad.
– Buscar el texto con el mensaje de error reportado, y de esa manera mediante el “Find all references” identificar de abajo hacia arriba la posible pila de llamadas y en el camino encontrar lo que ocasiono el problema.

Pero llegados a este punto vemos que se ha incrementado la demanda por desacoplamiento y pruebas unitariasdentro de nuestros codigos, todo como parte de los patrones SOLID:

* SRP: The Single Responsibility Principle (Principio de Responsabilidad Única)
* OCP: The Open/Closed Principle (Principio Abierto / Cerrado)
* LSP: The Liskov Substitution Principle (Principio de Sustitución de Liskov)
* ISP: Interface Segregation Principle (Principio de Segregación de Interfaces)
* DIP: The Dependency Inversion Principle (Principio de Inversión de Dependencias)

Principios muy interesantes, que valen la pena revisar, pero que introducen tendencias como la Inyección de Dependencias y la Inversión de Control, para lo cual recomiendo este muy bien explicado articulo de Gisela Torres de donde extraigo esta explicacion;

Generalmente, cuando tenemos una clase que depende de otras para ciertas acciones, necesitamos inicializar instancias de las mismas para poder utilizarlas posteriormente. En ocasiones, una de las alternativas puede ser crear un objeto de dichas clases de forma privada e inicializarlas, utilizando el constructor de la clase principal.

Si vemos estas acciones desde el punto de vista de la Inyección de Dependencias y la Inversión de Control, no sería la forma más óptima debido a que la clase que sufre estas dependencias no debería ser la responsable de la creación de las mismas.

¿QUÉ CONSEGUIMOS?

  • Desacoplamiento.
  • Mejora la posibilidad de testeo de la aplicación.
  • Mejor mantenimiento a la hora de realizar cambios de los componentes, gracias a la modularidad.
  • […]

Ambos conceptos están tan ligados que, en ocasiones, no se hace distinción. Se utiliza el concepto Inversión de Control para delegar en otro componente, un framework por ejemplo, la responsabilidad de crear las instancias necesarias en lugar de crearlas nosotros mismos. Por otro lado, la Inyección de Dependencias es el término utilizado cuando una clase depende de otra y, a través del constructor generalmente acepta un parámetro del tipo del cual depende. 

Siguiendo el ejemplo, podemos ver que en lugar de el tradicional mecanismo de instanciación de la clase que necesitamos, por detras existe un interesante mecanismo de Configuración y Factoria de Objetos que nos permiten que en lugar de:
public class HomeController : Controller
{
private readonly ITwitterService _twitterService;
public HomeController()
{
_twitterService = new TwitterService();
}

public ActionResult Index()
{
return View(_twitterService.FetchTweets());
}
}

Tengamos:
public class HomeController : Controller
{
private readonly ITwitterService _twitterService;

public HomeController(ITwitterService twitterService)
{
_twitterService = twitterService;
}

public ActionResult Index()
{
return View(_twitterService.FetchTweets());
}
}

Nada mal según parece, usamos interfaces, y se logra una mayor facilidad para pruebas unitarias, lo cual es uno de los objetivos a lograr, pero oh sorpresa… si ahora le hacemos “Go To Definition” al FetchTweets notaremos que ya no vamos a la implementación del método en cuestión (definido en la clase TwitterService), sino al cuerpo de la Interfaz ITwitterService, lo cual detendría nuestra búsqueda en cascada, al no tener mucha idea de cual es la implementación real que se esta invocando, por lo cual nos quedan dos potenciales soluciones:

– Correr la aplicación y en tiempo de ejecución ver la implementación real para así tomar las medidas de análisis necesarias a fin de resolver el problema.
– Tratar de entender la configuración de las dependencias y así inferir cual es la clase que se esperaba instanciar.

Como se comprenderá esta circunstancia puede hacer complicado una tarea de mantenimiento, y la idea de que esas tendencias pueden significar un problema, no en el tiempo de desarrollo, sino en posteriores mantenimientos me han dado vueltas en la cabeza durante un buen tiempo, hasta que encontré este interesante articulo, del cual cito y traduzco:

Yo lo he experimentado de primera mano, en muchos diferentes proyectos donde he tenido que hacerme cargo de codigo despues de que un desarrollador dejo la compañia, y puede ser una experiencia exasperante. Una mejora es solicitada, o un bug es reportado, digamos que se trata de un bug. Se me puede haber dado una excepcion en la pila, y eso al menos me lleva al codigo fuente en donde empezar. Lo que usualmente encuentro es un bonito set de pruebas unitarias que puedo correr y comprobar que todas se ejecutan correctamente, lo cual no es una gran sorpresa; pero, todos los tests usan “mocks” por lo que no puedo reproducir inmediatamente el bug como no sea escribiendo un lindo mock test para simular como el código debería responder ante un particular error de entrada, puesto que yo puedo “mockear” facilmente el error. Eso esta bien, pero no es util si mi objetivo principal es evitar que el error ocurra.

¿Que clase en concreto es la responsable del bug? Aqui es donde se pone complicado, en la mayoria de los casos, la pila no te da ninguna pista. Leer el codigo y examinar la configuración puede ser una enorme perdida de tiempo y termina siendo una tediosa búsqueda en amplitud.

Como el autor apunta “la capacidad para obtener información rápidamente y entender un programa al leer el código es degradada por IoC debido al desacoplamiento”, y así.. esa seria la alerta con la que nos deberíamos quedar, ver cual es el lugar de estos patrones, y si la búsqueda de objetivos en este momento como el desacoplamiento y las pruebas unitarias, no vendrían a significar un lastre en el largo plazo, cuando la aplicación tenga que ser mantenida por un equipo diferente.

El paso por mantenimiento de aplicaciones te hace tener en cuenta estas otras consideraciones.

Otro articulo interesante:
Dependency Injection makes code unintelligible

No siempre empezaras desde cero

Como desarrolladores generalmente esperamos estar desde el arranque de un proyecto, con la idea de que asi “esta vez hacer las cosas bien” usando una buena arquitectura y claro, con lo ultimo de la tecnología, al final terminamos llegando al estado de “parecia una buena idea en su momento” y que hay que terminar el proyecto “como sea”, bueno… exagero un poco, pero debe quedar claro que estar en el proyecto desde un inicio no es una garantia para que todo vaya como una seda todo el tiempo.

Pero para bien o para mal, si uno es un desarrollador “desde las trincheras” y no un “guru”, no sera rara la situación en que nos veamos en la necesidad de dar mantenimiento a un programa que alguien mas haya hecho o empezado (en cualquier grado de avance), y ahí es donde empieza nuestra historia…..

Antes de proseguir, debo decir que cuando he estado una buena temporada en un proyecto, trato de pensar (sobre todo en las ultimas etapas) en “como hacerle mas simple la vida al pobre tipo que se hara cargo de esto” para lo cual opto por un enfoque realista, dejar comentarios en las secciones de código que se que pueden ser mas crípticas, y de ser el caso dejar documentación útil, ¿y cuando una documentación es útil? ¿no se supone que lo útil es documentar todo lo posible? ¡Error! una documentación es util cuando uno honestamente sabe que leyéndola proveerá una idea para entender la lógica detras de la implementación de un código.

Entonces como decia, nos encontramos en la situación de que hay una aplicación existente, en cuya creación no hemos intervenido, y se nos pide ver porque ha dejado de funcionar o que le agreguemos una nueva funcionalidad, la documentación es escasa y con suerte tenemos las referencias de los servidores involucrados.

Asi que con esta premisa vamos tras el codigo fuente a ver que podemos sacar en claro (*), con lo que nuestra rutina es mas o menos como sigue:
– Ubicar el punto de entrada de la aplicacion, o sino, los controles y sus eventos respectivos que desencadenan la accion a investigar.
– Ubicado el punto de entrada o el evento deseado (capa de Interfaz de Usuario), ir viendo como se van creando las sucesivas instancias de las capas de Negocio, Fachada, Datos y los métodos involucrados.
– De ser necesario ir depurando para evaluar los valores que van tomando las variables criticas…

En fin, este es el mundo real y creo que alguna vez todos habremos pasado por este lió, siendo nuestros dilemas el saber a que clase/metodo se esta invocando desde un punto del código, así que me he sentido afortunado cuando he podido hacerme una idea del código usando las herramientas para encontrar la “Definicion” de un método invocado.

Es que así es el código típico:

– Método f1 de la clase A necesita llamar al método f2b de la Clase D.
– Método f1 instancia un objeto “miD” de la Clase D.
– Método f1 ejecuta el método miD.f2b.
– Método f2b de la clase D necesita……

Si el código esta mas o menos estructurado (y no es un spagetti por supuesto), esa es la lógica que uno busca, con las debidas excepciones de cuando se tienen que ejecutar instancias remotas y/o usando Interfaces en vez de clases directas.

Una de las cosas que tienen de bueno los entornos RAD como Delphi y .NET (WebForms y Winforms) es que brindan un mecanismo comprensible para empezar a depurar, sabes el control y quieres ver que hace, pues entonces… a ver los eventos vinculados y de ahi para adelante, de capa en capa. Quienes hemos trabajado con ASP Clasico recordamos la pesadilla que eran los puntos de entrada de las paginas, revisando todas las posibles combinaciones de parametros que venia en el Request razon por la que la introducción de WebForms fue la respuesta a nuestros problemas, y para mi lo sigue siendo.

Pero la evolución del desarrollo de software es imparable, y asi hemos visto como han surgido tendencias que han procurado añadir valor a nuestros ciclos de desarrollo como: WebServices, Refactorizacion, SOA y varios intentos de mecanismos para construir una arquitectura distribuida: DCOM, COM+, .Net Remoting, WCF….

Pero al margen de como vayan evolucionando las tendencias, una cosa que siempre procuro en mis desarrollos, es dejar el camino mas o menos despejado para que el que venga luego pueda entender el código que esta leyendo, procurando tener las inevitables sofisticaciones bajo control. Teniendo esto en cuenta… cabe preguntarse si tendencias como el “desacoplamiento” y la necesidad de “pruebas unitarias” facilitan o no la vida del que luego tiene que enfrentarse a mantener tu código, pero ese análisis lo dejo para un posterior post.

De momento quiero dejar la reflexión de que a veces estamos tentados a emplear unos patrones novedosos, potentes, pero… también debemos pensar que no todos los desarrolladores siempre desarrollan desde cero, que se llega a proyectos ya empezados, a código terminado en producción que hay que mantener, y que no hay que complicarle la vida en aras de lucirte con lo mas novedoso en metodologias y arquitecturas si es que no es de veras necesario, ya que estas no solo deben prometerte mas facilidades para ti, si no para el que luego tendra que mantener tu codigo.

(*)Aunque alguna vez no contamos ni siquiera con el código fuente, como me paso en un cliente hace 3 años, por lo que toca ver si podemos desensamblar el código, pero eso ya es otra historia y mas bien un extremo de irresponsabilidad por parte del cliente.