El blog del burgués

14 septiembre 2010

Programación orientada a componentes: Fundamentos I

Filed under: Uncategorized — elburgues @ 6:54 AM

Antes de seguir hablando de los principios de la programación orientada a componentes, es necesario aclarar ciertos conceptos.

El Common Language Runtime (CLR)

El CLR provee un contexto común dentro del cual todos los componentes .NET se ejecutan, independientemente del lenguaje con el que han sido escritos. El CLR maneja cualquier aspecto del código en tiempo de ejecución, (gestión de la memoria, entorno seguro de ejecución, acceso a los servicios del sistema operativo subyacente…). O sea, que lo que hace el CLR es gestionar la ejecución de las aplicaciones diseñadas para la plataforma .NET. Por eso, al código de estas aplicaciones se le suele llamar código gestionado o manejado y al código no escrito para ser ejecutado directamente en la plataforma .NET se le suele llamar código no gestionado o no manejado.

Microsoft Intermediate Languaje (MSIL)

Compilar código manejado es un proceso que comprende dos fases_

  1. Todos los compiladores que generan código para la plataforma .NET no generan código máquina para CPUs x86 ni para ningún otro tipo de CPU concreta, sino que generan código escrito en el lenguaje intermedio conocido como Microsoft Intermediate Language (MSIL). MSIL es el único código que es capaz de interpretar el CLR, y por tanto cuando se dice que un compilador genera código para la plataforma .NET lo que se está diciendo es que genera MSIL definido por Microsoft.
  2. Ya que las CPUs no pueden ejecutar directamente MSIL, antes de ejecutarlo habrá que convertirlo al código nativo de la CPU sobre la que se vaya a ejecutar. De esto se encarga un componente del CLR conocido como compilador JIT (Just-In-Time) o jitter que va convirtiendo dinámicamente el código MSIL a ejecutar en código nativo. La actuación de un jitter durante la ejecución de una aplicación gestionada puede dar la sensación de hacer que ésta se ejecute más lentamente debido a que ha de invertirse tiempo en las compilaciones dinámicas. Esto es cierto, pero en .NET, cada código no es interpretado cada vez que se ejecuta sino que sólo es compilado la primera vez que se llama al método al que pertenece. El hecho de que la compilación se realice dinámicamente permite que el jitter tenga acceso a mucha información sobre la máquina en que se ejecutará la aplicación, con lo que puede optimizar el código para ella generado.

Metadatos

Cuando un cliente usa un servidor ¿Cómo sabe que tipos contiene, el espacio de nombres en el que está contenido cada tipo, el nombre de cada tipo, su visibilidad, su clase base, que interfaces soporta, sus métodos, el prototipo de cada método y cosas así? La solución que .NET da a este problema se llama metadatos. Los metadatos son un conjunto de datos organizados de forma estándar en tablas, generados por el compilador de alto nivel directamente desde los archivos fuente e incrustándolos en el archivo físico que contiene el MSIL.

El significado de los metadatos es similar al de otras tecnologías previas a la plataforma .NET como lo son los ficheros IDL (interface definition languaje). Sin embargo, los metadatos tienen ventajas:

  • Contienen más información.
  • Siempre se almacenan incrustados en el módulo al que describen, haciendo imposible la separación entre ambos.
  • Es posible consultar los metadatos de cualquier módulo a través de las clases del espacio de nombres System.Reflection. Por ejemplo, IntelliSense usa Reflection.

En otra entrada ya haremos un resumen de lo que son los ensamblados y los archivos manifiestos y con eso ya tendremos los fundamentos para seguir hablando de los principios de la programación orientada a componentes.

Anuncios

12 septiembre 2010

Separar la implementación de la interfaz

Filed under: C# — elburgues @ 8:30 AM

Comprando un ratón usb, da igual la marca, uno espera poder conectarlo en cualquier ordenador, ya que ambos se comunican a través de una interfaz bien definida (USB). Otra cosa son los detalles de implementación física del ratón. Se trata de lograr algo así en desarrollo de software, a través de las interfaces. Una interfaz provee la definición abstracta de un servicio entre clientes y servidores. Cada servidor es libre de proveer su propia interpretación de esa interfaz. La interfaz es implementada por un componente binario de caja negra que encapsula completamente su interior. Este principio es el de la separación de interfaz e implementación y contrasta con la orientación a objetos, en la que el objeto en sí es el centro de atención.

En la programación orientada a componentes, la unidad fundamental de reutilización es la interfaz, para usar un componente, el cliente lo único que necesita conocer es la definición de la interfaz y ser capaz de tener acceso al componente binario que implementa esa interfaz. Veamos un ejemplo:

