A partir de una visión clara e intima del proceso de desarrollo de software, Kent Beck a creado un enfoque metodológico que a primera vista pareciera contra intuitivo pero que ha resultado exitoso y ampliamente aceptado en la comunidad de programadores.
Beck propone contracorriente que es posible separar las consideraciones de calidad de código, desde la perspectiva de ingeniería de software, de la verificación de la funcionalidad, y que el primer paso en cada iteración del proceso de desarrollo es definir y aplicar las pruebas de funcionalidad.
Beck utiliza un proceso de refactorización para pasar de código funcional a código limpio, utilizando la eliminación de redundancia o duplicidad como guía metodológica.
Haciendo una analogía con un semáforo, Beck describe un proceso iterativo de 3 pasos:
Rojo. Empezar con una prueba que debe fallar, tal ves ni compilar siquiera.
Verde. Hacer que el código pase la prueba de la manera más expedita y simple, sin consideración alguna a normas y patrones de calidad de código.
Refactorizar. Eliminar redundancia en código, pruebas, y datos.
Entlib – Enterprise Library es la evolución de los Bloques Aplicativos .NET que han sido desarrollados por el Grupo PAG (Microsoft Platform Architecture Guidance) dentro de Microsoft. Este grupo genera guías y arquitecturas de referencia, patrones de diseño, y código fuente desarrollado con la implementación de diversos escenarios tecnológicos.
Los desarrolladores en su momento puden usar la guía para comprender las mejores prácticas referenciadas y sugeridas por Microsoft para aplicaciones .NET; o incorporar el bloque aplicativo como tal dentro de sus desarrollos, en su formato original y/o extendido.
Los “Bloques Aplicativos .NET” que en su momento fueron liberados son los siguientes:
Por la forma gradual en que fueron desarrollados dichos bloques aplicativos, los mismos estaban desintegrados y la experiencia de utilización e extensibilidad eran diferentes entre si. Además que la utilización de cada uno de dichas piezas de software obligaba a la instalación de componentes de software independientes.
Con estas áreas de oportunidad la nueva versión de los “.NET Application Blocks” se integró con la nueva etiqueta de Enterprise Library. El grupo de PAG ha anunciado lo siguiente:
Entlib es una librería de activos de software reutilizable que atenderá los retos comunes en el desarrollo del software empresarial.
Entlib está focalizado en la consistencia, extensibilidad, fácil utilización e integración de los diversos bloques aplicativos existentes y futuros.
Es importante aclarar que Enterprise Libray no es un producto como tal, sino que es un componente de software que es proporcionado como está, pero del cual se puede contratar soporte directamente de Microsoft, tratado bajo un esquema parecido al código escrito por los usuarios.
Sistema oprativo: Windows Server 2003; Windows Vista; Windows XP
Note: If you already have the Enterprise Library 3.0 installed, you must uninstall it before installing the Enterprise Library 3.1. However, you can install the Enterprise Library 3.0 or the Enterprise Library 3.1 when 2.0 is already installed.
Microsoft .NET Framework 2.0 or 3.0. You need .NET Framework 3.0 for the Application Block Software Factory and the WCF adapters for the Validation Application Block and Exception Handling Application Block
Microsoft Visual Studio 2005 development system (any of the following editions):
Microsoft Visual Studio 2005 Standard Edition
Microsoft Visual Studio 2005 Professional Edition
Microsoft Visual Studio 2005 Team Edition for Software Developers
Microsoft Visual Studio 2005 Team Edition for Software Testers
Microsoft Visual Studio 2005 Team Edition for Software Architects
Microsoft Visual Studio 2005 Team Suite
To use the Application Block Software Factory and the Strong-Naming Guidance Package, you need the Guidance Automation Extensions (GAX). To modify these guidance packages, you also need the Guidance Automation Toolkit (GAT).
Some blocks and samples require the use of Microsoft SQL Server or other database products.
Visual Studio Team System or NUnit 2.2 is required if you want to execute unit tests.
Enterprise Library The patterns & practices Enterprise Library is a library of reusable and extensible application blocks designed to assist developers with common enterprise development challenges. Enterprise Library 3.0 contains application blocks for Caching, Cryptography, Data Access, Exception Handling, Logging, Policy Injection, Security and Validation.
Caching Application Block The Caching Application Block is a component of Enterprise Library which provides a flexible and extensible caching mechanism for use in client and server-side .NET development projects.
Smart Client – Composite UI Application Block Are you building applications with complex user interfaces? Do you want to take full advantage of the power of the Microsoft Windows desktop? Check out this recently released application block that provides guidance on building world-class, enterprise ready, client applications. Available both in C# and Visual Basic .NET.
Cryptography Application Block The Cryptography Application Block is a component of Enterprise Library which makes it easier to include cryptographic functionality in .NET applications. The block provides a simple interface to DPAPI, symmetric encryption and hashing, and uses the Enterprise Library configuration tool to simplify key management.
Data Access Application Block The Data Access Application Block is a component of Enterprise Library which reduces the amount of custom code that you need to create, test, and maintain when building data access layers in .NET applications.
Exception Handling Application Block The Exception Handling Application Block is a component of Enterprise Library that makes it easier to implement consistent exception handling policies at logical tiers in an application. Exception policies can be configured to perform tasks such as logging exceptions, wrapping or replacing exception types.
Logging Application Block The Logging Application Block is a component of Enterprise Library that allows developers to instrument their applications with logging and tracing calls. Log and trace messages can be filtered, formatted and routed to a choice of trace listeners, including the event log, text files, database or WMI.
Policy Injection Application Block The Policy Injection Application Block is a component of Enterprise Library which allows developers to specify the crosscutting behavior of objects in terms of a set of policies. Crosscutting concerns are the necessary tasks, features, or processes that are common across different objects. Examples are logging, authorization, validation, and instrumentation.
Security Application Block The Security Application Block is a component of Enterprise Library that builds on the capabilities of the Microsoft .NET Framework to help you perform authentication, authorization, check role membership and access profile information.
Validation Application Block The Validation Application Block is a component of Enterprise Library which provides a common approach to defining validation rules for your business objects that allows them to be reused across different layers of your application.
Web Service Facade for Legacy Applications This guide discusses best practices for interfacing with legacy applications by using Microsoft® ASP.NET Web services and the Microsoft .NET Framework. The .NET Framework provides the foundation for creating a Legacy Application Interface solution using Microsoft technologies. This guide provides a sample solution using a Microsoft FoxPro® database as the legacy application and connecting it to a .NET-based application using ASP.NET Web services and SOAP. The specific technologies involved are ASP.NET, C# or the Microsoft Visual Basic® .NET development system, the .NET Framework, XML, Visual Basic, COM, and ADO.
Conforme va madurando el campo de tecnología de información, se van estableciendo patrones de referencia de cómo deben ser las aplicaciones de negocio y va aumentando la presión para tener ciclos de desarrollo cortos.
Surge entonces la necesidad de mecanizar el proceso de producción de software, y además hacerlo de manera flexible y ágil que permita incorporar la parte variable de manera robusta.
Un enfoque es desarrollo Cut-and-Paste usando programadores experimentados en el desarrollo de aplicaciones similares a la que se esta haciendo. Este modelo tiene sus limitaciones y no es realmente escalable. Por un lado es propenso a errores y consume horas-hombre que serian mejor empleadas en actividades que se beneficien de la capacidad creativa y visión del desarrollador. Por otro lado, realmente no permite de manera natural institucionalizar y transferir experiencias entre desarrolladores y entre grupos de desarrolladores.
En el ciclo de vida y desarrollo de una aplicación se requieren distintas perspectivas y niveles de abstracción. En un proceso mecanizado de desarrollo debe haber herramientas que idealmente nos permita partir de la conceptualización de las necesidades de negocio y de manera automática llegar a la implantación bajo tecnologías específicas.
UML se utiliza en algunas herramientas que generan código a partir de un diagrama de clases por ejemplo. De manera más general el Object managment Group (OMG) ha desarrollado el concepto de arquitectura dirigida por modelos (model-driven architecture, MDA). Este enfoque pudiera ser a un nivel de abstracción y generalización demasiado alto para ser de uso practico.
MDA enfatiza independencia de plataforma. En la práctica, esto no puede ser un absoluto. Las características de una tecnología o implementación son restricciones en el modelo.
MDA asume que están disponibles modelos para cualquier artefacto.
MDA utiliza UML como lenguaje de uso general. Algunas tecnologías y aplicaciones no se prestan para ser representados en UML y se pueden describir mejor con herramientas específicas que permitan una mayor fidelidad al pasar de concepto a implementación.
MDA asume que 3 tipos de modelo son suficientes:
computation-independent model,
platform-independent model,
platform-specific model.
MDA se enfoca en transformaciones. Es difícil lograr un proceso completamente automático que vaya de concepto a implementación. La metodología debe incluir el manejo de la parte variable que no se puede automatizar y los cambos que se requieran durante el mantenimiento de una aplicación
Un lenguaje de modelación de uso general como UML esta diseñado para soportar el desarrollo de modelos que sirvan principalmente como documentación. Estos lenguajes pueden describir cualquier dominio, pero necesariamente de manera imprecisa por el alto nivel de abstracción que utilizan. En el caso de UML, las abstracciones genéricas se definen utilizando lenguaje natural informal.
Un lenguaje de domino especifico (DSL), esta diseñado para describir con precisión una tarea especifica. En vez de abstracciones genéricas utiliza conceptos tomados directamente de la tarea a modelar.
El concepto de fabricas de software de Microsoft utiliza como componente básicos leguajes de alta fidelidad como XML, C# y SQL, lenguajes de domino especifico (Domain Specific Language, DSL), scripts de flujos de trabajo (workflow), archivos WSDL, archivos DDL, SQL.
Las fábricas de software son específicas a subsistemas como administración de clientes, administración de catálogos, cumplimiento de órdenes.
El machote (template) de una fábrica de software incluye código y metadata que se pueden cargar en un IDE o en una herramienta de desarrollo de aplicaciones empresariales. El concepto de machote es similar al de un machote de un documento de Word o Excel.
El uso de una fábrica de software incluye los siguientes pasos:
Análisis de problema. Primero determinar si el producto cae dentro del alcance de la fábrica de software.
Especificación del producto. Definir los requerimientos del producto en términos de sus diferencias con los requerimientos de los componentes de la fábrica de software.
Arquitecta del producto. Ajustar la fabrica de software a las características particulares del producto.
Implementación. Las actividades usuales de pruebas unitarias, pruebas de ejecución, ensamblaje de componentes, desarrollo de componentes
Instalación. Crear o re usar restricciones, configuración de infraestructura, validaciones, instalación de requerimientos y ejecutalbes.
Pruebas. Crear o re usar recursos de pruebas, datos de prueba, scripts de prueba, uso de herramientas de medición.
Las fábricas de software proporcionan un enfoque robusto a la creación de software usando un paradigma de modelación visual, pero va más allá del uso de modelos como documentación. Usando DSL y XML permiten usar metadata para automatizar la generación de código. Los cuatro pilares de las fábricas de software son: Líneas de software, marcos arquitectónicos (architecture frameworks), desarrollo dirigido por modelos, y guías contextuales
El esquema de fábrica de software es un modelo diseñado para soportar cómputo. El esquema de una fábrica es un árbol. Cada nodo en el árbol se conoce como una perspectiva (viewpoint). La perspectiva raíz corresponde a construir todo el entregable. Las perspectivas subyacentes se derivan por descomposición. Cada perspectiva describe la solución en términos de actividades a realizar y una explicación como realizar cada actividad. Las actividades se describen en términos de los productos que generan. Esto productos son los componentes que se utilizan para construir el entregable. Además cada perspectiva incluye recursos suministrados por la fábrica para resolver los problemas del dominio, generalmente automatizando total o parcialmente la tarea.
Par construir una fabrica se empieza sencillo con recursos simples y se va invirtiendo tiempo en desarrollar recursos más sofisticados conforme se va ganando experiencia en el dominio.
Así como los objetos físicos se mueven a través del tiempo y el espacio, las aplicaciones de software se mueven por diferentes ejes en su ciclo de vida. Concretamente, el mantenimiento de una aplicación requerirá de una serie de adecuaciones y cambios por distintos motivos: cambio de plataforma, cambios en el proceso de negocio, nuevos requerimientos, nueva base de datos. Etcétera. Además, desde el punto de vista del desarrollador, lo ideal es poder reutilizar lo más posible de esfuerzos anteriores. En el ciclo de vida de un sistema, más del 60% del costo es el mantenimiento
La tendencia a requerimientos cada vez más complejos con tiempos de desarrollo cada vez más cortos vuelve el re-uso de código un imperativo.
Teóricamente, la programación orientada a objetos facilita el re uso de código. Los atributos de los lenguajes orientados a objetos que promueven el re-uso de código son:
Abstracción de datos que promueve sistemas modulares.
Herencia que permite que las subclases re-usen código de las superclases.
Poliformismo facilita el re-uso de comportamiento bajo diferentes contextos.
Marcos (frameworks) que son conjuntos de clases abstractas que solucionan familias de problemas relacionados.
Pero, para que se cumpla esta promesa divina de re-uso, el código, o más bien dicho, el diseño, debe ser bueno, muy bueno. ¿Qué es, entonces, un buen diseño? Cada cuál tendrá su idea. A manera de contrapunto empecemos por lo negativo, ¿Qué características tiene un mal diseño? Concediendo que la aplicación cumple con los requerimientos para los que fue diseñada, un diseño puede adolecer de lo siguiente:
Rigidez. La aplicación es difícil de cambiar porque cualquier cambio afecta demasiadas cosas.
Fragilidad. Cuando se hace un cambio, la aplicación deja de funcionar en lugares inesperados.
Inmovilidad. Es difícil utilizar la aplicación como parte de otra aplicación porque las dependencias con el contexto están enmadejadas en el código.
¿Qué es lo que hace un diseño rígido, frágil, e inmóvil? Las interdependencias de sus módulos. Entonces, para que el proceso de mantenimiento no sea la imagen de un perro persiguiendo su cola, se debe tener cuidado de minimizar interdependencias.
Desde el punto de vista de la programación estructurada, un diseño se puede ir construyendo bottom-up o top-down. Es decir, a partir de los componentes o módulos que tengo disponibles voy construyendo módulos más complejos, hasta cubrir los requerimientos, o conversamente, voy dividiendo mis requerimientos entre sub-módulos, hasta que llego a un punto suficientemente concreto para resolverlo de manera independiente. Al final, de manera iterativa, se llega a un diseño de capas jerárquico, donde en un sentido estricto, los únicos componentes que pueden ser completamente independientes del resto son los módulos de más bajo nivel en la jerárquia, es decir los más concretos y específicos, los más ligados al problema particular que se esta resolviendo.
La mecánica establecida para re-usar rutinas de bajo nivel es el uso de librerías. En la practica la productividad de un lenguaje o ambiente de desarrollo esta ligada con la calidad y disponibilidad de librerías. Esto esta bien, pero desde el punto de vista de re-uso de código las dependencias están al revés. Los módulos de alto nivel, que resuelven un proceso complejo de interacción entre la aplicación, sus módulos internos, y el contexto exterior son los que queremos re-usar. De acuerdo a este precepto, un buen diseño debe cumplir con el principio de inversión de dependencias.
Módulos de alto nivel no deben depender en módulos de bajo nivel. Ambos deben depender de abstracciones.
Abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
Al concepto de inversión de control se le refiere como el principio de Hollywood:
Do not call us, we call you
Inversión de control es un aspecto clave que diferencia un marco orientado a objetos de una librería. Una librería es un conjunto de funciones, tal vez organizadas dentro de clases, que una aplicación (cliente) llama dentro del código, la función hace lo que tiene que hacer, y regresa el control al cliente. En un marco orientado a objetos, es el marco el que llama al código del cliente. En .Net, por ejemplo, una manera de hacer esto es que el marco defina eventos a los cuales se subscribe el cliente y mediante el uso de delegados, el cliente asigna el compartimiento especifico que requiere.
En términos más generales, Interfaces es la manera de abstraer la interacción entre el cliente y el marco (framework). Una técnica de inversión de control es dependency injection.
La inversión de control es parte de lo que hace la programación de marcos orientados a objetos perturbadora para algunos. Al programar un procedimiento, la atención del programador esta en el flujo de control. Es difícil imaginar como se pudiera entender un programa sin saber la lógica de ejecución. Pero un buen marco abstrae el detalle del control de flujo. El foco de atención esta en los objetos, lo que puede ser al mismo tiempo más y menos tangible que el flujo de control.
En el marco, lo importante son las responsabilidades de cada objeto y la interacción (colaboración) entre ellos. Es una visión más abstracta, más declarativa del mundo, potencialmente más flexible y amplia que el enfoque en procedimientos.
Resumiendo, un buen diseño es aquel que nos permite hace cambios de manera no intrusiva, es decir, añadiendo código en vez de cambiando código. Un buen diseño se puede modificar sin tocar el código existente. O sea, en un desarrollo orientado a objetos el esfuerzo debe estar en el diseño. La programación orientada a objetos debe ser fácil, a costa de un proceso exhaustivo de diseño. He ahí la promesa y el reto fundamental de la orientación a objetos.
Los buenos patrones de diseño no se inventan, se descubren. Desde una perspectiva macro de diseño el principio de inversión de control es fundamental. Desde la perspectiva de las clases en si, ¿Qué principios se deben seguir para facilitar un buen diseño?, o más importante, ¿Qué debemos evitar para no inhibir el potencial del diseño? ¿Cómo garantizar que no haremos daño?
Algunos tips:
Es más fácil reusar un comportamiento agregando un componente que a través de herencia.
Eliminar análisis de casos. En el caso de .Net se pueden usar genéricos.
Reducir el número de argumentos. Sin embargo, al crear un objeto, es preferible exponer todas las dependencias para facilitar pruebas de clases individuales.
Reducir el tamaño de los métodos. El propósito del método debe ser obvio e idealmente el código debe ser auto documentado.
Las jerarquías de clases deben ser profundas y espigadas. Una clase todopoderosa, rodeada de ratoncitos indica un área de oportunidad en el diseño. Cada clase debe tener una responsabilidad principal, de preferencia única, claramente definida.
Minimizar acceso a variables. Una clase debe exponer solo aquello que sea estrictamente necesario para cumplir con su responsabilidad. En .Net se promueve el uso de propiedades en vez de variables públicas, para que la clase tenga mayor control en el uso de sus valores a través de métodos get y set.
La raíz de la jerarquía de clases debe ser abstracta. Es decir, no debe tener ningún (minimizar) detalle de implementación y solo exponer la interfaz de la clase.
Subclases deben ser especializaciones. Usualmente una subclase no debe redefinir métodos de la superclase, solo añadir nuevos.
Dividir clases grandes. Factorizar diferencias de implementación en sub-componentes. Separar métodos que no se comunican entre si.
One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user’s application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.
Tal vez sea porque estamos a principios de siglo o simplemente un espejismo pero pareciera que estamos en los albores de un cambio paradigmático en el desarrollo de software post orientación a objetos.
Uno de los ideales del desarrollo de software es la capacidad de modificar el funcionamiento de un sistema sin tocar una línea de código. Algunos enfoques en este sentido es inyección de dependencias y programación orientada a aspectos (AOP).
David Hayden en su bitácora presenta un ejemplo, en el contexto de la librería empresarial del grupo de patrones y practicas de Microsoft, del uso del bloque de aplicación de inyección de políticas para guardar registros de llamadas a métodos y se quejaba de que la librería en realidad no soporta el patrón de inyección de dependencias. Lo cual provoco una demostración de las capacidades de Windsor para soportar AOP.