Noticias Weblogs Código

Variable not found

Enlaces interesantes 181

December 22, 2014 12:45 PM

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

.Net

ASP.NET

Data access

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

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

Koalite

Rutas en ReactJS con React Router

December 22, 2014 05:06 AM

Cuando hace unas semanas veíamos qué es ReactJS explicaba que ReactJS no es un framework “todo incluido” (como Angular o Durandal), sino que es más bien una librería que se limita a la generación de vistas. Esto tiene la ventaja de que nuestra aplicación queda mucho menos acoplada a ReactJS, pero también hace que cuando necesitemos más cosas nos toque buscar opciones y decidir cómo queremos hacerlas, cómo vimos al hablar de tests de extremo a extremo con Nightwatch.

En muchas aplicaciones web actuales se acaban manejando rutas desde la parte cliente, y esa es una de las cosas que ReactJS no incluye de serie, pero que podemos implementar utilizando distintas librerías. En este caso vamos a ver una que me ha gustado especialmente: React Router.

React Router (enlace) es una libería para gestionar rutas en aplicaciones que utilicen ReactJS. Está inspirada en el sistema de enrutado de Ember.js y su forma de manejar las rutas es un poco diferente de lo que podemos ver en otros sistemas, como ASP.NET MVC, AngularJS, Express o Compojure, por poner unos cuantos ejemplos.

La idea fundamental es que podemos tener rutas anidadas mapeadas a vistas anidadas. ¿Qué quiere decir esto? Vamos a verlo con un ejemplo.

Un ejemplo

Imaginemos el típico dashboard de estadísticas de una web. Tenemos distintos tipos de métricas: Visitantes, Páginas, Orígenes, etc., y para cada una de ellas podemos una visión global con un par de datos significativos y los detalles, que podemos mostrarlos de forma tabular o mediante una gráfica:

dashboard-sample

Existen varias partes de la página que se van a ir repitiendo entre las distintas “subpáginas” del sitio. Todas tendrán las pestañas de la parte izquierda para navegar entre secciones y, dentro de cada sección, tanto en la vista de tabla como la vista de gráfico se repetirá la parte superior en la que aparece el resumen.

Una forma habitual de resolver esto es mediante el uso de plantillas que permitan “incluir” fragmentos de html comunes en varias páginas, de una forma similar a cómo se hace con las Master Pages de ASP.NET MVC o los layouts de Jade.

En el caso de React Router la forma de resolver este tipo de situaciones es ligeramente diferente y se basa en el uso de rutas anidadas. Al definir las rutas, podemos ir definiendo parte de la estructura de la página y delegar en las rutas hijas la generación del resto de la estructura.

Si pensamos en el ejemplo anterior, podríamos tener las siguientes rutas:

route-parts

  • / : Ruta base en la que se define el menú de la izquierda con las distintas secciones del dashboard.
    • visitors : Ruta para visitantes en la que se define el resumen de visitantes
      • table : Ruta con la tabla
      • chart : Ruta con el gráfico
    • … resto de rutas

De esta forma evitamos que repetir nada entre una “página” y otra, y podemos implementarlo todo mediante componentes de ReactJS independientes.

Uso de React Router

La definición de rutas se realiza a través del componente Router:

var routes = (
  <Route handler="{App"} path="/">
       <Route name="visitors" handler="{Visitors}">
            <Route name="visitors-table" path="table" handler="{VisitorsTable}"/>
            <Route name="visitors-chart" path="chart" handler="{VisitorsChart}"/>
       </Route>
       <Route name="pages" handler="{Pages}">
            <Route name="pages-table" path="table" handler="{PagesTable}"/>
            <Route name="pages-chart" path="chart" handler="{PagesChart}"/>
       </Route>
       {/* ... resto de rutas */}
  </Route>
);

Router.run(routes, function(Handler) {
  React.render(<Handler />, document.body);
});

En la tabla de rutas vamos definiendo la jerarquía de rutas, indicando la manera en que están organizadas y el componente que se encargará de renderizar cada una. Ahora sólo falta definir cada componente:

var App = React.createClass({
  render: function() {
    return (
      <div>
        {/* Pintamos el menú de la izquierda */}
        <Menu/>
        {/* Delegamos al router pintar el resto */}
        <RouteHandler/>
      </div>
    );
  }
});

var Visitors = React.createClass({
  render: function() {
    return (
      <div>
        {/* Pintamos resumen */}
        <VisitorDetails/>
        {/* Delegamos al router pintar el resto */}
        <RouteHandler/>
      </div>
    );
  }
});

var VisitorsTable = React.createClass({
  render: function() {
    return (
      <div>
        {/* Pintamos la tabla */}
      </div>
    );
  }
});

La idea es sencilla, cada componente renderiza la parte que le toca y delega a RouteHandler la generación de la parte que es dependiente de la ruta. Esto permite unir de una forma muy intuitiva la estructura de los componentes con la estructura de las rutas de la página.

Por supuesto se pueden hacer muchas más cosas, como definir rutas por defecto, redirigir de una ruta a otra, crear enlaces automáticamente, pasar parámetros entre rutas y todo lo que cabría esperar de un sistema de enrutado moderno. Todo eso lo podéis ver en la documentación de React Router, que además es bastante clara y completa.

Resumen

Una de las cosas que más me está gustando de ReactJS es que no intenta solucionar todos los problemas de golpe y se centra sólo en la parte de generación de vistas. Eso hace que podamos elegir entre distintas implementaciones para el resto de componentes de la aplicación, y en este caso concreto de las rutas, la solución propuesta por React Router y sus rutas anidades es muy interesante.

Hay un parte que no tengo muy claro todavía si me gusta o no, y es el uso de componentes de ReactJS para la definición de la tabla de rutas. Por una parte, la definición de la tabla de rutas como tal creo que se podría desacoplar más de JSX y hacerla con un API diseñada para ser usada con Javascript “puro”, pero por otra parte la naturaleza jerárquica de las rutas encaja muy bien con el pseudo XML de JSX a la hora de anidarlas.

Supongo que para los que estén acostumbrados a Ember.js (que es de dónde está copiado este sistemma) no será nada nuevo, pero a mi esta idea de las rutas anidadas me ha parecido más cómoda de manejar que los sitemas de había usado anteriomente con AngularJS o ASP.NET MVC. Aun así, si prefieres una alternativa más parecida a ellos, puedes usar React Router Component.

Posts relacionados:

  1. Cómo utilizar ReactJS con Browserify
  2. Crear un componente con ReactJS
  3. ReactJS: un enfoque diferente

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

Blog Bitix

Introducción al gestor de proyectos y tareas Redmine

December 19, 2014 06:57 PM

Redmine
Bitnami

Para desarrollar un proyecto de software se hace imprescindible disponer de algunas herramientas que nos permitan realizar las tareas. Una de estas herramientas es un gestor de tareas, peticiones o errores, que nos permite recoger en una herramienta gran parte de la información, conocer el estado, planificar y hacer el seguimiento las tareas necesario para desarrollar de forma ordenada, sin que perdamos nada de información y pudiendo recuperarla en cualquier momento en un futuro.

Como es habitual herramientas que gestionan tareas disponemos de varias algunas de las más conocidas son Bugzilla, JIRA, Mantis, Trac y la herramienta de la que hablaré en este artículo, Redmine. Cada una de estas herramientas como gestores de tareas son parecidas pero se diferencian en algunas cosas como la licencia que tiene, el esquema de precios o la funcionalidad que ofrece. Redmine tiene una licencia de software libre GPL y por tanto la podemos usar sin ningún coste, en la siguiente tabla podemos compararla con los precios de JIRA que para pocos usuarios son asumibles pero que a medida que se aumentan los usuarios empiezan a ser notables aunque posiblemente alcanzables en función del tamaño de la empresa. En cualquier siendo JIRA también una herramienta excelente Redmine cumple perfectamente con la misma función. En la wikipedia podemos encontrar más opciones y comparar unas con otras.

Si queremos evaluar Redmine una forma sencilla podemos hacerlo mediante una imagen de Bitnami con VirtualBox. En la introducción a Bitnami comento qué es y como nos puede ayudar a disponer de software que en algunos casos no es simple de instalar y que con Bitnami podemos disponer de forma sencilla y rápida, además de como usar con VirtualBox cualquier imagen de Bitnami de las herramientas ofrecidas. Una vez seguidos los pasos de la guía anterior podemos acceder a Redmine con el navegador web y una dirección similar a http://192.168.0.11, el usuario y contraseña para acceder es user y bitnami respectivamente.

Con Redmine podemos adaptar el flujo de las tareas a la forma de organización que empleemos, podemos personalizar el grafo de estados que siguen las tareas y que personas tiene permisos para hacer cada uno de los cambios de estado. También podemos añadir campos personalizados que queremos recoger para cada petición, por ejemplo, podemos querer dar un tamaño a las tareas en función de si estimamos que es grande, media o pequeña. También podemos crear filtros y guardarlos para encontrar fácilmente tareas.

Además de gestionar las tareas Redmine dispone de herramientas que nos pueden ser útiles en el proyecto como una wiki para recoger documentación del proyecto y un repositorio de documentos para aquellos que no queremos incluir en la herramienta de control de versiones por su tamaño pero que queremos que estén disponibles para cualquiera que trabaje con el proyecto.

Pero Redmine es más que una herramienta de gestión de tareas, los complementos pueden añadirle funcionalidad adicional que permite convertirla en un CRM para gestionar las comunicaciones con clientes o en un helpdesk para atender las tareas de clientes. Además de otros como personalizar los usuarios de Redmine o crear pequeñas listas de tareas que nos evitará crear subtareas.

En el siguiente artículo comentaré como instalar el plugin agile de Redmine con la imagen de Bitnami en VirtualBox de forma que podamos visualizar las tareas en un panel kanban, y de un vistazo y rápidamente conozcamos las tareas que están terminadas, que están en progreso, a punto de empezarse o en la cola de tareas por hacer.

Referencia:
5 plugins gratuitos para instalar a Redmine
Aplicar y guardar filtros
Como modificar un filtro
Blog con varios artículos interesantes sobre Redmine

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

Cuaderno de software

Notas sobre tuneo de IntelliJ Idea

December 18, 2014 10:30 AM

Esto son solo unas notas sobre los flags y settings que se proponen aquí para tunear el rendimiento de IntellJ Idea. Ha resultado ser una buena excusa para aprender sobre algunas de las opciones de la JVM.

-server

Si lo arranco en modo servidor, el compilador añade optimizaciones más cachas. Tarda más en arrancar, pero luego tira mejor

-Xms2048m
-Xmx2048m
-XX:NewSize=512m
-XX:MaxNewSize=512m
-XX:PermSize=512m
-XX:MaxPermSize=512m

Heap y permgen

-XX:+UseCompressedOops

http://javarevisited.blogspot.com.es/2012/06/what-is-xxusecompressedoops-in-64-bit.html

-XX:ParallelGCThreads=3

http://es.slideshare.net/jclarity/hotspot-garbage-collection-tuning-guide slide 46

-XX:MaxTenuringThreshold=1

Cuántos ciclos de GC puede aguantar cada objeto antes de ser promocionado al old space (y ser GCado)

(with high values) As your old space is useless (as it is empty), server will do much more full ‘stop-the-world’ GCs to defragment heap. This will have an impact to your applications, as you will see many unnecessary pauses.

http://stackoverflow.com/questions/13543468/maxtenuringthreshold-how-exactly-it-works

-XX:SurvivorRatio=8

Esto indica el ratio (1:8) en el tamaño de cada espacio de supervivientes.

Si los espacios son pequeños, los objetos pasaran directamente a espacios más viejos. Si son demasiado grandes estarán vacíos, provocando stop-the-world

-XX:+UseCodeCacheFlushing

https://blog.codecentric.de/en/2012/07/useful-jvm-flags-part-4-heap-tuning/

-XX:ReservedCodeCacheSize=64m

Idea viene 224 por defecto

Mirar link de UseCodeCacheFlushing

Es para darle un tamaño a la cache de codigo

-XX:+AggressiveOpts

