Resumen Programación Orientada a Objetos y Test Driven Development PDF

Title Resumen Programación Orientada a Objetos y Test Driven Development
Course Diseño de aplicaciones 1
Institution Universidad ORT Uruguay
Pages 8
File Size 269.9 KB
File Type PDF
Total Downloads 33
Total Views 132

Summary

Download Resumen Programación Orientada a Objetos y Test Driven Development PDF


Description

OOP, UML, TDD Conceptos de objetos: Objeto: Un objeto es una entidad visible y tangible interna al problema, cualquier entidad que se puede contextualizar. Es de carácter identificable, capaz de almacenar información y ofrecer un conjunto de operaciones que nos permiten examinar o modificar su información. Esto implica que los objetos tienen estado. Los objetos son instanciados y realizan interacciones entre sí, por este motivo se evita el uso de componentes estáticos.   

Estado: abarca todos sus atributos más sus valores en un momento dado. Comportamiento: como actúa y reacciona un objeto en términos de sus cambios de estado y paso de mensajes. Representa su actividad visible y comprobable exteriormente. Identidad: Lo distingue de todos los demás objetos. Clase: Plantilla o modelo que indica que atributos y comportamientos van a tener los objetos que se terminaran instanciando. Descripción abstracta de un grupo de objetos con propiedades similares (atributos), comportamiento común (operaciones), relaciones comunes con otros objetos y semántica común. Todos los objetos son instancias de una clase y la clase de un objeto es una propiedad implícita. Atributo: Un atributo es una propiedad nombrada de una clase, que describe un rango de valores que puede tomar esa propiedad en las instancias. Abstracción: Proceso de representar un elemento real, tomando sus características significativas y aislándolo del contexto. Encapsulamiento: Agrupar datos y comportamiento en un mismo elemento. Consiste en unir en una clase las características y los comportamientos de las abstracciones, aumentando la cohesión. Provee barreras explicitas entre diferentes abstracciones lo que lleva a una clara separación de responsabilidades. Suele lograrse a través del ocultamiento de información. Las abstracciones se enfocan en el comportamiento observable de un objeto, mientras el encapsulamiento se centra en la implementación que da lugar a ese comportamiento. Por ende, el encapsulamiento sirve para separar la interfaz contractual de una abstracción de su implementación. Facilita el entendimiento del código, facilita reuso disminuye el impacto de cambio de la abstracción en el sistema, y aumenta la cohesión del sistema, ya que cada abstracción se encapsula en una sola clase. Ocultamiento de información: Esconder características internas de un elemento. Cada objeto está aislado del exterior, exponiendo una interfaz a otros objetos que especifican cómo puede interactuar. “Importan los métodos, no su implementación”. Generalización: Forma de representar relaciones jerárquicas de especialización entre clases, expresando elementos comunes entre las mismas. Implica que los objetos de una las subclases pueden usarse dondequiera que aparezcan las clases padre”. Herencia: Forma de representar jerarquía de generalización entre clases en lenguajes orientados a objetos. Expresa elementos comunes entre clases. Beneficios: Reuso de clases y código que evitan la repetición, reduce el impacto de cambio

Desventajas: Viola el encapsulamiento de objetos. Expone a las subclases los detalles de la implementación de la superclase. Requiere conocimiento de la herencia a lo largo y a lo ancho. A la larga podría llegar a generar problemas. Si se tiene un árbol jerárquico muy grande, no se sabe de qué clase fue redefinido un método o en que clase se implementó por primera vez. Suponga clase base Persona y especializaciones Alumno y Profesor. La herencia rompe el encapsulamiento, ya que una abstracción no se corresponde a una sola clase, sino a una rama de la jerarquía. En el ejemplo, la abstracción alumno queda dividida entre la clase Alumno y la clase Persona (ídem Profesor). Impacto de romper el encapsulamiento: mantener jerarquía, cambios en especialización impactan una rama, más difícil de reutilizar el código, puede aportar complejidad a entender una especialización. Polimorfismo: Es un concepto de teoría de tipos del cual un nombre (variable) puede representar objetos de diferentes clases mientras estos estén relacionados por una superclase común. Cualquier objeto representado por esta variable es capaz de responder a un conjunto de operaciones común de forma diferente. Aplicar polimorfismo permite generar código abierto al a extensión (Ver: GRASP, SOLID - Principio Abierto-Cerrado), posibilitando que una clase no conozca con el tipo concreto que está hablando y por lo tanto poder sustituirlo por más especializaciones.

