Merges un poco más inteligentes para C#

Las operaciones de merge son muy comunes en los sistemas de control de versiones distribuidos, y si hay muchos cambios a nivel de pocos ficheros (equipos trabajando en una misma funcionalidad) podemos tener muchos conflictos. Para ayudar a mejorar la productividad en estas operaciones ayer hemos anunciado la disponibilidad a todo el público de la beta de SemanticMerge.

La idea es simplificar la resolución del conflicto entendiendo el código, resolviendo de manera automática aquellos en los que sea posible y permitir al usuario, de manera sencilla, encargarse de los conflictos restantes. En este artículo veremos de un vistazo la herramienta sus características, los casos que cubrimos y cómo la hemos desarrollado.

Una interfaz sencilla

La herramienta, formada básicamente por un panel donde se muestran los conflictos y diferencias, y un visor de código, permite por una parte resolver conflictos, y por otra ver en detalle los cambios sucedidos en cada fichero respecto a la base.

Para ayudar al usuario, cada conflicto tiene, en la cabecera, un campo identificado por una letra y un color por cada cambio que lleven al conflicto, en el ejemplo, un cambio concurrente en un método.

Semantic Merge tool

La magia

Para poder mostrar estos conflictos y resolver de manera automática aquellos en los que sea posible, analizamos los ficheros que el usuario nos pasa por parámetros, o a través de la pantalla inicial, si iniciamos sin parámetros (origen, destino y base).

Una vez hemos leído los ficheros y comprobado que no haya errores de análisis, creamos, para cada uno, un árbol semántico, similar a la ventana de clases que se puede ver en Visual Studio.

Semantic tree

Ya con estos árboles, comparamos el origen y el destino con la base para obtener lo que denominamos un árbol de diferencias. Finalmente comparamos estos árboles de diferencias para obtener los posibles conflictos y las diferentes formas de solucionarlos.

Escenarios

Hemos empleado cientos de horas de análisis, y procesado millones de repositorios para obtener las operacions y los conflictos más comunes, entre los que destacan:

  • Movidos divergentes: Si estamos haciendo refactor de nuestro código y movemos a diferentes partes del mismo (desarrollador A los prefiere por orden alfabético y desarrollador B los prefiere por orden de scope) detectamos el cambio y damos al usuario la opción de elegir.
  • Movidos/borrados: En caso de que un elemento (método, clase…) se haya movido en origen y se haya borrado en destino, lo detectamos y damos al usuario la opción de conservar el movido o el borrado.
  • Movidos + cambiados: En el caso de que un desarrollador mueva un método a otra clase y otro realice cambios en el mismo, se detectará automáticamente, y no habrá conflicto :)

Hay mucho más, disponible en semanticmerge.com

Integración

De momento, tenemos tutoriales sobre cómo integrarlo en Git, PlasticSCM, TFS y Perforce, y pronto deberíamos tener para Mercurial y SVN. Si usas otro sistema de control de versiones, avísanos!

Personalización

Mediante los parámetros de entrada, podemos especificar una herramienta de diff y merge personalizada, a través de los parámetros -emt y -edt de entrada. Además se puede especificar el tipo de fichero que estamos procesando aunque no tenga la extensión adecuada mediante el parámetro -t. En estos momentos el único lenguaje de programación soportado es C#, así que en este caso el único valor válido será text/csharp.

One more thing: Diferencias semánticas

Otra de las cosas que incorporamos es una herramienta de diff, que dados dos ficheros nos permite obtener las diferencias entre ellos.

difftool-included

Cómo se hizo

Aunque la idea ha estado en fase de análisis y diseño varios años, el desarrollo principal del proyecto se ha llevado a cabo en los úitimos 6 meses, en el que una buena parte del equipo de Códice ha estado implicada. Hemos estado divididos en dos grupos, uno encargado de las operaciones de merge y del backend de la herramienta, y otro grupo, que hemos estado cubriendo el diseño y la usabilidad de la herramienta.

Además, llevamos varias semanas usando la herramienta como herramienta de merge por defecto de manera interna, y las primeras betas privadas que distribuimos han tenido una acogida muy buena por parte de los voluntarios.

Bajo el capó

