Usar un datepicker con Rails, JQuery, Twitter Bootstrap y SimpleForm

Todos sabemos que la manera más rápida de introducir una fecha es usar el teclado y un simple campo de texto; sin embargo nuestros usuarios no usan el ordenador tantas horas al día ni llevan tantos años haciéndolo como nosotros, por lo que no les importa destrozarse un poco más la muñeca usando el ratón y pinchando en un bonito calendario.

A la hora de intentar usar algún tipo de calendario para introducir las fechas nos encontramos con dos problemas:

  • El bootstrap no incluye ninguno de serie.
  • Los estilos de la librería JQuery UI no son compatibles con él, por lo que si intentamos usar el datepicker de éste, se va a ver fatal.

Mi objetivo es poder usar un datepicker en el que pueda especificar la fecha que se muestra inicialmente en el calendario mostrado, o si no indico nada, que coja la actual. La versión de Rails utilizada en este ejemplo es la 3.2.3, y las gemas son: bootstrap-sass 2.0.2 y simple_form 2.0.2

Tras googlear un poco encontré la página de Stefan Petre, autor de un Colorpicker y un Datepicker bastante resultones.

Insertar el código del datepicker

Tras descargarlo, lo único que hay que hacer es copiar el css y js que lo forman en nuestra carpeta de assets (obviamente en stylesheets y javascripts, respectivamente), y tal como indica la documentación, utilizarlo es tan sencillo como lo siguiente(los inputs de fechas en mi app llevan la clase date_picker):

$(document).ready(function() {

  $("input.date_picker").datepicker({format: 'yyyy-mm-dd', weekStart: 1});

})

Por defecto, cuando pulsamos en el input, aparece el calendario mostrando la fecha que aparezca en su value; si éste es nulo, aparecerá el 1 de enero de 1900, que raramente será lo que queremos. Por otro lado este plugin contempla el caso de no usar un input, y entonces coge por defecto la fecha que indiquemos en el atributo data-date de la etiqueta en cuestión.

En mi caso me interesa usar inputs, y no quiero asignar un value inicial, por lo que para usar un atributo data-date en los input podemos modificar el fichero bootstrap-datepicker.js, y la línea 115 (método update) la modificamos para tener esto:

this.date = DPGlobal.parseDate( (this.isInput && (this.element.prop('value') != "")) ? this.element.prop('value') : this.element.data('date'), this.format );

Una vez hecho esto, añadiendo data-date="2012-10-12" conseguiríamos un input vacío pero con el calendario inicializado en esa fecha.

Crear un tipo específico de input para el SimpleForm

A la hora de usarlo con el SimpleForm, para evitar tener que escribir continuamente líneas como:

<%= f.input :begin_date, :as => :string, :input_html => {:class => 'span2 date_picker', "data-date" => "2012-10-12" } %>

se puede crear una clase que defina un nuevo tipo de input. Para ello creamos un fichero en app/inputs/ denominado date_picker_input.rb, y creamos nuestra clase:

class DatePickerInput < SimpleForm::Inputs::StringInput

  def input

    input_html_classes.push 'span2'

    super

  end

  def input_html_options

    options[:date] ||= Date.today

    super.merge('data-date' => options[:date])

  end

end

Ahora podemos usar nuestro propio input en los formularios así:

<%= f.input :begin_date, :as => :date_picker %>

<%= f.input :birthdate, :as => :date_picker, :date => Date.new(1940, 1, 1) %>

Solución de problemas

Aunque (en teoría) por defecto el SimpleForm lee los inputs propios que hayamos definido en la carpeta app/inputs, es posible que no lo haga (fué mi caso); si nos pasa esto basta editar config/initializers/simple_form.rb y descomentar la línea:

config.inputs_discovery = true

Por otro lado, el plugin incluye los meses y días en inglés, por lo que tendremos que localizar los arrays oportunos en el fichero bootstrap-datepicker.js y cambiarlos al español si es lo que necesitamos. Lo ideal sería prepararlo para usar i18n.

Generalización

Si todos nuestros inputs de fecha van a llevar el datepicker, y además todos incluyen la palabra date en su nombre, podemos hacer que automáticamente sean de tipo date_picker sin tener que especificarlo, incluyendo en el config/initializers/simple_form.rb lo siguiente:

