Mi Neurona Favorita

Analizando

Archive for agosto 2012

Refactoring en Eclipse. (9) Self Encapsulate Field

with one comment

Nota: Este post pertenece a una serie. Ver introducción e índice.

Refactoring: Self Encapsulate Field

Para encapsular el acceso a un atributo de una clase hay que crear los métodos acceso y modificación (get y set) y sustituir cada uso que se haga del atributo por el correspondiente método. En Eclipse podemos hacerlo más rápidamente de la siguiente forma:

  1. Hacer click derecho sobre el atributo a encapsular, Refactor > Encapsulate Field…
  2. En el cuadro de diálogo, seleccionar “use setter and getter”. Eliminar el método set o usar el modificador de acceso a private para evitar su modificación.

Ejemplo antes de refactorizar:

public class Test {
  private int low, high;

  boolean includes(final int arg) {
    return arg >= low && arg <= high;
  }
}

Tras refactorizar, quedaría:

public class Test {
  private int low, high;

  boolean includes(final int arg) {
    return arg >= getLow() && arg <= getHigh();
  }
  
  private int getLow() {
    return low;
  }

  private int getHigh() {
    return high;
  }
}

Written by Recacha

30 agosto 2012 at 7:00

Publicado en Refactoring

Tagged with , ,

Refactoring en Eclipse. (8) Extract Class

with one comment

Nota: Este post pertenece a una serie. Ver introducción e índice.

Refactoring: Extract Class

Si tenemos una clase con demasiadas responsabilidades y queremos extraer algunas de ellas a una nueva clase, podemos extraerlas con ayuda de Eclipse. Lo haremos en 3 pasos, y en cada uno de ellos actuaremos según las necesidades de cada caso:

  1. Extraer atributos a una nueva clase
    1. En cualquier punto de la clase hacer click derecho > Refactor > Extract Class…
    2. En la ventana que aparece, le damos un nombre a la nueva clase, seleccionamos los atributos a extraer y nombraremos también la referencia que creará en la clase original del tipo de la nueva clase.
  2. Mover los métodos necesarios a la nueva clase, aplicando el refactoring “Extract Method”: SHIFT + ALT + V (o click derecho > Refactor > Move…)
  3. Eliminamos los getters y setters de los atributos movidos en el paso 1 de la clase original.

Ejemplo antes de refactorizar (sombreados los atributos y métodos que se van a mover a la nueva clase):

public class Person {
  private String _name;
  private String _officeAreaCode;
  private String _officeNumber;

  public String getTelephoneNumber() {
    return ("(" + _officeAreaCode + ") " + _officeNumber);
  }

  // GETTERS AND SETTERS

  public String getName() {
    return _name;
  }

  public String getOfficeAreaCode() {
    return _officeAreaCode;
  }

  public void setOfficeAreaCode(final String arg) {
    _officeAreaCode = arg;
  }

  public String getOfficeNumber() {
    return _officeNumber;
  }

  public void setOfficeNumber(final String arg) {
    _officeNumber = arg;
  }
}

Creamos la nueva clase TelephoneNumber con los atributos _officeAreaCode y _officeNumber (sombreados los cambios en la clase original):

public class Person {
  private String _name;
  private TelephoneNumber _telephoneNumber = new TelephoneNumber();

  public String getTelephoneNumber() {
    return ("(" + _telephoneNumber.get_officeAreaCode() + ") " + _telephoneNumber.get_officeNumber());
  }

  // GETTERS AND SETTERS

  public String getName() {
    return _name;
  }

  public String getOfficeAreaCode() {
    return _officeAreaCode;
  }

  public void setOfficeAreaCode(final String arg) {
    _officeAreaCode = arg;
  }

  public String getOfficeNumber() {
    return _officeNumber;
  }

  public void setOfficeNumber(final String arg) {
    _officeNumber = arg;
  }
}

public class TelephoneNumber {
  private String _officeAreaCode;
  private String _officeNumber;

  // GETTERS AND SETTERS

  public String get_officeAreaCode() {
    return _officeAreaCode;
  }

  public void set_officeAreaCode(final String _officeAreaCode) {
    this._officeAreaCode = _officeAreaCode;
  }

  public String get_officeNumber() {
    return _officeNumber;
  }

  public void set_officeNumber(final String _officeNumber) {
    this._officeNumber = _officeNumber;
  }
}