Turns on point performance optimizations that are expected to be on by default in upcoming releases. The changes grouped by this flag are minor changes to JVM runtime compiled code and not distinct performance features (such as BiasedLocking and ParallelOldGC). This is a good flag to try the JVM engineering team’s latest performance tweaks for upcoming releases. Note: this option is experimental! The specific optimizations enabled by this option can change from release to release and even build to build. You should reevaluate the effects of this option with prior to deploying a new release of Java.

http://www.oracle.com/technetwork/java/tuning-139912.html#section4.2.4

Opciones del Garbage collector

-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC

Usar el colector de basura Concurrent Mark Sweep

http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-java-8/

http://sanjaal.com/java/tag/jvm-option-parameter-xxuseconcmarksweepgc/

-XX:+CMSClassUnloadingEnabled

Este activa sweep de clases que ya no se usan. Antiguamente lo haría en la permgen. Tiene que ir de la mano del UseConcMarkSweepGC

-XX:+CMSIncrementalMode

http://www.fixdeveloper.com/2014/03/jvm-tuning-cmsincrementalmode-overrides.html

After some digging around, I found that -XX:+CMSIncrementalMode was set in the parameter. The mode is also known i-CMS and it is scheduled to occur mid-way between minor GC. By doing the GC in small units of time and creating multiple small pauses over the same period, it avoid a long pause. This is helpful for application where low latency is a priority.

-XX:+CMSIncrementalPacing

https://themindstorms.wordpress.com/2009/01/21/advanced-jvm-tuning-for-low-pause/

Enables automatic adjustment of the incremental mode duty cycle based on statistics collected while the JVM is running

-XX:+CMSParallelRemarkEnabled

http://www.liferay.com/es/documentation/liferay-portal/5.2/administration/-/ai/performance-tuning-1

+CMSParallelRemarkEnabled: For the CMS GC, enables the garbage collector to use multiple threads during the CMS remark phase. This decreases the pauses during this phase.

-XX:+UseCMSInitiatingOccupancyOnly

http://stackoverflow.com/a/9698982

Para que el siguiente setting XX:CMSInitiatingOccupancyFraction funcione.

-XX:CMSInitiatingOccupancyFraction=65

https://blog.codecentric.de/en/2013/10/useful-jvm-flags-part-7-cms-collector/

The Throughput Collector starts a GC cycle only when the heap is full, i.e., when there is not enough space available to store a newly allocated or promoted object. With the CMS Collector, it is not advisable to wait this long because it the application keeps on running (and allocating objects) during concurrent GC. Thus, in order to finish a GC cycle before the application runs out of memory, the CMS Collector needs to start a GC cycle much earlier than the Throughput Collector.
As different applications have different object allocation patterns, the JVM collects run time statistics about the actual object allocations (and deallocations) it observes and uses them to determine when to start a CMS GC cycle. To bootstrap this process, the JVM takes a hint when to start the very first CMS run. The hint may be set via -XX:CMSInitiatingOccupancyFraction= where value denotes the utilization of old generation heap space in percent. For example, value=75 means that the first CMS cycle starts when 75% of the old generation is occupied. Traditionally, the default value of CMSInitiatingOccupancyFraction is 68 (which was determined empirically quite some time ago).

-XX:+CMSScavengeBeforeRemark

CONTROVERTIDA

https://blogs.oracle.com/jonthecollector/entry/did_you_know

There is an option CMSScavengeBeforeRemark which is off by default. If turned on, it will cause a minor collection to occur just before the remark. That’s good because it will reduce the remark pause. That’s bad because there is a minor collection pause followed immediately by the remark pause which looks like 1 big fat pause.l

-XX:-TraceClassUnloading

Para desactivar el debuggado de carga/descarga de clases

-ea

Versión EA
EA significa “acceso anticipado (del inglés Early Access)”; EA es una versión preliminar a la siguiente versión del software. Esta versión puede contener muchas funciones nuevas y correcciones de errores y, como versión preliminar, puede contener algunos problemas inesperados. No se recomienda el uso de esta versión preliminar en un entorno de producción. Actualice a la última versión disponible en java.com

-Dsun.io.useCanonCaches=false

WAT

http://konigsberg.blogspot.com.es/2009/10/answer-to-symbolic-puzzler.html

So by default, the cache canonicalization is on, but when you specify the VM arg -Dsun.io.useCanonCaches=false, the cache is never used.

Getting back to the puzzler, the first call to TESTDIR_SYMLINK.getCanonicalPath() always returns the path to the symlink, while the second call returns either the cached value (the path to the symlink) or the up-to-date resolved symlink, but only when -Dsun.io.useCanonCaches=false is specified.

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

Blog Bitix

8+ libros para mejorar como programadores

December 16, 2014 08:00 PM

Hay cantidad de información para aprender y en diferentes formatos desde libros si queremos tener un conocimiento más profundo sobre alguna materia pasando por presentaciones en SlideShare o SpeakerDeck que aún comentando los detalles de forma escueta sirven para conocer los detalles importantes sobre un tema, charlas de hangouts que quizá requieran menos esfuerzo y tiempo por nuestra parte que leer un libro como las compartidas en desarrolloweb o en Virtual JUG, blogs con artículos que explican un detalle específico (aquí hay una buena colección de bitácoras sobre java), katayunos y merendojos en los que se practican técnicas de programación sobre un problema conocido, sencillos, de los que ya se conoce su solución y que se realizan junto a otras personas, convenciones como Codemotion, PyCon, Greach, LibreCon, CAS, Spring I/O, ApacheCon, BilboStack… En estas conveciones se hacen presentaciones de alrededor de una hora para los asistentes, además siendo presenciales permiten reunirse con otras personas con los mismos intereses y de las que algunas los vídeos están disponibles en YouTube… en definitiva, para aprender lo único que se necesita es tiempo y motivación que no es poco después de una jornada laboral que ocupa la mayor parte de nuestro tiempo.

En este artículo comentaré algunos libros que a mí me han gustado y que mucha gente recomienda leer ya que contienen cantidad importante e interesante de información útil para realizar mejor la tarea de programación, algunos tratan sobre el código otros sobre como enfrentarnos a las tareas y problemas que nos encontramos en el desarrollo y trabajo.

Thinking in Java

Yo como programador Java el libro que recomiendo para aquellos que ya tengan unos pocos conocimientos de programación estén empezando a programar en Java es Thinking in Java aunque también es recomendable para aquellos que incluso llevan varios años programando en Java, contiene una explicación detallada de cada uno de los aspectos del lenguaje. Java 8 ha introducido numerosas novedades (streams, lambdas, mejorada la programación asíncrona, date api, default methods, programación funcional, …) y el libro Java 8 in Action nos permite conocerlas detalladamente. En otros lenguajes hay otros libros que nos pueden introducir en la materia como C# 5.0 All-in-One For Dummies o Beginning Python.

Effective Java

Para aquellos que ya tienen varios años de experiencia el libro Effective Java contiene numerosos consejos para usar Java de forma “efectiva” aunque algunos puntos del libro son aplicables a cualquier otro lenguaje de programación orientado objetos. La segunda edición no está actualizada con las novedades introducidas en Java 8 pero prácticamente todo sigue siendo válido, el libro Java 8 in Action también contiene algunos consejos en la misma linea que complementan a este libro.

Head First – Design Patterns

Los patrones de diseño nos presentan una solución que se ha comprobado válida para resolver problemas. En varios casos tratan de hacer que los cambios no afecten de forma notable a la estructura de los programas. Hay patrones de creación, estructurales o de comportamiento, … conviene conocerlos por si en algún momento determinado podemos aplicarlos a nuestro código. El formato del libro Head First Design Patterns no sigue la estructura tradicional de los libros sino una estructura más esquemática y con ejemplos que hacen sencillo comprender los patrones, cuando aplicarlos, que ventajas tienen, que desventajas y como están relacionados los patrones entre ellos. Otro libro con un formato más tradicional y muy comentado es Design Patterns.

Clean Code

El contenido de Clean code es aplicable a cualquier lenguaje y de interés para cualquier programador, contiene consejos para escribir mejor código en nuestras aplicaciones, desde como asignar nombres, como escribir funciones, comentarios, formatear el código, objetos y estructuras de datos, …, temás relacionados con el código que escribimos. El objetivo de la programación es escribir código que funciona y resuleva necesidades pero también es casi tan importante que sea fácilmente entendible por otros programadores o nosotros mismos unas semanas más tarde ya que la mayor parte del tiempo no la dedicamos a escribir nuevo código sino a modificarlo.

Code Complete

Code Complete es otro libro que se centra en como mejorar el código que escribimos de forma similar a Clean Code, explica muchos principios que pueden guiar el código que desarrollamos. Aún no lo he leído pero es mencionado bastante bastantes veces en libros de lectura recomendada. Por una lectura rápida por encima parece que está bastante bien.

The Pragmatic Programmer

El libro Pragmatic programmer también es aplicable independientemente de lenguaje que utilicemos. Contienen consejos que podemos usar como guía para tomar decisiones, para escribir mejor código y también para ser mejores programadores y profesionales.

The Clean Coder

Quizá ya conocieses Clean Code pero conocías ¿The Clean Coder?. Del mismo autor que Clean Code pero en este caso se centra no en el código sino en el programador, explica como enfrentarnos a situaciones que nos encontramos como programadores en el trabajo, en la programación escribir código solo es una pequeña parte y comprende mucho más que escribir lineas de código, también dar solución a las necesidades del negocio y de forma correcta. Trata de explicar como comportarnos de forma profesional, el decir no, el decir sí, practicar, gestión del tiempo, estimaciones, colaboración, equipos, aprender de un mentor, ser un mentor, …

Refactoring

Comenzar un proyecto desde el inicio no es lo habitual y aún así pasado un tiempo no muy grande el código se convierte en heredado, lo habitual es que tengamos que modificar código que ya están escrito. El libro Refactoring nos explica como modificar el código para que tenga mejor diseño y sea más legible o fácil de modificar en un futuro y ante los posibles cambios que se vayan introduciendo. Algunas de las acciones están relacionadas con aplicar algunos principios de los patrones de diseño explicados en Head First – Design Patterns o algunos principios comentados en Clean Code.

En una pregunta y respuesta de stackoveflow sobre los libros a leer por un programador, están recogidos una buena colección de los mejores de ellos.

De la lista de este artículo el que me falta por leer es Code Complete el resto por mi propia experiencia recomiendo leerlos incluso más de una vez dependiendo de lo bien que absorbamos el conocimiento recogido en ellos y más tarde lo tengamos presente mientras trabajamos y programamos. Estos son de los libros más mencionados en artículos similares a este como buena documentación que leer sobre programación, si los leemos y nos quedamos con un porcentaje aunque sea pequeño ya mejoraremos bastante, también es probable que algunas cosas de las comentadas en los libros ya las tengamos presentes con la experiencia que hemos adquirido por nosotros mismos, en estos libros ese conocimiento adquirido y más comprobaremos que está documentado. ¡Feliz lectura!

Referencia:
Novedades de Java 8
Patrones de diseño en la programación orientada a objetos
Ejercicios (katas) para mejorar habilidades de programación practicando

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

Variable not found

Filtros asíncronos en MVC 6

December 16, 2014 12:45 PM

ASP.NET MVC 6Como ya hemos visto por aquí en alguna ocasión, hace tiempo que MVC soporta controladores asíncronos, permitiendo la implementación de acciones muy eficientes desde el punto de vista de la utilización de los recursos del servidor.

Sin embargo, en cuanto pretendíamos llevar a los action filters la misma filosofía nos encontrábamos con que la infraestructura no estaba preparada, es decir, no teníamos una forma clara de introducir llamadas asíncronas en el cuerpo de los filtros. Como consecuencia, todas las tareas que se realizaban en su interior eran puramente síncronas y dejaban bloqueados los hilos destinados a procesar peticiones mientras se completaban las operaciones, lo cual es especialmente un despilfarro cuando se trata de tareas de entrada/salida.

Afortunadamente esto parece que va a terminar con MVC 6, que soportará ya esta solicitada característica. Pero ojo, que MVC 6 está aún en desarrollo, por lo que todo lo que cuento a continuación puede cambiar.

