Reingeniería del Software

Download Report

Transcript Reingeniería del Software

Software Reengineering
Juan Carlos Olivares Rojas
MSN: [email protected]
[email protected]
http://antares.itmorelia.edu.mx/~jcolivar/
@jcolivares
Social Network: Facebook, LinkedIn. G+
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:
programadores
ahora
ya
programan como
de antes.
los
de
no
los
• 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?
• “Código mutante”
• “Diseño roto”
• El código es antiguo y muy
grande
• Falta
de
planeación
y
documentación
Problemáticas
• ¿Qué malas prácticas de
codificación tendría un edificio
como el de la izquierda?
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
mantenimiento del software
la
evolución
y
• Generalmente se siguen los siguientes pasos
para aplicar reingeniería:
Reingeniería del Software
Reingeniería del Software
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
reutilizar.
no
todo
se
puede
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.
La gran foto
Refactoring
• 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).
¿Qué es esto?
•f(z) = sin(x)cos(y)
Otro modelo
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
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?
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.
¿cuándo se debe refactorizar?
• Aplicar la “Regla de Tres”:
1.Para añadir una nueva funcionalidad
2.Cuando se necesita localizar un error
3.Como revisión de código
Codificar este modelo
• Una vez desarrollado el modelo,
probar con los siguientes valores
e indicar su resultado:
Práctica
•
•
•
•
•
6
19
28
43
118
• Los resultados obtenidos deben
de ser:
Práctica
•
•
•
•
•
6 es perfecto
19 no es perfecto
28 es perfecto
43 no es perfecto
118 no es perfecto
• Una vez desarrollado el modelo,
¿Detectas alguna mala práctica
de programación?
Práctica
• Al parecer en algo tan pequeño
podría ser que no existieran
malos diseños o prácticas de
programación…
Práctica
import javax.swing.*;
public class programa1 {
public static void main (String[]
args){
int
Num=Integer.parseInt(JOptionP
ane.showInputDialog("Introduce
numero"));
int i=1;
int suma=0;
Práctica
while(i<=(Num/2)){
if(Num%i==0){
suma+=i;
i+=1;}
else{
i+=1;}
}
if(Num==suma)
JOptionPane.showMessageDial
og(null,"El numero "+Num+" es
un número perfecto");
Práctica
else
JOptionPane.showMessageDialog
(null,"El numero "+Num+" no es
un número perfecto");
}}
• No tomar en cuenta el mal
sangrado
• En realidad hay algunas.
Práctica
• La primera de ellas es la
conjunción o mezcla de la lógica
de la aplicación con la
presentación.
• Un objeto debe de realizar solo
las cosas pertinentes al objeto.
Práctica Refactoring
• Para
solucionar
esta
problemática podemos aplicar el
“”principio de separación de
interfaces”; para ello, realizar lo
siguiente:
• Reestructurar para tener
siguiente firma de método:
public boolean esPrimo(int n){
la
Práctica de Refactoring
…
return true/false
}
• En el método main(){} hacer las
adecuaciones necesarias para la
lectura de datos, la invocación
de la funcionalidad y la
impresión de resultados
Práctica de Refactoring
• ¿Cómo
visualizas
la
aplicación?¿Crees que aun se
pueda mejorar?
• En
general
tenemos
una
pequeña clase que implementa
la lógica y la presentación. Si
bien es cierto que ya está
separada aun está en la misma
clase
Práctica de Refactoring
• Para ello, refactorizaremos a la
siguiete arquitectura:
• App
• +main(String args…):void
• Numero
• +esPerfecto(int):boolean
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
las estructuras)
o*
Manejador
(handler)
h
p
Descripción
Abr
Carácter con signo
c
Carácter sin signo
b
Entero
n
Palabra (entero sin
signo)
w
Puntero a entero de
16 bits
lp
Doble palabra
(entero 32 bits)
dw
Puntero largo (32
bits)
Enumeraciones
Largo
l
Flotante
f
Doble
d
Cadena terminada
en /0
sz
Estructura Abc
sA
Descripción
Abr
Formulario
frm
CheckBox
chk
Botón
cmd
Imagen
img
e
Etiqueta
lbl
Puntero largo a una
cadena terminado
en nulo
lpsz
Menú
mnu
PictureBox
pic
Puntero largo a una
función que
devuelve un entero
lpfn
TextBox
txt
ComboBox
cbo
Línea
lin
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.
Pasos en la reestructuración
• Un paso a la vez
• Mejorar el diseño una vez que
se ha escrito el código
Pasos
• De pasos sencillos (refactorings)
se
logra
mejorar
sustancialmente
el
código
fuente.
Metodología
• Escribir pruebas unitarias y
funcionales.
(Se
es
muy
riesgoso si no se tienen)
• Refactorizar los principales fallos
de diseño.
• Refactorizar un malor olor
aunque sea sencillo y probar.
Metodología
• Cuando se desarrollo software
utilizando métodos ágiles, el
tiempo de desarrollo se divide
en dos:
1.Agregar nuevas funcionalidades
2.Refactorizar
Metodología
• Cuando se agrega nueva
funcionalidad no se modifica
código existente, la única forma
de medir el avance es a través
de pruebas unitarias.
• Cuando se refactoriza, no se
agregas pruebas unitarias
Metodología
• Al realizar cambios en el código,
la estructura de software es
modificada y por lo tanto es
necesario refactorizar.
• A continuación se detalla un
pequeño ejercicio aplicando el
refactoring de Encapsulated
Field
• Los pasos a seguir son:
• Crear los méodos get y set para
cada atributo que se desea
acceder.
Ejercicio
• Localizar todas las referencias y
reemplazar todos los accesos a los
campos con los métodos get y
todas las asignaciones con set.
• Compilar y cambiar después de
cada referencia.
Ejercicio
• Declarar el campo como privado.
• Compilar y probar.
• Inicialmente se tiene el siguiente
código:
Ejercicio
public class Persona {
public String name
}
Se tiene la siguiente prueba unitaria
@Test
public void prueba(){
Ejercicio
Person person;
person.name = “Juan Pérez”;
assertEquals(“Juan
Pérez”,
person.name);
}
• Después se aplica el paso 1 (crear
métodos get y set):
Ejercicio
public class Person {
public String name;
public String getName() {return
name;}
public
String
setName(String
NewName){
name=NewName;
}
Ejercicio
• Ahora se aplica el paso 2:
Encontrar todos los clientes;
reemplazar
referencias
con
llamadas. Se modifica la primera
referencia.
• Antes: person.name = “Juan
Pérez”;
• Después: person.setName(“Juan
Pérez”);
Ejercicio
• Se compila y prueba. Ahora se
sigue con la reestructuración de la
siguiente referencia:
• Antes: assertEquals( “Juan Pérez”,
person.name);
• Después: assertEquals( “Juan
Pérez”, person.getName());
Ejercicio
• Se compila y vuelve a probar. Una
vez que se ha probado que
funciona se sigue el paso 4 de
hacer privado el campo:
public class Person{
private String name;
……}
Ejercicio
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
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
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)
Téc, de Ofuscación
• La ofuscación al igual que el
refactoring se puede hacer
sobre las estructuras de datos.
• Por ejemplo en arreglos:
Tec. de Ofuscación
• Arreglos
Tec. de Ofuscación
• También
clases:
se
puede
ofuscar
Tec. de Ofuscacion
• Clases
Tec de Ofuscación
• Variables
Tec. de Ofuscación
• Variables
Tec. de Ofuscaciòn
• Sobre el flujo del programa
Tec. de Ofuscación
• Sobre el flujo del programa
• Sobre el flujo del programa
Tec. Ofuscación
• Paralelización
Tec. de Ofuscación
• Paralelización
Tec. de Ofuscación
• Paralelización
Tec. de Ofuscación
• Ciclos
Tec. de Ofuscación
• Ciclos
Téc. De Ofuscación
• Lo más adecuado es realizar la
ofuscación sobre el código
objeto generado sin alterar el
original.
• Existen
ofuscadores
como
proguard, yguard que son libres
o comerciales como Dasho o
KlassMaster
Substitución de Algoritmo
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?
Sintactic Sugar
Azúcar Sintáctico
• Es una facilidad dada por los desarrolladores
del lenguaje para escribir menos. El ejemplo
más sencillo es el operador ++, C++ es
equivalente a C=C+1
• Ciclo for (implementación while)
Azúcar Sintáctico
• IF como operador ternario ?:
• Goto en java, etiquetas:
public
static
void
imprimir(String
... cadenas) {
for (String cadena : cadenas)
System.out.println(cadena); } }
Azúcar Sintáctico
• Boxing automático de Datos Primitivos a
Objetos: Integer a int
• Anotaciones: @deprecated
• Arreglos Triangulares
• Uso de objetos y métodos Thread-safe
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?