Editando las connection strings “en caliente” de un proyecto ASP.net

Un problema peculiar con el que me he encontrado recientemente tiene que ver con dos equipos con la misma base de código y un punto de sincronización común, que en este caso es o bien dos bases de datos distingas del mismo servidor, o a la misma base de datos con diferentes credenciales, en un gráfico como el que se muestra.

Capture

Para guardar la configuración de la base de datos recurrimos habitualmente al apartado connectionStrings de nuestro fichero web.config. Dicho fichero cuenta además con diferentes transformaciones según la configuración de build seleccionada, como muestra la siguiente imagen:

Capture_debug

Pero… las transformaciones solamente se ejecutan al desplegar un proyecto…

El hecho de no poder ejecutar las transformaciones en tiempo de compilación no nos permite depurar nuestra solución con las cadenas de conexión necesarias, y, aunque existe una manera de transformar el fichero web.config durante la compilación, quería buscar una aproximación diferente.

Editando el objeto ConnectionStrings

Dentro del código de nuestra aplicación disponemos del objeto ConfigurationManager.ConnectionStrings que nos da una colección de solo lectura en la que podemos acceder a los datos. Si intentamos escribir en dicha colección obtenemos la siguiente excepción:

An exception of type 'System.Configuration.ConfigurationErrorsException' occurred in System.Configuration.dll but was not handled in user code

Additional information: The configuration is read only.

Sin embargo si vamos al código fuente de ConnectionStrings veremos que el atributo connectionString tiene setter, con lo cual en teoría podemos fijar el valor:

public string ConnectionString {
    get {
        return (string)base[_propConnectionString];
    }
    set {
        base[_propConnectionString] = value;
    }
}

Si vamos un poco más abajo nos encontraremos con la clase ConfigurationElement, cuyo método IsReadOnly() se comprueba al intentar fijar un valor.

protected void SetPropertyValue(ConfigurationProperty prop, object value, bool ignoreLocks) {
if (IsReadOnly()) {
    throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
}

public virtual bool IsReadOnly() {
    return _bReadOnly;
}

Este valor IsReadOnly lee una variable _bReadOnly, y no sería maravilloso que pudiéramos editar esa variable y editar nuestras cadenas de conexión? Pues gracias a Reflection podemos hacerlo!:

ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[0];
var field = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(connectionString, false);
connectionString.ConnectionString = "CustomConnectionString";
field.SetValue(connectionString, true);

Tras nuestra edición podemos volver a establecer el atributo _bReadOnly a true restaurando el bloqueo de la escritura. Hemos de tener en cuenta que este proceso ha de realizarse lo antes posible en nuestra aplicación, así que yo usaría Startup.cs o Global.asax.cs (recordemos que este último desaparece con ASP.net vNext).

Cargando nuestras connection strings personalizadas

Una vez que sabemos que podemos cargar las connection strings en caliente, el siguiente paso es cargar el fichero que contiene las transformaciones:

string path = HostingEnvironment.MapPath("~/Web.TEAM1.config");
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList list = doc.DocumentElement.SelectNodes(string.Format("connectionStrings/add[@name='{0}']", "Title"));
XmlNode node = list[0];
string connectionStringToReplace = node.Attributes["connectionString"].Value;

En este caso cargamos el fichero de TEAM1, buscamos la cadena de conexión con la clave especificada y la asignamos a la variable connectionStringToReplace.

Código completo

private void ReplaceConnectionStrings(string team)
{
    string path = HostingEnvironment.MapPath(string.Format("~/Web.{0}.config", team));
    XmlDocument doc = new XmlDocument();
    doc.Load(path);

    foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings)
    {
        XmlNodeList list = doc.DocumentElement.SelectNodes(string.Format("connectionStrings/add[@name='{0}']", connectionString.Name));
        if (list.Count == 0) continue;

        XmlNode node = list[0];

        var field = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
        string connectionStringToReplace = node.Attributes["connectionString"].Value;

        field.SetValue(connectionString, false);
        connectionString.ConnectionString = connectionStringToReplace;
        field.SetValue(connectionString, true);
    }
}

Este código recorre todas las Connection Strings, y si encuentra una en nuestro fichero de transformaciones, la reemplaza.

Finalmente, directivas de preprocesador

Las configuraciones de Build nos permiten fijar ciertas directivas a nuestros proyectos, y estas directivas se aplicarán en tiempo de compilación. De esta manera si alguna de las dos claves está presente se sustituirán, en caso de que ninguna esté presente no se realizará una sustitución.

#if TEAM1
    ReplaceConnectionStrings("TEAM1");
#elif TEAM2
    ReplaceConnectionStrings("TEAM2");
#endif

A continuación se pueden ver dos ejemplos para los diferentes equipos.

Capture_team1

Capture_team2

Conclusiones

Esta solución nos da una manera efectiva de poder depurar nuestro código sin afectar el ciclo de vida del fichero web.config, sus transformaciones, y el comportamiento por defecto. El código agregado solamente se ejecutaría en caso de que alguna de las dos directivas se cumpliese, con lo cual podemos tener diferentes configuraciones para diferentes equipos.

Reflection es una característica que nos permite sacar mucho más de lo que un objeto nos ofrece públicamente, a costa de un impacto en rendimiento y requerir un mayor conocimiento de lo que estamos haciendo, de ahí a que se use con moderación.

Enlaces adicionales

Eliminando acoplamiento en un controlador ASP.net MVC

Cuando desarrollamos aplicaciones web podemos caer en el error de dar demasiada responsabilidad a nuestros controladores lo que nos puede traer problemas en el futuro al intentar refactorizar ese código.

En este artículo veremos cómo partiendo de una acción donde la carga de datos se realiza desde el propio controlador podemos reducir el acoplamiento a la manera de guardar los datos. Con ello conseguiremos mejorar la reusabilidad y legibilidad del mismo, así como permitir realizar pruebas unitarias o cambiar componentes de manera sencilla.

Código inicial

Nuestro primer código es un simple controlador con un método que lista un catálogo de libros. Este controlador contiene un método que lista un catálogo de libros. Usaremos directamente sentencias SQL contra una base de datos LocalDB.

public class HomeController : Controller
{
    public ActionResult Books()
    {
        List<Book> books = new List<Book>();
        SqlConnection connection = new SqlConnection(@"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True");
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = connection;

        connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        connection.Close();
        return View(books);
    }
}

El resultado es una lista de objetos de tipo Book, que es un POCO (Plain Old C# Object) que contiene dos campos, Title y Author. La principal desventaja, y es la que intentaremos resolver a lo largo de este artículo, es que presenta un fuerte acoplamiento con el gestor de base de datos, y si cambiamos a MySQL o MongoDB, por poner un ejemplo, nos veríamos obligados a reescribir la esta implementación.

Primera aproximación, patrón Repository

El objetivo de un patrón Repository es crear una capa de abstracción entre la lógica de negocio (representada en este caso por el controlador) y la lógica de base de datos (representada por el acceso a SQL). Dicha capa de abstracción nos permite probar nuestro controlador de manera independiente a los datos y a la manera de almacenar los mismos.

La implementación de un patrón repository la podemos realizar usando una interfaz y su correspondiente implementación:

public interface IBookRepository
{
    List<Book> GetAllBooks();
}

public class BookRepository : IBookRepository
{
    private SqlConnection _connection;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public BookRepository()
    {
        _connection = new SqlConnection(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        List<Book> books = new List<Book>();
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = _connection;

        _connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        _connection.Close();
        return books;
    }
}

El código de la implementación es el mismo, ya que seguimos usando SQL para el acceso a datos, sin embargo hemos creado una abstracción que nos permite realizar pruebas unitarias y dejar los detalles de la implementación del acceso a datos al Repositorio.

El código del controlador se reduce al código siguiente:

public class HomeController : Controller
{
    private IBookRepository _bookRepository;

    public HomeController()
    {
        _bookRepository = new BookRepository();
    }

    public ActionResult Books()
    {
        return View(_bookRepository.GetAllBooks());
    }
}

Pese a que el repositorio se inicia desde el controlador, podríamos usar una solución de inyección de dependencias como Ninject o crear nuestra propia solución para que la inicialización de las dependencias se realice fuera del mismo.

Reduciendo acoplamiento en nuestro Repositorio

Una vez tenemos separados el controlador y el repositorio, tenemos varias alternativas para mejorar la legibilidad y la facilidad de uso del código

LINQ to SQL

Usar LINQ to SQL nos permite realizar un mapeado directo entre nuestra tabla y una clase, así como una capa de abstracción adicional sobre nuestro repositorio.

public class LinqToSqlBookRepository : IBookRepository
{
    private DataContext _db;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public LinqToSqlBookRepository()
    {
        _db = new DataContext(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        Table<Book> book = _db.GetTable<Book>();
        return book.ToList<Book>();
    }
}

Para que el mapping funcione correctamente, hemos de decorar nuestro modelo con los nombres de las columnas equivalentes:

[Table(Name = "Table")]
public class Book
{
    [Column(Name = "Title")]
    public string Title { get; set; }
        
    [Column(Name = "Author")]
    public string Author { get; set; }
}

Esta aproximación nos da una capa de abstracción mayor, comprobación de tipos en tiempo de compilación, capacidad de debug, y facilidad de acceso, a costa de perder algo de flexibilidad y rendimiento.

Conclusiones y pasos adicionales

LINQ to SQL no es la única manera de agregar abstracciones a nuestros datos, también podemos usar sistemas más complejos como Entity Framework, NHibernate, o Massive, siendo este el último que he descubierto y al que espero dedicarle pronto un artículo. Cada capa de abstracción, como decíamos anteriormente, nos permite desacoplar el código que estamos usando, aumentar su facilidad para ser probado, y su legibilidad, a la vez que cumplimos con principios como el de responsabilidad simple.

El proyecto termina con 3 capas diferenciadas:

  • Capa de presentación (Controlador)
  • Capa de datos (Repositorio)
  • Capa de persistencia (SQL)

Podemos agregar capas de lógica de negocio (si queremos realizar validaciones sobre los datos antes de que lleguen a la base de datos) o de servicio (si tenemos varias interfaces para nuestra aplicación). Cada capa aumenta la complejidad de nuestra aplicación pero también aumenta nuestra capacidad para limitar las responsabilidades de cada clase.

Puedes ver el código completo en github

Lecturas adicionales

Extra: Código de creación de la base de datos y datos de ejemplo

El código de creación de la base de datos y de los datos de ejemplo también es muy simple (SQL)

CREATE TABLE [dbo].[Table]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [Title] NVARCHAR(50) NULL, 
    [Author] NVARCHAR(50) NULL
)
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('Hamlet', 'William Shakespeare')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('El Ingenioso Hidalgo Don Quijote de la Mancha', 'Miguel de Cervantes y Saavedra')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('La divina comedia', 'Dante Alighieri')

Adding multiple languages to a Windows Store app with Javascript and Angular

Leer este artículo en castellano aqui

Last thursday I could attend a debate organized by MSCoders Madrid user group, related with localization of apps in a web enfironment.

After the event I got interested in frontend localization with Javascript. As Karmacracy for Windows is a Javascript app, I decided to do some experimentation on localizing the user interface in the context of a Windows Store app, to be able to distribute it for other markets.

Detecting the system language

For a Windows Store app the first thing to do is to detect the sustem language. This can be archieved with the following piece of code:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

The culture is the language that is currently being used for the UI, in culture format. For example for Spanish of Spain would be es-ES, for US English would be en-US, and for British English would be en-GB. To be able to change this order and deploy our app, we must go to the control panel:

Captura de pantalla 2014-09-15 00.29.43

In this example we only need the language, not the culture, so we are going to get a substring of the culture getting en, es, de, etc.

Adding angular-translate

Angular-translate is a module that allows us to define key-value pairs for each language and perform the translation according to the configuration. For installing it, if we don’t use a package manager such as bower, we must download the last package from github and add it to our project.

Once installed, we must add it to the configuration of our app, in the section we define external modules (in this case the module is pascalprechtr.translate).

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finally, we configure the different languages by using the code we defined previously for getting the OS display language:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

     $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Also, in case the current language is not available, we set English by default

#Usage

For accessing our keys we don’t need any aditional configuration on our controllers, we just need to modify our views so they can access the localized information

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

If the language is set to English or other language not controlled, the result will be the following:

en

If the language is set to spanish, the result will be the following:

es

As it shows, is an easy way to localize our javascript apps for the Windows Store.

Recap and next steps

Angular-translate provides a simple way of localizing texts in our views and Windows provides the information we need for setting the current language of an app.

As an aditional step, we may try to localize winjs controls such as buttons, which work in a very different way. Angular-translate also supports loading the translations from a json files, an option that may be useful if we want to distribute those files for translation by 3rd parties.

Links

Agregando múltiples idiomas a una aplicación de Windows Store con Javascript y Angular

**Read this article in English here

El pasado jueves tuve la ocasión de asistir a una mesa redonda organizada por el grupo MSCoders relacionada con la localización de aplicaciones en entornos web.

Tras el evento, uno de los temas que más llamó mi atención fue la localización en la parte Javascript, y como tenía una aplicación ya en la Windows Store que usaba ese lenguaje, me pareció interesante intentar localizarla para poder ofrecerla en otros mercados.

Detectando el idioma del sistema

Para una aplicación Windows 8 el primer paso es detectar el idioma del sistema, y eso lo podemos hacer de la siguiente manera:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

En este caso tomaremos la lista de lenguajes preferentes, y de esa lista obtendremos el primer elemento. Para poder cambiar el orden de los elementos y probar los diferentes lenguajes, podemos cambiarlo en el panel de control:

Captura de pantalla 2014-09-15 00.29.43

El resultado se muestra en formato cultura, es decir, español de España se mostraría como es-ES, e inglés de EEUU se mostraría como en-US. Para nuestro ejemplo inicial, solamente necesitamos el idioma, con lo cual hacemos un substring y obtenemos en o es respectivamente.

Agregando angular-translate

Angular-translate es un módulo de angular que nos permite definir de manera las claves y los valores para cada lenguaje, y realizar la traducción en función de la configuración. Para instalarlo, si no contamos con gestores de paquetes como bower, es tan sencillo como descargar el último paquete de github y agregarlo a nuestro proyecto.

Una vez instalado, tendremos que agregarlo a la configuración de nuestra app, en el apartado en el que definimos módulos externos en este caso pascalprecht.translate:

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finalmente, configuramos los diferentes idiomas usando el código que hemos visto anteriormente para seleccionar un idioma acorde con el sistema operativo:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

    $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Además, en caso de que el sistema tenga un idioma no controlado, estableceremos el inglés por defecto.

Uso

Para acceder a nuestras claves no necesitamos realizar ninguna configuración adicional en nuestros controladores, solamente necesitamos modificar nuestras vistas para que accedan a la información localizada:

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

En caso de que tengamos el idioma establecido a inglés (o a cualquier idioma no controlado), se mostrará el siguiente resultado:

en

En caso de que el idioma esté establecido a español, el resultado será diferente:

es

Como se ve, es una manera sencilla de poder localizar nuestras aplicaciones en javsacript para Windows Store

Conclusiones y pasos adicionales

Angular-translate proporciona una manera sencilla de localizar textos en nuestras vistas, por otra parte, Windows proporciona, a través de su API, la información que necesitamos para saber en qué idioma mostrar una aplicación.

Un paso adicional sería localizar controles winjs como los botones, que funcionan de manera diferente. Por otra parte se podría sacar un fichero de traducciones fuera de la configuración en formato json, útil si queremos distribuir esos ficheros para su procesamiento.

Enlaces adicionales

Artículo Invitado: ECMAScript 6 y la nueva era de JavaScript por @CKGrafico

Comenzamos con este artículo una nueva sección llamada “Artículos Invitados”, en este caso tengo la suerte de contar con Quique Fernandez Guerra, Microsoft Student Partner y desarrollador Javascript:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Quique es un usuario muy activo de comunidades de desarrollo frontend, y le hemos visto en varios hangouts mostrando su experiencia, así que le he pedido que nos cuente sus impresiones de lo que está por venir en la nueva versión del estandar ECMAScript 6, en el cual se basarán las próximas versiones de Javascript. A continuación sus impresiones


Desde siempre se ha considerado a JavaScript cómo un lenguaje simplón, es seguramente uno de los lenguajes actuales más sencillos de aprender, pero además es conocido por no ser muy completo (ya sea por la manera de trabajar con las clases, o los artículos sobre ‘JavaScript the weird parts’).

Por otro lado, en los últimos años JavaScript a empezado a tener más importancia hasta el punto que se ha vuelto el único lenguaje universal, es decir, lo encontramos en web, servidor, hardware, móvil, etc, cómo ya comenté en un artículo hace un tiempo.

Aún así el lenguaje sigue igual, de hecho ha llegado un momento en que la gente sabe mucho más sobre frameworks del lenguaje que del propio lenguaje. Está lleno de ofertas de trabajo en las que se pide conocimientos en jQuery y Backbone o Angular y por supuesto hay mucha gente aprendiendo directamente estos frameworks (Aprender un framework antes de saber el propio lenguaje…).

Por suerte, parece que con la nueva versión del estándar ECMAScript vamos a poder tomar más en serio JavaScript, aunque cómo siempre vamos a tener que esperar que todos los navegadores lo soporten. A continuación voy a explicar las partes que considero más importantes de esta nueva versión.

Declaración let

Ahora podemos declarar variables que existan solo en un bloque de código, entendiendo por bloque de código desde una función hasta un bucle o una condición.


if(1) {
var a = 5;
let b = 6;
console.log(a,b); // 5 6
}

console.log(a,b); // b is not defined

Constantes, ¡¡Sí constantes!!

Ya era hora de poder utilizar constantes en nuestro apreciado JavaScript, muy sencillas de utilizar igual que en otros lenguajes.

const PI = 3.14;
console.log(PI); // 3.14

function test() {
 console.log('test', PI); // test 3.14
}

test();

PI = 6; // Error!!

Arrow functions

Si trabajas con lenguajes cómo C# que tienen lambda verás que es algo parecido, que se ha traído a JavaScript.

let simple = a => a / 2;
console.log(simple(8)); // 4

let complex = (a, b) => {
 if (a < b) {
 return a;
 }
 return b;
}

console.log(complex(3,6)); // 3

Valores por defecto en parámetros

Otro ejemplo más de algo que tienen casi todos los lenguajes y JavaScript aún no lo tenía, pero ya está aquí.

function test(a, b = 10) {
 return a + b;
}

console.log(test(1)); // 11
console.log(test(1,2)); // 3

Rest parameters

Nos va a ser muy útil cuando no sepamos el número de parámetros exactos, muchas veces usábamos arguments para eso, pero ahora vamos a tenerlo mucho más fácil.

function test(a, b = 1, ...c) {
 return a + b + c.length || 0;
}

console.log(test(1)); // 2
console.log(test(1,10,1,1,1,1)); // 15

Pero no solo eso, también lo vamos a poder utilizar en un array o al llamar a una función.

let arr = [4, 5, 6];
let numbers = [1, 2, 3, ...arr, 7, 8];

console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8]

Object literals

Simplificaremos los objetos, de manera que no haya que poner información irrelevante.

// ECMA 5
var world = 'world';
var obj = {
 world: world,
 hello: function() {
 console.log('hello', this.world);
 }
};

obj.hello(); // hello world

// ECMA 6
let world6 = 'world';
let obj6 = {
 world6,
 hello() {
 console.log('hello6', this.world6);
 }
};

obj6.hello(); // hello6 world

for..of

La evolución lógica del for..in

// ECMA 5
var arr = ['a', 'b', 'c'];
for(var i in arr) {
 console.log(arr[i]); // a, b, c
}

// ECMA 6
let arr6 = ['a', 'b', 'c'];
for(let i of arr6) {
 console.log(i); // a, b, c
}

Generadores

Un nuevo tipo de función que nos ayuda a crear un iterador de manera fácil, utilizan yield en vez de return que es una nueva palabra reservada.

function* range(start, end) {
 for (let i = start; i <= end; i++) {
 yield i;
 }
}

var ranger = range(1,10);

var res = {
 value: null,
 done: false
};

while(!res.done){
 res = ranger.next();
 console.log(res.value, res.done);
}

Symbol

symbol es un nuevo tipo de dato y Symbol() nos devuelve un objeto único de tipo symbol, pensado para tener objetos o métodos que son distintos de los demás, sería un sustituto a usar cadenas para los nombres de los métodos por ejemplo.

let myMethod = Symbol();
let obj = {
 [myMethod]() {
 console.log('Soy único e irrepetible');
 }
};

obj[myMethod](); // Soy único e irrepetible
console.log(typeof myMethod); // symbol

Map

El objeto Map  es un objeto de clave / valor, la mejor manera de entenderlo es ver un ejemplo.

let map = new Map();
let arr = [];
map.set('string', 'Ola k ase');
map.set(arr, [1, 2, 3, 4]);
map.set(typeof 8, 'I\'m a number');

console.log(map.size); // 4

console.log(map.get('string')); // Ola k ase
console.log(map.get(typeof 1)); // I'm a number
console.log(map.get([])); // undefined -> arr !== []
console.log(map.get(arr)); // [1, 2, 3, 4]

Set

Sirve para poder crear algo parecido a las listas en otros lenguajes, aunque aún bastante simple.

let set = new Set();
set.add('test');
set.add(8);
set.add('Quique');

console.log(set.size); // 3
console.log(set.has(8)); // true

set.delete('Quique');

set.forEach(function(value) {
 console.log(value); // test 8
});

Clases

Vamos a tener clases en condiciones, más o menos van a hacer lo mismo que hasta ahora pero vamos a tener una sintaxis más sencilla para implementarlas.

class Human {
 constructor(name = 'anonymous') {
 this.name = name;
 }

 hello() {
 console.log('Welcome to the world ' + this.name);
 }
}

class Male extends Human {
 constructor(name) {
 super(name);
 this.sex = 'male';
 }

 get age() {
 return this._age;
 }

 set age(age) {
 this._age = age;
 }
}

let me = new Male('Quique');
me.hello();
me.age = 1;
console.log(me.age); // 1

Módulos

Ha llegado la hora de poder crear partes de nuestro código por separado e importarlas cuando nos sea conveniente, para no cargarlo todo de golpe y trabajar de una manera ordenada.

// number.js
module 'number' {
 let num = 8;
 export class Number {
     constructor() {
         console.log('The number is: ' + num);
     }
 }

}

// app.js
module number from '/number.js';
import Number from 'number';

var n = new Number(); // The number is 8

Templates

Una de las cosas que más he usado este último año en JavaScript han sido los templates, sobretodo trabajando Handlebars, pues ahora mismo se convierten en algo propio de este lenguaje.

let name = 'Quique', twitter = 'CKGrafico';
let template = `Hello, this is ${name}, find my on ${twitter}`;
// Nota, fíjate en las ` que no es lo mismo que '
console.log(template); // Hello, this is Quique, find my on CKGrafico

Estas son las cosas más destacables que trae la nueva versión, puedes encontrar la lista entera en su especificación.

Mientras esperas a que sea compatible en los navegadores puedes trabajar con ECMA6 en ES6 fiddle (un sandbox) o utilizar un pequeño transpiler llamado Traceur que te permite trabajar en ECMA6 y compilar a ECMA5

 


Si tienes preguntas o comentarios no dudes en dejarlas en la sección de comentarios, y si tienes más información sobre Quique, aquí tienes algunos datos de contacto:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Creando un motor de inyección de dependencias con C#

Read this article in English: Creating a Dependency Injection in C#

De acuerdo con la Wikipedia, la inyección de dependencias es un patrón de diseño de software que nos permite seguir el principio de inversión de dependencias mediante inversión de control, es decir, definir las dependencias de una clase desde fuera de la misma. En el caso de C# tenemos a nuestra disposición varios proyectos que generan todas las dependencias necesarias para nuestros objetos. Uno de estos es Ninject, un motor open-source con una sintaxis simple y plugins para ASP.net MVC y SignalR.

En este artículo veremos cómo funciona un motor de inyección de dependencias creando uno propio, basado en la sintaxis y la filosofía de Ninject.

Introducción

La inyección de dependencias nos ayuda a separar las responsabilidades entre las diferentes capas de nuestro código, así como mejorar la encapsulación y la facilidad de crear pruebas en nuestro código. Comencemos por un ejemplo simple, una lista de notas que nos permiten agregar una nota y guardarla llamando a _dataStorage, un objeto inicializado en el constructor:

public class NoteList
{
    private DataStorage _dataStorage;
    public NoteList()
    {
        _dataStorage = new DataStorage();
    }
    public void Add(string note)
    {
        if (string.IsNullOrEmpty(note))
        {
            throw new ArgumentException("Note cannot be empty");
        }

        _dataStorage.Save(note);
    }
}

DataStorage es una clase que escribe el contenido de una nota en disco, y que tiene el siguiente código para el método Save:

internal void Save(string note)
{
    using (StreamWriter writer = new StreamWriter("db.txt"))
    {
        writer.WriteLine(note);   
    }
}

El código de test se muestra a continuación:

//Arrange
var noteList = new NoteList();
var noteText = "myCustomNote";

//Act
noteList.Add(noteText);

//Assert
using (StreamReader reader = new StreamReader("db.txt"))
{
    var all = reader.ReadToEnd();
    Assert.IsTrue(all.Contains(noteText));
}

Como se puede ver, generamos un acoplamiento con DataStorage, esto significa que no podemos probar NoteList a menos que también probemos el comportamiento de DataStorage.

Eliminando el acoplamiento

El primer cambio que podemos hacer es abstraer DataStorage en una interfaz llamada IDataStorage. Seguidamente pasamos dicha interfaz como argumento en el constructor, en vez de inicializarla dentro de nuestra clase:

...
private IDataStorage _dataStorage;
public NoteList(IDataStorage dataStorage)
{
    _dataStorage = dataStorage;
}
...

El código de test cambia también, ya que pasamos a definir las dependencias fuera de la clase:

...
var dataStorage = new DataStorage();
var noteList = new NoteList(dataStorage);
var noteText = "myCustomNote";
...

Construyendo nuestro inyector

Una vez que tenemos una clase que recibe los parámetros como argumentos. Estos parámetros deben ser definidos e inicializados manualmente antes de llamar a nuestro constructor, con lo cual, el primer paso es generar dichos parámetros solicitando un tipo específico a nuestro Iniector. La primera versión es una clase estática con dos métodos y un diccionario interno para almacenar los mapeos, que tiene este aspecto:

private static Dictionary<Type, object> mappings
    = new Dictionary<Type, object>(); 

public static T Get<T>()
{
    return (T)mappings[typeof(T)];
}

public static void Map<T>(object o)
{
    mappings.Add(typeof(T), o);
}

Ahora podemos solicitar un objeto para la interfaz de nuestro test:

Injector.Map<IDataStorage>(new DataStorage());
var dataStorage = Injector.Get<IDataStorage>();

Este código presenta un problema, y es que siempre devolveremos el mismo objeto, y seguimos especificando el inyector en el constructor. Sería mucho más sencillo si el inyector devolviera una nueva copia de nuestro objeto, y si adicionalmente pudiéramos pedir nuestro objeto directamente desde el inyector:

Injector.Map<IDataStorage>(new DataStorage());
var noteList = Injector.Get<NoteList>();

Para poder llegar a estos resultados necesitamos una serie de mejoras importantes en nuestro inyector. El primer paso consiste en dividir el método Get en un método no genérico, de tal manera que podamos realizar llamadas recursivas como veremos más adelante:

public static T Get<T>()
{
    var type = typeof(T);
    return (T)Get(type);
}

El segundo paso consiste en cambiar la manera de almacenar los objetos, ya que en vez de una instancia, almacenaremos un tipo. De esta manera cambiamos el método Map para asegurarnos que no estamos almacenando un objeto específico, y que el tipo a almacenar hereda o implementa el tipo que se usará de clave:

public static void Map<T, V>() where V : T
{
    mappings.Add(typeof(T), typeof(V));
}

Finalmente, cambiamos nuestro método Get para invocar al constructor del tipo requerido, tras algunas comprobaciones adicionales:

private static object Get(Type type)
{
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();

    List<object> resolvedParameters = new List<object>();

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

    return constructor.Invoke(resolvedParameters.ToArray());
}

Veamos este código paso a paso: En primer lugar se resuelve el tipo, es decir, se comprueba si hay algún mapping disponible para el tipo especificado, en caso contrario se devuelve el mismo tipo:

private static Type ResolveType(Type type)
{
    if (mappings.Keys.Contains(type))
    {
        return mappings[type];
    }

    return type;
}

Una vez nos hemos asegurado de estar usando el tipo de dato correcto, el siguiente paso es recuperar el constructor, y su lista de parámetros (si existe).

...
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();
...

Si el constructor tiene parámetros, para cada uno de ellos se intentará resolver (es decir, se repetirá el proceso de manera recursiva), y si la resolución tiene éxito, se agregará a una lista de parámetros resueltos. En este caso el orden es muy importante ya que debe coincidir con el orden en el que se especifican los parámetros en el constructor**.

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

Finalmente se invoca el constructor con la lista de parámetros y se devuelve el objeto que se acaba de crear.

    return constructor.Invoke(resolvedParameters.ToArray());

La sintaxis final para obtener un nuevo objeto de nuestro inyector de dependencias es la siguiente:

Injector.Map<IDataStorage, DataStorage>();
var noteList = Injector.Get<NoteList>();

El resultado es una manera muy conveniente de generar un objeto sin preocuparnos de sus dependencias, que pueden estar definidas a un nivel mucho mayor.

Resumen

La inyección de dependencias no es un término oscuro ni mucho menos, nos permite crear arquitecturas desacopladas, y motores como el que acabamos de crear nos permiten crear la infraestructura necesaria a un nivel más alto, con lo cual el resto de las clases pueden tener solamente la lógica relacionada con su propio comportamiento (principio de responsabilidad simple) con un conjunto mínimo de dependencias. Por otro lado no es una pieza de software muy complicada, aunque en este caso es un ejemplo y el conjunto de casos cubiertos es mínimo.

Finalmente, las características de C# nos permiten hacer algo de metaprogramación al obtener tipos y parámetros de una función en tiempo de ejecución, así como crear objetos de manera dinámica, lo cual no está mal para un lenguaje fuertemente tipado. Sería interesante comprobar cómo podríamos crear una versión de este inyector en un entorno más dinámico y débilmente tipado.

Descarga el código!

Kata UpperCounter con Software Craftsmanship Madrid

El pasado martes 5 de agosto tuve la oportunidad de acudir a mi primer meetup de Software Craftsmanship Madrid, en el que se celebaba un coding dojo facilitado por Carlos Ble @carlosble. El objetivo de la sesión era hacer uso de un patrón diseñado por Robert “Uncle Bob” Martin llamado “Transformation Priority Premise” que nos lleva a una programación más genérica y funcional.

Tras sentarnos por parejas y escoger el entorno y el lenguaje de programación (En mi caso, C# con Visual Studio 2013 y XUnit como motor de pruebas) se desveló el objetivo de la kata:

Dada una cadena, devolver, en forma de array, las posiciones de dicha cadena cuyos caracteres sean la letra mayúscula

Ejemplos:
– A: {0}
– bA: {1}
– aBcdE: {1, 4}

Primera iteración, sin restricciones

Para esta primera iteración no teníamos ninguna limitación más allá de intentar resolver la kata. El resultado es el que se muestra en el vídeo:

El código completo, tanto del test como de la implementación se puede ver a continuación:

El enfoque es iterativo, utilizando un bucle para recorrer los caracteres de la cadena y la comprobación es bastante artesanal (a mejorar en la segunda iteración) y además, como teníamos tiempo, pudimos probar las Theories de XUnit, que nos permiten utilizar, en el mismo test, diferentes conjuntos de entrada y esperar diferentes resultados.

Segunda iteración, con restricciones

En esta segunda iteración teníamos una limitación importante: No podíamos asignar variables, ni modificar valores existentes. Esto nos deja sin la posibilidad de usar bucles (ya que vamos actualizando la posición del iterador) y forzando nuestro código a que sea más funcional. El resultado es el que se muestra:

El código completo es el siguiente, con el que intentamos seguir a rajatabla la indicación de no asignar o modificar los valores de las variables. En este caso el tiempo no permitió pasar de unos pocos test, pero se aprecia una diferencia notable por una parte en el test y por otra en el código de implementación:

Como nota adicional, gracias a @DanielRoz0 que me ha estado ayudando con la edición del vídeo, se pudo simplificar la comparación de una letra con su correspondiente mayúscula mediante el uso de la función char.IsUpper(source, index).

Información y enlaces: