jueves, 22 de abril de 2010

Principios básicos de la Orientación a Objetos

A los que sobre todo han ido a la Universidad a estudiar asignaturas de programación con orientación a objetos les sonarán los conceptos de acoplamiento, cohesión y encapsulación. Son conceptos muy fáciles de entender, pero que normalmente muchos desarrolladores no aplican a sus proyectos. Muy probablemente se deba a que estos desarrolladores, a pesar de conocer estos conceptos, no entienden los beneficios de usar diseños con bajos niveles de acoplamiento, alta cohesión y una buena encapsulación de los componentes.

En esta entrada quiero mostrar las ventajas de usar correctamente estos principios y como nos podría ayudar en os desarrollos que estemos haciendo.

Acoplamiento

En desarrollo software, el acoplamiento se puede definir como el grado en el que dos ó más componentes o clases dependen unas de otras.

Un buen diseño o una buena arquitectura tratará de mantener un nivel de acoplamiento bajo. Me explico con un ejemplo: supongamos que tenemos un software con la siguiente arquitectura de componentes donde se muestran las dependencias que hay entre estos: Acoplamiento Ahora tenemos otro desarrollo distinto, y vemos que una de las funcionalidades ya la realiza el Módulo C del proyecto de la imagen. Perfecto, cogemos ese módulo y lo usamos en nuestro nuevo desarrollo. En seguida nos damos cuenta que es más fácil decirlo que hacerlo. Tiene demasiadas dependencias con otros componentes que a su vez también tienen otras dependencias. Por lo que usar el componente C nos va a suponer también traernos muchos de los otros componentes de los que depende. Es decir, el componente C tiene un grado de acoplamiento muy alto con el resto de componentes.

“Si un componente tiene un alto grado de acoplamiento con otros componentes, entonces para usar ese componente vas a tener que usar también los otros de los que dependen aunque no los necesites.”

Se puede reducir el nivel de acoplamiento de un componente de muchas maneras. La más usual es la de usar interfaces o herencia de clases entre los componentes que desacoplen la dependencia entre estos.

Por el lado contrario, no existen los componentes con nivel de acoplamiento cero. No tienen sentido. Un módulo que no depende de nada y del que nadie depende, ¿qué uso puede tener?

En definitiva, el acoplamiento no es algo estrictamente malo. Los componentes que forman parte de un sistema deben de poder interactuar unos con otros para que este pueda realizar alguna función. Por tanto, el objetivo es alcanzar un equilibrio en el grado de acoplamiento de los componentes de manera que sea funcional (que haga lo que tiene que hacer), entendible y mantenible por otros desarrolladores.

Cohesión

El grado de cohesión de un componente es la relación funcional que existe entre las funciones de ese componente para realizar una tarea. Es decir, un módulo coherente es capaz de realizar una tarea sin necesidad de interactuar con otros componentes.

Haciendo una extrapolación para sistemas complejos, la cohesión define cómo los distintos componentes que forman parte del sistema se relacionan e interaccionan para crear un sistema que da un valor añadido mayor que el que pueden dar la suma de sus partes.

“El todo es mayor que la suma de las partes.”

Este es un concepto mucho más abstracto y quizás más difícil de conseguir debido a que no hay modelos ni recetas mágicas que nos digan como conseguir desarrollar software con un alto grado de cohesión. Sin embargo es un concepto que es bastante usado de la vida cotidiana. Muchas veces hemos oído aplicarlo al deporte: Equipos con alto valor de cohesión consiguen mejores resultados en las competiciones en las que participan que otros menos cohesionados aunque sus jugadores sean mucho mejores. También las empresas buscan esa cohesión: tener equipos de trabajoque trabajen juntos para conseguir productos a tiempo con la mejor calidad posible.

Supongamos la arquitectura del sistema de la imagen siguiente.Cohesion

Si se analizan por separado cada uno de los componentes del sistema realmente no se tiene gran cosa. Por separado cada componente realiza una serie de tareas muy limitadas con poco valor por si mismo. Sin embargo, cuando se juntan los componentes y se hace que interaccionen coherentemente entre sí, el valor aportado es muchísimo mayor.

Para conseguir hacer software con un nivel de cohesión elevado debemos tratar de huir de las mega-clases y mega-componentes que hacen de todo. Es posible que internamente estén bien cohesionados, pero a nivel de sistema no será así. Por ejemplo, que un componente sea capaz de leer los datos de la base de datos, procesarlos y mostrarlos en algún tipo de interfaz de usuario.

Hay muchos patrones que están enfocados a lograr buenos niveles de cohesión. Por ejemplo el multi-capa (como el del diagrama anterior), MVC, MVVM, etc.

Encapsulación

El grado de encapsulación de un componente viene definido por la forma en el que el componente oculta la información superflua y la lógica de lo que hace al resto de componentes del sistema.

