Que es Encriptación ?

Toda encriptación se encuentra basada en un Algoritmo, la función de este Algoritmo es básicamente codificar la información para que sea indescifrable a simple vista , de manera que una letra “A” pueda equivaler a :“5×5mBwE” o bien a “xQE9fq”, el trabajo del algoritmo es precisamente determinar como será transformada la información de su estado original a otro que sea muy difícil de descifrar.

Una vez que la información arrive a su destino final, se aplica el algoritmo al contenido codificado “5×5mBwE” o bien a “xQE9fq” y resulta en la letra “A” o según sea el caso, en otra letra. Hoy en día los algoritmos de encriptación son ampliamente conocidos,es por esto que para prevenir a otro usuario “no autorizado” descifrar información encriptada, el algoritmo utiliza lo que es denominado llave (”key”) para controlar la encriptación y decriptación de información. Algunos algoritmos son DES (algoritmo simétrico) AES que posiblemente suplantará a DES y uno de los más conocidos RSA (algoritmo asimétrico)

Que función tiene la llave (”key”) ?

Existen dos tipos de llaves (”key’s”) , pero la de mayor uso en Internet es denominada “public key” o algoritmo asimétrico. El nombre “public” proviene de su funcionamiento: existe una llave pública que es dada a conocer a cualquier persona que así lo desee (todo Internet), esta llave pública es utilizada por los emisores de mensajes para encriptar información , sin embargo, existe otra llave ( su pareja por llamarla de alguna manera) única que es conocida exclusivamente por el destinatario del mensaje, y es mediante esta llave única | secreta que el destinatario descifra (”decripta”) los mensajes encriptados por el emisor.

Firmas Digitales (”Digital Signatures”)

Una firma digital utiliza el mismo funcionamiento del “public key” o algoritmo asimétrico mencionado anteriormente.
Como se mencionó, existe una “llave pública” y una “llave secreta”, en el caso de firmas digitales la llave pública que es ampliamente conocida es capaz de identificar si la información proviene de una fuente fidedigna.En otras palabras, la llave pública será capaz de reconocer si la información realmente proviene de la “llave secreta” en cuestión.Ejemplo:

El departamento de compras posee las llaves públicas de todos los empleados de la compañía, si llega un pedimento con la dirección de email del Director de Finanzas, Cómo puede asegurarse el departamento de compras que en realidad esta persona realizó el pedimento y no alguna otra que sobrepuso el email ?. La llave secreta del director de finanzas debe de encontrarse solo en su computadora, por lo tanto al enviar el mensaje electrónico esta llave pública se añadió al email,y por lo tanto las llave publicas determinarán si la llave secreta coincide con la del director.

Encriptación de Cadenas



Algunos Procedimiento Visual Basic para Codificar y Decodificar Información

Por Harvey Triana

La Encriptación, es un tema de la programación bien interesante, de hecho se trata de una alta ciencia de la informática, que pasa por arte, inclusive hoy se trata de una tecnología. Encriptación es una palabra rara en español, quizá fea, no obstante se emplea en documentación técnica.

Un Proyecto sobre Encriptación...

Buscando en el cajón de los recuerdos, encontré un par de procedimientos para Codificación / Decodificación con QuickBasic. Desaforadamente desconozco al programador de tales procedimientos. Después de traducir las rutinas para que trabajasen en Visual Basic me di cuenta que tenían fallas de programación, sin embargo la documentación del código me llevo a captar la idea del autor y ponerla a funcionar perfectamente. Tales procedimientos se exponen en este documento.


Algo de Teoría

Recuerdo que alguien comentaba que codificar era muy sencillo, simplemente cambias unas letras por otras, y el receptor del mensaje conoce este secreto. También, aumentar o disminuir un número discreto a los códigos ASCII, suele ser otra sugerencia. Estas estrategias pasan a ser infantiles tratamientos del problema, y no presentan problema alguno para un decodificador experto y malo.

La encriptación se hace a través de la aplicación de cierto tratamiento a los códigos ASCII de los mensajes, de manera que el tratamiento inverso será el único camino práctico para decodificar el mensaje.

¿Cómo se mantiene indescifrable una cadena codificada?. Se trata de combinar la clave de encriptación con el mensaje de manera que las probabilidades de decodificar el mensaje, sin conocer la clave, sean virtualmente infimas, es decir, el tan prolongado el trabajo de desciframiento que no existen esperanzas próximas. Por ejemplo cuando un cristal ornamental se rompe violentamente, es casi imposible volver a juntar las piezas para obtener la pieza original.

Como una cita teórica, uno de los algoritmos de codificación se basa en la función números primos. Por ejemplo resulta fácil multiplicar dos números primos, sean a = 11927 y b = 20903, de manera que a • b = c = 249310081. Pero resulta muy difícil determinar a y b a partir de c. Matemáticamente esto se hace a través del procedimiento conocido como Descomposición Factorial. En el ejemplo c viene a ser la codificación, mientras a y b son la clave de decodificación. Esta estrategia es la base de un ingenioso y sofisticado sistema de encriptación llamado Criptosistema RSA (en honor a sus autores). de hecho este es el mejor sistema de encriptación y es posible que sea aplicado en las comunicaciones masivas de Internet en un futuro. Siguiendo con mí ejemplo, en un caso real, se trata de cifras de alrededor de 250 dígitos, lo cual teóricamente requiere de millones de años para descomponer factorialmente. Una anécdota citada en el libro Camino al Futuro (2ª edición) de Mr. Gates, cuenta que un reto publico de descifrar una clave de 129 dígitos fue superado al coordinar un trabajo de varias computadoras e Internet, para finalmente lograr la respuesta en menos de un año. En el reto los autores predecían que su mensaje jamás sería desvelado. El libro mencionado hace una exposición más detallada de este tema. Por supuesto, este articulo no llegará tan lejos.


Dos Procedimientos de Encriptación

La Encriptación tiene dos elementos: Un mensaje, y una clave privada de acceso entre el emisor y el receptor, con la cual se puede descifrar el mensaje. El procedimiento de encriptación produce un mensaje o archivo cifrado. Presento dos procedimientos escritos en Visual Basic, catalogados como verdaderas maneras de encriptación.


Modelo EncryptionString

EncryptionString, es un clásico sistema el cual toma el mensaje y una clave del usuario, y a través de una combinación de estos dos parámetros se produce una cadena codificada. Mantengo la explicación original del método:

Texto a codificar:         ENCRYPTION
Caracteres del Texto:      E   N   C   R   Y   P   T   I   O   N
Códigos ASCII:             69  78  67  82  89  80  84  73  79  78
Contraseña KEY:            K   E   Y   K   E   Y   K   E   Y   K
Caracteres de KEY:         75  69  89  75  69  89  75  69  89  75
Suma de Códigos ASCII:     144 147 156 157 158 169 159 142 168 153
En caracteres:                "   œ      ?   ©   Ÿ   ?   ¨   TM

Texto codificado:          "œ?©Ÿ?¨TM

El modo para usar la función EncryptionString es el siguiente:

'//Codifica
TextoCodificado = EncryptString(TextoOriginal, Contraseña, ENCRYPT)

'//Decodifica
TextoOriginal = EncryptString(TextoCodificado, Contraseña, DECRYPT)