Por último movemos el método getTelephoneNumber() a la nueva clase y eliminamos de Person los getters y setters de los atributos movidos:

public class Person {
  private String _name;
  private TelephoneNumber _telephoneNumber = new TelephoneNumber();

  public String getTelephoneNumber() {
    return _telephoneNumber.getTelephoneNumber();
  }

  // GETTERS AND SETTERS

  public String getName() {
    return _name;
  }
}

public class TelephoneNumber {
  private String _officeAreaCode;
  private String _officeNumber;

  public String getTelephoneNumber() {
    return ("(" + get_officeAreaCode() + ") " + get_officeNumber());
  }

  // GETTERS AND SETTERS

  public String get_officeAreaCode() {
    return _officeAreaCode;
  }

  public void set_officeAreaCode(final String _officeAreaCode) {
    this._officeAreaCode = _officeAreaCode;
  }

  public String get_officeNumber() {
    return _officeNumber;
  }

  public void set_officeNumber(final String _officeNumber) {
    this._officeNumber = _officeNumber;
  }
}

Written by Recacha

28 agosto 2012 at 7:00

Publicado en Refactoring

Tagged with , ,

Función currval en Postgres

with one comment

Tenemos la siguiente situación: necesitamos hacer un script SQL para Postgres que inserte un valor en una determinada tabla, y para la PK hacemos uso de la función nextval sobre la secuencia. ¿Qué ocurre si a continuación necesitamos ese valor devuelto por la secuencia?

Pongamos un ejemplo práctico. Tenemos la clásica relación empleado – departamento:

department(id, name)
employee (id, name, id_department)

Necesitamos, mediante scripts, añadir un departamento y asignárselo al empleado llamado ‘John’. Además tenemos que hacer uso de la secuencia en el insert. Lo podríamos hacer de la siguiente forma:

INSERT INTO department VALUES (nextval('seq_department'), 'New department');
UPDATE employee SET id_department=currval('seq_department') WHERE name='John';

Written by Recacha

27 agosto 2012 at 17:00

Publicado en Base de datos

Tagged with

Refactoring en Eclipse. (7) Move Method

with 3 comments

Nota: Este post pertenece a una serie. Ver introducción e índice.

Refactoring: Move Method

Para aplicar esta refactorización en Eclipse, consistente en mover un método a una clase más apropiada, lo haremos en 2 pasos:

  1. Encapsular el acceso a los atributos de la clase que se usen en el método (usando get y set). Como veremos más adelante, se corresponde con el refactoring “Encapsulate Field”.
    1. Doble click sobre el atributo a encapsular.
    2. Click derecho > Refactor > Encapsulate Field…
    3. En la ventana, seleccionar el modificador de acceso más adecuado para el get y set, según dónde se encuentre la clase a la que se moverá el método.
  2. Mover el método
    1. Doble click en el nombre del método a mover.
    2. SHIFT + ALT + V (o click derecho > Refactor > Move…)
    3. Si se desea dejar el método original delegando en el nuevo, marcar el check “Keep original method as delegate…”. Eclipse cambiará el modificador de acceso del método si fuese necesario.

Ejemplo antes de refactorizar (sombreados los atributos que se van a encapsular en el primer paso):

public class Account {
  private AccountType _type;
  private int _daysOverdrawn;

  double overdraftCharge() {
    if (_type.isPremium()) {
      double result = 10;
      if (_daysOverdrawn > 7) {
        result += (_daysOverdrawn - 7) * 0.85;
      }
      return result;
    } else {
      return _daysOverdrawn * 1.75;
    }
  }

  double bankCharge() {
    double result = 4.5;
    if (_daysOverdrawn > 0) {
      result += overdraftCharge();
    }
    return result;
  }
}

Tras encapsular los atributos _type y _daysOverdrawn:

public class Account {
  private AccountType _type;
  private int _daysOverdrawn;

  double overdraftCharge() {
    if (get_type().isPremium()) {
      double result = 10;
      if (get_daysOverdrawn() > 7) {
        result += (get_daysOverdrawn() - 7) * 0.85;
      }
      return result;
    } else {
      return get_daysOverdrawn() * 1.75;
    }
  }

  double bankCharge() {
    double result = 4.5;
    if (get_daysOverdrawn() > 0) {
      result += overdraftCharge();
    }
    return result;
  }

  public AccountType get_type() {
    return _type;
  }

  public void set_type(AccountType _type) {
    this._type = _type;
  }