ClassDiagram

Todo lo que el cliente tiene que hacer es instanciar una clase que soporte la interfaz y asignar el objeto a una variable de la interfaz:

IMiInterfaz objeto;  
objeto = new MiClase();   
objeto.Metodo1();

Si cambia la implementación en MiClase, el cliente no tiene porqué enterarse. Además, en el ejemplo, esto también es posible:

IMiInterfaz objeto;
objeto = new MiOtraClase();
objeto.Metodo1();

De esta manera tenemos acceso a la interpretación que MiOtraClase de para la interfaz. En el ejemplo, IMiInterfaz sería como la interfaz USB, en dónde cada ratón (MiClase, MiOtraClase), cumplen con ella (la implementan), pudiendo tener cada objeto ratón sus peculiaridades de diseño (color, tamaño etc, eso ya depende de cómo definas cada una de las clases). Sin embargo, .NET también te deja hacer esto:

MiClase objeto;
objeto = new MiClase();
objeto.Metodo1();

en donde se está accediendo directamente a la clase que provee el servicio, en vez de hacerlo a través de la interfaz. O sea, que .NET no te obliga a cumplir con este principio a la hora de programar, siendo así accesible también a todos aquellos programadores que no están acostumbrados a usar los conceptos abstractos de la programación orientada a interfaces, pero que sepáis que los desarrolladores .NET disciplinados siempre deberían forzar la separación en sus desarrollos para obtener los beneficios de la programación orientada a componentes.

11 septiembre 2010

Programación orientada a componentes

Filed under: Uncategorized — elburgues @ 9:22 AM

El término componente quizás sea uno de los más confusos en programación. Un componente es el responsable de exponer lógica hacia los clientes, siendo los clientes cualquier cosa que use al componente. Un componente puede ser una clase, siendo el cliente otra clase. Entonces, ¿en qué se diferencia la programación orientada a componentes de la programación orientada a objetos? Pues ahí reside la confusión que suele envolver al término componente, en saber dónde trazar las líneas que separan:

  • La clase que implementa cierta lógica.
  • La entidad física que contiene a la clase (dll).
  • La lógica asociada para hacer uso de la clase (información de tipos, política de seguridad, información de versiones…).

Digamos que la programación orientada a objetos se focaliza en las relaciones que hay entre las clases combinadas dentro de un gran ejecutable binario, mientras que la programación orientada a componentes se centra en módulos intercambiables que trabajan de forma independiente y de los cuales no es necesario saber nada acerca de sus implementación interna. La diferencia entre ambas técnicas es la manera que tienen ellas de ver a la aplicación final. En la programación orientada a objetos, el resultado es un código binario monolítico, todas las clases se localizan en él, mientras que la programación orientada a componentes se puede imaginar como las piezas del lego, un cambio en la implementación de una de las piezas está disponible inmediatamente para todo cliente que la use, sin necesidad de recompilar.

En la programación orientada a objetos, las aplicaciones son modeladas con jerarquías de clases complicadas, pero esa es una forma pobre de alcanzar la reutilización de código. Para derivar de una clase base y extenderla, tienes que estar muy familiarizado con los detalles de implementación de la clase base, para estar seguro de cómo va a afectar a los clientes los cambios que tú hagas. Es lo que se conoce con el nombre de reutilización de caja blanca. La programación orientada a componentes, lo que predica es la llamada reutilización de caja negra, es decir, permite usar un componente existente sin necesidad de conocer los detalles internos de su implementación. Esto se logra a través de las interfaces. En vez de diseñar complejas jerarquías de clases, se diseñan interfaces usadas como contratos entre componentes, clientes y servidores. O sea, que hay que tender ha diseñar jerarquías de clases simples y centrarse en la programación orientada a interfaces.

Una aplicación orientada a componentes es más fácil de extender (cumplir con nuevos requisitos a través de nuevos componentes sin tocar los ya existentes), reduce los costes de mantenimiento de las aplicaciones y normalmente sus desarrollos suelen ser más cortos en términos de tiempo.

Los principios más importantes de la programación orientada a componentes son:

  1. La separación de la interfaz de la implementación.
  2. La compatibilidad binaria.
  3. La independencia del lenguaje.
  4. La transparencia en la localización.
  5. La gestión de la concurrencia.
  6. El control de versiones.
  7. La seguridad basada en componentes.

.NET te habilita para cumplir con cada uno de estos principios, pero no obliga. En próximas entradas iré explicando cosas de cada uno de ellos.

Blog de WordPress.com.