Es muy común en nuestro día a día, como desarrolladores, trabajar con códigos escritos por otros desarrolladores, ya sea para comprender una regla de negocio o para la evolución del programa en general.
Para entender mejor esta situación, consideremos una aplicación Java para un inventario de productos. En esta aplicación, tenemos el siguiente código:
public class ProductoDAO {
public List<Producto> lista() {
// Implementación cualquiera que devuelve una lista de productos
}
public void productosResumido() {
List<Producto> prs = lista();
for (Producto p : prs) {
String dse = p.getDescripcion().trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < dse.length(); i++) {
if (i > 15) {
sb.append("...");
break;
}
sb.append(dse.charAt(i));
}
String da = sb.toString();
String vf = p.getValor().toString().replace(".", ",");
String df = p.getId() + " - " + da + " - $ " + vf;
System.out.println(df);
}
}
}
public class Producto {
private Integer id;
private String descripcion;
private Double valor;
// Constructores, getters, setters y métodos
}
Al ejecutar el método productosResumido()
, obtenemos el siguiente resultado:
1
- Refresco de ... - R$ 5,0 2
- Doritos ... - R$ 3,5 3
- Pan de forma Pre... - R$ 4,5 4
- Leche Larga Vida... - R$ 2,75 5
- Jugo Tang 30g - R$ 4,0
Observando el resultado, obtenemos un resumen de los productos guardados en el inventario. Sin embargo, al analizar rápidamente la implementación del método produtosResumido()
, no resulta tan evidente que este resultado se presentaría de manera tan clara. A primera vista, no...
En otras palabras, observa que hemos llegado a una situación en la que tiene todo el sentido detenerse y pensar en maneras de mejorar nuestro código actual, ¿cierto?
Este proceso de mejora del código se conoce técnicamente como code refactoring, o en español, refactorización de código.
Esta técnica, en términos generales, consiste en diversas prácticas que buscan mejorar el código en los siguientes aspectos:
A primera vista, podrías estar pensando:
""¡La refactorización es genial, pero si hago esto, estaré modificando el comportamiento de mi aplicación!"
La primera impresión que tenemos durante este tipo de proceso es imaginar que nuestra aplicación será modificada y presentará comportamientos diferentes.
Esto es algo muy común, pero la idea de la refactorización es aplicar técnicas que modifican únicamente el aspecto visual del código, es decir, ¡el comportamiento inicial sigue siendo el mismo!
¡Parece demasiado bueno para ser verdad, verdad? Por lo tanto, apliquemos algunas técnicas de refactorización en el código que vimos inicialmente ¡y veremos cómo ocurre la magia!
La primera técnica que aplicaremos será la renombración de variables. A simple vista, puede parecer algo trivial, pero echemos un vistazo a un fragmento de nuestro código:
Aquí tienes el código traducido al español:
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionFormatada = producto.getDescripcion().trim();
// restante del código
}
¿Para ti, prs
, p
, dse
tienen algún significado? Para mí y para cualquier persona que vea este código por primera vez, no tienen significado alguno a primera vista. Entonces, ¿qué tal si hacemos la siguiente modificación?
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionSinEspacios = producto.getDescripcion().trim();
// resto del código
}
Ahora es evidente que estamos trabajando con una lista de productos, y que para cada producto de la lista productos
estamos obteniendo una descripcionSinEspacios
.
¡Nota que incluso leer el código es más fácil! En otras palabras, durante el proceso de refactorización, renombrar variables facilita la lectura del código. Por lo tanto, cuanto más significativo sea el nombre de la variable, más fácil será leerlo. Ajustemos los demás puntos:
public void productosResumidos() {
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionSinEspacios = producto.getDescripcion().trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < descripcionSinEspacios.length(); i++) {
if (i > 15) {
sb.append("...");
break;
}
sb.append(descripcionSinEspacios.charAt(i));
}
String descripcionAjustada = sb.toString();
String valorFormateado = producto.getValor().toString().replace(".", ",");
String descripcionFinal = producto.getId() + " - " + descripcionAjustada + " - R$ " + valorFormateado;
System.out.println(descripcionFinal);
}
}
Observa que la variable sb
, que se refiere a la instancia de la clase StringBuilder
, se mantiene. Dado que es una instancia de una clase conocida por la mayoría de los desarrolladores y no tiene un nombre tan corto, no hay problema en dejarla como sb
.
En otras palabras, para casos en los que estamos creando una instancia de una clase con un nombre largo, podemos usar una abreviación. En el caso de StringBuilder
, incluso podríamos haber usado builder
, ya que tendría un significado suficiente.
Recuerda: Durante el proceso de renombrar las variables, lo más importante es que al momento de leer el código, la lectura sea fácil y objetiva. Es decir, incluso para alguien que no esté tan familiarizado con la implementación, debería ser comprensible simplemente leyendo el código.
Extracción de método Aunque nuestro código ha mejorado significativamente en términos de legibilidad —es decir, con nombres más claros para nosotros los humanos—, sigue siendo algo complejo. Si observamos con atención, tenemos una gran cantidad de líneas dentro de un solo método.
Teniendo en cuenta esta situación, ¿qué podemos hacer para resolver este detalle? Para este tipo de escenario, podemos aplicar la técnica conocida como extracción de método. Ahora probablemente estés pensando:
"Genial, pero ¿cómo funciona esta técnica?"
Extracción de método y renombrado de variables: traducido al español
Básicamente, al leer el código, analizamos y verificamos qué hace un conjunto de código. Por ejemplo, este fragmento:
String descripcionSinEspacios = producto.getDescripcion().trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < descripcionSinEspacios.length(); i++) {
if (i > 15) {
sb.append("...");
break;
}
sb.append(descripcionSinEspacios.charAt(i));
}
String descripcionAjustada = sb.toString();
Si lo observamos con atención, ¡todo este código tiene como objetivo ajustar la descripción de un producto! Entonces, ¿qué tal si transformamos todo este bloque en un método como este?
private String ajustarDescripcion(Producto producto) {
String descripcionSinEspacios = producto.getDescripcion().trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < descripcionSinEspacios.length(); i++) {
if (i > 15) {
sb.append("...");
break;
}
sb.append(descripcionSinEspacios.charAt(i));
}
return sb.toString();
}
Ahora basta con realizar la siguiente llamada dentro de nuestro código anterior:
public void productosResumidos() {
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionAjustada = ajustarDescripcion(producto);
String valorFormateado = producto.getValor().toString().replace(".", ",");
String descripcionFinal = producto.getId() + " - " + descripcionAjustada + " - $ " + valorFormateado;
System.out.println(descripcionFinal);
}
}
¡Mira cómo se redujo el método! Leerlo se vuelve mucho más fácil de esta manera. Podemos aplicar lo mismo a otros puntos del código, como este:
String valorFormateado = producto.getValor().toString().replace(".", ",");
Básicamente, este fragmento formatea el valor de acuerdo con la moneda. En este caso, nada nos impide extraer otro método:
private String formatearMoneda(Producto producto) {
return producto.getValor().toString().replace(".", ",");
}
Además, podemos aplicar el mismo concepto al siguiente fragmento de código:
String descripcionFinal = producto.getId() + " - " + descripcionAjustada + " - $ " + valorFormateado;
Y extraerlo de esta forma:
private String resumirDescripcion(Producto producto, String descripcionAjustada, String valorFormateado) {
return producto.getId() + " - " + descripcionAjustada + " - $ " + valorFormateado;
}
Ahora nuestro método inicial queda así:
public void productosResumidos() {
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionAjustada = ajustarDescripcion(producto);
String valorFormateado = formatearMoneda(producto);
String descripcionFinal = resumirDescripcion(producto, descripcionAjustada, valorFormateado);
System.out.println(descripcionFinal);
}
}
¡Mucho más fácil de leer, cierto?
Incluso podemos simplificar más, en lugar de enviar tres parámetros para crear la descripción final, podemos enviar solo el objeto Producto
y llamar a los demás métodos dentro de resumirDescripcion()
:
public void productosResumidos() {
List<Producto> productos = lista();
for (Producto producto : productos) {
String descripcionFinal = resumirDescripcion(producto);
System.out.println(descripcionFinal);
}
}
private String resumirDescripcion(Producto producto) {
String descripcionAjustada = ajustarDescripcion(producto);
String valorFormateado = formatearMoneda(producto);
return producto.getId() + " - " + descripcionAjustada + " - $ " + valorFormateado;
}
private String formatearMoneda(Producto producto) {
return producto.getValor().toString().replace(".", ",");
}
private String ajustarDescripcion(Producto producto) {
String descripcionSinEspacios = producto.getDescripcion().trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < descripcionSinEspacios.length(); i++) {
if (i > 15) {
sb.append("...");
break;
}
sb.append(descripcionSinEspacios.charAt(i));
}
return sb.toString();
}
Ahora el método productosResumidos()
es mucho más fácil de entender.
Sabemos rápidamente que recorre cada producto, genera una descripcionFinal
y la imprime.
Conclusión: Aunque el código parecía complejo al principio, simplemente aplicando algunas técnicas de refactorización como extracción de método y renombrado de variables logramos mejorar mucho la legibilidad y comprensión del código.
¿Te gustaría aprender más técnicas de refactorización? Entonces consulta nuestro curso de Refactorización en la práctica con Java, donde abordamos estas técnicas y otras que marcan una gran diferencia en la mejora del código.
Cursos de Programación, Front End, Data Science, Innovación y Gestión.
Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana
Paga en moneda local en los siguientes países
Cursos de Programación, Front End, Data Science, Innovación y Gestión.
Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana
Paga en moneda local en los siguientes países
Puedes realizar el pago de tus planes en moneda local en los siguientes países:
País | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Plan Semestral |
486.67
BOB |
69704.84
CLP |
290438.59
COP |
65.90
USD |
259.47
PEN |
1441.54
MXN |
3031.66
UYU |
65.90
USD |
533.19
GTQ |
34952.61
CRC |
4234.92
DOP |
Plan Anual |
737.76
BOB |
105667.89
CLP |
440285.52
COP |
99.90
USD |
393.34
PEN |
2185.29
MXN |
4595.79
UYU |
99.90
USD |
808.29
GTQ |
52985.83
CRC |
6419.86
DOP |
Acceso a todos
los cursos
Estudia las 24 horas,
dónde y cuándo quieras
Nuevos cursos
cada semana