config.input_mappings = { /date/ => :date_picker }

Y con esto nuestros formularios vuelven a ser concisos:

<%= f.input :begin_date %>

<%= f.input :birthdate, :date => Date.new(1940, 1, 1) %>

Es posible que haya algun otro plugin mejor por áhí. ¿Has probado algún otro que se pueda usar con comodidad? Cualquier sugerencia será bienvenida.

Quiero hacer TDD, pero... ¿qué tengo que testear?

Es lo primero que te planteas cuando te inicias en el maravilloso mundo del TDD y BDD. Normalmente piensas: pues todo aquello que pueda fallar. En general, es la idea clave, aunque hay que elaborarla un poco más.

Pese a llevar un par de años escribiendo primero tests y después el código, no siempre he tenido muy claro qué testear. Hay infinidad de cosas que pueden fallar, y según el contexto pueden ser más importantes unas que otras.

Tras leerte  The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends y Scripted GUI Testing with Ruby aprendes el uso de las herramientas para realizar los tests, así como empiezas a desarrollar instinto para ver que métodos testeas y como hacerlo, pero ha sido al leerme hace poco Pragmatic Unit Testing in Java with JUnit que no vi una explicación un poco más sistematizada sobre esto.

Así que ante la pregunta ¿qué tengo que testear en un método?, los autores (Andy Hunt y Dave Thomas) proponen el siguiente acrónimo (a los norteamericanos les encanta usarlos):

Right BICEP

  • Right: ¿son los resultados correctos? Hay que validar los resultados.
  • Boundary: ¿el comportamiento del método es correcto en condiciones límites? Como por ejemplo cuando los datos de entrada están mal formateados, o faltan, valores que exceden expectativas razonables (edad de una persona: 1000 años), el primer elemento de algo, listas vacías, etc...
  • Inverse: ¿puedes testear la relación inversa? Por ejemplo, tengo un método que calcula raíces cuadradas, pues testeo que el resultado del método elevado al cuadrado es igual (con cierto margen de error) al número que introduje como argumento de mi método.
  • Cross-check: realizar verificaciones cruzadas con otros métodos/técnicas de los resultados de mi método. Esta es un poco esotérica para mi gusto, aunque alguna vez lo he hecho.
  • Error: forzar condiciones de error. Usar mocks para simular fallos de conexiones de red, escritura/lectura en disco, etc...
  • Performance: de cara a la escalabilidad tenemos que ver como se comporta ante valores grandes de datos a tratar: conexiones, listas, etc..

Vale, pero...¿qué tengo que testear?

Pues en base a esta lista, mi receta personal, como no puedo testearlo todo por falta de tiempo, lo que hago es apostar por el Right (sin duda hay que validar el resultado del método) y luego de la parte del BICEP aquellos puntos que:

  • He visto que han surgido alguna vez en la historia de este proyecto u otros similares.
  • Los que de suceder pueden fastidiar bastante al usuario/cliente (pérdida de dinero, vidas humanas, etc...)
  • Los que intuyo tienen más probabilidad de aparecer o provocar errores desastrosos.

Aunque en esencia, de esta anterior lista el punto más importante suele ser el primero, ya que si tienes la suerte de que tu cliente (o usuarios) de la app van trabajando con ella desde las primeras iteraciones, a medida que tropiezan con bugs irás identificando las áreas más problemáticas y los casos más comunes con los que te vas a encontrar; esas partes tenderás a reforzarlas con tests, ya que en el proceso de resolución del bug escribes el test que lo expone primero, incluso varios si sospechas que debes probar otras condiciones límite.

Y tú, ¿qué testeas? ¿cómo priorizas?

Cuando abordas un proyecto software, ¿piensas en casas o jardines?

Nos hemos adentrado 12 años en el siglo XXI y aún seguimos sufriendo una de las grandes lacras del desarrollo de software: la metáfora de la construcción de edificios.

Afortunadamente cada vez son menos los programadores que piensan de esta manera (aunque por desgracia aún quedan bastantes haciendo mucho daño con esta mentalidad), sin embargo persiste un problema: los clientes han sido intoxicados durante generaciones con esa misma idea.

