Weblogs Código

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

Recuperando programas antiguos: Los programas

February 22, 2017 06:07 PM

Continuando con Recuperando programas antiguos: El proceso, vamos a proceder a analizar los programas que he encontrado, y que son parte de mi historia. Veréis que es muy fragmentario, en unos casos, no todo son las últimas versiones de lo que programé. En otros, son tan últimas, que ni siquiera funcionaban. Cuando ha sido posible, […]

La entrada Recuperando programas antiguos: Los programas aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Variable not found

Acceder a IIS Express desde otro equipo de la red local, edición 2017

February 22, 2017 08:48 AM

Aunque IIS Express está diseñado principalmente para ser utilizado por desarrolladores en el interior su equipo de trabajo, seguro que la mayoría sabéis que haciendo un par de cambios en la configuración también es posible utilizarlo desde equipos externos, por ejemplo para poder hacer pruebas de una web o servicio desde otros dispositivos conectados a la misma red.

Es sencillo encontrar cómo hacerlo porque hay mucho escrito al respecto en la red, y sin embargo de vez en cuando me encuentro con desarrolladores que no saben que esto es posible hacerlo, así que este post va por vosotros ;D

Partiremos de un proyecto ASP.NET 4.x creado en Visual Studio 2015 o 2017, da igual si se trata de una aplicación MVC, Web Forms, Web API o lo que sea. Para desarrollar el ejemplo, imaginemos que al ejecutarlo en local estamos usando la URL http://localhost:3803/.

Veamos paso a paso cómo acceder a esta aplicación desde otro equipo conectado a la red local, y cómo solucionar algunos de los problemas que podemos encontrar por el camino.


1. Averiguamos con qué dirección está visible nuestro equipo desde el exterior
Esto podemos hacerlo con cierta facilidad ejecutando el comando "ipconfig" en la consola de la siguiente forma:
C:\>ipconfig | find "IPv4"
Dirección IPv4. . . . . . . . . . . . . . : 192.168.1.33
Dirección IPv4. . . . . . . . . . . . . . : 192.168.56.1
Dirección IPv4. . . . . . . . . . . . . . : 10.71.34.1

C:\>
El número de resultados que veremos ahí dependerá de los adaptadores de red (físicos o virtuales) que tengamos configurados en nuestro equipo. De ellos tendremos que seleccionar la dirección que se encuentre en el rango de red usado por los equipos externos desde los cuales queremos acceder a nuestra web.

En mi caso, sé que todos los equipos de la red local usan direcciones del tipo 192.168.1.*, por lo que el nombre de host que deberían usar para acceder a mi equipo de trabajo sería la 192.168.1.33.

2. Localizamos el archivo de configuración de IIS Express del proyecto

Este archivo se llama "applicationhost.config" y en proyectos de Visual Studio se encuentra en una carpeta llamada ".vs" que encontramos en el directorio raíz de la solución, y dentro de ella, en la subcarpeta "config".

En otros casos, el archivo de configuración podréis encontrarlo en la carpeta de configuración de IIS Express de vuestro usuario en el equipo: %userprofile%\documents\iisexpress\config.

3. Localizamos las líneas donde se especifica la URL por defecto del proyecto

En el archivo "applicationhost.config", debemos localizar la parte de la configuración donde se indica la URL de acceso al proyecto en la máquina local. Por ejemplo, podría ser algo como esto:
<bindings>
<binding protocol="http" bindingInformation="*:3803:localhost" />
</bindings>
Observad que este binding está limitando el acceso a vuestro sitio web, permitiendo únicamente el uso del host "localhost" para acceder al mismo. Para habilitar el acceso desde equipos externos, lo primero que tenemos que hacer es añadir otros bindings con el nombre de host que se utilizará desde fuera.

4. Añadimos a la configuración de IIS Express el nuevo binding con la dirección de nuestro equipo

En la sección de configuración <bindings>, añadimos una nueva línea en la que indicaremos que la aplicación también será accesible utilizando como host nuestra IP, de forma que quedaría más o menos como aparece a continuación. Ojo, ¡tened en cuenta que debemos elegir un puerto distinto al que usamos en localhost para que no haya conflictos!
<bindings>
<binding protocol="http" bindingInformation="*:3803:localhost" />
<binding protocol="http" bindingInformation="*:3804:192.168.1.33" />
</bindings>
Bien, pues si ahora intentamos ejecutar sin depuración nuestra aplicación es posible que pensemos que algo hemos roto ;)

Unable to launch the IIS Express Web server.
Failed to register URL "http://192.168.1.33:3804/" for site "DemoMvc5" application "/". Error description: Acceso denegado. (0x80070005)
Unable to launch the IIS Express Web server.

Este error aparece siempre que no hayamos lanzado Visual Studio como administrador, pues el nivel de permisos del proceso bajo el que se lanza IIS Express no es suficiente como para "apropiarse" de una dirección y puerto TCP/IP del equipo y utilizarla para escuchar peticiones.

En cambio, si iniciamos Visual Studio como administrador veremos que arranca correctamente y que, de hecho, podemos acceder a la aplicación utilizando tanto localhost:3803 como 192.168.1.33:3803, lo que quiere decir que, si no existen problemas de permisos, el binding está bien hecho.

5. Reservar la URL y conceder permisos de uso (sólo no administradores)

Como hemos comentado antes, este paso no será necesario si estamos ejecutando Visual Studio (y por tanto IIS Express) como administrador. Pero si no es así, debemos abrir una la línea de comandos con permisos elevados y utilizar la siguiente instrucción para reservar la URL y darle derechos de uso a determinados usuarios del equipo, por ejemplo como sigue:
C:\>netsh http add urlacl url=http://192.168.1.33:3808/ user=todos

La reserva de dirección URL se agregó correctamente

C:\>
Pero antes de hacerlo tened en cuenta unos detalles:
  • Primero, la URL debe estar completa, incluida la barra del final.
  • El usuario puede ser cualquier grupo del sistema o nombre de usuario con dominio. En mi caso, en lugar de "todos" podría haber indicado "pc-jma\josem", que es mi usuario en la máquina local.
  • Los nombres de grupo son sensibles al idioma de instalación de Windows. Es decir, si vuestro Windows está instalado en inglés, debéis usar el nombre "everyone" en lugar de "todos".
Tras ejecutar el comando, ya debería ser posible acceder a la aplicación desde el equipo utilizando tanto la URL interna (localhost) como la externa (192…), cada una con su puerto correspondiente.
IIS Express mostrando que la aplicación está disponible a través de dos URL distintas

Pero el acceso externo aún no está garantizado: el firewall impedirá el acceso a no ser que le indiquemos lo contrario.

6. Abrir el firewall

Por defecto, el firewall de Windows rechazará cualquier intento de acceso a la máquina desde el exterior, por lo que debemos configurar una regla de entrada que asegure que las peticiones hacia nuestra web podrán entrar sin problema.

Esto podemos hacerlo a base de ratón, utilizando las herramientas de administración de Windows o, ya que teníamos abierta una consola de comandos con permisos de administrador, ejecutando la siguiente orden:
C:\>netsh advfirewall firewall add rule name="External Access to MyApp" dir=in action=allow protocol=TCP localport=3804

C:\>
Por supuesto, recordad que:
  • El parámetro localport debe ser el puerto que habéis elegido para el acceso externo, el mismo que usamos en el archivo de configuración de IIS Express, y más adelante al reservar la URL.
  • Es conveniente poner un nombre reconocible a la regla, de forma que más adelante podamos identificarla con facilidad.
¡Y eso es todo! Si habéis llegado hasta aquí, ya podréis ejecutar o depurar vuestra aplicación en Visual Studio, y acceder a ella desde cualquier equipo de la red local usando la dirección que hayáis elegido en los pasos anteriores.

Espero que os resulte de utilidad ;)

Publicado en Variable not found.

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

Poesía Binaria

¿Qué son y cómo utilizar direcciones IP flotantes en DigitalOcean? [Vídeo]

February 21, 2017 09:36 PM

Un problema que teníamos los que utilizamos los servicios de Digital Ocean es que cuando paras una máquina para realizar una actualización, la dirección IP de la misma es inaccesible y dejas a todos tus visitantes en la estacada y mi humilde blog sin visitas ni nada que le diga a mis visitantes que sigo vivo.

Al menos sucedía así hasta hace un tiempo, cuando lanzaron las IP flotantes o Floating IPs.

Te lo cuento

Si prefieres leerlo todo, puedes saltarte el vídeo. Aunque son 3 minutos.

Para más información, sigue leyendo…

El problema

En DigitalOcean la asignación de direcciones IP públicas va por cada uno de los servidores que reservas. Eso por un lado quiere decir que todos VPS que pides están conectados a Internet (¿Quién puede querer que un VPS no esté conectado? Lo veremos pronto). Y por otra parte, podemos comprobar cómo las direcciones pueden cambiar. Es decir, nadie nos garantiza que cuando sacamos una máquina de nuestro sistema, cuando metamos otra, ésta vuelva a tener la misma dirección IP. Es verdad que en muchos casos es así, pero es que Digital Ocean no es capaz de saber si vamos a crear una máquina tras destruir una antigua.
Por otro lado es muy común que en un servidor hagamos tareas de mantenimiento y, durante ese tiempo, no deberíamos tener ninguna entrada de visitantes. Se pueden encontrar con cosas que no deben, fallos, de esos que asustan a los visitantes y podemos exponer información del sistema de esa que hace que a un atacante se le iluminen los ojos.
Otro caso, que es muy es cuando tenemos que rehacer el sistema (hay veces que una reinstalación sale más barato que actualizar), reservemos una máquina nueva y empecemos a trabajar en ella. Mientras tanto, todos los visitantes estarán accediendo a nuestra web alojada en nuestro servidor antiguo. Pero, cuando hayamos terminado de montar la nueva máquina, después de hacer pruebas y todo, cuando esté a punto, hacer un cambio de IP del servidor viejo al nuevo…

La solución de DigitalOcean

En este caso, DigitalOcean nos presenta las IPs flotantes. Esto son direcciones IP que podemos “enchufar” a un servidor. De modo que nuestros visitantes y usuarios accederán siempre a la IP flotante. Dejando la IP del servidor para un uso privado e interno, todavía no podemos eliminar dicha IP para que no sea accesible, aunque sí podríamos filtrarla por IPtables por ejemplo.

Ya que estas IP son “enchufables”, pueden estar conectadas a nuestro servidor web, y nuestros visitantes acceder a dicha IP. La ventaja es que esta dirección la podemos desenchufar de un servidor y enchufar en otro sin problema y de forma instantánea. Anteriormente podíamos actualizar la DNS del dominio para cambiar la IP, aunque la propagación DNS ha mejorado mucho los últimos años, puede tardar varios minutos o incluso horas en el peor de los casos, y dependiendo de nuestro proveedor.

