Noticias Weblogs Código

Arragonán

Semana 368

July 01, 2015 07:57 PM

La semana pasada fue movidita en muchos aspectos, y parece que la tónica general de mi verano va a ser bastante así, el trabajar de contractor por el momento me está absorbiendo más tiempo y energía de lo que esperaba inicialmente.

Durante la semana estuve trabajando sobre una propuesta para un posible proyecto, ahora que ya tenemos en claro el presupuesto y los tiempos en los que el cliente necesita tenerlo funcionando, tenemos que ver si encaja el alcance. También se concretó un pequeño proyecto del que iba detrás hacía bastantes meses, ya iré contando avances.

A finales de semana tuvimos charla de Capistrano en zaragozarb por un lado y por otro había betabeers. En el betabeers estuvimos con Néstor y Razvan hablando de la experiencia de SenpaiDevs.

Y el sábado cerramos la temporada futbolera nada menos que ganando la final de copa.

Campeones de copa

Campeones de copa.

En cuanto a trabajo actual:

  • Empecé con el trabajo de adaptación del frontend de Bichomanía
  • Como contractor, continué avanzando en la documentación técnica y pude empezar a programar un poco. Por el momento poca cosa enseñable-reseñable, ya que el cliente final requiere mucho detalle de algunas decisiones de arquitectura que se están tomando.
  • Estuve haciendo algunas modificaciones por el cambio de marca a OutreachTool. También tuvimos una reunión para un próximo (y más que necesario) rediseño de la web.
  • Estuvimos con mails de coordinación para la integración de minchador

Buena semana.

» Leer más, comentarios, etc...

El blog de Adrián Arroyo

Un repaso por las aplicaciones de Haiku

June 30, 2015 10:00 PM

Haiku dispone de un catálogo pequeño pero interesante de aplicaciones que merecen la pena ser vistas. Voy a probar estas aplicaciones en una versión nightly recién descargada del sitio de Haiku (hrev49344)
Solo voy a usar los paquetes binarios. En Haikuports hay todavía más software, pero requiere compilación y puede estar desactualizado.

HaikuDepot

Se trata de la tienda de aplicaciones de Haiku. Similar a Ubuntu Software Center. Desde aquí podemos instalar cientos de aplicaciones ya compiladas para Haiku. Además permite comentar los progranas con una valoración.
HaikuDepot dispone de una versión web

HaikuDepot
HaikuDepot

Instalar

HaikuDepot ya viene instalado en Haiku

WonderBrush

WonderBrush se trata del editor gráfico de Haiku para imágenes de mapa de bits como PNG, JPEG o BMP.

La ventana principal puede contener cualquier número de documentos llamados Canvas. Un canvas tiene asociado un nombre y una resolución por píxel además de muchas otras propiedades. También referencia a dos archivos, uno como formato de exportación y otro como formato nativo.
Cada canvas puede tener cualquier número de capas, actualmente representadas como una lista. Cada capa representa una imagen del tamaño del canvas. Dependiendo del método de fusión de capas, estas son unidas para formar la imagen final.

WonderBrush
WonderBrush

Instalar

Lo puedes encontrar en HaikuDepot o

pkgman install wonderbrush

Icon-O-Matic

Icon-O-Matic es la aplicación de gráficos vectoriales nativa de Haiku. Trabaja con el formato HVIF (Haiku Vector Icon Format) y está pensada para diseñar iconos principalmente. También exporta a PNG y SVG.

Icon-O-Matic

Instalar

Ya viene instalado por defecto en Haiku

WebPositive

WebPositive es el navegador web por defecto en Haiku. Usa una versión especial de WebKit adaptada a Haiku y algo retrasada en funcionalidad.

WebPositive
Multiversos en WebPositive

Instalar

WebPositive ya viene instalado

PoorMan

PoorMan es un ligero servidor HTTP totalmente gráfico.

PoorMan

Instalar

PoorMan ya viene instalado por defecto en Haiku

Vision

Vision es un cliente IRC

Vision

Instalar

Ya viene instalado por defecto en Haiku

People

People es el gestor de contactos de Haiku

People

Instalar

Ya viene instalado por defecto en Haiku

Album

Una aplicación para tratar los metadatos de las imágenes

Album

Instalar

En HaikuDepot o pkgman install album

ArmyKnife

Una aplicación para tratar los metadatos de las canciones

ArmyKnife

Instalar

En HaikuDepot o pkgman install armyknife

BeAE

BeAE es una gran aplicación junto a Wonderbrush e Icon-O-Matic para la edición multimedia. En este caso podremos editar audio de manera muy intuitiva. En su momento fue una aplicación de pago para BeOS.

BeAE

Instalar

En HaikuDepot o pkgman install beae

BePDF

El visor de documentos PDF de Haiku

BePDF

Instalar

En HaikuDepot o pkgman install bepdf

BeShare

Haiku también dispone de un sistema de transferencia de archivos P2P propio. Se trata de BeShare y esta es la implementación referencia. BeShare como no podía ser menos, tiene un magnífico soporte para búsquedas.

BeShare

Instalar

En HaikuDepot o pkgman install beshare_x86. Para permitir la conexión entre distintos sistemas operativos a las redes BeShare se creó JavaShare

BeZilla

El port de Mozilla Firefox para Haiku. Está muy desactualizado y no lo recomiendo.

BeZilla

Instalar

En HaikuDepot o pkgman install bezilla

MailNews

El port de Mozilla Thunderbird para Haiku. Está igual de desactualizado que BeZilla pero al tratarse de correo electrónico puedes tener menos problemas al usarlo.

MailNews
MailNews

Instalar

En HaikuDepot o pkgman install mailnews

Beam

Se trata de un cliente de correo electrónico plenamente integrado en Haiku

Beam

Instalar

En HaikuDepot o pkgman install beam

BlogPositive

Una aplicación para escribir en blogs de WordPress y otros proveedores sin tener que usar el navegador

BlogPositive

Instalar

En HaikuDepot o pkgman install blogpositive

CapitalBe

Una aplicación de contabilidad sencilla y fácil de empezar a utilizar. GnuCash, que es el que uso en Linux, es mucho más complejo de empezar a usar.

Capital Be
Capital Be

Instalar

En HaikuDepot o pkgman install capitalbe

Sum-It

Una sencilla hoja de cálcula para realizar operaciones no muy complejas. La mejor hoja de cálcula es la de GoBe Productive, pero sigue siendo un producto privado que no se puede adquirir.

Sum It

Instalar

En HaikuDepot o pkgman install sum_it

Caya

Caya es una aplicación que unifica la mensajería instantánea el estilo de Pidgin. Soporta AIM, Google Talk, Jabber, Facebook, MSN y Yahoo.

Caya

Instalar

En HaikuDepot o pkgman install caya

LibreCAD

LibreCAD es una aplicación de CAD 2D escrita en Qt.

LibreCAD

Instalar

En HaikuDepot o pkgman install librecad_x86

Pe

Pe es el editor de texto más usado en Haiku. Tiene resaltado de sintaxis y soporte para extensiones.

Pe
Pe

Instalar

Pe viene instalado por defecto en Haiku

NetSurf

NetSurf es un navegador ligero que no implementa JavaScript. Tiene una arquitectura interna muy limpia. Todo está contenido y modularizado. Está diseñado pensando en Haiku, RISC OS y otros sistemas desconocidos, aunque en Linux también funciona.

NetSurf

Instalar

En HaikuDepot o pkgman install netsurf

BePodder

BePodder es una aplicación para escuchar tus podcasts favoritos por RSS

BePodder

Instalar

En HaikuDepot o pkgman install bepodder

A-Book

Una aplicación de calendario con recordatorios

Instalar

En HaikuDepot o pkgman install a_book

BurnItNow

Una aplicación gráfica y fácil de usar para grabar CDs de todo tipo (datos, audio, rescate, …)

Burn it now

Instalar

En HaikuDepot o pkgman install burnitnow_x86

Clockwerk

Ya hemos hablado de Wonderbrush, Icon-O-Matic y BeAE. Le toca el turno a Clockwerk, el editor de vídeo no linear open source que trabaja en Haiku.

Clockwerk

Instalar

En HaikuDepot o pkgman install clockwerk

LMMS

LMMS es una completa suite de edición de audio pensada para Linux pero que funciona también en Haiku.

LMMS

Instalar

En HaikuDepot o pkgman install lmms_x86

MilkyTracker

MilkyTracker es un programa para componer música de estilo 8 bits o tune.

Milky Tracker

Instalar

En HaikuDepot o pkgman install milkytracker

Paladin

Paladin nace con la idea de ser el IDE de referencia en Haiku. Trae plantillas y ejemplos y se integra con el resto de Haiku para no reduplicar esfuerzos. Por ejemplo, el editor de texto es Pe.

Paladin

Instalar

En HaikuDepot o pkgman install paladin

QEMU

QEMU es un contenedor de máquinas virtuales open source que permite emular arquitecturas diferentes a la de nuestro ordenador. Con QEMU podemos ejecutar Linux dentro de Haiku.

Instalar

En HaikuDepot o pkgman install qemu_x86

Yab IDE

Yab es un entorno que permite programar aplicaciones para Haiku en BASIC. Yab IDE es el IDE para este entorno espefífico.

Yab IDE
Yab IDE

Instalar

En HaikuDepot o pkgman install yab_ide

Juegos

En este apartado voy a mencionar algunos juegos disponibles para Haiku. Todos se pueden encontrar en HaikuDepot

BeMines

  • BeLife - pkgman install belife
  • BeMines - pkgman install bemines
  • Critical Mass - pkgman install criticalmass
  • DOSBox - pkgman install dosbox_x86
  • Flare - pkgman install flare_x86
  • FreedroidRPG - pkgman install freedroidrpg_x86
  • LBreakout2 - pkgman install lbreakout2
  • LMarbles - pkgman install lmarbles
  • LTris - pkgman install ltris
  • OpenTTD - pkgman install openttd_x86
  • Pipepanic - pkgman install pipepanic
  • Road Fighter - pkgman install roadfighter
  • Rocks’n’diamonds - pkgman install rocksndiamonds_x86
  • SDL Lopan - pkgman install sdllopan
  • Slime Volley - pkgman install slime_volley
  • Super Transball 2 - pkgman install super_transball
  • XRick - pkgman install xrick

» Leer más, comentarios, etc...

Variable not found

¿Dónde se añaden los filtros globales en MVC 6 / ASP.NET 5?

June 30, 2015 06:45 AM

ASP.NET MVCDesde la versión 3 de ASP.NET MVC, los filtros globales nos han solucionado con facilidad la anteriormente ardua labor de definir filtros en todos los controladores y acciones de nuestra aplicación sin tener que introducirlos uno a uno o crear controladores base.

Por convención, los registrábamos en una clase llamada FilterConfig, habitualmente ubicada en la carpeta /App_Start del proyecto, y cuya pinta era más o menos la siguiente:

Filtro global en MVC 5 y anteriores

Este código era llamado durante la inicialización de la aplicación desde el evento Application_Start() del archivo Global.asax:

Evento Application_Start()


Como sabemos, en MVC 6/ASP.NET 5 el Global.asax ha desaparecido para no volver, y, si profundizamos un poco, veremos que tampoco existe el tipo GlobalFilterCollection, ni la clase estática FilterConfig que antes daban soporte a esta característica.

¿Y a dónde ha ido a parar todo esto en el nuevo MVC 6? Pues, como era de esperar, al tratarse de algo que se realiza durante el arranque, su destino ha sido la clase Startup.

El método ConfigureServices() de esta clase es el punto desde el que se añaden los distintos servicios y componentes usados por la aplicación al sistema de resolución de dependencias de ASP.NET 5, pero, además, al tratarse de un punto muy inicial en la ejecución de la aplicación, lo usaremos también para establecer las configuraciones básicas de algunos componentes, como el framework MVC.

La forma de hacerlo es muy sencilla. En la siguiente porción de código se muestra cómo se añaden los servicios de MVC, y cómo seguidamente añadimos a la colección de filtros globales un filtro RequireHttps para obligar a que el acceso a nuestros controladores se realice siempre sobre el protocolo seguro HTTPS:

Añadiendo filtros globales en MVC 6

Ese método ConfigureMvc() que veis en el código anterior en recibe como parámetro una instancia de la clase MvcOptions, en cuyo interior encontraremos propiedades en las que podemos configurar muchos aspectos de MVC, como los binders, motores de vistas, filtros, proveedores de metadatos, etc. Recordad que en versiones anteriores del framework estas configuraciones se realizaban a través de clases estáticas globales, por lo que ahora queda todo mucho más ordenado y accesible :)

Publicado en Variable not found.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 205

June 29, 2015 07:10 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada, espero que os resulten interesantes :-)

.Net

ASP.NET

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Cross-platform

Otros

Publicado en Variable not found

» Leer más, comentarios, etc...

Variable not found

Variables de sesión en MVC6 / ASPNET5

June 28, 2015 09:49 AM

ASP.NET MVC
Seguimos hablando de novedades que acompañarán la próxima versión de MVC y ASP.NET, y esta vez le toca el turno a otra de los grandes ausencias que podemos notar cuando creamos desde cero una aplicación utilizando estos frameworks: las variables de sesión.

Bueno, en realidad no se trata tanto de una ausencia como de un desplazamiento de esta característica. Resumidamente, las variables de sesión seguirán existiendo, pero no son parte del core de ASP.NET 5, como ocurría desde la primera versión de ASP.NET, sino un componente totalmente opcional implementado en forma de middleware que deberá ser instalado y configurado de forma independiente.