Para agravar el problema, esta metáfora fallida entronca muy bien con las necesidades de un hombre de negocios. Desean y esperan tener una previsión de tiempo y gastos un 100% fiable para poder conducir su negocio en consecuencia, manejar el cashflow, establecer acuerdos con partners a partir de fechas concretas, etc...

Construcción de software

Siempre nos contaron que los pasos para construir software son:

- Análisis

- Diseño (el arquitecto dibuja los planos)

- Construcción (el contratista hace los cimientos, fabrica encima, mete todas las canalizaciones de luz, agua, etc., se pinta, se ponen puertas, ventanas...)

- Testing (los inquilinos se mudan a la casa y viven felizmente en ella, y llaman a los de mantenimiento del edificio cuando tienen algun problema).

Todos (o al menos una amplia mayoría) los programadores sabemos a estas alturas que esta metáfora nunca ha funcionado. No aburriré con cifras, pero basta buscar un poco por la red para encontrar datos sobre tremendas inversiones de dinero en proyectos que nunca llegaron a desplegarse.

Un edificio es hard, el software es soft. Y esa es una distinción poderosa.

Sin embargo a día de hoy sigo topándome con clientes que exigen desde un primer momento documentos de análisis, diseño, previsión exacta de despliegue de funcionalidades, etc...

Y lo peor de todo, me han comentado incluso que en algunas Universidades aún siguen enseñando ese paradigma.

Cultivo de software

Andrew Hunt y Dave Thomas, en su excelente libro The Pragmatic Programmer: From Journeyman to Master, proponían (el libro es de 1999) la metáfora de la jardinería:

Plantas muchas variedades de plantas en un jardín acorde a un plan y unas condiciones iniciales. Algunas prosperan y otras acaban como compost. Puedes recolocar algunos de los cultivos para aprovechar luces y sombras, el viento y la lluvia. Las plantas que crecen en exceso son divididas en esquejes o podadas, los colores que no pegan pueden ser movidos a otras áreas. Eliminas telarañas, abonas las plantas que necesitan más ayuda. Constantemente supervisas el estado de salud de tu jardín, y realizas ajustes (al suelo, las plantas, la disposición) según se vaya necesitando.

Creo que es la mejor metáfora que he visto hasta la fecha para definir la elaboración de software; partes de una idea inicial más o menos estudiada, pero tu jardín va a depender de como salgan las cosas, las circunstancias externas, la interacción entre los componentes del jardín...en definitiva un montón de factores que son imposibles de determinar a priori.

No estoy construyendo tu casa, estoy cultivando tu jardín

La pregunta del millón es: ¿como venderle esta idea a tu cliente? Aunque por lo general puedes vender parcialmente la idea de la indefinición y la incertidumbre en el desarrollo software, él necesita poder realizar cierto tipo de previsión, especialmente en proyectos largos y complejos.

Más de una vez me he encontrado que tras explicarle detenidamente a un cliente la dificultad de establecer plazos inmutables cuando apenas estás empezando a desarrollar y no tienes ni idea de las complejidades que te vas a encontrar en ciertas áreas de la aplicación, las bondades del desarrollo iterativo y el BDD, éste te mira y te dice: muy bien, pero... ¿cuándo vas a poder terminar el programa?

¿Construyes o cultivas? ¿Como logras vender tu jardín a tus clientes? Yo aún sigo dándole vueltas, así que cualquier sugerencia será extremadamente bienvenida y agradecida!

Herramientas de colaboración online (III): Teambox

Al igual que el ClockingIt, esta herramienta también la puedes usar de dos maneras:

Ofrece las mismas características básicas que el ClockingIt:

  • subscripción iCal
  • Feed RSS
  • Posibilidad de comentar directamente las tareas y adjuntar archivos a éstas
  • Compartir archivos en general
  • Foros de discusión y Wikis
  • Time tracking e informes de horas
  • Recibir notificaciones por email y responder a éstos directamente

No he probado el servicio online, por lo que hablaré de la versión instalable.