Pero empecemos desde el principio, viendo qué ha cambiado por abajo para que sea posible crear filtros con código asíncrono en su interior. Quizás sea una lectura un poco densa, pero creo que es interesante para comprender cómo funcionan las cosas por dentro.

Abriendo el capó

Hasta MVC 5, era posible crear filtros personalizados tomando como base varias clases abstractas e interfaces, ofreciendo cada una de ellas un conjunto de métodos a implementar o sobrescribir para introducir nuestro código personalizado.

Por ejemplo, la implementación de la clase abstracta ActionFilterAttribute, una base usada con mucha frecuencia para crear filtros personalizados, era de la siguiente forma:
public abstract class ActionFilterAttribute : 
FilterAttribute, IActionFilter, IResultFilter
{
public virtual void OnActionExecuting(ActionExecutingContext filterContext) { }
public virtual void OnActionExecuted(ActionExecutedContext filterContext) { }
public virtual void OnResultExecuting(ResultExecutingContext filterContext) { }
public virtual void OnResultExecuted(ResultExecutedContext filterContext) { }
}
Como se puede observar, no hay rastro de las “marcas” que indican la presencia de asincronía, como el uso de las clases Task o Task<T>, o de las palabras clave async y await. Los métodos OnXXX() presentes en la signatura eran invocados de forma síncrona antes y después de la ejecución de las acciones y del  resultado (objetos ActionResult) retornado por éstas. Dado que estos métodos son virtuales, la creación de filtros personalizados consistía normalmente en heredar de ActionFilterAttribute y sobreescribir uno o varios de ellos.

Pues fijaos ahora en la implementación de esta misma clase en MVC 6:
public abstract class ActionFilterAttribute: Attribute, IOrderedFilter,
             IActionFilter, IAsyncActionFilter,
             IResultFilter, IAsyncResultFilter
{
public int Order { get; set; }

public virtual void OnActionExecuting(ActionExecutingContext context) { }
public virtual void OnActionExecuted(ActionExecutedContext context) { }

public virtual async Task OnActionExecutionAsync(
              ActionExecutingContext context, ActionExecutionDelegate next)
{
OnActionExecuting(context);
if (context.Result == null)
{
OnActionExecuted(await next());
}
}

public virtual void OnResultExecuting(ResultExecutingContext context) { }
public virtual void OnResultExecuted(ResultExecutedContext context) { }

public virtual async Task OnResultExecutionAsync(
              ResultExecutingContext context, ResultExecutionDelegate next)
{
OnResultExecuting(context);
if (!context.Cancel)
{
OnResultExecuted(await next());
}
}
}
¡Esto ya es otra cosa! Siguen existiendo los mismos métodos síncronos OnXXX() que teníamos en las versiones anteriores, pero ahora se han implementado un par de métodos nuevos, OnActionExecutionAsync() y OnResultExecutionAsync(), ambos definidos en sus respectivos interfaces IAsyncActionFilter y IAsyncResultFilter, que brindan la posibilidad de introducir código asíncrono de forma sencilla.

Acerquémonos ahora a la implementación de estos métodos. Son muy similares, por lo que nos centraremos en un principio en OnActionExecutionAsync():
public virtual async Task OnActionExecutionAsync(
           ActionExecutingContext context, ActionExecutionDelegate next)
{
OnActionExecuting(context);
if (context.Result == null)
{
OnActionExecuted(await next());
}
}
Como podemos observar, en su interior se encuentra en primer lugar una llamada síncrona a OnActionExecuting(). Esto lo pone sencillo para los escenarios en los que no sea necesario asincronía, manteniendo retrocompatibilidad con filtros escritos para versiones anteriores del framework.

Sólo si no se ha cortocircuitado la ejecución de la acción estableciendo un resultado “precocinado” desde el propio filtro, es cuando se ejecuta la acción realmente mediante la invocación al delegado next(), y su retorno será enviado como parámetro al método síncrono OnActionExecuted().

Exactamente lo mismo ocurre con OnResultExecutionAsync(); se encargará de invocar a los tradicionales métodos síncronos OnResultExecuting() y OnResultExecuted() antes y después de la ejecución del resultado, proporcionando una interfaz síncrona para aquellos escenarios donde no sea necesario la asincronía.

Pero en cualquier caso, lo interesante de esto es que tenemos un punto asíncrono de entrada a nuestros filtros que, como ya os habréis dado cuenta, son métodos virtuales, es decir, fácilmente reemplazables por código propio en nuestros filtros personalizados.

Creando filtros asíncronos personalizados

Si habéis llegado hasta este punto, probablemente la creación de un filtro asíncrono os resultará totalmente trivial. Basta con heredar de ActionFilterAttribute y sobrescribir OnActionExecutionAsync() u OnResultExecutionAsync() dependiendo de si queremos tomar el control durante la ejecución de la acción o del resultado, respectivamente.

El siguiente ejemplo muestra un sencillo profiler implementado en forma de filtro que envía de forma asíncrona los tiempos de ejecución de la acción y del resultado a un logger que podría estar almacenando esta información en disco o en una base de datos:
public class ProfilerAttribute : ActionFilterAttribute
{
private ILogger _logger = new Logger();
public override async Task OnActionExecutionAsync(
               ActionExecutingContext context, ActionExecutionDelegate next)
{
var stopWatch = Stopwatch.StartNew();
await base.OnActionExecutionAsync(context, next);
stopWatch.Stop();

var message = FormatProfilerInfo("Action", context, stopWatch);
await _logger.Log(message);
}

public override async Task OnResultExecutionAsync(
               ResultExecutingContext context, ResultExecutionDelegate next)
{
var stopWatch = Stopwatch.StartNew();
await base.OnResultExecutionAsync(context, next);
stopWatch.Stop();

var message = FormatProfilerInfo("Result", context, stopWatch);
await _logger.Log(message);
}

private string FormatProfilerInfo(
               string what, FilterContext context, Stopwatch stopWatch)
{
return string.Format("{0}.{1} >> {2} execution: {3}ms",
context.RouteData.Values["Controller"],
context.RouteData.Values["Action"],
what,
stopWatch.ElapsedMilliseconds);
}
}
Por cierto, seguro que más de uno ha pensado que el filtro anterior usa una forma algo chunga para obtener la referencia a la clase Logger. Pues sí, pero está hecho aposta ;) La forma en que se consigue la inyección de dependencias en filtros de MVC 6 es muy interesante, pero para no desviarnos mucho lo dejaré para un post futuro :)

Publicado en Variable not found.

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

Arragonán

Semana 340

December 15, 2014 06:18 PM

Se hizo corta la semana pasada, contaba con ello por la suma de que el lunes era festivo y que el jueves tuvimos cena de autónomos, sabía que el viernes no estaría para muchas historias y lo dejé para hacer cosas fáciles.

Con ese panorama, nada de saraos en toda la semana aún habiendo alguna charla que en una semana normal raramente me hubiera perdido. Me centré en sacar trabajo de proyectos, incluido alguno propio:

  • Dediqué unas horas para migrar elDisparate a heroku. Tuve que añadir algunas dependencias y modificar el modo en que se cargan los datos en memoria al arrancar la aplicación.
  • Con minchador estuve tan sólo con tareas más administrativas y de soporte.
  • Estuve con un par de bugs de mhop. Uno que rompía algunos detalles del diseño de la home y un problema de memoria. Los gestores de contenido estaban tratando de subir fotos extremadamente grandes y el servidor se terminaba quedando sin memoria al procesarlas.
  • Finalmente retomé FarmaHuesca con Ionic. Tengo casi toda la funcionalidad ya replicada, pero tengo que refactorizar bastantes cosas y ver ejemplos de cómo organizan algunas cosas quienes tienen costumbre de trabajar con Angular.

Buena semana.

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

Variable not found

Enlaces interesantes 180

December 15, 2014 12:45 PM

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

Una sinfonía en C#

Tips de Javascript: String multilínea

December 15, 2014 12:05 PM

En ocasiones necesitamos escribir un string largo en nuestro código, no viene al caso el por qué.

La forma más común de solucionarlo sería esta:

var texto = 'Hola a todos, este es un texto largo'
+ ' largo que intento poner en varias '
+ 'líneas pero javascript no soporta esto o si?';

console.log(texto);

Por supesto que esto funciona, pero es un poco engorroso y feo además.

Bien, me he sorprendido al saber que mucha gente no sabe que Javascript tiene una sintáxis especial para esto, y es sencillamente agregar una barra invertida al final de cada línea, de este modo:

var texto = 'Hola a todos, este es un texto largo\
largo que intento poner en varias \
líneas pero javascript no soporta esto o si?';

console.log(texto);

Un detalle importante es que sólo funciona con comillas simples.

Como vemos además de ahorrarnos de poner las comillas y los signos + en cada línea que un poco más compacto.

Nos leemos.

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

Picando Código

Agregar aplicaciones al lanzador de GNOME Shell, KDE o Unity

December 15, 2014 12:00 PM

La mayoría de las aplicaciones en sistemas como Debian se encuentran en los repositorios y las podemos instalar con el gestor de paquetes correspondiente. Sin embargo en muchos casos instalamos aplicaciones “por fuera” o simplemente descargamos los ejecutables y los usamos a la par con el resto del sistema.

Esta modalidad de “instalación” tiene algunas desventajas:

  • Las actualizaciones del software quedan -en general- a cargo del usuario.
  • No hay integración con el sistema como cuando instalamos algo desde el gestor del paquete.

En mi caso me encontré con esta situación con Firefox Developer Edition. Lo descargué a un directorio en mi computadora y vive a la par con Iceweasel. Lo bueno de esta aplicación en particular es que cuenta con actualizaciones automáticas, así que no hay problema con eso.

Pero para abrir Firefox DE tenía que ir hasta el directorio donde lo descargué desde la terminal y ejecutarlo. También podía generar un ejecutable que se encargue de ese paso y ejecutarlo desde la terminal. Pero la verdad es que con Gnome Shell vengo bastante acostumbrado a apretar una tecla para cargar el lanzador de aplicaciones, escribir las primeras letras de la aplicación que quiero usar, y apretar enter cuando aparece el ícono en cuestión.

Buscando resolver este tema, encontré la respuesta en enseguida en StackExchange:

En GNOME y otros ambientes de escritorio compatibles con freedesktop.org, como KDE y Unity, las aplicaciones se agregan a los menúes de los escritorios o shell de escritorio mediante entradas desktop, definidas en archivos de texto con la extensión .desktop (archivos desktop). Los ambientes de escritorio construyen los menúes para el usuario a partir de la información combinada extraída de las entradas desktop disponibles.

Los archivos desktop pueden ser creado en cualquiera de estos dos lugares:

/usr/share/applications/ para entradas disponibles para todos los usuarios del sistema
~/.local/share/applications/ para entradas disponibles para un solo usuario

Por convención, los archivos desktop no debería incluir espacios o caracteres internacionales en su nombre.

Hay más información al respecto en la respuesta de Unix StackExchange (por ejemplo si se necesita ejecutar un script para mayor personalización de una aplicación). En mi caso fue suficiente con agregar lo siguiente a ~/.local/share/applications/firefox-developer.desktop:

fernando@endor ~/.local/share/applications 16:00:23
$ cat firefox-developer.desktop
[Desktop Entry]
Name=Firefox Developer Edition
Exec=/home/fernando/downloads/firefox-dev/firefox
StartupNotify=true
Terminal=false
Type=Application
Icon=/home/fernando/downloads/firefox-dev/browser/icons/mozicon128.png

Y el resultado final es que Firefox Developer edition se encuentra disponible desde el Shell de Gnome y convive amigablemente con Iceweasel:

Firefox Gnome Shell

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

Poesía Binaria

Enviar e-mails con adjuntos desde la terminal con sendmail [Bash script]

December 15, 2014 09:10 AM

En varias ocasiones, he necesitado enviar un e-mail a un compañero de trabajo (o a mí mismo) con información recién extraída de un servidor (por ejemplo un CSV de base de datos o información subida desde la web) y lo que he hecho al final ha sido bajármelo por SSH y una vez en mi ordenador he enviado el archivo donde ha sido necesario. Si eres como yo, que siempre tengo una sesión SSH abierta en mi servidor, ganarás un par de minutos con este script.

