Jan 09

“Duck Typing”

En un lenguaje fuertemente tipado y orientado a objetos, se comprueban las clases de los objetos antes de asignarlos a variables, de forma que sólo se pueden asignar a una variable objetos que son de la misma clase que la variable o hijas de la misma. Por ejemplo, si la clase Hija herada de la clase Padre, se puede hacer esto

Padre p = new Hija();

Una vez hecho, sólo pueden llamarse a métodos o atributos que estén declarados en la clase Padre. Si Padre tiene metodo1() e hija tiene metodo2(), sólo podemos hacer p.metodo1(), mientras que p.metodo2() dará error. Todo esto da sentido a cosas como las interfaces, definiendo a priori que métodos necesitan tener las clases hijas para que luego estas lo implementen.

Hay otros lenguajes, como javascript, que usan lo que se llama "Duck typing" o como lo traduzco yo "tipado tipo pato". La idea básica de este tipado es que si algo anda como un pato, grazna como un pato y nada como un pato, pues entonces es un pato. Los lenguajes que usan este tipado no miran los tipos ni las herencias de los objetos, simplemente permiten asignar cualquier cosa a cualquier variable. De esta forma, podemos hacer

p = new Hija();

y luego llamar tranquilamente a p.metodo1() o p.metodo2(), pero también podemos hacer

p = new Padre();

y llamar a p.metodo1(), dando error p.metodo2(). Es decir, no importa el tipo, el error saltará a la hora de hacer la llamada si "el pato no es capaz de granzar".

 

Dec 20

KanbanFlow

 Hace unos días descubrí una herramienta online que me ha encantado, KanbanFlow.

Te registras gratuitamente y tienes la posibilidad de crear tableros Kanban. Lo que me ha gustado es la sencillez de uso, pero con bastantes posibilidades de configuración. Puedes crear varios tableros, indicar qué columnas tiene cada tablero, crear etiquetas de colores y simplemente arrastrarlas de una columna a otra, en fin, todo lo que se espera de un tablero. Puedes añadir subtareas, que no serían más que una lista de "checks" dentro de una etiqueta. Lleva además un cronómetro de pomodoro con el que podemos guardar tiempos de trabajo en las tareas.

La versión gratuita en principio permite crear cualquier número de tableros y compartirlos con cualquier número de usuarios. La versión de pago principalmente permite asignar roles a los usuarios, exportar a ficheros pdf, csv, etc, llevar histórico de las tareas y tiempos, …

Otro detalle es que la gente que está trabajando en esto parece estar pendiente del asunto. Puse una pequeña petición en su página de ayuda y soporte y aunque me la negaron, tardaron en contestar una o dos horas.

Oct 25

He leído “OpenLayers 2.10 Beginner’s Guide”

http://blog.sonxurxo.com/wp-content/uploads/2011/03/openlayers-beginners-guide.pngAcabo de leer OpenLayers 2.10 Beginner’s Guide 

OpenLayers es una librería javascript que nos permite hacer aplicaciones con mapas en nuestra página web. Los mapas pueden ser los de Google Maps, Bing, OpenStreetMap o servidor por cualquier servidor que cumpla los estándares OGC, como Geoserver. OpenLayers "traga" además otro montón de formatos para dibujar mapas directamente de ficheros.

El libro es muy básico, empieza desde el principio, tan desde el principio que incluso nos explica lo básico de javascript y qué son las clases, la herencia, los métodos y atributos. Por supuesto, no se entretiene demasiado en ello, una simple explicación para no pillarse los dedos según va avanzando en OpenLayers.

Si, como yo, has empezado con OpenLayers a base de ensayo y error, copy-paste de código en google y ya tienes algo de experiencia, este libro es muy básico, pero siempre acalara algún concepto que puedes no haber "pillado" en tus pruebas, ensayos, errores, copies y pastes.

Es ideal sin embargo para leer antes de empezar con OpenLayers, el libro va despacio, no es muy complejo lo que explica y va asentando bases antes de seguir. Cada apartado resulta un poco repetitivo porque primero te explica cómo funciona, luego te lo vuelve a explicar mientras te dice cómo codificarlo y finalmente te lo vuelve a explicar añadiendo un título "¿Qué acaba de pasar?" después de que hayas ejecutado el ejemplo que acabas de codificar. Lo dicho, ideal para quien no tiene idea del tema y le gusta asentar bien las cosas.

 

Sep 29

