Alessio Mavica PHP & MySQL Developer, Project Leader & Scrum Master

17sep/110

PHP refactoring

Cada aplicación en continuo crecimiento necesita modificaciones para que sea más rápida, para reorganizarla o para prepararnos a nuevos desarrollos a medio o largo plazo.

Este proceso se llama Refactoring, palabra que mucha gente odia porque necesita recursos para algo que no es ni un producto completo ni una release. Entonces es natural que vuestro Product Owner no lo vea favorablemente. Aunque en continua lucha para el Time To Market los desarrolladores deberían prestar la debida atención a esta fase ya que se podría llegar a la clásica situación de entrada en pérdida en la que para modificar el código spaghetti que hemos generado tiene un coste mayor que refactorizarlo.

Entonces cuáles son las lineas guías para un buen Refactogin? Buscamosles juntos...


CUÁL ES LA DEFINICIÓN DE REFACTORING

Oficialmente podemos definir el refactoring como el proceso para alterar el funcionamiento interno de una aplicación sin modificar su comportamiento externo.

LOS OBJETIVOS

  • Menor complejidad
  • Mayor legibilidad
  • Mejorar la fase de mantenimiento
  • Mejorar la escalabilidad

Entonce aquí un decálogo para acabar de manera satisfactoria un refactoring:

  1. CREAR NUEVOS MÉTODOS
  2. INTRODUCCIÓN DE NUEVAS VARIABLES EXPLICATIVAS
  3. RENOMBRAR MÉTODOS
  4. MOVER ELEMENTOS
  5. CREAR NUEVAS CLASES
  6. OCULTAR DELEGADOS
  7. TRANSFORMAR ARRAY EN OBJECTOS
  8. CAMBIAR LAS HERENCIAS POR DELEGADOS
  9. LAS ÚLTIMAS TRES REGLAS

1. CREAR NUEVOS MÉTODOS

Asumimos de tener esta función que calcula el precio total de un articulo con impuestos y gastos de envío:

public function getTotalPrice($id_product)
{
	$product_price = $this->getProductPrice($id_product);
	$product_price_taxed = $this->tax * $product_price;
	$product_price_shipping = $this->getProductShipping($id_product);

	$product_price_total =
		$product_price_taxed + $product_price_shipping;

	return $product_price_total;
}

Podemos aislar la línea para calcular los impuestos en un nuevo método:

// line 4 modified
$product_price_taxed = $this->getPriceTaxed($product_price);
// new method
public function getPriceTaxed($product_price)
{
	return $this->tax * $product_price;
}

2. INTRODUCCIÓN DE NUEVAS VARIABLES EXPLICATIVAS

Sobretodo en los casos de ciclos con condiciones muy complejas es aconsejable crear nuevas variables explicativas.

if (strpos($_SERVER['SERVER_NAME'], 'local') === FALSE)
	// do something

Aquí la vesión con una nueva variable explicativa:

$is_local = strpos($_SERVER['SERVER_NAME'], 'local');

if ($is_local === FALSE)
	// do something

3. RENOMBRAR MÉTODOS

Odio profundamente los desarrolladores que crean métodos con nombre inútiles porque genéricos:get, set, getForm, setValue...

Los nombres de los métodos son como los titulares de los periódicos: tienen que ser explicativos pero no demasiado largos.

4. MOVER ELEMENTOS

Otro paso para un buen refactoring es encontrar la posición correcta para métodos y atributos. Asumimos de haber creado una clase car con la variable piston y que luego hayamos creado la clase motor. Es evidente que la variable piston es un atributo de la clase motor y no de la clase car. Entonces en la fase de refactoring tenemos que reorganizar las asociaciones correctas entre clases, métodos y atributos.

5. CREAR NUEVAS CLASES

Si tenemos una sentencia if (o switch) de este tipo:

public class car
{
	private $motor;

	public function __constructor($motor)
	{
		$this->motor = $motor;
	}

	public function getMotor()
	{
		if($this->motor == 'DIESEL')
			return $this->getDieselPrice();
		elseif($this->motor == 'UNLEADED')
			return $this->getUnleadedPrice();
	}
}

Entonces es muy probable que tenemos que crear tres nuevas clases:

  • una abstracta motor
  • una dieselMotor que extende motor
  • una unleadedMotor que extende motor

6. OCULTAR DELEGADOS

Si tenemos una línea de código del tipo:

$fuelType = $car->getMotor()->getFuelType();

En que el método getMotor es:

public function getMotor()
{
	return $this->motor;
}

Tenemos que modificarlo para devolver directamente el atributo que necesitamos:

public function getMotor()
{
	return $this->motor->getFuelType();
}

Ésto para seguir la Ley de Demeter que dice que no tenemos que confiar en la estructura interna de un objecto ya que si viene modificado tendremos que cambiar muchas partes del código.

7. TRANSFORMAR ARRAY EN OBJECTOS

Asumimos que tenemos una clase car así:

public class car
{
	private $details;

	public function __constructor($details)
	{
		$this->details = $details;
	}
}

Entonces para crear el objecto car tenemos que pasar como parámetro un array con las características del coche. Si queremos devolver un detalle del coche tendremos que leerlo del array $details.
La manera más correcta para inicializar un objecto y almacenar sus atributos es crear una variable por cada característica.

public class car
{
	private $motor;
	private $brand;
	private $model;

	public function __constructor($motor, $brand, $model)
	{
		$this->motor = $motor;
		$this->brand = $brand;
		$this->model = $model;
	}
}

8. CAMBIAR LAS HERENCIAS POR DELEGADOS

Asumimos de tener una clase que implementa una interfaz para efectuar el log de la aplicación:

public class car extends Logger
{
	public function run()
	{
		...
		$this->log(...);
	}
}

La manera más correcta para hacerlo es pasa el objecto logger como parámetro en el momento de crear el objecto car y acceder a la variable sin extender ninguna clase. También en este caso estamos siguiendo la Ley de Demeter.

public class car
{
	private $logger;

	public function __contruct($logger)
	{
		$this->logger = $logger;
	}
	public function run()
	{
		...
		$this->logger->log(...);
	}
}

9. LAS ÚLTIMAS TRES REGLAS

Los últimos tres consejos para un buen refactoring son:

  1. eliminar código redundante
  2. escribir bloques de código pequeños
  3. separar conceptos diferentes

CONCLUSIONES

La fase de refactoring tiene que ser incluida en un buen proyecto y es fundamental para que la aplicación se mantenga simple, rápida y fácil de mantener.

¿Te gustó este artículo?

¡Suscríbete a nuestro feed RSS!

Comentarios (0) Trackbacks (0)

Aún no hay comentarios.


Leave a comment

(required)


2 × = dos

Aún no hay trackbacks.