Pero antes de continuar, recordad que tanto MVC6 como ASP.NET 5 siguen estando en proceso de desarrollo, por lo que algunas de las cosas que contaremos podrían cambiar en las versiones definitivas, aunque espero que no demasiado.

Y dicho esto, vamos al lío: ¿cómo utilizamos variables de sesión en aplicaciones basadas en ASP.NET 5?

1. Descarga e instalación del middleware proveedor de sesión

Siguiendo la nueva filosofía modular de ASP.NET 5, los mecanismos de almacenamiento y recuperación de variables de sesión son ahora un componente que podemos añadir a nuestras aplicaciones de forma opcional.

Como es habitual, la descarga e instalación la realizaremos a través del interfaz de Nuget en Visual Studio, o bien añadiendo manualmente la referencia al archivo project.json. El nombre del paquete que nos interesa es Microsoft.AspNet.Session, como se muestra en la siguiente captura de pantalla:

Reference session package

Una vez hecho esto, ya tenemos en nuestro proyecto los componentes básicos que necesitamos para poder usar variables de sesión. Continuamos el proceso…

2. Añadir el middleware al pipeline

Session middleware in the pipelineEl estado de sesión es proporcionado por el middleware SessionMiddleware, presente en el paquete que acabamos de descargar. Este middleware, insertado en el pipeline de proceso de las peticiones, ofrecerá a los frameworks o componentes posicionados tras él la capacidad de usar variables de sesión.

El hecho de posicionarse en el pipeline y ser “atravesado” por la petición brinda a este middleware la posibilidad de establecer la cookie de sesión que distinguirá de forma única al usuario, preparar el acceso a sus datos y almacenar los cambios producidos durante el proceso de la petición.

Y ojo, que esto es importante: hay que añadir el middleware que proporciona el estado de sesión antes que el propio framework MVC. De no ser así, la petición será procesada por MVC antes de el middleware de sesión sea ejecutado, por lo que desde nuestras aplicaciones no tendremos acceso a las variables de sesión.

El siguiente ejemplo muestra cómo introducir el middleware en el pipeline, utilizando la memoria como almacenamiento para el estado de sesión:

UseInMemorySession

En aplicaciones pequeñas y sin demasiadas aspiraciones, almacenar las variables de sesión en memoria es una solución efectiva y razonable. Sin embargo, cuando la aplicación debe crecer a varios servidores o se necesita una solución menos volátil, podemos usar otros mecanismos de persistencia, utilizando el extensor UseDistributedSession() en lugar de UseInMemorySession() visto anteriormente. No entraremos en más detalle en este post, lo dejaremos para más adelante, pero es muy interesante el hecho de que esto descanse sobre el sistema de caching de ASP.NET, del que ha hablado el gran Unai hace poco.

Como suele ser habitual a la hora de añadir módulos al pipeline, es posible indicar opciones de configuración:

Middleware options

3. Establecer, obtener y eliminar variables de sesión

En primer lugar, es importante tener en cuenta que los pasos anteriores son obligatorios si queremos utilizar variables de sesión. Cualquier intento de utilización de las mismas sin haber instalado y configurado previamente los componentes que las proporcionan provocarán la aparición de un error:

Error trying to use Session vars without installing or configuring the middleware

El acceso a las variables de sesión se realiza utilizando la propiedad Context.Session, es decir, la clase Controller no proporciona ya una propiedad Session como en versiones anteriores de MVC, aunque obviamente siempre podríamos crearnos un atajo (por cierto, fijaos qué limpio queda usando las nuevas expresiones lambda en miembros de función de C# 6):

Session property
Los que ya habéis usado antes variables de sesión, seguro que os sorprende esos métodos GetInt() y SetInt() de la propiedad Session. Pues sí, esto otro cambio importante sobre las versiones anteriores del framework.

Hasta ahora podíamos introducir cualquier tipo de objeto en variables de sesión, y el abuso de esta capacidad ha generado muchísimos problemas. He llegado a ver incluso contextos de datos o conexiones a bases de datos mantenidas en memoria de esta forma, creando unos problemas terribles en tiempo de ejecución. También ha sido tradicionalmente un limitante de la posibilidad de escalado de las aplicaciones (aunque puede solventarse usando algunos trucos de balanceado), y un problema para la fiabilidad  de los sistemas (recordad que un reseteo del servidor, de IIS o incluso un reciclado del pool limpia la memoria).

Session vars are byte arraysPara evitar esto, a partir de ASP.NET 5/MVC 6 sólo podremos guardar en variables de sesión objetos serializados, y esto se manifiesta en el tipo de dato que es ahora el diccionario Session: un array de bytes. Con esto, se acabó el establecer o leer objetos completos directos como hemos hecho siempre, tendremos que serializarlos a un array de bytes para guardarlos el almacén de sesión, así como deserializarlos para poder acceder a ellos. De esta forma, simplificamos el uso de almacenamientos distintos a la memoria local para esta información, facilitando la escalabilidad y mejorando la fiabilidad.

El framework nos proporciona métodos extensores para facilitar las tareas de serialización y deserialización en escenarios comunes, como el almacenamiento y recuperación de variables de sesión de tipo entero y cadenas de texto, mediante los métodos GetInt(), SetInt(), GetString() y SetString(), como se muestra en el siguiente ejemplo:

Session extensions

Si por cualquier motivo queremos guardar un objeto o grafo complejo, tendremos que crear nuestro propio mecanismo de serialización. Aunque la primera tentación puede ser crear un serializador binario usando la clase BinaryFormatter de toda la vida, resulta que la serialización binaria no está soportada en .NET Core, supongo que debido al carácter cross platform de este framework.

Pero sí podríamos, por ejemplo, serializarlo a JSON y guardarlo como string en la variable de sesión y realizar el proceso inverso al recuperar el valor, o bien crear nuestras propias funciones extensoras para facilitarnos la vida en el futuro:

Serialization helpers

Así, ya podríamos usar construcciones más sencillas como las siguientes:

Helper usage

Nota: existen conversaciones en Github sobre la inclusión de métodos genéricos Set<T>() y Get<T>() que permitan indicar un componente de serialización como Protobuf o Bond, así que posiblemente las versiones finales de ASP.NET 5/MVC 6 encontremos algo de ello.

Por otra parte, para eliminar variables de sesión podemos seguir utilizando el método Remove(), al igual que hemos hecho siempre:

Context.Session.Remove()

4. Otros cambios respecto a versiones anteriores

Por último, vamos a comentar un par de detalles que han sido modificados respecto a versiones anteriores de ASP.NET.

Comenzaremos diciendo que en ASP.NET 5 no existe (al menos de momento) un método Abandon(). En cambio, se añade un método Clear() que permite eliminar toda la información de sesión del usuario conectado.

Y una última cosa interesante a tener en cuenta es que ya no están disponibles los eventos Session_Start() y Session_End() que podíamos capturar en el Global.asax en versiones anteriores del framework.

Bueno, pues de momento lo dejaremos aquí. Espero que lo visto os sea de utilidad para continuar interiorizando los cambio que se avecinan con las nuevas plataformas y que la transición a ellas sea un poco menos dolorosa ;)

Publicado en Variable not found.

» Leer más, comentarios, etc...

Blog Bitix

Hemeroteca #7

June 27, 2015 08:00 AM

Pasado un nuevo semestre he escrito principalmente sobre temas de programación, Java y poco sobre Linux o software libre. Incluyo aquí el listado completo de los artículos que he escrito.

Otros seis meses que han pasado y estos especialmente para mi muy rápido. Como suelo hacer cada este periodo de tiempo recopilo en un artículo Hemeroteca los artículos que he publicado al ritmo que mantengo de uno por semana. Este ya es el séptimo contando los de El blog de pico.dev y de Blog Bitix.

Como resumen de estas 26 semanas he publicado 27 artículos destacando que he cambiado de herramienta con la que mantengo la bitácora pasando de usar Octopress a Hugo que me ha permitido cambiar el diseño completamente personalizándolo enteramente a mi gusto y agregar algunas nuevas funcionalidades como un mejor previsualizador de imágenes, resúmenes al inicio de los artículos, o un nuevo menú con las categorías principales de las que escribo. De lo que más he escrito ha sido sobre programación y como no pueden faltar en este blog algún artículo sobre Apache Tapestry.

De los artículos que he escrito destacaré los siguientes, son con los que más a gusto he quedado después de escribirlos y me parece que merecen una lectura, por orden cronológico:

El resto de artículos son los siguientes, también interesantes:

Cada mes sigo aumentando ligeramente o manteniendo el número de visitas del mes anterior, la mayoría procedentes del buscador Google. En enero andaba en unas 1125 sesiones y 1400 páginas vistas semanales, hoy en unas 1450 sesiones y 2000 páginas vistas, siguen siendo pocas comparadas con algunos otras bitácoras de temática similar. De vez en cuando tengo algún nuevo seguidor en twitter y son pocos los comentarios que recibo probablemente esté haciendo algo que podría hacer mejor. Los artículos que publico suelen ser para un público de nivel medio y uno a la semana, recomiendan escribir artículos de un nivel básico y probablemente si siguiese esta recomendación recibiría más visitas o más comentarios pero me suele gustar escribir de algo que incluso yo aprenda algo y que no esté ya en un millardo de sitios y sea medianamente fácil de encontrar con una búsqueda sencilla, aunque igual me planteo de vez en cuando seguir esta recomendación.

Evolución de sesiones semanales en Blog Bitix

Sigo teniendo pendiente de publicar unos cuantos nuevos artículos que continúen la serie sobre Docker que ya publiqué, también tengo más artículos preparados sobre programación con Java y bastantes ideas ya listadas para seguir escribiendo. Pero si te interesa un determinado tema y quisieras que explicase o hablase de algo relacionado con lo que suelo escribir añade un comentario y trataré de ver si me es posible, ¡comenta, pregunta lo que quieras o hazme la recomendación que estés pensando!.

Para finalizar agradecer a varios usuarios de twitter que aunque no conozco suelen compartir muchos de los artículos que escribo y me ayudan enormemente a hacer que el contenido de Blog Bitix llegue a más personas. Joaquin Bravo, Diego Saavedra, Camilo Bernal, A. Daniel Pereyra y otros en la linea de tiempo de Blog Bitix, ¡gracias!.

» Leer más, comentarios, etc...

Arragonán

Semana 367

June 26, 2015 11:52 AM

Casi se me solapan de nuevo las semanas, a buenas horas escribir en viernes la retro de la semana anterior…

La semana pasada estuvo marcada por el viaje a Gijón con motivo de Agile Open Space 2015. Como viene siendo habitual en los últimos AOS, quería aprovechar el viaje para tener unas micro-vacaciones y hacer algo más que asistir al Open Space. Este año fuimos un grupo bastante majo los que nos juntamos desde el grupo de Agile Aragón como avanzadilla, en plan almogávares. Fue todo un acierto el contratar una sesión de iniciación a surf, nos lo pasamos genial y terminamos exhaustos, yo desde luego que repetiré en cuanto tenga otra oportunidad.

Ya en cuanto al AOS, como me da pereza hacer un resumen yo mismo y tampoco tomé notas, os recomiendo que os leáis los resúmenes de Néstor Salceda y Eduardo Ferro, coincidimos en bastantes sesiones y comparto gran parte de las opiniones expresadas por ellos.

Este año creo que elegí mejor mis sesiones e hice mejor uso de mis dos pies para moverme entre ellas que la edición previa. Mis criterios eran más o menos estos:

  • Evitar sesiones introductorias.
  • El facilitador que proponía la sesión.
  • Descartar las que no entendía de que iban.
  • Las personas que hay en la sala de la sesión.
  • La temática.
  • Buscar sesiones más técnicas.

Y aunque me parecieran interesantes, tampoco es que me apasionara ninguna de las sesiones a las que asistí. Charlando con algunos amigos por los pasillos vi que no era sólo cosa mía, supongo que algunos ya no encontramos la frescura que tenían nuestros primeros AOS.

Y bueno, de vuelta a mis cosas, la semana pasada llegaron un par de leads para nuevos proyectos con clientes para los que ya hemos trabajado. Aparte de eso poca cosa la semana pasada:

  • Estuve en las oficinas de un cliente trabajando en temas de documentación técnica.
  • Empezamos a centrar el tiro de la integración de un partner con minchador.

Buen finde.

» Leer más, comentarios, etc...

Variable not found

Inyección de dependencias en filtros MVC 6

June 23, 2015 06:45 AM

ASP.NET MVCLos filtros de MVC, o action filters, han sido potenciados en la versión 6 del framework añadiéndoles características que en versiones anteriores no estaban disponibles de serie en la plataforma pero que han sido muy solicitadas por los desarrolladores. Hace algún tiempo vimos una de ellas, los filtros asíncronos, y hoy veremos que la inyección de dependencias en filtros también es ya una realidad.

El problema con la inyección de dependencias en los filtros es la instanciación de éstos, pues al definirse en forma de atributos de .NET no puede realizarse de forma controlada, o al menos lo suficientemente controlada como para poder inyectarles parámetros en el constructor o cargar sus propiedades desde un contenedor de inversión de control. Y aunque los filter providers aportaron alguna solución vía los contenedores IoC más populares, aún no eran una solución todo lo limpia que debería ser.

Pero como decía David Wheeler, “Cualquier problema en ciencias de la computación puede ser solucionado con otro nivel de indirección”… y eso mismo han debido pensar la gente del equipo de ASP.NET en Microsoft, cuando la solución que han dado consiste, básicamente, en crear un filtro capaz de instanciar otros filtros usando el contenedor de servicios integrado :)