Enchufando y desenchufando

Ya que podemos hacer lo que queramos, practiquemos un poco. Y es que si vamos a realizar tareas de mantenimiento en el servidor que requieran desconectar el servicio, en lugar de dejar a nuestros visitantes con la dirección IP de nuestra web sin respuesta podemos crear un pequeño VPS con un servidor web y que dirija a una página estática que diga: “Lo sentimos, estamos de mantenimiento”. Seguro que encontráis por Internet plantillas muy buenas con páginas que hagan que nuestros usuarios no quieran matarnos, sino que nos den su apoyo por querer mejorar el servicio. Una vez creado el VPS que sirve páginas estáticas (muy importante, porque si son dinámicas seguramente necesitemos más servidor), vinculamos la IP flotante que apunta al servidor que tenemos que parar a nuestro nuevo servidor de páginas estáticas. En este momento, nuestros usuarios comenzarán a entrar al servidor de “vuelva más tarde”. Así no perderemos desesperaremos a nuestras visitas o clientes mientras mejoramos nuestro servidor. Incluso podríamos dejar algunos servicios mínimos activos.

Como decíamos antes, también podemos empezar a trabajar en una actualización de nuestros servicios poco a poco, reinstalar una nueva máquina y luego cuando esté todo hecho cambiar la IP flotante de nuestro servidor al nuevo, seguidamente destruir el antiguo servidor, que ya no nos importa.

Como vemos, son muchas las posibilidades que nos da tener IPs flotantes cuando contratamos el servicio. Y, a partir de ahora es una buena práctica cuando trabajamos con esta empresa. Aunque para otros servicios en la nube suele haber conceptos parecidos, esto de enchufar y desenchufar direcciones IP no es nuevo y podemos ponerlo en práctica en otros proveedores.

Jugando con la API

DigitalOcean, tiene una ventaja añadida, desde el primer día, y es su API. Desde ahí nos dejan tocar muchas y, sobre todo, automatizar acciones. Podemos crear y destruir droplets, administrar DNS, imágenes, e IPs flotantes, tamaños de servidores, etc… pero hoy vamos a hablar de la API de metadatos de DigitalOcean. Esta API hace que desde una misma instancia se pueda acceder a información sobre la misma. Es decir, que una misma instancia pueda preguntar su dirección IP pública, o privada, o la IP flotante, conocer su ID, etc.

Aunque ya que utilizamos GNU/Linux sabemos que podemos utilizar ifconfig para sacar direcciones IP locales, combinandolo con grep, cortando la cadena resultante, etc, las llamadas a la API de DigitalOcean suelen ser más directas. Además, nadie nos dice que en el futuro este proveedor no cambie la forma en la que asigna las direcciones IP a nuestra máquina (Amazon lo hizo hace unos años), haciendo que nuestra antigua forma de hacerlo no sea efectiva ya. Además, con estas llamadas a la API de metadatos podremos crear scripts generales que podremos subir en varias máquinas y cada uno averigüe información de la máquina por sí mismo.

Todas estas llamadas se hacen haciendo una petición GET a http://169.254.169.254/ , al ser una conexión interna y directa no necesita protocolo SSL (y es tan rápida que el servicio estará alojado en la misma máquina física). Esta llamada la podemos hacer con cURL, o desde cualquier lenguaje de programación. Tenemos algunas llamadas interesantes, como por ejemplo:

  • Extraer hostname de la máquina:
    curl -s http://169.254.169.254/metadata/v1/hostname
  • Extraer IP pública:
    curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address
  • Extraer IP privada:
    curl -s http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address
  • Extraer información del usuario (esta información con algún script de inicialización para la máquina):
    curl -s http://169.254.169.254/metadata/v1/user-data
  • Extraer región geográfica:
    curl -s http://169.254.169.254/metadata/v1/region
  • Extraer etiquetas:
    curl -s http://169.254.169.254/metadata/v1/tags
  • ¿Tenemos IP flotante? (true/false)
    curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/active
  • Extraer IP flotante:
    curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/ip_address

Y con esta información podremos hacer muchas cosas.

¿Quieres un servidor en Digital Ocean?

Este post no es patrocinado. Sólo quería compartir esta utilidad de este servicio que utilizo. Aunque aprovechando esto, ya que estamos, si quieres contratar el servicio con este proveedor, si te registras de mi parte te darán $10 para gastar en hospedaje. Aunque sea en dólares puedes contratarlo con independencia de tu país.
Para contratar el servicio de mi parte, sigue este enlace: https://m.do.co/c/fa10e4099dbc.
Y yo también me llevaré algo por recomendarte.

The post ¿Qué son y cómo utilizar direcciones IP flotantes en DigitalOcean? [Vídeo] appeared first on Poesía Binaria.

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

Una sinfonía en C#

Novedades de Visual Studio 2017: Intellisense Filtering

February 20, 2017 01:45 PM

Entre las muchas novedades que nos trae la nueva versión de Visual Studio una que me resultó muy útil es Intellisense filtering, una características que nos permite aplicar filtros sobre los que nos muestra intellisense, es decir, hasta hoy si presionamos Ctrl + Space vemos algo así:

image

Lo clásico un listado con todo lo que tenemos disponible en el contexto actual, por supuesto que la lista puede ser muy larga lo cual dificulta encontrar lo que estamos buscando, más aún si se trata de una API que no conocemos y no tenemos muy claro qué estamos buscando

Intellisense filtering al rescate

Intellisense filtering permite justamente eso, poder usar intellisense y aplicar filtros en el mismo momento

image

Ahí debajo tenemos los filtros, podemos ir con el mouse y tocarlos pero mejor que eso, tenemos teclas de acceso directo para hacerlo

Teclas rápidas

  • Methods (Alt + M)
  • Interface (Alt + I)
  • Classes (Alt + C)
  • Structure (Alt + S)
  • Enums (Alt + E)
  • Delegates (Alt +D)
  • Namespace (Alt + N)
  • Keywords (Alt + K)
  • Snippets (Alt + T)

intellisense filtering

Como se ve se pueden ir tocando las teclas rápidas y agregando o quitando filtros.

De momento no existe la posibilidad de hacer nuestros propios filtros, por ejemplo si quisiéramos mostrar elementos con ciertos atributos hoy no lo podemos hacer.

De todos modos es una característica excelente que seguro le vamos a sacar provecho.

Hasta la próxima, nos leemos.

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

Variable not found

Enlaces interesantes 270

February 20, 2017 10:28 AM

Happy 15th Birthday .NET!Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET

ASP.NET

.NET Core / ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Componentes/bibliotecas

Publicado en Variable not found

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

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

Recuperando programas antiguos: El proceso

February 20, 2017 08:30 AM

Llevaba unos diez años intentado encontrar una disquetera de 5 y cuarto, las que manejaban disquetes que se llamaban, erróneamente, blandos, de 5,25 pulgadas. Había mirado en tiendas de segunda mano, preguntado a conocidos entusiastas de la informática que llevan tiempo en el mundillo, y nada. Resulta extraño que nadie se haya planteado crear una […]

La entrada Recuperando programas antiguos: El proceso aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

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

Ejemplo con PB/CC

February 18, 2017 02:23 PM

Cuando escribía Ejemplo con PB/Forms, creo que la conclusión a la que llegasteis es que PowerBasic es un lenguaje bastante tedioso. Nada más lejos de la realidad, lo que en realidad es tedioso es crear aplicaciones Windows, usando su API, y el bucle de proceso de mensajes. Algo en donde PBForms / DDT ayuda, pero […]

La entrada Ejemplo con PB/CC aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Blog Bitix

Ejemplo de RabbitMQ con Java para enviar y recibir mensajes

February 18, 2017 09:00 AM

Entre las ventajas de integrar dos aplicaciones mediante el envío de mensajes están que evita que estén acopladas y la comunicación es asíncrona. Con RabbitMQ también podremos implementar cada uno de ellas con el lenguaje de programación que prefiramos de entre las varias posibilidades para las que ofrece clientes y por esto último podemos preferir usarlo en vez de las especificación JMS propia de Java EE que nos obligaría a usar un servidor de aplicaciones que lo implemente, posiblemente JBoss/Wildfly o Weblogic en vez de Tomcat o Jetty. En el artículo incluyo un ejemplo para el lenguaje Java mostrando el envío y recepción de mensajes junto con la aplicación de administración que nos proporcionará información útil.

RabbitMQ
Java

Las aplicaciones que se integran mediante el envío y recepción de mensajes evitan el acoplamiento y sincronía junto con la posibilidad de implementar cada una de ellas con diferentes lenguajes o plataformas. Entre las especificaciones que componen Java EE está JMS pero tanto la aplicación que envía como la que recibe mensajes deben estar programadas en el lenguaje Java, a menos que incluyamos un adaptador que permita a la aplicación no Java interactuar con JMS.

RabbitMQ es un software que proporciona una funcionalidad similar a JMS pero con la ventaja que ofrece soporte para los lenguajes más populares como Java y JVM, Ruby, Python, .NET, PHP, Node.js, Go y varias más. Usa varios conceptos similares a los presentes en JMS como que el emisor envía los mensajes a una cola y el receptor los lee de ella de modo que ni el emisor ni receptor se conocen consiguiendo de este modo el desacoplamiento entre ellos. Los mensajes son leídos de las colas con la posibilidad de que cada mensaje sea recibido por un único receptor o por cada uno de ellos.

Realmente en RabbitMQ los mensajes no son enviados directamente por el emisor a las colas sino que se envían a un exchange que finalmente lo enruta y encola en la cola destino. Los exchanges pueden ser directos basando su lógica de encolado según el valor del binding key enviada junto con el mensaje y un routing key asociada con la cola o basados en temas en los que se usa una cadena formada por una lista de palabras separada por puntos, la lógica de enrutado se toma según si el binding key cumple el patrón del routing key que puede contener sustituidores de palabras, siendo un * una palabra exacta y # varias palabras contiguas.

En la documentación de RabbitMQ hay 6 tutoriales en diferentes lenguajes para el envío y recepción de mensajes.

Basándome en estos ejemplos he creado un proyecto uno muy similar al Tutorial 1, ejecutable más fácilmente con Docker y Gradle.

Tanto en el emisor como en el receptor deberemos declarar las colas que van a usar (si una no existe se creará y si existe se usará), a la cola se le asigna un nombre y el receptor define un manejador para recibir los mensajes según se envían.

Para ejecutar el ejemplo usaré el contenedor de Docker para RabbitMQ iniciándolo con Docker Compose y el siguiente archivo descriptor. Puedes consultar la serie de artículos sobre Docker que escribí para conocer cómo usarlo.

