Noticias Weblogs Código

Made In Flex

BlackBerry dejará de dar soporte a Adobe AIR a nivel de SO

April 17, 2014 12:39 AM

BlackBerry dejará de dar soporte para Adobe AIR en la versión 10 a nivel de SO.…

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

Made In Flex

Desarrollo Flex para iOS

April 16, 2014 11:40 PM

Con Flex y Adobe AIR podemos desarrollar para la gran mayoría de plataformas disponibles hoy en día, tales como iOS, Android, Mac, Windows o cualquier navegador. No obstante, vamos a centrar este artículo en el desarrollo para iOS…

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

Made In Flex

vSphere Web Client SDK for vSphere 5.1 y 5.5

April 15, 2014 08:43 AM

Desde hace unas versiones VMware paso su cliente de java a Flex de hecho las nuevas funciones y sistemas solo son modificables con su versión web por ejemplo modificar una VM de la versión 10 no es…

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

Navegapolis

Ética empresarial

April 14, 2014 08:20 PM

ÉticaLa "ética empresarial" es cuestionable cuando se antepone el beneficio propio al del cliente.

Para medir la ética de mis comportamientos no tengo que mirar los beneficios que me producen, sino los que producen en los demás.

La ética empresarial no se muestra con palabras, sino con los beneficios que la actividad de la empresa genera en los demás. La ética es esencialmente altruista, y las empresas éticas deberían responder más a motivaciones altruistas que egoístas.

En una empresa ética el beneficio propio es una consecuencia de su actuación para garantizar la continuidad de su trabajo, pero no es su fin. Su fin es el beneficio de sus clientes, trabajadores y la sociedad en general.

Quizá un criterio para determinar el nivel ético de la empresa pudiera ser saldo "green" y "commons" que produce esa empresa en el sistema: si es positivo o negativo y en qué proporción.

Post relacionado: ¿Cuál es la finalidad de las empresas?

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

Picando Código

aprend.io – Aprende Front-End de forma gratuita y en Español con videos

April 14, 2014 02:36 PM

aprend.ioSi están con ganas de empezar a aprender HTML y CSS, o conocen a alguien en esa situación, esto les va a interesar.

La semana pasada se lanzó el proyecto aprend.io: un sitio compuesto por 16 videos acompañados de código para empezar a aprender los fundamentos de Front–End Development.

Los videos están divididos en 3 temas principales: HTML, CSS y un proyecto de ejemplo; Pizzatio. Viendo los videos en orden y practicando con ayuda del código de ejemplo podrás llegar a tener una comprensión firme de lo fundamental de Front–End Development.

aprend.io

aprend.io

DrummerHead es el anfitrión del curso y te lleva de la mano con los videos y ejemplos de código, pero depende también del esfuerzo que cada uno le ponga arriba para seguir aprendiendo.

Genial tener recursos de aprendizaje nuevos, en español, libres y gratuitos. Todo el código de ejemplo esta bajo los términos de la Licencia MIT, el código que compone aprend.io también esta bajo los términos de la Licencia MIT. Los videos están bajo los términos de la licencia Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International

Los invito a visitar aprend.io y que vean de qué va la cosa.

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

Arragonán

Semana 305

April 14, 2014 12:53 PM

Bastante variada la semana que acaba de pasar, desde una visita relámpago por mi pueblo hasta ejercer de facilitador en el hackathon Space Apps Challenge celebrado en Zaragoza, pasando por impartir una charla en el Betabeers Zaragoza o quedarme colgado en mitad de una portabilidad de proveedor de ADSL en mi casa.

Quedarme sin ADSL a mitad de semana ha trastocado mis rutinas. Aún pudiendo ir tirando de tethering para algunas cosas, ha provocado que pase más horas en el estudio de lo que para mi es habitual. A ver si esta semana se hace efectiva mi portabilidad y vuelvo a mi “normalidad”.

Dediqué bastante tiempo en preparar mi charla A falta de APIs buenas son tortas para la edición especial de Betabeers Zaragoza, a modo de introducción al web scraping.

Aunque tenía claro en mi cabeza qué es lo que quería contar, a mi siempre me cuesta mucho definir cómo hacerlo y además intentar que sea lo más ameno posible. Al ser una edición especial me había hecho a la idea de que apenas pasaría de la veintena de asistentes, pero resultó que estaba bastante equivocado, menudo susto XD.

Ya durante el finde, ejercí de “facilitador” del Space Apps Challenge, era el primer hackathon en el que asumía un rol diferente al de participante. A nivel técnico no es que hiciera gran cosa, echar una mano en momentos puntuales de atasco en un par de equipos, lo demás fue ayudar a la organización en algunas cosillas y andar dando apoyo moral a los participantes.

Además de ver lo mucho que se lo curraron los equipos y los resultados del hackathon, me gustó ver que hay cantera; había un buen puñado de jóvenes participando muchos de ellos aún estudiando. Por poner un par de peros, eché de menos que hubieran más variedad de perfiles, especialmente encontré mucho a faltar la presencia diseñadores; y cómo no, que más chicas se hubieran animado a participar tal y como lo hizo Sandra.

Y lo que en mis proyectos se refiere, la semana fue algo así:

  • Tras un par de pequeños arreglos en mhop, empecé a dedicarme a implementar el alta de productos por parte de los diseñadores. Ahora mismo sólo pueden hacerlo los administradores y se consume mucho esfuerzo en la comunicación con los diseñadores industriales.
  • Tuvimos una reunión de proyectoSinNombre de la que surgieron detalles que cerrar, y a ello le dedicamos algunas horas semana.
  • Prepararé y envié una propuesta para un proyecto relacionado con eventos y ticketing.
  • Recopilé las facturas para el IVA trimestral.
  • Hice algunas tareas de mantenimiento minchador.

Buena semana.

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

Variable not found

Enlaces interesantes 154

April 14, 2014 11:58 AM

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...

Made In Flex

FlexUnit 4.2.0 es ahora parte de Apache Flex

April 14, 2014 10:39 AM

En las últimas semanas se ha estado preparando la donación de FlexUnit al proyecto Apache Flex. Una vez realizado el trabajo y las adaptaciones necesarias, se ha realizado la votación de rigor y ya podemos decir que…

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

Una sinfonía en C#

Backbonejs: Rutas

April 13, 2014 01:37 PM

Dijimos que Backbone es especialmente útil para aplicaciones SPA (single page applications) así que vamos a ver un componente que nos ayuda con este tipo de aplicaciones.

¿Qué es una SPA?

Son aplicaciones que transcurren en la misma página, sin ir de una página a otra, un ejemplo típico de Gmail, cuando estamos en la bandeja de entrada vemos un listado de mails, hacemos click en uno de ellos y seguimos en la misma página pero si mirando con atención vamos a notar que parte de la URL ha cambiado, es decir, permanecimos dentro de la misma página pero, de algún modo, hemos ido a un lugar dentro de ella.

Cuando estamos en la bandeja de entrada vemos esta URL

https://mail.google.com/mail/u/0/?pli=1#inbox

Cuando vemos un mail vemos la siguiente

https://mail.google.com/mail/u/0/?pli=1#inbox/145511f0ec63a6d4