Veámoslo con un ejemplo. El siguiente ejemplo implementa un filtro asíncrono de MVC 6 cuya misión es almacenar en un log las acciones ejecutadas por los usuarios:



Observad que el almacenamiento del log se realiza utilizando un servicio externo, una instancia de IUserLoggingServices inyectada en el constructor del filtro.

Este filtro no podemos aplicarlo directamente sobre nuestras acciones o controladores, pues el framework no podría crear una instancia satisfaciendo sus dependencias. Lo que tenemos que hacer en este caso es registrarlo en el contenedor de dependencias de ASP.NET 5, tarea que se hace en el método ConfigureServices() de la clase Startup:

Configuración de servicios en la clase Startup

En esta porción de código fijaos estamos registrando también la clase IUserLoggingServices para asegurar que la dependencia de nuestro filtro pueda resolverse correctamente.

Por último, ya sólo tenemos que aplicar el filtro a los controladores o acciones que nos interesen. Para ello, en lugar de hacerlo directamente, utilizaremos el filtro ServiceFilter, que actuará como factoría creando la instancia del filtro que le suministremos como parámetro, utilizando el contenedor de dependencias.

Uso de ServiceFilter en un controlador

Y eso es todo :) Como hemos podido ver, algo que en versiones anteriores era bastante complicado, o incluso imposible, como la inyección de dependencias en constructores de filtros, tiene solución trivial en el nuevo MVC 6 / ASP.NET 5.

Publicado en Variable not found.

» Leer más, comentarios, etc...

Poesía Binaria

Scripts multilingües en bash con gettext / Traducciones en scripts

June 22, 2015 08:56 AM


Hace tiempo, empecé un proyecto en el que comparto algunos scripts que utilizo para hacerme la vida un poco más fácil. En esta colección, encontramos algunos scripts que ejecutaremos desde consola, y otros que, suelo tenerlos vinculados a una tecla rápida para ejecutarlos más rápidamente. El caso es que, los mensajes que se muestran en pantalla a través de diálogos suelo ponerlos en español, pero me gusta compartirlos con el mundo, y comprendo que cada uno quiera verlo en su idioma.

Bien, pues tal y como hacíamos en C y en PHP, ahora le toca el turno a nuestros scripts de Bash.

En este ejemplo, incluyo algunos consejos y soluciones a problemas que me he encontrado en el proceso.

Lo primero que se me ocurre

Bueno, lo primero que se nos pasa por la cabeza es meter los mensajes en variables, y, dependiendo del idioma cargar uno u otro archivo de mensajes:
es.sh

1
2
MENSAJE1="MENSAJE 1"
MENSAJE2="MENSAJE 2"

en.sh

1
2
MENSAJE1="MESSAGE 1"
MENSAJE2="MESSAGE 2"

test.sh

1
2
3
4
5
LCN=`locale | grep LC_NAME | cut -d'=' -f2 | cut -d'_' -f1`

. $LCN.sh

echo $MENSAJE1

El problema que tiene esto, es que, queda un poco como cogido con pinzas, parece que en cualquier momento va a fallar y no tiene pinta de ser muy estable. Además, el mantenimiento es incómodo, tienes que saber los nombres de las variables y luego tienes que hacer que se correspondan los mensajes.

Solución con gettext

La solución con gettext es mucho más larga, bueno, vamos a ver, es algo más larga pero mucho más fácil de mantener que la anterior. No tenemos que mantener los nombres de las variables, tenemos en cuenta directamente el mensaje y nos basamos en él.
Eso sí, tenemos que tener un fichero de traducciones aparte, bueno, antes teníamos ficheros sh, ahora tendrán una ruta y nombre específico; y en el resto del post veremos poco a poco cómo construirlo.
Aunque en posts anteriores he puesto alguna forma de hacerlo, aquí voy a empezar desde cero con un método nuevo (para que tengamos variedad, y para no hacer que nadie tenga que visitar otro post para conseguir una parte de la información y luego volver).

Nuestro programa: preparando el entorno

A la hora de crear nuestro programa, a mi me gusta crear un archivo “common.sh” (lo podéis llamar como queráis) situado en el mismo directorio del script, donde almacenamos funciones y variables que no tienen que ver con nuestro script propiamente dicho, son generales, en este caso, relativas a las traducciones (voy paso a paso, si sois impacientes, id al final del post, pero mientras voy poniendo experimentos):

common.sh

1
2
3
4
5
6
7
#!/bin/bash

function __()
{
    ARGS=$@
    echo "$ARGS"
}

multilin.sh

1
2
3
4
5
6
7
#!/bin/bash

SCRIPT_SOURCE=`dirname $BASH_SOURCE[0]`
. $SCRIPT_SOURCE/common.sh

echo $(__ "This is a message for you")
echo $(__ "This is another message for you")

¡Valiente tontería acabo de hacer! Pero quiero que esto vaya tomando forma. He creado una función __ que me servirá para introducir mensajes, y esta función se encargará de traducirlos. Todavía no, ahora mismo hace un echo y listo, ya llegaremos a las traducciones en el siguiente paso.

Por otra parte, en mi script, lo único que tendré que hacer es llamar al common.sh (las dos líneas nos servirán para ubicar el directorio donde se encuentra el archivo (y con ello, ubicar common.sh que está en el mismo directorio), e incluirlo en nuestro script.

Lo siguiente será que, cada vez que quiera escribir un mensaje, debo introducirlo entre $(__ mensaje), es decir, llamaré a la función que está en common que me devolverá la traducción.

Generando el archivo de mensajes

Ahora tenemos que generar un archivo que contenga todos los mensajes que se encuentran en nuestro proyecto. Lo primero es crear un directorio para esos mensajes (podemos usar directamente /usr/share/locale/) que es el directorio por defecto, pero prefiero no utilizar el usuario root para nada, por el momento. Así que crearemos un directorio, hijo del directorio donde se encuentran nuestros script:

mkdir -p locale/es/LC_MESSAGES

El directorio locale lo podemos llamar como queramos, por otro lado el directorio es corresponde al idioma de las traducciones, en este caso español, por ejemplo, Francés será fr_FR, alemán, de, etc. El directorio LC_MESSAGES hay que dejarlo como está, no nos queda otra, porque lo que vamos a modificar serán los mensajes del programa.

Bueno, a partir de ahora, podemos utilizar los comandos que voy a decir, o utilizar poedit, como en otros posts, que es una herramienta gráfica que nos permitirá hacerlo todo cómodamente.

Desde el directorio de nuestros scripts (por ejemplo), corremos el siguiente programa

$ xgettext -o multilin.pot –from-code=UTF-8 –keyword –keyword=__ *.sh

Nos creará un archivo .pot que podemos editar para rellenar los campos que consideremos oportunos (nombre del proyecto, e-mails, versiones, etc).

Entramos en LC_MESSAGES para crear un archivo de idioma español y ejecutamos:

$ msginit -i ../../../multilin.pot -l es_ES.UTF-8 -o multilin.po

A continuación, se habrá creado multilin.po , es un archivo de texto que podemos editar sin miedo, en el que pondremos los textos traducidos

# Spanish translations for PACKAGE package
# Traducciones al español para el paquete PACKAGE.
# Copyright (C) 2015 THE PACKAGE’S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Gaspar Fernández , 2015.
#
msgid “”
msgstr “”
“Project-Id-Version: PACKAGE VERSION\n”
“Report-Msgid-Bugs-To: \n”
“POT-Creation-Date: 2015-04-04 03:53+0200\n”
“PO-Revision-Date: 2015-04-04 04:18+0200\n”
“Last-Translator: Gaspar Fernández \n”
“Language-Team: Spanish\n”
“Language: es\n”
“MIME-Version: 1.0\n”
“Content-Type: text/plain; charset=UTF-8\n”
“Content-Transfer-Encoding: 8bit\n”
“Plural-Forms: nplurals=2; plural=(n != 1);\n”

#: multilin.sh:6
msgid “This is a message for you”
msgstr “Este es un mensaje para ti”

#: multilin.sh:7
msgid “This is another message for you”
msgstr “Este es otro mensaje para ti”

Y una vez generados todos los mensajes, debemos compilar este archivo, para ello, debemos ejecutar:

$ msgfmt -v multilin.po -o multilin.mo

Una modificación importante a common.sh

Nuestro common.sh quedará parecido a este:

1
2
3
4
5
6
7
8
9
#!/bin/bash

TEXTDOMAINDIR=$SCRIPT_SOURCE/locale

function __()
{
    ARGS=$1
    gettext "multilin" "$ARGS"
}

En lugar de hacer echo directamente, he llamado a gettext con el dominio multilin (que es el que estamos usando para nuestros scripts.

En este momento cuando ejecutemos multilin.sh, lo que mostrará por pantalla será:

$ ./multilin.sh
Este es un mensaje para ti
Este es otro mensaje para ti

Bueno, ya tenemos la traducción automática, ya sólo nos queda mejorar esto un poco más.

Mejoras

common.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
GETTEXT=`which gettext`
DOMAIN="multilin"

if [ -z "`ls -R /usr/share/locale | grep $DOMAIN.mo`" ]; then
    TEXTDOMAINDIR=$SCRIPT_SOURCE/locale
fi

function __()
{
    ARGS=$@

    if [ -z "$GETTEXT" ]; then
    printf "$ARGS"
    else
    LINE="$1"
    shift
    printf "$(gettext "$DOMAIN" "$LINE")" $@
    fi
}

Así quedaría mi common.sh, en este caso, miramos si tenemos la herramienta gettext disponible, porque es posible que el usuario final no la tiene instalada, y no podemos ponernos a mostrar fallos a cada mensaje en pantalla.

Lo siguiente es saber si el usuario ha instalado los idiomas de nuestra aplicación a nivel de sistema (si es así, esos archivos estarán en /usr/share/locale y usaremos estos. Si no, buscaremos en el directorio de nuestro script (SCRIPT_SOURCE lo definimos en el script multilin.sh).

Ahora, en la función __(), miramos si gettext está disponible, lo utilizamos para mostrar las traducciones (en lugar de usar DOMAIN, podemos utilizar TEXTDOMAIN, que es una variable de entorno de gettext y no tenemos que pasarle nada más, yo prefiero dejarlo así por si en mi proyecto incorporo varios dominios de traducciones.

Podéis ver que en lugar de echo, he usado printf. Y es para poder utilizar cadenas de formato con %s. Así un programa como:

1
2
3
4
5
6
#!/bin/bash

SCRIPT_SOURCE=`dirname $BASH_SOURCE[0]`
. $SCRIPT_SOURCE/common.sh

echo $(__ "You have %d apples and %d bananas" 12 30)

Daría una salida como:

You have 12 apples and 30 bananas

Y si en multilin.po lo traducimos como:

#: multilin.sh:8
msgid “You have %d apples and %d bananas”
msgstr “Tienes %d manzanas y %d plátanos”

Tendremos una salida como:

Tienes 12 manzanas y 30 plátanos

Lo que nos ayuda tremendamente a incrustar valores dentro de nuestras traducciones.

Instalar traducciones en el sistema

Si queremos instalar las traducciones a nivel de sistema, sólo tenemos que hacer esto:

$ sudo install locale/es/LC_MESSAGES/multilin.mo /usr/share/locale/es/LC_MESSAGES/multilin.mo

Así con cada idioma.

The post Scripts multilingües en bash con gettext / Traducciones en scripts appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 204

June 22, 2015 07:08 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada, espero que os resulten interesantes :-)

.Net

ASP.NET

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data access

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

» Leer más, comentarios, etc...

Koalite

Liebres, tortugas y zorros

June 22, 2015 05:06 AM

Llego a través del blog de Jose María Arranz a un post sobre tres tipos de desarrolladores con respecto a la adopción de nuevas tecnologías. Esto de clasificarnos no es algo nuevo, de hecho es una de las cosas que más nos gusta hacer (deformación profesional, supongo), y hay muchas clasificaciones diferentes. Personalmente, siempre me gustó cómo Microsoft clasificó tradicionalmente a los desarrolladores a través de Mort, Elvis y Einstein, 3 tipos de persona a los que quería dirigir su plataforma.

Jose María habla en su post de tres tipos de desarrolladores:

  • Aquellos obsesionados por utilizar las tecnologías más novedosas y que están más de moda.
  • Los que son más conservadores o escépticos (generalmente personas con más experiencia y/o malas experiencias).
  • Personas interesadas en promover alguna tecnología concreta.

La liebre y la tortuga

Los dos primeros casos podríamos situarlos hacia la izquierda y la derecha de la típica curva de adopción de tecnologías:

DiffusionOfInnovation

El análisis del post original, realizado cómo él mismo dice desde un punto de vista “psedo-psicológico”, me parece bastante acertado. Creo que hay un componente de experiencia, pragmatismo y sensatez, muy importante para saber situarse entre ambos extremos. En general, ser el primero suele ser muy arriesgado pero ser el último puede ser fatal.

Es importante mejorar siempre en lo que hacemos y aprovechar las nuevas tecnologías, pero es aún más importante darnos tiempo para aprenderlas y saber realmente qué podemos sacar de ellas y no dejarnos llevar por la pasión inicial.

En nuestro afan de mantener nuestros sistemas al día no podemos caer en el error de estar continuamente reescribiendo código que funciona sólo porque ya no nos parece tan cool. Destinar recursos a “mejorar” algo que no necesita ser mejorado, es desperdiciar esos recursos.

El zorro

El tercer caso me parece especialmente interesante, tal vez porque cada vez es más frecuente y sobre todo difícil de detectar, por lo que puede acabar siendo peligroso. Se trata de personas que promueven el uso de una tecnología no sólo por sus méritos, sino por otro tipo de intereses.

El caso más típico es cuando llega una consultora líder en el sector y referente a nivel internacional, Mithril Partner por sexto año consecutivo de Megacorp y, curiosamente, la mejor solución para tu problema es utilizar la base de datos de Megacorp, con el servidor web de Megacorp, y la nube de Megacorp.

Es algo perfectamente normal y razonable (todos tenemos que comer, al fin y al cabo). Por suerte, también es algo que todos sabemos juzgar en su contexto por lo que, automáticamente, activamos nuestro sentido crítico para intentar separar los beneficios reales de la tecnología en cuestión del aderezo comercial que hay alrededor.

Hoy en día esto se ha complicado un poco porque la manera de llegar a los usuarios/clientes de una tecnología ha cambiado.

Ahora si me quieren vender que use el lenguaje X, la plataforma Y o la metodología Z, es poco probable que me llame un comercial para intentar convencerme; ahora probablemente me llegará la información a través de twitter, un post en un blog o un evento convenientemente patrocinado y supervisado. Vamos, social media management, content marketing y todas esas cosas en las que ha derivado el cluetrain manifesto.

Aparecen figuras como los embajadores, los evangelizadores (nombre con unas connotaciones horribles, no sé a quién se le ocurrió), los que quieren ser profesionales muy valorados dentro de una comunidad, los fanboys que dirán lo que sea por defender a su empresa/tecnología/plataforma fetiche, los que escribieron un libro, los que imparten un curso o los que pagaron por 3 certificaciones que tienen que aprovechar.

Insisto, tener intereses particulares para promover una tecnología concreta me parece algo completamente lícito (siempre y cuando no caigamos en el engaño para promoverla, claro), y muchas veces esos intereses no interfieren con realizar un excelente trabajo de comunicación y divulgación.

Conozco personalmente bastantes casos de personas que podrían encajar en los roles anteriores y, aun así, su opinión me merece total confianza, creo que mantienen un criterio suficientemente objetivo y que sus conocimientos les avalan.

Pero también he visto demasiados casos de los otros. De los que necesitan hablar bien de una tecnología para cubrir su agenda.

El peligro de estos casos es que, cuando no tienes experiencia suficiente o estás aprendiendo algo nuevo, cuesta analizar en profundidad lo que te están contando, y si el medio por el que te llega es un medio “no oficial”, como un blog personal, una cuenta de twitter o una charla en un grupo de usuarios, es fácil bajar la guardia y no ver que la argumentación sobre esa tecnología no es tan objetiva como debería ser y que hay unos intereses detrás condicionándola.

Conclusión

Lo de siempre: sentido común.

Trata de no correr demasiado detrás de novedades que puede que desaparezcan antes de que te dé tiempo a entrar en producción, pero tampoco te empeñes en usar COBOL para diseñar tu próxima aplicación web.

Y mientras tratas de encontrar el equilibrio entre innovación y estabilidad, mira con perspectiva las opiniones de los demás “usuarios”. Puede que sus intereses no estén tan alineados con los tuyos como pueda parecer.

Imagen de Wikipedia

No hay posts relacionados.

» Leer más, comentarios, etc...

El blog de Adrián Arroyo

Tutorial de CMake

June 21, 2015 10:00 PM

Llevo varios años usando de forma habitual CMake. Sin embargo me doy cuenta que alguien que quiera empezar a usar este sistema va a encontrarse con documentación confusa.

1º Regla de CMake. La documentación puede ser confusa

¿Qué es CMake?

CMake se trata de una herramienta multiplataforma para generar instrucciones de compilación del código. No sustituye a las herramientas de compilación como Make o MSBuild, sino que nos proporciona un único lenguaje que será transformado a las instrucciones del sistema operativo donde nos encontremos. Sería un sustituto de Autotools.

Flujo de trabajo con CMake

Las ventajas son que no tenemos que tener varios archivos para gestionar la compilación. Usando CMake podemos generar el resto. Actualmente CMake (3.2.3) soporta:

  • Unix Make
  • Ninja
  • CodeBlocks
  • Eclipse CDT
  • KDevelop
  • Sublime Text 2
  • Borland Make
  • MSYS Make
  • MinGW Make
  • NMake
  • NMake JOM
  • Watcom WMake
  • Kate
  • CodeLite
  • Xcode
  • Visual Studio (desde el 6 hasta 2013)

Usando CMake

En CMake las configuraciones estan centralizadas por defecto en un archivo llamado CMakeLists.txt. Este se encuentra en la carpeta central del proyecto. Normalmente con CMake los proyectos se construyen en una carpeta diferente de la que tenemos el código fuente. Es corriente crear una carpeta build en lo alto del proyecto. Así si tenemos un proyecto con CMake ya descomprimido haríamos lo siguiente.

mkdir build
cd build
cmake ..
# make o ninja o nmake o lo que toque

También puedes usar la aplicación gráfica. Muy cómoda cuando debamos modificar las configuraciones.

Aplicación gráfica de CMake

Podemos ajustar las variables de CMake desde la interfaz de usuario, usando el modo interactivo de la línea de comandos (cmake .. -i) o usando flags cuando llamamos a CMake (cmake .. -DCMAKE_CXX_FLAGS=-std=c++11)

El archivo CMakeLists.txt

Ya estamos listos para crear nuestro primer archivo de configuración de CMake.

Proyecto de prueba

Vamos a ir viendo distintas versiones del archivo donde voy a ir añadiendo diferentes tareas. Estate atento a los comentarios de los archivos

Compilar como programa main.cpp

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# Indicamos la versión mínima que necesitamos de CMake

SET(MiProyecto_SRC "src/main.cpp")
# Creamos la variable MiProyecto_SRC y le asignamos el valor "src/main.cpp" que es la ubicación de nuestro archivo.
# Por defecto las variables son listas o arrays
# Si tenemos dos archivos sería SET(MiProyecto_SRC "src/main.cpp"
"src/segundo.cpp")
# Se permite multilínea

ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})