Una vez iniciado el contenedor y con el código fuente del ejemplo, iniciamos en cualquier orden la parte receptora de los mensajes y la parte emisora de mensajes con los comandos ./gradlew receive y ./gradlew send respectivamente, momento en el cual veremos que en la consola salen las notificaciones de recepción y envío.

En la comunicación con RabbitMQ se puede usar TLS/SSL así como mecanismos de autenticación y autorización para mayor seguridad. Usando confirmaciones si el receptor falla en el procesado el mensaje no se pierde ya que no se habrá declarado como acknowledge aún así si RabbitMQ falla los mensajes se perderán a menos que las colas se declaren como persistentes las cuales se guardarán en disco perdurando a una catástrofe.

RabbitMQ posee un plugin para la administración con el que podemos administrar permisos, tener una vista global, ver ratios de mensajes, estadísticas, colas, exchanges y más información, nos da información muy interesante sobre el estado del procesamiento de mensajes. Es accesible mediante el navegador y la URL http://localhost:15672/. En la captura del estado de la cola hello hay 10 mensajes encolados pendientes de entregar a algún receptor.

Para profundizar más en las aplicaciones basadas en mensajes con RabbitMQ dos buenos libros son Learning RabbitMQ y Matering RabbitMQ cubriendo temas más avanzados como clustering, alta disponibilidad, arquitectura, patrones de diseño, seguridad y rendimiento.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando docker-compose up && ./gradlew receive && ./gradle send.

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

xailer.info

La mejor documentación de Harbour

February 15, 2017 09:30 AM

Estimado usuario de Xailer,

Queremos compartir con vosotros la que pensamos es la mejor documentación de Harbour realizada hasta la fecha. Es un estupendo trabajo realizado por Viktor Szakats y desde aquí queremos agradecerlo por el gran esfuerzo realizado. Este es el enlace:

https://harbour.github.io/doc/

Saludos,

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

xailer.info

Servidor virtual y en la nube, una opción cada vez más real para la pyme

February 14, 2017 04:27 PM

Buenas tardes,

No lo digo yo, lo dice un blog muy conocido enfocado a la PYME. Os aconsejo que le echéis un vistazo y se lo paséis a vuestros clientes para empezar a crearles la necesidad del cambio.

https://www.pymesyautonomos.com/tecnologia/servidor-virtual-y-en-la-nube-una-opcion-cada-vez-mas-real-para-la-pyme

Por supuesto, Xailer en su versión Enterprise ofrece todo lo necesario para hacer software de acceso remoto a la nube, siendo su gran baluarte el data control WebDataSource que permite realizar aplicaciones completamente autónomas (un sólo archivo EXE) que no requieren ningún tipo de instalación y que acceden remotamente a los datos en servidores en la nube con absoluta seguridad.

Si alguno de vosotros tiene algo de experiencia o un caso de éxito, os agradezco que pongáis un comentario al respecto.

Un saludo

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

Variable not found

Refresco automático de setting tipados en ASP.NET Core 1.1

February 14, 2017 09:34 AM

ASP.NET CoreHace algunos meses comentábamos por aquí cómo en ASP.NET Core es posible modificar los archivos de configuración de una aplicación en caliente, sin necesidad de detenerla, siendo los cambios aplicados de forma inmediata.

En aquél momento ya vimos que era realmente sencillo conseguirlo cuando usábamos settings no tipados, bastaba con añadir el parámetro reloadOnChanges a la hora de añadir el origen de configuración, como en el siguiente ejemplo:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
Sin embargo, también vimos que conseguir lo mismo cuando queríamos acceder a los settings de forma tipada era algo más engorroso, puesto que había que configurar manualmente el proceso de recarga y bindeado de datos con la instancia de la clase de configuración, para poder acceder luego a ella a través de un objeto IOptions<T> disponible en el contenedor de dependencias.

Pues bien, en ASP.NET Core 1.1, la cosa se ha simplificado bastante :) Vamos a ver paso a paso cómo acceder de forma tipada a los settings almacenados en un archivo JSON, y que éstos se refresquen automáticamente cuando el archivo de configuración sea modificado.

1. Añadimos al raíz del proyecto un archivo de configuración, al que llamamos por ejemplo MySettings.json, e introducimos un contenido como el siguiente. Observad que podemos estructurar los settings como más nos convenga:
{
"AppTitle": "Settings demo",
"Author": {
"Name": "John Smith",
"Age": 99
}
}
2. En el constructor de la clase Startup, creamos un objeto de configuración añadiendo el archivo JSON como origen, indicando que debe recargar automáticamente mediante el parámetro reloadOnChanges:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("mysettings.json", optional: false, reloadOnChange: true)
... // Other setting sources
Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }
...
}
3. Creamos una clase cuya estructura coincida con la de los settings a los que queremos acceder de forma tipada, por ejemplo como la que sigue. Aseguraos de que los nombres de las propiedades coincidan con los usados en el archivo de configuración:
public class MySettings 
{
public string AppTitle { get; set; }
public AuthorInfo Author { get; set; }

public class AuthorInfo
{
public string Name { get; set; }
public int Age { get; set; }
}
}
4. En ConfigureServices() configuramos la instancia de la clase de settings en el contenedor de dependencias, asociándola al objeto de configuración que hemos creado anteriormente:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
... // Other services
services.Configure<MySettings>(Configuration);
}
Como podréis comprobar, no hay nada nuevo en lo que hemos hecho hasta el momento. En versiones de ASP.NET Core anteriores a la 1.1 eran exactamente los pasos que debíamos seguir para tener nuestra instancia tipada disponible a través de instancias IOptions<T> obtenidas a través del inyector de dependencias. La novedad viene ahora ;)

5. Para acceder a los datos de configuración siempre frescos lo hacemos a través de una instancia de IOptionsSnapshot<T>, como en el siguiente ejemplo:
public class TestController : Controller
{
private readonly MySettings _settings;

public TestController(IOptionsSnapshot<MySettings> settings)
{
_settings = settings.Value;
}
public IActionResult Index()
{
var message = $"{_settings.AppTitle}, " +
$"created by {_settings.Author.Name} " +
$"({_settings.Author.Age} years old)";

return Content(message);
}
}
Observad que el único cambio respecto a las versiones anteriores es que el acceso a la instancia de la clase de settings tipada lo hacemos solicitando un IOptionsSnapshot<T> en lugar de usar IOptions<T>.

Tras esto, si ejecutamos la aplicación, veremos que las modificaciones al archivo de configuración son tenidas en cuenta sobre la marcha, mostrándose en cada acceso a /test los valores actualizados.

Publicado en Variable not found.

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

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

La corta, y tormentosa vida del genio de la computación Phil Katz

February 14, 2017 08:14 AM

Hace ya mucho tiempo, escribía ¿Por qué escribí PGP?, el visionario manifiesto de Phil Zimmermann sobre la privacidad. Hoy quiero hacerme eco del documento The short, tormented life of computer genius Phil Katz, escrito por Lee Hawkins Jr, que se publicase el 21 de mayo del 2000 en el Milwaukee Journal Sentinel, y que hoy […]

La entrada La corta, y tormentosa vida del genio de la computación Phil Katz aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Picando Código

Tomb Raider en GNU/Linux

February 13, 2017 12:00 PM

Feral Interactive es una de las empresas favoritas de quienes jugamos en GNU/Linux. Han publicado en nuestro querido sistema operativo juegos como XCOM, la saga Warhamer, Mad Max, Middle-earth: Shadow of Mordor, y más.

En abril de 2016, Feral publicó Tomb Raider. Este nuevo título es un reboot de la saga y reconstruye el origen de Lara Croft. Con motivo del cumpleaños de Lara, Feral tiene alguno de sus juegos de oferta en su sitio web:

Oferta Tomb Raider

Generalmente podemos comprar el juego a USD 19.99, pero con este descuento del 50% podemos obtenerlo a USD 9.99 y con un descuento del 70% el DLC a 5.99. No había jugado un Tomb Raider desde el original en los 90, y aprovechando que decidieron portarlo a Linux, lo compré (sólo el juego, no el DLC). Obtuve una clave para Steam y lo dejé descargando en el cliente mientras salía a hacer unos mandados. ¡Atención que la oferta es válida hasta el viernes que viene!

Los requisitos mínimos para sistemas Steam OS y Linux son:

Mínimo:
Ubuntu 14.04 o Steam OS 2.0 (64 bit)
Procesador Intel i3 o AMD FX-6300
4GB de memoria RAM
15 GB de espacio en disco (una vez instalado en mi computadora ocupa unos 10.48 GB)
Tarjeta de video: Nvidia GeForce 640 con 1GB de memoria (testeado en driver 364.12), AMD R7 260X (testeado con driver MESA 11.2).

Sugerido:
Ubuntu 14.04 o Steam OS 2.0 (64 bit)
Procesador Intel i5
8GB de memoria
Tarjeta de video Nvidia GeForce 760 con 3GB de memoria

La computadora donde lo instalé es una laptop de 2012 con Debian Stretch (testing), un procesador Intel Core i7-3517U @ 1.90GHz, tarjeta de video Nvidia GeForce 610M y 8GB de memoria Ram. Se le notan los años ya, porque estoy jugando con los gráficos al mínimo y el benchmark no es muy optimista:

Tomb Raider - Benchmark

De todas formas se deja jugar, sabiendo que podría verse mucho mejor y tener muchos más FPS en una computadora más potente. Habiendo jugado unas horas desde que lo compré, ya estoy enganchado.

Desde el principio tenemos varias cinemáticas que nos van introduciendo en la historia. Uno de los recursos que usa (y viene estando muy de moda en juegos AAA últimamente) son escenas interactivas (Quick time events). En medio de una cinemática o evento tenemos que reaccionar apretando un botón o serie de botones que se muestran en pantalla en un tiempo determinado para lograr un resultado. Hace un poco más interactivas algunas escenas, pero el abuso que he notado de este recurso en distintos juegos hace que no sea muy partidario. Además me resulta perezoso, pero por algo tampoco juego tantos juegos AAA…

La historia es entretenida y vamos siendo testigos del desarrollo de la personalidad de Lara Croft. Empieza siendo una inocente arqueóloga -en un momento del juego hasta le escuchamos decir “Odio las tumbas”- y pasa por miles de situaciones que van formando su carácter de heroína aventurera asesina. Así también se van dando pistas de a poco del misterio que cubre la isla donde se desarrolla todo.

Como me lo esperaba, premia la exploración. Hay muchos secretos e ítems que podemos encontrar explorando y usando elementos del ambiente. Algunas situaciones me dieron la impresión de estar jugando una versión de The Legend Of Zelda, pero para adultos. Hay incluso unas escenas en las tumbas escondidas donde Lara abre un cofre de tesoro enorme que me resultó muy familiar. La observación de “para adultos” es porque incluye mucha violencia, lenguaje “fuerte” y un poco de gore. En ciertas partes hasta se incluyen elementos del género terror, creando ambiente tenso seguido por la aparición de algún tipo de susto de golpe.

