Introducción a Indigo (WCF)

viernes, 23 de marzo de 2007


Qué es Indigo (o WCF)?


WCF, Windows Communication Foundation (se pronuncia Indigo), es la solución integral para sistemas distribuidos que forma parte de .NET 3.0, en particular para la implementación de arquitecturas SOA.

WCF permite describir, publicar, implementar y consumir servicios, no solo con la interoperabilidad de los Web Services entre plataformas servidor y cliente, sino también utilizando diferentes plataformas de transporte de forma transparente al resto de la arquitectura.

Una forma de introducir brevemente que nos "trae de nuevo" WCF es mediante estos 3 puntos:



1. Uno para todos y todos para uno

WCF Integra diversas plataformas de comunicación preexistentes para sistemas distribuidos bajo una capa de abstracción

Para la construcción de sistemas distribuidos Microsoft tenía ya distintas tecnologías cada una con sus ventajas y desventajas, Indigo pretende incorporar varias de ellas y "esconderlas" detrás de un modelo de servicio. Esto significa que podemos evitar (o posponer) la decisión clave de escoger el tipo de transporte al momento de diseñar la arquitectura de nuestra solución.

Las tecnologías de comunicación preexistentes que WCF engloba son:

- ASP.NET Web Services (incluyendo las WSE, Web Service Enhancements)
- Microsoft Message Queue
- Enterprise Services/COM+
- .NET Remoting

Una gran promesa de WCF es poder intercambiar, combinar (y extender, puntos 2 y 3) cualquiera de éstas tecnologías en nuestros servicios, dejando la posibilidad de aprovechar los puntos fuertes de cada una según sea apropiado en el entorno de nuestra aplicación. Esto significa también el ahorro de horas dedicadas al dominio de cada tecnología particular.



2. Extensibilidad

El comportamiento de los servicios WCF puede extenderse con distintos grados de granularidad

La principal muestra de extensibilidad se da en la posibilidad de definir "Behaviors" e "Inspectors"

Los Behaviors, como su nombre indica, permiten extender, según se desee, el comportamiento de un servicio, una operación que ofrece un servicio, o un Endpoint.

Endpoints

Un Endpoint representa un punto de acceso donde un servidor recibe clientes, se define mediante un terna "ABC":
  • Address, dirección (una url, un puerto TCP, etc)
  • Binding (Tcp, Http, Pipes, etc)
  • Contract (descripción del servicio, de las operaciones disponibles, tipos de datos, etc)

Así un servicio puede ser expuesto en múltiples Endpoints, un ejemplo típico sería el de un servicio disponible vía Web (un Endpoint con Binding Http, o wsHttp) y vía Intranet (usando un EndPoint con Binding TCP) simultáneamente.


Los Behaviors permiten "colgarse" de diferentes sucesos en la vida de un servicio (en el pipeline de WCF), en la invocación de una operación, o en el procesamiento de los mensajes entrantes y salientes. Muchas veces se usan los Behaviors para colgar un Inspector que realiza el verdadero trabajo.

Un ejemplo típico es la interfaz IParameterInspector, ésta declara los metodos "BeforeCall" y "AfterCall" que se invocarán antes y después de la ejecución de una Operación determinada, permitiendo en ese momento validar parámetros, o verificar la autorización de usuario cliente, crear un log de las operaciones invocadas, o simplemente debuguear.

Estas extensiones, tanto Behaviors como Inspectors pueden "engancharse" decorando con atributos la descripción del servicio, programáticamente, o en archivos de configuración. Esta opción triple para definir o configurar un servicio es característica en WCF, cada modo claramente es útil a distintos fines.




3. WS-*

Los servicios de WCF implementan las WS-*, agregando métodos de seguridad y enrutamiento de forma nativa

Estas extensiones (análogas a las WSE, de los Web Services ASP.NET) apuntan principalmente a la integridad y confidencialidad de los mensajes, direccionamiento, garantía de entrega y transaccionabilidad.

WS-Security, WS-Policy, WS-Trust, WS-Addressing, WS-SecureConversation, WS-ReliableMessaging, WS-AtomicTransaction, WS-Coordination

Esto significa un gran abanico de opciones de autenticación, encriptación, y enrutamiento de los mensajes.



Links para seguir leyendo:

  • Introduction to Building Windows Communication Foundation Services
http://msdn2.microsoft.com/en-us/library/aa480190.aspx
  • Windows Communication Foundation (Indigo) FAQ
http://msdn2.microsoft.com/en-us/windowsvista/aa905015.aspx
  • Windows Communication Foundation (netfx3)
http://wcf.netfx3.com/
  • Introducing Indigo: An Early Look
http://msdn2.microsoft.com/en-us/library/aa480188.aspx
  • WCF Extensibility: Behaviors and Inspectors
http://steve.emxsoftware.com/Indigo-WCF/WCF+Extensibility+Behaviors+and+Inspectors
Leer más...

Unit testing Buenas practicas

Los tests unitarios son una herramienta que ayuda el desarrollo de aplicaciones en escenarios de trabajo formados por equipos donde cada uno tiene un rol definido. En este artículo hablaremos sobre prácticas recomendables a la hora de utilizar Unit Testing.

Los tests de nuestros proyectos serán ejecutados por los desarrolladores y es a ellos en quien se debe pensar a la hora de crearlos, que sean amigables es una propiedad tan importante como que nuestros tests funcionen correctamente.

Verdades relativas de los tests unitarios

  • La detección de errores se ve facilitada.
  • El código es fácil de mantener.
  • El código es más comprensible.

Para que estas tres verdades se cumplan es necesario un buen desarrollo de tests unitarios. A continuación daremos una serie de recomendaciones útiles para lograrlo.

Testear lo correcto

Un test debe probar el que y no el como, debe asegurarse que la funcionalidad del código a probar se cumpla en forma correcta y no prestar atención a como lo logra.
Hacer test sobre la interfaz pública de las clases nos permitirá generalmente probar toda la funcionalidad disponible en la misma, mientras que si hacemos test sobre los métodos privados y/o protegidos seguramente nos estaríamos involucrando en la forma en que están implementadas las tareas y no si el fin se cumple correctamente. Cumpliendo con esta premisa sortearemos fallas en nuestros test cuando por algún motivo halla cambios en como se realizó determinada tarea.

Cuando un test falla en forma incorrecta

A veces encontramos un test que falla incluso sabiendo que los cambios realizados en el código son correctos. Esto generalmente nos llevará a la conclusión de que hemos hallado requerimientos incompatibles. En esta situación podremos tomar dos caminos diferentes...

  1. Borrar el test, luego de verificar que no será válido nunca más, ya que el requerimiento que lo hizo necesario ya no es un requerimiento del sistema.
  2. Modificar el test antiguo para adecuarlo a los nuevos requerimientos. Generalmente agregando un nuevo test que modifique las condiciones iniciales o finales del mismo.

Cobertura y ángulos de prueba

Como saber si el código se encuentra suficientemente cubierto por los test? Una prueba básica y muy efectiva es eliminar una línea de código de una funcionalidad completa, en el caso de que hecho esto un test falle esa porción de código tiene razón de ser, de lo contrario, será necesario agregar un nuevo test. En el caso de llegar a esta situación y no encontrar la forma de hacer un test que falle al comentar el código, es muy probable que el mismo no sea necesario.
Jamás sabremos cuando será necesario que otro programador modifique nuestro código, y si no se tienen los test necesarios para probar cada porción del mismo, no podrá notar si sus cambios perjudican otra funcionalidad que lo utilizaba parcial o totalmente
Seguramente en muchos casos un método necesitará varias pruebas, todas bajo diferentes condiciones para asegurar su correcto funcionamiento, uno de los errores más recurrentes en la escritura de un test es intentar abarcar todas las opciones dentro de un mismo test, esto es inadmisible ya que estaríamos violando la regla básica de este método de prueba, como su nombre lo indica estamos haciendo “Test Unitarios”, es decir, cada test prueba una y sólo una cosa. Nos daremos cuenta cuando estemos infringiendo esta regla si nos encontramos escribiendo una sentencia if, while, Etc... Respetar esta regla nos ahorrará, probablemente, tiempo valioso en prueba de nuestros test.

Los test deben ser sencillos de ejecutar

Facilitar la ejecución de test hará que los desarrolladores, para quienes esto es solo una perdida de tiempo en sus primeras aproximaciones, no se resistan a la idea de que ejecutar los test les ayuda a ganar tiempo y a encontrar errores en el código más fácilmente.
Existen básicamente dos tipos de test

  1. Los que pueden ejecutarse aleatoriamente.
  2. Los que necesitan una condición previa, para testear una situación en particular.

La idea es que todos nuestros test formen parte del primer grupo, de no ser posible, deberíamos agrupar unos separados de los otros con el objetivo de tener una serie de test que cualquiera sea capaz de ejecutar y probar que la funcionalidad básica esta cubierta y funcionando correctamente y otro grupo que pruebe más exhaustivamente que corramos menor cantidad de veces.
Los test del primer grupo se ejecutarían todo el tiempo, ante cualquier cambio por menor que sea, mientras que el segundo, después de haber completado la implementación de determinado requerimiento.

Desarrollo y mantenimiento