# Se creará un ejecutable llamado MiProyecto en Linux o MiProyecto.exe en Windows.
# Se hace referencia a las variables con ${NOMBRE_VARIABLE}.

Y ya está. Si quieres saber las flags que se usaran al llamar al compilador mira algunas variables interesantes

Trabajar con opciones y condicionales

CMake permite ajustar muchas opciones como hemos visto con el asistente gráfico de CMake. Sin embargo no todas las variables se muestran ahí. Solo son modificables las que nosotros marquemos explícitamente. Se usa OPTION()

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(MiProyecto_SRC "src/main.cpp")

OPTION(EXPERIMENTAL_FEATURE "Activar característica experimental" OFF)
# OPTION(NOMBRE_VARIABLE DESCRIPCION_LEGIBLE VALOR_POR_DEFECTO)
# ON/OFF es la pareja de valores booleanos en CMake. TRUE/FALSE también es correcto

IF(EXPERIMENTAL_FEATURE) # El condicional más básico
	LIST(APPEND MiProyecto_SRC "experimental_feature.cpp")
	# Añadimos un elemento a la lista
	# También se puede hacer con
	# SET(MiProyecto_SRC ${MiProyecto_SRC} "experimental_feature.cpp")
ENDIF()

ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})

Usar librería estática

PROJECT(MiProyecto C CXX)
# Podemos marcar opcionalmente los lenguajes para que CMake busque los compiladores
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(MiProyecto_SRC "src/main.cpp")
SET(Lib_SRC "lib/lib.cpp")

ADD_LIBRARY(Lib STATIC ${Lib_SRC})
# El comando es exactamente igual que ADD_EXECUTABLE, pero marcamos si STATIC o SHARED
ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})
TARGET_LINK_LIBRARIES(MiProyecto ${Lib})
# Necesitamos "unir" la librería con nuestro ejecutable
# Si necesitamos una librería tal cual usamos su nombre
# TARGET_LINK_LIBRARIES(MiProyecto pthread)
# Se pueden hacer las llamadas que se quiera a TARGET_LINK_LIBRARIES

Usar librería dinámica

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(MiProyecto_SRC "src/main.cpp")
SET(Lib_SRC "lib/lib.cpp")

ADD_LIBRARY(Lib SHARED ${Lib_SRC})
ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})
TARGET_LINK_LIBRARIES(MiProyecto ${MiProyecto_SRC})

Seleccionar archivos de forma masiva

Usar SET para los archivos es muy fácil de entender, pero es posible que no queramos mantener una lista explícita del código fuente.

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

FILE(GLOB MiProyecto_SRC "src/*.cpp")
# FILE GLOB selecciona todos los archivos que cumplan la característica y los almacena en MiProyecto_SRC
# GLOB no es recursivo. Si lo necesitas, usa GLOB_RECURSE

ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})

Esto tiene un inconveniente y es que CMake no detecta automáticamente si hay nuevos archivos que cumplen la característica, por lo que hay que forzar la recarga.

Copiar, crear, eliminar y descargar archivos

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

FILE(GLOB MiProyecto_SRC "src/*.cpp")

# Copiar archivos
FILE(COPY "MiArchivo.cpp" DESTINATION mi-carpeta)
# COPY usa como destino siempre una carpeta
# Se puede crear con FILE(MAKE_DIRECTORY mi-carpeta)

# Crear archivos

FILE(WRITE "Generado.txt" "Este archivo ha sido generado por CMake\nLos archivos son: ${MiProyecto_SRC}")

# Borrar archivos 

FILE(REMOVE "Generado.txt")
# No es recursivo, REMOVE_RECURSE sí lo es

# Descargar archivos

FILE(DOWNLOAD http://mi-servidor.com/archivo.tar.gz archivo.tar.gz)
# Podemos mostrar el progreso
# FILE(DOWNLOAD http://mi-servidor.com/archivo.tar.gz archivo.tar.gz SHOW_PROGRESS)
# Comprobar la suma MD5
# FILE(DOWNLOAD http://mi-servidor.com/archivo.tar.gz archivo.tar.gz EXPECTED_MD5 LaSumaMD5)
# Usar SSL
# FILE(DOWNLOAD http://mi-servidor.com/archivo.tar.gz archivo.tar.gz TLS_VERIFY ON)
# Guardar la información en un archivo de log
# FILE(DOWNLOAD http://mi-servidor.com/archivo.tar.gz archivo.tar.gz LOG descarga.log)


# Calcular suma de control

FILE(SHA256 archivo.tar.gz VARIABLE_CON_EL_HASH)

ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})

Incluir archivos de cabecera

A veces es necesario incluir archivos de cabecera en localizaciones no estándar

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(MiProyecto_SRC 
"src/main.cpp" 
"src/algo_mas.cpp")

INCLUDE_DIRECTORIES("src/includes")
# Se añade el directorio a la ruta de búsqueda del compilador de turno

ADD_EXECUTABLE(MiProyecto ${MiProyecto_SRC})

Plugins de CMake

CMake es extensible a través de módulos. La instalación por defecto de CMake trae unos cuantos módulos, no obstante, podemos añadir módulos solo para nuestro proyecto. Los módulos tienen extensión .cmake. Normalmente se dejan en una carpeta llamada cmake.

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

LIST(APPEND CMAKE_PLUGIN_PATH "cmake")
# Simplemente añadimos un nuevo lugar a buscar. Veremos como se usan los módulos más adelante

ADD_EXECUTABLE(MiProyecto_SRC "src/main.cpp")

Mostrar información y generar errores

En ciertas situaciones querremos que no se pueda compilar el proyecto. MESSAGE es la solución.

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

MESSAGE("Información relevante")
MESSAGE(STATUS "Información sin relevancia")
MESSAGE(WARNING "Alerta, continúa la configuración y generación")
MESSAGE(SEND_ERROR "Error, continúa la configuración pero no generará")
MESSAGE(FATAL_ERROR "Error grave, detiene la configuración")

ADD_EXECUTABLE(MiProyecto "src/main.cpp")

Condicionales avanzados

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

## Con variables booleanas, es decir, ON/OFF, TRUE/FALSE

IF(NOMBRE_VARIABLE)
	MESSAGE("Algo es cierto")
ENDIF()

IF(NOT NOMBRE_VARIABLE)
	MESSAGE("Algo no es cierto")
ENDIF()

# La estructura completa es algo así

IF(CONDICION)
	
ELSEIF(CONDICION_2)

ELSE()

ENDIF()


# Se pueden aplicar operadores lógicos

IF(CONDICION AND CONDICION_2)

IF(CONDICION OR CONDICION_2)

# Con números y texto

IF(VAR_1 LESS VAR_2) # VAR_1 < VAR_2

IF(VAR_1 GREATER VAR_2) # VAR_1 > VAR_2

IF(VAR_1 EQUAL VAR_2) # VAR_1 === VAR_2

IF(VAR_1 MATCHES REGEX) # Se comprueba la expresión regular

# Además, CMake provee operadores para trabajar directamente con archivos, comandos y ejecutables

IF(DEFINED VAR_1) # ¿Está definida VAR_1?

IF(COMMAND CMD_1) # ¿CMD_1 es un comando de CMake?

IF(POLICY POL_1) # ¿La directiva POL_1 está activada?

IF(TARGET MiProyecto) # ¿Está definido el ejecutable MiProyecto?

IF(EXISTS src/main.cpp) # ¿Existe el archivo src/main.cpp?

IF(src/main.cpp IS_NEWER_THAN src/old/main.cpp) # ¿Es src/main.cpp más nuevo que src/old/main.cpp?

IF(IS_DIRECTORY src/includes) # ¿src/includes es un archivo o una carpeta?