  public int get_daysOverdrawn() {
    return _daysOverdrawn;
  }

  public void set_daysOverdrawn(int _daysOverdrawn) {
    this._daysOverdrawn = _daysOverdrawn;
  }
}

Por último movemos el método overdraftCharge() a la clase AccountType:

public class Account {
  private AccountType _type;
  private int _daysOverdrawn;

  double bankCharge() {
    double result = 4.5;
    if (get_daysOverdrawn() > 0) {
      result += overdraftCharge();
    }
    return result;
  }

  public AccountType get_type() {
    return _type;
  }

  public void set_type(AccountType _type) {
    this._type = _type;
  }

  public int get_daysOverdrawn() {
    return _daysOverdrawn;
  }

  public void set_daysOverdrawn(int _daysOverdrawn) {
    this._daysOverdrawn = _daysOverdrawn;
  }
}

public class AccountType {
  [...]
  double overdraftCharge() {
    if (get_type().isPremium()) {
      double result = 10;
      if (get_daysOverdrawn() > 7) {
        result += (get_daysOverdrawn() - 7) * 0.85;
      }
      return result;
    } else {
      return get_daysOverdrawn() * 1.75;
    }
  }
}

Written by Recacha

26 agosto 2012 at 7:00

Publicado en Refactoring

Tagged with , ,

Organización y productividad: mi método (parte III)

with 2 comments

Las 3 Fases

A los conocedores del método GTD, las 3 fases que sigo en mi sistema de organización les resultarán familiares.

Fase 1: Recopilar

Como no queremos que ninguna tarea pendiente esté en nuestra cabeza, cualquiera que sea la forma en que nos lleguen las nuevas cosas que hacer, debemos tener un sitio donde soltarlo inmediatamente, olvidarnos, y seguir con lo que estuviésemos haciendo. Es la bandeja de entrada. De momento hablaré de la bandeja de entrada como concepto, más adelante me centraré en la implementación.

Los medios más frecuentes para que nos lleguen tareas son el teléfono, el correo electrónico, correo postal, oído en una reunión u otro lugar, o en la herramienta de gestión de tareas corporativa (si existe y se usa, claro).

Fase 2: Procesar

La bandeja de entrada es un sitio temporal donde están todas las cosas que tenemos que hacer, pero no es nuestra lista de tareas propiamente dicha. Periódicamente hay que procesar la bandeja de entrada. La naturaleza de nuestro trabajo y el sentido común nos ayudarán a decidir cada cuánto tiempo se procesa. Yo intento procesar después de una tarea larga, y como poco, una vez al día.

Procesar la bandeja de entrada no es más que ir recorriendo cada elemento de la lista (sin saltarse ninguno) y realizarse las siguientes preguntas, que conllevan cada una a su respectiva acción:

  • ¿Tardaré menos de 2 minutos? Hacerlo ya.
    Si es una tarea que con toda seguridad nos llevará a lo sumo 2 minutos resolverla, la haremos inmediatamente. No merece la pena que forme parte de mi lista de cosas por hacer algo que me puedo quitar tan rápidamente de encima.
  • ¿Es material de consulta? Archivarlo.
    Si es un documento, un folleto, un libro o cualquier cosa que necesitarás consultar en un momento indeterminado del futuro, archívalo. Sobre formas eficiente de archivar (y me refiero a ficheros físicos y digitales) podéis encontrar información en el propio libro de David Allen, pero no profundizaré más por el momento.
  • ¿Es un evento con fecha determinada? Cita en el calendario.
    Reuniones, llamadas telefónicas a una determinada hora, recordatorios futuros, y en general, cualquier cosa que no se pueda hacer ahora mismo, sino que deba esperar a un momento concreto, se incluirá en nuestro calendario.
  • ¿Es una tarea que deba delegar? Delegar y añadir a la lista “En espera“.
    Si delegarla no me lleva más de dos minutos, la delegamos ya y lo anotamos en una lista de tareas delegadas, que en adelante llamaremos “En espera”. Sobre el arte de delegar también daría para una serie de artículos, por lo que tampoco se profundizará más.
  • ¿Ninguna de las anteriores? Es una tarea pendiente, por lo que se incluye en la lista “Tareas

Fase 3: Hacer

Por último, la mayoría del tiempo realmente estaremos llevando a cabo una tarea de nuestra lista. Aquí surge la pregunta: ¿qué tarea hago primero de mi lista? ¿Uso un sistema de prioridades? ¿Las clasifico por importantes, urgentes, etc? Yo simplemente uso el sentido común, la experiencia y el instinto en cada situación para elegir qué debo hacer en primer lugar. Si algo es importante y/o urgente, lo coloco en los primeros puestos de la lista. Cuando debo comenzar una nueva tarea, echo un vistazo y determino cual será la siguiente. He probado multitud de sistemas para priorizar, ordenar, etc, y ninguno me dio resultado. A veces la mejor tarea a realizar depende del momento del día y del tiempo que tengas para hacerla, sin más.

Conclusión

Como se ve, he simplificado al máximo el procedimiento a seguir en cada caso, y por ello quizá haya personas que necesiten fases intermedias, incrementar la frecuencia de procesado, o tener en cuenta otros factores durante el procesado. Ya queda en manos de cada cual adaptarlo a sus necesidades.

En este artículo hemos hablado de la bandeja de entrada, del calendario, de las listas de espera y la de tareas, pero ¿a qué me refiero exactamente con cada una de ellas? Veremos en el siguiente artículo cómo implemento yo cada uno de ellos.

Written by Recacha

26 agosto 2012 at 1:00

Refactoring en Eclipse. (6) Remove Assignments to Parameters

with one comment

Nota: Este post pertenece a una serie. Ver introducción e índice.

Refactoring: Remove Assignments to Parameters

Es una mala práctica asignar valores a los parámetros de entrada de un método, porque el código resultante puede llevar a confusión. Para evitar esto, es aconsejable marcar siempre los parámetros de entrada del método como final. Para aplicar esta refactorización bastará configurar Eclipse para que lo haga automáticamente de la siguiente forma:

  1. Entramos en Preferences > Java > Editors > Save Actions
  2. Marcar “Perform the selected actions on save” y “Additional actions”.
  3. Pulsar el botón “Configure…” y entrar en la pestaña “Code Style”. Abajo, en el apartado “Variable declarations”, marcar “Use modifier final where possible” y marcar “Parameter”.

Si estamos refactorizando un código existente, cuando guardemos la primera vez un cambio, Eclipse solo marcará como final los parámetros de entrada que NO sean reasignados dentro del método. Para el resto, se pueden seguir estos pasos:

  1. Añadir final a los parámetros de entrada que no lo tengan.
  2. Crear una variable temporal y asignarle el parámetro de entrada.
  3. Sustituir todos los usos del parámetro de entrada dentro del método por la nueva variable.

Ejemplo antes de refactorizar:

public void discount(int inputVal, int quantity, int yearToDate) {
  if (inputVal > 50) {
    inputVal -= 2;
  }
  // do something
}

Añadir final a todos los parámetros de entrada, crear la variable result y refactorizar:

public void discount(final int inputVal, final int quantity, final int yearToDate) {
  int result = inputVal;
  if (result > 50) {
    result -= 2;
  }
  // do something
}

Written by Recacha

24 agosto 2012 at 7:00

Publicado en Refactoring

Tagged with , ,

Refactoring en Eclipse. (5) Introduce Explaining Variable

with one comment

Nota: Este post pertenece a una serie. Ver introducción e índice.

Refactoring: Introduce Explaining Variable

Si tenemos expresiones complejas, puede resultar interesante crear una variable temporal con un nombre explicativo, lo que favorecerá la legibilidad del código. Para aplicar este refactoring en Eclipse, seguiremos los siguientes pasos:

  1. Seleccionar la expresión a sustituir.
  2. SHIFT + ALT + L (o bien, click derecho > Refactor > Extract Local Variable…)
  3. Dar un nombre a la nueva variable y marcar ambos checks, para que sustituya todas las apariciones de la expresión y declare la variable como final.

Ejemplo antes de refactorizar:

public void test() {
  if ((platform.toUpperCase().indexOf("MAC") > -1) &&
      (browser.toUpperCase().indexOf("IE") > -1) &&
      wasInitialized() && resize > 0 ) {
    // do something
  }
}

Refactorizamos las expresiones del if:

public void test() {
  final boolean isMacOS = platform.toUpperCase().indexOf("MAC") > -1;
  final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
  final boolean wasResized = resize > 0;

  if (isMacOS && isIEBrowser && wasInitialized() && wasResized ) {
    // do something
  }
}

Written by Recacha

22 agosto 2012 at 7:00

Publicado en Refactoring

Tagged with , ,