Lara tiene que cazar, escalar, explorar, prender fuego cosas y asesinar para mantenerse viva. Las armas que vamos obteniendo se pueden mejorar con cosas que encontramos en el camino. A su vez, Lara gana experiencia al realizar ciertas acciones, y podemos usarla para aprender distintas habilidades de caza, supervivencia y ataque. Los controles son cómodos, los vamos aprendiendo a medida que necesitamos nuevas acciones. Ahora que le agarré un poco la mano, por alguna razón matar a los maleantes de un headshot con arco y flecha me resulta muy disfrutable.

Lo estoy jugando con el control de XBox en la PC. Con la palanca de la izquierda movemos a Lara y con la de la derecha la cámara, la configuración común para este tipo de juegos. El Steam Controller parece no haber funcionado, pero debería probar de nuevo.

En conclusión me viene resultando muy bueno por ahora y lo recomiendo. Si les interesa comprarlo, aprovechen la oferta en la tienda de Feral.

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

Variable not found

Enlaces interesantes 269

February 13, 2017 08:08 AM

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

.NET

ASP.NET

.NET Core / ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Componentes/bibliotecas

Y para acabar, añado una tira que refleja algo que seguro habéis vivido en algún momento. Todos llevamos dentro un desarrollador que sigue trabajando mientras dormimos, y a veces incluso nos ayuda a resolver problemas espesos…

image

Publicado en Variable not found

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

Koalite

Tratar con Fechas en JSON en Javascript y TypeScript

February 13, 2017 05:06 AM

Hace ya tiempo que JSON ganó la batalla de los formatos de transmisión de datos y se hizo ubicuo. Es simple, fácil de leer, fácil de editar manualmente… una maravilla, vamos. O no. Por desgracia, un lenguaje cuya grámatica cabe en el reverso de una tarjeta de visita también tiene limitaciones importantes, y una de ellas, con la que todos tropezamos de vez en cuando, es la falta de soporte estandarizado para fechas.

Al final cada serializador de JSON utiliza su propio sistema para tratar con fechas. Algunos optan por convertir fechas a strings usando el formato ISO 8601, otros prefieren utilizar formato epoch para convertirlas a números, y otros muchos utilizan formatos específicos en sus aplicaciones.

El problema de esto es que al recomponer los datos serializados hemos perdido información del tipo original, por lo que en lugar de un valor Date/DateTime/etc., tendremos un string o number. Si a eso le unes que generalmente JSON se utiliza sin acompañarlo de un esquema, interpretar los datos que tenemos es complicado y acaba siendo incómodo.

Hace unos días comentaba el tema con los señores Landeras y Ros, reconocidos expertos en la materia, y acabamos con un pequeño catálogo de opciones para tratar con esta situación. Algunas son más simples, otras aportan más magia. Hasta dónde quieras llegar es cosa tuya.

Todos los ejemplos son aplicables a Javascript, pero veremos también hasta dónde son “tipables” con TypeScript.

En TypeScript el problema es aun mayor, porque al tener el tipado estático es fácil pensar que estamos trabajando con C# o Java, y que si tenemos una referencia a algo que dice ser un Date realmente es un Date, pero no tiene por qué ser necesariamente así. Podemos escribir let d: Date = "Macario" as any, y no descubriremos el problema hasta que intemos usar d, lo que puede ocurrir mucho tiempo después. En Java o C#, aunque podríamos engañar al compilador pasando por los casts correspondientes, en tiempo de ejecución al menos obtendríamos el error en el momento de hacer la asignación incompatible y no mucho tiempo después al intentar usar la referencia.

Vaya por delante que, por las características de JSON, vamos a necesitar saber a priori el formato que usará el servidor para serializar las fechas. Si no, la parte de convertirlas a objetos Date se puede complicar enormemente porque implicaría empezar a probar formas de conversión hasta que alguna funcione, y nunca estaríamos muy seguros de si esa conversión es correcta o sólo fruto de la casualidad.

Parsing manual

Esta es la opción más directa y que casi todos habremos usado alguna vez. La idea es realizar una conversión explícita de las propiedades que necesitamos:

getCustomer('/customer/1').then(function(customer) {
  customer.birthdate = new Date(customer.birthdate);
  customer.lastLogin = new Date(custoemr.lastLogin);
  return customer;
});

Cuando obtenemos el objeto deserializado desde JSON, nos encargamos de actualizar las propiedades que son de tipo Date (en este caso asumiendo que nos llega un valor que new Date es capaz de interpretar, pero podríamos usar técnicas más avanzadas para parsearlo).

Como esto es un poco tedioso, podemos escribir una función que nos eche una mano:

function convertDates(target, ...properties) {
  for (let prop of properties)
    target[prop] = new Date(target[prop]);

  return target;
}

getCustomer('/customer/1').then(function(customer) {
  return convertDates(customer, 'birthdate', 'lastLogin');
});

En TypeScript podemos tipar parte de la función convertDates usando keyof T, pero necesitaremos recurrir a algún any dentro de la función y intentar parsear propiedades que no son fechas:

function convertDates<T, S extends keyof T>(target: T, ...properties: S[]) {
  for (let prop of properties)
  target[prop] = new Date(target[prop] as any) as any;
  return target;
}

// Esto es válido
convertDates(customer, 'birthdate');

// Esto genera un error de compilación
convertDates(customer, 'invalid-property');

// Pero desgraciadamente esto no lo detecta el compilador
convertDates(customer, 'name');

No es una maravilla, pero algo ayuda el tipado.

Lo peor que tiene esta opción es que es laboriosa de mantener y muy propensa a errores. Si añadimos nuevas propiedades al objeto serializado o les cambiamos el nombre, hay que actualizar las invocaciones a la función convertDates para que las tenga en cuenta.

Una forma de solucionarlo es tener algún mecanismo que nos permita detectar potenciales fechas y haga la conversión automática. Para ello podríamos aplicar alguna convención del tipo “todos las propiedades fecha lleva el sufijo Date” o “todos los strings con formato ISO 8601 son fechas”.

Aun así, hay que recordar llamar a convertDates cada vez que obtengamos un objeto que proceda de deserializar JSON.

Aprovechando JSON.parse

La forma que todos conocemos de deserializar JSON en Javascript es utilizando JSON.parse, que recibe un string y devuelve el objeto deserializado.

Lo que no es tan conocido es que JSON.parse recibe un segundo parámetro, el reviver, que permite controla la forma en que se realiza la deserialización.

Llevado esto a nuestro problema de fechas, si pudiéramos ser capaces de detectar los valores que representan fechas, por ejemplo porque se ajustan a una expresión regular, podríamos automatizar la conversión:

const customer = JSON.parse(someJsonString, function(key, value) {
  if (typeof value !== 'string')
    return value;

  const isoDate = /(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/;

  return value.match(isoDate) ? new Date(value) : value;
});

Con esta solución tenemos dos problemas.

El primero es que volvemos a necesitar acordarnos de invocar JSON.parse con nuestro reviver, y si se nos olvida tendremos problemas. Si tienes un único punto de la aplicación que parsea JSON no es demasiado grave porque sólo tendrás que hacerlo ahí, pero si andas parseando JSON por toda la aplicación es más incómodo (y tal vez deberías darle una vuelta a ese diseño).

De todas formas, podrías evitar el problema usando monkey patching sobre JSON.parse:

(function() {

  const customReviver = function(key, value) {
    if (typeof value !== 'string')
      return value;

    const isoDate = /(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/;

    return value.match(isoDate) ? new Date(value) : value;
  }

  const _parse = JSON.parse;
  JSON.parse = function(text, reviver) {
    return _parse(text, reviver || customReviver);
  }
})();

¿Qué tal se lleva esto con el tipado de TypeScript? Igual de bien o mal que antes de hacer el parcheado. El tipo de JSON.parse no ha cambiado y sigue siendo:

parse(text: string, reviver?: (key: any, value: any) => any): any;

Por tanto, lo que nos devolverá es un any, del cual haremos un cast al tipo que queramos y ya está, ya tendremos algo que parece un Customer (por ejemplo) de cara al compilador, pero que vete tú a saber qué lleva dentro y, lo más importante, ya veremos cuándo te enteras de que no es lo que pensabas.

El segundo problema que tiene esta solución es que no siempre que se parsea JSON se pasa por este método, lo que hace que aunque lo hayamos parcheado se nos puedan escapar casos. Por ejemplo, si estás utilizando fetch y response.json(), el parsing se hace a nivel más bajo (al menos en Chrome), por lo que esta solución no te sirve.

Interceptando las respuestas del servidor

En la mayoría de los casos el momento en que necesitamos deserializar JSON es cuando estamos recibiendo una respuesta de un servidor. Hay otros escenarios, como recuperar datos de LocalStorage o SessionStorage, pero son menos frecuentes.

Muchas librerías permiten interceptar de alguna forma la respuesta y procesarla, por lo que es un buen punto para enganchar nuestra conversión de fechas. Si estás utilizando fetch, podemos extender el objeto Request para parchear el método json(), o incluso añadir nuestro propio método haciendo algo así:

Response.prototype.typedJson = function () {
  // Aquí podemos usar cualquiera de las técnicas anteriores,
  // por ejemplo, la del reviver
  const customReviver = function(key, value) {
    if (typeof value !== 'string')
      return value;

    const isoDate = /(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/;

    return value.match(isoDate) ? new Date(value) : value;
  }

  return this.text().then(text => JSON.parse(text, revivir));
}

Podríamos haber reescrito directamente el método json, pero en este caso prefiero mantener también el método original por si fuese necesario acceder al JSON “puro” en algún escenario.

Llevado a TypeScript, podemos aplicar la técnica para extender tipos existentes que vimos hace unas semanas. Además del añadir typedJson al prototipo de Response usaríamos el declaration merging para tiparlo incluyendo esto en nuestro código:

interface Response {
  typedJson<T>(): T;
}	

Con esto, el uso quedaría bastante cómodo:

fetch('/customer/1')
  .then(response => response.typedJson<Customer>())
  .then(customer => customer.name);

No tenemos más seguridad de tipos que antes (seguimos convirtiendo por debajo de any a T), pero al menos las fechas estarán convertidas a Date y el código queda muy legible.

Resumen

Todas estas técnicas no dejan de ser parches para el problema subyacente, que es la elección de un formato de serialización con muchas limitaciones como es JSON. Desgraciadamente es también uno de los formatos más populares y toca lidiar con él.

Probablemente lo más limpio sea la primera opción porque no implica andar tocando los prototipos de cosas existentes, pero también es cierto que, ya que estamos en un lenguaje que lo permite (y pagas un precio por ello), parece razonable intentar aprovecharlo.

Posts relacionados:

  1. Echo de menos la BCL: formato y parsing de fechas en Javascript
  2. Sopa de Siglas: AJAX, JSON, JSONP y CORS
  3. TypeScript, ¿ahora sí?

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

Blog Bitix

Cómo crear un servicio de systemd para una aplicación con Spring Boot

February 11, 2017 09:00 AM

La mayoría de distribuciones Linux ya usan systemd como gestor y supervisor de los servicios del sistema. Creando un descriptor podremos gestionar un servicio propio con los mismos comandos de systemd que usamos para cualquier otro servicio del sistema.

Linux
Java

Habiendo creado una aplicación o microservicio, por ejemplo con Spring Boot, necesitaremos que se inicie con el sistema y una forma de gestionarlo para detenerlo, reiniciarlo y que se reinicie en caso de salida abrupta.

systemd es el gestor de servicios que han adoptado la mayoría de distribuciones importantes como Debian, CentOS, RHEL, openSUSE, incluso Ubuntu después de abandonar su propio gestor de servicios Upstart. Podemos usar systemd para que gestione como servicio una aplicación propia. Para ello deberemos crear un archivo unit que describa el servicio y sus dependencias con otros servicios para que se inicie correctamente, él y sus dependencias.

Los servicios se definen en archivos de texto denominados unit que tienen un formato similar a los archivos .desktop que a su vez están inspirados en los archivos .ini de Windows. En la documentación de los archivos unit de systemd se detalla con amplitud los archivos unit de systemd, tienen tres secciones:

  • [Unit]: contiene información genérica independiente del tipo de servicio como descripción, requerimientos, deseos o orden de inicio.
  • [Service]: define el tipo de servicio, los comandos de preinicio, inicio, postinicio, parada, postparada, condiciones reinicio y más parámetros comentados en la documentación de los sevicios de systemd.
  • [Install]: esta sección es usada al habilitar o deshabilitar un servicio en el sistema con el comando systemctl, pudiendo por ejemplo que se inicie este servicio cuando otro se inicie siendo otra forma de declarar dependencias. De este modo se puede indicar que un servicio tiene otros como dependencia pero también se puede indicar que un servicio se inicie cuando otro lo haga.

Usando la aplicación del Ejemplo de API REST en Java con JAX-RS y Spring Boot, crearé un archivo unit de systemd para que se inicie con el sistema y se reinicie en caso de fallo. Primeramente deberemos crear los archivos que definen el servicio para systemd y sus dependencias si las tienen. En los siguientes ejemplos spring-boot-jaxrs.service es una aplicación de Spring Boot con una interfaz REST que simplemente devuelve el mensaje indicado por parámetro con la fecha en la dirección http://localhost:8080/message?message=Hola. spring-boot-jaxrs-postgres.service es el mismo servicio pero que tiene una dependencia sobre un contenedor de Docker con una base PostgreSQL, aunque la aplicación Spring Boot no hace uso de la base de datos PostgreSQL sirve para observar que si se inicia el servicio de la aplicación Java también se inicia el servicio de la base de datos si no estuviera ya en ejecución. postgres.service es el servicio de la base de datos PostgreSQL en un contenedor de Docker y que tiene como dependencia el servicio de Docker.

<noscript><a href="https://asciinema.org/a/102785" target="_blank"><img src="https://asciinema.org/a/102785.png" width="734" /></a></noscript> Servicio de systemd para una aplicación con Spring Boot

La instalación de la aplicación y de los servicios de systemd en el sistema se realizan copiando archivos, cambiando algunos permisos y usando los comandos de systemd para gestionar los servicios. Los mensajes de salida que emite el servicio se obtienen con el comando journalctl -u spring-boot-jaxrs.service.

Los archivos unit propios deben ser ubicados en el directorio /etc/systemd/system/, siendo el directorio /usr/lib/systemd/system/ donde se ubican los instalados por los paquetes del sistema. Iniciado el servicio con el comando sudo systemctl start spring-boot-jaxrs.service, si queremos habilitarlo con el inicio del sistema usamos el comando sudo systemctl enable spring-boot-jaxrs.service. Para ver el estado del servicio usamos el comando sudo systemctl status spring-boot-jaxrs.service.

En los enlaces de referencia hay documentación más detallada tanto para gestionar los servicios con systemd como también documentación de sus archivos unit.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando sudo systemctl start spring-boot-jaxrs.service.

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

xailer.info

Múltiples escritorios de Windows 10

February 10, 2017 10:01 AM

Estimados usuarios de Xailer,

Tan sólo quiero compartir con vosotros una pequeña herramienta que acabo de descubrir. Siempre he echado en falta en Windows la posibilidad de tener varios escritorios virtuales, y de hecho probé varias aplicaciones, que no me gustaron, antes de que por fin con Windows 10 los incluyese. La solución aportada por Windows 10 funciona muy bien, pero de forma inconcebible se les ha olvidado incluir algo que para mi es esencial que consiste en saber que escritorio virtual estoy en cada momento. Manias de uno 😉

Pues bien, si alguno tenéis manías como las mías, existe una pequeñísima utilidad que hace el trabajo poniendo un pequeño icono en la barra de tareas que además permite cambiar el fondo de pantalla cuando cambiemos de escritorio. Su nombre es VirtualDesktopManager y lo podéis descargar de aqui: https://github.com/m0ngr31/VirtualDesktopManager/releases. Como veis es un enlace un proyecto en GitHub, por lo que incluso está todo el código fuente del proyecto.

¡Espero que os guste!

Un saludo

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

Picando Código

Personalizar el inicio de sesión de la terminal con fortune, cowsay y lolcat

February 09, 2017 12:00 PM

Ayer publiqué en Twitter mi nuevo mensaje de bienvenida de la terminal cuando inicia una nueva sesión. Como me preguntaron cómo se hacía, aprovecho para dejar la información por acá para quienes quieran usarlo. No lo inventé yo, lo he visto varias veces en foros y sitios sobre Linux, y parece ser de uso común para personalizar la terminal.

Se trata de un mensaje del comando fortune de Unix, un programa que muestra un mensaje al azar de una base de datos de mensajes. Algunos son citas directas de distintos autores, chistes, y más. El texto que sale de fortune se pasa al comando cowsay que es un filtro de texto que genera una imagen en ASCII de una vaca diciendo el mensaje que le pasemos. Este texto a su vez se manda al comando lolcat que se encarga de darle color al mensaje.

El comando final quedó así (por ahora):


fortune -a | cowsay -p | lolcat

Lo agregué a mi archivo ~/.bashrc, el script que ejecuta Bash cada vez que inicia una sesión interactiva.

fortune

Por lo menos en Debian, el paquete fortune requiere un paquete adicional fortunes-min que incluye una base de datos bastante chica de mensajes. Para obtener más mensajes podemos instalar el paquete fortunes, y si buscamos más, podemos encontrar paquetes como fortunes-off (mensajes ofensivos) y fortunes-es (mensajes en español) y fortunes-es-off (mensajes ofensivos en español).

cowsay

Algo interesante de cowsay es que tiene varios formatos para el personaje que muestra el mensaje que no necesariamente debe ser una vaca. Si ejecutamos cowsay -l, podemos ver todos los formatos disponibles en nuestro sistema. Ejemplo:


$ cowsay -l
Cow files in /usr/share/cowsay/cows:
apt beavis.zen bong bud-frogs bunny calvin cheese cock cower daemon default
dragon dragon-and-cow duck elephant elephant-in-snake eyes flaming-sheep
ghostbusters gnu head-in hellokitty kiss koala kosh luke-koala mech-and-cow
milk moofasa moose mutilated pony pony-smaller ren sheep skeleton snowman
sodomized-sheep stegosaurus stimpy suse three-eyes turkey turtle tux
unipony unipony-smaller vader vader-koala www

Así que tenemos varias opciones como un tux, una tortuga, el demonio de BSD, Ren & Stimpy y más. Para hacer uso de uno de estos formatos, simplemente ejecutamos cowsay -f formato, como cowsay -f turtle por ejemplo. Existen varios parámetros para cambiar la apariencia de la vaca misma, dependiendo de sus emociones o estado físico. La opción -b inicia en modo Borg, -d muestra una vaca muerta, y más. RTFM con man cowsay para conocer más parámetros.

lolcat

Es una gema Ruby para darle los colores del arcoíris a lo que le mandes desde un archivo o la entrada estándar.

La instalamos con:

$ gem install lolcat

Lo podemos usar para un archivo o desde la salida estándar directamente:

$ echo "Hola mundo, esto es un texto desde la entrada estándar" | lolcat

Tiene varios parámetros para personalizar el arcoíris que muestra y si queremos animación. Pueden ver el código fuente en GitHub.

Es el componente final para obtener un inicio asombroso de sesión en nuestra terminal:

fortune-cowsay-lolcat

 

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

Blog Bitix

Conferencia BilboStack 2017

February 08, 2017 08:30 PM

Cuando me inscribí en la BilboStack para reservar entrada no me llamaron mucho la atención las presentaciones del programa pero ya a una semana de decidir a cuales iba a ir definitivamente he tenido dificultades para elegir y en varios casos me hubiese gustado ir a las de los dos tracks. Como años anteriores la BilboStack se ha celebrado en Bilbao en el mismo emplazamiento de la Universidad de Deusto pero volviendo como en años precedentes al edificio de las ingenierías. Otro cambio ha sido que este año fueron cuatro presentaciones por track cuando en años anteriores fueron cinco.

El número de asistentes ha sido numeroso quedando algo de sitio libre en el track 2 que era un aula pero en la sala de conferencias del track 1 aunque tiene cómodas butacas salvo por su estrechez el sitio libre era inexsitente de modo que en algunas presentaciones ha habido algunos asistentes que han debido estar de pie.

BilboStack 2017
Universidad de Deusto

Este era el programa completo con su horario, temas muy distintos y variados como Xamarin, internet of things, el siempre presente JavaScript con Angular y Node, Lean Analytics y DDD entre algunos otros de la siguiente agenda:

Hora Track 1
09:30-10:20 Xamarin.Forms en el mundo real™ : Verdades y Mitos por Josué Yeray
10:30-11:20 Una visión de Angular 2 y TypeScript por Hugo Biarge
11:20-11:50 Café
11:50-12:40 Lights, Camera, Node! por Catalina Oyaneder
12:50-13:40 Domain-Driven Design, uniendo negocio con el software por Gorka Laucirica y Beñat Espiña
Hora Track 2
09:30-10:20 Invisible o desaparece... por Isabel Cabezas y Juliet Moreiro
10:30-11:20 Érase una vez... el Design System por Naiara Abaroa
11:20-11:50 Café
11:50-12:40 Agile for scrummies por Jorge Uriarte
12:50-13:40 Lean Analytics, mi faro de cabecera por Carlos Iglesias
Agenda

Al igual que en ediciones previas hago un pequeño resumen de las presentaciones a las que asistí. Los resúmenes no le hace justicia a las grandes ponencias que fueron en realidad pero espero haber captado y transmitir aquí escuetamente las ideas básicas que se expusieron. Y con este es el tercer resumen consecutivo que escribo de la BilboStack, los anteriores (y posteriores que si tengo oportunidad espero escribir) de esta serie de artículos están al final de este artículo.

Invisible o desaparece… por Isabel Cabezas y Juliet Moreiro

El IoT o esos pequeños dispositivos que tienen conexión a internet están surgiendo como una forma de ayudarnos en algunas situaciones cotidianas como cambiar la ruta cuando hay un accidente para no llegar a un atasco o encender la calefacción antes de llegar a casa o antes de levantarnos, espejos que proporcionan información como notificaciones o el tiempo o un centro comercial que te posiciona y ofrece ofertas según la localización en la que estas y tus hábitos de consumo. Aparatos como Amazon Echo son asistentes a través de los cuales mediante comandos de voz podemos realizar acciones como pedir comida a domicilio.

Estos aparatos conectados a internet nos ofrecen una nuevo área posibilidades. Muestra de ellos es la demostración presentada que consistía en base a los mensajes escritos en Twitter iluminar una lámpara PLAYBULB con color verde si eran positivos, rojo si eran negativos y azul si eran neutros haciendo uso de Microsoft Cognitive Services y de algunas de sus APIs para evaluar el sentido de los mensajes. Por ejemplo el mensaje BilboStak is an awesome event! se evaluará como positivo y sumará a la media para que la lampara cambie a color verde.

El hardware era la propia lámpara y una placa de computación Intel Edison junto con un servicio en la nube de Azure pero perfectamente podría ser una Raspberry Pi u otra de las numerosas pequeñas placas que están surgiendo en este nuevo mercado. El código fuente del ejemplo está compartido en un repositorio de GitHub.

Referencia:

Érase una vez… el Design System por Naiara Abaroa

El diseño de una página es una parte importante de la misma, no considerarlo así seguramente nos encontremos con problemas.

  1. Requiere de un conocimiento específico para hacerlo bien y esta es la habilidad que posee un front-designer.
  2. Falta de arquitectura de CSS a pesar de que existen herramientas como Sass o less se sigue produciendo código espagueti.
  3. Hay duplicidades y está poco estructurado.
  4. Falta de coherencia en la tipografía, color, …
  5. Problemas de especifidad al no considerar la evaluación en cascada y el orden de precedencia de inline, id, clases y elementos con lo que se ha de usar el denostado !important como último recurso.
  6. Mezcla de varias convenciones, en el nombrado de elementos.

La solución es el Design System consiguiendo primero claridad, segundo eficiencia y finalmente «belleza». Siguiendo el Atomic Design se consigue una mayor reutilización y facilidad de mantenimiento combinándolo con herramientas como Sketch para el desarrollo de mockups.

Algunos recursos de diseño e implementaciones conocidas de Design Systems son:

Referencia:

Agile for scrummies por Jorge Uriarte

La situación respecto a las metodologías de desarrollo ha cambiado, hace 10 años había resistencia al cambio ahora se aplica pero tampoco resuelve mágicamente los problemas del desarrollo de todos los casos donde se usa.

Algunas esencias de scrum que permanecerán son:

  • En el producto: no detallar en exceso el backlog ya que cambiará.
  • En las historias: siendo completas, entregables individualmente y según el valor que aportan.
  • En los equipos: siendo estos autoorganizados, multidisciplinares, alineados, dueños del proceso y autónomos.
  • En las entregas: serán incrementales y continuas.
  • En el proceso: no estará sacralizado y cambiará con el fin de mejorar al igual que tratan de conseguir las retrospectivas.

Un sistema ágil es una aproximación a la incertidumbre. Incertidumbre que siempre está presente en los desarrollos de software al tratar de responder preguntas como ¿que hay que hacer? ¿cuanto tiempo se tardará? ¿que tecnología se usará?. Para evitar los problemas que genera la incertidumbre un work in progress o WIP pequeño es un buen arma. Lo terminado elimina incertidumbres, se considera que es lo menos que se puede hacer ahora que de el máximo valor. Una consecuencia es que en el flujo de desarrollo habrá menos cosas pero pasando más rápido. Esto se resume en título del libro Stop Starting, Start Finishing! y que tiene la siguiente reseña.

This booklet tells the story of Justin - a project manager who achieved remarkable results with his team by doing very simple things! This guide covers the core concepts of Kanban for knowledge work, and shows how limiting your amount of work-in-progress can lead to getting things done better and faster.

La combinación de un WIP pequeño junto con un sistema pull en el que no se construye lo no necesario, no se prueba lo que no se puede entregar, no se desarrolla lo que no se puede probar y no se especifica lo no se puede desarrollar produce una reducción de tiempos de entrega, hay mayor predictibilidad y elimina rehacer trabajo.

Referencia:

Domain-Driven Design, uniendo negocio con el software por Gorka Laucirica y Beñat Espiña

El Domain-Driven Design o DDD se centra en el dominio de la aplicación, la lógica de negocio y lo que quiere el negocio de la aplicación.

Los modelos anémicos con getters y setters se consideran un antipatrón y hace que la lógica esté dispersa. En el patrón MVC los controladores pueden contener múltiples responsabilidades generando duplicidad de código. Aplicar los principios SOLID generan código limpio y una arquitectura hexagonal ayuda a no crear en la aplicación una dependencia con el framework posibilitando usar por ejemplo Symfony como herramienta y no como base.

DDD se divide en patrones estratégicos (bounded context) que no tienen código y tácticos (entities, agregados, eventos de dominio, factorías, repositorios) que si tienen código. Hay un servicio para cada caso de uso de la aplicación. Para cosas simples junto con su curva de aprendizaje esto seguramente será demasiado complejo pero en los casos en los que haya lógica de negocio, equipos medianos/grandes si será útil.

Un ejemplo de aplicación donde han aplicado DDD es Kreta.

Referencia:

Nuevamente gracias la dedicación de los organizadores por crear otra edición de este gran pequeño evento anual, los ponentes que altruistamente colaboran compartiendo su conocimiento y a la Universidad de Deusto por acoger un año más uno de los mejores eventos para desarrolladores de Bilbao y alrededores.

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

Picando Código

Cómics: Morgan’s Organs – como “Inside Out” de Pixar pero para adultos

February 08, 2017 12:00 PM

Morgan’s Organs es una idea que se gestó en la cabeza de Daniel Brodie por mucho tiempo. El año pasado decidió convertirlo en un cómic y se unió al artista Robert Jennex para poder realizarlo. Tras una exitosa campaña en Kickstarter, el primer número del cómic vio la luz.

Aquellos que decidimos financiar el proyecto recibimos (entre otras opciones) una copia impresa de la historia de 40 páginas, con una funda especial por el artista Greg Merrit, numerada, firmada por Brodie (al igual que el cómic), un póster y unos stickers. Como se acostumbra en las campañas de Kickstarter, uno podía elegir entre varias opciones de recompensas.

Morgan's Organs #1

En el cómic las entrañas de Morgan forman una comunidad liderada por el cerebro, y cada una tiene su funcionalidad y una personalidad propia. Mientras que la preocupación de Pepe -el órgano reproductor- es el sexo, el cerebro se concentra en la tarea de eseñarle que no todo en la vida es sexo. El hilo conductor de la historia es que ha sido una temporada de apareamiento complicada para Morgan (como Bird Person). Así se van relatando dos visiones en paralelo de la acción: cómo se enfrenta Morgan a sus problemas y cómo reacciona su interior.

Tal vez recuerden una premisa similar en el episodio “The Nose Job” (temporada 3, episodio 9) de Seinfeld donde el cerebro y el pene de Jerry juegan una partida de ajedrez para decidir quién controla sus acciones. Al igual que en ese capítulo, Morgan’s Organs #1 plantea esta situación en la que un hombre debate si pensar con una cabeza o la otra. Seguramente si el cerebro ganara más veces de las que gana en general, el mundo sería un lugar mejor…

Pero el cómic no se queda sólo en esa idea. Cada personaje aporta su personalidad al mundo visceral de Morgan, y no siempre actúan con los intereses comunes de todo el organismo. Hay una lucha entre los órganos presentados en esta historia (algunos muy graciosos) y cómo se enfrentan a los problemas en su sociedad.

El arte caricaturesco acompaña muy bien al estilo de la historia, le quita seriedad a todo el tema y la paleta de colores acompaña. Hay alguna referencia externas en las viñetas, como para dejarnos contentos a los que apreciamos esos guiños. Se supone que es para mayores de edad, este primer número se centra en temas sexuales de manera un poco gráfica (dentro de lo que el estilo permite). Pero nada que no sea natural, así que sería debatible. Simplemente comparte experiencias comunes del protagonista con las que muchos se podrían sentir identificados.

Sin entrar en detalles de la trama, me pareció importante mencionar que no todo se centra exclusivamente en el organismo de un hombre. Supongo que en números posteriores habrá más de eso si se siguen sumando personajes.

La historia es divertida y autocontenida, pero nos deja con ganas de leer más. Además del humor y la diversión, el escritor hasta nos tira alguna moraleja. Pueden ver un preview de este primer número en éste enlace.

Morgan’s Organs #2

Morgan's Organs #2

El segundo número de Morgan’s Organs se encuentra en plena campaña en Kickstarter. Ya se aseguró el importe para financiarlo, y todavía faltan 20 días de campaña. Lo que lo que se sume a partir de estos momentos va directo a alcanzar nuevas recompensas. La descripción de este nuevo libro: “Las cosas siguen igual de embarazosas, graciosas e incómodas para Morgan. Excepto que esta vez, exploramos distintos elementos del cuerpo.”

Si les resulta interesante la premisa, pueden apoyar el proyecto y conseguir ambos libros en esta nueva campaña en Kickstarter. El primer tomo se ofrece a un precio muy conveniente al comprar el segundo. Con suerte Morgan’s Organs alcanzará que alguna editorial decida publicarlo y podamos tener nuevas historias más seguido. Por lo pronto,  me quedo a la espera de la versión impresa de esta segunda aventura de Morgan y sus órganos en Julio de este año.

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

Variable not found

Personalizar la negociación de contenidos en ASP.NET Core MVC

February 07, 2017 07:58 AM

ASP.NET Core MVCDurante el proceso de negociación de contenidos en un API desarrollado con ASP.NET Core MVC, lo habitual es que el output formatter utilizado para componer el resultado enviado de vuelta al cliente sea seleccionado a partir de lo indicado por el cliente en la cabecera Accept de la petición HTTP, pero en este post vamos a ver que esto no tiene por qué ser necesariamente así.

Por ejemplo, supongamos que tenemos una aplicación MVC con un controlador que expone un servicio como el siguiente:
[Route("api/contacts")]
public class ContactsController : Controller
{
private readonly IContactRepository _repository;

public ContactsController(IContactRepository repository)
{
_repository = repository;
}

[HttpGet("{id}")]
public IActionResult Get(int id)
{
var contact = _repository.Get(id);
if (contact == null)
return NotFound();
return Ok(contact);
}
}
Esta acción, que retornaría un objeto de tipo Contact del modelo de nuestra aplicación, podría ser fácilmente utilizada desde otras capas o sistemas, por ejemplo como sigue:
// Petición:
GET http://localhost:2805/api/contacts/1 HTTP/1.1
Accept: application/json

// Respuesta:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 51

{"id":1,"name":"John Smith","phone":"998-12-32-12"}
Imaginad ahora que incluimos en nuestra aplicación ASP.NET Core MVC el paquete Microsoft.AspNetCore.Mvc.Formatters.Xml y añadimos el formateador XML en la configuración de servicios:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddXmlSerializerFormatters();
...
}
A partir de este momento, si en la petición anterior sustituimos el valor del encabezado Accept por "application/xml" obtendríamos lo siguiente:
// Petición: 
GET http://localhost:2805/api/contacts/1 HTTP/1.1
Accept: application/xml
 
// Respuesta:
HTTP/1.1 200 OK

Content-Type: application/xml; charset=utf-8
Content-Length: 178
 
<Contact xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">   <Id>1</Id>
  <Name>John Smith</Name>
  <Phone>998-12-32-12</Phone>
</Contact>
Aunque este comportamiento será válido en la mayoría de escenarios, el framework proporciona otras fórmulas para controlar el formato de salida sin necesidad de atender a dicho encabezado.

1. El filtro [Produces]

Si queremos forzar un formato determinado, lo más sencillo es, sin duda, utilizar el filtro [Produces]. Este filtro, aplicable a controladores o acciones específicas, permite establecer manualmente el tipo de contenido a retornar, ignorando el encabezado Accept indicado por el cliente.

Por ejemplo, la siguiente acción retornará los datos formateados como XML sea cual sea la petición:
[Produces("application/xml")]
public IActionResult Get(int id)
{
...
}
Bueno, obviamente lo anterior es cierto siempre está instalado que el formateador de salida encargado de gestionar las respuestas de tipo "application/xml" (hemos visto antes cómo hacerlo).

En caso contrario, el cliente obtendrá un error HTTP 406 (Not acceptable) porque no existirá ningún formateador capaz de generar correctamente ese tipo de respuesta.

2. Especificar el formateador mediante un parámetro de query string

Otra posibilidad interesante, es poder utilizar otra información contenida en la query string para determinar el formateador a utilizar. Para ello, el framework nos proporciona el filtro [FormatFilter], utilizable tanto en acciones como en controladores, que establece el formato de salida en función del valor indicado en el parámetro de ruta "format" asociado a la petición actual. Observad su uso sobre la siguiente acción:
[FormatFilter]
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var contact = _repository.Get(id);
if (contact == null)
return NotFound();
return Ok(contact);
}
Tras incluir este filtro, el solicitante podría especificar el formato en el que desea obtener los datos directamente indicándolo en la query string. Una petición hacia /api/contacts/1?format=xml retornaría los datos en XML, mientras que serían retornados en JSON si la petición se dirige a /api/contacts/1?format=json.

Es importante tener en cuenta que MVC necesita conocer los mapeos entre los posibles valores del parámetro "format" y los tipos de contenido a los que representan. Es decir, necesita saber que cuando encuentre en la query string el valor "xml", éste se corresponde con el formato de salida "application/xml".

Estos mapeos se encuentran en la colección FormatterMappings, y deben ser configurados en la clase Startup. Por ejemplo, el siguiente código establece mapeos de los valores "js" y "xml" a sus respectivos media types:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(opt =>
{
opt.FormatterMappings.SetMediaTypeMappingForFormat("xml", "application/xml");
opt.FormatterMappings.SetMediaTypeMappingForFormat("js", "application/json");
});
...
}
De esta manera, cuando el parámetro de ruta "format" tenga un valor "xml", la respuesta se generará usando el formateador configurado para los resultados de tipo "application/xml", mientras que "js" se mapeará a "application/json". Por defecto, el framework introduce automáticamente en FormatterMappings el mapeo entre "json" y "application/json", por lo que no sería necesario realizarlo.

