Weblogs Código

Variable not found

Tuplas en C# 7

junio 23, 2017 12:18

C#Y continuamos escarbando en las nuevas características disponibles en C#7, incluido de serie en Visual Studio 2017. Hasta el momento hemos profundizado en las siguientes novedades:
En esta ocasión nos centraremos en la vuelta de tuerca que se ha dado a las tuplas a nivel de lenguaje, reforzándolas como first-class citizens para los desarrolladores C#.

Pero empecemos desde el principio…

Como recordaréis, la clase Tuple está con nosotros desde .NET 4 y podíamos utilizarla como un "cajón" en el que almacenar una serie de valores relacionados entre sí sin necesidad de crear una clase o estructura específica para cada ocasión. Gracias a los tipos incluidos en el framework Tuple<T>, Tuple<T1, T2>Tuple<T1, T2, T3, T4, T5, T6, T7> , podemos crear tuplas de hasta siete elementos con suma facilidad, por ejemplo:
// Tupla con dos elementos enteros:
var coords = new Tuple<int,int>(100, 200);
// Creación usando factoría con inferencia de tipos:
var coords = Tuple.Create(100, 200);
// Con tres elementos:
var coords3d = Tuple.Create(100, 200, 300);
// Con cuatro elementos de distinto tipo:
var person = Tuple.Create("John", new DateTime(1997, 2, 3), 1.68m, true);
Cada tupla tenía propiedades como Item1 para acceder al primer elemento, Item2 para el segundo, y así sucesivamente hasta llegar al número de elementos de la misma. Esto hacía que el acceso a estas propiedades fuera sencillo, aunque a nivel de legibilidad de código dejara bastante que desear:
Console.WriteLine(coords.Item2); // 200
Console.WriteLine(coords3d.Item3); // 300
Console.WriteLine(person.Item4); // True
Sin embargo, es cierto que las tuplas tienen sentido en algunos escenarios, como cuando queremos que un método retorne más de un valor. Muchas veces podemos usar parámetros out (que, como sabéis, también han sido mejorados en C# 7), pero por ejemplo no están disponibles en métodos asíncronos. También son útiles para evitar la creación de clases de transferencia de datos sólo para determinados métodos, o incluso para evitar el uso de tipos dinámicos, objetos anónimos, diccionarios u otras fórmulas de almacenamiento de datos.

Introducing ValueTuple

Pues bien, lo que han hecho en C#7 es un reboot de la idea. Han creado un tipo nuevo llamado ValueTuple para representar las tuplas, y han añadido al lenguaje azúcar sintáctico para gestionarlo de forma más cómoda.

A diferencia del tipo Tuple clásico el nuevo ValueTuple es un struct, por lo que es un tipo valor, más eficiente en términos de uso de memoria (se almacenan en la pila, nada de allocations, presión en recolección de basura y esas hierbas), y hereda características como las operaciones de igualdad o la obtención del hash code. En este issue de Github podéis profundizar en los motivos que llevaron a tomar esta decisión.

Salvo esas pequeñas diferencias, su uso a priori es muy parecido a Tuple:
var coords3d = ValueTuple.Create(100, 200, 300);
Console.WriteLine(coords3d.Item1); // 100
Ah, y ojo, que dado que el tipo ValueTuple no ha sido añadido al framework hasta la reciente versión 4.7, para usar las tuplas de C#7 en vuestros proyectos .NET 4.6 y anteriores debéis instalar el paquete Nuget "System.ValueTuple".

Uso de tuplas desde C# 7

Bien, veamos a nivel de código cómo podemos utilizar este nuevo tipo de datos aprovechando su integración con C#7. En primer lugar, observad lo sencillo que resulta ahora crear una tupla con la nueva sintaxis; simplemente debemos especificar los elementos entre paréntesis, separados por una coma:
var person = ("John", 34);
Console.WriteLine(person.Item1);  // John
Console.WriteLine(person.Item2);  // 34
El código anterior crearía un ValueTuple<string, int>, con los valores ya establecidos. ¿Fácil, eh? Pero aunque hemos mejorado la forma de crearla, aún el acceso a los elementos de la tupla lo hacemos utilizando sus miembros Item1 e Item2, algo totalmente inapropiado para los tiempos que corren (¿Qué es Item1? ¿El nombre de la persona o el de su perro? ¿Y 34? ¿Su talla de zapatos?).

Por esta razón, C# nos permite endulzar un poco esta situación facilitando la asignación de nombres a las propiedades. Fijaos ahora cómo mejora la cosa:
var person = (name: "John", age: 34);
Console.WriteLine(person.name); // John
Console.WriteLine(person.age);  // 34
Console.WriteLine(
person.GetType() // System.ValueTuple`2[System.String,System.Int32]
);
Como podéis observar, se trata de una sintaxis muy compacta, y en cierto sentido bastante parecida a los tipos anónimos. Sin embargo, fijaos que sigue siendo una tupla, sólo que el compilador tiene la cortesía de permitirnos el acceso a sus miembros vía propiedades nombradas en lugar de Item1 o Item2. De hecho, si compilamos el código anterior y descompilamos el código resultante, encontraríamos algo como esto:
ValueTuple<string, int> valueTuple = new ValueTuple<string, int>("John", 34);
Console.WriteLine(valueTuple.Item1);
Console.WriteLine(valueTuple.Item2);
Este tipo de tuplas son ciudadanos de primer orden en C#, por lo que pueden pasarse como argumentos y retornarse desde métodos con total normalidad. Por ejemplo, en el siguiente código vemos cómo podríamos declarar parámetros de un tipo tupla:
var person = (name: "John", age: 34);
Show(person);
...
static void Show((string name, int age) person)
{
Console.WriteLine($"Name: {person.name}");
Console.WriteLine($"Age: {person.age}");
}
A continuación vemos también cómo consumir un método que retorna una tupla con miembros nombrados:
var person = Create();
Console.WriteLine(person.age); // 23
...

static (string name, int age) Create()
{
return (name: "Test", age: 23);
}

Deconstrucción de tuplas

Otra forma curiosa de consumir estos tipos es mediante la deconstrucción. Aunque es un tema que da para otro post, la deconstrucción consiste en “despiezar” un objeto o estructura y crear variables locales con las propiedades o miembros que nos interesen. Por ejemplo, el siguiente código muestra cómo deconstruir una tupla para obtener los valores como variables independientes:
(var name, var age, var height) = Create();
//O bien, más conciso: var (name, age, height) = Create();
Console.WriteLine($"{name} is {age} years old");
...

static (string name, int age, decimal height) Create()
{
return (name: "John", age: 23, height: 1.68m);
}
También podríamos haber especificado los tipos concretos para cada variable al hacer la deconstrucción, pero la inferencia hace posible el uso de “var”, por lo que es más cómodo a la hora de codificar.

Esto de la deconstrucción tiene más chicha porque se trata de un mecanismo "configurable", así que probablemente más adelante le dediquemos un post en exclusiva. Pero mientras tanto, podéis echar un vistazo aquí.

En conclusión…

En resumen, estamos ante una interesante característica de C# 7 que bien utilizada puede ayudarnos a hacer nuestro código más limpio y expresivo al facilitar soporte de primer nivel para tuplas. Podemos crear tuplas con una sintaxis muy sencilla, dar nombres a sus elementos, pasarlas como argumentos o retornarlas desde métodos o funciones, dispondremos de comprobaciones en tiempo de compilación, intellisense… en definitiva, todo lo que podríamos esperar de un ciudadano de primera clase en el lenguaje. Además, su implementación interna deja a un lado la antigua clase Tuple y se apoya en la nueva estructura ValueTuple, lo que trae consigo mejoras .

Pero ojo, que como casi siempre ocurre, no se trata de una bala de plata. Personalmente, se me antoja raro el hecho de que puedan desarrollarse aplicaciones completas donde el paso de información entre capas o componentes se base exclusivamente en tuplas, sin necesidad de crear clases o estructuras específicas para cada caso.

De hecho, los diseñadores de C#7 lo han hecho tan sencillo que será difícil esquivar la pereza de crear clases en escenarios que fácilmente podamos solucionar con una tupla. Como siempre, es una característica que debe usarse con sentido común y no a destajo con el simple argumento de que es más rápido de escribir, sino tener en cuenta otros aspectos como la legibilidad del código o las posibilidades de reutilización a la hora de optar por este enfoque. Sin duda, es mucho más claro y conveniente que un método GetInvoice() retorne un objeto Invoice a que retorne una tupla de N elementos, uno por cada propiedad de la factura.

Habrá que ver, ya aplicado en la práctica, cómo vamos utilizando estos nuevos superpoderes que nos han sido concedidos ;)

Pero eso sí, son mecanismos útiles, y sin duda recomendables, cuando nos interese que un método o función retorne varios valores sin usar parámetros out, para agrupar valores con propiedades de igualdad (por ejemplo, para crear claves compuestas en diccionarios o almacenar varios valores en el interior de colecciones o listas), o cuando estemos ante un escenario donde la optimización milimétrica del rendimiento sea imprescindible.

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 287

junio 22, 2017 07:03

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

.NET/.NET Core

ASP.NET/ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Gráfica que relaciona salarios con años de experiencia, según uso de tabs/espaciosY para terminar, un descubrimiento que seguro os interesa. Resulta que Stack Overflow ha publicado los resultados de su encuesta anual Stack Overflow 2017 Developer Survey, y jugando un poco con los datos han descubierto una curiosa relación entre el salario de los desarrolladores y el uso de tab/espacios para la indentación del código.

La conclusión es que los desarrolladores que usan exclusivamente espacios ingresan hasta un 8% más que los que utilizan tabuladores o ambas posibilidades indistintamente. Podéis leer más sobre ello en el post de David Robinson “Developers Who Use Spaces Make More Money Than Those Who Use Tabs”.

Visto esto, ¿todavía no usáis espacios? ¿a qué estáis esperando? ;D

Publicado en Variable not found

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

Picando Código

10 años del blog Picando Código

junio 21, 2017 09:10

Hoy se cumplen 10 años del primer post de este blog. El 21 de junio de 2007 en una de esas primeras noches programando con amigos hasta el amanecer surgió la idea de hacer un blog sobre programación, software libre y demás. Es increíble pensar que el sitio me ha acompañado por una década entera.

10 años de Picando Código

Obviamente mucho ha cambiado desde entonces en lo que respecta a tecnología y programación, e internet ya no es ni cerca lo que era en 2007. En principio los blogs han decaído en popularidad, y los contenidos e interacciones entre personas se centralizan ahora en los servidores de grandes corporaciones como lo son Facebook, Google, Twitter y demás

A la lucha del software libre, la idea de que los usuarios deberían ser dueños de sus dispositivos y el software que ejecutan, se le suma la lucha por la privacidad. Un derecho humano que parece perdido hoy en día, donde el software libre es pilar: no podemos saber a ciencia cierta que un dispositivo respeta nuestra privacidad si no es software libre. ¿Nos ganaron los supervillanos? El fundador de Pirate Bay dice que sí, Assange también.

En la programación, nacen nuevos paradigmas todo el tiempo, el desarrollo de software viene intentando transformarse en algo más humano en algunos lugares, mientras que siguen habiendo empresas que tratan a sus programadores como simples incorporaciones al engranaje universal del capitalismo.

Comparándolo con novelas de ciencia ficción, parece que nuestro presente se transformó en un futuro distópico. Estados que explotan la tecnología para espiar a sus ciudadanos a lo 1984. Corporaciones y gobiernos que condicionan la manera de pensar y los gustos de las personas para acatar y adaptarse a las normas de un mundo feliz. Diría que la introducción ya está escrita, y vamos por el segundo acto donde empiezan a aparecer pequeños focos de resistencia de donde surgen los protagonistas que en el desenlace nos rescatan de las garras de los malvados. Grupos como Mozilla, EFF, FSF, cientos de personas organizadas de sociedad civil luchando por privacidad, transparencia, datos abiertos y más están del lado correcto de la historia y trabajando contra el tenebroso estado de las cosas.

En lo personal, como siempre he venido evolucionando en lo que respecta a mi carrera profesional, y obviamente creciendo (por no decir envejeciendo) como persona. Empecé el blog con 21 años, y ya estoy en los treinta. Pasé por de todo desde aquellas primeras veces en que me pagaban por escribir código. Estuve en fábrica de software a lo Dilbert u Office Space, pasé por startups, logré trabajar en la empresa en la que soñaba trabajar, estuve en una empresa que se vendió a otra más grande, programé mucho código libre voluntario, también pago, fui freelance por más de tres años, y más. Conocí varias ciudades distintas en el mundo gracias a mi trabajo, e hice muchos amigos nuevos.