La ventaja de esta técnica es que es muy flexible de usar e intuitiva. Sin tener la máxima seguridad, es muy segura. Escribir un programa para encriptar archivos resulta bastante simple por aquello de la contraseña. No ocurre lo mismo con el siguiente procedimiento: ChrTran.

El código de EncryptionString es el siguiente:

DefInt A-Z
Option Explicit

'//For Action parameter in EncryptString
Public Const ENCRYPT = 1, DECRYPT = 2

'---------------------------------------------------------------------
' EncryptString
' Modificado por Harvey T.
'---------------------------------------------------------------------
Public Function EncryptString( _
    UserKey As String, Text As String, Action As Single _
    ) As String
    Dim UserKeyX As String
    Dim Temp     As Integer
    Dim Times    As Integer
    Dim i        As Integer
    Dim j        As Integer
    Dim n        As Integer
    Dim rtn      As String

    '//Get UserKey characters
    n = Len(UserKey)
    ReDim UserKeyASCIIS(1 To n)
    For i = 1 To n
        UserKeyASCIIS(i) = Asc(Mid$(UserKey, i, 1))
    Next

    '//Get Text characters
    ReDim TextASCIIS(Len(Text)) As Integer
    For i = 1 To Len(Text)
        TextASCIIS(i) = Asc(Mid$(Text, i, 1))
    Next

    '//Encryption/Decryption
    If Action = ENCRYPT Then
       For i = 1 To Len(Text)
           j = IIf(j + 1 >= n, 1, j + 1)
           Temp = TextASCIIS(i) + UserKeyASCIIS(j)
           If Temp > 255 Then
              Temp = Temp - 255
           End If
           rtn = rtn + Chr$(Temp)
       Next
    ElseIf Action = DECRYPT Then
       For i = 1 To Len(Text)
           j = IIf(j + 1 >= n, 1, j + 1)
           Temp = TextASCIIS(i) - UserKeyASCIIS(j)
           If Temp < 0 Then
              Temp = Temp + 255
           End If
           rtn = rtn + Chr$(Temp)
       Next
    End If

    '//Return
    EncryptString = rtn
End Function

Modelo ChrTran

ChrTran es violentamente complicado de violar, de hecho imposible. Virtualmente las probabilidades de descifrar un mensaje son del orden de 255! (255 factorial), un numero sin fin en la práctica (por ejemplo las calculadoras comunes soportan solo hasta 69!).

Tengo que confesar que tuve que reescribir ChrTran porque presentaba errores de programación y mucho código para optimizar, el resultado es sorprendente. Ni que decir que no tenía en cuenta que en español usamos tildes y eñes.

Como su abreviación lo dice ChrTran transpone caracteres, usa dos claves de 255 caracteres (la carta ASCII) y produce un texto codificado de origen aleatorio. Toma cada carácter del texto, encuentra su posición en la primera clave, e intercambia este carácter por el carácter en la misma posición de la segunda clave. Es complicado de asimilar.

Lo más difícil de ChrTran es el manejo de las claves. La primera clave (la sarta de búsqueda) podría ser publica (mejor debiera decir debe ser publica). Mientras que la segunda clave es una sarta aleatoria de la carta ASCII.

El modo de manejar ChrTran es el siguiente:

ClaveAleatoria = RandomChart()

'// Se podría usar la sarta de búsqueda, ClaveDeBúsqueda, como
'// otra cadena aleatoria con ClaveDeBúsqueda = RandomChart()
'// aqui se mantiene un nivel de Encriptación flexible, más no
'// inseguro, al hacer ClaveDeBúsqueda como la secuencia 0 a 255
'// de la carta ASCII:
For i = 0 To 255
    ClaveDeBúsqueda = ClaveDeBúsqueda + Chr$(i)
Next

'//Codifica
TextoCodificado = ChrTran(TextoOriginal, ClaveDeBúsqueda, ClaveAleatoria)

'//Decodifica
TextoOriginal= ChrTran(TextoCodificado, ClaveAleatoria, ClaveDeBúsqueda)

En la primera línea se usa RandonChart, la cual es una función que retorna la carta ASCII en un orden aleatorio.

Como posiblemente se deduce, usar ChrTran para escribir un programa que trabaje encriptación, representa una labor bastante especializada, pero por supuesto nada del otro mundo.

El código de ChrTran es el siguiente:

DefInt A-Z
Option Explicit

'//---------------------------------------------
'// Return a random string of ASCII Chart.
'// Used by ChrTran. By Harvey T.
'//---------------------------------------------
Public Function RandomChart() As String
    Dim Char    As String
    Dim RndStr  As String
    Dim n       As Integer

    Randomize Timer
    Do
       Char = Chr$(Int(Rnd * 256))
       If InStr(RndStr, Char) = 0 Then
          n = n + 1
          RndStr = RndStr + Char
       End If
    Loop Until n = 256

    RandomChart = RndStr
End Function

'---------------------------------------------------------------------
' ChrTran
' Optimizing by Harvey T.
'---------------------------------------------------------------------
Public Function ChrTran(Text As String, SStr As String, EStr As String) As String
    Dim i   As Integer
    Dim rtn As String

    For i = 1 To Len(Text)
        rtn = rtn + Mid$(EStr, InStr(SStr, Mid$(Text, i, 1)), 1)
    Next
    ChrTran = rtn
End Function

Aplicación de Ejemplo

La figura que encabeza este articulo muestra la cara de la aplicación EncryptProject, la cual es una herramienta que utiliza las técnicas de encriptación descritas y lo creé con el propósito de proteger código Visual Basic. Es decir, supón que trabajas en un proyecto grande, en un equipo de programación y deseas mantener en privado ciertos módulos. Generalmente yo organizo mis proyectos por módulos, en carpetas aparte, así, EncryptProject tiene la finalidad de encriptar los módulos Visual Basic de esta carpeta. Así, cuando voy a trabajar, decodifico, cuando me voy encripto.

Si desea usar EncryptProject , debe tener en cuanta esta precuación:

Backup your files (in another disc or with password) before encrypt project.
No forget your password, it’s without it reversing !
Encrypt only work over: Bas, Frm, Cls, Ctl, html files

Es decir, como una percusión, debiera tener al menos una copia aparte del proyecto. Pero no se atemorice, el programa es seguro, lo peor que le podría pasar al que lo use es olvidar la contraseña (EncryptProject pide verificación de la contraseña antes de codificar). Recomiendo para empezar, hacer una prueba sencilla con un proyecto simple.

Dos pasos y salimos. Hagamos una prueba simple. Cree una carpeta, copie o cree u proyecto Visual Basic en ella.


Encriptando

Abra EncryptProject, y escriba la trayectoria completa de la carpeta (si lo prefiere, arrastre un archivo cualquiera de la carpeta desde el Explorador de archivos de Windows a la caja de texto Project Folder).

Escriba la contraseña y use el comando [Encrypt]. Se pedirá la verificación de la contraseña. Después de confirmar, se encriptará el proyecto.

Encriptar en Visual Basic y Visual Basic.NET

Aqui les dejo un buen articulo sacado de djk

Una clase sencilla para encriptar cadenas

 

Uno de los problemas clásicos con los que nos enfrentamos los programadores es el de encriptar los datos. La cantidad de situaciones en las que necesitamos encriptar los datos es incontable.

 