3. Especificar el formateador en la ruta de la petición

Antes hemos visto que "format" podemos añadirlo como parámetro a la query string, pero ciertamente no queda todo lo elegante que debería, por lo que siempre podríamos jugar con el sistema de routing y hacer que dicho parámetro sea parte de la ruta. Veamos el siguiente ejemplo, que nos permitiría hacer peticiones como /api/xml/contacts/1 para obtener los datos del contacto en formato XML:
[FormatFilter]

[Route("api/{format}/contacts")]

public class ContactsController : Controller
{
   [FormatFilter]   
[HttpGet("{id}")]   
public IActionResult Get(int id)
   {
    ...   
}

}

4. Especificar el formateador mediante la extensión del recurso solicitado

Otra posibilidad sería usar el formato como si fuera la extensión del recurso solicitado, de forma que una petición como /api/contacts/1.xml retornaría el contacto en XML, mientras que /api/contacts/1.js o /api/contacts/1.json lo retornaría en JSON. Esto podemos conseguirlo de forma igualmente sencilla, sólo retocando un poco las rutas:
[FormatFilter]
[HttpGet("{id}.{format?}")]
public IActionResult Get(int id)
{
...
}

5. ¿Y si quiero seleccionar el formateador usando criterios personalizados?

Pues también podemos hacerlo, pues existe la posibilidad de implementar nuestra propia lógica de selección de formato. Aunque no veo a priori muchos escenarios en los que podría resultar interesante, siempre es bueno saber que estamos hablando de un mecanismo fácilmente extensible.

Por ejemplo, observad el siguiente código, donde heredamos de la implementación por defecto de la clase FormatFilter y hacemos que el formato retornado sea "json" o "xml" aleatoriamente (poco útil, pero seguro que da para echar unas risas con el desarrollador encargado de consumir los servicios ;DD)
public class RandomFormatFilter : FormatFilter
{
private readonly Random _rnd;

public RandomFormatFilter(IOptions<MvcOptions> options) : base(options)
{
_rnd = new Random();
}
public override string GetFormat(ActionContext context)
{
return _rnd.Next(0, 2) == 1 ? "json" : "xml";
}
}
Para activar este selector de formato bastaría con añadir la siguiente línea a la configuración de servicios de ASP.NET Core:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(opt =>
{
opt.FormatterMappings.SetMediaTypeMappingForFormat("xml", "application/xml");
opt.FormatterMappings.SetMediaTypeMappingForFormat("js", "application/json");

}).AddXmlSerializerFormatters();

services.AddSingleton<FormatFilter, RandomFormatFilter>();
}
Publicado en Variable not found.

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

Picando Código

Congelada Debian 9 Strech, próxima versión estable de Debian

February 06, 2017 12:00 PM

Debian StretchEl querido sistema operativo Debian anunció que Debian 9.0 Stretch ha entrado en su fase final de desarrollo y se encuentra en modo “frozen” o congelado. Esto implica que no se migrarán más paquetes nuevos a la distribución salvo que se requiera explícitamente desde el equipo de release.

Stretch será la próxima versión estable de Debian, por lo tanto la que venimos probando los que usamos testing como branch de nuestro sistema operativo.

Los paquetes que quieran ser desbloqueados para actualizarse en la distribución a partir de ahora, deben seguir un proceso de “desbloqueo”. Los cambios que se toman en cuenta para desbloquear son:

  • correcciones en bugs críticos (errores de gravedad crítica, severa y seria) en todos los paquetes
  • correcciones para bugs severos o importantes en paquetes de prioridad: opcional o extra, sólo cuando se puede hacer mediante unstable
  • actualizaciones de traducción y arreglos en la documentación que son incluidos con arreglos del criterio mencionado antes

Se piensa que Debian 9 estable estaría listo este año, pero sabemos que Debian se libera cuando está lista. Algunas de las novedades: Linux 4.9, GNOME 3.22, KDE Plasma Desktop 5.8, Iceweasel es Firefox de nuevo.

Todas sus versiones llevan de nombre clave el nombre de un personaje de Toy Story y la décima no es la excepción. Debian Buster -en honor al perro salchicha de Andy- es el nombre de la próxima versión estable y en la que se convertirá testing eventualmente.

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

Variable not found

Enlaces interesantes 268

February 06, 2017 07:55 AM

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

.NET

ASP.NET

.NET Core / ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data

Visual Studio/Complementos/Herramientas

Componentes/bibliotecas

Otros

Y para terminar, una ilustración que os resolverá para siempre las dudas sobre Map, Filter y Reduce. Una imagen siempre vale más que mil palabras ;)

mapfilterreduce
(Fuente)

Publicado en Variable not found

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

Koalite

Las clases como code smell

February 06, 2017 05:06 AM

Parece que la moda hoy en día es criticar la programación orientada a objetos y glosar las bondades de la programación funcional. Desde esa perspectiva, éste puede parecer un post partidista, pero no es esa mi intención. En serio. De hecho, muchas de las ideas que voy a explicar en el post ni siquiera se pueden considerar programación funcional, sino en todo caso programación procedural de toda la vida.

En realidad esto viene por la típica conversación en twitter en la que el límite de los 140 caracteres hace difícil explicar una idea:

Cada clase que creas en TypeScript es una oportunidad perdida de simplificar el código. Son un code smell que hay que justificar, no la opción por defecto.

Aunque originalmente estuviera pensando en TypeScript, diría que muchos de los argumentos son aplicables a cualquier lenguaje en el que no sea necesario encapsular todo en clases.

Obviamente, si estás utilizando un lenguaje como C# o Java, donde todo debe estar definido necesariamente dentro de una clase, no hay más que hablar. Podrás utilizar clases más o menos degeneradas (llegando al extremo de clases puramente estáticas), pero no podrás salir de ahí.

Sin embargo, si utilizas un lenguaje como Javascript, Python, TypeScript o C++, dispones de más opciones a la hora de organizar el código, y puedes crear clases, pero también puedes crear funciones sueltas, y puedes agrupar esas clases y esas funciones en módulos, que a su vez pueden tener estado propio… en fin, un mundo de posibilidades (para bien y para mal).