Metodologías ágiles y entregas frecuentes.

En la metodologías ágiles, Scrum por ejemplo, es típico que se hable de entregas al cliente frecuentes, con algo que les sea útil y donde puedan ir viendo los progresos. Últimamente, estoy pensando si eso es o no posible en todos los proyectos. ¿Por qué? Porque en el proyecto que estoy ahora es claramente posible y así lo estoy haciendo, pero eso me ha hecho darme cuenta que en los proyectos anteriores no solo no es tan fácil, sino que posiblemente es poco menos que imposible.

Los proyectos en los que ando actualmente, ya casi desde hace dos años, son proyectos web. Y cada proyecto lleva dos o como mucho tres desarrolladores y se hacen en unos meses, menos de un año, cada uno de ellos. En estas condiciones es fácil hacer entregas frecuentes. Tu proyecto solo lleva software y está público en internet. Así que haces un pequeño desarrollo de un par de semanas, aunque sólo sea el login, o la página principal con un poco de funcionalidad, la subes al servidor, se lo dices al cliente y ellos prueban y dan su opinión. Y repites el proceso cada 15 días o así añadiendo cada vez un poco más de funcionalidad, siguiendo las indicaciones de tu cliente.

¿Y cómo eran los proyectos de antes?. Pues bien, el proyecto más gordo en el que estaba metido era un proyecto en el que había varios departamentos implicados, de software, de hardware, de montaje (hierros, tornillos y cables), etc, etc. En unos camiones suministrados por el ciiente (unos 10 camiones), se montan varios equipos hardware, unos comprados como GPSs, estaciones solaris, PCs con Windows, receptores de radio, .. otros diseñados y fabricados específicamente para el proyecto, bien a otras empresas, bien a otro departamento, como radiogoniómetros o exploradores de frecuencia, … y se hace mucho, pero que mucho software, para controlar todo eso y presentar datos decentes a los usuarios en cada camión. Desgraciadamente, en semejante entorno, el software es lo que menos se nota. Por mucho software en varios lenguajes (Ada, Java y C++ sobre Windows y Solaris) que lleve el sistema, siempre llama más la atención 10 camiones, repletitos de equipos en su interior y con varias antenas gigantes en su exterior.

¿Cómo hacer entregas frecuentes y funcionales al cliente en este entorno?. Teniendo en cuenta que el hardware tarda lo que tarda en llegar, que los camiones no se nos entregan hasta que hay suficiente hardware como para empezar el montaje físico y que la mayor parte importante del software no se puede integrar hasta que están los equipos físicos…. la única opción es hacer simuladores de todo y hacer "demos" más o menos frecuentemente, que el cliente vea la interfaz de usuario, la pinta que tiene, qué datos va a presentar y cómo, como se va a manejar, …. pero todo con datos simulados. Y cuando llega el tiempo de integrar realmente con los equipos hardware verdaderos y ver cómo los ejecutables que corren en los diferentes camiones se comunican entre ellos, os aseguro que es un verdadero infierno, cualquier bug puede ser debido a cualquier cosa, desde un cable mal conectado, pasando por un equipo que no funciona correctamente hasta, por supuesto, un bug en el software.

¿Y cómo haces test automáticos de todo esto? Sí, se pueden hacer test automáticos de las "chorradas", como que si un usuario introduce mal su password no se le deja entrar en el sistema, típico ejemplo de cualquier manual ágil, pero no se puede probar de forma automática y fácilmente que si dos radiogoniómetros en camiones distintos detectan un emisor de radio y se triangula su posición, aparece dibujado en el mapa de  un tercer camión (de hecho, tiene que aparecer dibujado en el mapa de todos los demás camiones). Un test automático de todo esto, eliminado el hardware y sustituyéndolo por simuladores, implica arrancar al menos tres ejecutables (uno por camión), más los simuladores si son ejecutables sueltos ya que simulan un equipo hardware, y verficar que en un mapa (o en la base de datos que hay detrás del mapa) aparece el emisor de radio detectado en la posición correcta.

Estoy mucho más de acuerdo con la filosofía ágil que con la tradicional, pero no existe la llave inglesa universal que vale para todo tipo de tuercas y  tornillos simultáneamente. Si es posible aplicarla, adelante, y si no es posible, hay que hacer lo que se pueda intentando conseguir lo mejor de ella.

Sep 20

He leído “Test Driven: TDD and Acceptance TDD for Java Developers”