El siguiente script envía un correo electrónico utilizando sendmail. sendmail no es difícil, simplemente tenemos que escribir como entrada del correo las cabeceras necesarias y el mensaje, aunque podemos echar unos minutos hasta que se puede enviar correctamente el mensaje.
El problema con las cabeceras viene cuando tenemos que enviar archivos adjuntos, ya que las cabeceras que tenemos que enviar son un poco más complejas, y luego tenemos que codificar el archivo para que encaje en un e-mail y es algo que a mano resulta muy pesado.

Pues nada, si salvamos esto como gemail.sh sólo tenemos que hacer lo siguiente:

$ email.sh destino@servidor.com “Asunto del mensaje” “Hola mundo! Te mando un mensaje”

para enviar un mensaje normal, si queremos enviar adjuntos:

$ email.sh destino@servidor.com “Asunto del mensaje” “Hola mundo! Te mando un mensaje” fichero1 fichero2

siempre y cuando existan los archivos, la cosa irá bien, aunque también podemos insertar cabeceras nuevas en el correo, por ejemplo From (para especificar el remitente), CC y BCC (para copias) y Reply-to (para responder a esta dirección), etc. de la siguiente manera:

$ email.sh destino@servidor.com “Asunto del mensaje” “Hola mundo! Te mando un mensaje” “From: Yo mismo ” “CC: un_amigo@direccion.com” fichero1 fichero2…

Siempre y cuando tengamos sendmail configurado, todos los e-mails se enviarán. Si algún e-mail no ha salido, podemos ver en /var/log/mail.log y /var/log/mail.err qué ha pasado con el envío, ya que sendmail se limita a encolar los mensajes, que ya se podrán enviar con el método que tengamos configurado (postfix, nullailer, etc)


GeSHi Error: GeSHi could not find the language sh (using path /home/gaspy/www/totaki.com/www/poesiabinaria/wp-content/plugins/codecolorer/lib/geshi/) (code 2)

Este código lo encontráis también en mi Github.

Foto: Esparta Palma (Flickr CC-by)

La entrada Enviar e-mails con adjuntos desde la terminal con sendmail [Bash script] aparece primero en Poesía Binaria.

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

Koalite

Herramientas que solucionan y ocultan problemas

December 15, 2014 05:06 AM

Cuando era pequeño me sabía de memoria un montón de números de teléfono: el de casa de mis amigos, el de mis abuelos, el de algunos de mis tíos… Hoy en día, a duras penas recuerdo el mío.

La causante de todo esto es, claro está, la agenda del móvil, que me libera de tareas tan mundanas como recordar números de teléfono. A cambio, si me quedase sin batería y tuviera que llamar a alguien, tendría serios problemas para localizarlo.

En innegable que la agenda del móvil es una herramienta muy útil y que su contrapartida, es decir, no saber de memoria ningún teléfono de nadie, es fácilmente solventable, basta con memorizar un par de números para emergencias, pero eso no quita que confiar ciegamente en un herramienta también tenga sus consecuencias negativas.

En las últimas semanas he estado trabajando casi todo el tiempo en proyectos con Javascript y ReactJS usando simplemente un editor de texto y unas cuantas herramientas de líneas de comandos, lo que supone un cambio bastante grande con respecto a desarrollar en C# usando Visual Studio y Resharper.

Esto me ha hecho replantearme algunas cosas de la forma en que suelo programar y reflexionar sobre las implicaciones de usar herramientas avanzadas.

Solucionando un problema, ocultando otro. Solucionando un problema, ocultando otro.

A simple vista, uno diría que si tienes una herramienta más potente, que te permite hacer más cosas en menor tiempo y ser “más productivo”, la calidad del código debería ser mayor. A fin de cuentas, el usuario (o sea, yo) es el mismo, por lo que su capacidad para escribir buen (o mal) código es la misma, y cuantas más ayudas tenga mejor código escribirá, ¿no?

Lo cierto es que, en mi caso, no tengo tan claro que esto sea así.

Tener herramientas más avanzadas, como un compilador que chequea tipos o un IDE capaz de refactorizar y navegar automáticamente entre multitud de ficheros te ayuda a gestionar mejor la complejidad siempre creciente de un proyecto, pero también te oculta justo eso: que la complejidad está creciendo, y quizá demasiado.

A fin de cuentas, no necesitas prestar tanta atención al número de ficheros que creas o cómo organizarlos, navegar entre ellos es cuestión de pulsar una combinación de teclas y saltar de uno a otro.

O para qué pensar detenidamente el nombre de un método. Puedo poner el que quiera y, más adelante, renombrarlo en segundos. Siempre y cuando me acuerde de hacerlo y no quede con un nombre poco indicativo para siempre. Además, aunque sea un nombre poco memorable, tengo un completo intellisense que me ayuda a encontrarlo cuando lo necesito.

¿Y la gestión de dependencias? ¿Qué más me da si una clase se utiliza en 30 sitios distintos? Total, el using me lo añade automáticamente el Resharper y la dependencia la puedo acabar inyectando a través del contenedor de inversión de control.

Si quiero modificar código existente tampoco tengo problema, aunque eso introduzca fallos en mucho otros sitios. Lo modifico y el análisis en tiempo real de Resharper me irá guiando por todos los sitios en los que tengo que realizar correcciones. Correcciones que además muchas veces puedo automatizar y realizar sin prestar mucha atención.

¿Librerías externas? Todas las que quiera. Si necesito usar cualquier funcionalidad, usando un gestor de paquetes puedo añadir una librería que la implemente en un momento.

No es que la herramienta me obligue a hacer las cosas mal, pero me permite no prestar atención a esos pequeños detalles y vivir con la ¿falsa? sensación de que en realidad no son problemas, pero ciertamente los ejemplos que ponía puede ocultar problemas reales en una aplicación.

Tener un proyecto con miles de ficheros puede indicar que su tamaño es demasiado grande y que tal vez sería mejor partirlo en proyectos más pequeños, que pueda evolucionar y versionar por separado.

Escribir código de manera descuidada confiando en que luego refactorizarlo es fácil implica que si luego no me acuerdo de refactorizarlo, acabaré teniendo un montón de código escrito de manera descuidada.

Mantener una base de código en la que existen muchas dependencias interconectadas y clases que se utilizan en cincuenta sitios sólo porque es fácil depender de ellas acaba siendo un problema porque el acoplamiento entre unas partes y otras del sistema crece y es más difícil realizar modificaciones, ya que los cambios se propagan de unos puntos a otros.

Realizar cambios de forma masiva en el código, aunque tengas una herramienta que te guíe para solucionar los errores que estás generando, no suele ser una buena idea porque implica que están modificando demasiados sitios a la vez y el riesgo de introducir errores en mayor.

Introducir una librería con 5000 líneas de código sólo para utilizar un par de funciones que se pueden escribir en 5 minutos con 15 líneas de código añade una complejidad innecesaria a la hora de comprender las dependencias del proyecto e incrementa el API global con un montón de funciones que no necesitamos.

Sin embargo, cuando programo en Javascript usando un editor de texto, pierdo muchas de estas ayudas. Por ejemplo, para referenciar un fichero desde otro, es necesario hacer un require (o algo equivalente) a mano, lo que me hace ser muy consciente de cuantas dependencias tiene cada fichero porque me supone un esfuerzo extra añadirlas y mantenerlas.

Utilizar cientos de ficheros, aunque tengas ayudas para navegar entre ellos, se vuelve mucho más incómodo porque las opciones para saltar a la definición de un objeto o un método no son tan potentes como las del Visual Studio, y eso hace que te plantees si realmente necesitas tener un fichero para cada función o es preferible mantener ficheros un poco más grandes pero más cohesionados.

Puesto que renombrar es más complicado y recordar los nombres sin intellisense cuesta más, pongo más cuidado en intentar elegir un buen nombre desde el principio, y como cambiar la signatura de una función no es una tarea trivial (no tengo compilador ni Resharper), me cuido mucho de tener un método que se use en 1000 sitios diferentes por si tengo que modificarlo.

Eso hace que intente acotar más el uso de cada función para poder hacer cambios de forma más controladay y con menos riesgo de introducir errores.

Todo esto, que no nos engañemos, son limitaciones impuestas por el entorno, acaba redundando en que el código está más cuidado, resulta más compacto, más cohesivo y menos acoplado. Porque si no lo haces así, es imposible mantenerlo.

Cuando trabajo con este tipo de herramientas mi forma de trabajar cambia.

Mientras que con un IDE tiendo a escribir código rápidamente de la primera forma que se me ocurre porque sé que luego será fácil modificarlo aprovechando la potencia de las herramientas, si pierdo esa posibilidad, escribo código más despacio, pensando más lo que escribo pero dando menos vueltas para llegar al resultado final. Hammok driven development, que diría Rich Hickey.

En realidad, no creo que (al menos en mi caso) ninguna de las dos tácticas dé lugar a un código inherentemente mejor, y con ambas puedo llegar a conseguir escribir código muy bueno o código muy malo. Simplemente se trata de dos formas diferentes de trabajar impuestas por el tipo de herramientas que tengo disponibles y no deja de ser interesante plantearse esas diferencias y tratar de ver si se puede conjugar lo mejor de dos mundos.

No se trata de una adoptar una postura neoludista y renunciar a todo avance tecnológico, sino de ser consciente de que a veces las herramientas avanzadas nos puede hacer demasiado vagos y prestarle poca atención a la herramienta más poderosa que tenemos: nuestra capacidad de pensar y razonar.

Lo ideal sería tener toda la potencia disponible para cuando sea necesaria, pero no por ello dejar de pensar cuidadosamente en lo que estamos haciendo. Para eso hacen falta dos cosas: por una parte, ser consciente de cuando dejamos de pensar y nos dejamos guiar por la herramienta, y por otra tener una disciplina que no siempre es sencilla de mantener.

Y en eso estamos. Utilizar herramientas menos potentes me ha permitido ser consciente de algunos “vicios” que había adquirido por disponer de funcionalidades avanzadas y ahora, incluso cuando vuelvo a Visual Studio y Resharper, trato de ser más consciente del código que escribo y hacerlo mejor, independientemente de que las herramientas hagan tolerable trabajar con código de peor calidad.

No hay posts relacionados.

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

Blog Bitix

Ejercicios (katas) para mejorar habilidades de programación practicando

December 13, 2014 11:06 AM

La semana pasada escribía sobre algunos libros que leer para ser mejores programadores, sin embargo, toda esa teoría solo sirve cuando se interioriza para usar más tarde en la práctica. Para interiorizar parte de ese conocimiento hasta el momento creo que no se ha inventado mejor manera que escribiendo código teniendo en cuenta esos principios.

Las katas y dojos son unos ejercicios que se realizan para practicar, son problemas sencillos de los que se conoce la solución pero lo importante no es resolverlos sino aplicar las lecciones aprendidas y mejorar nuestras habilidades de programación que posteriormente usemos en los proyectos que trabajamos. Estos ejercicios se suelen realizar con otras personas, en la página Katayunos – Merendojos se suelen organizar encuentros en algunas ciudades y fechas, si no nos cuadran las fechas y lugares podemos realizarlas individualmente cuando y donde prefiramos aunque una de las partes que nos perderemos es aprender de las habilidades y formas de trabajar de otras personas.

En la página CodeKata podemos leer una introducción a las katas y una colección de ejercicios con los que practicar. En estos ejercicios deberemos intentar aplicar varios principios de la programación orientada a objetos como el principio SOLID, DRY, abierto a extensión cerrado a modificación (OCP), patrones de diseño, nombres de métodos y variables que hagan que el código sea expresivo, teses unitarios, refactorizaciones, … todas esas cosas que consideramos correctas para escribir buen código.

El primero de los ejercicios propuestos en CodeKata es Kata01: Supermarket Pricing que consiste en pensar una forma de representar los precios de los productos de un supermercado, aparte de un precio simple como puede ser $0.65 por producto, otros como tres por un dolar, $1.99 / pound o compre dos obtenga uno más gratis o con descuento. Para esta kata en internet hay comentadas varias soluciones, probablemente para representar los diferentes precios una solución sea crear una clase que calcule los diferentes tipos de precios aplicando el patrón Strategy en función de como se calcule el precio de cada producto.

