Desde que inicie mi carrera de aprendizaje en SharePoint pude notar la ausencia de buenas prácticas de desarrollo con el Modelo de Objectos de SharePoint que para nada es amigable y abierto, sino rígido y algo limitado para aplicar TDD y una forma desconectada y desacoplada para probar nuestro lógica dentro de dicho modelo.
Hay una necesidad imperante de mejorar este modelo actual del cual tenemos de coexistir y desarrollar por la gran demanda que hay hoy en día de esta plataforma muy productiva de Portales y Colaboración.
Motivado por esta imperiosa necesidad, por la iniciativa de los amigos de Patterns & Practices con su SharePoint Guidance para SharePoint, por el articulo de Francis Cheung sobre "Unit Testing para SharePoint Apps", y por ultimo por la influencia de El Diseño Basado en Dominio, me veo en la obligación de publicar este y una serie de artículos que desarrollare para contribuir a el esparcimiento de mejores prácticas de desarrollo para el modelo de objetos de SharePoint, junto con soluciones que ayuden y den como resultado la practica de TDD y patrones dentro de este ambiente deliberadamente hostil hasta esta versión.
Iniciemos con describir a lo que nos enfrentamos:
En español, es difícil separarnos del ambiente conectado, y emularlo para nuestras pruebas unitarias o Unit Testing, porque las interfaces (fundamental para Implementar Mocking dentro de Unit Testing) son escasamente utilizadas dentro del modelo de objetos de SharePoint.
Para incrementar la dificultad están selladas, es decir no podemos sobrescribir, ni sus propiedades, ni sus métodos, ni tampoco heredaras (esto se hizo apropósito me imagino y con justificada razón para asegurar el buen comportamiento, pero dejaron a las pruebas unitarias entre otras cosas).
Ajuste de penas!, como por si fuera poco los constructores de las clases son internos por lo que no podemos crear en memoria para emular estos objetos fuera del contexto conectado las clases del modelo de SharePoint, esto si que fue adrede colocar esta complejidad (Algo desconfiados mis amigos del Equipo de SharePoint).
Y para las colecciones no tiene métodos Add y no implementan el IEnumerable para agregar picante el problema, Es decir no puedo utilizar LinQ en la colecciones de SharePoint porque no implementan la interfase mas básica de las colecciones. Esto si es el colmo!, pero no se asuste amigo, hay formas de usar LinQ dentro de SharePoint, aunque no sean las nativas (Vea este enlace LintQ to SharePoint).
Que opciones para realizar pruebas unitarias tenemos entonces!:
Bueno primero pues nos que damos con lo establecido (Status Quo), es decir contra una instancia en vivo de SharePoint, Ugh!. Aunque ya podemos instalar SharePoint en Windows Vista, para realizar un prueba sencilla necesitamos hacer un deployment o por lo menos una copia de dll nuevo, No way!, para esto esto todo este discurso para encontrar otra solución.
Una solución elegante, pero tediosa y difícil es crear clases Wrapper y Facade para separar el modelo conectado con las pruebas unitarias a esto le llamamos "Separation of Concers", hablaremos mas adelante de este tema. Pero que si podemos generarlo con la ayuda de una aplicación, ya no suena tan mal y esta solución pueda que se las presente en siguientes post en mi blog. Pero por le momento diremos que es una solución no tan viable si la desarrollamos a manita.
Hay por allí unos magos que inventario una herramienta para eliminar las barreras de constructores internos y clases selladas para podemos emular estos objetos y desarrollaron esta herramienta denominada Typemock Isolator la cual cubre el 80% de código dentro del modelo de objetos de SharePoint, el cual es un porcentaje aceptable para asegurar la tranquilidad de los desarrolladores en la plataforma SharePoint, especialmente los que hoy en día no validan nada y esta corrigiendo constantemente sus errores por no tener cobertura de pruebas de su código.
Así que la motivación para el cambio es esta frase: "La separación de las áreas de preocupación, de los aspectos", para concentrarnos por separado en cada una de ellas. Esto implica la independencia y separación de responsabilidad de cada objeto dentro de mi área de preocupación, aspecto o concern. Y esto es lo que pretendemos hacer en el modelo de objetos de SharePoint, es separarnos de el para probar nuestra lógica de este modelo y al mismo tiempo estemos integrados para que luego encajando los concerns (mi lógica y el modelo de objetos de SharePoint) obtengamos una aplicación que funcione, y que este asegurada en un buen margen para nuestra tranquilidad y la mantenibilidad de nuestra solución.
Así que unidos todos estos argumentos desarrollamos el siguiente modelo(gracias a nuestro amigo Cheung):
Utilizar el patrón MVP o Model View Presenter que lo que hará para el caso de los WebParts dentro de SharePoint es separar la Vista o Control de Usuario del Presentador y este a su vez del Modelo (mi lógica de negocio el dominio). Este patrón esta muy bien documentado en la red y básicamente podemos hacer lo siguiente de una manera muy práctica y ligera:
Definimos dos interfases, que nos servirán de base para aplicar el patrón y luego para utilizar de plantilla para la interfase particular de cada WebPart:
public interface IViewBase
{
string MensajeError { set;}
}
Esta propiedad será la base para recordarnos que la forma para acceder la vista o user control será a través de una interfase que herede de esta y que por lo menos maneje los mensajes de error para la interfase de usuario (disculpe si le hablo en chino pero es de madrugada y no quiero hacer un libro, sino solo un articulo de este tema).
La segunda interfase será para el presentador el que va a contener la lógica del control no así del dominio que es una capa mas abajo. Este es el código:
public interface IPresenterBase
{
void SetView(IViewBase view);
}
Esta interfase me recordará que debo implementar en mi clase Presentador este método donde debo de pasarle la instancia de mi vista al presentador, de esta forma:
public class TareaPendientePresentador : IPresenterBase
{
private IViewBase _view;
public void SetView(IViewBase view)
{
_view = view;
}
}
Y en mi control de usuario o WebPart (depende como hagamos la implementación del WebPart) implementamos la interfase IViewBase o la que hereda de esta, de la siguiente forma:
public partial class Demo : System.Web.UI.UserControl, IViewBase
{
private readonly TareaPendientePresentador presentador = new TareaPendientePresentador();
protected void Page_Load(object sender, EventArgs e)
{
presentador.SetView(this);
}
public string MensajeError
{
set
{
ContenedorMensaje.InnerText = value;
}
}
protected override void CreateChildControls()
{
presentador.MostrarTareas();
}
}
De esta forma ya separamos la vista del presentador, luego a través de servicios o un controlador podemos acceder a nuestro modelo (en otro post profundizare en este tema y mostrare el código), que es donde esta la lógica que deseamos probar, lejos del aspecto de la capa de presentación, de la lógica de esta para concentrarnos en nuestro modelo. cada aspecto deberá ser probado gracias a que logramos separarlos.
Regresemos a donde íbamos, El Patrón que sigue es el Repositorio, este con el fin de encapsular las listad dentro de SharePoint, he aquí la separación del modelo de objetos de SharePoint y mi lógica si lo vemos en capas el Patrón MVP esta adelante iniciando del de la capa 7 de presentación y el patrón de Repositorio esta luego de la separación de mi modelo en la capa de Acceso a Datos que en este caso es a las listas de SharePoint donde se persiste la información de este modelo de programación. Quiero aclarar Mi modelo es mi lógica es lo que deseo enfocarme, el modelo de SharePoint son la definición de las clases que utiliza para representar la persistencia de la información almacenada en la bases de datos de SharePoint.
Y por último utilice TypeMock para emular el API de SharePoint, y este es el que le da el jaque mate a levantar una instancia de SharePoint para probar nuestro código este creará de una forma emulada la API de SharePoint para que yo pueda probar mi código sin necesidad de tener que estar haciendo el deployment por cada cambio y prueba que deseo realizar.
Así que amigos, esta es la primera parte de una serie de post donde implementaremos esta solución, e incluiré referencias a la Guidance de P&P, para que vayamos juntos por el camino para desarrollar soluciones dentro de SharePoint de una forma mas asegurada y profesional, minimizando los errores y disfrutando de lo que nos gusta hacer Code4Fun!.
Nos vemos luego!,
Manolo Herrera