Normalmente los datos se almacenan en una base de datos, y esta suele ser segura, pero las claves de conexión se encuentran en archivos de texto planos, XML … Incluso hay muchas bases de datos en las que la información de las claves con las que los usuarios se conectan a los sistemas corporativos estan sin encriptar, con lo que además podemos llegar a comprometer la seguridad de todo nuestro sistema.

 

Existen complejos algoritmos que permiten la encriptación de datos y que garantizan matemáticamente que nadie los puede desencriptar, como es el caso de MD5, utilizado para emitir certificados de seguridad en sistemas SSL. Tambien existen componentes de software que realizan el trabajo de encriptación por nosotros.

 

Estas soluciones tienen su parte negativa, por un lado los algoritmos seguros no se pueden desencriptar, por lo que no siempre son utiles. Por otro lado los componentes de software desarrollados por compañias pueden llegar a ser muy caros y además es necesario instalarlos en el los servidores, cosa que no siempre es posible.

 

La solución son los sistemas de clave pública-privada. Son sistemas en los que la encriptación se basa en un par de claves, con una clave se encriptan los datos y sólo se pueden desencriptar si se conoce la otra.

 

Nuestra clase esta basada en esta idea. Vamos a desarrollar una clase que escripta cadena basandose en un patrones. La clase está escrita en VB.NET, pero al utilizar unicamente tipos comunes podemos exportarla facimente a cualquier otro lenguaje.

 

Lo primero que vamos a hacer es crear la clase a la que vamos a llamar Encriptador.

 

Public Class Encriptador

End Class

 

La idea de esta clase es definir dos patrones, cada uno con todos los caracteres del idioma, de la A-Z en mayúscula y minuscula, los numeros … y cada uno en un orden diferente y aleatorio. Después aplicaremos un sencillo algoritmo que nos haga correcponder cada elemento de un patrón con otro.

 

Lo primero que necesitamos definir los patrones,para ello tecleamos el abecedario y los números en una cadena de texto como esta:

 

ABCDEFGHIJKLMNÑOPQRSTVWXYZabcdefghijklmnñopqrstvwxyz1234567890

 

Y ahora la desordenamos hasta que quede ilegible. Asignamos estas cadenas a nuestras cadena de patrón. Definimos las cadenas a nivel de instancia.

 

Tambien declaramos dos métodos, uno para encriptar la cadena y otro para encriptar una única letra, que además recibe otros dos parámetros, uno denominado variable, que representa la longitud de la cadena a encriptar y otro a_indice, que representa el índice del caracter dentro de la cadena. Con ellas construiremos un sencillo algoritmo, que evitará que alguien pueda establecer una relación del tipo de “la a es la j encriptada” y que hará que cada letra se encripte de modo diferente dependiendo de la longitud de la cadena y de donde esté situada dentro de ella.

 

Public Class Encriptador

Private patron_busqueda As String = “0ABIZ2ÑebDNOEcwGl6oSñixq1…”
Private Patron_encripta As String = “vQÑO8dk1VgIPZxAR3UsLD6XBz…”
‘Los patrones están aquí sin terminar por falta de espacio.

Public Function EncriptarCadena (ByVal cadena As String) As String

End Function

Private Function EncriptarCaracter (ByVal caracter As String, _
ByVal variable As Integer, _
ByVal a_indice As Integer) As String

End Function

End Class

 

 

Ahora escribimos el código para EncriptarCadena, que sencillamente recorre la cadena letra a letra invocando al método de encriptar caracter, pasandole como parémetros el caracter, la longitud de la cadena y el índice de la iteración. El código es muy sencillo.

 

Public Function EncriptarCadena (ByVal cadena As String) As String

Dim idx As Integer
Dim result As String

For idx = 0 To cadena.Length - 1
result += EncriptarCaracter(cadena.Substring(idx, 1), cadena.Length, idx)
Next
Return result

End Function

 

Ahora tenemos que escribir el método EncriptarCaracter, como hemos visto al declarar el método, recibe tres parámetros, el caracter que queremos encriptar, un entero variable (que será la longitud de la cadena a encriptar) y el indice que ocupa el caracter a encriptar dentro de la cadena que queremos encriptar. Esto nos va a permitir escribir un sencillo algoritmo para devolver el índice que le va a corresponder a nuestro caracter dentro del patron encriptado.

 

Private Function EncriptarCaracter (ByVal caracter As String, _
ByVal variable As Integer, _
ByVal a_indice As Integer) As String

Dim caracterEncriptado As String, indice As Integer

If patron_busqueda.IndexOf(caracter) <> -1 Then
indice = (patron_busqueda.IndexOf(caracter) + variable + a_indice) Mod patron_busqueda.Length
Return Patron_encripta.Substring(indice, 1)
End If

Return caracter

End Function

 

La función busca el índice de mi caracter en la cadena denominada patron_busqueda, si lo encontramos (recordar que tenemos todas las letras y números), lo encriptamos, si no lo encontramos devolvemos el mismo caracter que hemos recibido como parámetro.

 

La encriptación en muy sencilla, ¡pero muy efectiva!, encontramos el lugar que ocupa dentro del patron de busqueda el caracter, le sumamos la longitud de la cadena y le sumamos por último el lugar que ocupa el caracter que estamos encriptando dentro de ella. Obtenemos el caracter correspondiente al índice calculado dentro del patron_encriptado. De este modo conseguimos que el mismo caracter se encripte de forma diferente en cada cadena, y que una pequeña modificación en la cadena cambie totalmente la encriptación.

 

Este algoritmo plantea un problema, ¿que ocurre cuando la suma de estos tres parámetro es superior a la longitud de los patrones?. Estariamos intentando estraer un elemento que supera los límites de las cadenas patrón. Para solucionar este problema trabajamos con módulos matemáticos. La operación módulo devuelve el resto de la división entera entre dos números. De este modo cuando nuestro índice supera los limites de la cadena, volvemos a la posición inicial.

 

Ejemplos con operaciones de modulos

15 Mod 20 ==> devuelve 15

20 Mod 20 ==> devuelve 0

21 Mod 20 ==> devuelve 1

45 Mod 20 ==> devuelve 5

 

Ya tenemos nuestra clase que encripta cadenas, vamos a escribir una pequeña aplicación de consola que pruebe nuestra clase.

 

Module Encriptador_Test

Sub Main()

Dim cadena As String
Dim enc As Encriptador
enc =New Encriptador()
Do
Console.WriteLine(”Introducca la cadena que quiera encriptar:”)
cadena = Console.ReadLine()
Console.WriteLine( ” ==> ” + enc.EncriptarCadena(cadena))
Loop While cadena <> “”

End Sub

End Module

 

Vamos a ejecutar nuestro programa, y probamos a encriptar varias cadenas.

 


C:\VB.net\Encriptar\Encriptar\bin>encriptar.exe

Introducca la cadena que quiera encriptar:
Hola mundo! ==> 9QPz hpKIZ!

Introducca la cadena que quiera encriptar:
www.Devjoker.com ==> feo.Frfxy¥hb.jii

Introducca la cadena que quiera encriptar:
La misma letra varia aaaaaaaa! ==> YB WMb¤I JC¥yH Q¥CgP v7Ky8qj4!

 

Ahora necesitamos escribir lo métodos para desencriptar. Las declaraciones son parecidas.

 

 

Public Function DesEncriptarCadena(ByVal cadena As String) As String

End Function

Private Function DesEncriptarCaracter(ByVal caracter As String, ByVal variable As Integer, _
ByVal a_indice As Integer) As String

End Function

 

 

La implementación de los métodos tambien es sencilla, si bien el método de desencriptar caracter es algo más complicado, debido a la posibilidad de encontrar índices negativos. Aún así resultan faciles de comprender.

 

 

Public Function DesEncriptarCadena(ByVal cadena As String) As String

Dim idx As Integer
Dim result As String

For idx = 0 To cadena.Length - 1
result+=DesEncriptarCaracter(cadena.Substring(idx, 1),cadena.Length,idx)
Next
return result
End Function

Private Function DesEncriptarCaracter(ByVal caracter As String, _
ByVal variable As Integer, _
ByVal a_indice As Integer) As String

Dim indice As Integer

If Patron_encripta.IndexOf(caracter) <> -1 Then
If (Patron_encripta.IndexOf(caracter) - variable - a_indice) > 0 Then
indice = (Patron_encripta.IndexOf(caracter) - variable - a_indice) Mod Patron_encripta.Length
Else
‘La línea está cortada por falta de espacio
indice = (patron_busqueda.Length) + ((Patron_encripta.IndexOf(caracter)
- variable - a_indice) Mod Patron_encripta.Length)
End If
indice = indice Mod Patron_encripta.Length
Return patron_busqueda.Substring(indice, 1)
Else
Return caracter
End If

End Function

 

Con esto ya tenemos escrito todo el código necesario. Como vereis no se trata de un sistema excesivamente seguro, pero para poder desencriptar nuestras cadenas es necesario conocer dos patrones de 64 caracteres, que además han sido generadas de forma aleatoria. Además este código es facilmente portable a cualquier plataforma, dado que se basa completamente en tipos sencillos, cadenas de caracteres, por lo que reescribir el codigo para una clase Java es muy facil.

 

El código necesario para que nuestra aplicación de consola desencripte es trivial, por lo que no lo comentaremos.

 

Bueno, espero que oa haya parecido interesante el articulo, saludos y hasta la proxima.

Progamacion Orientada A Aspectos

Lo ultimo y mas nuevo miren esto, el paradigma de la programacion orientada a los aspectos, vean esto

 

Ver mas y algo mas de info, y mas info, otro documento

Creo que debere cambiar el titulo del blog :P

Refactorizacion

Aqui les dejo un articulo encontrado por ahi, que habla de la refactorizacion, el “rehacer y sin modificar” , espero les siva, bye

Refactorización en la práctica: peligros y soluciones

            Jesús Pérez y Jorge Ferrer

