Malos Hábitos de la Codificación M.C. Juan Carlos Olivares Rojas Marzo 2010

Preview:

Citation preview

Malos Hábitos de la Codificación

M.C. Juan Carlos Olivares Rojas

Marzo 2010

• 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 (creatividad), Habilidad para trabajar en forma autónoma, Preocupación por la calidad.

Competencias

• Código duplicado• Codificación excesiva

• Mal diseño

• Pruebas

• Refactorización de Generalización• Más patrones de Diseño.

Temario

• 30% Prácticas

• 10% Otras actividades en el aula

• 60% Actividad de Evaluación Integral (Teórico-Práctico)

Evidencias

• 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.

Código duplicado

• 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 sus métricas de codificación y de refactoring.

Codificación excesiva

• 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.

Mal diseño

• 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 código donde previamente no existe 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.

Pruebas

• 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 para cada funcionalidad de tu programa.

• 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.

Actividades

• La generalización es una herramienta muy potente que nos permite evitar mucha duplicación de código. 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.

Ref. en el manejo de Herencia

• 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.

Pull Up Constructor Body

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;}

• 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 el constructor de su superclase, y después el de ella misma.

Pull Up Constructor Body

• 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.

Extract Subclass

Trabajo

getTotalPricegetUnitPricegetEmployee

TrabajogetTotalPricegetUnitPrice

Labor

getUnitPricegetEmployee

• 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 Subclass

• Problema: se tienen dos clases con características similares

• Solución: crear una superclase y mover las características comunes a la superclase.

Extract Superclass

Department

getTotalAnnualCost()getName()

getHeadCount()

Employee

getTotalAnnualCost()getName()

getld()

PartygetTotalAnnualCost( )

getName( )

Department

getHeadCount( )

Employee

getld( )

• 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 Superclass

• 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

• Extract Interface

EmployeegetRate()

hasSpecialSkill()getName()

getDepartment()

<<interface>>Billable

getRate( )hasSpecialSkill( )

EmployeegetRate()

hasSpecialSkill()getName()

getDepartment()

• 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.

Extract Interface

• 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?

Interfaz vs Clase Abstracta

• Problema: Una superclase y una subclase no son muy diferentes

• Solución: mezclar las clases

Colapse Hierarchy

Empleado

Vendedor

Empleado

• 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

Colapse Hierarchy

• 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.

Actividad

• El constructor recibirá un String como argumento para construir su valor.

• Se deberán realizar casos de prueba que validen todas las opciones de la implementación.

Actividad

• 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. 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.

• 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.

Patrón Estado

Patrón Estado

• 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");

Reeplace Array with Object

• Problema: un método set nunca se utiliza. En general cualquier método que no se use debe de eliminarse (tener cuidado con las referencias).

Remove Setting 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.

Hide Method

• 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];}

Reeplace Exception with Test

• 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

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 Signed Bytes Possible Values

sbyte System.sbyte Yes 1 -128 to 127

short System.Int16 Yes 2 -32768 to 32767

int System.Int32 Yes 4 231 to 231 - 1

long System.Int64 Yes 8 263 to 263 - 1

byte System.Byte No 1 0 to 255

ushort System.Uint16 No 2 0 to 65535

uint System.Uint32 No 4 0 to 232 - 1

ulong System.Uint64 No 8 0 to 264 - 1

float System.Single Yes 4 ±1.5 x 10-45 to ±3.4 x 1038 with 7 significant figures

double System.Double Yes 8 ±5.0 x 10-324 to ±1.7 x 10308 with 15 or 16 significant figures

decimal System.Decimal Yes 12 ±1.0 x 10-28 to ±7.9 x 1028 with 28 or 29 significant figures

char System.Char N/A 2 Any Unicode character

bool System.Boolean N/A 1/2 true or false

Arreglos• C# soporta dos tipos de arreglos

multidimensional: rectangular y jagged.

• Cuando son rectangulares tienen el mismo tamaño.

• Cuando son jagged tienen un tamaño irregular: 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:• /// <summary>• /// The myClass class represents an arbitrary class• /// </summary>

• Se utliza el parámetro /doc:myfile.xml en csc

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 Worldusing 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# Language3.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

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

• Sanchez, M., (2009), Material del Curso de Reestructuración de Códigos, Instituto Tecnológico de Morelia.

Referenicas

Dudas