El test unitario debe ser escrito antes de programar una nueva funcionalidad o al modificar una que aún no tenía su test, no hay que confundirse en este paso el punto más importante en el comienzo de la generación de nuestros tests, “Los test deben fallar solo cuando la funcionalidad esté incompleta o no cumpla con los requerimientos”, comprender bien este punto nos ayudará a no hacer test que fallen por estar probando cosas ilógicas.
Un test creado no debe ser eliminado, sólo se llevará a cabo esta acción cuando los requerimientos sean modificados y la funcionalidad ya no sea requerida.

Eliminación de dependencias entre test

Anteriormente hablamos de dos grupos de test y las ventajas de tener test independientes que no necesiten un estado para salir airosos en su ejecución. Dos sentencias que ayudan bastante a esto son “TestInitialize” y “TestCleanup” que ayudan a mantener frescas todas las instancias de las clases utilizadas en nuestros test.
El método “TestInitialize” es el lugar donde debe encontrarse el código necesario para generar el estado básico para la ejecución de todos los test de una clase, si solo para uno de estos, parte del código no es relevante, no debería estar ahí. En estos casos es posible y recomendable, escribir un método de inicialización que se llame desde un test en particular, así estaríamos también modularizando el código, lo que nos facilitará la reutilización del mismo.

No incluir más de un ASSERT por test

Aparte de no estar reutilizando el código en nuestros test, esto nos hará perder más tiempo del necesario en resolver los problemas que detecten los mismos por los siguientes motivos. En primer lugar, cuando una sentencia assert falla se detiene la ejecución del método y por lo tanto las posteriores sentencias no serán ejecutadas y quizás fallen en el próximo intento. Necesitando así varias corridas de un mismo test para solucionar todos los problemas que era capaz de detectar. Eliminando la acumulación de estas sentencias en nuestros test no solamente nos libraremos de este problema, sino que, el tener de una vez la mayor cantidad de errores posibles nos ayudará a tener una idea más abarcativa del posible problema.

Crear test legibles

Hay un par de puntos básicos a seguir para lograrlo, dividir expresiones complejas en varias más sencillas y llamar a cada ítem con un nombre representativo a su funcionalidad dentro del código.
Aprender a nombrar cada ítem puede ser muy difícil pero sin duda es un punto más que importante a la hora de que el código sea legible y más aún a la hora de escribir test ya que con mirar el error que se detecta en uno de ellos deberíamos ser capaces de comprender que causó la falla y poder solucionarlo.
El nombre de un método de test se podría dividir en tres partes, el nombre del método bajo prueba, el estado o regla a probar y la salida esperada del mismo. No debería incluirse “Test” y/o el nombre de la clase bajo prueba ya que seguramente esto forma parte del nombre de la clase a la cual pertenecen nuestros test. Siguiendo estas reglas es probable que tengamos nombres mucho más largos que de costumbre pero no será relevante si esto ayuda a ganar tiempo cuando este apremia, a la hora de corregir bugs.

Conclusión

Como pudimos ver en este pequeño informe, escribir test no es una tarea trivial ni sencilla. Si bien escribir un test unitario no es más complicado de lo que es hacerlo con cualquier otro método y/o clase, para poder sacar provecho de la utilización de los mismos debemos tener en cuenta muchos aspectos que ayudarán a lograr mayor productividad utilizándolos. De lo contrario, no solo perderemos tiempo en escribirlos, sino también, en mantenerlos, correrlos, resolver los problemas por estos detectados y más.

Finalmente, la utilización de test puede ser de muchísima ayuda a la hora de producir y mantener una aplicación, solo debemos tener en cuenta que esta tarea no es sencilla y debemos prestar mayor atención en la redacción de los mismos.

Leer más...

Windows Workflow Foundation

jueves, 22 de marzo de 2007


¿Que es Windows Workflow Foundation?

Windows Workflow Foundation es el modelo de programación de Microsoft que permite crear aplicaciones con funcionalidad de workflow. Consiste en un motor de workflow embebido y un add-ins para el entorno de desarrollo de Visual Studio 2005.

Un workflow es un conjunto de actividades guardadas como un modelo que describe un proceso del mundo real. El trabajo pasa a través del modelo desde el principio hasta el final, y las actividades pueden ser ejecutadas por personas o por funciones del sistema.

Las actividades pueden ser simples o compuestas. Una actividad compuesta es un conjunto de actividades simples.

Seria totalmente posible escribir un workflow completamente en código, pero éste en general es mejor visto si es representado gráficamente.



¿Que puedo hacer con WWF?

Windows Workflow Foundation soporta una amplia gama de situaciones de flujo de trabajo, incluyendo aplicaciones de línea de negocio, flujo de páginas de interfaz de usuario, flujo de trabajo centrado en documentos, flujo de trabajo humano, flujo de trabajo compuesto para aplicaciones orientadas a servicios, flujo de trabajo impulsado por reglas empresariales y flujo de trabajo para gestión de sistemas.