Dependiendo del lenguaje hay más o menos tendencia hacia el estilo “clasista”, es decir, definir todo dentro de clases, o “modular”, esto es, crear módulos que agrupan funciones. En el caso de Javascript hay una gran variedad de estilos (quizá con una ligera inclinación al modular hasta hace no mucho tiempo), pero en TypeScript se nota mucho la ascendencia javera y nettera de muchos de sus usuarios y la balanza se inclina hacia el estilo clasista. Demasiado, a mi parecer.

Pero, ¿por qué veo las clases como un code smell en este tipo de lenguajes? Por una cuestión de complejidad. Para mi uno de los factores más importantes a la hora de escribir código es intentar conseguir los objetivos habituales (calidad, mantenibilidad, etc.) de la forma más simple posible, y para ello nada mejor que utilizar los conceptos más simples que pueda.

Igual que no empiezo una aplicación intentando encajar todos los patrones de diseño que conozco y todas las librerías que he visto en Reddit, trato de no introducir complejidad accidental. Cuanto más simples sean los conceptos que estoy utilizando, más fácil será entenderlos y más sencillo será reutilizarlos en distintos contextos. Para ello, suelo intentar partir de las cosas más simples e ir escalando según lo necesito.

Valores y funciones

Lo más fácil que puedes definir, claro, es un valor constante. Si puedes modelar algo como un valor, estupendo porque no habrá mucho que razonar. Sólo necesitas conocer el valor y ya está.

Puede parecer una tontería, pero muchas veces nos dejamos llevar por el síndrome de la abstracción prematura, y lo que podría ser un simple valor, se convierte en una configuración externa que debe ser almacenada en una base de datos o un fichero de texto, y acaba introduciendo una complejidad innecesaria.

Desgraciadamente, sólo con valores constantes no puedes llegar demasiado lejos y siempre necesitamos realizar algún tipo de cálculo o proceso, por lo que el siguiente paso sería tener funciones.

Las funciones son simples. Si son puras, sin efectos colaterales, es especialmente fácil razonar con ellas, pero incluso con funciones impuras puedes generar código bastante simple y comprensible.

Cuando tienes un lenguaje en el que puedes tratar las funciones como valores y pasarlas como parámetro o devolverlas desde otras funciones, o puedes crear cierres lambda, son un mecanismo muy potente para modelar infinidad de escenarios, como veíamos al implementar un diccionario sólo con funciones.

Tener un código basado en funciones, en el que las dependencias de una función son otras funciones (y que pueden ser inyectadas como parámetros si lo necesitas), es llevar el principio de segregación de interfaces al extremo y favorece el principo de responsabilidad única. Por cierto, es curioso que dos de los principios SOLID, tan ligados a la OOP, se resuelvan mejor con funciones que con objetos.

Un “problema” de las funciones es que necesitan recibir como parámetro aquellos datos sobre los que van a trabajar, y eso puede acabar dando lugar a código repetitivo. Es uno de los casos en los que solemos estar tentados de introducir una clase, pero en realidad se puede resolver muy bien con aplicación parcial sin necesidad de introducir ningún concepto nuevo.

Por ejemplo, si tenemos que hacer peticiones a un servidor, puede parecer incómodo tener que estar pasando la ruta en cada petición y es tentador acaba con una clase como ésta para encapsular ese pequeño trozo de estado (la ruta):

class HttpClient {
  constructor(path) {
    this.path = path;
  }
  get(params) {
    // hacer una petición al path con params
    // y devolver una promesa con el resultado
  }
}

Eso parece más cómodo que tener una simple función get(path, params) y andar pasando el path cada vez, pero lo cierto es que si tuviéramos esa función y quisiéramos fijar path lo tendríamos fácil:

function get(path, params) {
  // hacer petición y devolver promesa
}

const getFrom = (path) => (params) => get(path, params);

const getCustomer = getFrom('/api/customer');

getCustomer({id: 10}).then(...);

Este tipo de técnicas nos permiten llegar muy lejos sin necesidad de introducir elementos más complejos, pero hay veces que se pueden quedar cortas.

Módulos con estado

Las funciones que veíamos en el punto anterior podemos agruparlas en módulos por una cuestión meramente organizativa y prácticamente no habrá cambiado nada, pero hay un momento en que los modulos sí añaden complejidad.

Cuando empezamos a tener varias funciones que dependen de un estado común, aunque podemos aplicar técnicas como la anterior para tratar el estado como parámetros de la función, puede llegar un punto en que sea demasiado incómodo o que necesitemos garantizar que realmente se está usando el mismo estado.

Pensad, por ejemplo, en la típica implementación de un log. Normalmente tendrás varias funciones, logInfo, logWarning, logError, que guardarán o no información en el log dependiendo del nivel de detalle configurado.

Este nivel de detalle podríamos pasarlo como parámetro a cada función, pero obliga a gestionar esa información desde fuera del log, y responsabiliza a sus clientes de saber cómo obtener el nivel actual del log y pasarlo de un sitio a otro. Si nos ponemos cabezotas podemos hacerlo igual que en el caso anterior, pero empieza a parecer menos práctico.

¿Necesitamos recurrir a una clase? Todavía no.

En realidad, nos basta con aprovechar el concepto de módulo que existe en Javascript. Podemos tener un módulo que exporte las funciones que necesitamos, y que encapsule (e incluso oculte, si queremos), el estado del que están dependiendo las funciones (en este ejemplo, el nivel de detalle del log).

Cualquiera que quiera usar las funciones podrá importar el módulo y utilizarlas, sin preocuparse de cómo están gestionando su estado interno.

Este escenario no está libre de problemas y pierde parte de la flexibilidad de utilizar funciones más simples.

Resulta más difícil razonar sobre el comportamiento de las funciones porque hay más acoplamiento entre las funciones y un estado que, posiblemente, ni siquiera es observable desde el mundo exterior.

Además, puede ser más complicado reemplazar las dependencias de los clientes que están usando el módulo, porque no es sencillo cambiar un módulo por otro. Existen cosas como proxyquire que se utilizan para testing, pero no es lo más agradable del mundo.

Para solventarlo siempre puedes hacer que las partes del código en las que necesitas más flexibilidad reciban como parámetro las funciones que van a utilizar, y pasarle las funciones del módulo o las que necesites. Vamos, inyección de dependencias en estado puro.

Si lo piensas un poco, esta forma de agrupar funciones en módulos encapsulando parte de estado se parece mucho a otro (¿anti?)patrón de diseño en programación orientada a objetos: el singleton.

Es verdad que tienen muy mala fama, pero al final hay un montón de cosas en una aplicación que son singletons, ya sean explícitos o camuflados en la configuración de contenedor de inversión de control. Echadle un ojo a cualquier framework MVC de moda de C# y Java y encontraréis infinidad de singletons, especialmente en toda la parte de “fontanería” de la aplicación.

Clases

¿En qué momento se hacen necesarias las clases? Cuando necesitamos parametrizar módulos.

Volvamos un momento al caso del log. Al introducir el módulo, evitábamos a todos los clientes del logger tener que andar pasado como parámetro el nivel de log y, sobre todo, tener que estar mantiendo ese valor y obteniéndolo de algún sitio.

¿Y si necesitamos disponer simultáneamente en la aplicación de varios loggers? Es posible que, dependiendo del area de la aplicación, tengamos distintos loggers con distintos niveles de detalle (o si el log fuese más complicado, con distintos destinos para escribir la información).

En ese punto, nuestro módulo se empieza a quedar corto. Ya no hay una sóla configuración para las funciones de log, sino que queremos mantener en paralelo varias configuraciones, y queremos los clientes puedan utilizar una u otra de forma transparente para ellos, tan sólo accediendo al log adecuado.

Ahora sí tiene sentido introducir una clase. Una clase no deja de ser una forma de parametrizar esos módulos que describíamos antes, permitiéndonos crear distintas instancias del módulo, cada una de ellas con su propio estado. Hemos pasado de tener un singleton en la aplicación, a tener distintas instancias de ese componente cada una con su propia configuración.

Las clases solucionan en parte el problema que veíamos en los módulos por la dificultad de reemplazarlos. La dependencia no es entre el cliente y la clase sino entre el cliente y la instancia, por lo que si podemos pasar otra instancia que se comporte como queramos, habremos resuelto el problema.

En lenguajes como C# o Java esto suele requerir un interface o una clase derivada, pero en Javascript con su duck typing o en TypeScript con su tipado estructural, es trivial hacer el reemplazo y de hecho muchas veces ni siquiera es necesario crear un clase explícitamente y basta con crear un objeto anónimo con la estructura adecuada.

A cambio, introducen otro tipo de complejidad, ya que nos obliga a instanciarlas, y eso implica controlar de alguna forma el ciclo de vida de los objetos y el flujo de referencias de un sitio a otro.

En el caso de log, cuando sólo teníamos un módulo, cualquiera podía acceder a él y sabía que tendría la configuración adecuada. Al introducir una clase, si quiero logear algo, ¿de dónde saco la instancia? ¿Creo una nueva? ¿Qué configuración le pongo? ¿Cómo garantizo que todos los puntos de la aplicación que tienen que usar un mismo logger lo están usando, y no creando cada uno el suyo con distintos parámetros?

Toda esta flexibilidad que ganamos al poder parametrizar módulos, implica una mayor carga cognitiva a la hora de utilizarlos, por lo que hay que tenerlo en cuenta.

Conclusión

Un code smell es sólamente eso: código que huele raro. No quiere decir que esté mal, pero quiere decir que es código que necesita una justificación.

Igual que puedo resistir el olor de las clases grandes o acabar con clases degeneradas que sólo contienen métodos estáticos, no tengo ningún problema en utilizar clases en lenguajes como Javascript o TypeScript, pero tienen ser justificables.

Cuando el lenguaje lo permite, prefiero empezar por implementar las cosas de la forma más sencilla posible, e ir escalando en función de las necesidades que van surgiendo, en lugar de utilizar directamente las construcciones más complejas que tengo disponibles.

Posts relacionados:

  1. EventHandlers con jQuery 1.7: on() vs click()
  2. Clases, objetos, funciones e Information Hiding
  3. Usando convenciones para mejorar IHandlerSelector

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

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

Cosas de headhunters

February 04, 2017 10:39 AM

LinkedIn era a mi modo de ver, la única red social que mantenía su espíritu original. Facebook, se ha llenado de virales absurdos y de publicidad, y Twitter más de lo mismo. En LinkedIn en cambio, encontrábamos contenidos interesantes, y era una buena forma de mantener el pulso a temas profesionales. Lo primero que percibí, […]

La entrada Cosas de headhunters aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

» 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