AgileSpain (http://www.agile-spain.com/)

Introducción a la refactorización
La refactorización es uno de los nuevos conceptos que se han introducido en la terminología del mundo del desarrollo apoyado por las metodologías ágiles. Extreme Programming, una de las metodologías ágiles más extendida, la incluye dentro del decálogo de prácticas que propone como fundamentales. Sin embargo la idea de refactorización no es nueva, lo que resulta novedoso es la forma en que se lleva a cabo, una forma ágil y agresiva, pero al tiempo ordenada y segura. Refactorizar es una idea apoyada por una técnica que debemos controlar si queremos llevar a cabo un diseño evolutivo y un desarrollo ágil de nuestra aplicación.

        ¿Qué significa Refactorizar? La mejor definición la obtenemos de uno de los padres de esta técnica, Martin Fowler, que dijo: “Refactorizar es realizar modificaciones en el código con el objetivo de mejorar su estructura interna, sin alterar su comportamiento externo”. De esta definición extraemos ideas muy importantes y conceptos que a veces estaban equivocados. Refactorizar no es una técnica para encontrar y corregir errores en una aplicación, puesto que su objetivo no es alterar su comportamiento externo. De hecho, no modificar el comportamiento externo de la aplicación es uno de los pilares de cualquiera de las prácticas que forman parte de la técnica, para lo que en muchas ocasiones se hace uso de las pruebas unitarias. La esencia de esta técnica consiste en aplicar una serie de pequeños cambios en el código manteniendo su comportamiento. Cada uno de estos cambios debe ser tan pequeño que pueda ser completamente controlado por nosotros sin miedo a equivocarnos. Es el efecto acumulativo de todas estas modificaciones lo que hace de la Refactorización una potente técnica. El objetivo final de Refactorizar es mantener nuestro código sencillo y bien estructurado.
Refactorizar nos propone seguir las técnicas matemáticas que consiguen reducir fórmulas muy complejas en fórmulas equivalentes pero más sencillas. En el entorno matemático estas simplificaciones consiguen eficiencia, además de facilitar el cálculo de problemas libre de errores, muy fáciles de cometer cuando las formulas son muy complejas. No obstante conseguir un código sencillo es una tarea muy compleja

Como dice Carver Mead:
“Es fácil tener una idea complicada. Es muy, muy complicado tener una idea simple.”

¿Por qué debemos Refactorizar nuestro código? Existen muchas razones por las que deberíamos adoptar esta técnica:

           - Calidad. La más importante. Conseguir ser un buen profesional pasa inevitablemente por conseguir que tu trabajo sea de calidad. Refactorizar es un continuo proceso de reflexión sobre nuestro código que permite que aprendamos
de nuestros desarrollos en un entorno en el que no hay mucho tiempo para mirar hacia atrás. Un código de calidad es un código sencillo y bien estructurado, que cualquiera pueda leer y entender sin necesidad de haber estado integrado en el equipo de desarrollo durante varios meses. Se acabaron los tiempos en que lo que imperaba eran esos programas escritos en una sola línea en la que se hacia de todo, tiempos en los que se valoraba la concisión aun a costa de la legibilidad.

           - Eficiencia: Mantener un buen diseño y un código estructurado es sin duda la forma más eficiente de desarrollar. El esfuerzo que invirtamos en evitar la duplicación de código y en simplificar el diseño se verá recompensado cuando tengamos que realizar modificaciones, tanto para corregir errores como para añadir nuevas funcionalidades.

            - Diseño Evolutivo en lugar de Gran Diseño Inicial: En muchas ocasiones los requisitos al principio del proyecto no están suficientemente especificados y debemos abordar el diseño de una forma gradual. Cuando tenemos unos requisitos claros y no cambiantes un buen análisis de los mismos puede originar un diseño y una implementación brillantes, pero cuando los requisitos van cambiando según avanza el proyecto, y se añaden nuevas funcionalidades según se le van ocurriendo a los participantes o clientes, un diseño inicial no es más que lo que eran los requisitos iniciales, algo generalmente anticuado. Refactorizar nos permitirá ir evolucionando el diseño según incluyamos nuevas funcionalidades, lo que implica muchas veces cambios importantes en la arquitectura, añadir cosas y borrar otras.

          - Evitar la Reescritura de código: En la mayoría de los casos Refactorizar es mejor que rescribir. No es fácil enfrentarse a un código que no conocemos y que no sigue los estándares que uno utiliza, pero eso no es una buena excusa para empezar de cero. Sobretodo en un entorno donde el ahorro de costes y la existencia de sistemas lo hacen imposible.

Refactorizar es por tanto un medio para mantener el diseño lo más sencillo posible y de calidad. ¿Qué se entiende por sencillo y de calidad? Kent Beck define una serie de características para lograra un código los mas simple posible:

- El código funciona (el conjunto de pruebas de la funcionalidad de nuestro código pasan correctamente).
- No existe código duplicado.
- El código permite entender el diseño.
- Minimiza el número de clases y de métodos.

A pesar de todo ello, refactorizar parece ser muchas veces una técnica en contra del sentido común. ¿Por qué modificar un código que funciona? (si funciona no lo toques) ¿Por qué correr el riesgo de introducir nuevos errores?, ¿cómo podemos justificar el coste de modificar el código sin desarrollar ninguna nueva funcionalidad?
No siempre es justificable modificar el código, no se reduce a una cuestión estética.

Cada refactorización que realicemos debe estar justificada. Sólo debemos refactorizar cuando identifiquemos código mal estructurado o diseños que supongan un riesgo para la futura evolución de nuestro sistema. Si detectamos que nuestro diseño empieza a ser complicado y difícil de entender, y nos está llevando a un situación donde cada cambio empieza a ser muy costoso. Es en ese momento cuando debemos ser capaces de frenar la inercia de seguir desarrollando porque si no lo hacemos nuestro software se convertirá en algo inmantenible (es imposible o demasiado costoso realizar un cambio).

       Tenemos que estar atentos a estas situaciones donde lo más inteligente es parar, para reorganizar el código. Se trata de dar algunos pasos hacia atrás que nos permitirán tomar carrerilla para seguir avanzando. Los síntomas que nos avisan de que nuestro código tiene problemas se conocen como “Bad Smells”.

¿En qué momento debemos Refactorizar?, ¿es necesario planificar tareas específicas de refactorización?
La Refactorización no es un proceso que podemos aislar como una tarea. Es necesario que lo incluyamos como una actividad que realizaremos cuando estemos desarrollando. No tiene que ser exactamente en el mismo instante en que identifiquemos un “Bad Smell”, ya que como se ha apuntado anteriormente, la funcionalidad no debe verse modificada. Por ello, debemos acabar lo que estemos haciendo (recuerda, pasos pequeños). Una vez finalizado el paso que nos ocupa, es el momento de abarcar la refactorización que debe realizarse de forma natural como parte del mismo desarrollo.

        La adopción de la refactorización como parte de nuestros desarrollos no resulta muchas veces sencilla, puesto que intuitivamente no proporciona la sensación de avanzar en la finalización de nuestro desarrollo. No obstante el tiempo empleado en refactorizaciones se verá muy justificado a la hora de seguir con el diseño, realizar modificaciones o buscar errores en el código para subsanarlos. Como dice el refrán: “Vísteme despacio que tengo prisa”.
¿Cuales son estos “Bad Smells”?, ¿cuáles son los síntomas de que la evolución de nuestro desarrollo se encamina hacia un caos?, ¿cuándo nuestro código empieza oler?. En [Fowler] podemos encontrar una lista de ellas como Código Duplicado, Métodos largos, Clases Largas, Cláusulas Switch, Comentarios, etc.

       Existen herramientas en “Ant” como “checkstyle” que permiten automatizar la identificación de algunos “Bad Smell” (con “checkstyle” es posible fijar el numero máximo de líneas de un método, o el máximo número de parámetros de un método).

        Una vez identificado el “Bad Smell” deberemos aplicar una refactorización que permita corregir ese problema. Para comenzar a Refactorizar es imprescindible que el proyecto tenga pruebas automáticas, tanto unitarias como funcionales, que nos permitan saber en cualquier momento al ejecutarlas, si el desarrollo sigue cumpliendo los requisitos que implementaba. Sin pruebas automáticas, Refactorizar es una actividad que conlleva un alto riesgo. Sin pruebas automáticas nunca estaremos convencidos de no haber introducido nuevos errores en el código al término de una refactorización, y poco a poco dejaremos de hacerlo por miedo a estropear lo que ya funciona. “Refactorizar sin tener un conjunto de pruebas asociado al proyecto debe dejárselo a los profesionales y no intentarlo en su casa”, claro que los profesionales lo primero que harán para Refactorizar será implementar las pruebas automáticas que cubran la funcionalidad que se ve cubierta por el código objetivo de la refactorización.

        ¿Cómo debe aplicarse una refactorización?, ¿cuáles son los pasos a seguir?

        La mejor forma de comprender el proceso es llevar a cabo una refactorización.
Ejemplo de aplicación de una Refactorización, Refactorizar es una práctica, por lo que la mejor forma de entender esta técnica es aplicarla. Lejos de pretender enumerar aquí todos esos patrones, mostraremos uno de ellos a modo de ejemplo: Reemplazar los condicionales con polimorfismo.
Esta refactorización nos convierte el tradicional autómata de estados realizado con “switchs” en algo extensible y orientado a objetos, más fácil de mantener y de arreglar al adoptar el patrón State. Para centrar ideas, supongamos que tenemos que actualizar un control de las puertas del suburbano de alguna ciudad. El problema es que está realizado a la antigua usanza, con un método que se encarga a base de “ifs” (que podemos ver como un caso degenerado de “switches” que funcionaría tanto con cadenas como con otro tipo de objetos) de pasar de un estado a otro:

public class Metro {
private int estado;
static final private int PARADO = 0;
static final private int EN_MARCHA = 1;
static final private int PARANDO = 2;
static final private int ARRANCANDO = 3;
public void cambiaEstado() {
if(estado==PARADO) {
estado = ARRANCANDO;
} else if(estado==EN_MARCHA) {
estado = PARANDO;
} else if(estado==PARANDO) {
estado = PARADO;
} else if(estado==ARRANCANDO) {
estado = EN_MARCHA;
}

        else {
throw new RuntimeException(”Estado desconocido”);
}
}
}

Tras cada paso de los que vamos a dar, ejecutaremos los tests para ver que se pasan convenientemente.
Lo primero que deberíamos hacer sería separar las condiciones en un único método y subir dicho método lo más alto posible en la jerarquía. En nuestro ejemplo no es necesario dado que ya cumple las condiciones pedidas.
A continuación creamos una clase por cada posible estado y sustituimos los “==” por “instanceof” y las variables estáticas enteras por referencias a instancias de esas clases.
Obviamente, necesitaremos una interfaz base para nuestras clases de estado que por ahora será un simple marcador.

Public interface Estado {}
public class Parado implements Estado {}
etc…
public class Metro {
private Estado estado;
static final private Estado PARADO = new Parado();
static final private Estado EN_MARCHA = new EnMarcha();
static final private Estado PARANDO = new Parando();
static final private Estado ARRANCANDO = new Arrancando();
public void cambiaEstado() {
if(estado instanceof Parado) {
estado = ARRANCANDO;
} else if(estado instanceof EnMarcha) {
estado = PARANDO;
} else if(estado instanceof Parando) {
estado = PARADO;
} else if(estado instanceof Arrancando) {
estado = EN_MARCHA;
} else {
throw new RuntimeException(”Estado desconocido”);
}
}
}

Nuestro siguiente y penúltimo paso será proveer de control a las clases nuevas para que sean ellas las que decidan el paso de un estado a otro. Implementando el patrón Estado (las diferencias entre éste y el Estrategia son de interpretación), asignaremos un método a la interfaz creada que nos devuelva el siguiente estado, y daremos contenido a dicho método en las clases de estado:

public interface Estado {
public Estado siguiente();
}

public class Parado implements Estado {
// Por eficiencia, implementamos ya el patrón singleton
private static final Parado instance=new Parado();
public static Parado getInstance() { return instance; }
private Parado() {}
public Estado siguiente() {
return Arrancando.getInstance();
}
}
etc…
public class Metro {
private Estado estado;
public void cambiaEstado() {
if(estado instanceof Parado) {
estado = estado.siguiente();
} else if(estado instanceof EnMarcha) {
estado = estado.siguiente();
} else if(estado instanceof Parando) {
estado = PARADO;
} else if(estado instanceof Arrancando) {
estado = estado.siguiente();
} else {
throw new RuntimeException(”Estado desconocido”);
}
}
}
Por fin tenemos nuestro código casi refactorizado. Ahora nos falta eliminar los “ifs” inútiles y hacer desaparecer el “throw” que no se va a dar nunca si hemos implementado bien los distintos estados:
public class Metro {
private Estado estado;
public void cambiaEstado() {
estado = estado.siguiente();
}
}
La refactorización ya ha terminado. Por la simplicidad del código que requiere un ejemplo escrito sería discutible si esta refactorización era necesaria. Pero en la práctica es muy habitual encontrar máquinas de estados más complejas codificadas en forma de switches muy difíciles de mantener. Esta refactorización demuestra cómo es posible organizar ese código paso a paso y con poco riesgo.
Implantación de la refactorización
Además de conocer los aspectos teóricos de la refactorización, también es importante profundizar sobre los aspectos más prácticos de la aplicación de esta técnica en un proyecto de desarrollo real.
En el caso de comenzar un proyecto desde cero, la refactorización continua es una práctica que conlleva un gran número de beneficios y evita de forma natural algunos peligros mencionados. Sin embargo, no siempre se parte de cero, y lo habitual es encontrarnos con código cuyo diseño y/o estructura está lejos de ser los más apropiados. Esta situación puede darse cuando tenemos que ampliar la funcionalidad de código previamente existente o simplemente porque en un proyecto empezado desde cero no se detectó la necesidad de refactorizar a tiempo.. En estos casos nos encontramos con una
refactorización a posteriori y deben tomarse medidas específicas para que afecte lo menos posible al ritmo normal de desarrollo.
Pasos para implantar la refactorización en un equipo
Implantar la refactorización debe realizarse de una manera progresiva. Nuestra experiencia en la implantación de esta técnica nos dice que es necesario seguir los siguientes pasos:
* Escribir pruebas unitarias y funcionales. Refactorizar sin pruebas unitarias y funcionales resulta demasiado costoso y de mucho riesgo.
* Usar herramientas especializadas (más información en [PerezFerrerColado60]). Las refactorizaciones en muchas ocasiones obligan a pequeñas modificaciones muy simples en muchas clases de nuestro código. Con herramientas especializadas estas refactorizaciones se realizan automáticamente y sin riesgo.
* Dar formación sobre patrones de refactorización y de diseño. Una buena base teórica sobre las refactorizaciones más comunes permite al programador detectar “Bad Smells” de los que no es consciente y que harán que su código se degrade progresivamente.
* Refactorizar los principales fallos de diseño. Nuestra recomendación es comenzar realizando refactorizaciones concretas que corrijan los principales fallos de diseño, como puede ser código duplicado, clases largas, etc que son refactorizaciones sencillas de realizar y de las que se obtiene un gran beneficio.
* Comenzar a refactorizar el código tras añadir cada nueva funcionalidad en grupo. Una vez corregido los errores del código existente, la mejor manera de aplicar Refactorirzacion suele ser al añadir una nueva funcionalidad, de manera que se desarrolle de la manera mas eficiente. Realizar discusiones en grupos sobre la conveniencia de realizar alguna refactorización suele ser muy productivo.
* Implantar refactorización contínua al completo. Esta es la última fase y es cuando cada desarrollador incorpora la Refactorizacion como una tarea mas dentro del su proceso de desarrollo de Software.
Refactorización continua
Refactorizar de forma continuada es una práctica que consiste en mantener el diseño siempre correcto, refactorizando siempre que sea posible, después de añadir cada nueva funcionalidad. Esta no es una práctica nueva pero esta adquiriendo mayor relevancia de mano de las metodologías ágiles..
Dado que una refactorización supone un cambio en la estructura del código sin cambiar la funcionalidad, cuanto mayor sea el cambio en la estructura más difícil será garantizar que no ha cambiado la funcionalidad. Dicho de otra forma, cuanto mayor sea la refactorización, mayor es el número de elementos implicados y mayor es el riesgo de que el sistema deje de funcionar. El tiempo necesario para llevarla a cabo también aumenta y por tanto el coste se multiplica.
Cuando un diseño no es óptimo y necesita ser refactorizado, cada nueva funcionalidad contribuye a empeorar el diseño un poco más. Por ello cuanto más tiempo esperamos mayor es la refactorización necesaria.
Esta es la mayor de las justificaciones de una refactorización contínua, que trata de evitar las refactorizaciones grandes haciendo refactorizaciones pequeñas muy a menudo.
En concreto se refactoriza de forma inmediata a la inclusión de una nueva funcionalidad. Esta práctica tiene dos ventajas principalmente:
•El código afectado es el mismo que el que se modificó para añadir la funcionalidad y por tanto se reduce o evita completamente los inconvenientes para otros desarrolladores.
•El tiempo que se debe dedicar es reducido dado que en ese momento se tiene un conocimiento preciso del código que se verá afectado.
Las claves para poder aplicar refactorización contínua son:
•Concienciación de todo el equipo de desarrollo.
•Habilidad o conocimientos necesarios para identificar qué refactorizaciones son necesarias.
•Compartir con todo el equipo de desarrollo la visión de una arquitectura global que guíe las refactorizaciones en una misma dirección.
Lo más habitual es que este tipo de refactorizaciones surjan nada más implementar una funcionalidad y dejar los tests pasando satisfactoriamente. Estos mismos tests nos garantizarán que el código sigue funcionando después de la refactorización.
Sin embargo no siempre resulta evidente para todos los desarrolladores la necesidad de una refactorización. En estos casos el uso de herramientas como javastyle y jcsc pueden emplearse como ayuda para identificar bad smells además de unificar criterios entre todo el equipo. En cualquier caso es importante que estas herramientas no sustituyan nunca al sentido común y se usen únicamente como ayuda.
La refactorización continua también es una muy buena estrategia para evitar la proliferación de ventanas rotas. Este término, presentado por Dave Thomas y Andrew Hunt en The Pragmatic Programmer, representa todo aquel aspecto del código que un desarrollador percibe como negativo. Según Thomas y Hunt un desarrollador no tiene muchos escrúpulos en dejar una ventana rota más, en un código en el que él percibe o es consciente de muchas otras ventanas rotas. Sin embargo cuando el código no tiene ninguna, ningún desarrollador quiere ser el primero en romper una ventana.
El principal riesgo de la refactorización continua consiste en adoptar posturas excesivamente exigentes o criterios excesivamente personales respecto a la calidad del código. Cuando esto ocurre se acaba dedicando más tiempo a refactorizar que a desarrollar. La propia presión para añadir nuevas funcionalidades a la mayor velocidad posible que impone el mercado es suficiente en ocasiones para prevenir esta situación.
Si se mantiene bajo unos criterios razonables y se realiza de forma continuada la refactorización debe tender a ocupar una parte pequeña en relación al tiempo dedicado a las nuevas funcionalidades.
El desarrollo dirigido por pruebas incluye de forma natural la refactorización continua, es lo que se conoce como TDD (Test Driven Development), práctica en la que se se hace la prueba, se añade la funcionalidad necesaria para satisfacerla, se generaliza la prueba y se refactoriza. La consecuencia inmediata de la aplicación de está práctica suele ser la evolución de la arquitectura inicial, en beneficio de un código bien estructurado, de una arquitectura orientada en todo momento a la funcionalidad implementada y por tanto, clara y sencilla, características necesarias para que un código sea mantinible y extensible.
Dificultades de la refactorización en la práctica
Si para afirmar que sabemos refactorizar basta con conocer los principales patrones y seguir una serie de sencillos pasos, para refactorizar con éxito es necesario tener en cuenta otros muchos factores propios de los proyectos de desarrollo reales.
En un proyecto real hay que ser consciente de que no refactorizar a tiempo un diseño degradado puede tener consecuencias muy negativas, pero a la vez debe tener en cuenta que el tiempo dedicado a refactorizar no suele ser considerado como un avance del proyecto, por los usuarios, clientes o gestores del mismo. Otros factores clave para una correcta aplicación de la refactorización son la forma en que afecta a otros miembros del equipo, el hecho de que un desarrollador realice refactorizaciones sobre código en el que todos están trabajando, el que una refactorización provoque que el código esté mucho tiempo sin funcionar o el efecto negativo de no refactorizar, en el ánimo de los desarrolladores por la sensación de no estar haciendo un trabajo de calidad.
Pero antes de tratar estos temas y cómo base para entender sus verdaderas implicaciones comenzaremos por tratar un factor raramente considerado en los libros o artículos sobre refactorización: el factor humano. Es decir, cómo afecta al desarrollador o equipo de desarrollo el refactorizar poco o demasiado, el hacerlo pronto o tarde, etc.
El factor humano
Una realidad a veces olvidada es que cualquier desarrollador prefiere hacer código de calidad. También es cierto que esta realidad a veces queda oculta debido a condiciones de presión excesiva o menosprecio del trabajo técnico.
En este sentido refactorizar es una forma de mejorar la calidad y por tanto es una forma de hacer que el desarrollador esté más orgulloso de su trabajo. Puede decirse que la refactorización bien realizada, rápida y segura, genera satisfacción.
Pero también hay un peligro en este hecho: el exceso de celo para conseguir un resultado de calidad puede llegar a suponer un número excesivo de refactorizaciones dando vueltas sobre diseños similares una y otra vez.
Una posible solución consiste en mantener la refactorización bajo control, definir claramente los objetivos antes de comenzar a refactorizar y estimar su duración. Si se excede el tiempo planificado es necesario un replanteamiento. Quizá haya ocurrido que la refactorización era más complicada de lo esperado pero también es posible que se esté refactorizando más de lo necesario.
Además de la evidente pérdida de tiempo, refactorizar demasiado suele llevar a dos efectos negativos. El primero es que la modificacion del codigo incremente la complejidad de nuestro diseño, que es justo el efecto contrario del que intentabamos lograr al refactorizar. Por otro, es habitual fomentar la sensación bien del desarrollador o bien de todo el equipo de que no se está avanzando. Una sensación que conduce a repercusiones anímicas negativas.
Trabajo en equipo
Un equipo de desarrollo debe ser uno. Todos los miembros del equipo deben conocer la arquitectura en cada momento, el estado actual, los problemas que tenemos y el objetivo que se busca. Una reunión diaria es una práctica que facilita la comunicación entre
todos los miembros del equipo, y supone una práctica que proporciona un momento a todos los miembros del grupo para plantear sus ideas, dudas e inquietudes respecto al proyecto.
Cuando un desarrollador refactoriza, afecta al resto del equipo. En este sentido, las refactorizaciones internas a una clase son menos problemáticas, pero con las arquitecturales es necesario tener mucho cuidado. Este tipo de refactorizaciones supone cambios en un gran número de ficheros y por tanto es probable que se afecte a archivos que están siendo modificados por otros desarrolladores. La comunicación y coordinación entre los afectados es fundamental para que esto no se convierta en un problema. Por tanto es necesario que en la reunión diaria del equipo (u otro mecanismo de comunicación equivalente) se planteen las refactorizaciones de este tipo. De esta forma se sabrá en todo momento quienes son los afectados y cual es el objetivo de la refactorización. De esta forma se promueve la colaboración de todos en la refactorización arquitectural que se va a llevar a cabo. A veces, el comentar con el resto del equipo una refactorización que parece muy necesaria, puede hacernos ver que lo que parecía una muy buena idea, no lo es tanto por otros factores que ven otros compañeros y de los que no eramos conscientes. Esto evita también refactorizaciones en sentidos contrarios propias de equipos en los que falta comunicación.
Las refactorizaciones en sentidos contrarios suelen estar motivadas por tener cada miembro del equipo una idea diferente del diseño hacia el que debe dirigirse ese código. Este problema de comunicación puede tener repercusiones bastante negativas en el diseño resultante. Una vez ocurre debe volverse a una situación en la que todo el equipo comparta una misma visión de la arquitectura y diseño del sistema. Para ello la mejor manera es parar el desarrollo y reunir al todo equipo para alcanzar un acuerdo común. En estas reuniones es muy útil el uso de pizarras y diagramas UML si son conocidos por el equipo. Incluso los miembros del equipo que no se habían visto involucrados en la situación aprenderán de la experiencia para evitar que vuelvan a darse en el futuro.
Una vez extraidas conclusiones, es posible que sea necesario realizar una refactorización más para devolver el código y el diseño a parámetros acordes con nuestros requisitos de calidad.
Refactorización a posteriori
En este apartado nos referimos con el término refactorización a posteriori a todas aquellos cambios estructurales que se realizan un tiempo después de la implementación de la funcionalidad existente. Existen varios motivos para encontrarse con esta situación. Algunos de ellos son:
•Un equipo comienza a trabajar con código desarrollado por un equipo anterior que o bien no tiene buena calidad o bien no está preparado para que se incorporen nuevas funcionalidades.
•Se ha aplicado refactorización continua pero la calidad del código o el diseño se ha degradado porque no se identificó a tiempo la necesidad de una refactorización o bien se equivocó la refactorización necesaria.
Este tipo de refactorizaciones tiene un riesgo mucho mayor que los que nos encontramos con refactorización continua.
Otra característica de estas refactorizaciones es que afectan no sólo al desarrollador o desarrolladores que van a aplicar la refactorización, sino a todos aquellos que trabajan con la parte del código afectada: por un lado no pueden trabajar con el código o deben
hacerlo con mayor precaución durante un tiempo; y por otro cuando vuelvan a trabajar con él se encontrarán con un diseño desconocido.
La mejor estrategia a seguir en estos casos es tratar de dividir la refactorización en el mayor número de pequeños pasos posible. Tras cada paso el código debe seguir funcionando sin fallos.
Antes de abordar cada uno de estos pasos se debe comunicar a todas las personas afectadas por los cambios que se van a realizar. De esta forma se evita que cuando vuelvan a trabajar con ese código se encuentren con un panorama completamente desconocido. En ocasiones también es recomendable dar explicaciones después de la refactorización para explicar el diseño final. Si este tipo de explicaciones son necesarias con demasiada asiduidad, la solución no es no realizarlas sino identificar los motivos de tanta refactorización a posteriori. Probablemente sea necesario un mayor grado de refactorización continua.
La refactorización por pasos tiene la ventaja de afectar menos al ritmo normal de desarrollo y permite ser intercalada con la implementación de nuevas funcionalidades. El principal inconveniente es que extiende en el tiempo la existencia de código imperfecto. Por ello siempre que sea posible debe completarse la refactorización en el menor tiempo posible.
Cuando una refactorización es difícil técnicamente y lleva un tiempo considerable se corre el riesgo de entrar en lo que podríamos denominar la espiral refactorizadora. Esta situación ocurre cuando una refactorización se complica y conduce a nuevas refactorizaciones hasta que llega un momento en el que no es posible o es muy difícil estimar cuanto tiempo queda para terminar de refactorizar.
Toda situación durante un desarrollo de software en la que no puede estimarse la finalización debe evitarse. En este caso la situación se ve agravada porque se frena la adición de nueva funcionalidad en el código que está siendo refactorizado durante un tiempo indeterminado.
Hay varias medidas que pueden adoptarse para evitar caer en la espeial refactorizadora. La primera de ellas es declarar el objetivo de una refactorización antes de empezar. Si durante la misma aparece nuevo código susceptible de ser refactorizado debe dejarse sin modificar, por ahora sólo apuntaremos esta necesidad para no olvidarnos de hacer la refactorización más adelante. Cuando se considere más oportuno.
Otra práctica muy útil consiste en introducir el código en el sistema de control de versiones antes de emprender cualquier refactorización que podamos considerar grande.
Si cuando se está llevando a cabo una refactorización se dispersan los objetivos iniciales, se llevan muchas horas o incluso días sin tener un código que funciona o resulta imposible estimar cuanto queda para terminar es necesario asumir que la refactorización no va por buen camino. Para volver a la normalidad se debe devolver el código a un estado en el funcionara correctamente. Esto resulta muy fácil si se siguió el consejo anterior de comenzar con código guardado en el sistema de control de versiones. No deben tenerse reparos en tirar las modificaciones empezadas, estaremos cambiando un poco de tiempo de trabajo por recuperar una situación estable que nos permite seguir avanzando sin incertidumbres. Lo más importante será lo aprendido de la refactorización fallida, que nos será muy valioso para volver a intentarlo.
La mejor forma de enfocar correctamente una refactorización y evitar caer en espirales
de refactorizaciones, es conocer muy bien los patrones de diseño. Los patrones de diseño no son sino soluciones que funcionan para problemas comunes que todos encontramos cuando estamos desarrollando. Conocer perfectamente los patrones de diseño nos permite identificar y ver con claridad el objetivo de la refactorización, mejora la comunicación entre los miembros del grupo al compartir una base de conocimiento muy importante y además nos hace más eficientes en la resolución no sólo de problemas conocidos, sino también de problemas desconocidos al haber adquirido una forma mejor arquitecturada de enfocar los problemas.
Refactorización y pruebas unitarias
La existencia de pruebas automatizadas facilita enormemente las refactorizaciones. Los principales motivos son:
•El riesgo de la refactorización disminuye, dado que es posible comprobar cuando esta concluye que todo sigue funcionando satisfactoriamente.
•El desarrollador que realiza la refactorización puede comprobar que no ha estropeado la funcionalidad implementada por otros. Evita efectos colaterales.
•El tiempo necesario para comprobar que todo sigue funcionando es menor lo que permite avanzar en pasos más pequeños si se desea.
•Refactorizar sin tests es una actividad de alto riesgo y no debe hacerse salvo para las refactorizaciones más sencillas y realizadas con herramientas especializadas. En ocasiones incluso algunas refactorizaciones muy pequeñas pueden provocar la aparición de bugs muy difíciles de identificar a posteriori.
Sin embargo las pruebas también pueden llegar a ser un estorbo a la refactorización si se emplean de forma inadecuada.
En este sentido es muy importante resaltar la importancia de que las pruebas tanto funcionales como unitarias comprueben que el código bajo prueba funcione correctamente independientemente de cómo esté implementado. Cuanto mayor sea el acoplamiento de la prueba con la implementación, mayores serán los cambios que habrá que realizar en esta cuando se lleve a cabo.
Pero incluso aunque no exista este acoplamiento las refactorizaciones grandes, que afectan al diseño del código significativamente, obligarán a realizar cambios en las pruebas. Esto provoca una situación incómoda, las pruebas que deben ser una ayuda se convierten en este caso en un estorbo a la refactorización. La mejor solución es prevenir aplicando refactorizaciones continuas y más pequeñas. Pero una vez nos encontramos con esta situación, es recomendable cambiar las pruebas antes o a la vez que el código. De esta forma las pruebas colaborarán guiando la refactorización.
En este sentido también resulta útil pensar antes de refactorizar en cómo van a afectar a los tests y cómo podemos usarlos en nuestro beneficio en vez de dejar que se conviertan en un problema.

Conclusiones
El problema de abordar una refactorización es que supone un esfuerzo que no se ve compensado por ninguna nueva funcionalidad y por ese motivo muchas veces es complicado de justificar. Sin embargo si introducimos la refactorización como parte del desarrollo conseguiremos que nuestro código sea de calidad y la experiencia dice que
este tiempo que vamos empleando a lo largo del desarrollo será recuperado con creces según el proyecto avance.
Se puede afirmar que refactorizar nos facilita enormemente el mantenimiento de un código siempre correctamente estructurado. El hecho de que el código esté bien estructurado es una ventaja por su mantenibilidad y extensibilidad. Sin embargo, esta técnica que parece tan ventajosa, requiere de su aplicación continua, el empleo de pruebas que proporcionen seguridad a su aplicación un buen conocimiento de los patrones de diseño que van a permitir al desarrollador saber hacia donde camina y por último importantes dosis de comunicación con todos los miembros del equipo.

Referencias
[Fowler] Martin Fowler: Refactoring: Improving the Design of Existing Code. Addison-Wesley Co.[1999] http://www.refactoring.com
[Wiki] Páginas Wiki sobre Refactorización
http://c2.com/ppr/wiki/WikiPagesAboutRefactoring
[IntelliJ] Uno de los mejores Entorno de Desarrollo Java para Refactorizar
http://www.intellij.com
[Refactoring] Página de Refactorización en Español.
http://refactoring.blog-city.com
[PerezFerrerColado58] Jesús Pérez, Jorge Ferrer, César Colado. “Introducción a la refactorización”, Mundo Linux nº 58. Revistas Profesionales.
[PerezFerrerColado60] Jesús Pérez, Jorge Ferrer, César Colado. “Refactorización en la práctica”, Mundo Linux nº 60 (pendiente de publicación). Revistas Profesionales.