Sobre los test unitarios y la capa de acceso a datos

Lunes, 5 de marzo de 2012

Este viernes, durante una cena con integrantes de Gusenet y con Javier Torrecilla, que muy amablemente vino a darnos una charla sobre EF, saltó el comentario de que si decidía no hacer test unitarios a mi capa de datos el resto de tests de mi aplicación no serviría para nada, la casa se me caería sobre los cimientos y acabaría siendo víctima de la moda programando tests que no aportan nada a mi aplicación.

De buenas a primeras yo no estaba muy de acuerdo con la afirmación, pero hay que ser prudente, así que me he dado un par de días para pensarlo bien… y la verdad es que sigo sin pensar que sea cierto.

Por supuesto, hacer test unitarios a la DAL es algo deseable si se cuenta con el tiempo y los recursos (aunque hay que reconocer que es un grano en el culo). Si pudiera haría test unitarios hasta al desayuno de por las mañanas, pero hay que pensar que no siempre se cuenta con los recursos necesarios para hacer todo lo que queremos.

Unos buenos test unitarios deben tener unas características de sobra conocidas: Automatizables, completos (con respecto a lo que se está probando), independientes, repetibles, sencillos, etc. Si tenemos una buena separación en capas, y hemos cumplido estos principios le habremos dado un valor añadido al código de esa capa, independientemente de que otras capas carezcan de ese valor, porque los test deben ser UNITARIOS ¡Es su principal característica! No pasa nada si un test en la capa de negocio no me detecta un mal funcionamiento en la DAL. No solo no pasa nada, sino que es normal, porque lo deseable es que un test pruebe solo una cosa, y por eso usamos mocks y stubs: Para que aislandolo de sus dependencias nuestro test pruebe “una sola unidad de código”, y estar seguros en la medida de lo posible de que esa unidad en concreto funciona como esperamos.

No debemos esperar que los test nos detecten todos los errores porque sabemos que eso no va a pasar, pero sí es importante que las clases con lógica de negocio funcionen como nosotros pensamos que van a funcionar y que los bugs arreglados no vuelvan nunca a repetirse.

Lo que realmente me gustaría es probarlo todo, pero si no lo hago así, creo que un 20% de buena cobertura es mejor que un 0%, independientemente de las capas sobre las que esté hecho. ¿Y qué pasa entonces con los errores de la DAL? ¿Nos los comemos? No, por supuesto que no. ¿O acaso solo probamos nuestras aplicaciones con test unitarios? Tener una buena cobertura no es excusa ni de lejos para seguir haciendo las pruebas manuales de toda la vida.

Como diría Steven Sanderson, no es cierto que cualquier test unitario sea mejor que ninguno, pero sí que un buen test unitario es mejor que ninguno. A lo que yo añadiría “No importa en la capa que esté”.

Llegados a este punto corro el peligro de comenzar a repetirme y ponerme pesado, pero nunca podrán decir que me asusto del peligro: Voy a poner un par de ejemplos prácticos donde se clarifica mi postura:

-          Nos toca desarrollar una capa de negocio sobre una capa DAL que ya está hecha, tengo dos opciones:

a) No hacer pruebas unitarias a la nueva capa porque… total, la DAL no las tiene así que las que yo haga no aportan nada.

b) Hacer pruebas unitarias a la nueva capa conforme la estoy desarrollando.

En este caso, mi opción es la B.

-          Me toca mantener una aplicación que no tiene test unitarios, encuentro y arreglo un bug, tengo 2 opciones:

a)      Hago un test unitario que pruebe ese caso, para que el error no vuelva a repetirse misteriosamente.

b)      No hago un test unitario, porque cubrir solo ese 0.001% del código no me aporta nada, son solo modas.

 Esta vez… mi opción es la A.

Tests Unitarios ,

Tipo de dato Tupla en .Net

Jueves, 23 de febrero de 2012

En .Net una tupla es un tipo de dato que representa exactamente lo mismo que en el ambito matemático: Una secuencia o lista de un número concreto de objetos. El tipo tupla se ha integrado en el framework 4.0.

El manejo de tuplas es bien sencillo.  Si quisiéramos crear una tupla de tres elementos (una cadena, un entero y una clase propia, por ejemplo) y luego acceder a ellos lo haríamos de la siguiente manera.

//C#
 //clase propia
 var myInstance = new myclass();

 //creando una tupla de tres elementos
Tuple<string, int, myclass> myTuple = Tuple.Create("Valor", 1, myInstance);

//accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1);
Console.WriteLine(myTuple.Item2);
Console.WriteLine(myTuple.Item3);
'VB.Net
'clase propia
Dim myInstance As New CustomClass()

'creando una tupla de tres elementos
Dim myTuple As Tuple(Of String, Integer, CustomClass) = Tuple.Create("Valor", 1, myInstance)

'accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1)
Console.WriteLine(myTuple.Item2.ToString)
Console.WriteLine(myTuple.Item3.ToString)

Como podéis ver, el acceso a los miembros de la tupla se hace mediante item1, item2… item X, y podemos crear tuplas de hasta 8 elementos, pero ¿Para que nos puede servir realmente una tupla? Pues imaginemos que tenemos que empaquetar información de alguna manera para luego procesar esa información. Lo más habitual es crear una clase, pero en ocasiones esa información no está directamente relacionada entre sí y además se va a usar en un solo lugar, por lo que no queremos crear una nueva clase. En ese momento, las tuplas pueden echarnos una mano. Si necesitamos que un método retorne varios valores, una tupla es una de las muchas formas de conseguirlo.

¿Se te ocurren muchas situaciones en las que usar una tupla? Si es así, mal vamos. Recuerda el refrán: “A un tonto con un martillo, del cielo le caen los clavos”.  No hay que ser vago, si tienes que devolver un conjunto de datos relacionados, lo mejor es usar una clase. Si tienes dudas, crea una clase. Está bien usar una tupla para que métodos privados retornen datos localizados dentro de clases. Datos que no se van a exponer y a los que incluso te costaría poner un nombre porque no están fuertemente ligados.

Un método público nunca debería retornar una tupla. Piensa que el uso de estos tipos de datos hace que el código no sea autodocumentado. Item1, Item2…ItemX no son precisamente lo que llamaríamos nombres descriptivos. Nos obligarán a poner comentarios indicando qué es cada cosa.

Como curiosidad. ¿No podemos conseguir lo mismo usando tipos anónimos? Pues la verdad es que sí, podemos empaquetar los datos necesarios en un tipo anónimo y luego procesarlos.

Puede que estéis pensando “Ya, pero ¿Cómo retorno un tipo anónimo?” Bueno… lo primero que debo decirte es que nunca deberías retornar un tipo anónimo. Ni siquiera de un método privado y mucho menos de uno público. Además hacerlo es un poco artificial, pero… “Cuando un buen programador está decidido a hacer las cosas mal, ninguna dificultad técnica puede detenerlo”.

//C#
private void ejemplo()
{
    object o = DameUnTipoAnonimo();
    var tipoAnonimo = Cast(o, new { Nombre="", Apellido="" });
    MessageBox.Show(tipoAnonimo.Nombre + " " + tipoAnonimo.Apellido);
}

private object DameUnTipoAnonimo()
{
    return new {Nombre="Jonathan",Apellido="Fernández"};
}

private T Cast<T>(object obj, T type)
{
    return (T)obj;
}
'VB.Net
Private Sub Ejemplo()
    Dim o As Object = DameUnTipoAnonimo()
    Dim tem = New With {.Nombre = "", .Apellido = ""}
    Dim tpo = tem.GetType
    Dim tipoanonimo = CTypeDynamic(o, tpo)
    MessageBox.Show(tipoanonimo.Nombre + " " + tipoanonimo.Apellido)
End Sub

Private Function DameUnTipoAnonimo() As Object
    Return New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
End Function

También tiene su ciencia eso de crear una lista de tipos anónimos:

//C#
private void Ejemplo()
{
    var tipoAnonimo = new { Nombre = "Jonathan", Apellido = "Fernández" };
    var tipoAnonimoList = (new[] { tipoAnonimo }).ToList();
    tipoAnonimoList.Add(new { Nombre = "Kirill", Apellido = "Osenkov" });
    //Kirill Osenkov es el autor de un post en él que ví este ejemplo.
}
'VB.Net
Private Sub Ejemplo()
	Dim tipoAnonimo = New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
	Dim listaTipoAnonimo = CrearListaDesdeElemento(tipoAnonimo)
	listaTipoAnonimo.Add(New With {.Nombre = "Kirill", .Apellido = "Osenkov"})
End Sub

Public Function CrearListaDesdeElemento(Of T)(ByVal p1 As T) As List(Of T)
	Dim lista As New List(Of T)
	lista.Add(p1)
	Return lista
End Function

Con estos ejemplos de código que no deberían ser usados espero haber mostrado que los tipos anónimos no son una buena alternativa a las tuplas, pero volviendo al principio… las tuplas están ahí para ser usadas, pero su uso debe ser moderado y es probable que si aparece la necesidad de usarlas debamos platearnos si estamos haciendo las cosas bien.

.Net ,

Razones para no abrir un blog

Martes, 21 de febrero de 2012

En los últimos dos años he aprendido más que en el resto de mi vida como programador, llegando incluso a vislumbrar los cimientos del oscuro arte de la arquitectura del software, y eso tiene graves consecuencias: Cada vez soy más consciente de todo lo que se me escapa, y de que me es imposible estar mínimamente al día de todo lo que se mueve en el mundo de .Net. Cada cosa en la que meto la nariz resulta ser un mundo.

Casi todo lo que he aprendido me ha venido de otras personas, de libros, de blogs… y solo una pequeña parte de la investigación propia. Puedo citaros sin esfuerzo una docena de blogs en castellano que son mejores de lo que va a ser este. Es lo que hay.

Cualquier pieza de código que escriba aquí podría ser reescrita de forma más eficiente por muchos otros programadores, y cualquier explicación que ofrezca podrá ser reinterpretada de forma que se entienda mejor.

Cuanto más conoce uno, más sube el listón de lo que considera un buen programador. A poco inteligente que se sea con el conocimiento llegará la humildad. Cuando me preguntan si estoy seguro de algo pienso “Seguro solo estoy de la muerte” y a veces digo “Estoy razonablemente seguro” o “Tengo cierto grado de certeza”. Podría dejar el trabajo de escribir un blog a gente más preparada, y dedicarme a pasar más tiempo con mi familia cuando salgo de trabajar. Yo solo quiero hacer las cosas bien y no tener que avergonzarme nunca de mi código, que no es poco.

A pesar de todo, estoy razonablemente seguro de que más pronto que tarde alguien leerá uno de mis posts y dirá “Ahhh… ¡Ya veo por dónde vas!” y le ahorraré un par de horas de esfuerzo. Antes o después llegará una persona distinta que dirá que él lo habría hecho mejor y me explicará como aquí mismo o en su propio blog. Entonces habré ayudado, habré aprendido, y habrá merecido la pena.

Así que he abierto un blog, y sirvan estas reflexiones como disculpa por adelantando, porque tengo cierto grado de certeza en que voy a meter la pata de vez en cuando. Espero también haceros pensar, y haceros reír de vez en cuando.

Blogs ,