Está en la página 1de 167

Software Reengineering

Juan Carlos Olivares Rojas


MSN: juancarlosolivares@hotmail.com
jcolivar@itmorelia.edu.mx
http://antares.itmorelia.edu.mx/~jcolivar/
@jcolivares
Social Network: Facebook, LinkedIn. Hi5
Competencias
• Específica: conoce los términos básicos de la
reingeniería de software y aplica técnicas de
reingeniería para el mejoramiento de software
existente así mismo utiliza mejores prácticas
para el desarrollo de software.

• Genéricas

• Instrumentales: Capacidad de análisis y


síntesis, Solución de problemas, Toma de
decisiones.
Competencias
• Interpersonales: Capacidad crítica y autocrítica,
Capacidad de trabajar en equipo
interdisciplinario, Habilidad para trabajar en un
ambiente laboral, Compromiso ético.

• Sistémicas: Capacidad de aprender, Capacidad


de adaptarse a nuevas situaciones, Capacidad
de generar nuevas ideas (creatividad),
Habilidad para trabajar en forma autónoma,
Preocupación por la calidad.
Software Hoy en Día
• Mito: los
programadores de
ahora ya no
programan como los
de antes.

• Herramientas más
fáciles y productivas
• El software es cada
día más complejo
Reingeniería del Software
• ¿Si su software fuera un edificio, se parecería
mas a uno de la izquierda o de la derecha?
Software Sustentable
• Reducir

• Reusar

• Reciclar

• 80% Desarrollo de Software es para


mantenimiento. Por lo tanto se necesita de un
código simple, legible y bien diseñado para que
en un futuro pueda ser extensible.
Software Hoy en Día
• En el pasado las prioridades eran tener un
código rápido, pequeño (ocupa poca memoria),
optimizado, utilizando los algoritmos mas
eficaces etc...

• Hoy en día el software es más complejo pero a


la vez hay herramientas más poderosas, por lo
que actualmente el enfoque es que este
código tiene que ser simple.
Beneficios Código Simple
• El código es mas fácil de cambiar, evolucionar
o arreglar (más del 60% de desarrollo de sw es
darle mantenimiento a software existente)

• Es más fácil desarrollar de un modo iterativo e


incrementando

• El código es más fácil de leer (entender).


Reingeniería
• Se originó a finales de la década de 1980
aunque se popularizó en la década de 1990.

• La reingeniería es un proceso que trata de dar


respuesta a una interrogante: ¿Estamos acaso
haciendo las cosas bien o podríamos hacerlas
mejor?

• Es el rediseño o cambio drastico de un proceso


en un negocio (deriva hacia el producto). Es
comenzar de cero, cambio de todo o nada.
Ejemplo de Reingeniería
Reingeniería del Software
• La reingeniería de software es costosa y
consumidora de tiempo.

• La reingeniería es una actividad de


reconstrucción, preferible de realizar antes de
que se “derrumbe” la obra.

• Antes de derribar una casa, quizás se necesita


corroborar que está mal.
Reingeniería del Software
Reingeniería del Software
• La reingeniería es un proceso que altera los
elementos internos de toda obra, no es una
sola remodelación de la fallada.

• La reingeniería ayuda a la evolución y


mantenimiento del software

• Generalmente se siguen los siguientes pasos


para aplicar reingeniería:
Reingeniería del Software
Reingeniería del Software
La gran foto
Definición
• Refactoring (Reestructuración) es modificar el
comportamiento interno (generalmente código
fuente) sin modificar su comportamiento
externo (apariencia, funcionalidad).

• Un cambio al sistema que deja su


comportamiento inalterable (sin cambios), pero
aumenta alguna cualidad no funcional como
simplicidad, flexibilidad, comprensión, … [Beck,
1999]
Definición
• El término se creó como analogía con la
factorización de números y polinomios. Por
ejemplo, x² − 1 puede ser factorizado como (x +
1)(x − 1), revelando una estructura interna que
no era visible previamente (como las dos raíces
en -1 y +1)

• El libro de Martin Fowler Refactoring es la


referencia clásica (1999).
Uso de Refactoring
• Aplicaciones como el edificio de la derecha
padecen de malas prácticas en el desarrollo de
software como:

• “Código mutante”
• “Diseño roto”
• El código es antiguo y muy grande
• Falta de planeación y documentación

• ¿El softwre sufre degeneración?


• Sí
Ejemplo de Refactoring
• Es correcto el siguiente modelo

• ¿Se puede mejorar?¿cómo?


Ejemplo de Refactoring
• Si. Subiendo el método a la clase padre

• ¿En qué casos no sería conveniente esta


refactorización?
• Cuando los métodos difieren en su
implementación. ¿Pero aun así es mala?
Ejemplo Renombrar Métodos
• ¿Cuál de los dos códigos siguientes es lo más
correcto?

• Caso1:
double calcRngMaxPer() {
.... }