Bucles

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(MiProyecto_SRC
"src/main.cpp"
"src/list.cpp"
"src/algomas.cpp")

FOREACH(Archivo_SRC IN MiProyecto_SRC)
	MESSAGE(STATUS "Procesando archivo ${Archivo_SRC}")
ENDFOREACH()

Submódulos

CMake usa un único archivo, pero quizá nos conviene repartir la configuración de CMake por varias carpetas entre zonas diferenciadas.

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(src)

# src y lib tienen un CMakeLists.txt cada uno

Librerías externas

Una de las características más interesantes de CMake es que es capaz de encontrar librerías externas que necesite nuestro programa. Esta característica se implementa con plugins de CMake. Aquí voy a necesitar wxWidgets.

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

FIND_PACKAGE(wxWidgets) 
# El plugin debe llamarse FindPackagewxWidgets.cmake, este esta incluido en la distribución estándar de CMake
# En grandes librerías como wxWidgets, podemos pedir solo ciertos componentes
# FIND_PACKAGE(wxWidgets COMPONENTS core gl html base net)
# Podemos hacer que CMake no continúe si no encuentra la librería
# FIND_PACKAGE(wxWidgets REQUIRED)
# Si todo va bien, tenemos las variables wxWidgets_FOUND, wxWidgets_LIBRARIES y wxWidgets_INCLUDE_DIR

