Grado verde

Índice

Principios

Principio Abierto Cerrado (OCP)

Principio Abierto Cerrado (OCP)

¿Por qué?
Porque el riesgo de desestabilizar un sistema previamente libre de errores con nuevas funciones debe mantenerse lo más bajo posible.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

En Principio Abierto Cerrado (OCP) establece que una clase debe estar abierta a ampliaciones pero cerrada a modificaciones. Es otra de las SÓLIDO Principios. El siguiente ejemplo de código pretende ilustrar dónde radica el problema si no se sigue el principio:

public double Precio() {
    const decimal StammkundenRabatt = 0,95m;
    switch(tipo de cliente) {
        case Kundenart.Einmalkunde:
            return cantidad * precio unitario;
        case tipo de cliente.cliente regular:
            return cantidad * precio unitario * regularcustomerDiscount;
        por defecto
            throw new ArgumentOutOfRangeException();
    }
}

El problema de esta forma de implementación es que la clase debe modificarse si se requiere otro tipo de cálculo de precios. El peligro aquí es que se cometan errores durante esta modificación y las funciones existentes dejen de funcionar correctamente. Incluso si se dispone de pruebas unitarias automatizadas y pruebas de integración, existe el riesgo de dejar atrás nuevos errores porque no es posible lograr una cobertura de pruebas del 100%. Por lo general, lo que se necesita es un método que permita ampliar la clase sin tener que modificarla. Esto puede conseguirse, por ejemplo, con la ayuda del método Patrones estratégicos puede lograrse:

public interface IPreisRechner {
    double Precio(int cantidad, double precio unitario);
}

private IPreisRechner preisRechner;

public double Preis() {
    return preisRechner.Preis(cantidad, precio unitario);
}

public class Cliente único : IPrecioCalculador {
    public double Precio(int cantidad, double precio unitario) {
        return cantidad * precio unitario;
    }
}

public class Cliente regular : IPrecioCalculador {
    const decimal StammkundenRabatt = 0.95m;
    
    public double Precio(int cantidad, double precio unitario) {
        return cantidad * precio unitario * descuento cliente regular;
    }
}

El cálculo real del precio se subcontrata a otras clases a través de una interfaz. Esto permite añadir nuevas implementaciones de la interfaz en cualquier momento. Esto significa que la clase está abierta a ampliaciones, pero al mismo tiempo cerrada a modificaciones. El código existente puede, por ejemplo, ser refactorizado con la interfaz Sustituir Condicional por Estrategia rediseñarse de forma que se respete el principio de apertura y cierre.

Fuentes

FuenteAutorBreve descripción
 Robert C. MartinArtículo sobre el Principio Abierto Cerrado publicado en 1996 para The C++ Report
Cuéntalo, no preguntes

Cuéntalo, no preguntes

¿Por qué?
La alta cohesión y el acoplamiento débil son virtudes. Los detalles de estado públicos de una clase contradicen esto.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

Por decirlo de una manera algo provocativa, las clases no deberían tener getters de propiedades. Éstos tientan al usuario de una clase a tomar decisiones basadas en valores proporcionados por un objeto. En lugar de decirle al objeto lo que debe hacer, se le hacen preguntas para que luego emita juicios externos sobre el estado interno del objeto.

Uno de los principios básicos de la programación orientada a objetos es Ocultación de información (véase también el grado amarillo). Ninguna clase debe llevar detalles al mundo exterior que revelen cómo se implementa internamente. Si una clase requiere un estado interno para su trabajo, éste se almacena normalmente en un campo interno. Si este valor también es visible para el mundo exterior, los usuarios se ven tentados a utilizar este estado interno del objeto para sus propias decisiones. Esto degrada rápidamente la clase a puro almacenamiento de datos. Una implementación en la que a un objeto se le dice lo que debe hacer es siempre preferible. Esto significa que el usuario ya no tiene que interesarse por cómo la clase realiza la tarea internamente.

Como resultado de la No preguntes En principio, se crean objetos con comportamiento en lugar de objetos "tontos" de almacenamiento de datos. La interacción entre los objetos está poco acoplada, ya que los objetos no tienen que hacer ninguna suposición sobre los objetos colaboradores. Pero eso no es todo. Si los objetos no publican su estado, conservan la autoridad para tomar decisiones. Esto aumenta la cohesión del código decisivo, ya que se agrupa en un solo lugar.

A continuación se muestra un ejemplo de código típico. En lugar de preguntar primero si los mensajes de rastreo están activados en el registro (Ask), se debería ordenar directamente a la biblioteca de registro que emita el mensaje de rastreo (Tell). La biblioteca debería entonces decidir internamente si el mensaje se registra o no.