Intentando implementar en código una posible solución aplicando el patrón Strategy, usando BigDecimal para los precios (en vez de double y float que no pueden representar correctamente algunos valores decimales), este ejemplo muestra como calcular el precio de un producto dada su cantidad y su tipo de precio.

<noscript><pre><code>package io.github.picodotdev.blogbitix.kata01; import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public interface Pricing { BigDecimal calculate(BigDecimal quantity); } public interface Offer { BigDecimal calculateWithOffer(BigDecimal quantity); BigDecimal getNumberWithoutOffer(BigDecimal quantity); BigDecimal getNumberWithOffer(BigDecimal quantity); } public static class Product { Pricing pricing; Product(Pricing pricing) { this.pricing = pricing; } public BigDecimal calculate(BigDecimal quantity) { return pricing.calculate(quantity); } } public static class SimplePricing implements Pricing { BigDecimal unitPrice; SimplePricing(BigDecimal unitPrice) { this.unitPrice = unitPrice; } @Override public BigDecimal calculate(BigDecimal quantity) { return unitPrice.multiply(quantity); } } public static class WeigthPricing implements Pricing { BigDecimal weigthPrice; WeigthPricing(BigDecimal weigthPrice) { this.weigthPrice = weigthPrice; } @Override public BigDecimal calculate(BigDecimal weight) { return weigthPrice.multiply(weight); } } public static class OfferPricing implements Pricing, Offer { Pricing normalPricing; BigDecimal offerQuantity; BigDecimal offerPercent; OfferPricing(Pricing normalPricing, BigDecimal offerQuantity, BigDecimal offerPercent) { this.normalPricing = normalPricing; this.offerQuantity = offerQuantity; this.offerPercent = offerPercent; } public BigDecimal calculate(BigDecimal quantity) { BigDecimal withoutOfferPrice = normalPricing.calculate(getNumberWithoutOffer(quantity)); BigDecimal withOfferPrice = calculateWithOffer(getNumberWithOffer(quantity)); return withoutOfferPrice.add(withOfferPrice); } public BigDecimal calculateWithOffer(BigDecimal quantity) { return normalPricing.calculate(new BigDecimal(&quot;1&quot;)).multiply(quantity).multiply(getOfferPercent()); } public BigDecimal getNumberWithoutOffer(BigDecimal quantity) { BigDecimal groups = quantity.divide(offerQuantity, 0, RoundingMode.DOWN); return quantity.subtract(groups); } public BigDecimal getNumberWithOffer(BigDecimal quantity) { return quantity.subtract(getNumberWithoutOffer(quantity)); } private BigDecimal getOfferPercent() { return BigDecimal.valueOf(100).subtract(offerPercent).divide(new BigDecimal(&quot;100&quot;)); } } public static void main(String[] args) { Product p1 = new Product(new SimplePricing(new BigDecimal(&quot;2&quot;))); System.out.println(p1.calculate(new BigDecimal(&quot;3&quot;))); Product p2 = new Product(new WeigthPricing(new BigDecimal(&quot;1.35&quot;))); System.out.println(p2.calculate(new BigDecimal(&quot;3&quot;))); Product p3 = new Product(new OfferPricing(new SimplePricing(new BigDecimal(&quot;1&quot;)), new BigDecimal(&quot;3&quot;), new BigDecimal(&quot;50&quot;))); System.out.println(p3.calculate(new BigDecimal(&quot;6&quot;))); } }</code></pre></noscript>
<noscript><pre><code>package io.github.picodotdev.blogbitix.kata01; import io.github.picodotdev.blogbitix.kata01.Main.OfferPricing; import io.github.picodotdev.blogbitix.kata01.Main.Product; import io.github.picodotdev.blogbitix.kata01.Main.SimplePricing; import io.github.picodotdev.blogbitix.kata01.Main.WeigthPricing; import java.math.BigDecimal; import org.junit.Assert; import org.junit.Test; public class MainTest { @Test public void simplePrice() { Product p1 = new Product(new SimplePricing(new BigDecimal(&quot;2&quot;))); Assert.assertEquals(new BigDecimal(&quot;6&quot;), p1.calculate(new BigDecimal(&quot;3&quot;))); } @Test public void weigthPrice() { Product p2 = new Product(new WeigthPricing(new BigDecimal(&quot;1.35&quot;))); Assert.assertEquals(new BigDecimal(&quot;4.05&quot;), p2.calculate(new BigDecimal(&quot;3&quot;))); } @Test public void offerPricing() { Product p3 = new Product(new OfferPricing(new SimplePricing(new BigDecimal(&quot;1&quot;)), new BigDecimal(&quot;3&quot;), new BigDecimal(&quot;50&quot;))); Assert.assertEquals(new BigDecimal(&quot;4.5&quot;), p3.calculate(new BigDecimal(&quot;5&quot;))); } }</code></pre></noscript>

Aun practicando estas katas no va a hacer que luego nuestro código en un proyecto real sea perfecto ni siquiera algo cercano a ello más bien hará que sea un poquito mejor, estos ejercicios son bastante simples que no tienen las complejidades de algunos casos reales, aún así siguen mereciendo realizarlos. También hay que tener en cuenta que no son realmente para aprender a programar aunque si pueden servir para aprender un nuevo lenguaje sobre todo si se hacen con otra persona que ya lo conoce y mientras se realiza la kata podemos preguntarle y nos resuelva las dudas que nos vayan surgiendo de la sintaxis, API o herramientas de ese lenguaje.

Referencia:
http://codekata.com/
http://katayunos.com/
http://www.codewars.com/

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

Variable not found

Enlaces interesantes 179

December 09, 2014 01:05 PM

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

.Net

ASP.NET

Azure / Cloud

Data access

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

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

Arragonán

Semana 339

December 09, 2014 12:22 PM

A lo tonto fue una semana un bastante movida la pasada. Me pasé un rato por las Geek’s Talks. Cerré Movember afeitándome con la excusa de un reportaje que hizo Heraldo sobre el tema. Para rematar la semana terminé el sábado por la tarde pasándome por el festival De Generación Perdida y por la noche me fui a mi pueblo a celebrar una nueva Nochevieja Anticipada; efectivamente, el domingo estaba muerto.

Pero tuve más acción relacionada con lo profesional durante la semana.

Llegamos al mínimo en el crowdfunding OutreachBox y, aunque no pinta fácil, seguimos esperando acercarnos al óptimo de co-financiación.

Estuve hablando con Molpe para ver cómo colaborar con BeSEPA, su nueva aventura junto a Gonzalo Valverde. Van a ser cosas puntuales en las que les puedo ir echando una mano, por el momento nada “core” del negocio. Me motiva mucho volver a trabajar con él un puñado de años después.

Y sobre las cosas en marcha en las que trabajé durante la semana:

  • En mhop estuve implementando la limitación de permitir compras tan sólo en la península. Evidentemente por temas logísticos, que tenemos que aclarar varias cuestiones de cómo gestionar los envíos fuera de españa y península para soportarlo en la web.
  • Perdí una tarde en revisar un problema en DNDzgz. Encontré problemas con el tiempo real de lo que tarda una autobús en una parada.
    Inicialmente supuse que sería cosa de que habrían cambiado la web y tendría que modificar el scraper, pero no era así; luego llegué a pensar que habrían baneado nuestro servidor; y resultó ser que la respuesta del tiempo en las paradas en la web de Urbanos de Zaragoza va fatal aleatoriamente. Unas veces responde en torno a 1 o 2 segundos, mientras que en otras ocasiones se dispara a rondar al minuto.
  • Dejé prácticamente integrado el rediseño de minchador, faltan un par de flecos para poder publicar la nueva landing page. También recibí feedback interesante para implementar alguna mejora que ya está en el product backlog.

Buena semana.

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

Poesía Binaria

Buscar un archivo en el PATH en C

December 09, 2014 08:57 AM

En principio si vamos a ejecutar un programa con popen() o exec*() no habría problema. Siempre que exec sea de la familia de los exec*p(), es decir execvp(), execlp(), execvpe(), ya que estos buscan en la variable de entorno PATH el ejecutable, aunque los demás exec no lo hacen y requieren el fichero y path completo.

Podemos utilizarla, por ejemplo para ahorrarle a exec el trabajo de tener que buscar en el PATH si vamos a hacer muchas llamadas a un ejecutable o para mostrar al usuario la ruta y el nombre de archivo de un programa que va a ejecutar. También, un poco más abajo encontramos un bonus, que nos permite buscar archivos tanto en el PATH del sistema como en uno que nosotros espeifiquemos, y que nos será útil por ejemplo para buscar ejecutables en /usr/sbin, /usr/local/sbin y otros en sistemas en los que para nuestro usuario, ese ejecutable no se encuentra (hay más *nix que colores…)

En esta primera versión, somos nosotros los que debemos reservar memoria en una cadena de caracteres para almacenar el resultado, y el éxito o no de la ejecución vendrá dado por el return de la función:

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

short file_exists(char *filename)
{
  int fd=open(filename, O_RDONLY);
  if (fd==-1)
    {
      if (errno==2)             /* If errno==2 it means file not found */
        return 0;               /* otherwise there is another error at */
      else                      /* reading file, for example path not  */
        return -1;              /* found, no memory, etc */
    }
  close(fd);                    /* If we close the file, it exists */
  return 1;
}

int findInPath(char *result, char *executable)
{
  char *path = getenv("PATH");
  char *saveptr;
  char *tmpstr = malloc(strlen(path)+strlen(executable)+2);
  char *directory = strtok_r(path, ":", &saveptr);
  char *slash = "/";
  short found = 0;
  while ( (directory != NULL) && (!found) )
    {
      sprintf (tmpstr, "%s%s%s", directory, (directory[strlen(directory)-1]=='/')?"":slash, executable);
      if (file_exists(tmpstr))
    found = 1;
      directory = strtok_r(NULL, ":", &saveptr);
    }

  if (found)
    strcpy(result, tmpstr);

  free(tmpstr);

  return found;
}

int main ()
{
  char res[200];
  if (findInPath(res, "ls"))
  {
     printf ("Found at: %s\n", res);
  }
  else
    printf ("Not found!\n");

  return 0;
}

En esta segunda versión, directamente devolvemos un char* como resultado de la función, por lo que si éste vale NULL significará que el archivo no se ha encontrado en el PATH. Eso sí, cuando no utilicemos más el valor, es nuestra responsabilidad liberar la memoria.
También me gustaría indicar que se podría haber hecho una reserva de memoria más eficiente, ahora mismo reservamos un tamaño igual al tamaño del PATH + longitud del nombre de archivo + 2 (una / y el terminador), esto sería en el peor de los casos, en el que en el PATH sólo haya un directorio, aunque generalmente no será así, aunque preferí esto a estar reservando y liberando memoria cada vez que lea un directorio, y no creo que el PATH sea tan excesivamente largo como para que haya un gran desperdicio de memoria.

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

short file_exists(char *filename)
{
  int fd=open(filename, O_RDONLY);
  if (fd==-1)
    {
      if (errno==2)             /* If errno==2 it means file not found */
        return 0;               /* otherwise there is another error at */
      else                      /* reading file, for example path not  */
        return -1;              /* found, no memory, etc */
    }
  close(fd);                    /* If we close the file, it exists */
  return 1;
}

char* findInPath2(char *executable)
{
  char *path = getenv("PATH");
  char *saveptr;
  char *tmpstr = malloc(strlen(path)+strlen(executable)+2);
  char *directory = strtok_r(path, ":", &saveptr);
  char *slash = "/";
  short found = 0;
  while ( (directory != NULL) && (!found) )
    {
      sprintf (tmpstr, "%s%s%s", directory, (directory[strlen(directory)-1]=='/')?"":slash, executable);
      if (file_exists(tmpstr))
    found = 1;
      directory = strtok_r(NULL, ":", &saveptr);
    }
  if (found)
    return tmpstr;

  return NULL;
}

