Object oriented design – c# Principios de diseño de paquetes

Principios de diseño de paquetes
Principios de diseño de paquetes

Antes de empezar a hablar acerca de los principios de diseños de paquetes conozcamos a que nos referimos cuando hablamos de un paquete.

Un paquete es una pieza de software reusable y testeable que provee un conjunto de funcionalidades especificas dentro de un sistema y está formada por un grupo de clases. 

Nota: Al hablar de paquetes nos referimos a un componente o una librería que genera un archivo .jar o .dll.

Principios de diseño de paquetes

Estos principios fueron introducido por Robert C. Martin, existen 6 principios que se aplican al diseño de paquetes, los tres primeros principios hablan acerca de la cohesión y los otros tres acerca del acoplamiento entre paquetes.

Cohesión de paquetes

Los 3 primeros principios de diseño de paquetes señalan que debe contener cada paquete para obtener una alta cohesión.

REP: The realease/reuse equivalency principle

Un paquete reusable es un paquete liberado (release). Solo los paquetes que son liberados a través de un sistema de Tracking (Concurrent Version System) pueden ser efectivamente reusados. Para poder reusar efectivamente un código este debe venir en una caja negra (un archivo .dll o .jar) el cual es usado, pero no cambiado por nosotros. Los desarrolladores que deciden usar un paquete se encuentran protegidos de cambios que se realicen en el (nuevas versiones), ya que ellos deciden el momento para integrar estos cambios o simplemente deciden trabajar con una versión antigua. Al seguir este principio nos aseguramos que nuestro paquete es creado con clases reusables.

Por el lado de .Net contamos con el administrador de paquetes Nuget, cada vez que instalamos un paquete este registra la versión con la que estamos trabajando y ante una actualización del paquete (hecha por los responsables de su mantenimiento) somos nosotros los que decidimos si aplicamos los cambios o seguimos trabajando con la versión con la que empezamos el desarrollo.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AntiXSS" version="4.3.0" targetFramework="net40" />
  <package id="Common.Logging" version="2.3.1" targetFramework="net40" />
  <package id="elmah" version="1.2.2" targetFramework="net40" />
  <package id="NLog" version="3.1.0.0" targetFramework="net40" />
  <package id="Quartz" version="2.3" targetFramework="net40" />
</packages>

Además, para saber cuándo usar un paquete externo debemos asegurarnos que cumpla con lo siguiente:

  • Documentación: Completa, acertada y actualizada.
  • Mantenimiento: Bugs corregidos, las mejoras son consideradas, etc.
  • Confiabilidad: No hay cambios repentinos, se mantiene las versiones anteriores.

Otros administradores de paquetes:

  • RubyGems / Bundler (Ruby)
  • PIP / PyPI (Python)
  • Packagist / Composer (PHP)
  • NPM (Node.JS)
  • Bower (JS, CSS, HTML)
  • CocoaPods (Objective-C)
  • Maven (Java)
  • Lein (Clojure)
CCP: The common closure principle

Las clases que cambian juntas son empaquetadas juntas, un cambio en un paquete afecta a todas las clases que se encuentren dentro. El objetivo de este principio es minimizar el impacto de un cambio para afectar la menor cantidad de paquetes posibles, si existen clases que tienen un alto acoplamiento estas se deben empaquetar juntas. Al seguir este principio aumentamos el mantenimiento ya que al producirse un cambio este afecte pocos paquetes que tendrán que ser recompilados.

Common closure principle - antes
Common closure principle – antes
Common closure principle - despues
Common closure principle – despues
CRP: The common reuse principle

Las clases que son usadas juntas deben empaquetarse juntas. Las clases en un paquete son reusadas juntas, si reusas una de las clases, reusas todas. Esto quiere decir que sin un desarrollador confía en una clase del paquete debe confiar en todas. Debemos tener en cuenta que al usar un paquete se traen todas sus referencias, lo cual origina un problema si solo estamos interesados en ciertas funcionalidades. Este principio es análogo al principio de diseño SRP, si un paquete tiene muchas responsabilidades debe partirse para no obligar a tener dependencias innecesarias. Al seguir este principio  conseguiremos trabajar con paquetes específicos con responsabilidades únicas.

Common reuse principle - antes
Common reuse principle – antes

Common reuse principle - despues
Common reuse principle – despues

Acoplamiento de paquetes

Estos 3 últimos principios de diseño de paquetes hablan acerca de las métricas que evalúan la estructura de un sistema  con la finalidad de conseguir un bajo acoplamiento.

ADP: The acyclic dependencies principle

Un paquete no debe tener dependencias cíclicas con otros paquetes. La estructura de dependencias de un paquete debe ser un Direct Acyclic Graphic, esto quiere decir que no debe haber dependencias cíclicas.

Acyclic dependencies principle - antes
Acyclic dependencies principle – antes

Para romper las dependencias cíclicas se recomienda:

  • Abstraer interfaces, aplicar el principio DIP.
  • Dividir paquetes, aplicar el principio CRP.
Acyclic dependencies principle - despues
Acyclic dependencies principle – despues
SDP: The stable dependencies principle

La dependencia de paquetes en un diseño debe estar en dirección de la estabilidad de los paquetes. Un paquete solo debe depender de paquetes que son más estables que el para que nuestro paquete sea fácil de cambiar.

Métrica de inestabilidad:

Esta métrica es usada para conocer la resistencia al cambio que tiene un paquete, su fórmula es la siguiente: I = Ce / (Ce+Ca). Donde:

  • Afferent Couplings (Ca): El número de clases que se encuentran fuera del paquete y que dependen de las clases que se encuentran dentro del paquete, Afferent = entrante.
  • Efferent Couplings (Ce): El número de clases que se encuentran fuera del paquete y que las clases que se encuentran dentro del paquete dependen de ellas, Efferent = saliente.

El rango para esta métrica es de 0 a 1, con I=0 indica que un paquete es completamente estable y con I>0 indica que es paquete completamente inestable y que cualquier cambio será difícil de implementar.

Métrica de inestabilidad Caso 1: Paquete 1

  • Ce = 3
  • Ca = 0
  • Resultado = 1, Es un paquete inestable.
Métrica de inestabilidad - caso1
Métrica de inestabilidad – caso1
Métrica de inestabilidad Caso 2: Paquete 1
  • Ce = 3
  • Ca = 0
  • Resultado = 0, Es un paquete estable.
Métrica de inestabilidad - caso2
Métrica de inestabilidad – caso2
Métrica de inestabilidad Caso 3: Paquete 1
  • Ce = 1
  • Ca = 2
  • Resultado = 0.33, Es un paquete inestable.
Métrica de inestabilidad - caso3
Métrica de inestabilidad – caso3
Métrica de inestabilidad Caso 4: Paquete 1
  • Ce = 0
  • Ca = 3
  • Resultado = 0, Es un paquete estable.
Métrica de inestabilidad - caso4
Métrica de inestabilidad – caso4
No todos los paquetes deben ser estables

Si todos los paquetes es un sistema fueran estables no se podrían hacer cambios. En la estructura de paquetes que diseñemos algunos paquetes deben ser estables y otros inestables. Los paquetes estables deben mantener partes que no cambian, como el diseño de alto nivel del sistema (core), y los paquetes inestables deben mantener las partes cambiantes, como las implementaciones (infraestructura).

Configuración ideal de paquetes
Configuración ideal de paquetes

En el caso se desee cambiar o extender un paquete estable se debe aplicar el principio OCP para crear clases que son flexibles a ser extendidas sin necesidad de modificarlas, para esto debemos hacer uso de clases abstractas.

SPA: The stable abstraction principle

Los paquetes que son estables deben ser abstractos y los paquetes inestables deben ser concretos. La abstracción de un paquete debe en proporción a su estabilidad. Un paquete debe ser abstracto de modo que su estabilidad no impida que se extienda. Además, los paquetes estables deben ser fáciles de depender de ellos y los paquetes inestables deben ser fáciles de cambiar.

Métrica Distance from the Main Sequence:

Esta métrica indica que la abstracción y la estabilidad de los paquetes están estrechamente relacionados. También es conocido como “The Perpendicular Distance of a Package from the Idealized Line A + I = 1” el valor ideal es D = 0, es decir, a más abstracto un paquete es, más estable debería ser ya que debe tener muchos clientes que dependan de sus abstracciones. Los paquetes que son más estables (I=0) y al mismo tiempo más abstractos (A=1) son considerados buenos. Pasa lo mismo cuando un paquete es inestable (I=1) y al mismo tiempo es concreto (A=0) también son considerados buenos paquetes.

Distance from the Main Sequence
Distance from the Main Sequence

Nota: Para conocer más acerca de esta métrica les recomiendo visitar esta página.

Conclusión:

Son 6 principios que se dividen en dos grupos: cohesión y acoplamiento. En cohesión tenemos: REP: The realease/reuse equivalency principle, se enfoca en el reuso; CCP: The common closure principle, se enfoca en el matenimiento; y CRP: The common reuse principle, se enfoca en la división de dependencias. Para la parte de acoplamiento tenemos: ADP: The acyclic dependencies principle, indica que no deben existir dependencias cíclicas entre los paquetes; SDP: The stable dependencies principle, indica que se debe depender de paquetes estables; y SPA: The stable abstraction principle, indica que mientras más estable es una clase más abstracta debe ser.

Referencias:
Metal Tip:

Este artículo lo escribí escuchando el disco Extreme Aggression de la banda Kreator de Alemania, les comparto el enlace.

Anuncios

2 comentarios en “Object oriented design – c# Principios de diseño de paquetes

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s