tdd acceptance testBueno, realmente exagero un poco cuando digo "he leído…", me he dejado sin leer los últimos capítulos.

La parte central del libro me ha encantado, pero la primera parte y la última me han resultado muy pesadas e inútiles, hasta el punto de dejar de leerlo en esa última parte.

Los primeros capítulos nos cuenta principalmente las ventajas de TDD, no se extiende mucho en qué es o cómo se hace TDD, sino que se extiende mucho (muchísimos) en sus ventajas. Estas ventajas son más o menos conocidas por todos (código con menos fallos, confianza en que no estropeamos nada a la hora de hacer refactoring por lo que nos cuesta menos hacerlo, etc, etc). Por ello, varios capítulos dedicados a las ventajas me parece excesivo e incluso repetitivo, ya que una y otra vez comenta las mismas ventajas.

Afortunadamente el grueso de capítulos centrales me ha parecido una maravilla. No por TDD en sí mismo, sino porque se dedica para cada tipo de proyecto diffícilmente testeable (base de datos, jsp, swing, etc) a mostrarnos los distintos frameworks con los que podemos trabajar (jdbc, hibernate, spring, jsf, tapestry, wicket, …) como las librerías útiles para hacer test automáticos en esos frameworks (mockito, clases de spring que son mock objects de interfaces java complejas, jspunit, fit, etc, etc). Lo mejor de todo esto es que no da por supuesto que conocemos cada framework o librería, sino que nos da un resumen de cada uno de ellos, qué es, para qué sirve y cómo se usa. Así que esta parte, más que para hacer test automáticos, sirve realmente para conocer de qué van todas esas siglas que oímos de continuo y a veces no sabemos qué son (jsf, spring mvc, tapestry, jsf, wicket …) y es una primera guía para saber por dónde empezar a usarlas.

Dentro de este grupo de capítulos nos habla de los test de aceptación, que son test automáticos de más alto nivel donde idealmente se considera el sistema como caja negra y se testea desde fuera automáticamente. Idealmente estos test deben estar escritos por el cliente más que por los desarrolladores, puesto que el cliente es el que sabe lo que quiere y si el test es o no suficiente. Así que, aparte de discutir en qué casos se puede/debe testear desde fuera el sistema como caja negra, o cuando se puede/debe testear justo por debajo de la interfaz de usuario, nos introduce en herramientas como fit o fitnesse.

En la última parte, la que he dejado de leer, nos muestra los problemas que podemos tener con nuestros compañeros de trabajo si intentamos convencerlos de que usen TDD, y cómo identificar esos problemas y cómo abordarlos. Pero para mí, programador principalmente, lo de las relaciones humanas no es un libro que me entretenga. Y para mí, cabeza cuadriculada, semejante texto me parece demasiado "etéreo" y evidente. Oír por enésima vez las ya consabidas frases estilo "para que tus compañeros hagan TDD, dales ejemplo haciéndolo tú" o "si te dicen que sí sin entusiasmo igual te están diciendo que no", no me parece que ayuden demasiado a pelearte con los problemas día a día. Este tipo de problemas son problemas que puedes resolver si tu forma de ser es la adecuada para ello, y los resolverás o no independientemente de que hayas leído este libro. Hay quien de forma innata es un lider y que yo sepa, no existe quien de forma innata es un anti-lider y se convierte en lider con un cursillo.

Hablando de cursillos, me ha llamado la atención (creo que tiene toda la razón), este post sobre el peligro de las certificaciones, tan de moda hoy en día http://www.javiergarzas.com/2012/09/problemas-testing.html

Y volviendo al libro otra vez, una frase traducida más o menos libremente que me ha llamado la atención "Los buenos programadores sufren un tipo especial del síndrome de déficit de atención, consistente en poner todo su empeño en usar una herramienta nueva, para abandonarla pocos meses después  y poner nuevamente todo su empeño en otra herramienta más nueva". Real como la vida misma.

Aug 24

Cada vez me gusta menos google

Google sigue siendo una pequeña maravilla comparado con lo que había antes, tanto buscador como gmail y otras aplicaciones. También sigue siendo una maravilla comparado con otros buscadores o aplicaciones. Sin embargo, creo que va perdiendo respecto a cómo empezó.

Ahora me encuentro con frecuencia que el buscador de google es "demasiado listo" y pretende intuir qué estás buscando en vez de mostrarte resultados de lo que realmente estás buscando. Modifica las palabras "raras" que pones para buscarte las comunes (por ejemplo, si ente las palabras de búsqueda incluyes la herramienta buildr, es muy probable que te cambie y muestre resultados con la palabra "build"). También es muy frecuente que te ponga resultados de búsqueda en los que no aparece en absoluto algunas de las palabras que buscas. Quizás para búsquedas normales de gente normal sigue siendo un buscador muy válido, pero cuando un programador empieza a buscar conjuntos extraños de palabras por algún error que le ha salido a cómo hacer algo concreto y su búsqueda consiste en un conjunto extraño y heterogéneo de palabras, como "buildr nullpointer create project" (por decir algo), salen cosas que a lo mejor no tienen nada que ver con buildr, o no aparece project por ningún lado, o te cambia la palabra buildr por build (es sólo un ejemplo, no he probado a buscarlo y ver qué sale).

En cuanto a gmail, estoy hasta las narices de que me pida periódicamente mi número de teléfono móvil. No, no quiero dárselo, no me da la gana, pero él insiste, e insiste, e insiste,…

Y google+ tá como una maniega , me manda mensajitos, por ejemplo el de hoy,  indicándome que cuatro personas me han añadido a sus círculos. Bueno, me parece bien, si no fuera porque esas cuatro personas hace varios meses que me han añadido a sus círculos. Y hace quince días me había vuelto a avisar de lo mismo con las cuatro mismas personas. Debe ser alguna venganza por no querer darle mi número de teléfono móvil a gmail.

Y un "gadget" que tengo en igoogle para búsqueda de una palabra en blogs…. también "tá como una maniega", me muestra hoy lo que salió hace un mes, o no me muestra cosas. En fin, que no me parece en absoluto fiable.

Y youtube es últimamente un poco incordio. Visito la página para buscar videos o lo que sea … y cuando estoy a punto de darle al ratón para hacer click en alguno o ponerlo en marcha… el anuncio de la parte superior le da por aparecer de golpe (tarda en cargarse más que el resto de la página), desplazando todo el contenido de la página hacia abajo de golpe y haciendo que mi click caiga aleatoriamente en cualquier otro lado.

En fin, me disculpareis, pero me estoy desahogando, acabo de recibir de google+ que cuatro personas me han añadido a sus círculos, cosa que han hecho hace más de un mes algunos de ellos.

Aug 13

Configurando Hibernate para test unitarios.

Cuando hacemos test de JUnit o la herramienta que sea, una de las cosas difíciles de probar son las transacciones con base de datos. En nuestro entorno de desarrollo necesitaríamos una base de datos igual que la de producción y deberíamos borrar todos los datos, meter los datos previos al test para tener la base de datos en un estado conocido, hacer el test y luego revisar el contenido de la base de datos. Esto, aparte de complejo, puede ser muy lento con una conexión a una base de datos real.

Una de las soluciones es utilizar una base de datos en memoria (como HSQLDB, H2, etc). Estas bases de datos suelen ser un jar que no necesita instalación, así que basta con añadirlo a nuestro classpath en los test. Al ser en memoria, los test serán también muy rápidos. Sin embargo, sigue habiendo dos problemas:

  • En cada test habría que crear todas las tablas desde cero.
  • Las SQL de estas bases de datos pueden no ser las mismas que la de nuestra base de datos de producción (MySQL, Oracle, etc).

Para ayudarnos a solucionar estos problemas podemos usar Hibernate (u otra herramienta similar). Si en el fichero de configuración de Hibernate, los de mapeo de clases (o anotaciones) y nuestro código no usamos nada específico de una base de datos (debería ser lo normal salvo casos excepcionales), Hibernate nos hará independientes de la base de datos que usemos (de hecho, ese es uno de sus objetivos). Por otro lado, hibernate tiene un parámetro de configuración hibernate.hbm2ddl.auto en el que le podemos indicar que cree desde cero todas las tablas de la base de datos. Así que Hibernate nos resuelve, en principio, los dos problemas mencionados.

La primera idea que se nos ocurre es tener dos ficheros de configuración de Hibernate (hibernate.cfg.xml), uno para producción con la base de datos real y otro para test. Pero somos buenos programadores y no nos gusta tener cosas repetidas (principio DRY), posiblemente esos ficheros sean prácticamente iguales salvo los parámetros de conexión a la base de datos y el mencionado parámetro hibernate.hbm2ddl.auto, que en nuestro base de datos de test valdrá "create" y en la de producción puede valer algo como "verify".