Ventajas

  • Instalable con poco esfuerzo.
  • Código limpio, moderno; si le echas un vistazo a su Github verás además que tiene un desarrollo muy activo.
  • La interfaz, aunque no es perfecta, es más agradable y limpia que la de otras herramientas. Apariencia bastante “moderna”.
  • Tiene API.
  • Mobile friendly, la interfaz se adapta bien y se puede usar con facilidad.
  • Su filosofía es la sencillez de uso, sin sobrecarga de funcionalidades, opciones de edición, etc.

Desventajas

  • No incorpora cronómetros para las tareas, tienes que buscar tu propia aplicación y registrar manualmente en la tarea el tiempo invertido.
  • El informe de horas es muy rudimentario. Al no distinguir entre tareas normales y resolución de bugs, complica un poco la extracción de información para facturar.
  • Todas las páginas wiki pertenecen a proyectos en concreto, no permite crear páginas “globales” con información general como por ejemplo procedimientos de arranque de un proyecto, etc…

Conclusión

Esta es mi herramienta elegida actualmente para todos los nuevos proyectos, y la estoy desplegando en los servidores de las empresas con las que colaboro.

Herramientas de colaboración online (II): ClockingIT (Jobsworth Project Management)

Esta herramienta la puedes usar de dos maneras:

  • descargándola de Github e instalándola en tu propio servidor. Es la opción más segura si quieres garantizar el funcionamiento 24x7 de la aplicación.
  • creando una cuenta gratuita (admiten donaciones via PayPal); te despreocupas del alojamiento, instalación y mantenimiento, pero quedas a expensas de un funcionamiento sin garantías de ningún tipo. He visto la aplicación fallar algunas veces, siendo el fallo más grave que he visto el de mostrar las tareas y comentarios de proyectos pertenecientes a otras cuentas. Ofrece las características que considero básicas en toda herramienta de este tipo:
  • subscripción iCal
  • Feed RSS
  • Posibilidad de comentar directamente las tareas y adjuntar archivos a éstas
  • Compartir archivos en general
  • Foros de discusión y Wikis
  • Time tracking e informes de horas
  • Recibir notificaciones por email y responder a éstos directamente

Tiene más funcionalidades que por básicas o no relevantes para mi no detallaré.

Ventajas

  • Tienes la opción de usar el servicio online (más cómodo) gratuitamente, sin ningún tipo de restricciones.
  • Incorpora un cronómetro para añadir los logs de tiempo invertido a las tareas, aunque si cierras el navegador y te olvidas de pararlo seguirá corriendo, con lo que tendrás que editar el log para eliminar el tiempo adicional.
  • El servicio online te permite descargar la bd para que puedas tener una copia de seguridad, aunque no facilita una manera de descargar los archivos que hayas subido.
  • El informe de horas permite sacar por proyecto, personas, tipo de tareas, período de tiempo, etc… Es muy útil.

Desventajas

  • Carece de API
  • Las páginas del wiki son globales, con los cuales todo usuario con acceso a tu cuenta podrá verlas todas; teniendo en cuenta que por lo general los clientes tienen acceso a su proyecto para comentar tareas y demás, cualquier dato sensible que pusieses en el wiki (como información de configuración de tu servidor dedicado, por ejemplo) sería visible para ellos.
  • En su día traté de instalarlo pero no pude conseguirlo. Esto fue hace bastante tiempo, aunque supongo que ahora habrá mejorado el proceso, mi impresión fué totalmente negativa.
  • Asi mismo el código no me pareció tan bueno como el del Teambox, por ejemplo. Aunque insisto que esta es una impresión de cuando le eché un vistazo, hace más de un año y medio.
  • La interfaz no es muy cómoda de usar que digamos, las tipografías algo pequeñas y da la sensación de pantalla llena, un poco agobiante para mí.
  • Mobile unfriendly; intentar usarlo desde el móvil es casi imposible.

Conclusión

Aun con sus fallos, una de las empresas con las que colaboro la usa activamente (el servicio online) y nos presta un buen servicio, pero el hecho de no encontrarme cómodo con la idea de no tener control sobre la ubicación de la información, la interfaz incómoda de usar y no poder acceder bien desde el móvil me han llevado a comenzar a usar para otros proyectos el Teambox, del que hablaré en el próximo artículo.