Usando Windows Workflow Foundation, los desarrolladores pueden incorporar conceptos tales como scheduling, coordinación de tareas y escalabilidad en sus aplicaciones existentes sin costo alguno. WWF provee la plataforma base donde se pueden desarrollar aplicaciones con muchos procesos.


¿Cómo ejecuto un workflow?

Una vez que el modelo es compilado, puede ser ejecutado dentro de cualquier proceso de Windows, incluyendo aplicaciones de consola y WinForms, Servicios Windows y Web, como también páginas ASP.NET o aplicaciones de servidor.
Tambien en SharePoint y otros productos como Microsoft BizTalk Server y los servidores de Microsoft Office.

Tipos de workflows

Flujo Secuencial: Es aquel donde se ejecutan una serie de actividades en una secuencia predefinida. Esta secuencia puede incluir operadores de control de flujo similares a los que han existido durante años en lenguajes de programación. Por ejemplo, operadores de decisión (if…else) o de iteración (while). Se utiliza para flujos donde nos interesa que el control lo tanga primordialmente el proceso definido.

Flujo de Máquina de Estados: En este flujo las actividades se ejecutan dependiendo de el estado en el que se encuentre una máquina de estados, así como de las transiciones entre estos estados (que pueden ser iniciadas por las actividades mismas). Se utiliza normalmente para flujos donde se prefiere que el control recaiga mayormente en los usuarios del sistema.
Ejemplo


Requisitos

Microsoft .NET Framework 3.0 Redistributable Package
http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&displaylang=en

Visual Studio 2005 extensions for .NET Framework 3.0 (Windows Workflow Foundation)
http://www.microsoft.com/downloads/details.aspx?FamilyId=5D61409E-1FA3-48CF-8023-E8F38E709BA6&displaylang=en

Sitios de interés

http://wf.netfx3.com/
http://msdn2.microsoft.com/en-us/library/ms741723.aspx
Leer más...

TRY/CATCH en SQL 2005

viernes, 9 de marzo de 2007

Microsoft SQL Server 2005 trae incorporada una nueva forma de manejo de errores. Las versiones anteriores solo permitían el detectar errores con la función @@Error, que permite hacer un reporte del error pero no hacer un manejo, solamente muestra la información y la excepción se manda al que llamó al Stored Procedure y es él quien decide qué hacer.
Otra desventaja del @@Error es que el empleo apropiado de esta función requiere hacer una comprobación después de cada declaración, de otra manera el valor de la variable se resetea.
Por ejemplo:
SELECT 1/0
IF @@ERROR <> 0
BEGIN
SELECT @@ERROR
END
-----------
Msg 8134, Level 16, State 1, Line 1Divide by
zero error encountered.
-----------
0
(1 row(s) affected)

La función @@Error devuelve 0 en el select, y no el número de error, porque el IF no dio un error.

En SQL Server 2005 las excepciones se pueden manejar desde el SP con la nueva función TRY/CATCH, que emula el manejo de errores derivado del lenguaje C. Se escribe el código dentro del bloque TRY y si lanza una excepción la recibe el bloque CATCH, de esta forma el error puede manejarse dentro del SP sin necesidad de mandar una excepción al que lo llama.
Esta función también ayuda a mejorar el código de las transacciones ya que no hay que escribir la validación del @@Error después de cada declaración sino que desde el momento en que empieza la transacción se hace un TRY y en el CATCH se hace el rollback.

Microsoft SQL 2005 también tiene otras funciones que facilitan el reporte de errores que son ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_LINE(), ERROR_SEVERITY(), ERROR_STATE() y ERROR_PROCEDURE(). Estas funciones a diferencia del @@Error no se resetean.

Un ejemplo simple del uso del TRY/CATCH con las funciones de ERROR sería crear un Store Procedure con el siguiente código:
CREATE Procedure PruebaTryCatch
(
@Dividendo int,
@Divisor int
)
as
BEGIN TRY
SELECT @Dividendo/@Divisor
END TRY
BEGIN CATCH
SELECT
ERROR_MESSAGE() as Mensaje,
ERROR_NUMBER() as Numero,
ERROR_LINE() as Linea,
ERROR_SEVERITY() as Severidad,,
ERROR_STATE() as Estado,
ERROR_PROCEDURE() as Proceso
END CATCH
Si lo ejecuta con el número 1 como dividendo y el 0 como divisor:
EXECUTE PruebaTryCatch 1, 0
El resultado será:

Mensaje                          Numero Linea
-------------------------------------------------------
Divide by zero error encountered. 8134 11

Severidad Estado Proceso
------------------------
16 1 PruebaTryCatch
Leer más...