La solución es simple, basta tener un único fichero de configuración para la base de datos de producción, con toda la parámetrica real. Para los test cargamos ese fichero … y modificamos en código sólo lo que nos interese. Se puede hacer de esta forma

Configuration configuration = new Configuration().configure();
configuration.setProperty("hibernate.connection.url", "jdbc:h2:mem:databaseName");

configuration.setProperty("hibernate.hbm2ddl.auto","create");
SessionFactory sessionFactory = configuration.buildSessionFactory();
 

El método configure() de Configuration leerá el fichero por defecto de configuración (suponemos que es el de producción) y luego, con el método setProperty() podemos "machacar" todas las propiedades que queramos de ese fichero. En el ejemplo sólo hemos cambiado la url de la base de datos y hibernate.hbm2dll.auto, aunque posiblemente deberíamos cambiar también el nombre de la clase del Driver de base de datos, usuario, password, etc.

Ahora sólo nos quedaría poner este código en algún sitio al que nuestras clases de test puedan acceder. Nuestras clases de test obtendrían el sessionFactory usando este código, mientras que el código de producción lo obtendría de la forma habitual, posiblemente a través de un UtilHibernate.java.

Por supuesto, no nos libra nadie de llenar la base de datos en cada test con unos datos conocidos y analizar luego los resultados.

Nos queda un detalle, que es borrar los datos después de cada test. Utilizando la base de datos en memoria como hemos hecho en el código anterior, quedará "viva" y con datos mientras esté arrancada la máquina virtual java. Al ejecutar una batería de test (con mvn test, por ejemplo), la máquina virtual no muere hasta que acaban todos los test, por lo que los datos que unos test van dejando en base de datos quedan para los siguientes test, aunque estén en memoria. Debemos vaciar esos datos después de cada test.

Una opción "pesada" es ir borrando los datos o hacer un "drop" de las tablas, en el orden adecuado para evitar problemas de "contraints". Pero otro método rápido y sencillo consiste en simplemente cerrar el SessionFactory. El siguiente test tendrá que crear un SessionFactory nuevo (con el código de arriba) y así se volverán a crear todas las tablas desde cero. Es decir, nuestras clases de test tendrán los métodos setUp() y tearDown() (o @Before y @After en JUnit 4) de la siguiente forma

public class TestUno extends TestCase {
   private SessionFactory = sessionFactory;

   @Override
   public void setUp() {
      sessionFactory = // Obtener session factory con el codigo anterior
   }

   @Override
   public void tearDown() {
      sessionFactory.close();
   }
   …
}

 

Simplemente un detalle. De esta manera realmente no se borran los datos al terminar en test. En realidad se borran al empezar el siguiente test, ya que el "create" de hibernate.hbm2dll.auto hace exactamente eso, borrar para crear desde cero.

 

Aug 09

Se me han pasado las ganas de jugar con Git submodules

Sigo jugando con Git y lo siguiente que me apetecía probar era el tema de git submodule. Con ellos puedes construir un proyecto/repositorio de Git en el que algunos de los directorios son otros proyectos/repositorios de git. De esta forma tienes un "super repositorio" compuesto de varios pequeños repositorios (aparte de tener su propio código).

Me pongo a ello, a mirar en google cómo se hace y veo que es un poco liado. Finalmente este tutorial me quita las ganas de probarlo. Git tiene unas pequeñas restricciones que hace que la creación de módulos sea un poco laboriosa y "pesadita"

  • En un repositorio bare no se pueden hacer commits.
  • No se puede clonar como submodulo un repositorio vacío.
  • No se puede añadir un submodulo en un repositorio bare.
  • No se puede hacer push si el origin es un repositorio no bare

Con todo esto el proceso de creación es tan complicado como lo siguiente (puedo estar equivocado en algún detalle, sólo lo he leído, intentado probarlo rápidamente y desistido por ser algo pesado)

  • Creas los repositorios que harán de submodulos como repositorios normales (no bare) y haces algún commit en ellos (si es bare no puedes  hacer el commit)
  • Los clonas para convertirlos en bares, pero con git config tienes que tocar manualmente las referencias en la copia, para que el bare no tenga como origen el repositorio normal.
  • Creas el super repositorio como repositorio normal y haces algún commit en él.
  • Convertimos el super repositorio en bare haciendo otro clone y tocando nuevamente las referencias a mano con git config.
  • Hacemos otro clone más del super repositorio bare y entonces añadimos los submodulos en la copia. Hacemos commit y push al repositorio central.