int main ()
{
  char *res = findInPath2("kwrite");
  if (res != NULL)
    {
      printf ("Found at: %s\n", res);
      free(res);
    }
  else
    printf ("Not found!\n");

  return 0;
}

Como toque final, vamos a presentar un tercer ejemplo donde además de buscar en el PATH buscamos en rutas puestas a mano:

1
 

#include
#include
#include
#include types.h>
#include stat.h>
#include
#include

short file_exists(char *filename)
{
int fd=open(filename, O_RDONLY);
if (fd==-1)
{
if (errno==2) /* If errno==2 it means file not found */
return 0; /* otherwise there is another error at */
else /* reading file, for example path not */
return -1; /* found, no memory, etc */
}
close(fd); /* If we close the file, it exists */
return 1;
}

char* findInPath3(char *executable, char *additional_path)
{
char *path = getenv(“PATH”);
char *saveptr;
char *tmpstr = malloc(strlen(path)+strlen(executable)+2);
char *directory = strtok_r(path, “:”, &saveptr);
char *_additional_path;
char *slash = “/”;
short found = 0;
while ( (directory != NULL) && (!found) )
{
sprintf (tmpstr, “%s%s%s”, directory, (directory[strlen(directory)-1]==’/')?”":slash, executable);
if (file_exists(tmpstr))
found = 1;
directory = strtok_r(NULL, “:”, &saveptr);
}
if (found)
return tmpstr;

if (additional_path == NULL)
return NULL;

_additional_path = malloc(strlen(additional_path)+1);
strcpy(_additional_path, additional_path);
directory = strtok_r(_additional_path, “:”, &saveptr);
while ( (directory != NULL) && (!found) )
{
sprintf (tmpstr, “%s%s%s”, directory, (directory[strlen(directory)-1]==’/')?”":slash, executable);
if (file_exists(tmpstr))
found = 1;
directory = strtok_r(NULL, “:”, &saveptr);
}
free(_additional_path);

if (found)
return tmpstr;

return NULL;
}

int main (int argc, char *argv[])
{
char *res = findInPath3(“puertas.jpg”, (char*) “/home/usuario:/home/usuario/Descargas/Imágenes” );
if (res != NULL)
{
printf (“Found at: %s\n”, res);
free(res);
}
else
printf (“Not found!\n”);

return 0;
}

En este ejemplo es curioso cómo para strtok_r() es necesario hacer una copia de la cadena additional_path, más que nada porque ésta es modificada en cada iteración y si presentamos una cadena literal en realidad estamos pansando un valor constante y por tanto no podrá ser modificado y devolverá una violación de segmento. De todas formas, con strtok() y derivados es importante siempre trabajar con una copia (no lo hacemos con la variable path, porque no tiene uso más allá del bucle con strtok(), podemos probar poner su valor en pantalla al final del bucle para ver a lo que me refiero.

Como último apunte decir que he utilizado strtok_r porque éste es reentrante y es más seguro utilizar éste en aplicaciones multi-hilo. Si queremos utilizar el strtok() de toda la vida, perfecto, pero strtok_r() es más seguro, ya que la información necesaria para las iteraciones las almacena en una variable que nosotros controlamos. Por ejemplo strok() es un desastre también en funciones recursivas.

Foto: VectorOpenStock (CC-by)

La entrada Buscar un archivo en el PATH en C aparece primero en Poesía Binaria.

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

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

CRM Dymamics Templates

December 09, 2014 01:18 AM

Rapid ROI with 27 Industry Templates for Microsoft Dynamics CRM http://community.dynamics.com/crm/b/crmsoftwareblog/archive/2014/11/26/rapid-roi-with-27-industry-templates-for-microsoft-dynamics-crm.aspx

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

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

Microsoft Dynamics CRM 2015

December 09, 2014 01:15 AM

New Features in Microsoft Dynamics 2015 – Improvements for Sales, Marketing and More! https://community.dynamics.com/crm/b/crmsoftwareblog/archive/2014/12/06/new-features-in-microsoft-dynamics-2015-improvements-for-sales-marketing-and-more.aspx

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

proyectos Ágiles

Agile Management es diferente

December 08, 2014 05:42 PM

Sesión de la CAS2014, donde se explica el rol del Management en una empresa Agile-Lean: principios subyacentes, cultura, responsabilidades, tipos de Agile Managers y características de un Agile Manager.

 CAS2014-01-contexto-diferente

 CAS2014-02-vision-trabajadores

 

CAS2014-03-motivacion-empleados

 

/CAS2014-04-modelo-organizativo

 CAS2014-05-proposito-organizacion

CAS2014-06-organizacion-transparente

 

CAS2014-07-responsabilidades-agile-manager

 CAS2014-08-tipos-agile-managers

 

CAS2014-09-fractal-agile-managers

 

CAS2014-10-caracteristicas-agile-manager

 

CAS2014-11-premio-mejor-manager

 

 

slideshare

 Ver las presentaciones completas en slideshare:

 

Artículos relacionados

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

Navegapolis

Excipientes y principios activos de Scrum

December 06, 2014 08:18 PM

excipientes

Excipientes de Scrum

Gráficos burndown, estimación de póquer, product backlog, sprint backlog, formatos de historias de usuario, reuniones de pie, tableros visuales kanban etc.

Principios activos de Scrum:

  • Visión: El proyecto tiene un objetivo definido, conocido y asumido por todos los miembros.
  • Priorización: El criterio de prioridad del cliente define en cada momento las tareas inmediatas para avanzar hacia el objetivo.
  • Visibilidad: No hay información oculta y en las decisiones se tienen en cuenta las consideraciones y aportaciones del todo el equipo.
  • Competencia: Todos los miembros tienen la competencia profesional necesaria para aportar un trabajo valioso.
  • Respeto: Todos los miembros dan y reciben respeto y valoración.
  • Compromiso: Las personas no anteponen sus intereses propios a los del equipo.
  • Confianza: Todo el equipo tiene confianza real en el desempeño, valor y compromiso de los demás.
  • Coraje: Todos los miembros y el equipo en su conjunto hace frente con decisión y solvencia a las situaciones adversas.
  • Responsabilidad: Cada persona tiene el margen de acutación y decisión necesario para su aportación al proyecto y es responsable de sus decisiones, acciones y omisiones.
  • Ritmo: El desarrollo se realiza con una cadencia de avance objetivo continuo y sostenible.
  • Retroalimentación: De forma periódica el equipo analiza su forma de trabajo y toma decisiones de mejora.

La mejora que cabe esperar al emplear prácticas Scrum un equipo sin principios ágiles es la propia de un placebo.

 

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

Blog Bitix

Cómo crear una imagen para Docker usando un Dockerfile

December 06, 2014 11:00 AM

Docker

Las imágenes de docker son el sistema de archivos que usa el proceso o procesos que se arrancan en los contenedores. Si nos convencen las características de docker y estamos decididos a usarlo y ya sabemos como administrar de forma básica los contendores si queremos disponer de una imagen adaptada a los servicios que necesitamos para iniciar contenedores tendremos que crearla, en este artículo explicaré cómo crear una imagen para docker personalizada.

Antes de crear una imagen para docker podemos buscar en el registro de imágenes de docker que han creado otros usuarios y los han compartido por si hay alguna que ya se adapte a nuestras necesidades, si nos sirve alguna y es algo popular nos evitaremos tener que modificarla nosotros mismos según salgan nuevas versiones de los servicios que use. El registro de imágenes de docker es un servicio en el que los usuarios comparten y colaboran en la creación de las imágenes. Para los servicios más conocidos dispondremos ya de las imágenes como podrían ser: mysql, redis, postgresql, ubuntu, wordpress, nginx, mongodb, …

Si no hay ninguna que se adapte totalmente a nuestras necesidades, no nos gusta como están construidas las existes o no confiamos en el mantenimiento que puedan tener esas imágenes podemos crear las nuestras propias. Para crear una imagen de docker se necesita una receta en forma de archivo Dockerfile que contiene la descripción e instrucciones para construir la imagen. Para crear un dockerfile podemos basarnos en los de las imágenes del registro de docker.

Este podría ser el contenido y la receta de un dockerfile si quisiésemos crear una imagen de docker para mysql, lo paso a explicar después.

<noscript><pre><code>FROM phusion/baseimage:0.9.15 MAINTAINER picodotdev &lt;pico.dev@gmail.com&gt; ENV HOME /root RUN apt-get update -q RUN /etc/my_init.d/00_regen_ssh_host_keys.sh RUN echo 'root:$6$l/PahbyY$jFhqIAuvHeK/GwjfT71p4OBBkHQpnTe2FErcUWZ8GIN1ykdI7CgL05Jkk7MYW6l.0pijAlfoifkQnLpaldEJY0' | chpasswd -e ADD bashrc /root/.bashrc ADD timezone /etc/timezone EXPOSE 22 CMD [&quot;/sbin/my_init&quot;]</code></pre></noscript>
<noscript><pre><code>FROM picodotdev/base:1.0 MAINTAINER picodotdev &lt;pico.dev@gmail.com&gt; ENV HOME /root RUN apt-get install -y mysql-server mysql-client ADD my.cnf /etc/mysql/my.cnf RUN mkdir /etc/service/mysql ADD mysql /etc/service/mysql/run RUN chmod +x /etc/service/mysql/run RUN rm -R /var/lib/mysql &amp;&amp; \ mkdir /var/lib/mysql &amp;&amp; \ mkdir /mnt/keys VOLUME [&quot;/var/lib/mysql&quot;, &quot;/mnt/keys&quot;] RUN apt-get clean &amp;&amp; \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* EXPOSE 22 3306 CMD [&quot;/sbin/my_init&quot;]</code></pre></noscript>

Los Dockerfile tienen algunas instrucciones:

  • FROM: indica la imagen base a partir de la cual crearemos la imagen que construirá el Dockerfile.
  • MAINTAINER: documenta el creador de la imagen.
  • ENV HOME: establece el directorio HOME que usarán los comandos RUN.
  • RUN: permite ejecutar una instrucción en el contenedor, por ejemplo, para instalar algún paquete mediante el gestor de paquetes (apt-get, yum, rpm, …).
  • ADD: permite añadir un archivo al contenedor, en muchas ocasiones se utiliza para proporcionar la configuración de los servicios (ssh, mysql, …).
  • VOLUME: establece puntos de montaje que al usar el contenedor se pueden proporcionar, los volúmenes son al forma de externalizar un determinado directorio y proporcionar persistencia (las imágenes de docker son de solo lectura y no almacenan datos entre diferentes ejecuciones).
  • EXPOSE: indica los puertos TCP/IP por los que se pueden acceder a los servicios del contenedor, los típicos son 22 (SSH), 80 (HTTP) y en este caso el puerto por defecto de mysql 3306.
  • CDM: establece el comando del proceso de inicio que se usará si no se indica uno al iniciar un contenedor con la imagen.

El Dockerfile-base crea una imagen base que usaremos posteriormente en la imagen de mysql, configura el color del prompt, la contraseña de root y expone el puerto 22 para poder hacer ssh.

En este ejemplo en vez de usar una imagen propia de Ubuntu en la directiva FROM he usado una imagen especial, phusion/baseimage:0.9.15. La imagen phusion/baseimage proporciona un sistema init adaptado al funcionamiento de los contenedores de docker al contrario de las imágenes de ubuntu que emplean upstart. Si usásemos alguna imagen de ubuntu y quisiésemos iniciar varios procesos en el contenedor deberíamos usar un servicio como punto de entrada como supervisord, con la imagen phusion/baseimage no sería necesario ya que ya ofrece esta funcionalidad de forma más sencilla.

Con las instrucciones RUN y ADD instalamos el paquete de mysql y el cliente de mysql y añadimos la configuración de mysql en el archivo my.cnf. En /etc/service/mysql/run dejamos el comando del servicio que iniciará el proceso de mysql como espera el sistema init de la imagen phusion. Con VOLUME [“/var/lib/mysql”] establecemos un punto de montaje para poder externalizar y persistir los datos de las bases de datos de mysql.

Una vez tenemos el Dockerfile y los archivos de configuración a incluir con los comandos ADD contruimos la imagen con:

<noscript><pre><code>$ docker build -t &quot;picodotdev/base:1.0&quot; docker/base $ docker build -t &quot;picodotdev/mysql:1.0&quot; docker/mysql</code></pre></noscript>

Para proporcionar la persistencia a la imagen de mysql podemos crear un contenedor específico que contenga los datos. Con el siguiente comando creamos un contenedor de datos, uso la imagen busybox ya que es una de las más pequeñas:

<noscript><pre><code>$ docker run --name mysql-data -d -v /var/lib/mysql busybox</code></pre></noscript>

Posteriormente podemos iniciar y parar el contenedor de msql con:

<noscript><pre><code>$ docker run --name mysql -d -p 3306:3306 --volumes-from mysql-data picodotdev/mysql:1.0 /sbin/my_init</code></pre></noscript>

En el artículo solo he indicado los Dockerfile, los archivos que añadimos con la instrucción ADD a las imágenes de docker pueden encontrarse en el siguiente repositorio de GitHub.

En los siguientes artículos comentaré la herramienta de automatización ansible y como sacarle provecho para iniciar los contenedores en una máquina de desarrollo (devbox). También en algún otro artículo comentaré la opción de bitnami que dentro de poco ofrecerá soporte para docker y como con esta opción podemos usar un servicio «out-of-the-box» si tener que crear ni siquiera un Dockerfile o tener que documentarnos para instalar un servicio (que en algunos casos pueden tener cierta complejidad) aunque sea usando virtualización con virtualbox o computación en la nube.

Referencia:
Introducción a Docker
Guía de inicio básico de Docker
Lista de enlaces sobre Docker
Introducción a Ansible
Integración entre Ansible y Docker
Introducción a Bitnami

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

Blog Bitix

Introducción y características de Docker

December 06, 2014 11:00 AM

Docker

Docker es una de las herramientas de la que se está hablando mucho, esto es así ya que tiene varios aspectos interesantes que cambian la forma de desarrollar aplicaciones. Docker es una forma de ejecutar procesos de forma aislada pero también se compone de herramientas para construir imágenes y un repositorio para compartirlas.

Al contrario de la virtualización Docker no emula o virtualiza una máquina y su sistema operativo con lo que los procesos son mucho más ligeros y hace que el hardware pueda ser aprovechado más al poder aumentar la densidad de los servicios en una misma máquina. Los contenedores y servicios incluidos en ellos inician muy rápidamente, en pocos segundos. Además, no es necesario el sistema de archivos completo del sistema operativo invitado con lo que docker usa una fracción de espacio de almacenamiento necesario en la virtualización.

La tecnología de contenedores no es nueva y también está disponible en otros sistemas operativos como OpenVZ también en Linux, FreeBSD Jails o los contenedores de Solaris.

Docker tiene varias características interesantes. Es ligero ya que no hay virtualización aprovechándose mejor el hardware y únicamente necesitando el sistema de archivos mínimo para que funcionen los servicios. Los contenedores son autosuficientes (aunque pueden depender de otros contenedores, por ejemplo, un wordpress que necesita una base de datos mysql) no necesitando nada más que la imagen del contenedor para que funcionen los servicios que ofrece. Las imágenes de docker son portables entre diferentes plataformas el único requisito es que en el sistema huésped esté disponible docker. Es seguro, pudiendo hacer que los contenedores se comuniquen por un túnel solo disponible para ellos, los contenedores están aislados en el sistema mediante namespaces y control groups.

Para los desarrolladores tiene las siguientes ventajas:

  • Podemos disponer de un entorno de desarrollo (devbox) o servicio en varios minutos/horas en vez de algún día. Esto es así porque la configuración y los servicios necesarios están automatizados en la construcción de las imágenes de los contenedores mediante Dockerfiles.
  • Al estar los servicios en contenedores no hace falta instalarlos en la máquina en la que son alojados, de forma que podemos disponer de los servicios y después eliminarlos de forma sencilla sin “ensuciar” el sistema huésped.
  • Nos permite tener versiones más parecidas o iguales a las usadas en producción. Por ejemplo, en Arch Linux nos permite tener un mysql de la distribución Ubuntu usando la misma versión.

El registro de contenedores de Docker es una forma colaborativa de ofrecer imágenes. Hay disponibles multitud de contenedores con los servicios más populares: MySql, PostgreSQL, Redis, Nginx, WordPress, …

Para los administradores de sistemas tiene las siguientes ventajas:

  • Pueden proporcionar entornos similares o iguales a los entornos de pruebas, QA o producción independientemente de la distribución que se use.
  • Es posible desplegar un contenedor en cualquier infraestructura Linux.
  • La creación de los contenedores puede ponerse bajo un sistema de control de versiones.

En el siguiente vídeo y presentación muy completa están ampliados muchas de sus posibilidades y funcionalidades.

Una vez conocidos los aspectos básicos y en que se diferencia docker de la virtualización así como el caso de uso de por ejemplo un devbox o disponer de entornos similares a los de producción de una aplicación, en el siguiente artículo comentaré cómo instalar docker, cómo empezar a usarlo, cómo obtener imágenes de servicios y pararlos y administrarlos. En la siguiente lista de enlaces sobre Docker se puede encontrar mucha información reunida dispersa en la red, desde introducciones, opiniones, como usarlo, como empaquetar las aplicaciones, como monitorizar o como usarlo en microservicios.

Referencia:
Inicio básico de Docker
Cómo crear una imagen para Docker usando un Dockerfile
Docker
Introducción a Ansible
Integración entre Ansible y Docker
Introducción a Bitnami
Seguridad Docker
Four ways Docker fundamentally changes application development
Docker, qué es y sus principales características

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

Variable not found

Quo vadis, ASP.NET MVC?

December 03, 2014 09:25 AM

Aunque aún en beta e inmersa en un intenso proceso de desarrollo, la próxima versión de ASP.NET MVC está tomando forma en los hornos de Microsoft, y, sin ser definitivas, ya se pueden ver cuáles serán las novedades principales que la acompañarán.

En futuros posts iremos entrando en mayor detalle, pero de momento vamos a echar un vistazo desde una cierta distancia para tener la idea general sobre dónde estamos y la evolución que vamos a encontrar en las nuevas versiones de tecnologías y plataformas, de forma que podamos ver en qué nos afectará como desarrolladores y, en definitiva, para qué tenemos que irnos preparando.
Disclaimer: estamos aún en una fase en la que algunas cosas pueden cambiar y aún no existe información exhaustiva de muchos detalles, por lo que pueden existir ausencias o imprecisiones. Pero bueno, digo yo que el grueso será más o menos correcto ;-)

Piedras en la mochila

En estos momentos, tenemos una versión de ASP.NET MVC estable, potente, rápida y con una gran comunidad de desarrolladores, tanto noveles como los que encontraron en este framework la alternativa a Webforms que estaban esperando. En los cinco años transcurridos desde la aparición oficial de la primera versión, se ha convertido, sin duda, en el estándar de facto para el desarrollo web basado en tecnologías Microsoft.

imageSin embargo, ASP.NET MVC aún arrastra una pesada losa heredada de los primeros tiempos de .NET, allá por 2002: el mastodóntico core de ASP.NET, llamado de forma genérica “System.Web”. Este núcleo, que conforma la monolítica infraestructura básica sobre la que corren casi todas las aplicaciones ASP.NET actuales, es enorme, complejo, pesado, muy ligado a tecnologías y servidores, y en muchos aspectos está mal diseñado, o al menos no diseñado con los parámetros y buenas prácticas que hoy en día entendemos como razonables.

MVC sigue irremediablemente atado a System.Web porque internamente lo utiliza en demasiados puntos, y esta dependencia no es buena para la evolución del framework, ni para la apertura de nuevas fronteras como el salto a entornos multiplataforma, además de suponer un lastre importante en cuanto la velocidad y consumo de recursos de las peticiones, tan importantes en entornos escalables y servicios en la nube.

OWIN y Katana, de los que hemos hablado por aquí extensamente, vinieron al rescate hace algún tiempo como los aislantes que necesitábamos entre los marcos de trabajo de alto nivel y la infraestructura, y las últimas versiones de los frameworks más jóvenes como WebAPI y SignalR los utilizaron de forma correcta para desvincularse totalmente de System.Web. Esta independencia hizo posible que pudieran alojarse servicios WebAPI o SignalR en cualquier tipo de proceso (aplicación web, servicio windows, aplicación de consola…) y que fueran muy eficientes.

Sin embargo, migrar MVC a los conceptos propuestos por OWIN para  no era una tarea sencilla, por lo que la versión 5 continuó atada a System.Web, y el uso de componentes OWIN/Katana se limitaba a la inclusión de middlewares de plataformas ajenas al framework MVC, como Identity Framework.

Los nuevos aires


Y estando así el patio, aparece por el horizonte .NET Core 5 (aka Core CLR), un subconjunto del .NET tradicional escrito desde cero, open source, con vocación multiplataforma (soportado directamente en Linux y Mac), fácilmente distribuible a través de Nuget y optimizado en el mundo web para obtener lo mejor de los entornos servidor, tanto cloud como on premise.

.NET Core 5 no supone, al menos de momento, la desaparición del .NET “clásico”, cuya próxima versión será la 4.6, y que seguirá una línea más continuista con las versiones anteriores. NET Core es sólo una alternativa optimizada para distintos entornos, entre ellos los servidores, pero seremos nosotros los que decidiremos sobre qué infraestructura queremos construir. Pero por poner un ejemplo de las ventajas de Core CLR en el mundo web, se estima que al usarlo una petición típica puede requerir 2Kb de memoria de servidor para ser procesada, frente a los 30Kb que se ocuparía en caso de seguir usando la infraestructura tradicional. Imaginad la repercusión que puede tener esto en cuanto a aprovechamiento de recursos de un servidor.

¿Y qué tiene todo esto que ver con ASP.NET MVC 6? Pues la respuesta está en ASP.NET 5. La próxima versión de ASP.NET será un framework unificado en el que encontraremos tecnologías de desarrollo como MVC, WebPages o SignalR, y que podrá correr sobre .NET 4.6 en Windows/IIS o sobre .NET Core en cualquier plataforma (por supuesto, incluida Windows).

Si todo esto os parece algo confuso, que probablemente lo es, podéis profundizar en este gran post de César de la Torre, de donde he tomado prestado el par de diagramas que veis por aquí porque creo que resumen muy bien la estructura general del nuevo escenario:


Algunas novedades de ASP.NET 5

Siguiendo la línea iniciada por la idea “One ASP.NET” que casi monopolizó las novedades en la última oleada de tecnologías de desarrollo para la web, en ASP.NET 5 crearemos aplicaciones web de cualquier tipo usando una infraestructura común, a la que iremos añadiendo las piezas necesarias para cubrir nuestras necesidades: MVC, SignalR, seguridad, logging, etc. Con esto se consigue una modularidad que hasta ahora era imposible de serie, aunque muy a la filosofía OWIN que ya comenzó a cuajar tiempo atrás; de hecho, si en su momento comprendisteis o trabajasteis con OWIN/Katana la forma de configurar sistemas ASP.NET 5 os resultará bastante familiar.

Y dado este nuevo contexto, el primer cambio que encontraremos en MVC 6 y el resto de frameworks es que no hay ningún tipo de vínculo con componentes de ASP.NET clásico (System.Web), lo cual incide en muchos  aspectos generales, como el propio tamaño del framework o su la velocidad de ejecución, pero también en detalles que nos afectarán a la hora de desarrollar.

Por ejemplo, el global.asax dejaba de tener sentido como tal, pues en su interior encontrábamos código vinculado a eventos de objetos propios de ASP.NET clásico. El código de inicialización, de nuevo, será más parecido al de sistemas basados en OWIN y la implementación de funcionalidades trasversales como un logging las haremos a base de construir middlewares. Tampoco será ya necesario el archivo Web.config, que durante tantos años ha servido para configurar tanto el servidor como las aplicaciones. Los archivos de configuración de los proyectos han cambiado a un modelo mucho más potente y flexible que estudiaremos en su momento.

Claro, y puestos a retocar infraestructura, se ha aprovechado para poner al día algunas asignaturas pendientes en ASP.NET, como la inyección de dependencias, que ahora vendrá integrada de serie y aplicada internamente en todos los frameworks, o el uso de la asincronía de forma generalizada. Si hasta ahora habéis ignorado los célebres async/await, Task y otras hierbas similares,  me temo que tendréis que iros poniendo al día si queréis sacar provecho de las tecnologías que se avecinan.

Roslyn es otro gran protagonista en el nuevo ASP.NET, tanto que incluso está dispuesto a cambiar la forma en que desarrollamos. El ciclo “Editar>Salvar>Ejecutar>Parar>Editar…” se va a simplificar porque ya no hará falta compilar de forma explícita, será Roslyn el que se encargue por detrás de esta tarea. Por ejemplo, si cambiamos el código de un controlador bastará con recargar la página en el navegador para ver el resultado, no habrá que parar la ejecución y volver a empezar. Como podréis suponer, esto no sólo afecta al workflow del proceso de desarrollo, sino que además posibilita otros escenarios de despliegue que hasta ahora no existían. Es un cambio fuerte para los que llevamos años con ASP.NET, pero seguro que podemos acostumbrarnos  ;-)

En cuanto al tooling, también cambia bastante la cosa. Todas las herramientas de build y ejecución pueden lanzarse fácilmente desde la línea de comandos, supongo que porque se trata del común múltiplo en un contexto multiplataforma. Así, es posible realizar estas tareas exactamente de la misma forma independientemente de si estamos en Windows, Mac o Linux. Pero ojo, esto no significa que tengamos que usar oscuros comandos continuamente en nuestro día a día, seguro que Visual Studio y otras herramientas proporcionarán interfaces más similares a los que estamos acostumbrados a utilizar, aunque probablemente determinadas acciones estarán accesibles exclusivamente, al menos de momento, desde línea de comandos.
image
Puede usarse cualquier tipo de editor para programar aplicaciones ASP.NET, e incluso existen proyectos como  Omnisharp para llevar utilidades como intellisense o herramientas de refactorización a editores ajenos a Microsoft como Brackets, Emacs o Sublime Text, desde cualquier sistema operativo. De nuevo, la idea es que el desarrollo de aplicaciones ASP.NET pueda hacerse desde cualquier plataforma y herramienta, y dejar que el desarrollador decida si prefiere alejarse de Windows/Visual Studio.

De la misma forma, y siguiendo una tendencia que se apunta desde hace ya algún tiempo, Visual Studio 2015 se alinea y hace uso de herramientas ya asentadas en otras comunidades de desarrolladores web, como el gestor de paquetes de frontend Bower o el sistema de automatización Grunt. Esto, unido a la necesidad de dar un poco de coherencia a las necesidades de mejora en la organización interna de los propios proyectos, tiene también su incidencia en la estructura de carpetas de las soluciones, que seguirán a partir de ahora un esquema más cercano a la realidad del desarrollo web.

Observad que todo lo que estamos comentando son cambios y novedades generales de la infraestructura de ASP.NET 5 y, por tanto, aplicable para todos los frameworks que se construyan sobre ella. Nada específico de MVC hasta el momento.

Y entonces… ¿qué cambios concretos encontraremos en ASP.NET MVC 6?

Pues en primer lugar, encontraremos los cambios derivados de todas las novedades introducidas en ASP.NET 5 anteriormente comentados:
  • Posibilidad de crear aplicaciones MVC sobre .NET 4.6 o Core CLR.
  • La estructura de los proyectos cambiará.
  • Cambios en el workflow de desarrollo debido a la compilación automática. Si queremos.
  • Tendremos nuevas fórmulas para configurar los proyectos y aplicaciones.
  • En la mayoría de los casos no será necesario usar contenedores IoC para inyectar dependencias, puesto que ASP.NET ya incluirá este mecanismo de serie.
  • Desplegable en cualquier plataforma (Windows, Linux, Mac), y ejecutable en cualquier tipo de host (IIS  u otro servidores web, servicios del sistema operativo, aplicaciones…)
Pero claro, no podía queda ahí la cosa. Ya habíamos comentado por aquí en alguna ocasión que la ausencia de una infraestructura común estaba haciendo que nacieran arquitecturas y componentes paralelos, duplicados, por cada uno de los frameworks de desarrollo web. Esto era especialmente notable con MVC y WebAPI, que compartían muchos conceptos y entre los que existía mucha duplicidad a nivel de arquitectura y componentes. Estaba claro que era un escenario difícil de sostener a largo plazo, por lo que se ha aprovechado el momento para unificar MVC y WebAPI.

A lo bestia, podríamos decir que MVC se ha comido a WebAPI. Un ejemplo práctico es que ya no existirá la clase ApiController, sino que su comportamiento habrá sido absorbido por los habituales controladores MVC (que por cierto, podrán ser objetos POCO puros). Esto implica algunas modificaciones al sistema de routing, al binding, a los mecanismos de negociación de contenidos, y a la forma de retornar resultados desde las acciones, pero estos cambios afectarán principalmente a las aplicaciones WebAPI, las basadas exclusivamente en MVC sufrirán poco debido a esta unificación.

Otra novedad interesante es la introducción de los View Componentes, un nuevo tipo de elementos reutilizables que permiten realizar acciones y componer porciones de vista de forma más eficiente y mejor integrada que las conocidas acciones hija o vistas parciales. Lo veremos en mayor detalle más adelante, pero si queréis ir echando un vistazo, el amigo Eduard escribió sobre ellos hace unos meses.

Con MVC6 encontraremos también una nueva versión de Razor que incluye también novedades interesantes para la capa vista, como la integración de la asincronía en procesos de renderizado, flush parciales de páginas, inyección de dependencias sobre las propias vistas, o los nuevos e interesantísimos tag helpers, para mi gusto una de las novedades más interesantes de esta revisión, pues permiten seguir eliminando ruido de las vistas y hacerlas más fáciles de leer y escribir. Podéis ir leyendo algo sobre ello en el blog de Unai.

En general, no se trata de grandes novedades en sí mismas. De hecho, de no ser por los cambios en infraestructura y las modificaciones internas que esto ha acarreado casi casi podría pasar por un incremento menor de versión.

Pero lo importante, ¿me dolerá, doctor?

Pues depende, amigo. Para las nuevas aplicaciones, probablemente ASP.NET 5 y MVC 6 serán las plataformas naturales sobre la que trabajaremos siempre que el entorno de desarrollo y explotación nos lo permitan. Las novedades de ASP.NET y MVC comenzaremos a usarlas de forma progresiva y seguro que en poco tiempo nos haremos con el nuevo entorno. En este sentido, no creo que el aterrizaje de MVC 6 sea demasiado doloroso.

La entrada de ASP.NET 5 tampoco afectará especialmente a aplicaciones escritas con versiones anteriores de los frameworks como MVC 5, pues seguirán ejecutándose sin problema sobre .NET 4.6, el entorno completo. Pero obviamente no podrán beneficiarse de las novedades de ASP.NET 5 si no son migradas.

Y los problemas los encontraremos precisamente en la migración de una aplicación existente MVC 5 o anteriores a MVC 6. Pero observad que la mayor parte de una aplicación MVC convencional podría valer: los controladores seguirán siendo controladores, seguiremos teniendo vistas, y nuestro modelo podría seguir siendo el mismo (dependiendo de cómo lo hayamos construido, claro). Las mejoras al propio framework MVC 6 (view components, controladores POCO, inyección de dependencias de ASP.NET…) son opcionales y podemos usarlas según las necesitemos, pero no nos van a condicionar una migración, exceptuando quizás la unificación con WebAPI, que sí implicaría la adaptación o reescritura de componentes.

Por ello, las cosas más complicadas en una migración vendrán provocadas principalmente por los cambios en la infraestructura, que van a impedir que se pueda de forma directa, “a la copy&paste”. Los múltiples breaking changes nos obligarán siempre a revisar, replantear y reescribir en algunos casos partes de nuestra aplicación como:
  • La propia estructura de proyecto.
  • La configuración (lo que antes teníamos en el web.config).
  • El routing.
  • Código de inicialización (lo que hasta ahora teníamos en el Application_Start) o eventos de aplicación.
  • El sistema de inyección de dependencias.
  • Módulos, handlers y otros especímenes de esta fauna.
  • Todos los controladores WebAPI, debido a la fusión con MVC.
  • Si pensamos usar Core CLR y en nuestra aplicación hacemos uso de características no soportadas (recordar que se trata de un subconjunto de .NET, no incluye todo), tendremos que reescribirlas usando las alternativas que tengamos disponibles.Y si no las hay, tendremos un problema.
  • Lo mismo ocurrirá si hacemos uso de componentes de terceros que tengan dependencias a componentes no soportados.
  • Si usamos temas algo avanzadillos y hemos sustituido o extendido componentes internos del framework por personalizaciones podríamos encontrar también algunos problemas, pues muchos se han reescrito para dar cabida a los cambios en infraestructura.
  • … y seguro que se me olvidan cosas y que conforme vayamos conociendo mejor MVC 6 iremos descubriendo algunos temas conflictivos más.
Visto lo visto, seguro que habrá aplicaciones cuya migración requiera tal esfuerzo que ni siquiera las intentaremos migrar a MVC 6, quedando en su versión original in aeternum, mientras que más sencillas y asequibles. En cualquier caso, desde Microsoft proporcionarán algunas herramientas para ayudarnos en los procesos de migración, aunque de momento la única ayuda que tenemos disponible es la utilidad API Portability analizer, que nos ayuda a detectar en nuestras aplicaciones los puntos en los que hacemos uso de APIs que limitan la posibilidad de portarla a otros entornos.

En definitiva, si bien los cambios a nivel de plataformas de desarrollo de alto nivel como ASP.NET MVC no son enormes (salvo para WebAPI, descanse en paz ;-)), el replanteamiento de la infraestructura (desde ASP.NET hacia abajo) sí convierte esta nueva oleada de tecnologías en una revolución bastante interesante, probablemente la de mayor calado casi desde el origen del framework, y a la que tendremos que prestar la atención que merece durante los meses venideros.

Publicado en Variable not found.

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

Una sinfonía en C#

50 Ejemplos de Angular, paso a paso.

December 02, 2014 04:24 PM

Recientemente di un taller sobre AngularJs en Buenos Aires, guiado por un grupo de ejemplos de los conceptos que yo creo más relevantes del tema.

Esto ejemplos están disponibles en mi cuenta de github.

Cómo correr los ejemplos?

Las instrucciones para correr los ejemplos desde un runner hecho para la ocasión se encuentran también en gitub.

image

Cualquier comentario no dudes en contactarme.

Nos leemos.

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

Arragonán

Semana 338

December 01, 2014 01:45 PM

Última semana de pasear el mostacho de Movember (aún lo llevo pero no aguantará mucho y aún podéis donar). Lo que significaba que, de nuevo por 4º año consecutivo, tocaba ayudar a organizar una cena Movember en La Jamonería; con su fiesta posterior, que uno tiene que mantener su buen nombre, por lo que el viernes le pedí fiesta al jefe ;).

Antes de la cena teníamos reunión de Zaragoza Ruby. En esta edición me postulé para hablar un poco sobre mustache como de sistema de plantillas. No lo he usado en un proyecto de entidad, tan sólo he jugado con él en un pequeño proyecto personal, pero me parece una alternativa interesante para algunos contextos.

Charla de mustache en Zaragozarb

Como hace tiempo que ando con la cabeza el rehacer completamente FarmaHuesca y publicarla también como aplicación móvil, estuve perdiendo tiempo en ver algo de documentación de diferentes librerías y frameworks que podría utilizar.

Durante la semana también llegaron un par de leads para posibles proyectos, pero por el momento son temas que están muy verdes y a priori diría que no me encajan demasiado.

Sobre lo que sí ando trabajando:

  • Estuve integrando la nueva maquetación en la landing de minchador y adaptando la de la aplicación para que tuviera el mismo look and feel.
  • Tanto en mhop como en outreachbox estuve con tareas de coordinación. En mhop también atendiendo a algunas peticiones de pequeños cambios en el frontend.

Buena semana.

» 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