Y es que muchos desarrolladores entiende por encapsulación sólo la ocultación de información, dejando de lado la lógica que los componentes implementan.
Encapsulación

Supongamos un diseño en el que la clase X está bien encapsulado. Entre otras ventajas, el hecho de ocultar la lógica hacia el exterior hace que podamos cambiar la implementación interna sin que afecte al resto de clases del diseño. Por otro lado, si hacemos que la funcionalidad de la clase X se base en la implementación de interfaces, los componentes que necesiten usar X se referirán a ella por sus interfaces y no por la clase en sí.

Por ejemplo, supongamos este par de interfaces sencillas definidas en C#:

public interface IAnimal
{
string Especie { get; }
void Comer();
void Andar();
void Atacar();
}

public interface IPersona
{
string Nombre { get; set; }
DateTime FechaNacimiento { get; set; }
void Trabajar();
void Hablar();
}

public class HombreLobo : IAnimal, IPersona
{
#region IAnimal Members

public string Especie { get { return "Lobo"; } }

public void Comer()
{
// ...
}

public void Andar()
{
// ...
}

public void Atacar()
{
// ...
}

#endregion

#region IPersona Members

public string Nombre {get; set;}

public DateTime FechaNacimiento {get; set;}

public void Trabajar()
{
// ...
}

public void Hablar()
{
// ...
}

#endregion
}


Los componentes que quieran usar esta clase lo pueden hacer basándose en las interfaces que la clase implementa:



public class MiClase
{
public void HacerAlgo()
{
IAnimal lobo = new HombreLobo();
lobo.Atacar();
lobo.Comer();
}
}


Una correcta encapsulación de las clases o componentes nos ayuda a reducir la duplicación de datos y de procesos en nuestros desarrollos y nos va a ayudar en situaciones donde necesitemos usar alguna funcionalidad proporcionada por alguna de nuestras clases en más de un sitio.



Para terminar



Cada uno de los principios que hemos visto están conectados entre sí: El desarrollo de componentes fuertemente encapsulados facilita que consigamos disminuir el nivel de acoplamiento de estos componentes. Y por consecuencia, tener encapsulación y bajo acoplamiento nos ayudará a asegurarnos el tener un sistema altamente cohesionado.

domingo, 18 de abril de 2010

Windows 7. ¿32 o 64 bits?

Estoy pendiente de formatear mi PC y no tengo claro si poner la versión de Windows 7 de 32 ó la de 64 bits. O lo que es lo mismo, Windows x86 ó x64. Así que me he lanzado a la tarea de ver las diferencias que hay entre ambas versiones.

Haciendo un poco de historia, las versiones de sistemas operativos de 64 bits empezaron a popularizarse con la salida de Windows XP de 64 bits, que coincidió con la escalada tecnológica de AMD e Intel por sacar procesadores de 64 bits.
La historia ha dejado claro que el mercado no estaba preparado para sistemas operativos de 64 bits. Windows XP 64 bits no tuvo buena acogida. Además del pobre rendimiento que daba en algunas aplicaciones de 32 bits, tenía el handicap de que necesitaba drivers de dispositivos nativos de 64 bits.
No ha sido hasta Windows 7 que Microsoft se ha centrado en hacer un sistema operativo realmente enfocado para procesadores de 64 bits unido con la gran cantidad de drivers que traía y el comienzo de los fabricantes de dispositivos a entregar controladores nativos de 64 bits cuando Windows x64 se ha convertido en una opción real para los consumidores.

La principal diferencia entre cualquier sistema operativo de 64 bits y otro de 32 bits es la cantidad de memoria RAM que puede manejar. La CPU de un ordenador de 32 bits puede direccionar 2 elevado a 32 posiciones de memoria. O lo que es lo mismo, 4 gigas de RAM, que es lo máximo que normalmente tenemos en nuestros equipos. Sin embargo, con una CPU de 64 bits, la cantidad de memoria que se puede manejar se multiplica. La limitación de la cantidad de RAM que se puede poner en un PC no la pone la CPU,  sino el sistema operativo o la placa base del PC.
Si no me equivoco, Windows 7 x64 es capaz de soportar hasta 192 gigas de RAM, que es bastante más de lo que cualquier placa base soporta. Esto repercute en el rendimiento del sistema operativo, que es capaz de manejar más aplicaciones a la vez, y cambiar entre aplicaciones más rápidamente.

En definitiva. ¿Qué hace que me decante por instalar la versión de 64 bits en lugar de la de 32?
Bien, a parte de tener una CPU de 64 bits, lo principal es asegurarse de que disponemos de versiones de controladores para nuestros dispositivos que sean nativos de 64 bits.
Con respecto a los programas. Según Microsoft no hay problema en ejecutar software de 32 bits salvo algunos antivirus y por supuesto los controladores de dispositivos.

Así que por mi parte ya lo tengo claro. En cuento encuentre controladores de 64 bits le instalo el Windows 7 x64.

Saludos a todos.