y tras este "simple" proceso está más o menos listo, salvo el detalle de que si un segundo desarrollador clona el super repositorio, tiene que acordarse de ejecutar git submodule init y git submodule update para que los submodulos realmente se clonen … ¿cómo hacemos estos comandos en un hudson por ejemplo? ¿O hudson lo tiene controlado?

Y bueno, si sólo fuera el proceso de crearlos, aun se podía plantear hacerlo (eso se hace sólo una vez en la vida de cada proyecto y lo hace el que crea el repositorio, supuestamente una persona avezada en git). El problema son los "gotchas" que vienen en el tutorial anterior. Indica que siempre hay que acordarse de publicar los cambios en los submodulos ANTES que los cambios en el superproyecto. Me hace a mí que en un grupo relativamente grande de desarrolladores, alguno se va a equivocar con bastante frecuencia. Aunque todo es cuestión de aprender el truco y convertirlo en hábito : "siempre commit y push de los submódulos primero".

Está bien saber que existen los submodulos de git por si algún día hacen falta. De hecho, trabajando en java es algo que echo de menos cuando tenemos muchos proyectos independientes pero que comparten juegos de ficheros no java comunes. Por ejemplo, juegos de iconos, dlls de windows, ficheros de script o ficheros de configuración (xml, properties, etc). La solución de "copiar" todo ese juego de ficheros en cada proyecto es un poco pesada, pero si no se copia es dificil hacer automáticamente un zip de instalación que tenga todos esos ficheros. La solución que se me ocurre es hacer un repositorio git con todo ese juego de ficheros y añadirlo como submodulo en los proyectos que lo necesiten.

En cualquier caso, queda pendiente para más adelante. Ahora me he puesto a jugar con Spring Framework WEB/MVC 😉

Aug 02

Instalando el servidor de Git en Windows

Jugando toda esta semana, al final he conseguido instalar un servidor de Git en Windows.

La instalación de Git es ahora fácil al haber un instalador de Windows. Eso sí, para ser usado a través de bash para Git o de Cygwin, puesto que la opción de meterlo en el PATH de Windows no está aconsejada.

El git daemon quedó totalmente descartado al no tener autentificación de usuarios y quedarse colgado en Windows cuando se intenta un pull.

Así que me puse a intentar la siguiente opción de servidor, el ssh. Windows no lleva servidor de ssh, así que hay que buscarse uno. Primero probé con servidores específicos de Windows, gratuitos, en concreto FreeSSHd, La instalación muy sencilla y además coge los usuarios de Windows, por lo que lo tengo funcionando rápidamente. Un cliente ssh puede conectarse y obtiene un cmd de Windows remoto. El problema viene al intentar integrarlo con Git. Al ser un cmd de Windows, no tiene en el PATH los comandos de Git, Es más, no necesita los comandos de git que vienen en el directorio bin, sino algunos de los que vienen en el directorio libexec/git-core y alguna dll de bin. Tras copiar los ejecutables concretos y dlls concretas que hacen falta en C:\Windows, ya intenta funcionar el git clone ssh://… … pero sólo lo intenta, da error. Buscando en google, me encuentro con que mucha gente tiene el mismo problema, que nadie da solución y que aparentemente FreeSSHd devuelve algún caracter que no le gusta al protocolo de git y va mal, posiblemente los famosos retornos de carro /r/n o sólo /n, por lo que descarto el servidor FreeSSHd para usar con Git. Busqué otros servidores SSH de Windows, pero no encontré ninguno gratuito o que me convenciera.

Así que intenté OpenSSH para Windows, una instalación mínima de cygwin con OpenSSH para Windows. No conseguí hacerlo funcionar rápidamente, posiblemente debido a algún problema en el PC donde hice las pruebas, así que pasé a la siguiente opción, instalar cygwin con git y openssh. La guía del enlace anterior es una maravilla, exactamente lo que necesitaba y funcionó a la primera, incluso instalando OpenSSH como servicio de Windows e importando los usuarios propios de Windows. Un git clone ssh://  también funcionó bien sin problemas …. pero ya sabemos que esto de la programación no es tan maravilloso como parece y siempre hay algún "pero". El único problema, que mucha gente tiene en google y que nadie parece haber resuelto, es que no se pueden clonar repositorios de otros discos que no sean el C:\. Cosas como ssh://host/D:/repo, ssh://host/d/repo o ssh://host/cygdrive/d/repo no funcionan. Como todos sabemos, es buena costumbre en Windows dejar C:\ para el sistema operativo y meter nuestros datos en otro disco (D:\ por ejemplo), así que esta opción, aunque va con repositorios en C:\, no me convence.