• Caso 2:
double calcularRangoMaximoPermitido() {
....
Ejemplo Renombrar Métodos
• ¿Por qué?
• Cómo puede observarse en algunas
situaciones las recomendaciones de refactoring
pueden ser algo subjetivas.

• Para este caso se recomienda el caso 2 ya que


es más representativo el nombre del método.
Se abreviaba generalmente en el pasado
debido a las restricciones de los lenguajes con
el tamaño de los identificadores, actualmente
ya no es tanto problema.
Ejemplo números mágicos
• Cambiar números mágicos por constantes.

• El cambio de valor de un número mágico


implica un cambio en todo el código con su
pérdida de tiempo.

class CalculoSimple {
public static double CalcularCincunferencia
(double diametro)
{ return 3.14 * diametro; }
}
Ejemplo números mágicos
• ¿Cómo debe de quedar la reestructuración?

class CalculoSimple {
public const double PI = 3.14;
public static double CalcularCincunferencia
(double diametro)
{ return PI * diametro; }
}

• ¿En qué lenguaje está este código?


Patrón de Diseño
• Par Problema-Solución. Mejores prácticas.

• Patrón Singletón
• Problema: se admite exactamente una
instancia de una clase. Los objetos necesitan
un único punto de acceso global.

• Solución: Defina un método estático de la clase


que devuelva el Singleton
Singleton
Singleton
public class Singleton {
private static Singleton INSTANCE = null;
private Singleton() {}
private synchronized static Singleton
createInstance() {
if (INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
Patrón de Diseño de un Menú
Patrón MVC
Bad Smells
BAD SMELL REFACTORING PROPUESTO
• Algunas ideas sobre que reestructura
CODIGO DUPLICADO EXTRAER EL MÉTODO
SUBIR VARIABLES
SUSTITUIR EL ALGORITMO

MÉTODOS LARGOS EXTRAER EL MÉTODO


INTRODUCIR OBJETOS COMO PARÁMETROS
REEMPLAZAR EL MÉTODO CON UN OBJETO
MÉTODO

CLASES GRANDES EXTRAER CLASES


EXTRAER SUBCLASES

CARACTERÍSTICA DE LA “ENVIDIA” MOVER MÉTODO

CLASES “PEREZOSAS” COLAPSAR JERARQUÍAS


Herramientas de Refactoring
• Existen muchas herramientas de
reestructuración de códigos para los principales
lenguajes:

• Java
– Xrefactory, RefactorIT, jFactor, IntelliJ IDEA

• C++
– CppRefactory, Xrefactory

• C#
– C# Refactoring Tool, C# Refactory
Herramientas de Refactoring
• Los principales IDE’s las contienen de forma
natica

• NetBeans: RefactorIT
• Oracle Jdeveloper: RefactorIT
• Borland Jbuilder: RefactorIT

• Eclipse: built-in (propia)


• Emacs: Xrefactory
• Visual Studio .NET: C# Refactory
Herramientas de Refactoring
• Sólo soportan refactoring primitivo:

• Refactorización de clases (Añade (sub)clases a


la jerarquía, renombra, elimina clases).

• Reestructuración de métodos (añade a una


clase, renombra, elimina, mueve hacia abajo,
hacia arriba, añade parámetros, extrae código.

• Reestructuración de variables (añade a una


clase, renombra, elimina, cambia
modificadores, mueve de lugar.
Antipatrones de Diseño
• Antipatrón es un patrón de diseño que
invariablemente conduce a una mala solución
para un problema.

• Al documentarse los antipatrones, además de


los patrones de diseño, se dan argumentos a
los diseñadores de sistemas para no escoger
malos caminos, partiendo de documentación
disponible en lugar de simplemente la intuición.
Antipatrones de Diseño
• El estudio de los antipatrones es muy útil
porque sirve para no escoger malos caminos
en el desarrollo de sistemas, teniendo para ello
una base documental y así evitar usar
simplemente la intuición. Además proporciona
una denominación común a problemas que
facilita la comunicación entre diferentes
desarrolladores.
Antipatrón BLOB
• Mejor conocido como “objeto todopoderoso”.
Se presenta cuando una clase es muy grande
tanto en atributos y/o en métodos.

• Entre más grande son las clases es más


difíciles de mantener, reusar y probar. Su gran
tamaño puede perjudicar el tiempo de carga.
Generalmente son el resultado de un mal
diseño o de sistemas legados.
Antipatrón BLOB
Antipatrón BLOB
Antipatrón BLOB
Antipatrones de Diseño
• Algunos autores consideran al Singleton
(Simplicidad) un ejemplo de un antipatrón ¿por
que?

• Se tiene que estudiar el código para ver las


dependencias en lugar de simplemente ver las
interfaces de nuestras clases.

• Dificulta las pruebas de código ya que


promueve un alto acoplamiento.
Antipatrones de Diseño
• Los singleton permiten controlar las instancias
de nuestras clases, esto no está bien porque
una clase solo debe tener responsabilidades de
negocio. Para controlar la creación de clases
deberemos usar un patrón Factoría sobre las
clases de negocio.

• En general su naturaleza estática y pública no


son del todo bien vistas.
Catálogo de Ref. de NetBeans
• Renombrar (Rename)
– Cambia el nombre de una clase

• Mover (move)
– Mueve de forma segura una clase a otra ubicación
• Copiar (copy)
– Copia una clase a otra ubicación

• Eliminar de forma segura (Safely Delete)


– Borra una clases y las referencias a ésta.
Catálogo de Ref. de NetBeans
• Cambiar los parámetros del método (Change
Method Parameters)
– Modifica parámetros de un método

• Ascender (Pull Up)


– Mueve los métodos y campos a una clase que
hereda de su clase actual.

• Descender (Pull Down)


– Mueve las clases internas, métodos y campos para
todas las subclases de la claseactual (a las clases
hijas).
Catálogo de Ref. de NetBeans
• Mover de nivel interior a exterior(move inner to
outer level)
– Toma una clase interna (que se encuentre dentro
de otra) y la saca de ésta para colocarla en su
propio archivo

• Convertir anónimo en miembro (convert


annonymus to inner)
– Sirve para cambiar una clase miembro anónima (no
instanciable) a una clase miembro actual.
Catálogo de Ref. de NetBeans
• Introducir variable (introduce variable)
– Permite introducir una variable e inicializarla a partir
de la selección.

• Introducir constante (introduce constant)


– Introduce una constante al código con su referente
valor y tipo.

• Introducir campo (introduce field)


– Toma una expresión seleccionada y crea un campo
con el valor de la expresión; la cual será
reemplazada con el nombre del campo.
Catálogo de Ref. de NetBeans
• Introducir método (replace block code with a
field)
– A partir de varias líneas de código seleccionadas,
el reestructurador declara un nuevo método y
también se encarga de aplicarlo en lugar de las
líneas.

• Encapsular campos (encapsulate fields)


– Toma las variables seleccionadas y crea métodos
set y get para dicha variable.
Catálogo de Ref. de NetBeans
• Pull Up & Push Down (Ascender y Descender)
– Aplica las dos refactorizaciones en un solo paso

• Extract Interface (Extraer Interface)


– Crea una nueva Interface de los métodos públicos
no estáticos dentro de una Clase o Interface.
Catálogo de Ref. de NetBeans
• Extract Superclass (Extraer superclase)
– Crea una nueva Clase Abstracta, extiende a la
Clase actual la nueva Clase, y mueve los métodos
seleccionados y campos a la nueva Clase.

• Use Supertype Where Possible (usar supertipo


cuando sea psible)
– Convierte el uso de una Subclase a una Superclase
Refactorización Pequeña
• Reemplazar una Temp con un Query

• Reemplazar
Consejos para Reestructurar
• Cuando pienses que es necesario. No sobre
una base periódica

• Aplicar la regla de Tres


– Primera vez: Implementar la solución a partir de
cero
– Segunda vez: Aplicar algo similar por la duplicación
de código
– Tercera vez: No reimplementar o duplicar, sino
Factorizar!!
Consejos para Reestructurar
• Consolidar después de añadir nueva
Funcionalidad, especialmente cuando la
funcionalidad es difícil de integrar en el código
base existente.

• Durante la depuración (debugging)


– Si es difícil seguir la pista a un error, reestructure
para hacer el código más comprensible.

• Durante la inspección formal del código


(revisiones de código)
Estándares de Codificación
• Para la reestructuración de códigos se pueden
seguir convenciones ya definidas las más
importantes son la notación húngara y la
notación de camello.

• La notación húngara fue creada por Charles


Simonyi de Microsoft, el cual es húngaro y por
eso recibió ese nombre.
Notación Húngara
• Es un método ampliamente usado sobre todo
para convención de nombres de variables.

• Consiste en tener variables autodocumentadas


agregando un prefijo de tres caracteres o
menos para indicar su tipo.

• Las abreviaturas de los tipos de datos puede


variar dependiendo del lenguaje de
programación.
Notación Húngara
Descripción Abr
Objeto (parecido a o*
Descripción Abr
las estructuras)
Carácter con signo c
Manejador h Descripción Abr
Carácter sin signo b (handler)
Formulario frm
Entero n Puntero a entero de p
16 bits CheckBox chk
Palabra (entero sin w
signo) Puntero largo (32 lp Botón cmd
Doble palabra dw bits) Imagen img
(entero 32 bits) Enumeraciones e Etiqueta lbl
Largo l Puntero largo a una lpsz Menú mnu
Flotante f cadena terminado PictureBox pic
en nulo
Doble d TextBox txt
Puntero largo a una lpfn
Cadena terminada sz función que ComboBox cbo
en /0 devuelve un entero Línea lin
Estructura Abc sA
Notación Húngara
• int nTest;
• long lTemp;
• char *szString = "Prueba";

• struct Rect srRect;


• int nMiVariableEjemplo;
• char szEjemploString;

• int NNOMBREINVALIDO;
• int nNombre_Incorrecto;
Notación de Camello
• Es la utilizada por Java y herramientas afines.
Su uso está creciendo en popularidad mientras
que la notación húngara va en desuso.

• Su principal característica consiste en que no


separa nombres de identificadores (variables,
métodos, objetos) con “_” para palabras
compuestas.
Notación de Camello
• Los identificadores tienen la forma de la joroba
de un camello. No se indican tipos de datos.
Sigue respetando mucho de la Notación C.

• Los métodos inician en minúsculas y si hay una


palabra compuesta esta inicia con mayúscula
dando la apariencia de una joroba.
Notación de Camello
• Las clases inician con mayúscula siguiendo el
mismo método.

• Los métodos para acceder a atributos de las


clases no públicos deben llamarse por
convención set y get.
Convenciones de Desarrollo
• Algunas compañías como Google proponen
sus propios estándares de codificación:
http://code.google.com/p/google-styleguide/

• Los lenguajes que maneja son C/C++, Python,


Perl, Objective-C, XML, entre otros.

• Estos estándares son manejados en forma


obligatoria para el desarrollo de sus proyectos.
Ingeniería Inversa
• Se aplica para obtener un modelo detallado de
análisis, ingeniería de requerimientos, diseño y
en algunos casos implementación teniendo una
solución, la cual es una actividad consumidora
de tiempo.

• Tanto la Ingeniería Inversa como la


Reingeniería en la mayoría de las licencias de
Software se encuentran penadas por la ley.
Ingeniería Inversa
• Los archivos ejecutables pueden ser
desemsamblados obteniendo su código fuente
en ensamblador.

• Los archivos ejecutables con código portable


(Java, .NET) pueden ser desemsamblados
para obtener su código fuente.
Rediseño
Reuso de Software
• El reuso es una de las técnicas de resolución
de problemas que más utilizamos los humanos.
De hecho es lo primero que verifica nuestro
cerebro.

• El reuso en software nos ayuda a mejorar la


producción y calidad del software al “no
reinventar la rueda”.

• Desafortunadamente no todo se puede


reutilizar.
Reuso de Software
• La reutilización es la propiedad de utilizar
conocimiento, procesos, metodologías o
componentes de software ya existente para
adaptarlo a una nueva necesidad,
incrementando significativamente la calidad y
productividad del desarrollo.

• Para que un objeto pueda ser reusable se


necesita de un alto nivel de abstracción. Entre
mayor es su nivel de abstracción, mayor es su
nivel de reuso.
Ofuscación

La ofuscación permite
ocultar código y en
algunos casos reducir
el tamaño del mismo,
lo cual es muy útil en
lenguajes de script
(HTML por ejemplo)
Remover Asignación Parámetros
Substitución de Algoritmo
Mover Método
• El método de la clase original de preferencia
debe desaparecer o bien hacer referencia al de
la nueva clase.

• Una clase es responsable de una cosa


Ejemplo de Mover Método
• ¿Qué tiene de malo este código?

• Lab 1: Ejercicio de Fowler


Ejemplo de Mover Método
• El método amountFor utiliza muchas
referencias a métodos de la clase Rental.

• Haciendo un análisis a mayor profundidad se


puede determinar que la clase cliente no debe
de tener la responsabilidad de calcular el costo
de una renta, que realmentele corresponde a la
clase Renta.

• ¿Cómo debe de quedar la refactorización?


Ejemplo de Mover Método

• ¿Qué le hace falta?


Ejemplo de Mover Método
• Actualizar la referencia

• Nótese que el método no se eleminó de la


clase original. Se escogió una mejor forma de
llamarlo.
Extract Class
• Hay un clase que está haciendo el trabajo de
dos. Se soluciona creando una nueva clase
colocando los métodos y atributos pertinentes
en la nueva clase.
Inline Class
• Una clase no está haciendo nada. Se soluciona
fusionando en una nueva clase los métodos y
atributos de las dos clases anteriores.

• Cuando se tengan comportamientos diferentes,


se deberán manejar clases aparte.
Remover Bandera de Control
• Problema: una variable está actuando como un
indicador de control para una serie de
expresiones lógicas.
• Solución: sustituir por breaks o returns

¿Cómo debe
de quedar
este código
reestructurad
o?
Introducir Aserción
• Malor olor: un código hace un asunción sobre
el estado del programa.

• Desodorante: hacer explícita la asunción a


través de un aserción.

• Por ejemplo en cierto tipo de validaciones como


la raíz cuadrada asumimos que el dato
introducido es positivo.
Introducir Aserción
• ¿Hay aserciones en java?
Introducir Aserción
• Si. El código anterior es en C#

• Cuando una aserción falla se produce una


excepción “unchecked”

• Indican errores de programación (que deben


ser corregidos, no capturados).

• De hecho, normalmente las aserciones se


desactivan en el código de producción.
Aserciones en Java
• Las aserciones sólo están disponibles a partir
de JDK1.4, si se desea hacer una aserción se
deberá de lanzar una excepción:

• if (! (estamos_como_queremos) ) throw new


Error("fallo en tal zona del programa");

• Pero este esquema maneja banderas lo cual se


acaba de ver que no es nada bueno.
Aserciones en Java
• En su lugar se puede manejar:

• assert estamos_como_queremos;

• El cual evaluará la expresión indicada para


obtener un valor de verdad.

• Las aserciones han caído en desuso con la


extensa proliferación de frameworks para
pruebas unitarias donde se hacen aserciones:
assertEquals() por ejemplo.
Aserciones en Java
• IMPORTANTE: las validaciones de datos no
son aserciones!!!

• Las validaciones de datos se deben de hacer.


Una aserción en teoría es para indicar una
porción de código que no debiera de
ejecutarse.

• Para indicar la versión de java al momento de


compilar se deberá habilitar la opción –source
seguido del numero de versión.
Aserciones en Java
• IMPORTANTE: el contenido colocado en assert
no debe de ser vital para la ejecución del
código.

• Suponga el siguiente código:

public int calcularSalario(int comisiones){


assert comisiones >=0;
return 1000+(comisiones*20);
}
Aserciones en Java
• Y el siguiente método para probarlo:

public static void main(String args[]){


int comisiones = 5;
int sueldo = calcularSalario(comisiones);
System.out.println(“Sueldo=”+ sueldo);
}

• Si se corre tanto para valores de 5 y -5 para


comisiones no sucede nada. ¿Por qué?
Aserciones en Java
• Se ocupa activar las directivas del manejo de
aserciones:

• -ea: activa aserciones


• -da: desactiva aserciones

• CONSEJO: en caso de duda siempre meter


aserciones.
Extract Subclass
• Problemática: Una clase tiene características
que son usadas sólo en algunas instancias.
• Solución: Crear una subclase para este
subconjunto de características.

Trabajo Trabajo
getTotalPrice
getTotalPrice getUnitPrice
getUnitPrice
getEmployee
Labor

getUnitPrice
getEmployee
Extract Subclass
• Motivación: El principal motivo para utilizar esta
refactorización, es que una clase tenga
comportamiento que es usado por algunas
instancias de la clase y no se use para el resto.

• La principal alternativa para esta refactorización


es Extract Class. Esto significa seleccionar
entre delegación y herencia.
• Extract subclass es usualmente simple para
realizar, pero tiene sus limitaciones.
Extract Interface
• Problema: Varios clientes usan el mismo
subconjunto de una interface, o dos clases
tienen parte de sus interfaces en común

• Solución: Extraer el subconjunto dentro de una


interface
Extract Interface

<<interface>>
Billable
Employee getRate( )
getRate() hasSpecialSkill( )
hasSpecialSkill()
getName()
getDepartment()
Employee
getRate()
hasSpecialSkill()
getName()
getDepartment()
Extract Interface
• Motivación:
• Las clases son usadas por otras en diferentes
maneras, por lo que son implementadas de
forma diferente para cada clase.
• Cuando una clase necesita comportamientos
de más de una clase, se soporta con lo que se
llama Herencia múltiple. Java tiene herencia
simple, pero permite establecer e implementar
esta clase de requerimientos usando interfaces.
Interfaz vs Clase Abstracta
• Las clases abstractas como su nombre lo
indica son clases que no pueden instanciar
objetos. Por este motivo sólo se utilizan para
definir taxonomía de clases.

• Las interfaces definen las carácterísticas de


una clase pero no la implementan. Las
interfaces sirven para manejar “herencia
múltiple”.
Interfaz vs Clase Abstracta
• Un futbolista tiene ciertas carácterísticas que
no necesariamente definen su personalidad.
Una persona puede tener el comportamiento de
un futbolista. Por este motivo no heredan sino
que implementan una interfaz.

• Las clases abstractas pueden tener métodos


abstractos o no. Cuando un método es
abstracto debe ser redefinido en la subclase.
Interfaz vs Clase Abstracta
• Las interfaces todos sus métodos son
abstractos. Una interface no encapsula datos.
• ¿Cómo se implementaría en Java?
Colapse Hierarchy
• Problema: Una superclase y una subclase no
son muy diferentes

• Solución: mezclar las clases

Empleado

Empleado

Vendedor
Colapse Hierarchy
• Motivación: Refactorizar una jerarquía a
menudo involucra subir métodos y campos, así
como bajar la jerarquía en cuanto a niveles.

• Se tienen que encontrar las subclases que no


están añadiendo algún valor, y es necesario
mezclarlas con otra.
Colapse Hierarchy
• MECANISMO:

• Selecciona que clase será eliminada: la


superclase o alguna subclase.

• Utilizar subir campo o método, bajar campo o


método, para mover comportamientos y datos,
de la clase eliminada a la clase con la que será
mezclada.
Colapse Hierarchy
• Compilar y probar cada movimiento.

• Ajustar las referencias a la clase que será


eliminada para usar la clase mezclada. Esto
afectará declaraciones de variables, tipos de
parámetros y constructores.

• Eliminar la clase vacía.

• Compilar y probar
Patrón Estado
• State es un patrón que resuelve la problemática
de que el comportamiento de un objeto
depende de su estado, y sus métodos
contienen la lógica de casos que reflejan las
acciones condicionales dependiendo del
estado.

• Solución: cree clases de estado para cada


estado que implementan una interfaz común.
Patrón Estado
• Utiliza una superclase abstracta (clase de
estado), la cual contiene métodos que
describen los comportamientos para los
estados de un objeto.

• Se maneja una clase de contexto que es la que


sirve de interfaz al cliente.
Factory Pattern
• El patrón de diseño Fábrica o Factoría: se basa
en el principio de diseño para mantener una
separación de interfaces (separation of
concerns).

• Los objetos factoría separan las


responsabilidad de la creación compleja de
objetos de apoyo, ocultan la lógica de creación
de la parte compleja.
Factory Pattern
• En su versión más simple o pura se indica el
objeto que se desea construir. Se tiene un
método llamado create o createInstance al cual
se le pasa como parámetro el tipo de dato a
construir.

static Employee create(int type) {


switch (type) {
case ENGINEER: return new Engineer();
case SALESMAN: return new Salesman();
case MANAGER: return new Manager();
Factory Pattern
default: throw new
IllegalArgumentException("Incorrect type code
value");

• Nótese que esta implementación es elegante


aunque con frecuencia se crea generalmente
un método por cada tipo de objeto.

class Person...
static Person createMale(){
Factory Pattern
return new Male();}
static Person createFemale() {
return new Female();}

• Reemplazar: Person kent = new Male();

• Con: Person kent = Person.createMale();


Factory Pattern
Pruebas y depuración
• La fase de prueba se realiza una vez integrado
cada uno de los módulos del sistema.

• La fase de pruebas se realiza de distintas


formas tratando de encontrar la mayoría de los
errores que se encuentran de manera inherente
en el software.
Depuración
• Una vez identificado los errores en la fase de
pruebas, se procede a corregirlos. A esta fase
se le llama depuración.

• En la fase de depuración también se arreglan


detalles superficiales del software además de
optimizar y mejorar algunos procesos.
Pruebas y depuración
• La fase de prueba se realiza una vez integrado
cada uno de los módulos del sistema.

• La fase de pruebas se realiza de distintas


formas tratando de encontrar la mayoría de los
errores que se encuentran de manera inherente
en el software.
Depuración
• Una vez identificado los errores en la fase de
pruebas, se procede a corregirlos. A esta fase
se le llama depuración.

• En la fase de depuración también se arreglan


detalles superficiales del software además de
optimizar y mejorar algunos procesos.
Depuración
• Es la detección, corrección y eliminación de
errores de software.

• El tener un plan de pruebas ayuda a clarificar el


proceso de depuración.

• El plan de pruebas debe de estar mucho antes


de la construcción del software.
Depuración
• Existen muchos tipos de pruebas dependiendo de la
labor y características de cada una de ellas.

• Pruebas Alfa: se realizan por el usuario final en un


ambiente controlado.

• Pruebas Beta: se realizan por el usuario sin controlar


el ambiente.
Depuración
• A continuación se mencionan algunas características
deseables que deben contener los planes de prueba:

• Diseñar un caso de prueba para cada funcionalidad


del software.

• Establecer como mínimo un caso de prueba de datos


correcto.
Depuración
• Establecer como mínimo un caso de prueba de
datos incorrecto.

• Ejemplo: Caso de Prueba de un módulo de raíz


cuadrada.

• Qué el usuario ingrese un número mayor que 0.


Depuración
• Qué el usuario ingrese un número 0

• Qué el usuario ingrese un número menor que 0.

• Toda actividad de construcción (codificación) es


susceptible de cometer errores dado que se trata de
una actividad humana.
Depuración
• Al realizar la depuración de un programa existe
la posibilidad de un 50% de cometer otro error.

• Es recomendable realizar pruebas de trazado


(assert) para visualizar en donde ocurren los
errores.
Depuración
• Se recomienda probar lo antes posible
cualquier fragmento de código.

• Las pruebas ayudan al aseguramiento de


calidad pero no garantizan que un software
esté 100% libre de errores.
Depuración
• Las pruebas de caja blanca también llamadas
transparentes se concentran en lo que es el
código fuente.

• No se pueden tener pruebas que abarquen el


100% de los casos de uso. Se deben realizar
pruebas de segmentos
Depuración
• Las pruebas de segmentos son bloques de
instrucciones.

• Las pruebas de caja negra están orientadas a


lo que se espera realicen los componentes
modulares del sistema.
Depuración
• Son pruebas funcionales y no interesa como se
realizan las cosas sólo que el resultado obtenido sea
el correcto.

• Se recomienda que sean los usuarios quienes las


realicen.

• Existen diversas filosofías de pruebas como la


programación defensiva.
Depuración
• La programación defensiva es una técnica de
probar primero. Es considerada una técnica de
codificación. Se basa en el principio de divide y
vencerás.

• Se codifica el esqueleto de la aplicación.

• Se realizan pruebas.
Depuración
• Se corrigen los errores y se vuelven a hacer
pruebas.

• Las pruebas de estrés se encargan de observar


el rendimiento de la aplicación sobre cargas
demandantes de trabajo: grandes volúmenes
de datos con poco espacio en disco, 90% de
uso de CPU, múltiples conexiones, etc.
Depuración
• Existen otros tipos de prueba como:

• Pruebas de unidad: se encargan de un módulo


de software en particular.

• Pruebas de Integración: son pruebas que se


realizan con dos o más módulos trabajando en
conjunto.
Depuración
• Existen otro tipos de prueba como las de
aceptación que están más involucradas en el
concepto en sí que en el desarrollo.

• También se pueden aplicar pruebas aleatorias.


Lo ideal es poder utilizar un framework de
pruebas.
Depuración
• La mayoría de los IDEs modernos presentan
frameworks para la depuración desde el clásico
step by step o step over sobre cada uno de los
módulos hasta la realización de pruebas de
unidad.

• Entre las más famosas destacan JUnit para


realizar pruebas de unidad en Java.
Guía Prueba de Programas
• Se necesita especificar las salidas o resultados
esperados.

• Un programador debe de evitar probar sus


propios programas.

• Una organización no debe de probar sus


propios programas.
Guía Prueba de Programas
• Inspeccionar los resultados obtenidos de cada
prueba.

• Los casos de prueba deben escribirse con


condiciones de entrada que son inválidas e
inesperadas, así como también aquellas que
son válidas y esperadas.
Guía Prueba de Programas
• Examinar un programa para verificar que hace
lo que deba de hacer es sólo parte de la
prueba, la otra mitad es asegurarse que el
programa no haga lo que no deba de hacer.

• No realizar planeaciones asumiendo que no se


encontrarán errores.
Guía Prueba de Programas
• La probabilidad de la existencia de mas errores
en una sección de un programa es proporcional
al número de errores encontrados en esa
sección.

• La realización de pruebas es una actividad


extremadamente creativa e intelectualmente
retadora.
Guía Prueba de Programas
• Se debe de realizar una lista de verificación
para inspecciones de prueba que contenga los
siguientes puntos:

• Datos
• Declaración de datos
• Errores computacionales
• Errores de comparación
Guía Prueba de Programas
• Errores de control de flujo
• Errores de Interface
• Errores de Entrada/Salida

• Se pueden utilizar métodos deductivos e


inductivos para la prueba de software.
Depuración por Inducción
• Se siguen los siguientes pasos:

• Localizar los datos pertinentes


• Organizar los datos
• Estudiar las relaciones
• Divisar las hipótesis
• Probar las hipótesis
• Corregir el error
Depuración por Deducción
• Enumerar las posibles causas
• Usar procedimientos de eliminación
• Refinar las hipótesis restantes
• Probar las hipótesis restantes
• Si no se pueden probar las hipótesis entonces
coleccionar más datos y repetir el proceso
• En caso contrario corregir el error
XP eXtreme Programming
• Se tienen doce principios básicos:

• Planeación y requerimientos
• Entregas pequeñas e incrementales
• Metáforas de Sistemas
• Diseños simples
• Pruebas continuas
• Refactorización
XP eXtreme Programming
• Programación en pares
• Propiedad colectiva del código
• Integración Continua
• Semanas de 40 horas
• Clientes como miembros del equipo
• Codificar con estándares
Extreme Testing
• Las programación extrema tienen las siguientes
ventajas en lo que respecta al proceso de
pruebas:

• Se gana confianza ya que el código debe


cumplir las especificaciones.
• Se tiene el resultado final del código antes de
codificar
Extreme Testing
• Se entiende mucho mejor las especificaciones
y requerimientos de la aplicación.

• Se inicia con diseños simples y se refactoriza el


código después para mejorar el desempeño sin
preocuparse de que se estén rompiendo las
especificaciones.
Plan de Pruebas
• Se recomienda utilizar la metodología y
formatos del estándar IEEE 829 para
documentación de pruebas de software:

• Pasos que incluye:

• Identificador de plan de pruebas (se muestra el


estándar a seguir para el nombre de las
pruebas)
Plan de Pruebas
• Introducción (en que consiste las pruebas del
sistema)
• Elementos a probar
• Características a ser probadas
• Características que no se probarán
• Enfoque
• Criterio de fallo o aceptación de los elementos
Plan de Pruebas
• Criterio de Suspensión y Reanudación de
requerimientos
• Entregables de las pruebas
• Tareas de las pruebas
• Necesidades del entorno
• Responsabilidades
• Equipo y necesidades de capacitación
• Agenda
Plan de Pruebas
• Riesgos y contingencias
• Acuerdos

• A las pruebas se les ha empezado a llamar de


manera formal verificación y validación.

• Existen metodologías más robustas como el


TMMI (Test Maturity Model)
Plan de pruebas
Formato Plan de Pruebas
ID: 1 Nombre: Enviar artículo
Probado por: Fulanito
Descripción: Se introducen los datos del artículo y de
los autores.

Condiciones de Entrada: nombreArticulo=“Calidad del


Sw” … emailAutor=“jcolivar@itmorelia.edu.mx”

Resultado Esperado: El sistema confirma la correcta


recepción del artículo enviando un e-mail al autor de
contacto con un userid y password para que el autor
pueda posteriormente acceder al artículo.
Resultado Obtenido: Se generan bien userid y
password pero el correo no llegó.
Práctica de Laboratorio
• Realizar un programa que permita calcular el
área de un triángulo conociendo tres lados
utilizando la fórmula de herón.

• Realizar el plan de pruebas que garantice que


el programa está libre de errores
Arquitectura
Casos de Pruebas
• ¿Con cuantos casos de prueba valido que el
software está correcto?

• Para cada caso de prueba sólo indicar las


posibles entradas.

• Por ejemplo:

• Caso de Prueba 1: A=3 B=4 C=5, el resultado


esperado debe de ser 6.
• ¿Es diferente el caso A=4 B=3 C=5?
Casos de Prueba
• Tipos de Triángulo en Base a sus lados:

• Se deben tener al menos un caso de cada uno


de ellos y al menos un caso no válido: A=0 B=-
1 C=“Hola”.
Caso de Prueba
• ¿Cuál es el resultado esperado para el caso de
prueba A=1 B=2 C=3?

• Area=0

• ¿Qué pasó?

• !Exento este parcial quien pueda dibujar un


triangulo de dimensiones 1, 2 y 3 cm para cada
lado!
JUnit
• Es el framework de pruebas unitarias para Java
más utilizado en el mundo.

• En IDEs como Netbeans y Eclipse viene de


manera predeterminada.

• Para crearlo en Netbeans es muy fácil sólo se


escoge la opción de crear una prueba unitaria
de una clase existente y crea un bosquejo de
prueba con cada método impelementado.
JUnit
• Existen dos versiones populares a manejar la
3.x (anticuada pero ampliamente utilizada) y la
4.x (que maneja anotaciones pero no es
compatible con versiones viejas).

• La ventaja de utilizar pruebas unitarias es que


nos permite corroborar nuestro código sin
necesidad de crear una aplicación.
JUnit
• En la versión 3.x las pruebas unitarias tienen la
siguiente forma:

• Se importa la clase junit.framework.TestCase;

• La clase de prueba hereda de TestCase

• Se puede utilizar utilizar un constructor para


inicializar datos.
JUnit
• Se utiliza el método setUp() para realizar un
conjunto de acciones antes de evaluar un caso
de prueba.

• Se utiliza el método tearDown() para realizar


acciones una vez finalizado el caso de prueba

• Se utiliza el método fail() que recibe una


cadena de mensaje de error para forzar a una
falla.
JUnit
• Se utiliza el método
assertEquals(valoresperado, valorresultante)
para saber si el método se ejecutó de manera
exitosa.

• Se puede utilizar el método


assertNotNull(objeto) para saber si un objeto no
es nullo.

• Para tipos de datos flotantes el método


assertEquals utiliza un parámetro adicional
JUnit
• La diferencia con la versión 4.x de Junit radica
en lo siguiente:

• Se importan las siguientes clases:


org.junit.After, org.junit.AfterClass,
org.junit.Before, org.junit.BeforeClass,
org.junit.Test, org.junit.Assert.*;

• Se utilizan las anotaciones @BeforeClass,


@AfterClass, @Before, @After para indicar
cuando se utilizan los métodos auxiliares
JUnit
• La clase de prueba no extiende de ninguna otra
pero cada caso de prueba debe utilizar la
anotación @Test

• Se recomienda realizar los casos de prueba de


manera separada uno por uno y dejarlos
siempre presente.
Diseño por Contratos
• Contratos en software (Math.sqrt):
Obligaciones del cliente
- pasar un entero positivo
Derechos del cliente
- obtener la raíz cuadrada

Derechos del implementador


- asume que el argumento es positivo
Obligaciones del implementador
-Se debe computar la raíz cuadrada
JML
• Java Modeling Language (JML) puede ser
usada para especificar el diseño detllado de las
clases e interfaces de Java agregando
anotaciones a los archivos fuentes.

• Las anotaciones se hacen con comentarios


/**seguidos de una arroba con una palabra
clave.
Pre y Postcondiciones
• Una precondición es un requerimiento previo.

• Ejemplo: //@ requires y >= 0;

• Una postcondición es un requerimiento


posterior.

• Ejemplo:
• //@ ensures \result * \result == y;
Contratos como Documentación
• //@ requires y >= 0;
/*@ ensures -y <= \result
@ && \result <= y
@ && \result * \result <= y
@ && y < (Math.abs(\result) + 1)
@ * (Math.abs(\result) + 1);
@*/
public static int isqrt(int y) {
...
}
JML
• Otro ejemplo:

/*@ requires a != null


@ && (* a is sorted *);
@*/
int binarySearch(Thing [] a, Thing x)
{ ... }
Otro Ejemplo
public class Person {

private String name;


private int weight;

/*@ also
@ ensures \result != null
@ && (* \result is a display
@ form of this person *);
@*/
Otro ejemplo
public String toString() {
return "Person(\""
+ name + "\","
+ weight + ")";
}

/*@ ensures (* \result is


@ this person's weight *);
@*/
public int getWeight() {
Otro ejemplo
return weight;
}

/*@ requires kgs >= 0;


@ ensures (* this person's weight
@ is their old weight plus
@ kgs *);
@*/
public void addKgs(int kgs) {
if (kgs >= 0) {
Otro ejemplo
weight += kgs;
} else throw
new IllegalArgumentException();
}
}

/*@ requires n != null;


@ ensures (* This person has
@ name n and weight 0 *);
@*/
Otro ejemplo
public Person(String n) {
name = n; weight = 0;
}
}
Herramientas JML
Compilador: jmlc

Pruebas Unitarias: jmlunit

Generador de Documentación: jmldoc

Revisor de tipos: jml


Referencias
• (Weitzenfeld, 2007) Ingeniería de Software
Orientada a Objetos con UML, Java e Intrnet,
Thomson.

• (ITM 2007) Material de Libro de Texto de la


materia de Planificación y Modelado, Instituto
Tecnológico de Morelia.

• (Sánchez, M. 2009) Material del Curso de


Planificación y Modelado.
Referencias
• Roger S. Pressman, Ingeniería de software un
enfoque práctico.Ed. McGraw Hill.

• Piattini M.G. y F.O, Calidad en el desarrollo y
mantenimiento del software. Ed. RAMA.

• Fowler, M. (1999), Refactoring, Adison-Wesley.
¿Preguntas?

También podría gustarte