if (_logger.Trace()) {
_logger.TraceMsg("... un mensaje... ");
}

Ley de Deméter (LoD)

Ley de Deméter (LoD)

¿Por qué?
La dependencia de objetos en varios eslabones de una cadena de servicios provoca un acoplamiento poco atractivo.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

En el Ley de Deméter consiste en limitar la interacción entre objetos a un nivel saludable. En términos sencillos, esto se resume en "No hables con extraños". Según la Ley de Deméter, un método sólo debe utilizar los siguientes otros métodos:

  • Métodos de su propia clase
  • Métodos paramétricos
  • Métodos de clases asociadas
  • Métodos de objetos de creación propia

Sin embargo, hay que señalar que las clases puras de retención de datos también tienen sentido de vez en cuando. Por supuesto, no es necesario aplicar a éstas la Ley de Deméter. Por ejemplo, puede tener sentido distribuir jerárquicamente los datos de configuración en varias clases, de modo que al final se pueda acceder a un valor de la siguiente manera:

int margin = config.Pages.Margins.Left;

Si se aplicara aquí la Ley de Deméter, sólo se permitiría el acceso a config.pages.

Prácticas

Integración continua (IC)

Integración continua (IC)

¿Por qué?
La automatización y centralización de la producción de software aumentan la productividad y reducen el riesgo de errores durante la entrega.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

La integración de componentes de software suele posponerse y llevarse a cabo "a mano" de forma lenta y propensa a errores. Sin embargo, en realidad el software debería ser totalmente ejecutable en todo momento. La integración continua es un proceso que garantiza que todo el código se compila y se prueba después de enviar los cambios.

El proceso de integración continua es especialmente importante para los equipos, ya que garantiza que todo el código se compila y se prueba después de enviar los cambios, no sólo la parte en la que acaba de trabajar un desarrollador. Cada desarrollador debe realizar las pruebas automatizadas antes de enviar los cambios al sistema central de control de versiones. La integración continua no cambia esta situación. Para garantizar que las pruebas se ejecutan realmente y que los errores se reconocen en una fase temprana, siempre se ejecutan en el servidor de integración continua. Esto no exime al desarrollador de ejecutar las pruebas antes de la confirmación; después de todo, un código defectuoso que se ha comprobado en el control de versiones perjudica a todo el equipo, posiblemente incluso a otros equipos. Por tanto, el proceso de integración continua garantiza que los errores se reconozcan lo antes posible en todos los equipos.

Para el proceso de integración continua, existen numerosos Herramientas informáticas está disponible. Además de la compilación y prueba continuas, que tienen lugar inmediatamente cuando los cambios se transfieren al control de versiones, la integración continua también puede utilizarse para automatizar procesos de ejecución más larga, como las pruebas de bases de datos. Así, por ejemplo, sólo se ejecutan por la noche. A nivel ecológico, sólo se tiene en cuenta el proceso de compilación y prueba. La instalación y el despliegue continuos del software sólo se realizan más tarde en el nivel grado azul.

Martin Fowler ha escrito un artículo muy bueno sobre este tema, que puede leerse en http://www.martinfowler.com/articles/continuousIntegration.html

Véase también Herramientas.

Análisis estático del código

Análisis estático del código

¿Por qué?
La confianza es buena, el control es mejor, y cuanto más automático, más fácil.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

¿Cómo se define realmente la calidad de una unidad de código, por ejemplo, una clase o un componente? ¿Basta con que cumpla funcionalmente los requisitos del cliente? ¿Es suficiente que sea lo suficientemente rápida y escalable? Las pruebas automáticas y, en última instancia, las pruebas realizadas por el cliente proporcionan información al respecto. Sin esta conformidad con los requisitos, el software no tiene calidad relevante. Si no es útil para el cliente, no hay necesidad de hacer más preguntas.

Por otra parte, en contra de la creencia generalizada, no basta con cumplir los requisitos. La alta calidad no es sólo funcionalidad y rendimiento, por ejemplo. Además de los requisitos funcionales y no funcionales, también hay un requisito oculto, casi siempre tácito: los clientes siempre quieren que el software cumpla sus requisitos no sólo hoy, sino también mañana y pasado mañana. Los clientes quieren proteger su inversión mediante la posibilidad de cambios.

Para los clientes, este requisito suele estar implícito. Creen que no hace falta decir que un producto intangible como el software puede adaptarse a nuevas necesidades casi infinitamente y con sólo pulsar un botón. Incluso los directivos que no proceden del desarrollo de software suelen creerlo. E incluso los propios desarrolladores de software.

Sin embargo, el malentendido sobre el software difícilmente podría ser mayor. La capacidad de cambio no es algo natural, en el sentido de un objetivo que todo desarrollador de software persigue de todos modos, ni surge por sí sola. Más bien, la capacidad de cambio es un trabajo duro y debe sopesarse constantemente con otros valores.

Si ahora es posible determinar la conformidad con otros requisitos mediante pruebas (automatizadas), ¿qué ocurre con la modificabilidad? ¿Puede medirse también automáticamente la calidad del código en cuanto a su viabilidad (de supervivencia)? En parte. No todos los aspectos que hacen que un software sea evolutivo pueden probarse automáticamente. Por ejemplo, no se puede reconocer automáticamente si el software se mantiene abierto a ampliaciones mediante un concepto de complemento.

No obstante, existen Métricascuyo valor puede "calcularse" por software. Herramientas ayudan a ello. Por tanto, estas herramientas deberían utilizarse en todos los proyectos de software.

  • En el caso del código heredado, las herramientas pueden determinar el statu quo y definir así una línea de base con la que comparar el desarrollo posterior del código (para mejor).
  • En el caso del código nuevo que se planificó teniendo en cuenta la posibilidad de cambio, este análisis estático del código muestra si cumple el ideal de la planificación.

Los CCD no se conforman con probar el código automáticamente. También vigilan siempre su modificabilidad, porque saben que los clientes están igual de interesados en ella, independientemente de que lo hayan dicho explícitamente o no.

Véase también Herramientas.

Contenedor de inversión de control

Contenedor de inversión de control

¿Por qué?
Sólo las cosas que no están cableadas pueden reconfigurarse más fácilmente.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

Ya en el grado amarillo el CCD conoció el Principio de Inversión de Dependencias. Las dependencias seguían resolviéndose "a mano". El siguiente paso lógico es ahora automatizar la resolución de dependencias. Para ello existen dos métodos:

  • Localizador
  • Contenedor

Ambos utilizan un Contenedor de inversión de control (contenedor IoC). Antes de utilizar el contenedor, las clases utilizadas deben almacenarse en él. A continuación, el contenedor puede entregar instancias de las clases almacenadas. Con el Localizador esto se hace explícitamente. Esto tiene la ventaja de que no es necesario enumerar todas las dependencias en el constructor de la clase. Para tareas transversales como Registro se trata de un procedimiento habitual. Sin embargo, por regla general, las relaciones se enumeran como parámetros del constructor. Esto tiene la ventaja de que todas las dependencias son visibles. De este modo, el contenedor puede resolver las dependencias implícitamente instanciando recursivamente todos los objetos necesarios a través del contenedor.

Los contenedores IoC cobran importancia en cuanto crece el número de clases. Si usted Separación de preocupaciones se crean muchas clases pequeñas con tareas manejables. El ensamblaje de instancias de estas clases se vuelve cada vez más complejo. Aquí es precisamente donde entra en juego el contenedor IoC, que ayuda a instanciar y conectar los numerosos objetos pequeños.

Otra ventaja de los contenedores IoC es el hecho de que los Ciclo de vida de un objeto puede determinarse mediante la configuración. Si sólo va a haber una única instancia de un objeto en tiempo de ejecución (Singleton), se puede ordenar al contenedor que entregue siempre una misma instancia. Otros ciclos de vida como Una instancia por sesión son compatibles.

Para evitar depender de un contenedor IoC específico cuando se utiliza un localizador, la función Localizador de servicios comunes de Microsoft (ver Herramientas). Esto ofrece una interfaz estandarizada para los contenedores IoC comunes.

Para entender la mecánica que hay detrás de un contenedor IoC, es útil implementar la funcionalidad uno mismo. El objetivo no es implementar un contenedor completo, sino sólo las funciones básicas.

Véase también Herramientas.

Compartir experiencias

Compartir experiencias

¿Por qué?
Quienes transmiten sus conocimientos no sólo ayudan a los demás, sino también a sí mismos.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

El trabajo profesional requiere, como es natural, conocimientos constantemente actualizados. Por supuesto, esto no significa que cualquiera pueda y deba saberlo todo sobre el desarrollo de software, aunque sea en la plataforma .NET. Los conocimientos actualizados se refieren a las propias áreas de especialización, sean cuales sean. Un componente de otras titulaciones es, por tanto, la práctica de recibir regularmente información a través de diversos medios.

Sin embargo, por varias razones, esta recopilación de información debería ser sólo una de las dos caras de la moneda del "aprendizaje". La otra es la transmisión de información, la transferencia de conocimientos. En nuestra opinión, la verdadera profesionalidad implica no sólo "investigar", sino también "enseñar". Porque sólo con la "enseñanza" tiene lugar la verdadera reflexión y penetración en un tema.

Aplicar lo que has oído o leído es una cosa. Por supuesto, también te das cuenta de las lagunas en tu comprensión. Sin embargo, la "exploración" de un objeto está naturalmente limitada por su uso previsto. Si sólo investigas hasta donde necesitas una tecnología/concepto, no necesariamente profundizas en ella.

Sin embargo, es completamente diferente cuando el aprendizaje tiene lugar con el signo de la transmisión. Quien aprende no sólo para sí mismo, sino también para los demás, aprende más profundamente. Esto queda claro cuando intentas transmitir a otros lo que (supuestamente) has aprendido. Si no tienes esto en cuenta cuando aprendes, rápidamente surgen preguntas que nunca te has planteado. Los demás siempre tienen perspectivas completamente distintas.

Por eso creemos que sólo quienes se exponen repetidamente a enseñar, transmitir e impartir conocimientos son aprendices verdaderamente sólidos. Sólo aquellos que no sólo aplican lo que han aprendido, sino que además lo formulan con sus propias palabras para un público, se dan cuenta en el proceso de lo profundos que son realmente sus conocimientos. Porque si los signos de interrogación empiezan a acumularse entre los "alumnos", es que algo no va del todo bien.

Por supuesto, para ello lo mejor es un público real. Por ello, todos los CCD deberían buscar oportunidades periódicas para transmitir sus conocimientos verbalmente (por ejemplo, en actos con colegas o reuniones de grupos de usuarios). Seguro que reciben una respuesta directa. Como alternativa o complemento, también son útiles las declaraciones escritas de conocimientos. Se puede crear un blog en 5 minutos y las revistas especializadas buscan constantemente nuevos autores. Puede que en este caso la respuesta no sea tan directa, pero la formulación textual de los conocimientos sigue siendo un ejercicio muy bueno.

Por tanto, los desarrolladores de código limpio a partir del nivel verde no sólo aprenden "pasivamente" absorbiendo información, sino "activamente" transmitiendo sus conocimientos mediante presentaciones o textos. Esto puede resultar poco familiar, pero también puede serlo la Integración Continua. En cualquier caso, la transferencia activa de conocimientos es un buen ejercicio para profundizar en las propias competencias según el lema: "Haz el bien y habla de ello" ;-)

Ni que decir tiene que "enseñar" también tiene un beneficio para los oyentes/lectores. Pero los beneficios para los demás no son tan motivadores como los beneficios para uno mismo. Por eso hacemos hincapié en los beneficios de la transferencia de conocimientos para el desarrollador de código limpio.

Medición de errores

Medición de errores

¿Por qué?
Sólo quien sabe cuántos errores se producen puede cambiar su enfoque para reducir el porcentaje de errores.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

Los errores ocurren durante el desarrollo de software. Ocurren en todas las fases: los requisitos mal entendidos o formulados de forma poco clara conducen a errores, al igual que las implementaciones defectuosas. Al final, todo es un error, que hace que el cliente reciba un software que no cumple sus requisitos. Los procedimientos iterativos y la reflexión son dos elementos que sirven para mejorar el proceso. Sin embargo, para reconocer si realmente se está produciendo una mejora, debe existir una métrica que permita identificar una evolución a mejor.

Los errores pueden medirse mediante recuento o cronometraje. La precisión no es importante, siempre que el método de medición proporcione datos comparables. La tendencia de desarrollo a lo largo de varias iteraciones debe resultar evidente. Además, el objetivo no es aclarar quién es el responsable de un error. Al final, no importa quién causó el error mientras el equipo aprenda de él y mejore su proceso.

¿Qué errores hay que medir? No son los errores que se producen durante el desarrollo. Estos no pueden evitarse y es de esperar que conduzcan a la entrega de un producto sin errores al final de una iteración. Se trata más bien de los errores que el cliente o su representante (por ejemplo, el propietario del producto o el servicio de asistencia) comunican después de una iteración. Se trata de errores que dificultan la aplicación de nuevos requisitos. Los errores que hay que medir son, por tanto, los que se producen cuando se cree que no deberían existir ;-) El momento en que un equipo llega a este punto del proceso y maldice porque otro error interfiere con otro trabajo debe determinarse individualmente para cada equipo.

Continúa con el grado azul.

es_ESEspañol