Transcript Clase modelo - Instituto Tecnológico de Morelia
Malos Hábitos de la Codificación
M.C. Juan Carlos Olivares Rojas
Marzo 2010
Competencias
• Específica: conoce y corrige los errores que generalmente se cometen al desarrollar código.
• 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 Habilidad para trabajar en forma Preocupación por la calidad.
(creatividad), autónoma,
• Código duplicado
Temario
• Codificación excesiva • Mal diseño • Pruebas • Refactorización de Generalización • Más patrones de Diseño.
• 30% Prácticas
Evidencias
• 10% Otras actividades en el aula • 60% Actividad de Evaluación Integral (Teórico Práctico)
Código duplicado
• Es el principal indicador de un malor olor.
• Una vez detectada el principio básico de reestructuración es la unificación de todo ese código duplicado. Generalmente se puede aplicar el Refactoring de extraer el método.
• De hecho esta reestructuración básica fue motivo de muchas otras refactorizaciones.
Código duplicado
• ¿cuándo se aplica el refactoring de Pull up?
• Cuando se tiene código duplicado en dos clases hijas.
• En relaciones de generalización, también se pueden aplicar otros refactoring básicos cómo el método de plantilla y la sustitución de algoritmos.
Codificación excesiva
• La codificación excesiva se da por muchas razones: malos hábitos de programación, presión del tiempo de desarrollo, etc.
• El objetivo básico del refactoring es lograr la simplicidad del código y la codificación excesiva no ayuda a esto.
• Un ejemplo de esto son los métodos largos, ya que son más dificiles de entender y por ende darle mantenimiento.
Codificación excesiva
• ¿qué refactorings se pueden aplicar para evitar los métodos largos?
• Extraer método • Reemplazar método por objeto método.
• Sustitución del algoritmo • Mover método* • Todas los refactoring de simplificación de condicionales (descomposición condicional, consolidar condicional, remover banderas, etc.)
Codificación excesiva
• Otros buenos indicadores de malos olores son: • Clases muy grandes • Lista de parámetros muy grandes.
• Clases divergentes (una clase es cambiada constantemente) • Shotgun surgery (un pequeño cambio afecta a todos los componentes) • Clases perezosas.
Codificación excesiva
• Campos temporales • Cadenas de Mensajes • La decisión de reestructurar código depende de los desarrolladores. Para cada indicador debe de existir una métrica establecida.
• Cada empresa define codificación y de refactoring.
sus métricas de
Mal diseño
• Aunque no está enfocado directamente con la codificación, es el principal mal olor en la implementación del software.
• Generalmente no se hace diseño y cuando llega a hacerse se hace muy superficial sólo por cumplir el requerimiento.
• Ya se ha visto como muchas refactorizaciones se pueden hacer a través del modelado.
Mal diseño
• En un diagrama de clases en UML es posible verificar algunos indicadores de malos olores y poder reestructurarlos antes de codificarlos.
• Existirán indicadores que no son muy visibles en el modelado como los métodos largos o el código duplicado.
• Se pueden utilizar otros diagramas de UML como los de secuencia, actividades, estados, etc.
Mal diseño
• El modelado es subjetivo. El decir que un modelo es bueno o malo depende mucho del criterio del evaluador. Realmente los modelos deben de ser efectivos a tal punto de que sean útiles y se programen como deben.
• Cuando se realizó la práctica 4 nos tocó reestructurar nuestra aplicación a un diseño predeterminado consumiendo mucho tiempo si es que nuestro diseño no tenía esa forma.
Pruebas
• Ya se ha hablado de la importancia de las pruebas unitarias en el refactoring como proceso elemental.
• Si una aplicación no tiene pruebas unitarias se deberá hacer un refactoring de creación de casos de prueba automatizados para cada funcionalidad del sistema, esto nos permite entender un existe código donde previamente no documentación técnica.
Pruebas
• Las pruebas unitarias pueden leer desde un archivo de Texto todos los casos de prueba y bien generar la salida en un archivo de Texto.
• Se recomienda que las pruebas unitarias vayan aplicándose de manera progresiva hasta finalizar el plan de pruebas.
Actividades
• De tu programa Agenda de la práctica 4 encuentra porciones de código que pudiesen tener código duplicado (justificar en caso de que no) y aplica el refactoring adecuado.
• Verifica que tus métodos no sobrepasen de más de 24 LOCs totales (incluyendo blancos y comentarios). No se trata de ofuscar el código.
Actividades
• Realiza pruebas unitarias funcionalidad de tu programa.
para cada • Las pruebas unitarias deberán realizarse por cada clase de programa deberá existir una clase de prueba.
• Cada método y atributo de la clase deberán utilizarse en las pruebas unitarias.
Ref. en el manejo de Herencia
• La generalización es una herramienta muy potente que duplicación nos de permite código.
evitar mucha Utilizándola correctamente podemos conseguir que nuestro código sea muy fácil de extender. En estas refactorización encontramos: • Subir Atributo, • Subir Metodo, • Subir CodigoConstructor • Bajar Atributo,
Ref. en el manejo de Herencia
• Bajar Metodo, • Extraer Subclase • Extraer Superclase, • Extraer Interfaz, • Agrupar Jerarquia, • Sustituir Herencia Por Delegacion, • Sustituir Delegacion Por Herencia • En el caso de los refactorins de subir y bajar tanto campos como atributos ya se han comentado con anterioridad.
Pull Up Constructor Body
• Problemática: se tiene constructores en las subclases donde prácticamente es el mismo código.
• Solución: crear un constrctor de la clase.
Llamarlo desde las subclases.
class Manager extends Employee...
public Manager (String name, String id, int grade) { _name = name; _id = id; } _grade = grade; public Manager (String name, String id, int grade) { super (name, id); } _grade = grade;
Pull Up Constructor Body
• Motivación: Los constructores son engañosos.
No son totalmente métodos, por lo que su uso es restringido y delicado.
• ¿Por qué es necesario definir primero el constructor de la superclase en la subclase?
• porque al crear una instancia de una clase, se ejecuta primero superclase, y el constructor después el de ella misma.
de su
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 getTotalPrice getUnitPrice getEmployee Trabajo getTotalPrice getUnitPrice 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 Superclass
• Problema: se tienen características similares dos clases con • Solución: crear una superclase y mover las características comunes a la superclase.
Department getTotalAnnualCost() getName() getHeadCount() Party
getTotalAnnualCost( ) getName( )
Employee getTotalAnnualCost() getName() getld() Department getHeadCount( ) Employee getld( )
Extract Superclass
• Motivación: el código duplicado es una de las principales cosas malas en los sistemas.
• Una forma de código duplicado es tener dos clases que hacen cosas similares de la misma manera o de distinta manera. Los objetos proporcionan mecanismos de ‘construcción’ para simplificar esta situación con herencia.
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
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 definir sólo se utilizan para taxonomía de clases.
• Las interfaces definen las carácterísticas de una clase interfaces múltiple”.
pero sirven no para la implementan.
manejar Las “herencia
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.
• Las
Interfaz vs Clase Abstracta
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 menudo involucra subir una jerarquía a 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
Actividad
• Problemática: los tipos básicos para números tienen precisiones muy bajas para aplicaciones científicas.
• Diseñar una biblioteca para el manejo de números muy grandes. Sólo se distinguirá el concepto entre números enteros y reales.
• De momento sólo se permitirán las operaciones de suma y resta.
Actividad
• Las operaciones deberán ser definidas como estáticas. Se recibirán como argumentos los objetos de números grandes. Se deberán sobrecargar los métodos para que se puedan sumar sin distinción números enteros y reales.
• Se devolverá valores de los mismos datos.
• Se sugieren utilicen clases abstractas o interfaces.
• El constructor
Actividad
recibirá un argumento para construir su valor.
String como • Se deberán realizar casos de prueba que validen todas implementación.
las opciones de la
Rep. Inheritance with Delegation
• Problema: Una subclase usa solamente una parte de la interfaz de la superclase o no quiere heredar datos.
• Solución: crear un atributo para la superclase, ajustando los métodos para se delegados por la superclase, y remover la subclase.
• Motivación: no siempre la herencia es buena, sobretodo cuando no se saca provecho.
Rep. Inheritance with Delegation
• •
Rep. Delegation with Inheritance
Problema: se está usando delegación y frecuentemente se escriben muchas delegaciones simples en toda la interfaz.
Solución: hacer de la clase delegada una subclase del delegado.
Patrón Estado
• State es un patrón que resuelve la problemática de que el depende de contienen la comportamiento de un objeto su estado, y sus métodos 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 estados de un objeto.
para los • Se maneja una clase de contexto que es la que sirve de interfaz al cliente.
Patrón Estado
Reeplace Array with Object
• Problema se tienen datos diferentes en un arreglo.
Solución crear un objeto con las propiedades distintas.
• String[] row = new String[3]; • row [0] = "Liverpool"; • row [1] = "15"; • Performance row = new Performance(); • row.setName("Liverpool"); • row.setWins("15");
Remove Setting Method
• Problema: un método set nunca se utiliza. En general cualquier método que no se use debe de eliminarse referencias).
(tener cuidado con las
Hide Method
• Problema: un método sólo es utilizado dentro de la misma clase.
• Solución: el acceso deberá ser privado en lugar de público.
Reeplace Exception with Test
• Problema: se deben evitar al máximo las excepciones ya que generalmente cambian el transcurso del código.
double getValueForPeriod (int periodNumber) { try { return _values[periodNumber]; } catch (ArrayIndexOutOfBoundsException e) { return 0;}
Reeplace Exception with Test
double getValueForPeriod (int periodNumber) { if (periodNumber >= _values.length) return 0; } return _values[periodNumber];
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 responsabilidad de la separan las 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
Introducción a .NET
• .NET (dot-net) es la propuesta de Microsoft para el desarrollo de aplicaciones orientadas a objetos, basadas en servicios sobre la red.
• .NET se compone de una máquina virtual y de un compilador JIT (Just in Time) que permite que el código sea portable.
• Como todo framework cuenta con un conjunto de clases predeterminadas dentro del CLR (Common Language Runtime) que permite la ejecución de diversos lenguajes (Visual Basic, C++, J#, C# entre otros).
Introducción a C#
• El lenguaje estrella es C# (leído como c-sharp, c gato o c almoadilla).
• Es un lenguaje orientado a objetos derivado de C++. Es la competencia directa a Java (muchos dicen que es un clon mejorado). Este lenguaje deriva de la versión de Java propuesta por Microsoft Visual J++.
• Maneja la opción de código seguro (managed code) aunque puede acceder a código nativo el cual no es seguro (se recomienda utilizar Visual C++ .NET)
C# versus Java (Similaridades)
• Ambos derivan de C y C++.
• Incluyen características comunes como el recolector de basura, el uso de lenguaje intermedio: en C# recibe el nombre de Microsoft Intermediate Language (MSIL), en Java es el bytecode. • Maneja herencia múltiple a través del uso de interfaces.
C# versus Java (Diferencias)
• C# contiene más datos primitivos que Java (enumeraciones*, estructuras). • Hay sobrecarga de operadores • Existe el uso de delegados para manejar de forma segura punteros para el manejo de eventos.
Hola mundo en C#
• El código se puede hacer en un editor de texto plano } using System; public class HelloWorld { public static void Main() { // This is a single line comment.
/* * This is a multiple line comment.
*/ Console.WriteLine("Hello World!"); }
Hola mundo en C#
• Para compilar en mono: mcs HelloWorld.cs
• • Para compilar en el SDK de .NET: csc HelloWorld.cs
• Para correr el programa en Mono: mono HelloWorld.exe
• En el SDK simplemente doble click o nombre de programa en línea de comandos
Tipos Básicos en C#
C# Type .Net Framework Type sbyte System.sbyte
short int System.Int16
System.Int32
long byte ushort System.Int64
System.Byte
System.Uint16
uint ulong float System.Uint32
System.Uint64
System.Single
Signed Yes Yes Yes Yes No No No No Yes Bytes 1 2 4 8 1 2 4 8 4 double decimal char bool System.Double
System.Decimal
System.Char
System.Boolean
Yes Yes N/A N/A 8 12 2 1/2 Possible Values -128 to 127 -32768 to 32767 2 31 to 2 31 - 1 2 63 to 2 63 - 1 0 to 255 0 to 65535 0 to 2 32 - 1 0 to 2 64 - 1 ± 1.5 x 10-45 to ± 3.4 x 1038 with 7 significant figures ± 5.0 x 10-324 to ± 1.7 x 10308 with 15 or 16 significant figures ± 1.0 x 10-28 to ± 7.9 x 1028 with 28 or 29 significant figures Any Unicode character true or false
Arreglos
• C# soporta dos tipos de arreglos multidimensional: rectangular y jagged.
• Cuando son rectangulares tienen el mismo tamaño.
• Cuando son
irregular: jagged tienen un tamaño
int[][] jag = new int[2][]; jag[0] = new int [4]; jag[1] = new int [6]; int[][] jag = new int[][] {new int[] {1, 2, 3, 4}, new int[] {5, 6, 7, 8, 9, 10}};
Operadores
• Son prácticamente los mismos de C, C++ y Java.
• Para realizar la sobrecarga de operador se puede aplicar: • • • } public static bool operator == (Value a, Value b) { return a.Int == b.Int
• Where an operator is one of a logical pair, both operators should be overwritten if any one is.
•
Ciclos
Cuenta con las mismas estructuras de repetición que C++/Java adicionando el ciclo foreach:
• • • • foreach (variable1 in variable2) statement[s] int[] a = new int[]{1,2,3}; foreach (int b in a) System.Console.WriteLine(b);
•
Namespaces
Son el equivalente a los packages en Java. Sirven para agrupar un conjunto de clases. Ejemplo:
• • • • • namespace myapi { namespace math { } } public class Adder { // insert code here }
•
Declaración de Clases
• Se asemeja mucho a C++. Para indicar herencia se utiliza el operador “:”. Ejemplo: public class DrawingRectangle : Rectangle • Las variables constantes se definen con const.
Entrada/Salida
• • • •
using System; using System.IO;
• • • • • •
class DisplayFile { static void Main(string[] args) { StreamReader r = new StreamReader(args[0]); string line; Console.Write("Out File Name: "); StreamWriter w = new StreamWriter(Console.ReadLine());
• • • • • • • •
} } while((line = r.ReadLine()) != null) { Console.WriteLine(line); w.WriteLine(line); } r.Close(); w.Close();
Excepciones
• Se manejan de manera muy similar a Java: • • • • try { res = (num / 0); catch (System.DivideByZeroException e) { Console.WriteLine("Error: an attempt to divide by zero"); • • } } • • Se puede realizar autodocumentación del código: • • ///
DLL
• La creación de librerías es simplemente muy sencillo solo se deberá indicar al compilador la opcion /target:library clase.cs a nuestra clase pura.
• Para ligar la dll a nuestro programa se deberá indicar el parámetro /reference:mibiblioteca.dll programa.cs desde el compilador.
• Para ejecutar código inseguro se utiliza la palabra clave unsafe{} dentro del código nativo.
• C# cuenta con goto.
II. Hello World
using System.Windows.Forms; using System.Drawing; class MyForm:Form{ public static void Main(){ Application.Run(new MyForm()); } } protected override void OnPaint(PaintEventArgs e){ e.Graphics.DrawString("Hello World!", new Font("Arial", 35), Brushes.Blue, 10, 100); }
III. C# Language
3.Expressions and operators
Práctica 9
• En algunas ocasiones es necesario convertir un lenguaje de un paradigma a otro lenguaje de otro paradigma.
• Aspect Oriented Programming es un nuevo enfoque
Referenicas
• Fowler, M. (1999), Refactoring, Adison-Wesley.
• Sanchez, M., (2009), Material del Curso de Reestructuración de Códigos, Instituto Tecnológico de Morelia.