ACTUALIZACIÓN: Lo de usar distinto drive está funcionando. Desinstalé el git de windows e instalé el de cygwin a través del setup.exe de cygwin. Ya lo había hecho al instalar el OpenSSH. Ahora git clone ssh://localhost/cygdrive/e/repo funciona correctamente. Quizás el fallo se debiera a lguna incompatibilidad entre los paths del git de Windows que te bajas de http://git-scm.com/ y el de cygwin. 

Así que me cogí los servidores de Git de este comentario y me puse a ello. Una rápida búsqueda en Google para comparar y ver cómo se instalan en Windows me decidió rápidamente a probar gitblit. Entre esta guía de instalación de gitosis en windows y esta otra de gitblit (apartado GO: Single stack solution, con todas las dependencias integradas y 5 minutos para tenerlo funcionando), está claro. Viendo rápidamente el fichero de configuración de gitblit, veo que soporta LDAP, por lo que puedo intentar ponerlo en el Active Directory de Windows. Dicho y hecho, lo prometido por gitblit es cierto, en cinco minutos está funcionando bien y sin problemas. Sólo desempaquetar el zip, indicarle en el fichero de configuración el path donde están tus repositorios y arrancarlo con doble click. La integración con Active Directory me costó un poco más, pero más por culpa de Microsoft que de gitblit, Active Directory no es exactamente igual que LDAP y me dio algún problema hasta encontrar la solución. (principalmente, si necesitas un usuario para consultar LDAP, el nombre de usuario es estilo "cn=jsmith,ou=usuarios,dc=compania,dc=com", mientras que en Active Directory el usuario es "John Smith", es decir, el nombre "expandido" y sin cn=, ou= ni dc=. El segundo problema el campo email. gitblit espera un campo email y Active Directory (al menos el nuestro) tiene uno mail (sin la e delante). Aguí gitblit lanza una excepción y no va. Afortunadamente, el fichero de propiedades de gitblit permite indicar cómo se llama este campo.

Me he quedado con ganas de hacer alguna prueba más con lo del disco no C:\ de OpenSSH y de probar el servidor scm-manager, pero creo que he jugado bastante, tengo servidor git "oficial" con gitblit funcionando y todavía me queda actualizar Hudson o instalarle el plugin correspondiente para que entienda de git.

Resumiendo, si tienes un servidor en Windows, quieres un servidor Git con los usuarios de Active Directory y no quieres "jugar" mucho tiempo, gitblit es una buena opción.

Jul 27

Jugando con GIT

Tras el post anterior, me quedé con las ganas de ponerme a jugar con Git un poco más en serio, y eso he estado haciendo, a ratos, a lo largo de esta semana.

La primera sorpresa agradable es que ahora, desde la página oficial, existe descarga para windows, con un instalador fácil estilo windows. Me lo descargo e instalo. El instalador te da tres opciones, instalar un bash específico para Git, hacer una instalación paa cygwin o bien, con serias advertencias por parte del instalador, poner los comandos de git accesibles desde una ventana de comandos de ms-dos. Esto último requiere que ciertos comandos de windows, como find.exe, se cambien por otros al estilo unix. Vemos que windows, aunque ya hay instalador fácil oficial, sigue sin estar totalmente soportado, haciéndose necesario el uso de una shelll de unix. Supongo que esto no tiene especial importancia si estás acostumbrado a unix (como es mi caso), vas a usar un TortoiseGIT o directamente el IDE que sea.

Siguiente parte a probar, el servidor. Según la documentación hay tres opciones:

  • git daemon. Es lo más simple, se arranca con un comando y ya está compartido cualquier repositorio git en el servidor. El acceso es de solo lectura, haca falta configurar el arranque si queremos también acceso de escritura. La pega es que tiene ningún tipo de autentificación de usuario, así que cualquier anónimo sería capaz de escribir y borrar en nuestro repositorio sin ninguna restricción. Es ese el motivo por el que no se aconseja esta opción en redes que no sean de confianza. Este servidor se aconseja sólo en modo lectura, puesto que es el más rápido a la hora de hacer descargas (git clone).
  • ssh. Acceso a través de ssh, con una configuración de ssh más o menos estándar. No la he probado y es la opción aconsejada, con la pega de que todos los usuarios deben tener usuario en el servidor.
  • http. Publicar un repositorio en modo lectura desde un servidor http es casi inmediato. La parte de escritura requiere habilitar WebDAV en el servidor apache y la autentificación de usuarios recae totalmente en el servidor apache. Esta es la opción que he usado yo.

Con respecto a la primera opción, git daemon, simplemente comentar que git push se queda colgado (llevar algo al repositorio remoto) haciéndola totalmente inútil. Parece ser un bug del cliente windows que lleva ya un tiempo ahí. La parte de servidor ssh en windows tampoco parece que se pueda poner fácilmente en un windows que no sea "server" (creo que si no es un windows "server" ni siquiera tiene servicio de ssh) y por eso me he tenido que ir a la parte de apache http.

En cuanto a las ramas, me he puesto a jugar con ello y es una pequeña maravilla. La gran mejora respecto a svn no es que haga mejor los "merge" en si mismos, supongo que el algoritmo de merge deben ser parecidos y en ambos casos, si hay conflictos, hay conflictos y se deben resolver a mano. La gran ventajas de Git sobre SVN es que Git lleva automáticamente toda la cuenta de qué ramas se han hecho de qué ramas, qué merges se han hecho y cuando hacemos un nuevo merge, el sabe automáticamente qué ficheros son los que tiene que juntar y desde dónde. SVN no lleva toda esta cuenta, por lo que el primer merge que se hace suele funcionar bien (se hace desde las revisiones adecuadas), pero si más adelante intentamos hacer un segundo merge con las mismas ramas, o de una de estas con otra, svn no sabe exactamente desde qué revisiones partir y debemos decírselo manualmente en el comando. Eso nos obliga a llevar a nosotros, manualmente, un histórico de merges que se han hecho, desde qué ramas, etc, etc. Claramente, si quieres trabajar con muchas ramas y vas a hacer muchos merges, Git es muchísimo mejor opción que Subversion.

En cuanto a facilidad de comandos, sobre todo si se está acostumbrado s Subversion, cuesta acostumbrarse un poco. El principal motivo, aparte de saber o no la sintaxis de los comandos, es que venimos de Subversion con la idea de un único repositorio central. Nuestra copia de trabajo está siempre ligada al repositorio central y los comando svn se hacen siempre contra ese repositorio central. En Git, nuestra copia del repositorio "central" es exactamente igual de importante para Git que la "central". Y pueden evolucionar por separado, yo puedo tener ramas que no están en la central y evolucionan de forma distinta, el "central" puede tener sus propias ramas, llamarse incluso igual que las nuestras, y no tener nada que ver.

El tema va incluso más allá, lo de repositorio "central" es cosa nuestra, realmente no lo hay. Git permite incluso que traigamos cosas de repositorios distintos. Puedo traerme una rama del "central", otra rama del repositorio de mi compañero de trabajo Federico y otra de internet, teniendo así un repositorio local con ramas traídas de N fuentes distintas.

Y las ramas mías y de la central, aunque se llamen igual (o no) y tengan el mismo contenido, pueden no estar ligadas para Git o pueden si estarlo. Si no están ligadas, git las considera independientes y los comandos git push o git pull no funcionarán si no les damos la paramétrica adecuada indicando ambas ramas. Si están ligadas, aunque tengan nombres distintos, git lo sabe y es capaz de ejecutar push y pull sin problemas.

Todo esto añade una complejidad excesiva de conceptos y variedad de comandos, sobre todo para los que venimos de Subversion con un respositorio central en el que están todas las ramas que existen y no hay más. Para empezar a trabajar con Git y sacarle partido a todo esto de las ramas, es necesario hacer un montón de pequeñas pruebas con los comandos para entender exactamente qué hacen, o buscar tutoriales detallados, puesto que la documentación es más bien pobre (es más una documentación de referencia que un tutorial de conceptos).

Ahora probaré el tema de servidor y autentificación con LDAP. Si consigo algo decente, montaré un servidor Git en el curro para alguno de los proyectos pequeños y empezaremos a hacer pruebas para usarlo. Me queda también ver si redmine es capaz de sacar fuentes de Git y si Hudson/Jenkins entiende de Git.