El lenguaje usado para todo el desarrollo de la app es C#, de ahí nuestro interés con que sea el primer lenguaje de programación soportado (llevamos semanas probando la herramienta a nivel interno).

La interfaz está desarrollada en WPF con algunos toques de Windows Forms, y para la ventana sin marco usamos la integración con Windows a través de Windows.Shell.

Las herramientas utilizadas han sido PlasticSCM como control de versiones, Visual Studio 2010 – 2012 como entorno de desarrollo y Blend 4 como herramienta de diseño de interfaces,

Pasos adicionales

Estamos en fase beta, con lo cual hay muchas cosas que pulir, además seguimos trabajando en mejorar la herramienta, la usabilidad, el diseño, la velocidad, así como el soporte para lenguajes adicionales y escenarios más complejos. Para ello hemos habilitado un portal en uservoice para recibir feedback de nuestros usuarios.

Presentamos GitSync: Ahora PlasticSCM habla Git

index

En Códice Software desarrollamos Plastic SCM, un sistema de control de versiones enfocado a un entorno corporativo, que comparte filosofía con sistemas como Git o Mercurial, al ser un sistema pensado para su uso de manera distribuida.

A diferencia de estos, contamos con una serie de características dirigidas a entornos corporativos, por ello, nos adaptamos a sus infraestructuras integrándonos con mecanismos de autenticación existentes como LDAP o Active Directory, así como los diferentes sistemas de bases de datos disponibles, desde soluciones embebidas como Firebird o SQL CE, hasta soluciones basadas en Oracle. Además tenemos nuestra propia capa de seguridad a nivel de repositorio, rama o servidor, de tal manera que se pueden aplicar permisos específicos a diferentes roles de usuarios (por ejemplo, la rama de integración solamente la pueden tocar los chicos de Dev-Ops).

Además contamos con una interfaz muy limpia, elegante y completa, así como integración con entornos como Visual Studio, Eclipse o InteliJ IDEA.

Siempre intentamos ir un paso más allá, y es por eso que presentamos GitSync, un sistema por el cual se puede sincronizar un servidor de Plastic SCM con un servidor remoto de git. Esto nos permite compartir con otros desarrolladores que usen git para trabajar, subir nuestro código a sistemas como Github o Bitbucket, y aprovechar servicios que son compatibles con Git, como es el caso de Heroku, AppHarbor o, recientemente, Windows Azure.

Esta sincronización es bidireccional, y continua, no se trata de un importador/exportador (aunque eso, también lo hacemos). Sincronizamos todo el repositorio: ramas, changesets y etiquetas

En estos momentos estamos en fase de beta privada, a la que se puede acceder en este enlace. Valoramos mucho el feedback de nuestros usuarios, y por ello regalamos un iPhone 5 a aquellos que nos ayuden a mejorar nuestra herramienta. Quieres el tuyo?

Qué es un test exploratorio y por qué nos hace falta

El pasado lunes tuve la ocasión de asistir a una charla sobre tests exploratorios, una manera diferente de probar el funcionamiento de nuestras aplicaciones. La charla fue impartida por Luis Rodriguez nuestro Release Manager en Plastic SCM.

Cuando desarrollamos software estamos acostumbrados a hacer pruebas unitarias de clases, de integración entre componentes, y de aceptación con el cliente. Los test exploratorios, pese a ser menos conocidos, resultan tremendamente útiles ya que permiten, usando la intuición y la experiencia acumulada de la persona que realiza la función de tester, encontrar nuevos errores y escenarios que no saldrían a la luz en test automatizados.

Cuenta de 3 componentes específicos:

  • Charter: Contiene la definición del test. Qué es lo que se pretende probar durante el tiempo de pruebas.
  • Session test: El tiempo dedicado a la prueba. No se recomienda que sea de más de 3 horas.
  • Informe: Qué se ha probado, qué se ha encontrado, y cómo reproducir fallos.

Charter

La clave es «debe caber en un post-it«. Debe ser lo suficientemente específico como para poder ser probado (Mal ejemplo: Probar todo el sistema) así como suficientemente amplio como para que vaya más allá de un test automático (Mal ejemplo: Probar a introducir letras en un campo «Código postal»).

Session test