UML: Diagrama de clase: Un diagrama de clases describe la estructura estática de un sistema en términos de clases y de relaciones entre estas clases, mostrando los atributos y operaciones que caracterizan cada clase de objetos. Diagrama de objetos: Un diagrama de objetos representa la estructura estática del sistema mostrando los objetos (instancias) en el sistema y las relaciones entre los objetos.

Tipos de relaciones en UML:



Asociación: Conexión entre clases, que implica la existencia de una relación estructural entre objetos de esas clases. “La clase A ‘tiene’ a la clase B”.



Dependencia: Relación más débil. Una flecha por cada mención de la clase A en la clase B. Es una es una relación de uso entre clases.



Agregación: Es una relación “parte de”, en la que los objetos que representan los componentes de algo se asocian con un objeto que representa el agregado completo. Se define como una conexión entre la clase agregada y una clase componente. No hay dependencia de vida.





Composición: Agregación con dependencia de vida: Los componentes no pueden existir sin el agregado, que es responsable de la creación y destrucción de sus componentes.

Herencia

:

Interfaces: Una interfaz no tiene instancias, se realiza en una instancia de una clase o un componente. La clase o el componente proporcionan un conjunto de métodos que implementan apropiadamente las operaciones definidas en la interfaz. Una clase o un componente pueden realizar (relación de realización) muchas interfaces y depender (relación de dependencia) de varias interfases.

Herencia vs interfaz Clase abstracta es una clase base que puede tener métodos abstractos vacíos que se implementan en las subclases o métodos implementados que pueden sobrescribirse en clases hijas. Pueden tener cualquier visibilidad. La interfaz define un contrato con la firma de los métodos y propiedades. Cualquier clase que implementa la interfaz tiene que obligatoriamente implementar todos los métodos de la interfaz. Son públicos. Clase abstracta son clases base o padre que pueden tener métodos implementados o métodos abstractos, mientras que las interfaces son contratos (métodos vacíos). Las clases abstractas son heredadas (herencia simple) mientras que las interfaces se implementan (implementación múltiple). Las clases abstractas se utilizan cuando queremos aumentar la reutilización, mientras que las interfaces se utilizan para forzar un contrato entre objetos dispares.

Herencia vs Composición Herencia rompe encapsulamiento (reuso de caja blanca), def estatica y fácil de cambiar de forma estatica. Composicion no rompe encapsulamiento, reuso de caja negra y fácil de cambiar en forma dinámica. Caso: Stack y Vector, que rompe LSP como el mejor

Test Driven Development (TDD): Es la metodología de trabajo que consiste en escribir las pruebas unitarias antes de escribir cualquier código. No es solamente probar, sino que es diseñar de otro modo.

Implica TDD = TFD + Refactoring TDD es una metodología que las combina (testing unitario y refactoring) para formar una disciplina de desarrollo. Especifica un ciclo (rojo, verde, refactoreo) para garantizar que noexista código de producción sin código de pruebas asociado, es decir, asegurar la cobertura del código. Realizar testing unitario y refactoring, como metodologías separadas y sin el ciclo TDD, no asegura la cobertura de código. Debería estar constantemente revisando la cobertura de las pruebas, mientras que al realizar TDD, la disciplina asegura la cobertura.

Test First Development o o o o

Pensar, diseñar y escribir una prueba unitaria para una nueva funcionalidad. Correr la prueba y ver que falla. (Red) Escribir el mínimo código necesario para pasar la prueba. Correr nuevamente y verificar que pase. (Green)

Refactoring: Técnica controlada para mejorar el diseño de un código base existente. Es el proceso de cambiar el software de tal forma que no altere el comportamiento externo del mismo pero mejore su estructura externa.

    

Consiste en: Detectar “Code Smells” y quitarlos Evaluar principios de diseño y favorecerlos Eliminar código duplicado o repetido Aplicar Clean Code Aplicar técnicas de refactoring conocidas Algunas técnicas:

Extract method: Si hay un fragmento de código que puede agruparse, agruparlo en un método que tenga un nombre explicativo de lo que hace. Encapsulate field: Si hay un campo publico, hacerlo privado y poner get y set. Move method: Un método es usado o será usado mas por otra clase que aquella donde esta. Movel el método a esa clase y dejar el método viejo en la otra clase en forma de delegate, o borrarlo. Replace magic numbers with symbolic constant. Rename method. Replace error code with exception. Realizar refactoring implica modificar el código para mejorar su calidad. En cada modificación, se corre riesgo de cambiar su correctitud, por lo cual es necesario asegurar que esto no suceda. Para comprobar que no se introducen cambios, es necesario apoyarse en el testing para comprobar el comportamiento del sistema. El testing debe ser unitario y automático, para que valide más específicamente los cambios y no sea costoso (en tiempo y recursos) respectivamente. De realizar refactoring y no realizar testing , se corre el riesgo de cambiar la correctitud del sistema y en caso que el testing no sea automático, se hace demasiado costoso tener que testear manualmente cada refactoreo. Refactoring es paso indispensable de TDD (para mantener la calidad del codigo), y pruebas unitarias como requisito indispensable para Ref (asegurar que no se modifica el comportamiento observable).

Reglas de TDD:   

Nunca escribir código si no hay una prueba unitaria. Escribir el código mínimo y suficiente de la prueba para que sea una prueba fallida. Escribir solo el código mínimo y suficiente para que la prueba pase.

ATDD/BDD: Pruebas de caja negra de los requerimientos. Consiste en escribir una única prueba de aceptación, luego el código mínimo y productivo para la funcionalidad que haga pasar dicha prueba. TDD se enfoca en desarrollar unidades mínimas de código (clases) y en su implementación, mientras que ATDD está enfocado en el requerimiento. Esto significa que todo el equipo discute en colaboración criterios de aceptación, con ejemplos, y luego los divide en un conjunto de pruebas de aceptación en concreto antes de que comience el desarrollo. ATDD es más cercano a un proceso más que una actividad.

Consecuencias de usar TDD:     

TDD es una técnica para diseñar y construir no sólo una forma de probar. No es test, sino que es diseño. Escribiendo el caso de prueba antes el desarrollador profundiza en los detalles del problema antes de resolverlos. Realizar una prueba automática de una clase obliga a pensar en la interfaz más simple para la misma. Realizar un buen diseño de la interfaz en función de la especificación produce diseños más fáciles de mantener.

Ventajas:

          

Las pruebas unitarias completas son documentación que evoluciona naturalmente junto con el sistema. La mejor forma de documentar una clase es mediante la descripción de su comportamiento exterior, a través de un conjunto de casos de prueba. La documentación está siempre actualizada porque las pruebas deben correr. Para un desarrollador que se enfrenta a una base completa de casos de prueba es más fácil introducir cambios sin introducir defectos. Ejecutar los mismos casos de prueba que sirvieron como criterio de satisfacción de las clases al construirlas, da esta seguridad. Aumenta la confianza de quien introduce el cambio y permite hacerlo en forma rápida. Le da al desarrollador confianza sobre el trabajo propio. Representa el diseño más simple posible. Determina cuando una clase está terminada. Permite refactorizar rápidamente y efectivamente, sin miedos. Facilita el trabajo en equipo, al poder definir el comportamiento de las clases (interfaz), difiriendo la implementación real.

Prueba unitaria Una prueba unitaria es una pieza automatizada de código que invoca comprueba alguna suposición acerca de un único resultado de la unidad de trabajo siendo testeada. Una unidad de prueba si casi escrito utilizando un marco de pruebas unitarias, se escribe fácilmente y se ejecuta rápidamente. Es confiable, legible, fácil de mantener y es coherente en sus resultados, siempre y cuando el código producción no cambie.

Características de pruebas unitarias (FIRST):

    