Lo que ocurre que por más que cambiemos algo de la URL posterior al numeral ( # ) no se ejecutará la navegación pero nosotros podemos saberlo desde Javascript (y decidir hacer algo), llamamos a esto navegación por anclas.

Navegación por anclas

Un ejemplo muy sencillo de navegación podemos verlo con referencias dentro de la misma página, vamos a Wikipedia para comprobarlo. Ingresamos a la URL del artículo sobre Backbonejs escribiendo esto en el navegador

http://en.wikipedia.org/wiki/Backbonejs

Hasta ahora todo normal, pero si agregamos al final de la URL el numeral y una referencia vemos que el navegador cambia de sitio dentro de la página

http://en.wikipedia.org/wiki/Backbonejs#References

Lo que hicimos no fue más que ir hasta un elemento dentro de la página llamado References, esto es automático, lo interesante es que podemos poner cualquier cosa después del numeral y además si presionamos el botón volver del navegador volvemos a la misma URL tal como era antes, con lo cual podemos navegar estando siempre en la misma página.

Nosotros desde Javascript podemos saber de estos cambios en la URL y hacer cosas, en esto se basa el modelo de rutas de Backbone, vamos a ver un ejemplo:

<html>
<head>
	<script type="text/javascript" src="js/vendor/jquery/jquery.js"></script>
	<script type="text/javascript" src="js/vendor/underscore/underscore.js"></script>
	<script type="text/javascript" src="js/vendor/backbone/backbone.js"></script>
	<script type="text/javascript">
		//creamos una clase Router extendiendo la clase base de Backbonejs
		var Router = Backbone.Router.extend({
			//definimos las rutas
			routes:{
				"": "home", // la url por defecto va a llamar a la función home
				"accion1": "funcion1" //la url #accion1 va a llamar a funcion1
			},
			home: function(){
				console.log("estamos en casa");
			},
			funcion1: function(){
				console.log("la acción 1 ha sido llamada");
			}			
		});
		
		//creamos un router
		var router = new Router();	
		//iniciamos el motor de navegación
		Backbone.history.start();	
	</script>
</head>
<body>
<a href="#accion1">Ir a la acción 1</a>
</body>
</html>

Básicamente cargamos este html en el navegador se escribe en la consola “estamos en casa” y cuando presionamos el link (que apunta a #acccion1) “la acción 1 ha sido llamada”, entonces con Backbone es muy simple escuchar estos cambios en la URL y llamar funciones a partir de ello.

Pasar parámetros a las rutas

Hay muchas cosas que se pueden hacer con las rutas, por ejemplo pasar parámetros, del siguiente modo:

<html>
<head>
	<script type="text/javascript" src="js/vendor/jquery/jquery.js"></script>
	<script type="text/javascript" src="js/vendor/underscore/underscore.js"></script>
	<script type="text/javascript" src="js/vendor/backbone/backbone.js"></script>
	<script type="text/javascript">
		//creamos una clase Router extendiendo la clase base de Backbonejs
		var Router = Backbone.Router.extend({
			//definimos las rutas
			routes:{
				"": "home", // la url por defecto va a llamar a la función home
				"accion1": "funcion1", //la url #accion1 va a llamar a funcion1
				"accion1/:parametro1": "funcion2" //la url #accion1 va a llamar a funcion1
			},
			home: function(){
				console.log("estamos en casa");
			},
			funcion1: function(){
				console.log("la acción 1 ha sido llamada");
			},
			funcion2: function(parametro1){
				console.log("se llama a la acción con el valor de parámetro: " + parametro1);
			}
		});
		
		//creamos un router
		var router = new Router();	
		//iniciamos el motor de navegación
		Backbone.history.start();	
	</script>
</head>
<body>
<a href="#accion1">Ir a la acción 1</a> </br>
<a href="#accion1/valor1">Ir a la acción 1 y pasar un parámetro</a>
</body>
</html>

Mágico, para no extenderme más con detalles que se pueden ver en la documentación los dejo por ahora con un link a un gist de este código, nos leemos.

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

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

Desfragmentar disquete

April 13, 2014 06:21 AM

A muchos el proceso de desfragmentar un disquete les puede parece lejano, o incluso desconocido. Allá a finales de los 80, con la utilidad Compress, incluida entre otras en PC-Tools de Central Point Software, me proporcionaba las herramientas necesarias para desfragmentar mis disquetes, tanto de 3,5 pulgadas como de 5,25 pulgadas. Los candidatos eran aquellos [...]

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

Blog Bitix

Ejemplo lista de tareas con Backbone y React

April 11, 2014 02:33 PM

React

En anteriores entradas explicaba como hacer el típico ejemplo que se suele usar como demostración en los framework MVC de Javascript que consiste en una lista de tareas en la que se pueden añadir nuevas, marcarlas como completadas y eliminarlas. Realice este ejemplo en uno de ellos usando solo Backbone y posteriormente usando Marionette. Estos ejemplos eran parte de una serie de artículos sobre Javascript que la que mostaba como usar muchas otras herramientas como Require JS, Mustache, logging con javscript, capturar errores en javascript, introducción a Backbone, lista de tarea con Backbone, RESTEasy y Tapestry, pruebas unitarias con Jasmine y Sinon y que constituyen parte del actual «estado del arte» en cuanto a desarrollo con Javascript.

La lista de tareas aunque es un ejemplo sencillo sirve perfectamente como ejercicio para mostrar el uso de los frameworks MVC. En esta entrada voy a mostrar como hacer el mismo ejemplo usando Backbone y React y veremos, en mi opinión, que el ejemplo es mucho mas sencillo y lógico.

La parte más complicada y menos intuitiva del ejemplo de la lista de tareas con solamente Backbone o con Marionette probablemente era la V del MVC. Backbone es un framework que deja bastante libertad al desarrollador pudiendo usar únicamente las partes que necesitemos de él, sin embargo, esta sencillez nos obliga a gestionar ciertas «tareas de fontanería» y repetitivas nosotros mismos como la gestión de las vistas y la memoria. Marionette trata de dar solución a parte de estas tareas necesarias además de proporcionar unas guías y arquitectura para el desarrollo de las aplicaciones. Sin embargo, aún con Marionette la construcción de la parte de la vista con el uso de ItemView, CollectionView y Layout comentados en la documentación me resultó poco intuitivo y en cierta medida todavía complicado, no acabé convencido del todo, con React he acabado con la sensación que hacer algo más complejo que este ejemplo es algo al menos manejable.

React es una librería que en algunos casos se está usando en aplicaciones junto con Backbone para proporcionar la parte de la vista y controlador que en conjunto definen lo que en React se conoce como un componente. De esta manera Backbone proporciona los modelos, eventos, routing , … y React proporciona la representación de esos modelos en html y el código encargado de gestionar el estado de esa vista. React tiene ciertas ventajas adicionales por su funcionamiento y es que cuando se cambia algo en la vista no se reemplaza el html completo de la vista y se inserta uno nuevo sino que React busca las diferencias entre la vista actual y la nueva y realiza únicamente los cambios necesarios para tener la vista nueva, esto tiene la ventaja de que el proceso es más eficiente y rápido y puede notarse en aplicaciones con muchos datos gestionados en el cliente. Pero lo que más me ha gustado de React es la definición del concepto de componente (vista + controlador) que por una parte hace que la creación de las vistas es mucho más sencilla e intuitiva que en Backbone o Marionette y que junto con el controlador permite crear piezas reusables de código.

Los componentes de React reemplazan a las vistas de Backbone y vistas, controladores y layouts de Marionette. En el nuevo ejemplo los cambios principales se encuentran en el archivo tareas.js que contiene el código de la aplicación de lista de tareas.

<noscript><pre><code>define('tareas', [ 'jquery', 'underscore', 'backbone', 'react', 'mustache', 'plantillas', 'i18n!i18n/nls/mensajes' ], function($, _, Backbone, React, Mustache, Plantillas, Mensajes) { function render(plantilla, datos, mensajes) { var d = datos || {}; var m = mensajes || {}; var vista = _.extend(d, { message: m }); var p = Plantillas[plantilla]; var pp = p(); return pp(vista); } // An example generic Mixin that you can add to any component that should react // to changes in a Backbone component. The use cases we've identified thus far // are for Collections -- since they trigger a change event whenever any of // their constituent items are changed there's no need to reconcile for regular // models. One caveat: this relies on getBackboneModels() to always return the // same model instances throughout the lifecycle of the component. If you're // using this mixin correctly (it should be near the top of your component // hierarchy) this should not be an issue. var BackboneMixin = { componentDidMount: function() { // Whenever there may be a change in the Backbone data, trigger a reconcile. this.getBackboneModels().forEach(function(model) { model.on('add change remove reset', this.forceUpdate.bind(this, null), this); }, this); }, componentWillUnmount: function() { // Ensure that we clean up any dangling references when the component is // destroyed. this.getBackboneModels().forEach(function(model) { model.off(null, null, this); }, this); } }; var Tarea = Backbone.Model.extend({ urlRoot : 'rest/tareas/tarea', defaults : { id : null, descripcion : '', completada : false }, toogle: function() { this.set('completada', !this.get('completada')); } }); var Tareas = Backbone.Collection.extend({ url: 'rest/tareas', model: Tarea, findCompletadas: function() { return this.models.filter(function(tarea) { return tarea.get('completada'); }); }, removeCompletadas: function() { _.each(this.findCompletadas(), function(tarea) { tarea.destroy(); }); } }); var TareaComponent = React.createClass({ componentDidMount: function() { var _this = this; this.ui = { completada: $('input[name=completada]', this.getDOMNode()) }; this.ui.completada.change(function(event) { _this.props.tarea.toogle(); _this.props.tarea.save(); }); }, render: function() { // return ( // &lt;label className=&quot;checkbox&quot;&gt; // &lt;input type=&quot;checkbox&quot; name=&quot;completada&quot; checked={(this.props.tarea.get('completada'))?'checked':''}/&gt; &lt;span className={this.props.tarea.completada}&gt;{this.props.tarea.get('descripcion')}&lt;/span&gt; // &lt;/label&gt; // ); return React.DOM.label({className:'checkbox'}, React.DOM.input({type:'checkbox', name:'completada', checked:(this.props.tarea.get('completada'))?'checked':''}), React.DOM.span({className:this.props.tarea.completada}, this.props.tarea.get('descripcion')) ); } }); var TareasComponent = React.createClass({ render: function() { var tareas = this.props.tareas.map(function(tarea) { // return ( // &lt;li&gt;&lt;TareaComponent tarea={tarea}/&gt;&lt;/li&gt; // ); return React.DOM.li(null, TareaComponent({tarea:tarea}) ); }, this); // return ( // &lt;ul&gt;{tareas}&lt;/ul&gt; // ); return React.DOM.ul(null, tareas); } }); var EstadoComponent = React.createClass({ render: function() { var d = this.getData(); var m = { 'COMPLETADAS_tareas_de_TOTAL_completadas': Mustache.render(Mensajes.COMPLETADAS_tareas_de_TOTAL_completadas, d), 'Muy_bien_has_completado_todas_las_tareas': Mensajes.Muy_bien_has_completado_todas_las_tareas, }; var estado = render('estado', d, m); // return ( // &lt;span className=&quot;estado&quot;&gt;{estado}&lt;/span&gt; // ); return React.DOM.span({className:'estado'}, estado); }, // Métodos getData: function() { var completadas = this.props.tareas.findCompletadas().length; var total = this.props.tareas.length; return { completadas: completadas, total: total }; } }); var TareasApp = React.createClass({ mixins: [BackboneMixin], getBackboneModels: function() { return [this.state.tareas]; }, getInitialState: function() { return {tareas: new Tareas()}; }, componentDidMount: function() { var _this = this; this.ui = { nuevaTarea: $('input[name=nuevaTarea]', this.getDOMNode()), limpiar: $('input[name=limpiar]', this.getDOMNode()) }; this.ui.nuevaTarea.focus(); // Eventos this.ui.nuevaTarea.keypress(function(event) { // Comprobar si la tecla pulsada es el return if (event.which == 13) { var descripcion = _this.ui.nuevaTarea.val().trim(); // Comprobar si se ha introducido descripción de la tarea if (descripcion == '') { return; } // Añadir la tarea y limpiar el input var tarea = new Tarea({ descripcion: descripcion, completada: false }); _this.addTarea(tarea); _this.ui.nuevaTarea.val(''); } }); this.ui.limpiar.click(function() { _this.removeTareasCompletadas(); }); }, render: function() { // return ( // &lt;div&gt; // &lt;h2&gt;{Mensajes.Lista_de_tareas}&lt;/h2&gt; // &lt;input type=&quot;text&quot; name=&quot;nuevaTarea&quot; className=&quot;form-control&quot; placeholder={Mensajes.Introduce_una_nueva_tarea} /&gt; // &lt;TareasComponent tareas={this.state.tareas} /&gt; // &lt;EstadoComponent tareas={this.state.tareas} /&gt; // &lt;br/&gt; // &lt;input type=&quot;button&quot; name=&quot;limpiar&quot; value={Mensajes.Limpiar} disabled={(this.isTareasCompletadas())?null:'disabled'} className=&quot;btn&quot; /&gt; // &lt;/div&gt; // ); return React.DOM.div(null, React.DOM.h2(null, Mensajes.Lista_de_tareas), React.DOM.input({type:'text', name:'nuevaTarea', className:'form-control', placeholder:Mensajes.Introduce_una_nueva_tarea}), TareasComponent({tareas:this.state.tareas}), EstadoComponent({tareas:this.state.tareas}), React.DOM.br(), React.DOM.input({type:'button', name:'limpiar', value:Mensajes.Limpiar, disabled:(this.isTareasCompletadas())?'':'disabled', className:'btn'}) ); }, // Métodos isTareasCompletadas:function() { return this.state.tareas.findCompletadas().length &gt; 0; }, addTarea: function(tarea) { this.state.tareas.add(tarea); tarea.save(); }, removeTareasCompletadas: function() { this.state.tareas.removeCompletadas(); }, resetTareas: function(tareas) { this.state.tareas.reset(tareas); }, fetch: function() { // Con reset:true solo se lanza un evento para todos los cambios que se produzcan en la colección this.state.tareas.fetch({reset:true}); } }); return { Tarea: Tarea, Tareas: Tareas, TareaComponent: TareaComponent, TareasComponent: TareasComponent, EstadoComponent: EstadoComponent, TareasApp: TareasApp }; });</code></pre></noscript>

El resultado es el siguiente:

Los elementos de las vistas se recomienda definirlas con los elementos que proporciona React con React.DOM, pueden definirse más al estilo de html con jsx pero esto hace que el javascript haya de compilarse para transformar ese jsx/html a los elementos React.DOM, el mayor problema es que esto es un proceso costoso lo que puede ralentizar la carga de una página y que el compilador tiene un tamaño considerable de unos 300 KiB. El JSX es más claro y parecido al resultado final que el código equivalente React.DOM pero aún así el código javascript es suficientemente claro. Si aún así quisiésemos usar JSX lo recomendable sería que los archivos con contenido jsx se precompilase en un momento anterior de enviarlo al cliente, posiblemente antes del despliegue de la aplicación en el servidor.

Para probar el código podemos hacerlo abriendo el archivo test/javascript/SpecRunner.html, sin embargo, deberemos hacerlo con Chrome o Chromium y lanzándolo con un parámetro opcional para permitir la carga de los archivos.

<noscript><pre><code>$ chromium --allow-file-access-from-files</code></pre></noscript>

También podríamos probarlo usando gradle con:

<noscript><pre><code>$ ./gradlew jasmine</code></pre></noscript>

Sin embargo, PhantomJS que es lo que se utiliza para simular el navegador en las pruebas con jasmine y grunt, no soporta la función bind produciéndose la siguiente excepción al usarse en la librería de React.

<noscript><pre><code>Error: define: 'undefined' is not a function (evaluating 'RegExp.prototype.test.bind( &gt;&gt; /^(data|aria)-[a-z_][a-z\d_.\-]*$/ &gt;&gt; )')</code></pre></noscript>

Para evitarlo debemos añadir un polyfill. Deberemos añadir los polyfills de cujojs/poly, podemos hacer uso de ellos con RequireJS basta como añadirlo como dependencia:

<noscript><pre><code>define(['poly/function', 'specs/tareas-specs'], function() { });</code></pre></noscript>

Este problema de la función bind ya esta incluido como peticion en PhantomJS y probablemente se resuelva en la versión 2.0.

El ejemplo con el código fuente completo de este ejemplo está en mi repositorio de GitHub, puedes probarlo en tu equipo con el siguiente comando:

<noscript><pre><code>$ ./gradlew tomcatRun</code></pre></noscript>

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Introducción y ejemplo de Backbone.js
Ejemplo de pruebas unitarias en javascript con Jasmine y Sinon
Ejemplo lista de tareas con Marionette
Usar Grunt para ejecutar teses unitarios de código Javascript
Function/bind#Compatibility
React, JSX, and CoffeeScript

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

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

Visual Models

April 08, 2014 08:37 PM

Simple y práctico, así calificaría este artículo, se dice que a veces lo simple es lo mejor, aunque en modelos visuales yo tambien le daría mucho peso a UML sin que esto represente complicarte la vida, al contrario creo que este puede ser muy práctico.

Visual Models

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

Variable not found

Back to my roots, el evento de Gusenet que no debes perderte

April 08, 2014 10:23 AM

Gusenet(Léase con voz radiofónica) De los creadores de “Yo Node, tú XAML”, llega ahora “Back to my roots”, el nuevo evento con el que los chicos de Gusenet piensan liarla de nuevo y mantener su puesto como uno de los festivales frikis más potentes del panorama nacional.

Torrevieja!Tendrá lugar los días 25, 26 y 27 de Abril en Torrevieja, Alicante (no puedo evitar decirlo, crecí con el 1-2-3 ;-D), un entorno inmejorable para disfrutar de un fin de semana en la costa rodeado de gente que comparte tu misma pasión por la tecnología. Y cerveza, mucha cerveza, cortesía de la organización.

El registro es gratuito y debéis hacerlo cuanto antes a través del siguiente enlace: http://www.eventbrite.es/e/entradas-back-to-my-roots-10635022639.

Las charlas previstas a día de hoy son las siguientes:

Ponente Charla
Marc Estrada Pague una, llévese dos (apps para múltiples dispositivos).
Marc Rubiño AngularJS – Poli bueno, poli malo.
Juan María Hernández No pierdas tiempo escribiendo tests.
Alfredo Fernández Todo un misterio (es secreto: probablemente algo cañero de JS).
Juan Quijano Coded UI, iniciación a pruebas funcionales del interfaz gráfico.
Quique Martínez Video OnDemand y Live Streaming. Entrega de vídeo multiplataforma.
Luis Ruíz Pavón CQRS – Hasta el infinito y más allá
Alberto Díaz & Adrián Díaz Porque no veo otra cosa nada más que SharePoint
Pedro J. Molina Backends y arquitecturas para servicios con Radarc
Alex Casquete Programación funcional reactiva
Eduard Tomás Videojuegos web en tiempo real con Katana, SignalR y NancyFx
Roberto Luis Bisbé Firefox OS: Javascript vuela en primera clase
Enrique Catalá Nuevo motor relacional In-memory OLTP en SQL Server 2014
Bruno Capuano Coding 4 Fun, Kinect V2, Leap Motion, Unity3D, etc …
Josue Yeray & Santiago Porras Charla secreta
Isabel Cabezas & Toni Recio Javascript y por qué no comparar la velocidad con el tocino
Carlos Carrillo Windows Azure Mobile Services ahora con .NET
Juan Manuel Servera Introducción a Roslyn
Miguel Egea Diseñando bases de datos relacionales para mantener históricos
Eladio Rincón Índices compuestos para desarrolladores
Fernando G. Guerrero Reflexiones sobre el futuro, de alguien que ha peleado ya algunas recesiones
Fernando Escolar Load Tests: ¿sobrevivirías al efecto menéame?
Pedro Hurtado, LLuis Franco y Sergio León Dos tontos muy tontos y un tío con futuro
 


Y como los organizadores son gente importante, hasta les hacen entrevistas ;-) Podéis leer y oír algo más sobre el evento siguiendo este link: GUSENET nos habla de su mega-evento en Torrevieja el proximo 26 de Abril…

Por mi parte, aunque todavía no sé si podré asistir personalmente por problemas de agenda, como mínimo lo haré en espíritu mediante una pequeña colaboración ;-D: Entre los asistentes se sorteará una copia firmada de mi libro “SignalR Programming in Microsoft ASP.NET”!!


Publicado en Variable not found.

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

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

The internet of Things and CRM

April 07, 2014 11:27 PM

Interesante artículo que víncula el llamado Internet de las cosas y CRM, esta claro el mensaje Social, Mobile, Cloud  y Big Data

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

proyectos Ágiles

Adopción de Agile en la empresa. Entrevista revista Tendencias

April 07, 2014 09:54 PM

A continuación aparece una entrevista realizada para la revista Tendencias, donde entre otros temas se habla sobre qué es Agile, el porqué de Agile, qué implica adoptar Agile en la empresa, el rol del Scrum Master, la motivación y compromiso de personas, el liderazgo en un entorno Agile, métricas, quién utiliza Agile y el uso de Agile que hizo Obama en su campaña del 2012.

question-postits

 

 

1- ¿Cómo definiría brevemente la filosofía agile?
Agile es una forma de obtener mejores resultados basada en conseguir equipos de alto rendimiento, con el cliente integrado en el equipo, hacer que las personas estén motivadas, tener feedback rápido sobre el producto final que se está desarrollando y reflexionar de manera regular sobre cómo mejorar el proceso de trabajo. Para conseguir esto se necesita priorizar los objetivos a conseguir según el valor que aportan al receptor final de un proyecto/servicio, ser flexible en la incorporación de cambios, crear equipos multidisciplinares, auto-organizados y estables que conjuguen la simplicidad con la excelencia técnica de la solución.
 
2- ¿Cuándo y por qué decidió asumir esta filosofía laboral y, tal vez, personal? ¿Qué ha significado y está significando para usted en su vida diaria?
Mi contacto inicial con Agile (XP) fue en algunos proyectos en el 2002.  Tras estar trabajando en diversas empresas y con distintas metodologías, en el 2008 decidí que todo mi trabajo se basase al máximo en esa filosofía (lo cual significaba crear el contexto necesario para eso), para poder ejecutar proyectos complejos con mayor garantía de éxito. A nivel personal, me ha implicado tener que estar aprendiendo continuamente cómo mejorar en mi parte de soft-skills, un reto mucho más difícil (pero más agradecido) que el de aprender nuevas técnicas de gestión o desarrollo. Esto al final tiene que repercutir en que, a nivel laboral y personal, mi vida (y la de los que me rodean) sea más feliz (si no, no valdría la pena).
 
3- ¿Es fácil virar hacia agile?
Ser ágil no es sencillo, dependiendo del contexto puede ser un cambio cultural importante, que depende también de la idiosincrasia de las personas y de sus capacidades. Ser ágil requiere disponer de personas que estén realmente dispuestas a trabajar en equipo y sean abiertas de mente, que tengan ganas de probar cosas nuevas, de aprender y de mejorar, no dar por hecho que lo que no funciona bien “siempre ha sido así”.
 
open-minded
 
4- ¿De qué forma los principios ágiles están cambiando los objetivos y la misión de los departamentos de Recursos Humanos?
El foco pasa a estar no sólo en el crecimiento del individuo y en el satisfacer sus motivaciones “intrínsecas” (todo esto es básico), sino además en la creación de equipos (encaje de personas, team building, …), un equipo es un activo para la empresa y cuesta tiempo y esfuerzo crearlo, por lo que hay en dotar a sus miembros con soft-skills y técnicas para mejorar cómo se relacionan (team agreements, gestión de conflictos, …) y hay que modelar la cultura a nivel de empresa para que la colaboración sea algo "nuclear". Esto implica introducir en la empresa valores explícitos de trabajo en equipo y de apertura de mente, dar mensajes para conseguir alineamiento en esto, hacer un reconocimiento explícito de los comportamientos aceptados, contratar personas que tengan estos principios, hacer coaching a quienes tienen más dificultades, despedir a los que tras repetidos esfuerzos no se ha conseguido integrar o adaptar y siguen actuando de la manera contraria, etc.
 
5- Trabajar con personas motivadas y comprometidas es, según la filosofía Agile, una condición indispensable, pero ¿no le parece una utopía conseguir que los trabajadores estén siempre motivados y comprometidos?
La mayoría de las personas necesitan estar motivadas en su trabajo, son muchas horas como para no disfrutarlo mínimamente y “realizarse” (sea aprender cosas nuevas, hacer algo que sea importante, tener un margen para creatividad, que el trabajo no sea aburrido o tener reconocimiento). Conseguir que las personas estén motivadas no es sencillo, siempre habrán momentos complicados, donde la motivación bajará, pero esto no es opcional, el trabajo está realizado por personas, no son máquinas, y las personas motivadas hacen cosas increíbles. La motivación depende de la pripia persona y del management, que es quien debería crear el contexto para que haya partes del trabajo que sean motivadoras. Otro problema es cuando las personas ya vienen motivadas de casa pero en el trabajo son sus responsables los que les desmotivan.
 
6- El trabajo en equipo es clave, pero ¿no se ha encontrado con que muchas veces en los equipos acaban trabajando duro unos cuantos y el resto no tanto?
Cierto, en este caso hay una disfunción que, además de reducir el rendimiento y motivación general, puede crear tensiones. Forma parte de las funciones del responsable del "crecimiento" de ese equipo y del management identificar esta situación y ponerle remedio. En entornos maduros es el propio equipo el que, tras identificar el problema, analiza cuál es la razón por la que sucede esto y trabaja con el responsable para mejorar la situación (falta de motivación o de capacidades de los que trabajan menos, incompatibilidad de caracteres, falta de criterios o principios comunes, etc.). Tras trabajar las mejoras, si no hay resultado, el propio equipo y su responsable deberían tomar la decisión de sacar a esas personas de ese equipo.
green-growth
 
7- ¿La filosofía agile se puede aplicar sólo a parte de una empresa o tiene que aplicarse íntegramente?
Cuanto más extendida esté en la empresa, más oportunidades tendrá para proporcionar productos o servicios mejores y de calidad. El trabajo en equipo es un factor competitivo diferencial en las empresas más punteras. De cualquier manera, como he comentado antes, la adopción completa de Agile dependerá mucho de la cultura de la empresa y su capacidad para enfocarse toda en el cliente final.
 
8- ¿Qué caracteriza a un líder agile?
Un líder ágil es una persona que entiende que es quién es y está donde está por las personas de sus equipos. Se enfoca en crezcan en competencia, les enseña el "oficio", es un líder a al servicio del equipo (él es quien va a averiguar cuales son sus necesidades para que puedan hacer mejor su trabajo y se encarga quitarles los impedimentos que tengan), conoce a su gente, se preocupa por la motivación de cada individuo (no lo desmotiva), hace que trabajen en equipo, que colaboren y piensen juntos, mantiene una estrategia de mejora de su área con visión en el medio plazo (no es cortoplacista) y practica con el ejemplo, todo ello con una óptica positivay constructiva.
 
9- ¿El hecho de que sea tan importante la comunicación cara a cara en el día a día de una empresa agile hace que las nuevas tecnologías que promocionan la comunicación online no sean tan imprescindibles?
Si bien la comunicación cara a cara es casi la mejor opción (sólo superable si además se utiliza una pizarra blanca), la realidad es que hoy en día bastantes proyectos se realizan de manera distribuida por diversas razones. En este punto, es fundamental disponer de buenos sistemas de videoconferencia, compartición de pantallas, posibilidad de editar documentos por varios usuarios simultáneamente, diagramación colaborativa, etc.
 
10- ¿Por qué la filosofía agile es especialmente útil en contextos de incertidumbre?
Porque Agile también es un método de gestión de riesgos. Ya desde el inicio de un proyecto se priorizan los objetivos en función del valor que aportan al receptor del proyecto. También se divide la complejidad en partes más pequeñas que siempre tienen que proporcionar un trocito adicional de producto final, por que es crítico disponer de feedback rápido. Para ello el cliente revisa cada uno de estos incrementos de manera que se asegura que se va de la mano con él (para no tener sorpresas al final del proyecto). Adicionalmente, diariamente el equipo se sincroniza para identificar problemas, fomentando la ayuda mutua para desbloquearlos. Por último (y este es un aspecto nuclear de Agile, sino no se puede decir que sea ágil) el equipo dispone de tiempo “de calidad” de manera regular para reflexionar, para evaluar cómo está trabajando y poder mejorar la situación. 
 
risk_management
 
11- ¿Por qué aparece la necesidad de la filosofía agile?
La filosofía Agile aparece como reacción a planteamientos de gestión tradicionales, heredados de la ingeniería clásica, que no tienen tanto en cuenta el factor humano (capacidades, relaciones) que hay en entornos de gran incertidumbre y, especialmente, donde hay trabajadores de conocimiento. Más que focalizarse en los procesos de trabajo por encima de todo (como tienden a hacer los métodos tradicionales), los métodos ágiles asumen lo que empíricamente sabemos de la realidad de los proyectos: la importancia de disponer de gente competente y motivada que sea capaz de trabajar en equipo, apoyarles y confiar en ellos, la necesaria colaboración continua del cliente (no sólo al principio y al final del proyecto), la realidad de que va a ser necesario realizar cambios durante el proyecto, que el papel finalmente no “lo aguanta todo”, que el “momento de la verdad” sólo es cuando enseñas al cliente alguna parte de producto final, el foco en la simplicidad de las soluciones y el trabajar a un ritmo sostenible para ser más productivos. Adicionalmente los métodos ágiles son antagonistas del caos, introducen disciplina en el proceso y foco en la calidad del trabajo.
 
12- ¿Qué opina del uso que hizo Obama de Agile durante la campaña de 2012?
En esa campaña acertaron en utilizar Agile para gestionar un contexto complejo que necesitaba de resultados y ajustes rápidos. Además, como dice la primera línea del Agile Manifesto, el primer factor clave fue encontrar a gente “espabilada” y motivada por el reto (un aspecto crítico para conseguir soluciones rápidamente). Después también fue acertado en lanzar rápidamente un “producto” suficientemente bueno (no perfecto, incluso con defectos, pero con lo más relevante) e irlo iterando y repriorizando rápidamente, para tener mucha flexibilidad respecto a lo que fuese pasando en el contexto (en cada momento de una campaña las prioridades cambian). Otro acierto fue apoyar en datos objetivos las decisiones de qué era lo más importante desarrollar en cada momento, para que fuese útil para los usuarios finales. El hecho de que Agile proporciona mucha transparencia,visibilidad y feedback sobre el progreso y resultados del proyecto (en este caso a nivel semanal) a todas las personas con poder de decisión (Stakeholders) también les ayudó de manera significativa a que ganaran confianza en el método de trabajo (no estaban familiarizados con un método de “aprendizaje” y desarrollo continuo sobre un producto software) que, curiosamente, basándose en datos de velocidad empíricos, proporcionaba una gran fiabilidad acerca de cuándo determinados hitos se alcanzarían.
 
obama-sport
 
13- La filosofía Agile es intrínseca al Scrum Master? ¿qué papel juega esta nueva figura?
El Scrum Master es el “entrenador del equipo”, desde una perspectiva de coaching su objetivo es el hacer crecer un equipo para que sea de alto rendimiento (incluyendo en este equipo al cliente), donde la auto-organización y la motivación son aspectos clave. Para ello, el Scrum Master entiende cuáles son los valores y principios de Agile y facilita una serie de prácticas y reuniones con el fin de que el equipo piense junto, se creen sinergias, se complementen, se ayuden y el trabajo fluya. Adicionalmente, se dedica a quitar las “piedras del camino” (lo que llamamos "impedimentos") de manera que este equipo se pueda dedicar al máximo a aportar valor.
 
14- ¿Cómo podemos medir un proyecto en Agile?
Dependiendo del tipo de contexto, entre las principales métricas podemos encontrar las siguientes: el valor que se está aportado (si lo que se está desarrollado es lo que se esperaba o produce el resultado deseado), la productividad del equipo de trabajo (también llamada “velocidad”), la calidad del producto, el tiempo que falta para acabar, el tiempo de entrega de peticiones de trabajo, la motivación del equipo, etc.
 
15- ¿Qué empresas se han convertido en referencia tras asumir la filosofía agile?
Destacaría por más conocidas (entre muchas otras que me dejo): Google, SAP, Spotify, Salesforce, Amazon, eBay, BBC, Atlassian, Ferrari, InfoJobs, Idealista y la industria de los videojuegos.
 
16- ¿Se puede dar marcha atrás? ¿ha habido casos?
Sí, el cambio cultural puede ser muy fuerte dependiendo de la idiosincrasia actual de la empresa. Otro factor crítico de no éxito es no contar con algún experto en la materia (experto = experiencia de varios años trabajando ágilmente e introduciendo esta filosofía de trabajo en diferentes contextos) para que guíe en la transición haciendo coaching en la “trinchera”. Hay bastantes casos de fracaso, bien por falta de ambiente colaborativo en la empresa, apertura de mente y ganas de probar y aprender, así como por el “hacérselo por su cuenta”, lo que lleva a errores “de libro” y transiciones demasiado dolorosas por no entender lo que se está haciendo, lo cual quita las ganas de volver a ponerse en 2 o 3 años. 
 
17- ¿Cree que todas las empresas se pueden permitir el equilibrio salarial?
Si se refiere a que todo el mundo en la empresa cobre más o menos lo mismo, no creo que eso tenga mucho sentido, ni siquiera en una empresa ágil :)

 

Artículos relacionados:

 

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

Variable not found

Enlaces interesantes 153

April 07, 2014 12:10 PM

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

.Net

Asp.net

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data access

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

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

Koalite

Testeando sitios web con F# y Canopy

April 07, 2014 05:06 AM

Todos los que seguís este blog sabéis que me interesa mucho buscar la mejor forma de testear aplicaciones y que considero que unos buenos tests son fundamentales para conseguir aplicaciones más sólidas y dormir más tranquilo. A lo largo de los posts he hablado mucho sobre tests unitarios, tests de aprobación e incluso he tocado por encima los tests de extremo a extremo.

En este post vamos a ver una nueva herramienta para escribir tests sobre páginas web que me ha llamado especialmente la atención: canopy.

¿Qué es canopy?

Canopy es una herramienta open source que nos permite escribir tests sobre sitios web usando un DSL desarrollada en F#. Internamente utiliza Selenium, lo que nos permite testear directamente sobre distintos navegadores reales.

La documentación de canopy, aunque escueta, es lo bastante clara como para poder empezar a escribir tests sin mucho esfuerzo y, aunque no soy un gran fan de sintaxis de F#, tengo que reconocer que el DSL está muy logrado y permite escribir tests bastante claros.

Para usarlo sólo es necesario instalarlo desde Nuget. Esto podemos hacerlo en cualquier proyecto de .NET (sí, también C#), pero merece la pena escribir los tests en F#, por lo que lo más recomendable es escribir los tests en un proyecto de consola de F#.

Testeando MegaFacts

Como toma de contacto, vamos a usar canopy para testear la aplicación de ejemplo MegaFacts que he usado tanto en el tutorial de node.js y express, como en el tutorial de compojure, concretamente, testearemos la implementación de compojure.

Lo importante es que tengáis en cuenta que, puesto que estamos testeando desde el propio interface web, nos da igual cómo esté implementado por detrás, ya que estaremos interactuando directamente con el navegador.

La página principal (y única) de MegaFacts era algo así:

Mockup de la página de Mega Facts

A la izquierda se muestra una lista de “héroes” sobre los que podemos pulsar para mostrar los “facts” asociados a cada uno y añadir nuevos facts. Es importante reseñar que la página en sí no está pensada para ser testeada, pero aun así podremos conseguir unos tests relativamente legibles.

Los tests los vamos a organizar en un módulo llamado MegaFacts en el que lo primero que haremos será incluir los módulos que necesitamos:

module MegaFacts

open canopy
open runner

A continuación, añadiremos un Page Model para independizar un poco los tests de la estructura real de la página:

let factsUrl = "http://localhost:3000"

// Enlaces a los diferentes héroes
let heroArturo = "#heroes li:nth-of-type(1) a"
let heroBruce = "#heroes li:nth-of-type(2) a"
let heroChuck = "#heroes li:nth-of-type(3) a"

// Información sobre el héroe selecciando
let currentHeroName = "#right-column h2"
let currentFacts = "#facts li"

// Controles para añadir facts
let newFactText = "#new-fact"
let addNewFact = "#add-new-fact"

En el Page Model estamos “poniendo nombres” a los diferentes elementos que componen la página, los cuales identificamos mediante selectores CSS. Aquí se nota que la página no está diseñada para ser testeada y hace falta usar algunos selectores un poco rebuscados, pero al menos podemos testearla y, gracias al Page Model, si la cambiamos la estructura de la página para adecentarla un poco, sólo necesitaremos actualizar el Page Model y nuestros tests seguirán funcionando.

Ahora que ya tenemos todo preparado, vamos a escribir nuestro primer test, que consistirá en validar que al pulsar sobre nombre de cada héroe se muestran sus facts asociados:

let browseFacts _ =

    context "Consultando los facts de cada héroe"

    url factsUrl

    displayed "#heroes"

    "Al seleccionar un héroe se muestran sus facts" &&& fun _ ->
        
        click heroChuck

        currentHeroName == "Chuck Norris"

        currentFacts *= "Chuck Norris borró la papelera de reciclaje."

        click heroArturo

        currentHeroName == "Arturo Pérez-Reverte"

        currentFacts *= "Pérez-Reverte se baja música en casa de Ramoncín."

En este código podemos ver en acción el DSL de canopy. Usando context podemos indicar qué es lo que estamos testando y con la función (infija) &&& definimos nuestros tests. Veis que tenemos acciones, como url que nos permite navegar a una página o click para interactuar con un elemento, y aserciones, como displayed para comprobar que se muestra un elemento, == para validar el texto de un elemento, o *= que valida si alguno de los elementos de la colección contiene el texto indicado.

Vamos a ver otro test en el que comprobemos que podemos añadir nuevos facts a un héroe:

let addFact _ =
    
    context "Añadiendo un nuevo fact"

    "Al añadir un nuevo fact se muestra en la lista de facts" &&& fun _ ->

        click heroChuck

        currentHeroName == "Chuck Norris"

        newFactText << "Object hereda de Chuck Norris"

        click addNewFact

        currentFacts *= "Object hereda de Chuck Norris"

La única novedad de este test con respecto al anterior es la función << para establecer el texto de un control, en este caso el textarea usado para introducir el nuevo fact.

Por conveniencia, todos los tests de este módulo los podemos agrupar en una única función que se encargue de ejecutarlos secuencialmente:

let all _ =
    browseFacts()        
    addFact()

Si tuviésemos más páginas en nuestra aplicación podríamos definir módulos para cada una de ellas, cada uno de ellos con su función all para agruparlos. Finalmente, para ejecutar los tests, en el punto de entrada de nuestra aplicación de consola tendremos algo así:

open canopy
open runner

start firefox

MegaFacts.all()

run()

Simplemente abrimos un navegador (en este caso Firefox), definimos todos los tests de los módulos que tengamos y usamos la función run para ejecutarlos.

Para ejecutarlos, necesitamos que la página tiene que estar accesible (podríamos incluso levantar el servidor donde está alojada en el propio test) y ejecutar la aplicación de consola que acabamos de crear. Veréis como se abre un navegador y se empieza a interactuar con él para completar las acciones que hemos definido en los tests.

El resultado será algo así:

canopy-output

Por si queréis verlo más detenidamente, aquí os dejo el código completo del ejemplo y recordad que para ejecutarlo hace falta lanzar el servidor web de MegaFacts.

Conclusiones

Canopy es un proyecto muy interesante para realizar tests de extremo a extremo. Su sintaxis resulta clara, sencilla y natural. Como habéis visto en el ejemplo, es posible testear sin mucha dificulta páginas que, en un principio no estaban diseñadas para ser testeadas (aunque es verdad que pensar un poco en los tests a la hora de diseñar las págians simplifica luego el mantenimiento de los tests).

Una de las cosas que más me gusta de Canopy es que está desarrollado en F#. No es tanto por F# en si (todavía no tengo muy claro si me gusta o no el lenguaje), pero el hecho de ver que .NET es cada vez más políglota me hace tener más esperanzas en el futuro de la plataforma.

No hay posts relacionados.

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

Arragonán

Semana 304

April 07, 2014 02:16 AM

Semana movidita en cuanto a posibles nuevas colaboraciones a priori puntuales, tuve que invertir tiempo en un par de reuniones y en algún que otro mail de cara a preparar propuestas. Llevaba tiempo sin hacerlo y precisamente me rondaba en la cabeza el buscar algún proyecto o producto “no muy grande” en el que colaborar a partir de mayo, ni que me hubieran olido.

El martes me pasé por las Geek Talks tras un par de meses sin hacerlo, estuvimos hablando sobre las herramientas de gestión/organización que utilizamos. El miércoles me tuve que cruzar la ciudad tras jugar a fútbol sala para unirme a cenar con Jaume, Bea y una buena representación de los habituales de la comunidad local. El jueves me fui de concierto guitarrero, que me moló bastante: No Truck Truckers y Total Heels. El viernes publicaron un post mío, que terminé por fin esta misma semana, en el blog de CartoDB: Mapping food banks in Spain with CartoDB.

Sobre los proyectos en los que ando, mucha variedad:

  • En mhop estuve implementando en el frontend el poder buscar productos por etiqueta y en poder incrustar también vídeos de vimeo.
  • Para minchador estuve haciendo cambios en la landing, hay que darle vueltas aún al copywriting y hacer un rediseño en condiciones.
  • Arreglé un scraper de ShuttleCloud que se había roto.
  • Retomé cosas pendientes de proyectoSinNombre, básicamente algunos detalles relacionados con Refinery CMS.

Buena semana.

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

Variable not found

Ya está aquí: SignalR Programming in Microsoft ASPNET

April 06, 2014 05:46 PM

Por fin llegó el momento que estaba esperando desde hace tiempo: tras muchos meses de trabajo y preparativos, ya está disponible mi libro “SignalR Programming in Microsoft ASP.NET” :-) ¡¡Hurra!!

Publicado directamente en inglés por Microsoft Press, ha sido desde su origen un proyecto mucho más ambicioso que mi anterior incursión en el mundo literario, que seguro recordaréis, principalmente porque se trata de un libro con una difusión, repercusión y alcance mucho mayor que el anterior, y al que hemos tenido que dedicar muchísimo esfuerzo, tiempo e ilusión todos los implicados (¡que no son pocos!) para lograr un resultado que esperamos esté a la altura de las circunstancias.

El libro tiene más de 250 páginas a través de las cuales se describen tanto temas básicos como aspectos avanzados de la programación con la versión 2 de SignalR. El índice resumido es el siguiente:
  1. Internet, asynchrony, multiuser… wow!
  2. HTTP: you are the client, and you are the boss
  3. Introducing SignalR
    Estos tres primeros capítulos introducen las aplicaciones asíncronas en tiempo real y los conceptos básicos que necesitamos conocer para trabajar con SignalR: qué es, qué nos aporta, y qué mecanismos hacen que todo esto funcione.
  4. Persistent connections En el cuarto capítulo comenzamos ya a trabajar con conexiones persistentes, tanto en el lado servidor como en el cliente, describiendo en detalle las APIs que ofrece SignalR para comunicar ambos extremos.
  5. Hubs Aquí se describe profundidad el uso de hubs, tanto en el lado cliente como en el servidor, describiendo detalladamente las herramientas disponibles para enviar y recibir datos desde ambas partes, mantener el estado, implementar trazas, y muchos otros aspectos de interés al programar hubs de SignalR.
  6. Persistent connections and hubs from other threads
    En este capítulo se describen las herramientas proporcionadas por SignalR para utilizar hubs y conexiones persistentes desde hilos de ejecución externos a dicho framework.
  7. Real-time multiplatform applications
    Este capítulo está dedicado a la publicación y consumo de servicios desde servidores y clientes no web. Se describen técnicas de self-hosting en distintos entornos, y cómo implementar clientes en plataformas como Windows 8 o Windows Phone.
  8. Deploying and scaling SignalR
    En este capítulo se muestran los fundamentos de la escalabilidad de SignalR y distintas estrategias para enfrentarse a los problemas asociados al escalado de servicios. Estudiamos los backplanes incluidos de serie en el producto e incluso cómo crear backplanes propios, y finalmente, apuntamos técnicas para mejorar el rendimiento y medir el rendimiento de nuestros sistemas.
  9. Advanced topics
    Aquí tratamos temas como autorización en Hubs, extensión de SignalR, inyección de dependencias, pruebas unitarias, intercepción de mensajes e integración con otros frameworks en cliente y servidor.
En casi todos los capítulos hay ejemplos completos y multitud de porciones de código para ver de forma práctica los conceptos mostrados. Si tenéis interés, podéis ver un índice detallado en la página del libro en O’Reilly, el distribuidor oficial de libros de Microsoft Press, e incluso hay previews para hacerse una idea de lo que encontraréis dentro.

FAQ

¿Dónde puedo comprarlo? Pues básicamente donde quieras, aunque Amazon o InformIT  pueden ser buenos puntos de partida.
¿En qué formatos está disponible? El libro se comercializa en formato digital y en papel. En el primer caso, he visto que es posible obtenerlo en ePub, Mobi y PDF.
¿Va a salir el libro en español? Pues sinceramente, no lo sé. Desde luego, a corto plazo sólo estará en inglés y a día de hoy no existen planes para publicarlo en castellano, aunque no sé si esto cambiará en el futuro.

Agradecimientos

No me gustaría acabar el post sin antes agradecer al equipo de CampusMVP, con José Manuel Alarcón al frente, la oportunidad que me han brindado para poder participar en este proyecto y la fantástica gestión y ejecución del mismo. También al amigo Javier Suárez Ruíz por su imprescindible colaboración en algunos ejemplos.

Y por parte de Microsoft Press, entre muchos otros, agradecimiento infinito a Devon Musgrave por haber apostado por este proyecto desde el principio, a nuestra editora Carol Dillingham por su gran trabajo para llevarlo a cabo y a Todd Meister por sus minuciosas revisiones técnicas. Incluso hemos tenido la inmensa fortuna de contar con revisiones y comentarios de los padres de SignalR, Damian Edwards y David Fowler, a los que también envío mi agradecimiento. Todo un lujazo, vaya :)

Por mi parte, trabajar en este libro ha sido un honor y una experiencia impresionante, dura pero muy enriquecedora. Ahora espero que os sea de utilidad, que al fin y al cabo es lo que hace que el esfuerzo valga la pena :-)

Publicado en Variable not found.

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

.NET o no .NET, esa es la cuestión

Vuelta al redil y artículos publicados en otros lados

April 05, 2014 10:04 AM

Muchos de vosotros habréis supuesto que he abandonado el blog y he dejado de escribir de forma definitiva. Si bien en apariencia así, es la realidad es otra, ya que lo que no he puesto aquí lo he hecho en los blogs de la MDSN. 

Eso no quiere decir que haya abandonado esto, sino que simplemente primero publiqué allí y me olvidé de hacerlo aquí, o más bien de poner aquí una entrada que redirigiera allí.

Esta entrada soluciona eso mismo, y recoge todo lo que he publicado hasta la fecha allí y en otro blog que recientemente he abierto y que en próximos días también copiaré dichas entradas aquí.

Respecto a ese otro blog, no pretende sustituirlo, sino más bien complementarlo ya que la idea es publicar la misma cosa en paralelo en ambos, para tener algo más de visibilidad.

Bueno, comentado esto, os pongo la lista de entradas y sus enlaces.

Windows Phone, Windows 8: Portable Library y subida a la tienda: desde cero

Esta es, desde luego, la mejor entrada de todas las que he publicado allí. Como reza el título, en ella explico la creación de una aplicación sencilla tanto para Windows 8 como para Windows Phone usando la portable library y cómo subirla a las dos tiendas. Pese al tiempo transcurrido, todo sigue siendo relevante ya que pese a la unificación de las dos tiendas, el proceso de subida continua siendo igual al descrito.

Este artículo tiene su historia, ya que en origen iba a ser publicado en la revista DotNetManía pero a causa del cierre de la misma lo reutilicé allí.

Workaround para Windows Phone ListBox y LongListSelector y ScrollIntoView en elementos de diferente tamaño

 Este es un truco para hacer que el ListBox de Windows Phone 7.x se comporte como debe cuando se añaden valores de diferente tamaño y se llama a ScrollIntoView() para que se seleccione uno de ellos. Es decir, tanto Windows Phone 7 como 8 tienen un bug que ninguna actualización (hasta donde yo sé) ha resuelto: a veces no se muestra el elemento completo. Este truco mejora, aunque no solventa del todo, el problema.

Windows Phone: Subiendo un fichero a un servidor WEB con credenciales básicas sin tener que reintentar

El componente WebRequest de Windows Phone primero intenta la operación sin credenciales y cuando falla, lo hace con ellas si se han indicado. Pero eso le sienta bastante mal a algunos servidores Web, así que con este truco hacemos que el componente lo haga con ellas desde el primer momento.

El interior de Windows

Esta es una de esas entradas típicas mías que resumen o cuenta cosas que posiblemente sólo interesen a mi y a algún que otro trasnochado. Aquí hablo de Windows 8 y cómo es su arquitectura real y no la que nos muestran esos gráficos tan bonitos que hace Microsoft.

Llamando al API de WinRT desde aplicaciones de escritorio normales en C#

En este artículo describo cómo llamar al API de las aplicaciones de la tienda de Windows (las aplicaciones antes conocidas como Metro y ahora Modern UI, vamos, la de los cuadraditos de Windows 8) desde una aplicación de escritorio. La cosa queda más clara si antes de leer esta entrada, se lee la anterior de la lista.

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

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

La importancia de la comunicación

April 04, 2014 02:58 PM

Excelente artículo del PMI, lo importante que es la comunicación en las empresas y por ende en los proyectos, en los años que tengo como profesional me doy cuenta que aun en las organizaciones hay problemas básicos de comunicación y esto provoca a veces un efecto domino, agregaría que este problema de comunicación afecta varios aspectos del ser humano.

Artículo del PMI

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

Blog Bitix

Usar Grunt para ejecutar teses unitarios de código Javascript

April 04, 2014 02:43 PM

Grunt

En la serie de artículos que escribí sobre javascript hice un ejemplo más o menos complejo y parecido a lo que podría ser una aplicación real usando muchas de las herramientas que ahora se consideran una buena opción para desarrollar aplicaciones javascript como RequireJS, Backbone, Marionette, Jasmine y Sinon. En el ejemplo de la lista de tareas con estas herramientas hice unas cuantas pruebas unitarias para mostrar en un ejemplo como son y la forma de usar Jasmine.

Sin embargo, para ejecutar las pruebas unitarias se necesitaba un navegador y hacerlo de forma manual cuando quisiéramos comprobar el estado de las pruebas. Lo ideal tal y como se comenta en el libro The Pragmatic Programmer es que las pruebas unitarias se ejecuten de forma automatizada con la herramienta de construcción que usemos, esto evitará que se nos olvide ejecutarlas en cada cambio y así descubriremos los errores pronto, también podremos hacer que se ejecuten en un entorno de integración continua como podría ser Jenkins. En esta entrada mostraré como ejecutar esas pruebas unitarias de javascript con una tarea de la herramienta Gradle y usando una herramienta similar a Gradle pero para Javascript llamada Grunt.

Primeramente necesitaremos instalar node.js y el paquete de javascript grunt-cli con de forma global en el sistema:

<noscript><pre><code># pacman -S nodejs # npm install -g grunt-cli</code></pre></noscript>

En caso de que tengamos pruebas unitarias con Jasmine como es el caso de este ejemplo deberemos instalar los siguientes paquetes en el directorio raíz del proyecto:

<noscript><pre><code>$ npm install grunt-contrib-jasmine $ npm install grunt-template-jasmine-requirejs</code></pre></noscript>

La siguiente linea como se explica en la documentación del paquete grunt-template-jasmine-requirejs puede ser necesaria si en algún momento obtenemos el siguiente error:

<noscript><pre><code>$ npm install grunt-contrib-jasmine@0.5.3 --save-dev</code></pre></noscript>

<noscript><pre><code>npm ERR! peerinvalid The package grunt-contrib-jasmine does not satisfy its siblings' peerDependencies requirements! npm ERR! peerinvalid Peer grunt-template-jasmine-requirejs@0.1.10 wants grunt-contrib-jasmine@~0.5.3</code></pre></noscript>

<noscript><pre><code>$ npm install</code></pre></noscript>

Si usamos Mocha como librería de pruebas unitarias probablemente disponemos de varios paquetes que podemos instalar de forma similar. Una vez instaladas estas herramientas debemos crear dos archivos necesarios para Grunt, que son package.json y grunt.js. El primero contiene la definición del paquete js para Grunt, quizá lo más destacable es que el nombre del paquete debe estar en minúsculas sino obtendremos un error parecido a «Error: Invalid name: “MarionetteREST” npm ERR! at ensureValidName». El archivo grunt.js es la descripción de las tareas de grunt que contiene un poco de configuración donde indicamos las especificaciones que contienen las pruebas unitarias, las dependencias necesarias para ejecutar las pruebas y las tareas que se definen. Con todo esto ya podemos ejecutar las pruebas con:

<noscript><pre><code>$ grunt --gruntfile grunt.js jasmine:requirejs $ ./gradlew jasmine</code></pre></noscript>

Sin embargo, puede que deseemos ejecutarlas desde la herramienta de construcción que usemos, en mi caso con Gradle. Para añadir el soporte a Gradle de ejecutar las pruebas unitarias a su vez con Grunt debemos añadir la siguiente configuración a nuestro archivo build.gradle:

<noscript><pre><code>task jasmine(type: GruntTask) { gruntArgs = &quot;jasmine:requirejs&quot; } ... class GruntTask extends Exec { private String gruntExecutable = Os.isFamily(Os.FAMILY_WINDOWS) ? &quot;grunt.cmd&quot; : &quot;grunt&quot; private String switches = &quot;--gruntfile grunt.js&quot; String gruntArgs = &quot;&quot; public GruntTask() { super() this.setExecutable(gruntExecutable) } public void setGruntArgs(String gruntArgs) { this.args = &quot;$switches $gruntArgs&quot;.trim().split(&quot; &quot;) as List } }</code></pre></noscript>

Veremos como salida el siguiente resultado en la terminal.

Al hacer esta entrada de forma que las pruebas se ejecuten con Grunt he movido las plantillas de Mustache de lugar, antes estaban embebidas en el html en el ejemplo Backbone y las he movido a dentro del javascript de la aplicación de la lista de tareas. Esto hace que para pasar las pruebas no tengamos una dependencia sobre un archivo html externo en el que buscar las plantillas, también así el javascript es más autónomo y está incluido en él todo lo que necesita.

Aún tengo otra entrada preparada sobre javascript que es el mismo ejemplo de la lista de tareas pero en vez de usando las vistas de Backbone o Marionette usando React. El código fuente completo de este ejemplo sobre pruebas unitarias y Marionette está en mi regpostorio de GitHub.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Introducción y ejemplo de Backbone.js
Ejemplo de pruebas unitarias en javascript con Jasmine y Sinon
Ejemplo lista de tareas con Marionette
Ejemplo lista de tareas con Backbone y React

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

Variable not found

Routing en MVC y Web API (II): Restricciones

April 01, 2014 12:02 PM

ASP.NET MVCEn la entrega anterior de la serie hicimos una pequeña introducción al attribute routing introducido en ASP.NET MVC 5 y Web API 2, explicando cómo podíamos activar esta característica y las reglas básicas para la definición de rutas sobre acciones y controladores de ambos frameworks.

En esta ocasión vamos a ver cómo podemos incluir restricciones o constraints en dichas rutas, algo que podíamos conseguir también utilizando el rutado por convenciones pero de forma más farragosa y que ahora con attribute routing y otras mejoras incluidas en las últimas versiones de MVC y Web API se convierte en trivial.

Y ya de paso, repasaremos lo que son las restricciones de ruta y cómo podíamos usarlas en versiones anteriores de MVC y Web API, para que aquellos que aún no hayáis tenido oportunidad de trabajar con ellas.

1. ¿Qué son las restricciones de ruta?

Como sabemos, cuando una petición llega a nuestro sitio web, el sistema de routing analiza la URL entrante y la contrasta con el contenido de la tabla de rutas. Cuando en dicha tabla encuentra una regla cuyo patrón de ruta coincide con el path de la petición entrante, se utilizan sus datos para determinar a qué acción se delega el proceso de la petición, así como los parámetros a suministrarle.

Las restricciones de ruta, o route constraints, permiten añadir lógica adicional al proceso de matching entre la petición entrante y las reglas registradas en la tabla de rutas, de forma que no sólo se atienda a la coincidencia ambas URLs sino también a cualquier otro tipo de criterio. En la práctica, los constraints son básicamente funciones que retornan cierto o falso, por lo que podemos introducir en ellos cualquier lógica de comprobación.

Así, al entrar una petición, y una vez el sistema de routing ha determinado qué regla de la tabla de rutas encaja con la URL de dicha petición, se ejecutarán sucesivamente todos los constraints definidos en la misma. En cuanto uno de ellos retorne false, se descartará la ruta actual y se seguirá buscando en la tabla de rutas una entrada que encaje con la petición entrante; si todos retornan true, la ruta actual será la elegida para gestionar la petición.

2. Route constraints en versiones anteriores de MVC y Web API

En versiones de ASP.NET MVC anteriores a la 5 y Web API 2, las restricciones se introducían en las entradas de la tabla de rutas, cuanto menos, de forma algo “extraña”. Era necesario asignar al parámetro constraints de los métodos MapRoute() o MapHttpRoute() –de MVC y Web API, respectivamente-, un objeto anónimo en el que se definían a modo de diccionario clave/valor las restricciones a emplear por cada parámetro. Observad el siguiente ejemplo:
routes.MapRoute(
name: "ProductById",
url: "product/{id}",
defaults: new {controller = "product", action = "details"},
constraints: new { id = new MustBeInteger() }
);
En este código indicábamos al sistema de routing que teníamos una restricción sobre el parámetro de ruta id, cuya lógica estaba implementada en la clase MustBeInteger . La verdad es que es una forma realmente oscura y poco intuitiva para expresar algo que probablemente podría haberse solucionado de forma sencilla mediante lambdas y predicados, pero bueno…

Pero aún peor, sin duda, es que ni MVC ni Web API venían acompañados de restricciones de serie (exceptuando una, basada en expresiones regulares), por lo que todas ellas debíamos desarrollarlas nosotros, y esto ha provocado que muy poca gente se anime a usar constraints en las rutas de sus aplicaciones, aunque resulte bastante sencillo hacerlo.

Las restricciones son simplemente clases personalizadas que implementan el interfaz System.Web.Routing.IRouteConstraint, y en cuyo único método Match() se introduce la lógica de comprobación. Siguiendo con el ejemplo anterior, la siguiente restricción permitiría asegurar que el valor de un parámetro es de tipo int:
public class MustBeInteger : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
                      RouteDirection routeDirection)
{
int value;
return int.TryParse(values[parameterName].ToString(), out value);
}
}
Observad que este método recibe parámetros a través de los cuales puede acceder al contexto completo de la petición, la ruta actual, al nombre del parámetro evaluado (“id” en el caso anterior), la colección de parámetros de ruta, y la dirección de la conversión, que indica si la restricción se está evaluando durante el proceso de matching en una petición entrante, o durante la generación de una URL mediante los helpers que todos conocemos.

Y este era el mecanismo que teníamos hasta ahora para crear restricciones en las rutas de nuestras aplicaciones MVC y Web API. Aunque no era muy complicado, sí era bastante farragoso e incómodo, así que veamos cómo mejorar esto.

3. Restricciones incluidas “de serie” en MVC 5 y Web API 2

Independientemente de las novedades relativas a attribute routing que vienen ya de serie con ASP.NET MVC 5 y Web API 2, las últimas versiones de estos frameworks han venido acompañadas de un buen número de constraints predefinidas que permiten solucionar de forma muy rápida los escenarios más comunes.

Estas clases vienen definidas en System.Web.Mvc.Routing.Constraints en ASP.NET MVC y en System.Web.Http.Routing.Constraints en el caso de Web API y, como ya sabemos, todas ellas son clases que implementan el interfaz IRouteConstraint. Las disponibles son:
  • AlphaRouteConstraints, para permitir valores alfabéticos.
  • BoolRouteContraint, permite valores booleanos.
  • CompoundRouteConstraint, útil cuando queremos aplicar varias restricciones al mismo parámetro, pues actúa como contenedor de otras constraints que serán aplicadas de forma conjunta al mismo.
  • DateTimeRouteConstraint, para permitir valores de tipo fecha.
  • DecimalRouteConstraint, permitir valores decimales.
  • FloatRouteConstraint, permitir valores de tipo float.
  • GuidRouteConstraint, permitir exclusivamente valores Guid.
  • IntRouteConstraint, permitir valores enteros.
  • LengthRouteConstraint, para permitir parámetros con longitud comprendida entre los valores mínimo y máximo especificados, o de un tamaño exacto.
  • LongRouteConstraint, para permitir valores de tipo long .
  • MaxRouteConstraint, permite valores numéricos hasta el máximo indicado.
  • MaxLengthRouteConstraint, para permitir valores cuya longitud no supere la indicada.
  • MinLengthRouteConstraint, ídem, con valores de una longitud mínima.
  • MinRouteConstraint, permite valores numéricos mayores o iguales al indicado.
  • OptionalRouteConstraint, permite indicar una restricción que se superará si el valor suministrado coincide con el valor por defecto UrlParameter.Optional.
  • RangeRouteConstraint, permite valores numéricos que se encuentren en un rango determinado.
  • RegexRouteConstraint, los valores deben cumplir una expresión regular.
Así, a partir de este momento podríamos utilizar cualquiera de estas restricciones directamente en nuestro código para asegurar que a las acciones llegan los parámetros que nos interesan. En el ejemplo anterior quedaría algo así:
using System.Web.Mvc.Routing.Constraints;
[...]
routes.MapRoute(
name: "ProductById",
url: "product/{id}",
defaults: new {controller = "product", action = "details"},
constraints: new { id = new IntRouteConstraint() }
);
De nuevo, recordad que a la hora de aplicar estas restricciones debéis tener en cuenta el espacio de nombres usado, pues si incluis restricciones Web API en una ruta MVC no funcionarán, ni viceversa.

4. Especificación de restricciones en attribute routing

Attribute routing incluye su propia sintaxis para incluir restricciones en el interior de las definiciones de ruta que encontramos junto a las acciones o controladores. Lo vemos rápidamente con un ejemplo:
[Route("product/edit/{id:int}"] 
public ActionResult GetProductById(int id) { ... }
Pues sí, basta con incluir la restricción tras el nombre del parámetro, separándolo por los dos puntos “:”. Sencillo, ¿eh?

Los tipos de restricción son más simples y rápidos de escribir que las clases donde se implementa, que son las que hemos citado algo más arriba. En este caso debemos usar las siguientes denominaciones:

Constraint Descripción Ejemplo de uso
alpha Secuencia de caracteres alfabéticos latinos (a-z, A-Z) {x:alpha}
bool Valor booleanos (true o false) {x:bool}
datetime Valor DateTime (en formato aaaa-mm-dd) {x:datetime}
decimal Valor decimal (usando el punto como separador decimal) {x:decimal}
double Valor en punto flotante de 64-bits {x:double}
float Valor en punto flotante de 64-bits {x:float}
guid GUID {x:guid}
int Valor entero de 32 bits {x:int}
length Cadena de caracteres con una longitud específica, o en un rango {x:length(6)}

{x:length(1,20)}
long Valor entero de 64 bits {x:long}
max Entero, como máximo el valor indicado {x:max(10)}
maxlength Cadena de caracteres con un tamaño máximo {x:maxlength(10)}
min Entero, como mínimo el valor indicado {x:min(10)}
minlength Cadena de caracteres con un tamaño mínimo {x:minlength(10)}
range Entero que se encuentre en un rango de valores {x:range(10,50)}
regex Valor que cumpla la expresión regular indicada {x:regex(^\d{3}-\d{3}-\d{4}$)}

Si un parámetro está sujeto a más de una restricción, podemos especificarlas de forma consecutiva, siempre usando el mismo separador:
[Route("user/confirm/{pin:alpha:length(4}"] // 4 alphabet chars (a-z)
public ActionResult Confirm(string pin)
{
...
}
Por otra parte, si el parámetro tuviera un valor por defecto, se indicará tras las constraints:
[Route("~/test/{data:alpha:length(3)=car}")] 
public ActionResult Test(string data)
{
...
}
Y de momento vamos a dejarlo aquí, que creo que ya me estoy alargando demasiado. En la próxima entrega, la última  de la serie, veremos la extensibilidad de attribute routing, que permite crear nuevos tipos de restricciones e integrarlas en su sintaxis de forma muy limpia y elegante.

Publicado en Variable not found.

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

Picando Código

JSON más rico

March 31, 2014 02:30 PM

Hice una gema: ricojson – herramienta de línea de comando que muestra archivos JSON de forma linda:

fernando@endor ~
$ echo '{"name": "Captain America", "alterego": "Steven Rogers", "weapon": "Vibranium Shield"}' | ricojson
{
  "name": "Captain America",
  "alterego": "Steven Rogers",
  "weapon": "Vibranium Shield"
}
JSON

JSON

El contenido JSON puede provenir de un archivo, o directamente desde la entrada estándard. Así que puede ser el resultado de un pipe de cat o curl. Como salida vamos a obtener un JSON bien indentado. Usa el método pretty_generate de la biblioteca JSON de Ruby.

Si le pasamos la opción -o, va a abrir el JSON generado en la aplicación por defecto que usemos en nuestro sistema.

Instalación

$ gem install ricojson

Uso

Abriendo un archivo:

$ ricojson archivo.json
$ cat archivo.json | ricojson

Obteniendo la respuesta de una API:

$ curl https://mnav.heroku.com/artworks/62 | ricojson

Abriendo el JSON generado en la aplicación por defecto:

ricojson -o archivo.json

Gracias Daniel por el Pair Programming con esto, mejoramos mucho el código. Imagen de Jason por Robert Ball (Licencia Creative Commons).

Código fuente en GitHub: https://github.com/picandocodigo/ricojson

» 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