Como se ha comentado anteriormente, se recomienda reservar un espacio de tiempo no mayor que 3 horas. Se pueden emplear varias estrategias para planificar los test:

  • Exploración analítica: Partiendo de diferentes estados y eventos del sistema, se obtienen las posibles variaciones, y será aquello que pruebe.
  • Atención al detalle: Usar los logs para comprobar el rendimiento del sistema, así como comprobar las métricas (CPU, disco duro, RAM…) permitirá saber no solo si el programa funciona, sino cómo afecta al equipo
  • Asumir roles de usuario: Ya que existen diferentes roles, el novato, el experimentado, el impaciente o el hacker, entre otros. Cada rol verá nuestro programa de diferente manera.

Es importante destacar que este test está planificado, es decir, no es dedicarse durante 3 horas a recorrer aleatoriamente el sistema, sino que, basándonos en el charter, debemos pensar (y planificar) qué queremos probar, para que luego sea más fácil dejarlo por escrito en el informe.

Informe

Finalmente se redacta un informe con la información del sistema y el tiempo dedicado a cada una de las pruebas, los resultados de las mismas, y recomendaciones adicionales. Permite además encontrar escenarios que se puedan automatizar.

Conclusiones

Los beneficios de los test exploratorios se pueden resumir en más bugs encontrados, un mayor análisis en profundidad y más áreas cubiertas, aunque para poder aprovecharlo al máximo se requiere un perfil lo más creativo posible, ya que la persona debe pensar en escenarios probables y difíciles.

DVCS: La herramienta definitiva para un hackathon

Un hackaton es un evento social donde programadores y diseñadores compiten en grupos durante 24 – 48h en el desarrollo de la mejor aplicación para la plataforma elegida por los organizadores. En este tipo de eventos el tiempo es un factor clave, y la posibilidad de que un error en los últimos 5 minutos destroce horas de desarrollo es muy alta, ya que se viven momentos de muchísima tensión.

En estos casos es útil contar con un sistema de control de versiones para poder tener un registro de la evolución del proyecto, y evitar perder el rumbo original.

En el último Hackatón al que asistí hace unos días pude experimentar la frustración de grupos que usaban Team Foundation Services Preview, un sistema de control de versiones centralizado y en la nube. Es una herramienta muy potente para gestión de código fuente aunque muestra algunas debilidades para este escenario en concreto:

  • Necesita una conexión a internet estable y constante, ya que de otra manera no se puede realizar un check-in ni un checkout, y cada operación añade una carga adicional a la red.
  • Es centralizado, con lo cual cada vez que se hace un check-in se integra todo el código, y si había cambios en el servidor es necesario obtener primero la última revisión y luego integrarlo en local (manejando posibles conflictos, por supuesto) antes de poder enviar los cambios de vuelta, perdiendo ese preciado tiempo del que no se dispone.

Todo esto hace que se emplee el repositorio como una herramienta de sincronización, no como un control real de las versiones del código.

Veamos el mismo escenario con un sistema de control de versiones distribuido (DVCS):

  • Cada miembro del equipo puede desarrollar su código de manera independiente en una rama, y hacer commits frecuentes asegurando un mejor historial.
  • El resto de los miembros del equipo pueden replicar los cambios usando la red local, sin que sea necesario usar el ancho de banda, ni servidores externos.
  • Se puede controlar que otros equipos en la misma red no accedan al código, aunque compartan conexión a internet, mediante listas de control de acceso (ACL).
  • Las operaciones de merge son menos constantes, al hacer integración de componentes terminados, evitando riesgos de introducir errores de regresión. Además con tecnologías como Xmerge se puede detectar código refactorizado e integrar de una manera más sencilla.
  • Se pueden integrar los cambios en una rama principal sin que ello afecte al desarrollo del proyecto (una persona puede dedicarse a esa tarea, aunque no es necesario que lo haga de manera exclusiva).

PlasticSCM permite todas las características comentadas anteriormente y más, aunque hay otras herramientas como Git o Mercurial disponibles en el mercado.

Cuando el desarrollo es ágil (nada más ágil que un evento de esta magnitud) tener las herramientas adecuadas puede ser la diferencia entre una aplicación buena y una espectacular.

Para la próxima hackatón, te propongo usar un DVCS, y si escoges PlasticSCM, puedes dejar críticas y sugerencias en los comentarios.

Más información: