BDD
14:02 | Author: Unknown

Otra vez Rob Conery. esto es más un tweet que un post. Rob escribe sobre BDD, un post interesante, lo voy a leer en profundidad y compararlo con las técnicas que nosotros utilizamos. Por ahora y como comentario BDD funciona, aporta claridad y se puede complementar con TDD (y buenos User Stories por supuesto). Vuelven los post y espero que sea una vuelta que se mantenga en el tiempo.

Asp.Net MVC, para todos?
5:15 | Author: Unknown

Estaba escuchando un podcast de HerdingCode (esto me da pie para un próximo post sobre los podcast que escucho, thanks to commute!) donde Phil Haack habla sobre Asp.Net MVC. Y aprovechando la salida del RC (Release Candidate) podemos discutir algunos temas. (Más info sobre el patrón MVC)
Ante la pregunta de cual es el elevator speech que Phil utilizaría para describir Asp.Net MVC para alguien que utiliza Asp.Net webforms, Phil contesta:

Si utilizás Webforms y estás felíz, entonces ignorá MVC. Si sos muy productivo con Webforms, MVC no va a reemplazar Webforms. Pero los beneficios de utilizar MVC son varios: nos pone nuevamente en control de nuestra aplicación (por ejemplo los controles de Webforms generan mucho markup que si no hacen lo que deseamos puede ser complicado), otro beneficio es que el patrón arquitectónico de MVC es muy bueno en lo que respecta a la separación de conceptos, lo que permite aplicaciones más mantenibles y testeables (valgan los neologismos). Temas que no estaban tan en boga en la creación de Webforms.

 

Un ejemplo

Una pequeña aplicación que me permite almacenar los gastos diarios (me agarró la paranoia).
El modelo lo forman categorías y gastos.

image

 

La persistencia del mismo es a través de Entity Framework (del cual no voy a empezar una discusión, porque Gus tiene muchos argumentos en contra)
Una parte del ExpenseController de ejemplo:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
var expenseToCreate = new Expense();
Category category = new Category();
UpdateModel(expenseToCreate, new[]{"Date", "Amount", "Description"});
UpdateModel(category, new[]{"CategoryId"});
expenseToCreate.Category = _db.Category
.Where(cate => cate.CategoryId == category
.CategoryId).First();
_db.AddToExpense(expenseToCreate);
_db.SaveChanges();

return RedirectToAction("Index", "Home");
}
catch (Exception exep)
{
return RedirectToAction("Error");
}
}




Esta es la acción de crear un nuevo gasto. Acá y por culpa de no poder utilizar el SelecList.SelectedValue, tuve que hacer algo más rebuscado.

Por último, una parte de  la View que representa el Create:




   <fieldset>
<
legend>Fields</legend>
<
p>
<
label for="Date">
Date:</label>
<%= Html.TextBox("Date") %>
<%= Html.ValidationMessage("Date", "*") %>
</p>
<
p>
<
label for="Amount">
Amount:</label>
<%= Html.TextBox("Amount") %>
<%= Html.ValidationMessage("Amount", "*") %>
</p>
<
p>
<
label for="Description">
Description:</label>
<%= Html.TextBox("Description") %>
<%= Html.ValidationMessage("Description", "*") %>
</p>
<
p>
<
select size="5" name="CategoryId" id="CategoryId">
<
option value="0" selected="selected">Sin seleccionar categoría</option>
<% foreach (Category category in (IList)ViewData["Categories"])
{ %>
<%= "<option value='" + category.CategoryId + "'>" +
category.SmallDescription + "</option>" %>
<%} %>
</select>
<
br />
<%= Html.ActionLink("Crear Categoria nueva", "Create", "Categories") %>
</p>
<
p>
<
input type="submit" value="Create" />
</
p>
</
fieldset>



En la misma se ve como resolví el tema de no poder utilizar un Helper Method de la entidad Html (como Html.ListBox o Html.DropDownList) debido al problema del SelectList.



Es un pequeño ejemplo. Se encuentran muchos en internet, no intento hacer un tutorial, pero si les interesa el código no tienen más que pedirlo.



 



Felicidad


Siguiendo con el concepto de Phil Haack, aquellos que no éramos felices con Asp.Net Webforms, nos encontramos con la chance de encontrar la felicidad en éste camino de desarrollo.



Como seguir


El RC tiene todavía algunos problemas, por ejemplo tuve muchos problemas queriendo utilizar un SelectList (lista para Views) y obtener el SelectedValue. Nunca lo logré y tuve que utilizar otras formas. Tal vez sea problemas que se solucionen en la versión definitiva, hay que tener en cuenta que es un proyecto (MVC) con mucho tiempo y mucha gente muy interesante y capaz atrás. Seguimos atentos.

Tecnologías

TDD / DDD / IRepository / Patrones / NHibernate / NUnit / C# / Linq / Net 3.5 / BDO 

Linq to SQL

Está muerto ?Colonia

Aparentemente Microsoft esta dejando de lado LinqToSql  por su variedad en esteroides Entity Framework (voy a ver si puedo traducir este post al E/F). Un buen punto de partida sobre esta discusión es blog del buen Ayende (mucho tiempo con colombianos, ya digo "el buen", jaja) y en particular este post.


Helper?

Lo primero que debemos hacer es agregar al proyecto de implementación un ítem del tipo Linq to Sql classes. Y allí utilizando el editor crear el contexto con nuestras clases.

En el caso de la implementación para LinqToSql utilizamos en vez de un helper métodos en la implementación que nos proveen el DataContext y las tablas.

    public class Repository<T> : IRepository<T> where T : class
    {
        private DomainDataContext domainDataContext = null;
        public Repository()
        {
            domainDataContext = new DomainDataContext();
        }
        /// <summary>
        /// Gets the table provided by the type T and returns for querying
        /// </summary>
        private Table<T> Table
        {
            get { return domainDataContext.GetTable<T>(); }
        }








Tests de la implementación de LinqToSql









Testando los diferentes métodos del Repositorio.









        [Test]
        public void CanSave()
        { 
            // Arrange
            IRepository<Person> repository = new Repository<Person>();
            ResetDB(repository);
            Person person = new Person { FirstName = "Chapita", LastName = "Velazquez" };
            
            // Act
            repository.Save(person);
           
            // Assert
            Person personFromDB = repository
                .GetAll()
                .Where(p => p.FirstName == "Chapita" && p.LastName == "Velazquez")
                .FirstOrDefault();
            Assert.AreEqual(personFromDB.FirstName, person.FirstName);
            Assert.AreEqual(personFromDB.LastName, person.LastName);
        }








Una vez que sabemos que el test no funciona implementamos la funcionalidad.









        public void Save(T item)
        {
            if (!Table.Contains(item))
            {
                Table.InsertOnSubmit(item);
            }
            domainDataContext.SubmitChanges();
        }








Esto también nos muestra otro de los beneficios de TDD, y es la posibilidad de generar dise;os compactos, donde la funcionalidad es exclusivamente la necesaria para satisfacer el test.




Muestro la implementación del Find para tener una idea del uso extensivo de Linq en nuestra implementación.
















       public IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> expression)
        {
            return GetAll()
                .Where(expression);
        }








UPDATE: se puede bajar el código desde NetIRepository









Lo que sigue









En el próximo post me voy a ocupar un poco de como utilizar el repositorio desde servicios y por medio de ellos en las distintas tecnologías de presentación.

Tecnologías

TDD / DDD / IRepository / Patrones / NHibernate / NUnit / C# / Linq / Net 3.5 / BDO  2004-4-3 Regata Dr. Cingano a Colonia 026

Cómo manejo la persistencia de mi aplicación?

Tenemos la posibilidad de actualizarnos en temas de persistencia. Leyendo un artículo muy interesante de Rob Conery Crazy Talk: Reducing ORM Friction. En el mismo, Rob propone realizar la implementación de nuestra aplicación sin preocuparnos por los temas de mapeos con los ORM. Lo que nos propone es dediquemos al diseño a través del TDD (pensando en una orientación similar a la de DDD) de nuestra aplicación utilizando una implementación por medio de una base de datos orientada a objetos.

 

IRepository

Para ello y siguiendo con los conceptos de Domain Driven Design se elige el patrón Repository y se desarrolla la siguiente interfaz que nos va a permitir los distintos providers (implementaciones) que necesitamos para poder diseñar utilizando un modelo de Base de Datos  Orientado a Objetos y luego implementar los providers que necesitemos para ir a producción. con el ORM de nuestra preferencia. En este caso vamos a hacer la implementación de nuestro ejemplo con las elecciones de Rob, BD4O como base de datos orientada a objetos y LinqToSql como ORM. Al final veremos un poco la discusión sobre la ¨muerte de LinqToSql¨. En un próximo post buceo en la implementación del provider con NHibernate y las problemáticas de recorrer una expresión Linq para generar un Criterio de filtro para NHibernate.

using System;
using System.Linq;
using System.Linq.Expressions;
namespace Hover.Repository
{
    public interface IRepository<T>
    {
        IQueryable<T> GetAll();
        IPagedList<T> GetPaged(int pageIndex, int pageSize);
        IQueryable<T> Find(Expression<Func<T, bool>> expression);
        void Save(T item);
        void Delete(T item);
    }
}








DB4O



La opción que presenta Rob para la implementación del provider contra Base de Datos Orientada a Objetos es DB4O.


Lo primero que implementaremos en un helper que nos va a servir como ayuda para la comunicación con el motor de DB4o.


Básicamente es un singleton que nos devuelve una instancia de container para intractuar con la base de datos. Acá Rob, remarca constantemente que estamos realizando una implementación para la etapa de desa rrollo, que no vamos a estar preocupados por perfomance (de ahí a no preocuparnos por el momento por le Singleton!, que ya es mala palabra).


Una vez que tenemos el helper podemos comenzar con los tests de las implementaciones del Repository.



        [Test]
        public void CanSave()
        {
            // Arrange
            File
            IRepository<Person> repository = new Repository<Person>();
.Delete(DB4OHelper.DBPath);
            Person person = new Person { FirstName = "Chapita", LastName = "Velazquez" };
            // Act
            repository.Save(person);
            // Assert
            var result = from Person p in DB4OHelper.Container
                         where p.FirstName == "Chapita"
                         select p;
            Assert.AreEqual(1, result.Count());
            Person personFromDB = result
                .FirstOrDefault();
            Assert.AreEqual(person.FirstName, personFromDB.FirstName);
            Assert.AreEqual(person.LastName, personFromDB.LastName);
            // Just to chain the next test
            DB4OHelper.CloseContainer();
        }


El patrón que utilizamos para implementar TDD es AAA. Arrange / Act / Assert. Por lo tanto primero hay que realizar el setup Arrange, luego hacemos tdodo lo que nos interesa testear y por último realizamos los asserts. Por supuesto no olvidarse los conceptos de de TDD ROJO, VERDE, REFACTOR!.

Luego que nos de ROJO por los motivos esperados implementamos el método Save.




        public void Save(T item)
        {
            DB4OHelper.Container.Store(item);
        }






Les dejo como tarea testear, implementar y refactorizar los otros métodos.



Descargar el ejemplo



El ejemplo desarrollado se encuentra para descargar en google!!! En caso de no contar con Visual Studio 2008 se puede utilizar la versión express y correr los tests desde la consola de NUnit.



NetIRepository















Lo que sigue





En el próximo post voy a intentar implementar la misma interfaz del IRepository para utilizar primero desde LinqtoSQL y luego desde NHibernate, con los inconvenientes que tiene interfacer expresiones Linq con Criterios de NHibernate.

Luego inetntaré implementar los providers como servicios REST para usarlo desde Silverlight, WPF, Asp.Net MVC.



 













Setup para una nueva aplicación
16:04 | Author: Unknown
Tecnologíasimage

CC.Net / Subversion/ TortoiseSVN / Commit Monitor / AnkhSVN /VS 2008 / Resharper /TestDriven / NUnit / Watin / TDD

Un poco de historia

Años atrás (y lamentablemente lo seguimos viendo), desarrollábamos aplicaciones en forma colaborativa. Nos íbamos pasando desarrollos entre programadores y de ésta forma íbamos sumando desarrollo y entregando al cliente. El proceso del desarrollo del software ha dejado de ser un insight artesanal para convertirse en un proceso ingenieril (sin embargo es interesante escuchar el panel de cierre de Ágiles 2008, donde entre otros Mary Poppendieck y Micah Martin proponían volver al craftsman, al artesano).
Cuantas veces escuchamos la famosa frase ¨En mi máquina funciona¨. Para eliminar estas problemáticas debemos utilizar distintas sencillas prácticas que nos permitirán armar un ambiente de desarrollo tal que no tendremos que preocuparnos por esos viejos problemas.

Repositorio

El repositorio nos permite mantener la información centralizada, mantener log, generar tags/branchs, volver a revisiones anteriores, etc.
Nosotros utilizamos Subversion y para el ejemplo que vamos a realizar crearemos un repositorio en code.google.com que nos provee como repositorio SVN.
Para administrar el  repositorio en forma local utilizamos TortoiseSVN, que nos integra el manejo de la copia en checkout del repositorio local con el explorer de Windows.
AnkhSVN nos realiza la integración del Subversion en Visual Studio.
Existen otras opciones que iremos analizando, mientras tanto se puede ver este artículo.

TDD

Nuestra forma de trabajar está basada en TDD (Test Driven Development). Hay mucho para investigar sobre el tema. Lo único que proponemos aquí es tener en cuenta el patrón RED, GREEN, REFACTOR. Esto es realizamos el test necesario para verificar una funcionalidad que estamos agregando a nuestra aplicación. Al no estar desarrollado el código que satisface el test, el mismo va a fallar por el motivo esperado, estaremos en rojo. Se  realiza el código que satisface el test, por lo tanto estaremos en verde. por último realizamos el refactor, que nos permitirá eliminar código repetido, innecesario, etc. Volvemos a probar los test que deberán seguir en verde.
Las herramientas que utilizamos son NUnit como framework de tests. Y para ejecutarlos desde el ambiente de Visual Studio utilizamos ReSharper (que también nos provee muchísima otra funcionalidad espectacular, es adictivo!) o TestDriven, un plugin gratuito.

CruiseControl

Cada desarrollador trabaja en una copia local del repositorio y realiza las modificaciones necesarias, en el momento que ha finalizado alguna parte de una tarea que se encuentra funcional decide subir al repositorio. Para ello verifica que su aplicación compile, corre los test unitarios y de aceptación que corresponden y luego realiza commit al repositorio (si es necesario llevar un control en tiempo real de los commits se puede recurrir al Commit Monitor) .
Una vez que se sube al repositorio, contamos con el CruiseControl .Net que es el encargado de realizar las mismas tareas en el ambiente de integración. 
Decargará todo lo necesario del repositorio, verificará triggers, colas, prioridades, realizará las tareas de compilación, correrá test unitarios, test de aceptación, puede correr aplicaciones de verificacion como el FXCop, NCover, NDepend, etc.
Recién luego de todas éstas tareas estamos seguros que tenemos una aplicación integrada correctamente.
Existe una herramienta complementaria CCTray, que nos permite ver en el Tray el estado en que se encuentra la integración de la aplicación en forma constante. Es necesario tener reglas claras para mantener el repositorio en verde constantemente.

 

Watin

Este framework nos permite realizar test contra la web. Utilizamos nosotros esta herramienta dado que nos permite realizar tests unitarios (usando NUnit) por medio de COM obtenemos una instancia del browser y probamos la funcionalidad , no sólo, el alcance de nuestras interfaces. Esto también lo integramos al CC y lo verificamos en un night test.

Comentarios

Espero recibir comentarios, es sólo una forma de trabajar. Espero poder ampliarlo con ejemplos de cada una de las aplicaciones. para primer post está bien!