Hoy en día, se repite eso que dije una vez que todos los caminos llevan a Escocia. Empecé a trabajar oficialmente en Cultivate. Es mi segunda vez trabajando con ellos, pero esta vez me uno al equipo definitivamente. Estoy muy contento con este cambio. Si bien ser freelance fue una muy buena experiencia, se dieron las condiciones para que volviera a una empresa. Y en la ciudad que más me gusta de los que he conocido, nada menos. En el poco tiempo que llevo desde que empecé, es muchísimo lo que he aprendido, y me tiene muy feliz.

En cuanto a código y programación, me tomé un verdadero descanso. Estuvo un buen tiempo lejos de la computadora, concentrado en otros tipos de proyectos, y no le di tanta atención como generalmente lo hacía antes. Cambié un poco la filosofía en cuanto al encare de mi carrera, tratando de no sucumbir a la presión constante autoimpuesta (y un poco impuesta por el mercado) de mejorar mi nivel técnico. Debe ser la edad… o probablemente la experiencia. De todas formas al haber retomado me di cuenta que ese descanso realmente me sirvió. El nuevo trabajo implicó aprender muchas cosas nuevas y desafíos. Al agarrarle el gustito de nuevo a eso de resolver problemas y aprender, ese bichito se volvió a despertar y volví  “al ataque”. Digamos que ya hay varios posts nuevos sobre tecnología en borradores.

Sigo usando Ruby como lenguaje principal. Vengo personalizando (y disfrutando) cada vez más mis herramientas de trabajo. También sigo en contacto con JavaScript y demás tecnologías web actuales (a pesar de mi poco afecto hacia JavaScript), y mi objetivo este año es escribir al menos un proyecto con Elixir.

No he dado charlas en un buen tiempo. No me acuerdo bien cuál fue la última charla que di. Dejé de ir a meetups en Montevideo, y cada vez menos conferencias. Ya no las estaba disfrutando, varios eventos a los que asistí me resultaron malos por varias razones. Muchas veces me resultaban simplemente un intento de los organizadores de obtener algo, otras eventos organizados para los oradores en vez de para el público, y varias cosas más. En parte esto se debe seguramente a un desgaste que tuvimos en el equipo de organización de RubyConf Uruguay en su momento, que nos hacía ver cosas en otras conferencias que no nos gustaban. Dentro de todo creo que o se perdió algo que veía antes en estos eventos, o ya no estoy en la misma sintonía como para sacarles provecho y disfrutarlos. De todas formas ya me empezó a picar la curiosidad de eventos nuevos…

Estuve dando clases esporádicamente en Montevideo para alguna cosa particular que me contrataban. Pero no volví a trabajar fijo de “profesor” como lo hice por un tiempo en CEI Maldonado disfrutando de dar clases de Sistemas Operativos.

El blog ha seguido teniendo períodos dispares de tiempos de actualización y calidad/origen de los contenidos. Nunca pensé dejar de escribir acá, después de 10 años parece difícil imaginar que el blog dejara de existir. Siempre cuesta sentarse a escribir y enfrentarse a una página en blanco. Tengo cientos de entradas en borradores que nunca llegaron (y probablemente no llegarán) a ser terminadas o acercarse a un estado en el que no de vergüenza apretar el botón de Publicar. Espero con este evento de haber cumplido 10 años de escribir cosas más y menos relevantes o serias en este blog, me motive a empezar a escribir más seguido.

Este hito de 10 años con el blog me sirvió como una buena excusa para hacer un mini repaso e intentar saludar a quienes están del otro lado, esperando alguna respuesta. Con todos estos cambios, resulta difícil saber quienes quedan por ahí. ¿Qué esperan encontrarse al ver un post nuevo en Picando Código? ¿Qué les hace volver? ¿Cómo debería festejar estos 10 años?

Muchas gracias por leer, espero tus comentarios.

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

Adrianistán

Cuando ‘bad_style’ se convierte en algo ofensivo

junio 20, 2017 03:55

Voy a hacer un breve comentario sobre un asunto que ha levantado polémica dentro del mundo de Rust. Se trata de esta issue. Básicamente viene a decir que usar el término bad para referirse a el estilo de programación de Rust no estándar es incorrecto. Que puede ofender a la gente. Particularmente lo encuentro jocoso, pero hay mucha gente que no. La discusión se ha bloqueado (alguien diría que censurado) y parece que finalmente se ha adoptado la decisión de eliminar bad por ser ofensivo.

Con gran acierto el autor profetizó que esta issue traería mucho bikeshedding, aunque no únicamente en el nombre de la sustitución. Sin embargo me parece que este tema merece que le dedique un poco de tiempo.

En primer lugar se culpa de que usar bad hace a la gente sentirse mal, que es un término pasivo-agresivo y que echa las culpas al programador por usarlo. ¿Qué hace bad_style? Es un lint del compilador de Rust que emite advertencias si usamos una convención distinta la habitual. Por ejemplo,si usamos camelCase en vez de snake_case obtendremos un warning por este linter.

A mí en particular en condiciones normales me daría igual el término exacto de este linter, pero los argumentos que han dado me han parecido muy soprendentes. Supuestamente si algo tiene la palabra bad podría haber gente que se sienta mal y le afecte, que los principiantes se sientan bienvenidos en una comunidad con un lenguaje que no te hace usar la palabra bad cuando vas a saltarte la convención (y además les desmotiva).

El caso es que me resulta difícil entender como el flag para que el compilador no ejecute el susodicho linter pueda herir los sentimientos de alguien. El compilador no es algo personal, no te está insultando a ti, es una herramienta, y sí, existen cosas malas. Si llevamos esto al extremo el compilador no debería dar errores sino “sintaxis malointerpretada” Programar en bad_style es una mala práctica porque reduce la interoperabilidad y legibilidad entre proyectos. No importa si es camelCase o snake_case pero todos estamos de acuerdo que si un lenguaje adopta una forma por convención es mucho mejor adherirse a ella, podremos leer código ajeno más rápidamente y mejor. Si realmente te afecta emocionalmente usar bad_style porque es bad entonces quizá tu problema sea otro, mucho más grave y que necesites ayuda de un profesional.

Por otra parte la discusión presenta la más que alarmante falta de visión más allá del mundo angloparlante que presenta mucha gente. No es que les ignoran, es que creen que ciertas cosas que son aplicables a EEUU son aplicables al resto de culturas del mundo.

Fue en otra conversación donde se propuso cambiar stupid por foolishrude, ya que era menos ofensivo. Como si estúpido en español fuese un gran insulto. Para mí estúpido puede llegar a ser un insulto tierno. Sin embargo el grupo de trabajo dedicado a revisar las palabras prefería abolir sus usos con la excusa de que nadie pudiera sentirse ofendido. Yo no lo sabía pero existen detectores automáticos de estas palabras y muchas otras que no deben ser usadas. Para mí todo esto me parece sacado de contexto de forma excesivo y aunque no es algo único a la informática, es aquí donde me lo encuentro más a menudo. Sobre este asunto estoy bastante de acuerdo con Slavoj Zizek.

No sé donde quedó aquello de que no había libertad de expresión si no había libertad de ofender a la gente como decían Orwell o Chomsky. Cada vez más las comunidades que dicen ser welcoming me alejan más. Dije antes que este asunto no solo ha pasado en el mundo de Rust. Efectivamente, en Node.js también eliminaron suicide del módulo cluster porque era ofensivo también. No pudieron eliminar killhost porque eran ya términos históricos de UNIX, aunque les hubiese gustado.

La entrada Cuando ‘bad_style’ se convierte en algo ofensivo aparece primero en Blog - Adrianistan.eu.

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

Variable not found

Expresiones throw en C# 7

junio 20, 2017 06:55

C#Continuamos esta serie sobre las novedades incluidas en C#7, y en esta ocasión vamos a ver una pequeña mejora en el lenguaje que seguro nos será de utilidad para simplificar código muy frecuente: las expresiones throw.

Fijaos en un código como el siguiente, que seguro que habéis escrito cientos de veces, donde utilizamos el constructor de una clase para recibir sus dependencias y almacenarlas en miembros de la instancia:
public class MyService: IMyService
{
private readonly IDependency _first;
private readonly IAnotherDependency _second;

public MyService(IDependency first, IAnotherDependency second)
{
if (first==null)
throw new ArgumentNullException("first");

if (second == null) // O mejor, usando el operador nameof
throw new ArgumentNullException(nameof(second));

_first = first;
_second = second;
}

...
}

Habréis reconocido el patrón: hacemos una comprobación de precondiciones, y lanzamos una excepción con throw en función del resultado de ésta.

Pues bien, en C# 7 podemos simplificar esta sintaxis debido a que throw es considerada una expresión a efectos de compilación. Es decir, con la última versión de C# podemos simplificar el método anterior de la siguiente forma, y compilará correctamente:
public MyService(IDependency first, IAnotherDependency second)
{
_first = first ?? throw new ArgumentNullException("first");
_second = second ?? throw new ArgumentNullException(nameof(second));
}
Otro ejemplo de uso, aunque de utilidad y legibilidad dudosa, podría ser el siguiente:
public static int Divide(int a, int b)
{
return a / (b != 0 ? b: throw new ArgumentOutOfRangeException(nameof(b)));
}
Asimismo, dado que esta nueva capacidad permite lanzar excepciones desde el interior de expresiones, puede ser utilizada en los expression bodied members.

Con versiones anteriores del lenguaje no podíamos incluir un throw en un miembro de este tipo porque el lanzamiento de excepciones no era compatible con expresiones. Esto obligaba, por ejemplo, a escribir verbosos getters en ocasiones en las que simplemente queríamos lanzar una excepción, por ejemplo:
public interface IMyInterface
{
string SomeValue { get; }
}

// C# 6 y anteriores
public class Foo : IMyInterface
{
public string SomeValue
{
get { throw new NotImplementedException(); }
}
}
En C# 7, de nuevo, podríamos simplificarlo bastante:
public class Foo : IMyInterface
{
public string SomeValue => throw new NotImplementedException();
}
En fin, no es una mejora espectacular, pero es uno de esos pequeños detalles que nos facilitan un poquito el día a día y siguen haciendo de C# un mejor lenguaje.

Otros posts de esta serie:
Publicado en Variable not found.

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

Koalite

Optimiza, pero cuidado con los microbenchmarks

junio 19, 2017 05:06

gene amdhal

Siempre me ha parecido una parte muy entretenida de desarrollar software. Optimizar una aplicación, ya sea en cuanto a velocidad de ejecución o consumo de memoria, suele ser divertido y gratificante. Es como un juego en el que siempre puedes intentar exprimir un poco más el sistema para intentar mejorar, y eso lo hace divertido. Además, todo el mundo sabe que performance is a feature, así que invertir algo de tiempo en esto puede resultar rentable. Sin embargo, muchas veces a la hora de optimizar ponemos el foco en cosas que no tienen mucha importancia y dejamos pasar las oportunidades realmente interesantes de optimización.

Olvídate de microbenchmarks

No sé por qué, pero a la gente le encanta medir el rendimiento de cosas muy pequeñas, que la mayoría de las veces no influyen casi nada en el rendimiento real de una aplicación.

Cosas como si es más rápido usar !!string_value o Boolean(string_value) en Javascript, lo que tarda un contenedor IoC en instanciar un componente, o la diferencia entre hacer una llamada directa o a través de un interface, quedan muy bien para hacer un microbenchmark, pero en general hablamos de cosas tan rápidas que da más o menos igual lo que tarden.

Por ponerlo en contexto, en el PC en el que estoy escribiendo esto, puedo convertir en un segundo 1.200.000.000 de strings en booleanos usando !! y sólo 43.000.000 usando Boolean(). Eso es menos de 25ns por operación en el caso peor. Hay muy pocas aplicaciones para las que eso sea crítico.

El hecho es que es frecuente encontrase en redes sociales, hackernews, reddits y similares, información con “consejos” sobre la gran mejora que podemos conseguir aplicando estas microoptimizaciones, y es fácil caer en la idea de que para hacer bien las cosas hay que aplicarlas.

Que Nick Craver intente ahorrarse una reserva de memoria en StackOverflow, y Ayende se cree su propio gestor de memoria para RavenDB, puede ser muy entretenido como curiosidad, pero en la mayoría de escenarios no merece la pena dedicar mucho tiempo a ello, y mucho menos comprometer la legibilidad del código para obtener esas mejoras.

Por supuesto, si te dedicas a desarrollar máquinas virtuales, bases de datos, o tienes escenarios con un volumen de tráfico brutal, este tipo de optimizaciones pueden ser la diferencia entre que el sistema sea viable o no, pero pero reconozcamos que no son los escenarios más habituales.

Un problema adicional de este tipo de microbenchmarks es que suele tratarse de benchmarks sintéticos, por lo que no tienen en cuenta el efecto de otras partes del sistema sobre el código ejecutado, por ejemplo, recolectores de basura, memoria disponible, número de hebras activas, etc. Una implementación que sobre el papel puede parecer muy atractiva, llevada al mundo real puede tener un rendimiento deficiente por la carga de memoria que introduce al sistema o el número de recursos de otro tipo que consume.

La Ley de Amdahl

Gene Amdahl fue un señor que se dedicó, entre otras cosas, a diseñar ordenadores allá por los años 50. Como en aquella época no existía Javascript y no necesitaba aprenderse la librería disruptiva de cada semana, se ve que le dio por pensar en cosas académicas de esas inútiles y enunció una ley para medir la mejora teórica que se podía obtener en un sistema cuando se mejoraba alguna de sus partes. Se conoce, claro, como Ley de Amdhal y se resumen en esta fórmula:

amdhal

Donde:

Slatency(s) es la ganancia teórica de rendimiento del sistema global.
s es la ganancia de rendimiento en la parte mejorada.
p es el proporción de tiempo invertida en la parte mejorada.


Por verlo con un ejemplo, eso quiere decir que si conseguimos que una parte del sistema vaya 4 veces más rápido (s = 4), y esa parte consume el 10% del tiempo (p = 0.1), la ganancia teórica del sistema completo es de 1.08, es decir, pese a haber mejorado el rendimiento de una parte un 400%, la ganancia real es de “sólo” es 8%.

No hace falta ser un experto en matemáticas para darse cuenta de que, por mucho que mejoremos el rendimiento de una parte del sistema, si el tiempo total invertido en ejecutar esa parte es pequeño, el rendimiento global apenas mejorará.

Cómo mejorar el rendimiento de una aplicación

Armados con este conocimiento, es fácil trazar estrategias a seguir a la hora de optimizar una aplicación. La idea es sencilla: identifica qué partes consumen más tiempo, y haz que tarden menos.

Como siempre, el diablo está en los detalles, y es que los humanos somos especialmente malos en adivinar cuáles son las partes que consumen más tiempo, y para no ir a ciegas y esta estrategia sea realmente efectiva, es imprescindible medir. Puedes usar un profiler o algún mecanismo más rupestre (un triste log) para intentar identificar los cuellos de botella de la aplicación, pero hasta que no los tengas identificados, ponerse a optimizar “por si acaso”, no tiene mucho sentido.

En la mayoría de aplicaciones los cuellos de botella principales van a estar siempre ligados a procesos de entrada/salida: consultar una base de datos, lanzar una petición a un servidor externo, acceder a disco, pintar en pantalla…

En general, esos son los puntos en los que mayor impacto pueden tener las mejoras de rendimiento que hagamos, y como siempre, es bueno recordar que el código más rápido es aquel que no se ejecuta, por lo que todo lo que sea minimizar el número de operaciones de entrada/salida suele ser bastante beneficioso para una aplicación.

Por supuesto, si puedes introducir una cache que evite la operación de entrada salida, ganarás en rendimiento (a costa de memoria, claro).

Si en lugar de lanzar 30 consultas a la base de datos, te puedes traer la información en una, probablemente sea más rápido (no te olvides de medir, que te puedes llevar alguna sorpresa).

Hacer que tu API entre cliente y servidor use pocos mensajes “grandes” en lugar de muchos “pequeños”, dará lugar a un interface menos chatty (¿hablador?) y mejorará el rendimiento.

Comprimir la información enviada a través de la red reducirá el tiempo de descarga de datos (aunque incrementará el coste de CPU, recuerda, siempre debes medir el impacto de los cambios).

Si puedes consolidar los repintados en una página web y evitar hacer un relayout completo, estarás más cerca de los famosos 60fps.

Este tipo de optimizaciones son las que más pueden ayudarte a mejorar el rendimiento general de la aplicación, más que centrarte en cuál es la forma más rápida de comparar strings en C#.

Conclusión

La conclusión a este post en realidad la escribió Donald Knuth, otro señor que tuvo que dedicarse a pensar en lugar de producir mejor software cambiando el sistema de compilación de su aplicación .NET Core cada dos meses, y famoso, entre otras citas, por ésta que seguro que os suena:

La optimización prematura es la raíz de todo mal.

Es una lástima que se haya sacado de contexto, por que la cita real es más bien la siguiente:

Los programadores malgastan enormes cantidades de tiempo preocupándose por la velocidad de partes no críticas de sus programas, y estos intentos por mejorar la eficiencia tienen un fuerte impacto negativo a la hora de depurarlos y mantenerlos. Debemos olvidarnos de pequeñas mejoras, digamos, el 97% del tiempo: la optimización prematura es la raíz de todo mal. Pero no debemos dejar pasar la oportunidad de mejorar ese 3% crítico.

Si conseguimos identificar cuál es esa parte crítica de nuestra código que realmente tiene el peso del tiempo de ejecución, podremos centrarnos en mejorarla y obtener un impacto real en el rendimiento del sistema, pero evitemos complicar innecesariamente el código en aras de ganar unos nanosegundos que no van a ninguna parte.

Imagen de cabecera: Gene Amdahl en una fotografía de Computer History

Posts relacionados:

  1. Cuidado con quién dirige tu desarrollo

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

Blog Bitix

Autenticación mutua de cliente y servidor con certificados

junio 18, 2017 09:30

OpenSSL

Los certificados no solo sirven para autenticar a un servidor o acceder solo a aquellos en los que confiamos. El servidor también puede autenticar a los clientes mediante un certificado como alternativa a usar un usuario y contraseña ya sea una autenticación BASIC o un formulario personalizado. Al igual que en el cliente usa el certificado de la autoridad de certificación en la que confía para validar el que presenta el servidor, el servidor puede requerir que el cliente también proporcione un certificado que el servidor valida según las autoridades de certificación en las que confía, en ambos casos el servidor o cliente usan su clave privada para iniciar la conexión segura con el handsake del protocolo TLS.

Para el ejemplo usaré un servidor web nginx ejecutado como un contenedor de Docker configurado de tal manera que requiere autenticación para el cliente con certificados.

Inicialmente deberemos generar tres parejas de claves privadas y públicas, una para nuestra propia autoridad de certificación, una clave para el servidor y otra para el cliente. Al mismo tiempo generaré otras tres parejas de claves privadas y públicas para comprobar que cuando se proporciona un certificado incorrecto la autenticación falla.

El siguiente paso es generar los certificados y firmar con la clave y certificado de la autoridad de certificado los certificados del servidor y cliente. Como paso previo a que la autoridad de certificación emita los certificados del servidor y cliente hay que generar una petición de firma de certificado, los archivos .csr.

Con la misma herramienta de OpenSSL es posible comprobar si un certificado es válido para una autoridad de certificación en la que se confía, para ello se usa el certificado raiz de la autoridad.

Para hacer que el servidor nginx requiera autenticación mediante certificados para el cliente hay que añadir un poco de configuración mediante las directivas ssl donde se indica el certificado del servidor, la clave privada del servidor, el certificado de la autoridad de certificación contra la que se validarán los certificados de los clientes y finalmente la directiva que establece que se ha de verificar a los clientes mediante certificados.

Con el siguiente archivo descriptor de Docker Compose y comando se inicia el servidor web nginx.

Iniciado el servidor web ya se pueden realizar peticiones y el servidor y el cliente se autenticarán mutuamente. El servidor devolverá el código HTML de la página de bienvenida por defecto con las cabeceras del protocolo HTTP después de realizar el handsake donde se valida el certificado del servidor.

Si se intenta realizar una petición sin certificado de cliente o con un certificado de cliente en el que no confié el servidor (que no esté firmado por la autoridad de certificación en la que confía) se devolverá un código de estado 400 que indica que la petición se ha rechazado. También el cliente advertirá si la autoridad de certificación en la que confía no valida el certificado del servidor con un error 400 y título 400 The SSL certificate error.

El siguiente script escrito en lenguaje Groovy muestra como desde un programa para la plataforma Java se realiza autenticación mutua y que error da cuando alguno de los certificados es inválido ya sea el del cliente o el del servidor. Generando previamente los keystores de la autoridad de certificado y del cliente introduciendo como clave en el ejemplo password cuando se solicita.

En caso de que al usar un keystore con un certificado de una autoridad que no valida el certificado del servidor se producirán un error, también cuando el certificado del cliente no sea válido para el servidor.

Lo anterior es usando la herramienta curl o un un programa en la plataforma Java, en el caso de querer realizar autenticación mutua con un navegador web como Firefox hay que instalar el certificado del cliente y si es necesario el certificado de la autoridad de certificación para que el candado indicativo de la seguridad del protocolo HTTPS se muestre en verde y no indique ningún problema de seguridad en la autenticación del servidor. En Firefox los certificados se añaden en el menú Preferencias > Avanzado > Ver certficados. En la pestaña Sus certificados hay que importar el certificado del cliente en formato PKCS12 y en la pestaña Autoridades el certificado de la autoridad que haya firmado el certificado del servidor, con el botón Importar se selecciona el archivo crt de la autoridad. Al introducir la URL y realizar la petición Firefox solicita mediante un diálogo seleccionar el certificado a usar para realizar la autenticación en el servidor.

Autenticación mutua de cliente y servidor con el navegador web Firefox

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

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

Adrianistán

Tutorial de CouchDB

junio 15, 2017 08:40

Hoy vengo a hablar de CouchDB, una base de datos que no es precisamente nueva ni es precisamente famosa, pero que en mi opinión tiene unas características únicas.

En primer lugar vayamos con la teoría. Apache CouchDB es una base de datos NoSQL que almacena documentos JSON y tiene una potente API REST. Está programada en Erlang y es un proyecto Apache desde 2008. Usa JavaScript para la operativa interna. Visto este resumen uno podría pensar que estamos ante un clon de MongoDB (a pesar de que CouchDB es mucho más antigua) pero no. CouchDB parte de una filosofía distinta, ser la base de datos de la era de la web y se nota mucho como toma decisiones que la alejan de las bases de datos relacionales y de las bases de datos NoSQL más populares.

La API REST

Una parte fundamental de CouchDB es la API REST, que es la única API que dispone. CouchDB de este modo puede funcionar de dos formas:

  • En un modelo tradicional, con una servidor que haga las peticiones. Este servidor puede estar programado en cualquier cosa (Java, PHP, Node.js, C#, Python, Ruby, Elixir,…) y que no es muy distinto a como nos conectamos por ejemplo a MongoDB o a MySQL.
  • En un modelo innovador donde la base de datos está conectada directamente a Internet y no hace falta ningún servidor que gestione la comunicación. Este modelo da lugar a las CouchApps, aplicaciones CRUD pero sin servidor propiamente dicho, solo base de datos y un alojamiento estático de archivos. A través de JavaScript en el lado del cliente podemos obtener la información, conectándose directamente el navegador con la base de datos.

La posibilidad de hacer esto último es una de las mayores ventajas de CouchDB en mi opinión, ya que según el proyecto, esto puede ahorrar mucho tiempo y prevenir muchos posibles bugs en operaciones tontas. El desafío de este artículo será crear una aplicación en CouchDB que pudiera simular a una aplicación CRUD cualquiera. Esta aplicación reducirá costes respecto a una tradicional ya que eliminamos la parte del servidor, solo mantenemos la base de datos (y un proxy).

Instalando CouchDB

CouchDB está en casi todas las distros Linux. Es posible que no esté disponible la última versión, pero para lo que vamos a hacer no es necesario. Yo voy a usar CouchDB 1.4, una versión bastante antigua, pero es la que tiene Debian en sus repos. En Ubuntu tenéis CouchDB 1.6 y en la página oficial está la versión 2.0

Creando una base de datos

En CouchDB las bases de datos son cubos sin fondo. Podemos arrojar documentos JSON sin control.

Vamos a usar la API REST para crear la base de datos “supermercado”.

curl -X PUT http://127.0.0.1:5984/supermercado

Podemos comprobar que la base de datos ha sido creada con GET

curl -X GET http://127.0.0.1:5984/supermercado

En CouchDB ciertas rutas que comienzan por barra baja son especiales. Por ejemplo si queremos pedir una lista de todas las bases de datos podemos hacer GET a _all_dbs.

curl -X GET http://127.0.0.1:5984/_all_dbs

Para borrar la base de datos usaríamos DELETE

curl -X DELETE http://127.0.0.1:5984/supermercado

Pero no lo hagas todavía. Si has pensado en lo que hemos hecho te estarás alarmando. Hemos creado una base de datos, por HTTP y no se nos ha pedido ninguna autorización ni nada. Por defecto CouchDB es inseguro ya que arranca en un modo llamado Admin Party, pero rápidamente veremos que si vamos a exponer CouchDB a Internet vamos a necesitar seguridad, y CouchDB la trae. Pero antes, vamos a trabajar con documentos.

Insertando un documento

Insertar un documento es tan fácil como tirar documentos a la papelera (bueno, quizá no tan fácil).

curl -X PUT http://127.0.0.1:5984/supermercado/UUID -d '{"nombre": "Manzana", "tipo" : "fruta", "precio" : 5}'

Donde UUID es un UUID. Si no tienes un UUID a mano, CouchDB te ofrece uno a través de _uuids.

curl -X GET http://127.0.0.1:5984/_uuids?count=10

En realidad no es estrictamente necesario poner un UUID, pero es la convención habitual. Una vez hagamos el PUT obtendremos de respuesta un JSON con tres campos muy importantes. Ok para decirnos si la operación fue bien o no, _id, con el ID del documento (es el UUID de antes) y el _rev. Este último campo, nos indica con que versión del documento hemos interactuado, en nuestro caso, era la primera así que hay un 1 delante. Esto es muy importante en CouchDB y tiene que ver con como gestiona la concurrencia. CouchDB es eventualmente consistente. Quiere decir que en una situación de escritura y lectura simultáneas, la base de datos no se bloquea sino que puede mandar distintas versione de los documentos. Cuando editemos un documentos tendremos que indicar  sobre que versión hacemos la modificación, y si algún otro cliente se nos adelantó y modificó el documento antes, tendremos que basarnos en su revisión para que sea aceptada por la base de datos. Hay que tener que CouchDB no es un sistema de control de versiones, las revisiones antiguas pueden desaparecer sin previo aviso. Esta característica, la de ser eventualmente consistente, también facilita mucho su desempeño en clústeres, pero no vamos a entrar en ello. De momento hay que saber que en CouchDB, a diferencia de otras bases de datos, para actualizar un documento necesitaremos su ID y su revisión.

Para ver el documento conociendo su ID hacemos un simple GET

curl -X GET http://127.0.0.1:5984/supermercado/UUID

Nos devuelve el documento entero junto con las propiedades _id y _rev.

Actualizando un documento

El precio de las manzanas ha cambiado, vamos a actualizarlo. El proceso es muy simple, es como insertar un documento pero añadimos la revisión sobre la que queremos hacerlo. Es importante mencionar que CouchDB no preserva nada en las actualizaciones. Si quieres dejar campos sin tocar, tendrás que volver a subirlos.

curl -X PUT http://127.0.0.1:5984/supermercado/98c003b03bc8aa87cb05983d1c000713 -d '{"_rev": "1-eba25568090eb2dfffad770b55147a67","nombre": "Manzana", "tipo" : "fruta", "precio" : 4}'

Para borrar documentos necesitas usar DELETE indicando el número de revisión.

curl -X DELETE http://127.0.0.1:5984/supermercado/98c003b03bc8aa87cb05983d1c000713?rev=2-298fdb46385be60609b242b3e5cc3566

(pero no lo hagas)

Vistas

Todo muy bonito, pero, ¿cómo accedo a la información? En SQL usaríamos SELECT, en bases como MongoDB lanzaríamos un find. En CouchDB hay que usar vistas, que se programan en JavaScript y siguen un esquema MapReduce (que recordemos, funciona muy bien en paralelo). Esto se puede hacer de varias formas. Se puede usar Fauxton, una interfaz web de CouchDB, se puede usar Erica, una herramienta para facilitar la creación y mantenimiento de CouchApps o se puede hacer con la API REST, ya que las vistas se definen en documentos JSON también.

Tenemos que crear un Design Doc. Los design doc son muy útiles y permiten por ejemplo validar documentos que vayan a entrar en la base de datos (podemos definir schemas así) o definir las vistas. Un design doc simple es así. Definimos una vista llamada all con una operación map.

 

{
    "views" : {
        "all" : {
            "map" : "function(doc){ emit(null,doc); }"
        }
    }
}

Si lo tenemos guardado en un archivo JSON

curl -H "Content-Type: application/json" --data @super.json -X PUT http://127.0.0.1:5984/supermercado/_design/super

Ahora vamos a ejecutar la vista

curl -X GET http://127.0.0.1:5984/supermercado/_design/super/_view/all

Obtenemos un objeto JSON con todos los documentos que contiene la base de datos supermercado. Por supuesto es posible crear distintos documentos de diseño, con distintas vistas cada uno.

Las vistas solo las debería poder crear el administrador de la base de datos, por lo que al contrario que en otras bases de datos, el cliente no podrá realizar operaciones que no hayan sido definidas antes. En realidad, no es del todo cierto, ya que en CouchDB 2.0 se añadió Mango, un lenguaje de consulta declarativo que permite realizar cierta operativa sin usar las vistas, pero no es tan potente.

Otro ejemplo:

{
    "views" : {
        "by-price" : {
            "map" : "function(doc){ emit(doc.precio,doc); }"
        }
    }
}

Esta vista puede ser llamada con parámetros

curl -X GET http://127.0.0.1:5984/supermercado/_design/super/_view/by-price?descending=true&amp;limit=1

CouchDB realiza la operación de ordenado por su cuenta con el valor del key que devolvemos.

La base de datos en el salvaje oeste

Ahora vamos a ver como exponer CouchDB al salvaje Internet sin comprometer seguridad. En primer lugar toca hablar de los usuarios. Como hemos dicho, CouchDB arranca en el modo Admin Party. Este modo será desactivado en cuanto creemos un usuario como admin. CouchDB soporta además usuarios tradicionales, una característica muy útil que veremos después como usar.

Para crear un usuario como admin lanzamos esta petición:

curl -X PUT http://127.0.0.1:5984/_config/admins/aarroyoc -d '"MiPassword"'

A partir de ahora ya no estamos en una admin party y si intentamos crear una base de datos veremos que CouchDB nos deniega el acceso. Sin embargo, otras tareas como subir documentos a bases de datos ya existentes todavía funcionan.

Para protegernos mejor debemos saber los tipos de autorización que soporta CouchDB. En primer lugar soporta HTTP Basic Auth, un método en el que mandamos el usuario y la contraseña en texto plano en cada petición. Esto no es para nada seguro, pero combinado con SSL no es mala opción. Sin embargo sigue sin ser la mejor solución para los expertos en seguridad. CouchDB también acepta autenticación por cookies. Las cookies duran 10 minutos por defecto y se generan haciendo una petición a _session con formato de formulario HTTP.

curl -vX POST http://127.0.0.1:5984/_session -H "Content-Type:application/x-www-form-urlencoded" -d "name=aarroyoc&amp;password=MiPassword"

Que nos devuelve una cookie válida para operar en la base de datos

Existen plugins que permiten gestionar desde CouchDB autorizaciones más diversas, como por ejemplo OpenID o OAuth2, pero pueden complicarnos mucho el desarrollo.

Los usuarios normales se guardan en la base de datos especial _users y se les puede asignar roles, con permisos para cada base de datos. Por defecto, se pueden crear cuentas de usuario nuevas de forma tan simple como así:

curl -X PUT http://127.0.0.1:5984/_users/org.couchdb.user:USUARIO -d '{"name" : "USUARIO", "password" : "MiPassword", "type" : "user", "roles" : []}'

Es importante seguir el esquema org.couchdb.user:USUARIO para los documentos. Los roles solo los puede ajustar una cuenta de admin, así que en las peticiones anónimas deberá ir vacío.

Si en algún momento quieres saber cuántos usuarios tiene la base de datos, puedes usar la vista predefinida _all_docs.

curl -X GET http://usuarioadmin:contraseñaadmin@127.0.0.1:5984/_users/_all_docs

Estos documentos de usuarios por defecto son privados pero podemos mostrar cierta información para el resto de usuarios, sobretodo si añadimos campos extra a los documentos

curl -X PUT http://usuarioadmin:contraseñaadmin@127.0.0.1:5984/_config/couch_httpd_auth/public_fields -d '"name"'

Hará visible el campo name a todas las peticiones GET anónimas a ese documento de usuario.

Accesos a la base de datos

Ahora vamos a ver como controlar las lecturas y escrituras de una base de datos en concreto. Aquí creo que CouchDB tiene limitaciones y que debe ser algo en lo que enfocarse en futuras versiones pues es un control muy limitado. Si fuese una base de datos interna no sería mucho problema, pero teniendo en cuenta que va a estar expuesta a Internet sería necesario algo más potente. Eso no quiere decir que no se puedan hacer cosas, pero vamos a tener que tirar de funciones JavaScript internas.

Por un lado, tenemos un documento especia en cada base de datos llamado _security. Este contiene listas de admins y miembros. Las listas pueden estar vacías, contener usuarios o contener roles. En caso de que la lista de miembros este vacía se considera que todos los usuarios son miembros (incluido los anónimos). Los miembros pueden leer y escribir todos los archivos. Esto es muy insuficiente. Por poner un caso completo, yo necesitaba:

  • Que todos los usuarios pudieran leer los documentos (incluido anónimos)
  • Que todos los usuarios registrados pudieran crear documentos
  • Que solo se pudiesen modificar los documentos creados por cada usuario

Esto se puede hacer si obligamos a los documentos a que especifiquen un dueño. Todo lo podemos hacer en esta función:

function (new_doc, old_doc, userCtx){
    if(!userCtx.name)
        throw({forbidden: "Not authorized"});

    if(!new_doc.owner)
        throw({forbidden: "Plase, set an owner"});

    if(new_doc.owner != userCtx.name)
        throw({forbidden: "Owner in document should be the same as user"})

    if(old_doc!=null)
        if(old_doc.owner != userCtx.name && userCtx.roles.indexOf("_admin") < 0)
            throw({forbidden: "Not your document"});
    return;
}

Esta función puede ser subida a CouchDB con la API HTTP dentro de un design doc. El design doc quedaría así:

{
        "_rev" : "7-670f7428b5a5afb25ec61382024f0733",
        "views" : {
                "all" : {
                        "map" : "function(doc){ emit(doc.name,doc); }"
                },
                "by-price" : {
                        "map" : "function(doc){ emit(doc.precio,doc); }"
                }
        },
        "validate_doc_update":"function (new_doc, old_doc, userCtx){\n    if(!userCtx.name)\n        throw({forbidden: \"Not authorized\"});\n\n    if(!new_doc.owner)\n\tthrow({forbidden: \"Plase, set an owner\"});\n\n    if(new_doc.owner != userCtx.name)\n        throw({forbidden: \"Owner in document should be the same as user\"})\n\n    if(old_doc!=null)\n        if(old_doc.owner != userCtx.name && userCtx.roles.indexOf(\"_admin\") < 0)\n            throw({forbidden: \"Not your document\"});\n    return;\n} \n"
}

Por supuesto, en _rev irá la revisión que toque. Este sistema es más potente de lo que parece ya que podemos controlar todos los detalles de la operación. Es por ello que muchas veces la función validate_doc_update es la más compleja de los documentos de diseño. Para ayudarme un poco, estoy usando Node.js para leer archivos JavaScript y pasarlos a una cadena JSON válida.

CORS y SSL

Vamos a lanzar CouchDB a Internet. En primer lugar, un par de detalles. CouchDB idealmente vivirá en un dominio separado a la web estática. Para que las peticiones JavaScript funcionen hay que activar CORS. También vamos a proteger los datos así como los usuarios y contraseñas transmitidos. Todo esto podemos hacerlo del tirón con nginx:

 

server {
        listen 443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/alejandria.adrianistan.eu/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/alejandria.adrianistan.eu/privkey.pem;
        server_name alejandria.adrianistan.eu;
        location / {
                add_header Access-Control-Allow-Origin *;
                proxy_pass http://localhost:5984;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Ssl on;
        }

        location /_utils/ {
                return 404;
        }
}

¡Listo! Ya tenemos una instancia de CouchDB directamente conectada a Internet. Como podéis comprobar es una alternativa muy interesante en muchos casos. Sin embargo, ciertas cosas son un poco diferentes y más complejas de realizar. Mencionar que CouchDB también es posible usarse con un servidor de por medio en un esquema tradicional. En este caso, podemos usar la cuenta de admin para crear bases de datos personales para cada usuario. Este enfoque es necesario si necesitamos que los datos sean privados o queremos afinar más que roles tienen acceso a una base datos. CouchDB anima a crear tantas bases de datos como necesitemos, varias por usuario si es necesario, para satisfacer nuestros requerimientos. Esto no tiene gran impacto en el rendimiento tal y como está diseñado.

Puede hacerse de forma ligera, con una pequeña app que gestione el alta de usuarios y una vez creada la base de datos y ajustados los permisos se puede usar la API REST de CouchDB desde el lado del cliente con total normalidad, con protecciones de lectura y escritura más precisas.

Este modelo que hemos presentado es ideal para aplicaciones cuya base de datos principal sea pública y accesible y con unos pequeños ajustes puede adaptarse a muchas situaciones. Espero que os haya gustado el artículo. Nos hemos dejado cosas como la replicación entre nodos, los ficheros binarios o attachments ydos complementos a las vistas llamados show y lists, que permiten renderizar HTML o XML entre otras cosas, con los datos de salida de una vista si es necesario.

 

La entrada Tutorial de CouchDB aparece primero en Blog - Adrianistan.eu.

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

Variable not found

Enlaces interesantes 286

junio 12, 2017 06:55

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

.NET/.NET Core

ASP.NET/ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Cross-platform

Otros

Publicado en Variable not found

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

Blog Bitix

Introducción a la base de datos NoSQL Redis

junio 11, 2017 10:00

Redis es una de las bases de datos NoSQL en este caso de tipo clave-valor. Los valores pueden ser de diferentes tipos y tiene una amplia colección de operaciones disponibles para usar según el tipo de datos asociado a la clave.

Redis

Redis es una de las bases de datos para almacenar información de los conocidas como NoSQL. Almacena los datos en memoria por lo que es muy rápido y es usada como base de datos, como cache o broker de mensajes. Los datos no se almacenan en tablas como en los sistemas relacionales tradiciones RDBMS como PostgreSQL o MySQL sino en estructuras de datos como cadenas, hashes, listas, conjuntos, conjuntos ordenado con rangos, bitmaps, hyperloglogs e índices geoespaciales. Incorpora replicación, scripting con LUA, desalojo LRU, transacciones, diferentes niveles de persistencia en disco y alta disponibilidad con Redis Sentinel y paticionamiento con Redis Cluster.

El punto más crítico en el rendimiento en una aplicación suele estar en la base de datos relacional, dado que han de garantizar las propiedades ACID y almacenan grandes cantidades de datos en disco son lentas (comparativamente) además de presentar dificultades para escalar horizontalmente. Redis almacena los datos en memoria por lo que es significativamente más rápida que una base de datos relacional aunque con la limitación de no poder almacenar las grandes cantidades de datos medidos hoy en día en terabytes o TiB (1024 GiB) que podría almacenar una base de datos relacional. Para la necesidad de acceder datos de forma rápida, de cachear datos a los que acceder rápido, datos a los que se acceden frecuentemente, datos precalculados, hay grandes cantidades de escrituras o necesidad de escalar Redis es una opción a tener en cuenta.

Redis es un sistema de datos clave-valor en el que cada clave tiene asociado un tipo de datos y unos datos que almacena. Según el tipo de datos de la clave se pueden realizar diferentes operaciones o comandos de consulta.

Usando Docker se puede iniciar una instancia de Redis con un archivo descriptor del contenedor en formato yml y el comando docker-compose up. Redis al igual que otras bases de datos posee un shell de linea de comandos, redis-cli. Iniciada la instancia del contenedor y el servicio de Redis se puede iniciar una sesión de sh y con ella el shell.

Hay multitud de clientes para los lenguajes de programación más populares y otros menos usados, en Java uno de los clientes más conocidos es Jedis. En el siguiente ejemplo un cliente Java se conecta a la instancia de Redis y lanza los varios comandos para almacenar cadenas, un set, set ordenados, lista, hash y algunas operaciones sobre claves. Este ejemplo desde Java realiza las mismas operaciones que las realizadas en el shell de Redis anterior.

Cada comando de Redis tiene una complejidad de tiempo ejecución, para obtener el mejor rendimiento hay que analizar los datos para almacenarlos en la estructura de datos adecuada de las que ofrece Redis junto con los comandos que son utilizados y su complejidad indicada en la documentación del comando en notación Big O. Redis solo es uno de los sistemas NoSQL, hay otros conocidos con MongoDB orientado a documentos o Cassandra híbrido entre clave-valor y tabular.

Para un conocimiento mucho más detallado de las posibilidades de esta base de datos el libro Mastering Redis o Redis in Action son un buen inicio.

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

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

Picando Código

Actualizaciones en mis extensiones en GNOME

junio 09, 2017 12:00

Desde que escribí el último post sobre extensiones para GNOME 3, las cosas cambiaron un poco. Habiendo encontrado una nueva extensión bastante interesante para probar, volví a meterme en el tema de Extensiones GNOME Shell.

GNOME Extensions

Gnome Chrome Shell

La integración del navegador con el sistema GNOME parece haber cambiado. Al visitar el sitio web de las extensiones GNOME -por más que tuviera instalado el addon de Firefox GNOME Shell Extension– veía un error:

Although GNOME Shell integration extension is running, native host connector is not detected. Refer documentation for instructions about installing connector.

Buscando un poco, encontré que me faltaba el paquete chrome-gnome-shell. Éste provee la integración del repositorio de extensiones de GNOME Shell para Firefox, Google Chrome, Chromium, Vivaldi, y Opera. Se puede instalar directamente desde el gestor de paquetes del sistema en ArchLinux, Debian, Fedora, Gentoo, Ubuntu y FreeBSD. Más info.

Ejecutando sudo apt-get install chrome-gnome-shell en Debian ya pude ver nuevamente las extensiones GNOME Shell instaladas en el sitio de extensiones instaladas localmente. Ahí ya todo volvió a funcionar normalmente.

Maximus NG es discontinuada y se sugiere Pixel Saver

Una de las extensiones que más me gustaban era Maximus NG, que le quita la decoración a las ventanas cuando están maximizadas. De esta forma se aprovecha un poco más el espacio vertical de la pantalla. Pero me encontré con un mensaje del desarrollador avisando que la ha discontinuado, y que no cuenta con el tiempo de seguir manteniendo el proyecto.

Pero a partir de eso, recomienda Pixel Saver. La funcionalidad básica de Pixel Saver es la misma que Maximus NG, pero es todavía mejor. En primer lugar, no acorta el título de la aplicación que estamos ejecutando, como sí lo hacía Maximus. Aprovecha un poco más el espacio que hay entre el botón de “Actividades” de GNOME Shell. Había dos casos muy particulares en los que me molestaba no ver todo el título de la aplicación. En primer lugar, Firefox, donde apenas veía parte del título. En segundo lugar GIMP, que muestra información de la imagen que estamos manipulando en la decoración de ventanas (particularmente el tamaño, que tenía que ver con Alt+Enter), y ahora esa información se mantiene a la vista:

Pixel Saver

También se agregan los botones de cerrar ventana, minimizar, restaurar, etc. a la derecha de la ventana (que ya me acostumbré a no usarlos).

Pueden ver más información y el código fuente en su repositorio en GitHub.

Picture in Picture con Windows Corner Preview

Una de las cosas nuevas que encontré y quería probar fue Window Corner Preview. Llegué de casualidad por este blog post, donde comenta que es una característica recientemente añadida a Windows 10 y MacOS. La funcionalidad básica es mirar videos en una ventana muy chica por encima de todo, todo el tiempo, y que no sea tapada por todo lo demás que estemos haciendo en la pantalla. Algo así como lo que promocionaban los viejos televisores “Picture In Picture” en los 90’s:

Window Corner Preview

Está bastante interesante, aunque en general para la mayoría de los casos lo ideal seguro sea conectar un segundo monitor y dejar lo que sea reproduciendo en segundo plano. Pero para los casos en que eso no es posible, es una buena solución. Para usarlo, debemos aislar la pestaña donde se esté reproduciendo el video (en caso de ser en nuestro navegador web), elegir la ventana desde el ícono de la extensión (un simpático mono), y elegir la ventana. Para mover el preview de lugar, podemos usar: click izquierdo – salta a la esquina opuesta, click medio – se mueve a contrareloj – clic derecho, se mueve en dirección de las agujas del reloj.

Ver el clima con OpenWeather

Por último, una extensión nueva que instalé fue OpenWeather, una extensión que permite ver datos de clima en varias ciudades. Usa las APIs de OpenWeatherMap y Dark Sky. Podemos elegir las unidades de medida, el proveedor, y varias opciones del diseño.

OpenWeatherPueden ver el código y más información en su repositorio en GitHub.

De las extensiones que mencionaba en mi primer post sobre extensiones GNOME, las que sigo usando son TopIcons Plus, Optirun y Panel OSD. Diría que TopIcons Plus y Panel OSD serían de las más esenciales. Para ser sinceros, no he usado Optirun tanto como hubiera imaginado. Generalmente lo uso únicamente con los juegos en Steam y hay un método específico para eso.

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

Variable not found

Inline out variables en C# 7

junio 08, 2017 04:25

C#Seguimos revisando las novedades que nos llegan de la mano de C# 7, la nueva versión del lenguaje aparecida junto a Visual Studio 2017.

En un post anterior ya profundizamos un poco en las funciones locales, y hoy veremos en qué consisten las nuevas inline out variables, una característica muy útil que nos ahorrará escribir código en escenarios en los que siempre hemos tenido la sensación de que C# podía hacer algo más por nosotros.

Esa extraña sensación…

Observad el siguiente código; seguro que habéis escrito algo parecido más de una vez (y dos, y tres… centenares ;D)
public void ShowInteger(string str)
{
int number;
if (int.TryParse(str, out number))
{
Console.WriteLine("Number: " + number);
}
}
En mi caso, cuando escribo un código de este tipo, es raro que antes de comenzar a escribir la línea del TryParse() haya previsto que necesitaré una variable int. Normalmente escribo las llamadas a métodos con parámetros out, y mientras voy haciéndolo me doy cuenta de que las necesito, por lo que tengo que tengo que volver atrás, insertar la línea para declarar de forma estrictamente tipada la variable de salida, y después continuar por donde estaba. No es que rompa la productividad de la jornada, pero realmente resulta algo molesto.

imageTambién he de decir que esta molestia se relajaba un poco con las versiones modernas de Visual Studio, pues las quick actions (Ctrl+.) ya nos ofrecen soluciones automáticas al problema. Lo mismo ocurre con Resharper, que puede detectar este caso y solucionarlo a golpe de Alt-Enter.

Otro inconveniente asociado a esta forma de definir los parámetros de salida es que muchas veces debíamos definir las variables en un ámbito superior a aquél en el que íbamos a utilizarlas. Por ejemplo, en el bloque de código que hemos visto antes, era habitual es que el entero number lo usáramos exclusivamente en el interior del bloque if, por lo que su declaración fuera de éste tampoco tenía mucho sentido.

Por todos estos motivos, la sensación de que C# se quedaba algo corto en este escenario siempre ha estado ahí, y esto es lo que viene a solucionarse en la versión 7.

Inline out variables

A partir de ahora podemos utilizar esta nueva sintaxis, más concisa y fácil de leer, usando inline out variables:
public void ShowInteger(string str)
{
if (int.TryParse(str, out int number))
{
Console.WriteLine("Number: " + number);
}
}
El resultado de este código es exactamente el mismo que vimos al principio. Internamente se crea una variable de tipo entero llamada number en el ámbito del método ShowInteger(), que puede ser utilizada en cualquier punto del método una vez ha sido declarada:
Console.WriteLine("Number: " + number); // No compila: se usa "number" antes
                                        // de ser declarado

if (int.TryParse(str, out int number)) {
Console.WriteLine("Number: " + number); // Ok
}
Console.WriteLine("Number: " + number); // Ok, aunque "number" puede no haber
                                        // sido inicializado
Otro aspecto interesante, y que resulta bastante cómodo de utilizar, es que gracias a la inferencia de tipos podemos utilizar var para su declaración, pues ya el compilador es capaz de determinar de qué tipo se trata:
public void ShowInteger(string str)
{
if (int.TryParse(str, out var number))
{
Console.WriteLine("Number: " + number);
}
}
Por último, hay veces en las que invocamos un método con parámetros de salida cuyos valores no vamos a utilizar posteriormente. Para no obligarnos a declarar más variables de la cuenta, podemos utilizar el comodín "_" (guión bajo) para indicar al compilador que puede ignorar dichos valores:
public static void GetSomething(out int x, out double y, out string z)
{
x = 100;
y = 100.0;
z = "hello";
}

// Uso del método:
GetSomething(out var x, out _, out _);
Console.WriteLine(x); // Shows "100"
Visual Studio 2015 usando inline out vars¿Interesante, verdad? Pues recordad que, además de en Visual Studio 2017, también podéis usarlo en Visual Studio 2015 si instaláis o actualizáis a la última versión el paquete nuget "Microsoft.Net.Compilers"; aunque en el IDE se muestren como errores, la compilación irá bien y todo funcionará correctamente.

Publicado en Variable not found.

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

Variable not found

Cómo hacer que Chrome ignore certificados no válidos en localhost mientras desarrollamos una aplicación con HTTPS

junio 06, 2017 06:55

Google Chrome logoCuando desarrollamos aplicaciones web que funcionan sobre el protocolo HTTPS en la máquina local, lo más habitual es que utilicemos un certificado digital autofirmado o, en cualquier caso, firmado por una entidad no confiable.

Esto hace que los navegadores, por supuesto siempre con el ánimo de preservar nuestra privacidad,  sospechen del sitio web y muestren alertas como la siguiente, donde se nos informa de que el certificado es inválido y que alguien podría estar intentando robarnos información:

Chrome mostrando el error: La conexión no es privada

Pero no es grave, todos estamos acostumbrados a pulsar sobre el enlace "Opciones avanzadas" e indicar expresamente que deseamos acceder a localhost, aun siendo un sitio no seguro:

Opciones avanzadas, acceder a localhost (sitio no seguro)
El único problema de esta solución es que en Chrome no es permanente y de vez en cuando hay que volver a dar estos pasos para poder seguir haciendo pruebas en nuestro sitio web, lo cual resulta un poco tostón.

Preguntándome si habría forma de darle una solución algo más definitiva, me encuentro con este hilo de Stackoverflow donde se aporta una solución bastante sencilla, al menos para equipos con Windows (desconozco si en otros sistemas operativos funcionará). Basta con introducir esta URL en la barra de direcciones de Chrome:
chrome://flags/#allow-insecure-localhost
Tras ello, aparecerá la página de flags del navegador, donde veremos resaltada la opción que nos interesa habilitar ("Permitir que se carguen certificados no válidos desde localhost"):

Flag "Permitir que se carguen certificados no válidos desde localhost"
Así que basta con pulsar el link "Habilitar" de este flag, reiniciar Chrome, y a partir de este momento el navegador se tragará silenciosamente los certificados falsos cuando estemos navegando en localhost. Seguirá mostrándolo como inseguro en la barra de direcciones y dejará algún rastro en la consola, pero al menos habremos ganado en comodidad:

Barra de direcciones de Chrome mostrando que el sitio web https no es seguro
Para finalizar, simplemente quería recordaros que es importante ser consciente de que mediante este truquillo estamos invalidando un mecanismo de seguridad del navegador, por lo que debemos usarlo con precaución y sólo en casos donde sea estrictamente necesario.

Publicado en Variable not found.

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

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

Function Level Linking

junio 05, 2017 08:44

Tal vez después de Profile Guided Optimizations (PGO), si hubo una característica que me impresionó de los compiladores, fue el Function Level Linking, debería decir en realidad de los enlazadores, ya que su significado es Enlazado a Nivel de Función. Veréis, cuando comencé con los lenguajes de programación compilados, usando Turbo BASIC, me di cuenta […]

La entrada Function Level Linking aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Una sinfonía en C#

Javascript: Arrow functions

junio 05, 2017 02:23

Arrow function es otra de las novedades de Ecma Script 6 y para quienes usamos C# nos va a resultar familiar la sintaxis.

Básicamente nos permite expresar cualquier función usando una flecha ( => ) hasta ahora podíamos hacer esto:

 

[1,2,3,4,5,6,7,8].filter(function(item) { 
  return item > 4 ;
});

con ES6 se puede hacer así:

[1,2,3,4,5,6,7,8].filter( item => { 
  return item > 4;
});

En definitiva no es más que una forma corta de declarar una función anónima.

Parámetros

Con respecto a los parámetros podemos hacer varias cosas dependiendo de si tenemos parámetros, o cuántos tengamos uno o muchos, por ejemplo.

cuando no tenémos  parámetros podemos poner los dos paréntesis o un guión bajo.

var a = () => { console.log("hola");}
var a = _ => { console.log("hola”);}

Cuando tenemos un único parámetro podemos usar o no los paréntesis

var a = (y) => { return y };
var a = y => { return y };

En cuando a varios parámetros siempre usamos los paréntesis

var a = (x,y) => { return x + y;}

Retorno implícito

En ciertas circunstancias las arrow functions crean el return por nosotros, es decir, no siempre es requerido utilizar return

var a = (x, y) => x + y;

Es equivalente a

var a = (x, y)=> { return x + y; }

En resultado

Usando arrow functions el primer ejemplo quedaría así:

[1,2,3,4,5,6,7,8].filter(item => item > 4)

Nos leemos.

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

Picando Código

Cómo jugar StarCraft Gratis en Linux

junio 04, 2017 04:01

WineHace poco publicaba que StarCraft original es ahora gratuito . En su momento todavía no era posible ejecutar StarCraft en Linux con Wine de manera directa. Pero estuve siguiendo el avance del bug que no permitía que funcionara y los resultados de la base de datos de aplicaciones de Wine, y se resolvió. Ya hay una forma relativamente sencilla de jugar StarCraft en GNU/Linux con Wine:

Wine es una capa de compatibilidad capaz de ejecutar aplicaciones Windows en varios sistemas operativos POSIX, como Linux, macOS y BSD. En vez de simular lógica interna de Windows como una máquina virtual o emulador, Wine traduce llamadas a la API de Windows en llamadas POSIX al vuelo, eliminando las penalizaciones en rendimiento y memoria de otros métodos y permitiéndote integrar aplicaciones de manera limpia en tu escritorio.

La versión estable actual de Wine es la 2.0.1. Pero el bug fue corregido en Wine Staging (2.8), la rama de testing con arreglos de bugs y funcionalidades que no han sido integradas en la rama de desarrollo. Su instalación es bastante sencilla, ofrecen repositorios para Debian, Fedora, Ubuntu, Linux Mint y macOS. Obviamente en ArchLinux también está disponible por medio de AUR.

En Debian agregué el repositorio, actualicé apt e instalé winehq-staging. Wine Staging puede convivir con otras versiones de Wine, pueden leer más sobre su uso en la wiki. En mi caso había desinstalado Wine al ver que no funcionaba con StarCraft, pero eliminé el directorio .wine de mi home por las dudas al instalar wine-staging. El paquete instala Wine Staging en /opt/wine-staging, por lo que para ejecutarlo debemos usar /opt/wine-staging/bin/wine  o agregar la ruta a nuestro path.

Instalando StarCraftUna vez instalado wine-staging, podemos descargar el archivo de instalación de StarCraft clásico desde el sitio oficial. Lo ejecutamos con wine staging:

$ /opt/wine-staging/bin/wine StarCraft-Setup.exe

Y vamos a ver la familiar pantalla de instalación. Puede demorar un rato porque tiene que bajar todos los archivos. Una vez finalizado, el directorio de StarCraft ocupa unos 3,6GB.

Concluido este proceso, vemos un botón de “Launch StarCraft”. Si todo salió bien, al presionarlo vamos a poder disfrutar de este clásico de estrategia en tiempo real en nuestro sistema GNU/Linux de manera legal y gratuita. Incluye el original y la expansión StarCraft: Brood War.

También podemos ejecutar el juego desde el directorio de instalación:

$ /opt/wine-staging/bin/wine ~/.wine/drive_c/Program\ Files\ \(x86\)/StarCraft/StarCraft\ Launcher.exe

Obviamente es mucho más práctico agregar estas cosas al path, crear accesos directos y demás.

Al ejecutar StarCraft viajé en el pasado (aunque no hace TANTO que jugábamos StarCraft y WarCraft III en LAN con DM, DiegoTHX y otros amigos), e incluso volví a ver la animación de la presentación.

StarCraft Intro

StarCraft Home

StarCraft Campaigns

StarCraft Gameplay

StarCraft - Terrans

StarCraft Terran Campaign

StarCraft Terran Campaign

Todo funciona perfecto, incluso conocí el mítico Battle.net que nunca había podido ejecutar en Linux antes:

StarCraft Battle.net

Lo que me queda es ver si juego un rato para volver a familiarizarme, y convencer a algún amigo más de instalarlo y encontrarnos en LAN. Lo de Battle.net se ve interesante, pero no sé si estoy al nivel para jugar por ahí y no ser humillado. Si alguien me quiere agregar de amigo y jugar alguna partida amistosa, mi nombre de usuario es (¡sorpresa!) picandocodigo.

Ahora a esperar que salga StarCraft: Remastered, y ver cuánto demora Wine en hacerlo funcionar correctamente para nuestros sistemas. Sería interesante que le dieran el mismo tratamiento a WarCraft III y su expansión Frozen Throne. ¡Estaría genial poder volver a jugarlos con gráficos HD!

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

Blog Bitix

Usar la base de datos NoSQL MongoDB con Java

junio 04, 2017 11:00

MongoDB
Java

En un artículo anterior hacía una pequeña introducción a la base de datos NoSQL MongoDB comentando sus características, como empezar a usarla con Docker y como lanzar algunos comandos para crear bases de datos y colecciones junto las operaciones básicas de inserción, actualización, eliminación y búsquedas con consultas desde la shell que ofrece MongoDB para esta base de datos que guarda documentos.

La shell sirve para hacer estas consultas pero el caso de uso principal es usarlo desde una aplicación con alguno de los lenguajes de programación para los que se proporciona un controlador. MongoDB se puede usar desde cualquiera de los lenguajes de programación más populares entre ellos Java. En este artículo muestro con un ejemplo como realizar las operaciones que utilizaba desde la shell de MongoDB pero desde una aplicación Java.

Para el ejemplo uso una aplicación Java con Spring Boot en la que hay que incluir la dependencia org.springframework.boot:spring-boot-starter-data-mongodb que proporciona el acceso a esta base de datos. Para comunicación con el servidor de MongoDB hay que crear una instancia del cliente de la base de datos, una instancia de la clase MongoClient para lo que simplemente necesitamos el host y puerto en la que está arrancado el servidor. En el caso del ejemplo localhost y el puerto de MongoDB que por defecto es 27017. Al usar Spring defino un nuevo servicio en el contenedor de dependencias y la inyecto en la clase de la aplicación para hacer uso de ella, dado lo simple que es el ejemplo en el mismo archivo de código fuente.

Los documentos en MongoDB están en formato JSON, como Java no ofrece de una sintaxis sencilla de literales de listas y mapas para el uso de documentos JSON hay que usar algunas clases de la API de MongoDB para la construcción de los documentos, para las búsquedas en las que indicaremos filtros usaremos la clase Filters, Updates para las actualizaciones y para la construcción de documentos de datos y actualizaciones Document. Con la instancia de la clase cliente que da acceso a la base de datos MongoDB desde Java se listan las bases de datos, colecciones y lanzan los comandos.

Con la referencia a una colección se realizan las operaciones de inserción de un documento, actualización del documento completo o de una parte, eliminación de un documento y búsqueda de documentos con una consulta.

La instancia del servidor de MongDB la inicio usando Docker con un archivo de Docker Compose y el comando docker-compose up. En la serie de artículos sobre Docker que escribí puedes aprender como empezar a usar Docker y adquirir un conocimiento hasta un nivel intermedio.

El resultado en la terimnal de ejecutar el ejemplo con el comando gradlew run es el siguiente donde se muestran las bases de datos, la colección users creada en el ejemplo, los usuarios de la colección y una búsqueda de un usuario, el resultado de actualizar la propiedad de un documento y finalmente el número de documentos en la colección.

Spring ofrece en su API mediante el proyecto Spring Data MongoDB algunas clases adicionales para facilitar el acceso y obtención de datos de MongoDB. Entre estas clases están MongoTemplate, MongoOperations y MongoRepository cuyo uso puede consultarse en su manual de referencia.

En el libro MongDB in Action comentan más detalladamente y de forma más completa las opciones que se pueden utilizar en el lenguaje de consulta, muchas de las opciones son equivalentes a las que son conocidas del lenguaje SQL de las bases de datos relacionales.

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

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

Blog Bitix

Introducción a la base de datos NoSQL MongoDB

junio 04, 2017 10:30

En unos pocos años las bases de datos NoSQL se han dado a conocer ampliamente. Resuelven algunas problemáticas para las que las bases de datos relacionales más longevas no proporcionan una solución totalmente satisfactoria como el escalado horizontal y un modelo de datos normalizado en varias tablas, filas y columnas predefinidas y significativamente diferente del modelo de datos usados por las aplicaciones. La base de datos NoSQL MongoDB que almacena documentos se adecua mejor a cierto tipo de requerimientos.

MongoDB

Los sistemas de información empleados tradicionalmente en las aplicaciones son las bases de datos relacionales como MySQL, PostgreSQL u otras comerciales. Las bases de datos relacionales con sus propiedades ACID seguirán usándose pero desde hace unos años están surgiendo y empleándose para algunos casos otro tipo de bases de datos conocidas como NoSQL. Dentro de las bases de datos NoSQL hay varios tipos: clave-valor, de documentos, grafos, … Dentro de la categoría de bases de datos NoSQL orientadas a almacenar documentos una de las más destacadas es MongoDB.

Al igual que las bases de datos relacionales MongoDB posee un shell JavaScript con el que lanzar todas las operaciones anteriores que junto con Docker la experimentación de todo lo anterior será una tarea no demasiado complicada. Bastará descargar la imagen de MongoDB para Docker, iniciar un contenedor, iniciar una shell bash en el contenedor y la shell de MongoDB desde la que lanzar las consultas. Siguendo la seríe de artículos sobre Docker en unas pocas horas puedes usarlo.

La base de datos MongoDB al igual que muchas NoSQL no soporta completamente las propiedades ACID de las bases de datos relacionales, no soporta transacciones aunque sí garantiza que las operaciones individuales son atómicas, pero a cambio proporciona otras propiedades que para algunas necesidades podemos considerar más adecuadas como mayor escalabilidad horizontal, alta disponibilidad, réplicas y shards para distribuir los datos entre varias instancias. MongoDB guarda la información en documentos con formato JSON.

En vez de tablas, filas y columnas los términos en MongoDB son colecciones de documentos, los documentos son la unidad mínima de información almacenable y propiedades en esos documentos. Una propiedad interesante de los documentos es que estos no tiene porque tener todos las mismas propiedades, aunque se recomienda que las propiedades sean siempre del mismo tipo. Los documentos hacen menos necesarios y complejos los ORM para convertir del modelo relacional usado en las bases de datos al modelo de objetos de la aplicación.

Se pueden almacenar los documentos anteriores en la misma colección de artículos aunque ambos no tengan las mismas propiedades, en una base de datos relacional sería más complicado y en el caso de que los datos fuesen desconocidos en el momento de definir el modelo obligaría a usar el modelo entity-atribute-value.

La información que en una base de datos relacional está en varias tablas y es necesario realizar varias consultas SQL para obtenerla en MongoDB está en un mismo documento siendo más sencilla de recuperar con la posibilidad de no estar tan normalizada y sin necesidad de hacer joins entre varias tablas. Para guardar los documentos anteriores de ejemplo en una base de datos relacional se necesitan varias tablas, una para los artículos y otras para los comentarios, etiquetas y adicionales para las relaciones N a M.

Algunas bases de datos NoSQL no necesitan del potente lenguaje de consulta SQL de las bases de datos relacionales pero MongoDB proporciona su propio lenguaje de consulta diferente a SQL pero con muchas funcionalidades similares: proyecciones, agrupaciones, filtrado, agregación, ordenación, funciones lógicas, aritméticas, para fechas, para cadenas además de operaciones para realizar inserciones, actualizaciones de un documento completo o campos individuales y eliminaciones. Para que las búsquedas y filtrados tenga buen rendimiento en colecciones de documentos grandes también se pueden crear índices.

Estas son las operaciones CRUD ejecutadas desde la shell de MongoDB en una colección de artículos.

MongoDB proporciona controladores para acceder a la base de datos desde los lenguejes de programación más populares como muestro en el artículo Usar la base de datos NoSQL MongoDB con Java.

El libro MongoDB in Action es un buen material de referencia para dominar esta base de datos NoSQL con consejos prácticos de como guardar la información y como administrar la base de datos para replicar los datos en un cluster, escalar y otros temas administrativos como crear copias de seguridad, rendimiento, seguridad o monitorización.

La base de datos PostgreSQL es una de las mejores opciones en el ámbito de las bases de datos relacionales y el potente lenguaje SQL, las propiedades ACID o el PL/pgSQL entre otras funcionalidades hará que siga siendo una de las mejores opciones para almacenar de forma persistente la preciosa información. En los casos que la escalabilidad o la estructuración de la información en documentos se un factor determinante MongoDB es una buena opción. Ambas opciones no son excluyentes, según el caso estos dos sistemas de información se podrán combinar para obtener lo mejor de cada uno de ellos.

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

Blog Bitix

Así trata Pepephone a sus clientes

junio 03, 2017 10:00

Pepephone

El martes 30 de mayo Pepephone me enviaba y a todos sus clientes un correo informándome que el día anterior habían tenido una caída de servicio en el ADSL y que si había sido afectado que lo sentían. La caída del servicio había sido durante unas cuatro horas de la noche del día anterior y de la madrugada del mismo día. En mi caso por ese horario no había resultado afectado por la caída del servicio y si no llega a ser por el correo que Pepephone me envió no me hubiese enterado.

Este es el correo que Pepephone envió para informar a los clientes del ADSL y fibra de la incidencia.

Correo informativo incidencia Pepephone

Informaban de la caída del servicio junto con una breve disculpa pero también a modo de compensación y sin tener que solicitarlo un descuento en la siguiente factura por valor de un día entero del servicio aunque la incidencia solo fue durante unas horas y yo no había sido afectado, es más según explicaban en el correo posiblemente no todos los clientes habían sido afectados pero la compensación con el descuento la aplicarían a todos los clientes. Un aplauso para Pepephone por tratar así a sus clientes, lo que corresponde según la ley y algo más ya que creo que las condiciones para la compensación deben superar un importe y una duración mínima de la incidnecia. Muchas veces solo hablamos para quejarnos cuando algo no nos gusta algo pero no alabamos las cosas positivas. Aunque sería mejor que no hubiese habido caída de servicio, como se produjo la respuesta de Pepephone fue compensar a sus cliente sin que éstos lo pidan lo que es de muy agradecer.

Y la compensación no ha sido varios meses después sino en la siguiente factura que correspondía emitir unos días más tarde.

Descuento en la factura con la compensación

Esto forma de trato es una diferencia destacable de esta compañía con respecto a muchos de los otros proveedores de internet. Varias otras compañías lo que suelen hacer es sin que tu lo pidas subirte el importe de la factura ofreciendo más megas de bajada o subida, o más megas mensuales que puede que no te interesen y prefieras seguir con los mismos megas y con el mismo importe de la factura.

El ADSL de Pepephone, o de cualquier otro operador, no ofrece mucha velocidad de descarga y de subida (yo obtengo 10 MB de bajada y 1 MB de subida) pero es más que suficiente para navegar y para hacer descargas P2P vía torrent. Salvo momentos muy puntuales en los que en una descarga si quiero que vaya más rápido la velocidad del ADSL es más que suficiente. Yo no soy un usuario que realice muchas descargas y cuando las hago con la Raspberry Pi en una noche no hay nada que no pueda descargar todo lo que le eche aún a la velocidad de descarga de 1 MiB/s, no soy un usuario que descarga mucho pero si un usuario que usa internet bastante, si para mi es suficiente para usuarios que no le den tanto uso a internet también debería ser suficiente. Y si eres de los afortunados que tiene cobertura de la fibra de Pepephone es la fibra con mejor precio aún con su coste de instalación, con la menor cuota mensual posterior en unos pocos meses queda compensada.

En el artículo Eligiendo proveedor de internet, finalmente Pepephone explicaba mis motivos y comparándola con otras opciones que barajé para decidirme por un proveedor. Finalmente fue Pepephone por el precio aun con su coste de instalación al cabo de unos meses compensa siendo internet un servicio que no se cambia cada pocos meses, pero no solo fue el precio también consideré el trato que da Pepephone a sus clientes y con correos como el anterior se demuestra. Donde otros operadores te suben la factura de forma unilateral anualmente o incluso más de una vez al año sin que lo quieras Pepephone hace una compensación sin que lo pidas, para todos los clientes y por más tiempo de lo que resultó la caída del servicio.

Resulta que nos quejamos de los precios de algunos operadores o del trato que ofrecen a los clientes pero luego los usuarios siguen contratando con esas compañías cuando hay otras que tratan a sus clientes con respeto. No hacen regalos ni promociones pero ofrecen un precio ajustado y razonable y un trato respetuoso. En internet está Pepephone y en el sector de las eléctricas están empresas como HolaLuz o Pepeenergy que ofrecen energía 100% renovable y de las que también he oído hablar bien, cambiar de compañía que ofrece un servicio no se hace todos los días pero si en algún momento tienes que hacerlo considera alguna de estas u otras compañías con estos valores y no te dejes engatusar por promociones envenenadas destinadas más bien a engañar a los clientes. Como consumidores tenemos también una responsabilidad.

¿Tu proveedor de internet te trata así?

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

Adrianistán

WebAssembly para tontos (usando Rust)

junio 02, 2017 09:10

Una de las cosas que más me han sorprendido del mundo web en estos años fue el proyecto WebAssembly. Un proyecto que pretendía traer un bytecode unificado para navegadores. Un proyecto que permitiría compilar prácticamente cualquier lenguaje a la web sin necesidad de tocar JavaScript.

El proyecto surgía de iniciativas fracasadas de Google (PNaCl) y de Mozilla (asm.js). Pero a este proyecto se unieron Microsoft y Apple, por lo que la compatibilidad estaba asegurada.

WebAssembly es un bytecode (como el de Java o el de .NET) que puede ser ejecutado por un navegador, cada navegador implementa su máquina virtual. También es posible usarlo en otros entornos relacionados con el mundo JavaScript como Node.js. Sin embargo entre los objetivos de WebAssembly está no estar atado a JavaScript, por lo que la especificación puede ser implementada por cualquier otro tipo de entorno. Actualmente WebAssembly no tiene recolector de basura y no tiene acceso directo a las Web API. No obstante, sigue siendo un proyecto interesante. Vamos a ver como usar WebAssembly con Rust.

Instalando Rust y Emscripten

Instala Rust, la versión estable es compatible con lo que queremos. Recomiendo usar Rustup.

curl https://sh.rustup.rs -sSf | sh

El paso clave es instalar un nuevo target, el target de WASM32 (WebAssembly de 32 bits).

rustup target add wasm32-unknown-emscripten

Por supuesto también hace falta instalar Emscripten.

Descarga la versión portable de Emscripten aquí. Descomprime y ejecuta

source ./emsdk_env.sh
emsdk update
emsdk install latest
emsdk activate latest
source ./emsdk_env.sh
emcc -v (para comprobar)

Emscripten ya estará instalado junto con Clang y las piezas claves de LLVM necesarias.

Escribiendo el programa en Rust

Vamos a escribir un programa simple. Un hola mundo.

 

fn main(){
    println!("Hola mundo - WebAssembly + Rust");
}

Compilamos con rustc

 

rustc --target=wasm32-unknown-emscripten main.rs -o main.html

Esto genera diversos archivos: main.html, main.js, main.wasm y main.asm.js (para compatibilidad con navegadores que no tienen WebAssembly). El fichero .wasm contiene el bytecode, si intentas abrirlo verás que es ilegible. Sin embargo, Chrome, Firefox, Edge, Safari y Node.js entenderán ese archivo. Probamos el fichero main.html en Firefox (cuya última versión soporta WebAssembly por defecto):


Usando este sistema compilamos aplicaciones enteras. Si se ajustan ciertos parámetros de Emscripten y se usa una crate adecuada en Rust puede usarse para generar juegos 3D usando WebGL escritos 100% en Rust.

Cargas librerías en Rust desde JavaScript

En el paso anterior vimos como compilar a WASM aplicaciones enteras. Ahora vamos a compilar el código de Rust a una librería y vamos a cargarlo con JavaScript.

La librería va a ser muy simple:

#[no_mangle]
pub fn random_number() -> i32 {
    42
}

fn main() {

}

Ahora compilamos el fichero a WebAssembly

rustc --target=wasm32-unknown-emscripten random.rs

Ahora vamos a cargar el fichero random.wasm. Para ello usaremos la ayuda de random.js, que contiene el código necesario para cargar el fichero WASM así como definir los imports que el código Rust espera (variables de entorno, funciones globales, etc).

 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
	</head>
	<body>
		<script>
		var Module = {
			wasmBinaryFile: "random.wasm",
			onRuntimeInitialized: main,
		};
		function main() {
			var random_number = Module.cwrap("random_number","number",[]);
			alert(random_number());
		}
		</script>
		<script src="random.js"></script>
	</body>
</html>

Usando este sistema, podemos ir añadiendo código WASM poco a poco en nuestras webs.

 

Conclusión

 
Como vemos, ya es posible hoy día usar WebAssembly en nuestros proyectos. Para crear el código WebAssembly podemos usar Rust. El código WASM puede interactuar con el código JavaScript existente. ¿Qué opináis de WebAssembly? ¿Creéis que puede suponer un antes y un después en el mundo web o se seguirá usando JavaScript de forma masiva?

 

La entrada WebAssembly para tontos (usando Rust) aparece primero en Blog - Adrianistan.eu.

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

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

35 aniversario del Spectrum

junio 02, 2017 03:15

Un 23 de abril de 1982, Sinclair Research lanzaba en el Reíno Unido el ZX Spectrum. De manera que en este año 2017, conmemoramos su 35 aniversario, y fue uno de los motivos por los que mi felicitación de año nuevo, lo usaba. En algunos países de Europa, se presentó un poco después, y a […]

La entrada 35 aniversario del Spectrum aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Una sinfonía en C#

Material de mi charla sobre Blockchain, Smart Contracts y Azure

junio 02, 2017 01:49

El pasado Miércoles 24 de Mayo tuve el honor de una vez más participar de SGVirtual, en este caso con una charla sobre Blockchain, Smart Contracts y Azure.

El charla fue grabada como hace siempre la gente de Software Gurú.

 

El material que utilicé se puede bajar de mi repo de Github

Algunos links sobre el tema:

Nos leemos.

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

Picando Código

Probando KDE Plasma 5.10

junio 01, 2017 03:30

Recientemente se publicó Plasma 5.10, el nombre dado al entorno de escritorio antes conocido como KDE. Actualmente “KDE” se usa ahora para englobar todos los proyectos de su comunidad software libre, incluyendo el Framework KDE y varias aplicaciones.

Plasma busca dar una experiencia simple por defecto, y poderosa cuando así se requiere. Quienes lean el blog desde hace un tiempo recordarán que fui usuario KDE por muchos años. Pero en 2013 me pasé a GNOME cuando volví a Debian. Desde entonces he estado mirando de lejos cómo viene evolucionando el entorno Plasma, pero la presentación en video de su versión 5.10 me llamó mucho la atención:

Cómo probar lo más nuevo de Plasma – KDE Neon

KDE Neon es una distro GNU/Linux basada en Ubuntu LTS, que provee el software más reciente de KDE. Es la combinación ideal entre sistema estable y lo último de lo último para un escritorio Plasma. Lo interesante es que KDE Neon ofrece descargas de imágenes Live para probarlo e instalarlo. Así que descargué la imagen de User Edition – el software estable más reciente de KDE. También tenemos disponible versiones con el código más reciente en Git, estable e inestable, además de imágenes Docker. Los ISO se pueden quemar a un DVD, USB o levantar como imagen de booteo en una máquina virtual. En mi caso usé VirtualBox para esto último y jugar un rato con Plasma 5.

KDE Neon

Pantalla de booteo – KDE Neon

KDE Neon

KDE Neon – Escritorio limpio

Como es de esperarse, el escritorio es muy personalizable. Casi todo se puede configurar, pudiendo armar el entorno a gusto del usuario. Se ve todo bastante bien, y dan ganas de instalarlo del todo en el sistema… Ya teniendo el sistema más de un día, me avisó de algunas actualizaciones de seguridad, por lo que aproveché para ver el gestor de software.

KDE Neon - Software

KDE Neon – Software

KDE Neon - Paneles

KDE Neon – Paneles

En esta versión de Plasma se agregaron varias mejoras al panel de gestor de tareas, el escritorio (que acepta íconos además de widgets), controles multimedia en la pantalla de bloqueo, la habilidad de pausar la música en suspensión, mayor seguridad en la pantalla de bloqueo, mejoras en el soporte para pantallas táctiles, port a Wayland, y más. El applet de manejo de volúmen de audio cuenta con mejoras para elegir dispositivos o salida por auriculares y volúmen por aplicación:

KDE Neon - Volume

KDE Neon – Volume

Creo que casi todo lo que se puede personalizar a nivel visual está conectado directamente con KDE-Look para poder descargar temas nuevos directamente desde las vistas de configuración.

KDE Connect

Una de las tecnologías de KDE es KDE Connect, un proyecto para comunicarte a través de todos tus dispositivos. Por ejemplo, podemos recibir las notificaciones de nuestro teléfono en la computadora, controlar la música que reproducimos, y más. Por un lado tenemos KDE Connect en Plasma y por otro una aplicación KDE Connect en nuestro dispositivo Android. Funciona con un protocolo de comunicación seguro a través de la red, y permite crear plugins.

Usando la API de compartir en el teléfono, podemos enviar archivos a la computadora. Por ejemplo, saqué esta foto desde mi teléfono mientras escribía esto y la envié inmediatamente a la computadora:

KDE Connect - Compartiendo imagen

KDE Connect – Compartiendo imagen

La aplicación en Android es bastante básica, por ahora, y simple de usar:

KDE Connect en Android

KDE Connect en Android

KDE Connect se puede instalar desde F-Droid (la tienda y repositorio de aplicaciones software libre para Android) y Google Play Store. También hay extensiones para Firefox y Chrome/Chromium. Seguramente haya otras aplicaciones que permitan la comunicación bidireccional entre el teléfono y la computadora, pero KDE Connect es súper sencilla y funciona de maravilla. Se integra de manera tan transparente con el sistema que da gusto usarla.

Poder ver las notificaciones del teléfono en la computadora es bastante práctico. Si bien generalmente tengo las notificaciones muteadas, resulta práctico para casos particulares. También es excelente para ver los archivos de nuestro teléfono con el explorador de archivos al que estemos acostumbrados en nuestro sistema operativo. Podemos gestionar, manipular y transferir archivos de manera muy sencilla entre uno y otro.

También tenemos la funcionalidad que permite hacer sonar nuestro teléfono si lo perdimos dentro de la casa. Con la posibilidad de crear plugins sobre este protocolo, seguramente veamos más funcionalidades interesantes en el futuro:

KDE Connect - Plugins

KDE Connect – Plugins

Después de tanto tiempo usando GNOME, pensé que no volvería a considerar cambiar de entorno de escritorio. La mayor parte del tiempo pasamos dentro de las aplicaciones trabajando, y lo que necesitamos es que el entorno nos facilite el trabajo entre aplicaciones y la interacción con el sistema operativo. Pero viendo lo lindo que se está poniendo Plasma y las distintas personalizaciones y novedades, me entraron las ganas de volver a probarlo. No sé si llegaré a instalarlo en mi sistema de trabajo actual, pero está picando el bichito de volver a KDE…

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

xailer.info

Novedades de Xailer 5 (IX)

junio 01, 2017 10:38

Buenos días,

¡Y otro control más! Y seguro que más de uno lo ha echado de menos alguna vez. Y es la posibilidad de firmar documentos PDF con un certificado digital. Xailer 5 incorpora un nuevo componente de nombre TPdfSignTool que permite realizar esta tarea de forma muy sencilla, básicamente sólo hay que indicar el fichero origen, el fichero destino, el fichero del certificado y su clave. Eso es todo.

No obstante, la clase permite establecer exactamente donde deseamos ubicar visualmente el certificado o certificados y además permite que la fecha y hora de la firma esté sellada por una entidad autorizadora (‘time stamp authority’).

Y todavía hay más ….

¡Hasta pronto!

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

Picando Código

Capturas de pantalla en Firefox Nightly sin usar extensiones

mayo 30, 2017 07:00

Hace mucho tiempo que vengo usando Firefox Nightly como navegador web por defecto. Se trata de una versión con actualizaciones diarias que nos permite ir probando la tecnología de vanguardia. Además de los contenedores, y en general resultarme más ágil y liviano que Firefox estable, recientemente empecé a usar una nueva característica: Tomar capturas de pantalla.

Hasta hace no tanto, usaba o bien una extensión, o GIMP para capturas de cosas particulares. Pero en el caso de querer una captura completa de toda una página, usaba la extensión de Firefox Nimbus. La verdad que ofrecía mucho más características de la que necesitaba.

Pero esto no es más necesario desde una versión reciente de Firefox Nightly. Al actualizar nuestro navegador vamos a ver un ícono nuevo en la barra superior:

Firefox - Tomar captura

La primera vez que vemos este ícono, nos mostrará un tutorial sobre cómo usar la captura de pantalla:

Toma, guarda y comparte capturas de pantalla sin salir de Firefox

Toma, guarda y comparte capturas de pantalla sin salir de Firefox

Captura sólo lo que quieres - Haz clic y arrastra para capturar sólo una porción de una página. También puedes flotar para destacar tu selección

Captura sólo lo que quieres – Haz clic y arrastra para capturar sólo una porción de una página. También puedes flotar para destacar tu selección

Guarda tus imágenes a la web para compartirlas más fácilmente, o descárgalas a tu computadora. También puedes hacer clic en My Shots para encontrar todas las imágenes que has capturado

Guarda tus imágenes a la web para compartirlas más fácilmente, o descárgalas a tu computadora. También puedes hacer clic en My Shots para encontrar todas las imágenes que has capturado

Usa los botones en la esquina superior derecha para capturar el área visible de una ventana o capturar la página entera

Usa los botones en la esquina superior derecha para capturar el área visible de una ventana o capturar la página entera

Como ven, podemos capturar un área en particular, la parte visible de una página en nuestro navegador o toda la página. Como sucede desde hace bastante tiempo en las herramientas de desarrollo de Firefox, también podemos seleccionar capturar un nodo HTML. La interfaz de captura es bastante simple e intuitiva, e incluye una animación para seguir al cursor del mouse que hace acordar a xeyes:

Firefox Screenshots

Firefox Screenshots

Esta característica está basada en PageShot, parte de Test Pilot de Firefox. Test Pilot es una extensión de Firefox que nos permite probar experimentos que pueden o no ser incorporados eventualmente en el navegador.

Al guardar las capturas, se suben a un dominio de Mozilla en screenshots.mozilla.com.  De ahí podemos compartir los enlaces públicamente. De todas formas las imágenes tienen un vencimiento. Respecto a la privacidad, Mozilla comenta: Guardamos tus capturas en los servidores de Mozilla y tendremos acceso a esas imágenes. De todas formas, accederemos a tus imágenes únicamente cuando sea razonablemente necesario para la operación del servicio, como cuando alguien nos mande el link a una imagen usando nuestra característica de “reportar”, o para diagnosticar problemas. También analizaremos todas las capturas para mejorar Page Shot, por ejemplo, identificando el tamaño promedio y cantidad de imágenes capturadas por usuarios. Cabe aclarar que publicarlas públicamente a ese servidor es opcional, y podemos optar por descargar las capturas.

Una característica bastante útil que esperemos se mantenga en Firefox. Les sugiero probar Firefox Nightly para estar al tanto de esta y más funcionalidades nuevas en el navegador.

» 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