INCLUDE_DIRECTORIES(${wxWidgets_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(MiProyecto ${wxWidgets_LIBRARIES})

Definiciones

Podemos añadir directivas del preprocesador de C++ con CMake

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_DEFINITIONS(-DPREMIUM_SUPPORT)
# Ahora #ifdef PREMIUM_SUPPORT en el código evaluará como cierto 

ADD_EXECUTABLE(MiProyecto "src/main.cpp")

Dependencias

Se pueden crear árboles de dependencias en CMake

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_EXECUTABLE(MiProyecto "src/main.cpp")
ADD_EXECUTABLE(NecesitaMiProyecto "src/otro.cpp")

ADD_DEPENDENCY(NecesitaMiProyecto MiProyecto)
# NecesitaMiProyecto ahora depende de MiProyecto

Usando Qt

Ejemplo práctico usando CMake y Qt5 que es capaz de usar QML. Soporta archivos QRC de recursos. Requiere los plugins de Qt5

PROJECT(ProyectoQt)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(CMAKE_AUTOMOC ON)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)

FILE(GLOB ProyectoQt_SRC "src/*.cpp")

FIND_PACKAGE(Qt5Core REQUIRED)
FIND_PACKAGE(Qt5Widgets REQUIRED)
FIND_PACKAGE(Qt5Qml REQUIRED)
FIND_PACKAGE(Qt5Quick REQUIRED)

qt5_add_resources(Res_SRC "src/res.qrc")

ADD_EXECUTABLE(ProyectoQt ${ProyectoQt_SRC} ${Res_SRC})

qt5_use_modules(ProyectoQt Widgets Qml Quick)

Usando Java

CMake soporta Java, aunque no maneja dependencias como Maven o Gradle.

PROJECT(ProyectoJava)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

FIND_PACKAGE(Java REQUIRED)
INCLUDE(UseJava)

SET(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.6" "-target" "1.6")

FILE(GLOB JAVA_SRC "src/*.java")
SET(DEPS_JAR "deps/appengine.jar")

add_jar(ProyectoJava ${JAVA_SRC} INCLUDE_JARS ${DEPS_JAR} ENTRY_POINT "PuntoDeEntrada")

Comandos personalizados, Doxygen

En CMake podemos crear comandos personalizados. Por ejemplo, generar documentación con Doxygen

PROJECT(Doxy)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_CUSTOM_TARGET(doxygen doxygen ${PROJECT_SOURCE_DIR}/Doxyfile DEPENDS MiProyectoEjecutable WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generando documentación" VERBATIM )

# Ahora puedes usar "make doxygen"
# Como es un TARGET cualquiera de CMake, puedes usar ADD_DEPENDENCY
# También puedes usar el plugin FindDoxygen para más portabilidad

Archivos de configuración

En Autotools es común usar un archivo con configuraciones en tiempo de compilación. Normalmente se trata de una cabecera con soporte para plantillas. En CMake se puede hacer.

config.hpp.in

#ifndef CONFIG_HPP
#define CONFIG_HPP

#cmakedefine PREMIUM_SUPPORT

/* Si PREMIUM_SUPPORT está definido en CMakeLists.txt, se definirá aquí */

#define AUTHOR @AUTHOR@

/* Se definirá AUTHOR con el valor que tenga CMakeLists.txt de la variable AUTHOR */

#endif
PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(AUTHOR "\"Adrian Arroyo Calle\"")

CONFIGURE_FILE(src/config.hpp.in src/config.hpp)

Instalar

CMake permite instalar también los programas

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_EXECUTABLE(MiProyecto "src/main.cpp")

INSTALL(TARGETS MiProyecto DESTINATION bin/)
# Instala un ejecutable o librería en la carpeta seleccionada. Tenemos que tener en cuenta los prefijos, que son configurables en CMake.
# Si un programa en Linux suele ir en /usr/local/bin, debemos usar bin, pues /usr/local será añadido por CMake automáticamente
INSTALL(FILES ${ListaDeArchivos} DESTINATION .)
# Archivos normales
INSTALL(DIRECTORY mi-carpeta DESTINATION .)
# Copia la carpeta entera, conservando el nombre
# Se permiten expresiones regulares y wildcards
# INSTALL(DIRECTORY mi-carpeta DESTINATION . FILES_MATCHING PATTERN "*.png")

INSTALL(SCRIPT install-script.cmake)
# Un archivo de CMake que se ejecutará en la instalación

INCLUDE(InstallRequiredSystemLibraries)
# Importante si usas Windows y Visual Studio

# Y con esto se puede usar 'make install'

CPack

Pero make install es un poco incómodo. No se puede distribuir fácilmente. Aquí CMake presenta CPack, que genara instaladores. Yo soy reacio a usarlos pues son de mala calidad pero soporta:

  • ZIP
  • TAR.GZ
  • TAR.BZ2
  • TZ
  • STGZ - Genera un script de Bash que ejecutará la descompresión y hará la instalación
  • NSIS
  • DragNDrop
  • PackageMaker
  • OSXX11
  • Bundle
  • Cygwin BZ2
  • DEB
  • RPM

CPack necesita que usemos el comando cpack en vez de cmake

PROJECT(MiProyecto)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ADD_EXECUTABLE(MiProyecto "src/main.cpp")
INSTALL(TARGETS MiProyecto DESTINATION bin)

INCLUDE(CPack)
# Esto servirá para ZIP, TAR.GZ, TAR.BZ2, STGZ y TZ
# Para el resto deberás configurar manualmente unas cuantas variables necesarias
# http://www.cmake.org/Wiki/CMake:CPackPackageGenerators

Usando ensamblador

CMake soporta correctamente GNU ASM. Nasm requiere más trabajo.

PROJECT(gnu-asm ASM C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

ENABLE_LANGUAGE(ASM-ATT)

FILE(GLOB ASM_SOURCES "*.asm")
FILE(GLOB C_SOURCES "*.c")

ADD_LIBRARY(asm STATIC ${ASM_SOURCES})
ADD_EXECUTABLE(gnu-asm ${C_SOURCES})
TARGET_LINK_LIBRARIES(gnu-asm asm)

Algunas variables interesantes

Variable Información
CMAKE_CURRENT_SOURCE_DIR La ruta completa a la carpeta donde se encuentra CMakeLists.txt
CMAKE_MODULE_PATH Las rutas para buscar plugins de CMake
PROJECT_BINARY_DIR La carpeta que se está usando para guardar los resultados de la compilación
CMAKE_INCLUDE_PATH Las carpetas de búsqueda de cabeceras
CMAKE_VERSION Versión de CMake
CMAKE_SYSTEM El nombre del sistema
CMAKE_SYSTEM_NAME El sistema operativo
CMAKE_SYSTEM_PROCESSOR El procesador
CMAKE_GENERATOR El generador usado en ese momento
UNIX Si estamos en Linux, OS X, BSD o Solaris será cierto
WIN32 Si estamos en Windows
APPLE En OS X
MINGW Usando MinGW
MSYS Usando MSYS
BORLAND Usando Borland
CYGWIN Usando Cygwin
WATCOM Usando OpenWatcom
MSVC Usando Visual Studio
MSVC10 Usando Visual Studio 10
CMAKE_C_COMPILER_ID El identificador de compilador de C
CMAKE_CXX_COMPILER_ID El identificador de compilador de C++
CMAKE_COMPILER_IS_GNUCC El compilador de C es una variante de GNU GCC
CMAKE_COMPILER_IS_GNUCXX El compilador de C++ es una variante de GNU G++
CMAKE_BUILD_TYPE La configuración Debug/Release que estamos usando
CMAKE_C_COMPILER La ruta al compilador de C
CMAKE_C_FLAGS La configuración del compilador de C
CMAKE_C_FLAGS_DEBUG La configuración del compilador de C solo si estamos en la configuración Debug
CMAKE_C_FLAGS_RELEASE La configuración del compilador de C solo si estamos en la configuración Release
CMAKE_SHARED_LINKER_FLAGS La configuración del compilador para librerías compartidas
BUILD_SHARED_LIBS Por defecto en ADD_LIBRARY, las librerías son compartidas. Podemos cambiar esto

Muchas más en la wiki de CMake

RPath

El RPath es importante en los sistemas UNIX. Se trata de cargar librerías dinámicas que no están en directorios estándar.

SET(CMAKE_SKIP_BUILD_RPATH  FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 
SET(CMAKE_INSTALL_RPATH "$ORIGIN")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

Esto hará que los ejecutables construidos en UNIX puedan cargar librerías desde la carpeta donde se encuentran. Al estilo Windows.

» Leer más, comentarios, etc...

Variable not found

Acceso tipado a settings en ASP.NET 5

June 21, 2015 12:20 PM

ASP.NET 5La verdad es que el nuevo sistema de configuración de ASP.NET 5 tiene bastante buena pinta. Es potente, muy flexible y es bastante fácil de extender si tuviéramos necesidad de hacerlo.

Independientemente del proveedor que elijamos para almacenar los settings (un archivo JSON, un .INI, o el que sea), el acceso a la información siempre se realiza utilizando una cadena de caracteres hasta llegar al valor deseado de la configuración, como podemos observar en el siguiente ejemplo:



Sin embargo, esto puede ser una fuente de problemas, pues obviamente estas cadenas no son sometidas a ningún tipo de control en compilación y cualquier cambio de estructura o nombre de setting en el archivo de configuración podría provocar comportamientos incorrectos en nuestra aplicación.


Por ejemplo, si en algún momento decidiéramos cambiar “Name” por “FullName” en el archivo de configuración, nos veríamos obligados a buscar en toda la aplicación las apariciones de caracteres como “AppSettings:Name” y sustituirlos por “AppSettings:FullName”. Pero lo que es peor, tendríamos que acordarnos de hacerlo, y esto sí que es difícil ;)

Existe una fórmula muy sencilla para conseguir acceso tipado a las configuraciones de la aplicación utilizando el sistema integrado de inyección de dependencias de ASP.NET. Para ello, lo primero que tenemos que hacer es crear una clase cuyas propiedades coincidan con los settings de la aplicación, como la siguiente:

AppSettings en la carpeta Propertiesimage

Por supuesto, el nombre de la clase puede ser el que más nos guste, en el ejemplo usamos AppSettings sólo por recordar viejos tiempos ;) Curiosamente, en la plantilla de aplicación web ASP.NET 5 esta clase aparece definida en la carpeta “Properties” del proyecto, como se aprecia en la captura de pantalla lateral, supongo que por mantener una cierta semejanza con las versiones anteriores de ASP.NET. Pero realmente no hay necesidad de hacerlo así y podemos ubicar la clase en la carpeta que estimemos oportuna.

A continuación, en el método ConfigureServices() de la clase Startup, registramos la clase AppSettings para hacerla accesible utilizando el motor de inyección de dependencias. Observad que en la llamada a Configure() especificamos el nodo en el que podemos encontrar los valores de los settings que poblarán automáticamente las propiedades de nuestra clase:

Registro de AppSettings

Actualizado 20/06/2015: en la beta5, GetSubKey() ha sido renombrado a GetConfigurationSection().

Pero en realidad esto no registra realmente la clase AppSettings en el contenedor de dependencias, sino el tipo IOptions<AppSettings>. Es un detalle a tener en cuenta porque es el tipo que tendremos que utilizar cuando desde nuestra aplicación necesitemos acceder a los datos de configuración utilizando cualquiera de los “sabores” de inyección de dependencias disponibles. El tipo IOptions<T> es un interfaz definido en el espacio Microsoft.Framework.OptionsModel y su miembro más interesante es la propiedad Options, a través de la cual accederemos las propiedades del objeto AppSettings, que contendrá los valores obtenidos automáticamente desde el archivo de configuración.

Así, podríamos obtener un objeto IOptions<AppSettings> como parámetro inyectado en el constructor de un controlador, y usarlo para tener acceso tipado a los settings:

Uso de settings desde acciones

O bien utilizar inyección de propiedades, también  nivel de clase controladora:

Uso de settings desde acciones

Incluso inyección de parámetros en acciones, por si sólo necesitamos acceder a la instancia de AppSettings desde una acción concreta:

Uso de settings desde acciones

Y como en las vistas también está disponible la inyección de dependencias, podríamos incluso llevar allí el acceso a settings de la aplicación, de forma bastante limpia:

Acceso a settings desde vistas

¡Eso es todo! Espero que os sea de utilidad para seguir conociendo los cambios que se nos vienen encima, esta vez relativos a la forma de acceder a los parámetros de configuración de nuestras aplicaciones :)

Y ah, que ya se me olvidaba: recordad que ASP.NET 5 está aún en el horno, y parte de lo dicho en este post podría aún cambiar conforme avance su desarrollo.

Publicado en Variable not found.

» Leer más, comentarios, etc...

Blog Bitix

Servicio para obtener ratios de conversión entre divisas

June 20, 2015 08:00 AM

¿Trabajas con importes en diferentes divisas y necesitas hacer conversiones entre ellas? Si es el caso necesitas obtener los ratios de conversión entre divisas de alguna fuente de forma regular y de forma automatizada ya que se varían constantemente (en minutos) según diversos factores. Hay diferentes fuentes para obtenerlos y empresas que ofrecen las cotizaciones como producto, en este artículo comentaré una con suficiente detalle como para integrarla en cualquier aplicación.

Java

En una aplicación de comercio electrónico que venda sus productos o servicios a nivel internacional probablemente necesitará mostrar los precios en la moneda local del comprador. En estos casos será necesario hacer una conversión entre la divisa en la que está el importe del producto y la divisa del usuario con la que realizará el pago. Para hacer la conversión necesitaremos un ratio de conversión reciente entre la divisa origen y la divisa destino del importe o pivotar sobre una divisa entre ambas. Los ratios se actualizan constantemente cada día según diversos factores variando ligeramente su cotización en la economía global. En este artículo presentaré Open Exchange Rates, el mejor servicio de ratios de divisas que he encontrado.

Open Exchange Rates dispone de una API REST que podemos utilizar para automatizar la obtención de los ratios de conversión en nuestra aplicación, ofrecen los ratios para 165 divisas por supuesto incluyendo algunas dólares americanos (USD), euros (EUR), libras (GBP), yenes (JPY), rublos (RUB), países del este de europa, países asiáticos, latinoamericanos y del oriente medio. Para acceder a la API deberemos registrarnos momento en el que se nos proporcionará un identificativo para nuestra aplicación que usaremos al realizar consultas.

En el plan gratuito nos ofrecen los ratios respecto a USD, esto es, una dólar norteamericano equivale al valor del ratio en la moneda en concreto, en el momento de escribir el artículo la API devuelve los siguientes datos, en la que se ve que un USD ($) equivale a 0.880435 EUR (€). Disponemos de varios endpoints:

  • latest.json: para obtener los ratios de conversión más recientes.
  • historical/YYYY-MM-DD.json: para obtener los ratios de un día específico.
  • currencies.json: para obtener la lista de divisas y sus descripciones.
  • time-series.json: para obtener datos históricos durante un periodo de varios días.

Usando el primero de ellos junto con el api-key que nos han asignado https://openexchangerates.org/api/latest.json?app_id=[api-key] obtenemos los ratios en formato JSON, en el dato base está la divisa de referencia, en este caso dólares estadounidenses (USD):

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/88512f73b61bc11a2da4/raw/latest.json">latest.json</pre></a></noscript>

Estas son las 165 divisas soportadas:

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/88512f73b61bc11a2da4/raw/divisas-soportadas.txt">divisas-soportadas.txt</pre></a></noscript>

Teniendo esta API podemos automatizar en nuestra aplicación la obtención de los ratios con un límite de 1000 consultas al mes en el plan gratuito, por ejemplo una vez al día o cada seis horas dependiendo del grado de precisión que nos parezca suficiente para la aplicación. En los planes de pago disponibles las posibilidades de la API son más permitiendo por ejemplo aumentar el límite de consultas, obtener los ratios referenciados a otra moneda distinta al dólar estadounidense u otras consultas y funcionalidades.

Basta usar la librería cliente de Apache HttpComponents para hacer la petición HTTP y un parseador JSON como JSON in Java para acceder a los datos obtenidos.

Hay otras posibilidades como un servicio proporcionado por el banco central europeo pero que ofrece únicamente los ratios de 28 monedas y que solo se actualiza diariamente. Otra posibilidad es Yahoo Finance, en el parámetro de este enlace indicamos primeramente el código de la moneda origen y el código de la divisa destino en este caso de EUR a USD pero Open Exchange Rates me ha parecido mejor y de mayor confianza.

Referencia:
Open Exchange Rates
How do I get currency exchange rates via an API?
European Central Bank Rates

» Leer más, comentarios, etc...

Picando Código

Cerveza de DATA

June 18, 2015 02:00 PM

Este mes el Café de DATA cambia de nombre y se hace Cerveza de DATA. Durante un sábado vamos a trabajar en un proyecto que une dos de mis pasiones: Datos Abiertos y Cerveza Artesanal.

Es algo similar a un proyecto que se nos ocurrió en la primera o segunda Ruby Conf Uruguay con algunos programadores de la vuelta que llamamos “RuBeer” pero nunca tomó impulso. Esta vez se va a desarrollar un poco más organizado y con más posibilidades de éxito (y de que se termine el proyecto 😛 ).

La cita es el sábado 27 de junio a partir de las 15:00 en las oficinas de Crafted: Bulevar España 2529 esquina Libertad, Montevideo. Si quieren asistir, visiten la página de Meetup para inscribirse al evento.

A continuación les dejo más información:

Cerveza de DATA

DATA, Mirá Mamá y Underground Beer Club (UBC) convocan a la comunidad para crear un mapa que nos ayude a encontrar los lugares donde se hace, sirve o vende cerveza artesanal uruguaya.

Los insumos:

Igual que para hacer buena cerveza, vamos a precisar los mejores ingredientes. Por eso, la comunidad cervecera a través de UBC nos va a proveer datos como:

  • Productores (contacto, ubicación, web, abierto al público, compra, horario)
  • Cervecerías (contacto, ubicación, web, horario)Puntos de venta (contacto, ubicación, web, horario)
  • Marcas y estilos (datos etiqueta, descripción, producción si/no)
  • Calendario de eventos

El plan:

Desarrollar una webapp que permita geolocalizar al usuario, mostrándole las plantas, cervecerías (bares) y puntos de venta (almacenes, supermercados) donde se puede conseguir cerveza artesanal. Mostrar algo de detalle de esos lugares e idealmente, las variedades que hay en cada uno.

Ese es el objetivo mínimo. Hay mil ideas más para sumar, que las haremos en la medida que nos de el tiempo, las ganas y por supuesto, el apoyo de quienes se sumen al proyecto.

Se busca:

Este proyecto necesita gente con ganas de sumarse y destinar algo de su tiempo libre durante el sábado 27 y algunos ratos extra en las semanas siguientes, que seguramente seguiremos puliendo detalles vía web. Todo por la excelente causa de facilitarnos a todos encontrar más y mejor cerveza artesanal, allí donde se encuentre en Uruguay.

Precisamos gente con muchos talentos, como:

  • Desarrollo web/HTML/Javascript
  • Trabajo con mapas
  • Diseño web/maquetado
  • Migrar la app web a iOS/Android (soñar es gratis…)

¿Qué va a pasar el sábado?

Vamos obviamente a trabajar en la app, aunque es probable que no terminemos el mismo sábado. El objetivo es acordar el plan, dar los primeros pasos y marcar cómo avanzamos de ahí en adelante. Quienes quieran y puedan comprometerse para seguir, seguiremos en contacto mediante Slack para terminar el proyecto y lanzarlo.

Más allá de la app el sábado vamos a trabajar en pulir y publicar los datos como datos abiertos, previendo también una forma sencilla de mantenerlos actualizados por nosotros, con la colaboración de los cerveceros artesanales.

La pregunta que todos se están haciendo:

¡Claro que va a haber cerveza! Vamos a disfrutar de Birra Bizarra de barril, acompañando la jornada.

Ok me convencieron…

Podés empezar a participar ya mismo, comentando este documento, donde estamos recopilando ideas, recursos, etc. Ahí mismo podés pedir para sumarte a nuestro canal de Slack donde estamos peloteando el proyecto.

http://bit.ly/cervezaDATA

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Historia de Northwest/Datalight/Zortech/Zorland/Symantec/Digital Mars C/C++

June 17, 2015 11:33 AM

Tras mucho tiempo sin publicar nada acerca de la historia de clásicos entre los entornos de la programación, hoy os obsequio con un gran desconocido. Se trata de Symantec C++, el compilador de C/C++ del gigante americano, que históricamente destacó por lo compacto de sus ejecutables, y la excelente velocidad de compilación. La historia, está muy ligada a la de Walter Bright, el programador que lo desarrollara inicialmente como Northwest C sobre Northwest Software, luego como Datalight C / Datalight Optimum-C como Datalight, después como Zorland C como Zorland Ltd, posteriormente como Zortech C/C++ como Zortech Ltd / Zortech International Ltd, después como Symantec C++ como Symantec, y por último como DMC C++ como Digital Mars. Sin lugar a dudas, uno de los entramados más compejos con los que me he topado. * Northwest C. Se menciona 1985 como fecha, pero no queda claro si llegó a comercializarse. * Datalight [...]

» Leer más, comentarios, etc...

Picando Código

Scala Meetup Montevideo – Lift Aplicado

June 16, 2015 02:04 PM

Scala MeetupEste jueves 18 de junio hay un nuevo meetup de Scala en Montevideo a partir de las 20:00. El lugar es PyxisBulevar España 2511, esquina Libertad, Montevideo.

Sobre la charla

Lift es un framework para hacer aplicaciones web en Scala que conviven bien con el ecosistema Java Enterprise. Se distingue por su atencion a aspectos como la seguridad, excelente soporte para Comet y Ajax, facilidad para la interaccion con diseñadores web y otros.

En esta charla, de nivel introductorio, te mostramos como luce una aplicacion web pequeña hecha con Lift, que incluye una API REST / Json, interactua con backends via SOAP y Akka Remoting, se maquilla con Bootstrap y autentica / autoriza via Active Directory con Jespa. Destacaremos algunas de las funcionalidades de seguridad y la capacidad de enviar eventos asincronicos al browser.

Sobre Alvaro

Alvaro Rodriguez es gerente de I+D en PayTrue, un proveedor de sistemas propios dentro del ecosistema de tarjetas de credito. El area de I+D mantiene herramientas y sistemas de apoyo para el area de desarrollo y una suite de productos para colaborar con el cumplimiento de normas de seguridad de la industria de medios de pago, donde se usa Scala, Lift y Akka. Alvaro tambien es co-organizador del Montevideo Big Data & Data Science Meetup.

Confirmar asistencia en la página de Meetup.

» Leer más, comentarios, etc...

Arragonán

Semanas 365 y 366

June 15, 2015 11:30 PM

Otra vez que me toca hacer retro de 2 semanas. Entre dedicar esfuerzo en dar un buen apretón para sacar trabajo adelante y asuntos alejados de un teclado, la semana pasada no saqué tiempo ni ganas para escribir la retrospectiva.

Ha sido una quincena de tratar de dejar proyectos lo más cerrados posible, que ha tocado empezar una colaboración a modo de contractor. Aún así hemos tenido contactos iniciales para 2 posibles proyectos nuevos, ambos de negocios nada relacionados con el mundillo internetero-startapil.

El pasado viernes convocamos el 2ª FridayDojo, donde estuvimos terminando la kata de StringCalculator y posteriormente nos pusimos un video alrededor del que pretendíamos hacer debate. Como comenté al terminar, me pareció una sesión más floja que la 1º, tendremos que seguir iterando para ir mejorando y encontrar un punto en el que nos sintamos todos cómodos.

Mientras que esto es en lo que que estuvimos trabajando estas dos semanas:

  • Para Bichomanía finalmente terminé de integrar pagantis en spree (tengo pendiente extraerlo a una gema y liberar ese código). Además arreglé un par de errores en la importación de datos y estuvimos trabajando en el entorno de staging, pero por problemas varios no conseguimos dejarlo listo.
  • Tuvimos la aceptación de One-step tras implementar algunos cambios que nos pidió el cliente. Y aunque surgió un pequeño bug que tocará solucionar cuanto antes, ya lo tenemos facturado.
  • Dejé todo listo para el cambio de marca de OutreachBox a OutreachTool. Modificar dominios, textos, crear y redirigir cuentas de email… nos faltan los cambios relacionados con la parte gráfica para que queden reflejados en la web.
  • Hicimos unos pequeños cambios en la web de Mosica y dejamos cerca de terminar las páginas para las salas.
  • Le di algo de dedicación a la parte servidor de Bulletins corriendo en un entorno de pruebas. Me detuve en la parte móvil, que seguramente la termine haciendo a medias con otro programador.
  • Como contractor ha tocado empezar a ver por donde viene el aire del proyecto: reuniones, leer bastante documentación y empezar a esquematizarla, ver código de un prototipo…
  • En Minchador tenemos algún restaurante más que ha empezado a darnos feedback interesante. También estuvimos con algún contacto inicial para ver temas de partnership con vistas a medio plazo.

Buena semana.

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

OpenZinc

June 15, 2015 04:24 PM

Como me pasara hace unos cuantos años con AfterGRASP, hoy me he topado con otro clásico de los años 90 que tiene nuevos aires: OpenZinc. Seguro que recuerdas aquellas aplicaciones para DOS, que recreaban la apariencia de aplicaciones gráficas, para Windows 3.x o 9x, combinando así la facilidad de uso de éstos, pero con el rendimiento y el bajo consumo de recursos de DOS. Seguramente te vendrá a la mente Partition Magic. La mayoría de ellas, usaban una librería llamada Zinc. De hecho, Zinc, fue revolucionario en cuanto al concepto que después Sun llamaría look&feel, es decir, adaptarse, o imitar la experiencia de uso de una plataforma en otra. Pero además, apostaron por conceptos que en aquella época casi nadie conocía. Hablo de portabilidad entre plataformas, internacionalización, o diseño basado en componentes RAD. Como en todos los productos de software con larga historia, ha pasado por multitud de manos, y [...]

» Leer más, comentarios, etc...

Poesía Binaria

Pausar aplicaciones haciendo click en la ventana correspondiente

June 15, 2015 08:17 AM

Todo empezó un caluroso día del mes pasado. Cuando, estando trabajando, utilizando Firefox como navegador encuentro información interesante acerca de mi actual proyecto. Aunque no era el único programa en ejecución, el hecho es que tenía toda la RAM llena, y unas 20 ventanas abiertas. De repente, recibo una llamada de teléfono y tengo que ponerme inmediatamente con otra cosa. La página que tengo en mi navegador, es muy pesada, y el ordenador empieza a ir un poco lento, además, el ventilador de la CPU se pone en marcha, muy rápido y de manera muy ruidosa, haciendo que, hasta mi interlocutor se da cuenta de ello.

Mientras me cuentan mi nueva tarea, el ordenador no iba muy fluido y necesitaba consultar lo que me estaban relatando en la llamada telefónica.

De repente, vienen a mi cabeza las señales de los procesos y se me ocurre ejecutar un simple compando.

$ killall -SIGSTOP firefox

El uso de CPU baja a un nivel más o menos aceptable, dejándome abrir otro navegador para consultar la nueva información.

La historia anterior puede repetirse con muchas variaciones, pero el hecho es que, estamos acostumbrados a utilizar varias tarea en nuestro ordenador y, a veces, éstas son demasiado pesadas. Está bien, pero, si pasamos gran parte del día trabajando, puede que esa tarea pesada que estamos ejecutando, llegue un momento en el que no es prioritaria y tengamos que hacer otra cosa mientras, por lo que podemos pausarla y ya la reanudaremos luego cuando podamos destinar recursos a ello (puede que si la detenemos tengamos que empezar luego de nuevo, y eso tampoco está bien). Por cierto, para reanudar Firefox:

$ killall -SIGCONT firefox

La bombilla sobre la cabeza

Aunque, entonces se me ocurrió que podía tener una tecla rápida, tras la cual puedo seleccionar una ventana y pausar ese proceso automatizando todo el proceso, e incluso solucionando problemas; por ejemplo, si tengo varios perfiles de firefox y sólo quiero detener uno, con killall me los cargo todos, y con kill, tengo que saber la PID del firefox en concreto, y puede resultar complicado.

Para ello, voy a utilizar wmctrl, algunas herramientas del sistema, zenity para mostrar diálogos (uso KDE, pero zenity está más extendido) y notify-send para enviar notificaciones al entorno de escritorio en que nos encontramos acerca del estado de las órdenes que enviamos.

El script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/bin/bash
WMCTRL=`which wmctrl`
ZENITY=`which zenity`
# Leave this variable as is. zenity will use it to keep
# associated to a Window and we don't want this
WINDOWID=
NOTIFY_SEND=`which notify-send`
NOTIFY_SEND_ARGS="-t 2000 -i window-duplicate"
# First implementation. No locales. Spanish for now

function already_stopped()
{
    WINPID=$1
    NAME="$2"

    $ZENITY --question --text "El proceso $2 está pausado. ¿Desea reanudarlo?" --title "Proceso pausado"
    RES=$?
    if [ "$RES" == "0" ]; then
    kill -SIGCONT $WINPID
    RES=$?
    if [ "$RES" == "0" ]; then
        $NOTIFY_SEND $NOTIFY_SEND_ARGS "Se ha reanudado el proceso $NAME"
    fi
    fi
}

function already_running()
{
    WINPID=$1
    NAME="$2"
    PCPU=`ps ax -o pid,pcpu | grep $WINPID | awk '{print $2}'`
    $ZENITY --question --text "El proceso $2 está corriendo y consumiendo "$PCPU"% de CPU. ¿Desea pausarlo?" --title "Proceso en curso"
    RES=$?
    if [ "$RES" == "0" ]; then
    kill -SIGSTOP $WINPID
    RES=$?
    if [ "$RES" == "0" ]; then
        $NOTIFY_SEND $NOTIFY_SEND_ARGS "Se ha pausado el proceso $NAME"
    fi
    fi
}

function state_changer()
{
    WINPID=$1
    STATUS=`cat /proc/$WINPID/status`
    NAME=`echo "$STATUS" | grep "Name:" | awk '{print $2}'`
    STATE=`echo "$STATUS" | grep "State:" | awk '{print $2}'`

    if [ "$STATE" == "T" ]; then
    already_stopped $WINPID "$NAME"
    else
    already_running $WINPID "$NAME"
    fi
}

function get_window()
{
    if [ "$1" == "Using" ]; then
        WINDOWLIST="`$WMCTRL -l -p | grep $3`"
        if [ -z "$WINDOWLIST" ]; then
            $ZENITY --error --text "No se encuentra la ventana seleccionada"
            exit
        fi
        WINPID=`echo "$WINDOWLIST" | awk '{print $3}'`
        state_changer $WINPID
    fi
}

$NOTIFY_SEND $NOTIFY_SEND_ARGS "Seleccione la ventana para ver el estado del proceso"
$WMCTRL -a :SELECT: -v 2>&1 | while read line; do get_window $line; done

Bueno, vamos a comentar esto un poco.

La joya de la corona, es wmctrl, con él, podemos pedirle información sobre una ventana, en este caso, una ventana a la que hacemos click, con :SELECT: una vez tenemos el ID de la ventana, podemos pedir una lista de ventanas incluyendo los PID de los procesos asociados (get_window()) y filtrar por el ID de la ventana en la que hemos hecho click.

Teniendo el PID, podemos averiguar el estado del proceso consultándolo en /proc/PID/status y podemos saber si lo habíamos pausado antes o no. Si no estaba pausado, lo pausamos (quise meter un diálogo por si hacemos click en una ventana equivocada. Si el proceso ya estaba pausado, nos da la opción de reanudarlo.

Advertencia

El funcionamiento teórico está bien, además funciona bien, puede detener cualquier proceso que tenga una ventana asociada, no estamos haciendo nada del otro mundo. Aunque hay procesos que no les sienta bien que los pausen, y puede que al reanudarlos tengan algún problema. Al ser procesos interactivos, muchas veces, todos los clicks que hemos hecho sobre ellos cuando estaban detenidos se producirán cuando lo reanudemos. En definitiva, que algunos procesos puede que se vuelvan inestables tras reanudarlos, pero no suele pasar.

En github

Este script forma parte de un proyecto que mantengo en github: gscripts, forks y stars son bienvenidos. Además, puede que cuando se publique el post, haya novedades en el repositorio.

The post Pausar aplicaciones haciendo click en la ventana correspondiente appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Koalite

Alternativas al uso de ObjectMother y Builders en los tests

June 15, 2015 05:06 AM

Cuando estamos escribiendo tests automatizados, excepto en los casos más sencillos, es habitual que para testear el componente que queremos testear, necesitemos utilizar otros objetos, ya sea para construir el objeto que estamos testeando o como parámetros de los métodos que vamos a testear.

Si estamos siguiendo los principios canónicos de diseño orientado a objetos, huyendo de la obsesión por los tipos primitivos, encapsulando datos y comportamiento, manteniendo invariantes y demás, es probable que construir estos otros objetos y ponerlos en el estado que necesitamos resulte algo más laborioso de lo que nos gustaría.

Esto presenta dos inconvenientes fundamentales:

  • Se produce un acoplamiento entre el test y APIs de las dependencias que, en principio, no deberían importarnos mucho. Si para el test necesitamos tener un “cliente preferente”, la forma de construir un cliente preferente no debería ser importante. Al introducir este acomplamiento tenemos tests más frágiles y más costosos de mantener.
  • Hay un pérdida de legibilidad, puesto que tenemos que intoducir más ruido en el test para configurar las dependencias y eso hace que sea más complicado ver qué es lo que realmente queremos testear y dificulta resaltar qué aspectos son los imporantes para el test y qué aspecto son accesorios.

Para resolver esto existen varias técnicas, algunas de las cuales ya hemos visto por aquí.

ObjectMother

Una opción es utilizar un ObjectMother, que es una clase encargada de proporcionarnos instancias de las clases que usamos con frecuencia. No voy a entrar en mucho detalle, tenéis más información en el post que escribí sobre ObjectMother, pero la ventaja es que nos ahorra depender de los constructores de otros objetos.

La principal limitación de este patrón es que si necesitamos construir objetos con diversas características (un cliente de Madrid, otro de Segovia, uno preferente, otro que haya excedido el riesgo, etc.), la clase que hace de ObjectMother empieza a ser un lío y acabamos acoplando unos tests a otros indirectamente a través del ObjectMother.

Aunque cada vez uso menos esta técnica, sigue resultando útil para datos muy estáticos que no cambian mucho. Los típicos “datos maestros” entre los que podemos incluir un par de países, un par de formas de pago, etc.

Builder

Para los casos en que el ObjectMother se queda corto, se pueden utilizar builders para no depender de las APIs testeadas. Con los Builders podemos construir objetos y ponerlos en estado que necesitamos sin necesidad de depender del API concreta del objeto, omitiendo además aquellos detalles que no son relevantes para el test y generando tests más legibles, como veíamos en este ejemplo de test usando builders.

Los builders son una solución bastante buena, pero tienen sus problemas. Para empezar, son costosos de escribir. Para que sean realmente cómodos de usar hay que diseñarlos con cuidado, pueden requerir bastante código y eso ralentiza la escritura de los tests. Esto lleva a intentar construir builders genéricos que podamos reutilizar en varios tests con la idea de amortizarlos, pero eso es un arma de doble filo, porque llega un momento en que el builder tiene tantas opciones que se hace casi tan complejo como el API del objeto que estamos construyendo, y la legibilidad del test (recuerda, uno de los objetivos de introducir el builder) se resiente.

Normalmente utilizo builder genéricos para construir objetos que se necesitan en muchos tests diferentes y cuyos requisitos de construcción son similares de unos tests a otros. Por ejemplo, puedo tener 800 tests que necesitan construir productos con distinto nombre, precio o tipo de impuesto, pero poco más, por lo que el builder acaba con un API relativamente simple y se amortiza. Si tengo requisitos muy concretos, utilizo builders internos a la clase de test, optimizados para ese caso de uso concreto. Eso me permite simplificar al máximo el API del builder e incrementar mucho la legibilidad de los tests, pero el esfuerzo es mayor, por lo que sólo uso esta opción cuando son test que me interesa mucho mantener legibles.

Creation Methods

La alternativa que más utilizo actualmente para construir objetos en los tests son los métodos de creación. La idea es encapsular la creación y configuración de objetos auxiliares en un método dentro de la propia clase de test.

Por ejemplo, si estamos testeando un filtro sobre productos en base a la categoría a la que pertenecen y el nombre del producto, esos son los únicos datos que nos interesan y podríamos tener un método así:

private Product Product(string category, string name)
{
  var category = new Category(category);
  var tax = ObjectMother.Tax1;
  var product = new Product(name, tax);
  product.Category = category;
  return product;
}

[Test]
public void Filters_Products_By_Full_Text_Search()
{
  var products = new[]
  {
    Product("Ropa", "Camiseta"),
	Product("Ropa", "Pantalón"),
	Product("Menaje", "Copa"),
  };

  var result = products.Filter("opa");
  Assert.That(result.Length, Is.Equalto(3));
}

En el ejemplo se ve además cómo esta técnica interactúa con otra de las expuestas anteriormente, el ObjectMother, para acceder a datos estáticos (un tipo de impuesto predeterminado), que no nos interesa lo más mínimo para el test.

Este sistema es mucho más rápido de implementar que un builder y nos da la flexibilidad de diseñar el API del método exactamente cómo la necesitamos para los tests que vamos a escribir.

Como contrapartida, no conseguimos aislar tanto los tests de las APIs necesarias para construir y configurar los objetos. Si tenemos 80 clases de tests que construyen productos y cambiamos el constructor de producto, tendremos que cambiarlo en 80 sitios. Es una mejora con respecto a tener que cambiarlo en los 800 tests que usan productos, pero sigue siendo peor que cambiarlo sólo en el builder o en el ObjectMother.

Además, si tenemos muchas variantes de objetos a construir en una misma clase de test, necesitaremos crear muchos métodos, que no siempre son fáciles de nombrar (AddInvoice, AddInvoiceWithPreferredCustomer, AddInvoiceWithPreferredCustomerFromMadrid, etc.), o utilizar muchos parámetros en nuestros métodos de creación.

Si vamos por la vía de usar muchos parámetros, tendremos el problema de perder legibilidad en el test cuando tengamos varios parámetros del mismo tipo:

private Invoice Invoice(string customer, decimal customerDiscount, string product, decimal quantity, decimal price,  decimal shippingCost) { ... }

[Test]
public void Some_Invoice_Test()
{
  // ¿Qué es cada parámetro? ¿La cantidad es 1 o 4? ¿Y el precio?
  var invoice = Invoice("Paco", 0.1m, "Paraguas", 1m, 4m, 2.5m);
  ...
}

Cuando tenemos varios parámetros con el mismo tipo es difícil saber qué es cada parámetro por el contexto (aunque a veces el contexto ayuda, como “Paco” y “Paraguas”, es fácil distinguir el cliente del producto).

A veces para solventar esto se introduce un parameter object para agrupar los parámetros y poder ponerles nombre. Esto incluso permite aplicar el patrón builder al parameter object para no tener que indicar todos los parámetros si no son necesarios:

[Test]
public void Some_Invoice_Test()
{
  var invoice = Invoice(
    Customer("Paco").Discount(0.1m),
	Product("Paraguas").Price(4),
	1m,
	2.5m);
	
  // ...
}

Los builders pueden ser genéricos o específicos a la clase de tests, dependiendo del escenario pero la idea es similar. Si usamos esta técnica podemos repartir la lógica entre el método y el builder, lo que nos ayuda a mantener los builders más genéricos y reutilizables, y dejar las cosas “muy especiales” para los métodos específicos de una clase de tests. Lo malo es que seguimos teniendo que implementar y mantener los builders.

No es mi técnica preferida porque me parece que lleva bastante trabajo, pero a veces es una buena salida y la suelo emplear de vez en cuando.

En lugar de builders, podemos construir el parameter object mediante propiedades. Hay que escribir un poco más y no es igual de potente, pero nos ahorra algo de código:

private class CustomerInfo
{
  public CustomerInfo()
  {
    Name = "";
	Discount = 0;
  }

  public string Name { get;set; }
  public decimal Discount {get; set; }
}

[Test]
public void Some_Invoice_Test()
{
  var invoice = Invoice(
    new CustomerInfo { Name = "Paco" },
	new ProductInfo { Price = 4 },
	1m,
	2.5m);
	
  // ...
}

Usando objetos y propiedades podemos jugar con el constructor para definir valores por defecto y así en cada test sólo necesitamos hacer explícitas las propiedades que importan, al estilo de lo que haríamos con el builder. La verdad es que es una opción que no uso casi nunca porque me parece que obliga a escribir demasiado al invocar el creation method, especialmente por tener que incluir el nombre del parameter object (el new CustomerInfo) y lo encuentro poco legible.

Si vamos un paso más allá, podemos hacer esto mismo sin ningún parameter object, utilizando argumentos con nombre y valores por defecto en el método original:

private Invoice Invoice(
  string customer = "", decimal customerDiscount = 0,
  string product = "",  decimal quantity = 1, decimal price = 1,
  decimal shippingCost = 0) { ... }

[Test]
public void Some_Invoice_Test()
{
  var invoice = Invoice(
  	  customer: "Paco", customerDiscount: 0.1m,
	  product: "Paraguas", quantity: 1, price: 4,
	  shippingCost: 2.5m);
  ...
}

Esta técnica nos permite identificar claramente el rol de cada parámetro gracias a su nombre y, gracias a los valores por defecto, podemos omitir aquellos parámetros que no son relevantes para el test. Hay quien se pone nervioso cuando el creation method empieza a acumular muchos parámetros, y es cierto que puede ser un problema, pero al final es un problema que tienes acotado en un punto (ese método), por lo que es relativamente manejable.

Una limitación importante es que C# es muy restrictivo en los valores por defecto que se pueden usar para los argumentos de un método, y hay ocasiones en que esta técnica se nos queda corta justo por eso. Podemos recurrir al estilo tradicional de tener distintas sobrecargas, pero no es igual de flexible.

Últimamente estoy utilizando más esta técnica, aunque todavía es pronto para decidir cuánto me gusta.

Conclusión

Al escribir tests es muy importante que sean fáciles de mantener y que se pueda confiar en ellos. Para eso es crítico que sean fáciles de entender y que cuando fallen sea porque lo que están testeando ha dejado de funcionar, no porque se ha producido un cambio en otra área de la aplicación.

Para conseguir esto es útil independizar los tests de la construcción y preparación de los objetos “auxiliares” (prefiero evitar el término dependencia) que necesitamos en el test.

Existen muchas técnicas, entre ellas las que hemos visto en este post. Todas tienen valor en distintos contextos, pero si tuviera que resumir mi estrategia actual sería algo así:

Usa ObjectMother para datos maestros (países, formas de pago, impuestos, roles, usuarios, etc.). En generl, para cualquier cosa que casi nunca importa en el test pero que necesitas para construir los objetos o realizar las operaciones.

Si puedes apañarte con métodos de creación, hazlo. Es lo más rápido de implementar y a veces es también lo más legible. Lo idea es usar métodos de creación sin nada más, pero si no queda más remedio, añade parámetros con nombre o builders para construir parameter objects.

Cuando veas que estás construyendo el mismo tipo de objeto en muchos tests, refactoriza a un builder para aislarte de cambios en su API. Tus métodos de creación pueden llamar a ese builder si hace falta y te ahorrarás problemas a medio plazo.

Como siempre, nada de esto está escrito en piedra. Comprende lo que te ofrecen los distintos tipos de soluciones, analiza tu caso y diseña tu propia estrategia.

Posts relacionados:

  1. Tests de integración con Entity Framework (II): Escribiendo tests cómodamente
  2. Refactorizando tests unitarios hacia tests sin dependencias
  3. Aplicando el patrón builder para escribir tests unitarios

» Leer más, comentarios, etc...

Con un ojo al gato y el otro al garabato

El Patrón Repositorio y sus falacias

June 15, 2015 01:25 AM

Con el tema convertido en moda -que por cierto ya algo viejo- de aplicaciones orientadas al dominio, seguramente nos hemos llenado la cabeza de conceptos relacionados. Existen montones de implementaciones, y particularmente para los que estamos en el mundo de .NET, tenemos la referencia de DDD N-Layered .NET 4.0 Architecture Guide. Incluso en la misma […]

» Leer más, comentarios, etc...

Blog Bitix

Nueva visita a Herramientas para un proyecto Java

June 12, 2015 06:00 PM

Las tecnologías para desarrollar una aplicación son un medio para resolver las necesidades del negocio o un cliente, no un fin. Pero esto no quiere decir que la elección sea trivial o poco importante, realizar las elecciones adecuadas según lo requisitos puede evitar complicaciones en un futuro. Para un proyecto basado en la plataforma Java esta es mi selección de herramientas de las que conozco.

Java

Hace 4 años escribí un artículo comentando que tecnologías eligiría para un proyecto Java si tuviese posibilidad. Al ritmo que avanza la tecnología cuatro años es un tiempo bastante largo, también es un tiempo en el que he podido aprender y añadir a mi «caja de herramientas» nuevas opciones que después de evaluarlas me han gustado. En este artículo haré una nueva visita al artículo anterior y comentaré algunas nuevas herramientas.

Lenguaje de programación

Como lenguaje de programación seguiría usando Java, en mi caso es el lenguaje que más conozco y sigue siendo una de las opciones más válidas. Pero con la salida de una nueva versión usaría Java 8. La publicación de Java 8 incorporando varias novedades importantes han mejorado varios aspectos de este lenguaje, por mencionar los más relevantes están la incorporación de lambdas que proporciona una cierta forma de programación funcional, también destaca los streams que permite describir los algoritmos que procesan datos de una forma más expresiva y legible además de aprovechar mejor los procesadores multinúcleo, métodos por defecto en interfaces que permite mantener compatibilidad hacia atrás (aunque esto interesa más a los desarrolladores que hacen APIs para que sean usadas por terceras partes), una nueva API para el manejo de fechas eliminando una de las críticas de versiones anteriores y algunas cosas más. El futuro con Java 9 es prometedor si presenta la interesante modularidad.

Persistencia en base de datos

Para la persistencia en vez de usar la muy difundida librería Hibernate usaría jOOQ. jOOQ es una librería que no tienen tanta magia como Hibernate que en muchas ocasiones produce errores complicados de resolver y no tenemos tanto control de lo que hace, por otro lado jOOQ devuelve a la base de datos y al lenguaje SQL la relevancia que con Hibernate queda abstraída con el mapeado del modelo de datos a objetos y el lenguaje HQL. jOOQ permite construir las sentencias SQL de forma programática con lo que el compilador nos indicará errores de compilación y nos validará los tipos que usemos, ambas cosas son importantes cuando hacemos un refactor en alguna parte de la aplicación. En el artículo alternativa a Hibernate y ejemplo jOOQ entro en más detalles.

Modificaciones de la base de datos

En un proyecto de larga duración y en el que se realicen mejoras probablemente necesitaremos modificar el modelo de la base de datos. Empleando la herramienta Liquibase podremos automatizar la actualización del esquema de la base de datos ya necesitemos añadir campos, cambiarlos de nombre, eliminarlos, crear o eliminar tablas, insertar, eliminar o actualizar datos. Estas actualizaciones de la base de datos se indican en un archivo que podemos guardar en nuestro repositorio de control de versiones de forma que podamos ver y reproducir los cambios que se han hecho a la base de datos a lo largo del tiempo.

Pruebas

Para pruebas unitarias dos buenas posibilidades son Spock y Geb. Spock permite realizar los teses unitarias con un DSL bastante descriptivo que facilita la lectura posteriormente de la prueba. Por otro lado Geb permite automatizar las pruebas de las aplicaciones web proporcionando facilidades, se puede integrar con Spock.

Cliente

En el lado cliente de una aplicación web usaría la combinación de varias tecnologías, jQuery para acceder y manipular el DOM de la página web, RequireJS para cargar los archivos necesarios en la página y evitar la polución del ámbito global javascript. Si la aplicación tiene una carga importante en el lado cliente usaría Backbone, React y Mustache, en el ejemplo lista de tareas con Backbone y React puede verse como podría quedar el código, también Jasmine para hacer pruebas unitarias en javascript. Finalmente, Grunt para hacer algunas tareas de javascript y Bower para obtener las librerías que requiera el proyecto.

Framework web

Para el desarrollo de una página o aplicación web seguiría usando Apache Tapestry por la productividad y alta reutilización que se puede conseguir, también por la flexibilidad, extensibilidad y adaptabilidad del framework. Descargando el libro PlugIn Tapesty puedes conocer muchos más detalles. Si se tratase de una aplicación REST evaluaría Spark o RESTEasy para proporcionar la interfaz exterior de los microservicios y quizá evaluaría Apache Thrift o gRPC para consumirlos internamente, Thrift permite acceder a la API de una forma programática más sencillamente que consumir una interfaz REST cruda. La tendencia actual es desarrollar microservicios y esto en las aplicaciones web supone que sean capaces de ofrecer su servicio por si mismas no usando un servidor de aplicaciones que hay que instalar previamente simplificando el despliegue a los administradores de sistemas, esto también se puede conseguir en parte usando Docker. En vez de usar un Tomcat tradicional podemos usar la versión embebible.

Base de datos

Para una base de datos relacional en vez de MySQL usaría PostgreSQL. PostgreSQL posee numerosas opciones avanzadas y es una de las bases de datos libres más reconocidas. El futuro de MySQL con Oracle y su escisión en MariaDB es más incierto además de no poseer algunas características que PostgreSQL sí.

Dependiendo del causística de la aplicación otra opción complementaria es Redis, una base de datos clave-valor y en caso de tener que hacer búsquedas Elasticsearch.

Entorno de desarrollo

Para el entorno de desarrollo o devbox usaría Docker y Compose que permiten disponer de un entorno más parecido al entorno de producción y en menos tiempo que instalando todo lo necesario en la máquina física. También podemos usar Docker para el entorno de producción. Para automatizar la tareas de configuración o despliegue usaría Ansible ya que al contrario de otras opciones no requiere instalar un agente en las máquinas a administrar, con un acceso SSH es suficiente.

Hospedaje

En cuanto al alojamiento para la aplicación la nube es otra tendencia por su flexibilidad. La nube de Amazon proporciona muchos servicios que pueden sernos útiles sin embargo si nuestra aplicación no los necesita y no es demasiado complicada podemos optar por otras opciones más baratas. Si usamos Amazon podemos aprovecharnos de Bitnami si trabajamos con algunas de las aplicaciones para las que proporciona imágenes. Dos de estas opciones más baratas son Linode o Digital Ocean con las que por unos 5 o 10 € al mes podemos disponer de una máquina con 1 GIB de RAM, unos 30 GiB de discos SSD y una amplia transferencia de datos entrantes y salientes.

Otras

Hay otras herramientas aún pasado este tiempo seguiría usando como Git para el control de versiones, Redmine como gestor de peticiones, PMD y Checkstyle para analizar el código fuente, Gradle como herramienta de construcción, Jenkins como herramienta de integración continua, GNU/Linux tanto para desarrollar como para el servidor en el que desplegar la aplicación, eclipse para editar código Java o Sublime Text para editar archivos no Java, JasperReports para informes complejos, nginx como servidor web, Quartz para lanzar tareas en ciertos momentos o regularmente, Log4j 2 para emitir trazas de la aplicación en vez las propuestas anteriormente (SLF4J o Logback), less para facilitar la escritura de hojas de estilo CSS y Bootstrap como estilos por defecto para una aplicación. O alguna nueva como RabbitMQ para una comucación entre aplicaciones o partes de ella basada en mensajes y de forma desacoplada,

Para cada un de estas herramientas en muchos casos tendremos varias alternativas similares para elegir, a veces elegir una u otra es algo subjetivo. Estas herramientas en muchos casos son de lo mejor que hay disponible pero perfectamente se pueden usar alternativas similares.

¿Cuales serán las herramientas que formarán el «estado del arte» dentro de otros cuatro años? ¿Cuales sobrevivirán y cuales perecerán en el camino? ¡Apasionante!

Referencia:
Elegir herramientas para un proyecto
Build Your Own Technology Radar
Technology Radar

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin