Poor Man's CQRS - BDD con MSpec

El artículo forma parte de una serie de artículos: [http://www.serrate.es/2011/11/22/poor-mans-cqrs/]

En el proyecto de Testing se ha utilizado Machine.Specifications (MSpec) para realizar Behavior Driven Development (BDD).

MSpec utiliza las cláusulas Establish/Because/It equivalente a Given/When/Then disponible en otros frameworks como SpecFlow.

La forma de uso seria la siguiente:

  • Establish: Se usa para establecer el estado inicial.
  • Because: Definimos la acción que vamos a testear.
  • It: Comprobamos que el resultado es el esperado.

Ver Más

Poor Man's CQRS - Domain Layer

El artículo forma parte de una serie de artículos: [http://www.serrate.es/2011/11/22/poor-mans-cqrs/]

Empezaremos detallando la parte principal de la aplicación: la capa de dominio. Aunque el ejemplo que nos ocupa consta simplemente de dos míseras clases, es importante que interioricemos algunos conceptos.

Diseñar un modelo de dominio es una tarea altamente compleja: definir las entidades que formaran parte de los agregados, el límite de éstos, qué entidad será el agregado raíz, distinguir value objects, etc. y, curiosamente, es la parte que menor relación tiene con CQRS.

Como siempre, la recomendación principal que puedo dar es la de leerse y empaparse del libro Domain-Driven Design de Eric Evans.

Ver Más

Poor Man’s CQRS

[Url del proyecto: https://github.com/mserrate/PoorMansCQRS]

Muchas veces cuando se habla de Command-Query Responsibility Segregation (CQRS) empiezan a surgir conceptos tales como: Event Sourcing, 2-Phase Commit, Snapshots, mensajería asíncrona, eventual consistency y multitud más que hacen que mucha gente piense que CQRS es una arquitectura compleja y que solo se puede utilizar para desarrollar aplicaciones tipo Amazon, Twitter y Facebook (vamos, los proyectos que nos surgen cada día…).

Por el contrario, soy de la opinión de que el uso de este patrón nos permite implementar de forma exitosa una aplicación basada en Domain-Driven Design (DDD). Y es que no se entiende CQRS sin DDD.

Es decir, no hace falta implementar Amazon para utilizar DDD y CQRS pero tampoco vayamos a implementarlo en la web de la panadería de nuestro cuñado en Villaconejo del Monte.

Ver Más

ASP.NET MVC 3: Evento CatDotNet

El próximo sábado 2 de Julio se realizará el evento inaugural de CatDotNet en el cual participaré conjuntamente con los siguientes ponentes:

  • José Miguel Torres que nos hablará de la gestión de dependencias con NuGet
  • Álex Casquete con las mejoras de productividad con Entity Framework 4.1
  • Marc Rubiño con Javascript y Ajax para desarrolladores de ASP.NET

Mi presentación tratará de algunas de las novedades de ASP.NET MVC 3, entre ellas:

  • Soporte a HTML5
  • Data Scaffolding
  • IDependencyResolver con Unity
  • Testing

Os podéis registrar en el siguiente enlance: 

https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032489264&Culture=es-ES


CatDotNet

CQRS: Evento en SecondNug

El próximo día 5 de mayo voy a estar con los chicos de SecondNug realizando un evento acerca de Command-Query Responsibility Segregation (CQRS) en el que hablaremos de:

  • Domain-Driven Design
  • Problemáticas en aplicaciones típicas n-layer
  • CQRS y conceptos: Commands, Events, Task based UI, etc.
  • Event Sourcing
  • Demo

Si queréis asistir sólo tenéis que registraros en el siguiente enlace:


Evento CQRS
¡Nos oímos en el evento!

NServiceBus: Introducción y ejemplo One-Way

A raíz de algunos proyectos e inmersión en los mundos de Service Oriented Architecture (SOA) y Event-Driven Architecture (EDA) he conocido este producto creado por Udi Dahan y que podemos encontrar en: http://www.nservicebus.com/

NServiceBus es una implementación de Enterprise Service Bus (ESB) para .NET y que se apoya en Microsoft Message Queue Server (MSMQ) como transporte y persistencia de colas.

Enterprise Service Bus es una arquitectura que nos permite el intercambio de mensajes entre aplicaciones y servicios de manera desacoplada entre los mismos proporcionando la fiabilidad y manejo de errores que éste tipo de aplicaciones requiere.

Las diferencias entre Enterprise Service Bus y Enterprise Application Integration (EAI) como BizTalk y cuando usar uno u otro daría lugar a muchas discusiones y está fuera del alcance de éste humilde artículo.

NServiceBus proporciona varios patrones de mensajería OOB como One-Way, Request/Response y Publish/Subscribe aunque nos permite extenderlo según nuestras necesidades.

Ejemplo con mensajería One-Way

En este ejemplo veremos la comunicación asíncrona punto a punto. Aunque parezca a priori que podríamos conseguir los mismos resultados con netMsmqBinding y WCF, y en cierta manera así es, la verdad es que NServiceBus nos abstrae de muchas configuraciones que deberíamos realizar a mano: creación de las colas en MSMQ, habilitar permisos necesarios, etc.

Primero vamos a crear el proyecto Messages (Class library) con una referencia a la librería NServiceBus.dll. A continuación definiremos nuestro mensaje:

1
2
3
4
5
6
7
8
9
10
namespace Messages
{
    /// <summary>
    /// Esta clase será enviada por NServiceBus
    /// </summary>
    public class MyMessage : IMessage
    {
        public string SomeString { get; set; }
    }
}

La interface IMessage no obliga a implementar ningún método, simplemente se usa como marcador para NServiceBus.

Ver Más

ASP.NET MVC: Componente Autocomplete de jQuery

En el artículo de hoy vamos a ver qué fácil es alimentar mediante Ajax y objetos JSON componentes jQuery desde ASP.NET MVC.

Para empezar, vamos a usar la CDN de google para importar las librerías que necesitamos: jQuery y jQuery UI más los ficheros de estilos para jQuery UI:

1
2
3
http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js
http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js
http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css

Seguidamente definimos en nuestra vista un label y una caja de texto:

1
<label for="txtTitulos">Titulos: </label><input type="text" id="txtTitulos" />

El código cliente para enlazar la extensión de jQuery a la caja de texto es la siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script type="text/javascript">
$(document).ready(function () {
$("#txtTitulos").autocomplete({
minLength: 3,
source: getData
});
});
function getData(request, response) {
$.ajax({
url: '/Home/GetData',
type: 'GET',
dataType: 'json',
data: { words: request.term },
success: function (data) {
response(data);
}
});
}
</script>

Como podemos ver, inicializamos la opción source con nuestro propio callback getData. En que realizamos la consulta a la action GetData del controller Home. Para más opciones y eventos del componente autocomplete mirad la documentación en la página de jQuery UI.

Finalmente nuestra action GetData queda de la siguiente manera:

1
2
3
4
5
6
7
8
9
10
public ActionResult GetData(string words)
{
var mySource = GetData();
var result = from s in mySource
where s.Title.Text.Contains(words)
select s.Title.Text;
return Json(result, JsonRequestBehavior.AllowGet);
}

Si os fijáis en el segundo parámetro de Json, indicamos que admitimos peticiones de tipo GET. Esto se debe indicar para evitar problemas de seguridad. Para más información consultad este post de Phil Haack.

Los datos de ejemplo los he sacado del rss de la página de ASP.NET. Os dejo el código para que no es creáis que miento:

1
2
3
4
5
6
7
8
9
10
11
12
private IEnumerable<SyndicationItem> GetData()
{
string feed = "http://www.asp.net/rss/news";
var req = WebRequest.Create(feed);
using (var reader = XmlReader.Create(req.GetResponse().GetResponseStream()))
{
var rssData = SyndicationFeed.Load(reader);
return rssData.Items;
}
}

ASP.NET MVC: Múltiples botones en el mismo formulario

Seguramente os habréis encontrando en ocasiones en que, dentro de un mismo formulario, necesitamos alojar varios botones de acción sobre el mismo.

Existen varias opciones de conseguir este objetivo, pero mí preferida, como amante de client scripting, es con jQuery.

A continuación mostramos la vista con un formulario definido y dos botones de submit:

1
2
3
4
5
6
7
8
9
10
11
12
13
<% using (Html.BeginForm()) { %>
<div>
<%= Html.LabelFor(m=> m.Name) %>
<%= Html.TextBoxFor(m => m.Name) %>
</div>
<div>
<%= Html.LabelFor(m => m.Description)%>
<%= Html.TextBoxFor(m => m.Description) %>
</div>
<input id="btnSave" type="submit" value="Guardar" />
<input id="btnGetNextRow" type="submit" value="Siguiente registro" />
<% } %>

Por el momento, nada nuevo. A continuación vemos como enlazamos el evento click a los botones:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
$(document).ready(function () {
$("#btnSave").click(function () {
var form = $(this).parent("form");
form.attr('action', '<%= Url.RouteUrl(new { Controller = "Home", Action = "Save" }) %>');
form.attr('method', 'post');
});
$("#btnGetNextRow").click(function () {
var form = $(this).parent("form");
form.attr('action', '<%= Url.RouteUrl(new { Controller = "Home", Action = "GetNextRow" }) %>');
form.attr('method', 'get');
});
});
</script>

Obtenemos una referencia al formulario con la instrucción: $(this).parent(“form”) y a continuación cambiamos los atributos action y method del formulario. De esta forma, hacemos submit a la acción que nos interesa en cada momento utilizando GET o POST según convenga.

NHibernate: Paginando con DetachedCriteria

El propósito de este post es ver cómo podemos paginar de forma óptima en servidor mediante el objeto DetachedCriteria. El objetivo es evitar que nuestros controles de presentación hagan el trabajo sucio paginando en memoria los resultados al obtener todos los elementos de la base de datos en cada petición.

Por trivial que parezca, para poder mostrar los resultados de forma amigable al usuario en, por ejemplo un grid, la consulta debe devolver los elementos de la página en cuestión y el número total de elementos. Para ello se requieren dos consultas, una para los elementos y otra para el total, pero no suena muy práctico realizar dos consultas separadamente no? La gracia aquí está en agrupar las dos consultas en una y así optimizar el rendimiento.

Nota: En caso de utilizar directamente un objeto de tipo ICriteria podríamos hacer uso directamente de las clausulas Future y FutureValue que hacen internamente hacen uso de Multi Queries como haremos aquí. Más información en éste post de Ayende.

Antes de nada… Que es DetachedCriteria? Pues no deja de ser un objeto criteria que definimos sin tener acceso a ISession. Esto nos permite definir nuestras consultas y poderlas ejecutar más tarde en cualquier otra parte dentro de un contexto de ISession.

A continuación vemos una declaración típica para DetachedCriteria:

1
2
3
4
5
6
7
8
9
// Creamos el objeto DetachedCriteria
var detachedCriteria = DetachedCriteria.For<Customer>("c");
// Agregamos filtros a la consulta
if (!string.IsNullOrEmpty(criteria.Name)
&& !string.IsNullOrWhiteSpace(criteria.Name))
{
detachedCriteria.Add(Expression.Like("Name", criteria.Name, MatchMode.Anywhere));
}

Más adelante, en un contexto de ISession, tenemos el código para la paginación. Vemos los comentarios en cada línea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public PagedList<T> FindPaged(DetachedCriteria criteria, int startIndex, int pageSize)
{
using (var session = GetSession())
{
// Clonamos nuestro DetachedCriteria
DetachedCriteria itemsCriteria = CriteriaTransformer.Clone(criteria);
// Especificamos los parámetros de paginación:
// 1) El índice del primer elemento a obtener
itemsCriteria.SetFirstResult(startIndex * pageSize);
// 2) El número máximo de resultados
itemsCriteria.SetMaxResults(pageSize);
// Transformamos nuestra consulta original para que nos devuelva el número de elementos
DetachedCriteria countCriteria = CriteriaTransformer.TransformToRowCount(criteria);
// Creamos un objeto MultiCriteria para agrupar las dos consultas
IMultiCriteria multiCriteria = session.CreateMultiCriteria();
multiCriteria.Add(itemsCriteria);
multiCriteria.Add(countCriteria);
IList multiResult = multiCriteria.List();
// En posición 0 de la lista tenemos los elementos paginados
IList pagedElementsUntyped = multiResult[0] as IList;
// Con la extensión Cast<T> obtenemos la lista genérica de resultados
IEnumerable<T> pagedElements = pagedElementsUntyped.Cast<T>();
// En posición 1 de la lista tenemos el total de elementos
int totalCount = Convert.ToInt32(((IList)multiResult[1])[0]);
// Finalmente devolvemos la clase PagedList que encapsula los dos resultados
return new PagedList<T>(pagedElements, totalCount);
}
}

La clase PagedList es simplemente un contenedor de los resultados:

1
2
3
4
5
6
7
8
9
10
11
12
public class PagedList<T>
{
public IEnumerable<T> Items { get; protected set; }
public int TotalItems { get; protected set; }
public PagedList(IEnumerable<T> items, int totalItems)
{
this.Items = items;
this.TotalItems = totalItems;
}
}

A continuación mostramos como se termina haciendo la consulta a la base de datos meditante SQL Profiler:

1
2
3
exec sp_executesql N'SELECT top 5 this_.Id as CU1_0_0_, this_.Name as CU2_0_0_ FROM Customers this_ WHERE this_.Name like @p0;
SELECT count(*) as y0_ FROM Customers this_ WHERE this_.Name like @p1;
',N'@p0 nvarchar(6),@p1 nvarchar(6)',@p0=N'%name%',@p1=N'%name%' 

En este pequeño post hemos visto como con IMultiCriteria y NHibernate podemos hacer paginaciones optimizadas en servidor para que nuestros controles de presentación no tengan que hacer los cálculos en memoria obteniendo todos los datos de la base de datos en cada petición.