Fast – Las pruebas deben ser rápidas y ejecutarse de forma rápida. Si corren lento, no vamos a querer correrlas con frecuencia. Esto probablemente lleve a no detectar errores con la suficiente antelación como para solucionarlos sin consecuencias graves. Independent - Las pruebas no deben depender de otras pruebas. Una prueba no debe setear condiciones para la siguiente. Se deben poder ejecutar en el orden que se quiera. Repeatable – Las pruebas deben poder volver a realizarse en cualquier otro entorno. Si esto no es posible, siempre habrá una posible excusa por su fallo. Self-validating – Las pruebas deben tener una salida booleana (o fallan o son satisfactorias). No se tiene que tener que leer un log o hacer algún tipo de comparación manual, ya que entra la subjetividad en juego. Timely – Es importante cuándo es escrita la prueba. Debe escribirse justo antes del código que la resolverá. Sino, se da la posibilidad de decidir que hay partes del código que son muy complicadas de probar.

Ventajas de las pruebas unitarias:        

Permiten ejecutar los tests existentes en nuevas versiones o frente a cambios (regresion) Permite ejecutarlos tan seguido como se quiera Ejecutar tests que son difíciles o imposibles de correr a mano Optimizar recursos Reuso de tests Aumentan la confianza, deja de existir el miedo al cambio, instant gratification. Aumentan la calidad y productividad Menor time-to-market.

Desafios:     



Expectativas no realistas - No es todo lo que necesitamos. Técnicas de testing pobres - Ni la mejor herramienta sirve cuando tenemos malas prácticas. Caos automático resulta en caos más rápido. Falso sentido de seguridad - Que no encuentre errores no quiere decir que no haya defectos. Mantenimiento del código de los tests Problemas técnicos - Problemas con herramientas, interoperabilidad, etc. Si el software no está diseñado para ser testeable, entonces es difícil probarlo tanto manualmente como automáticamente. Aspectos organizacionales - La cultura, prácticas, etc pueden ser un problema

Test Doubles Test double: Objeto de simulación utilizado para tomar el lugar de un objeto real en una prueba.

    

Dummy: Objetos que no son utilizados, solo sirven para llenar las listas de parámetros. Fake: Objetos con implementaciones que funcionan, pero no son aceptables pues su implementación es pobre en términos de calidad. Stubs: Objetos que funcionan exclusivamente dentro de la prueba unitaria. Spies: Variante de los stubs que es capaz de guardar algo de información según como sean invocados. Mock: Objetos preprogramados con expectativas que forman una especificación de las llamadas que se espera que reciban. Solo los mocks insisten en la verificación del comportamiento. Los primeros 4 se pueden considerar de caja negra, y el último, los Mocks, de caja blanca. Esto se debe a que los mocks son los que se centran m´ as en la verificación de comportamiento; es decir, que las llamadas a otros m´ etodos se hagan correctamente. Relación con TDD con encapsulamiento Agrupar datos y comportamiento en un mismo elemento, por ejemplo clases. Consiste en unir en una clase las características y comportamientos. Es tener todo en una sola entidad. Reunir a todos los elementos que puedan considerarse pertenecientes a una misma entidad al mismo nivel de abstracción. Aumenta la cohesión. Provee barreras explícitas entre las diferentes abstracciones lo que lleva a una clara separación de responsabilidades. Suele lograrse a través del ocultamiento de la información. Realizar una prueba de una clase siguiendo TDD obliga a pensar en la interfaz más simple para la misma. Obliga a definir comportamiento que provee barreras explícitas entre las diferentes abstracciones, encapsulando la implementación concreta detrás de dicho comportamiento.

Consideraciones a la hora de ver si aplicar tdd Hay que mantener más código, alinear a la organización, evaluar costos y tiempo disponible para el desarrollo, calidad del código, experiencia del equipo, mantenimiento futuro, etc Las pruebas deberían comenzar de lo más sencillo hacia lo más complejo, listar las pruebas e ir desarrollándolas, y describir (aunque no es necesario que lo pongan con nombres) algunas de las cosas de Patrones de Testing (ejemplo: Fake it, Obvious Implementation, One To Many, etc)

Consideraciones a la hora de ver si aplicar CLEAN CODE en org Mantenibilidad al corto y largo plazo, claridad para futuros miembros del equipo, facilidad de desarrollo, bajo time-to-market, cualquier cosa que indique que entiende los beneficios de aplicar clean code. Desafíos: Todo el equipo tiene que estar alineado, hay que capacitar/orientar a los nuevos miembros del equipo, “alcanza con que uno solo no aplique clean code para empezar a impactar negativamente el desarrollo de todos” (similar TDD)....


Similar Free PDFs