Configurando Javadoc en Eclipse 2018-09 y Ubuntu 18.04 con OpenJDK 11

Si instalaste el paquete default-jdk en Ubuntu 18.04, por estas fechas (septiembre 2018) obtendrás el paquete openjdk-11-jdk. Es un poco confuso porque hasta septiembre de 2018 lo que en realidad instala es Java 10:

Captura de pantalla de 2018-09-22 18-32-27Sólo después de septiembre de 2018 se va a instalar Java 11 con el paquete openjdk-11-jdk.

También podrás comprobar que en Eclipse no está funcionando el Javadoc al hacer hover sobre las clases. Para solucionar el problema vamos a Window -> Preferences -> Java -> Installed JREs y seleccionamos el JDK “11”:

Captura de pantalla de 2018-09-22 18-48-29

Hacemos click en Edit, abrimos los detalles y seleccionamos Javadoc location:

Captura de pantalla de 2018-09-22 18-50-51

La URL es http://docs.oracle.com/javase/10/docs/api/. Asegúrate de usar http, no https. Puedes usar el botón Validate para comprobar la URL:

Captura de pantalla de 2018-09-22 18-53-22

También podemos configurar las sources para poder verlas desde Eclipse. Primero hay que instalar el paquete:

sudo apt install openjdk-11-source

Luego seleccionamos Source attachment en la ventana Edit JRE e ingresamos el path de las fuentes:

/usr/lib/jvm/openjdk-11/lib/src.zip

Captura de pantalla de 2018-09-22 19-25-54

Captura de pantalla de 2018-09-22 19-27-51

Captura de pantalla de 2018-09-22 19-38-24

De esta forma tenemos todo configurado y cuando hagamos hover vamos a ver el Javadoc y con F3 u Open Declaration las fuentes de la class library.

 

Instalando un entorno de programación C en Windows con Mingw-w64 y Visual Studio Code

Windows no es un sistema operativo que cuenta con un buen soporte para la programación en C. Por razones que no quedan del todo claras, Microsoft se ha negado rotundamente a actualizar el soporte del compilador C de Visual Studio, el cual ha quedado estancado en el estándar C89.

Afortunadamente la comunidad Open Source viene al rescate con el proyecto Mingw-w64, que provee el compilador GCC, el debugger GDB, binutils, más las headers y bibliotecas necesarias para producir binarios nativos de Windows. Mingw-w64 es ampliamente utilizado y actualizado constantemente con las últimas versiones de GCC y tecnologías como OpenGL y DirectX.

Hay varias formas de obtener Mingw-w64, pero una de las mejores es usando MSYS2 (Minimal SYStem 2), una línea de comandos y entorno de programación que usaremos para instalar Mingw-w64.

1. Instalando MSYS2

Para comenzar, vamos a msys2.github.io y descargamos el instalador de 64 bits (el que dice “x86_64”) que nos permitirá compilar programas nativos de 32 y 64 bits. Abrimos el archivo y lo instalamos con todas las opciones por defecto. Si al final dejamos tildada la opción “Run MSYS2 now“, vamos a ver la consola de MSYS2 MSYS que luce de esta manera:

msys2-console

MSYS2 usa el gestor de paquetes pacman de Arch Linux para instalar y actualizar el paquetes. Hay que seguir las instrucciones en la página de MSYS2 para actualizar el entorno. Al momento de escribir este artículo (MSYS2 versión msys2-x86_64-20160921) hay que ingresar en la consola (atento a las mayúsculas):

Puede que en alguno de los siguientes pasos aparezca un mensaje pidiendo cerrar la consola. En ese caso debemos cerrar la ventana por la equis y volver a abrirla desde el menú inicio, buscando MSYS2 MSYS.

pacman -Sy pacman
pacman -Syu
pacman -Su

MSYS2 se instala por defecto en el directorio c:\msys64. En el menú inicio de Windows podremos ver que en la carpeta MSYS2 64bit aparecen 3 consolas, lo cual se presta a cierta confusión. Las tres abren una consola bash pero con diferentes variables de entorno establecidas para diferentes usos:

  • MSYS2 MSYS: es la consola de MSYS que utilizaremos para correr pacman e instalar paquetes. Se puede compilar programas aquí pero los mismos dependerán de msys-2.0.dll, una capa de emulación POSIX. Basta decir que no utilizaremos ésta para compilar.
  • MSYS2 MinGW 32bit: provee un entorno de programación para compilar programas nativos de Windows de 32 bits que dependen de MSVC runtime.
  • MSYS2 MinGW 64bit: éste es el entorno de programación que usaremos para compilar programas nativos de Windows de 64 bits.

2. Instalando Mingw-w64

Ahora sí instalaremos Mingw-w64. MSYS2 sólo provee la consola bash y otras herramientas auxiliares, para obtener el compilador debemos instalar Mingw-w64.

Al momento de escribir este artículo había un bug en MSYS2 (versión msys2-x86_64-20160921, corregido en versiones posteriores) por lo tanto debemos ir al directorio C:\msys64 y crear dentro un directorio llamado “mingw64“.

Para descargar e instalar el paquete, abrimos la consola de MSYS2 MSYS e ingresamos:

pacman -S mingw-w64-x86_64-toolchain

Con esto hemos instalado dentro de MSYS2 la “toolchain” necesaria para compilar programas, que incluye binutils, make, pkg-config, y el compilador gcc.

Podemos cerrar la ventana de MSYS2 MSYS, ir al menú inicio y abrir la consola MSYS2 MinGW 64-bit (no MSYS2 MSYS). Si todo salió bien, al ingresar “gcc -v” veremos la versión del compilador:

gcc-version

Finalmente agregamos la ruta de MinGW al path de Windows. Para ello abrimos una consola de línea de comandos (Menú inicio -> cmd) e ingresamos setx path “%path%;C:\msys64\mingw64\bin”:

path

3. Instalando y configurando Visual Studio Code

Una vez instalado el paquete mingw-w64-x86_64-toolchain, es perfectamente posible compilar programas desde la consola de MSYS MinGW 64-bit, usando la interfaz de línea de comandos para invocar comandos como cc y make.

Sin embargo, si queremos un entorno mucho más amigable, podemos usar Visual Studio Code, el IDE de Microsoft que se presenta como la alternativa ligera y open source a Visual Studio.

Debemos ir a code.visualstudio.com, descargar el instalador y seguir las sencillas instrucciones. Luego debemos crear un directorio en nuestro disco que utilizaremos para el primer proyecto en C. A diferencia de Visual Studio, Visual Studio Code se basa en directorios y no en proyectos, por lo que debemos ir al menú Archivo -> Abrir carpeta y seleccionar el directorio vacío que creamos.

A continuación abrimos la Paleta de comandos (Ctrl + Shift + P), escribimos Extensiones: Instalar Extensiones y presionamos Enter. Esto nos abre el Panel de extensiones en el cual vamos a buscar cpptools, la extensión de Microsoft que agrega soporte para C y C++. Debemos instalarla (haciendo click en Instalar) y habilitarla (haciendo click en Recargar).

En el Explorador de archivos a la izquierda, creamos un archivo llamado hello.c en el cual ingresaremos el código del clásico Hello World:

vs-code1

Guardamos el archivo (Ctrl + S), hacemos click para poner un breakpoint en la línea 6, y luego situando el cursor en la línea 1, que aparece subrayada en verde, vemos que aparece un foco amarillo al cual haremos click para configurar el include path. Esto crea en nuestro directorio un archivo c_cpp_properties.json que indica a la extensión cpptools dónde están los headers de C. Debemos editar la sección Win32 de dicho archivo y cambiar el valor del includePath al directorio C:/msys64/mingw64/include (ingresar tal cual) Guardamos el archivo (Ctrl + S).

c_cpp_properties

Para configurar la compilación del proyecto abrimos la Paleta de comandos (Ctrl + Shift + P) y buscamos Tareas: Configurar ejecutor de tareas, seleccionando la opción Otros. Esto crea un archivo tasks.json que editaremos de la siguiente manera:

tasks

Guardamos el archivo (Ctrl + S). Lo que hemos hecho aquí es decirle a Visual Studio Code dónde encontrar el compilador cc que instalamos previamente en MSYS2. Los parámetros indican agregar símbolos de depuración para gdb, el nombre de nuestro archivo de fuente y el nombre del archivo de salida.

Para compilar presionamos Ctrl + Shift + B, si todo salió bien veremos que nuestro ejecutable hello.exe aparece en el explorador de archivos. Sino aparecerá un mensaje de error en el panel Salida y debemos verificar si configuramos bien la ruta y los parámetros.

Finalmente ejecutaremos nuestro programa usando dbg, el clásico debugger de GNU. Debemos abrir la barra lateral de depuración (Ctrl + Shift + D o haciendo click en el insecto), luego hacer click en el icono de la rueda para configurar, y seleccionar la opción C++ (GDB/LLDB). Esto crea un archivo launch.json que editaremos para indicar las rutas de nuestro ejecutable y del debugger. En la configuración C++ Launch hay que editar la propiedad program y agregar la propiedad miDebuggerPath con la ruta de gdb, como se muetra a continuación:

launch

Guardamos el archivo (Ctrl + S), y presionamos F5 o hacemos click en la flecha verde para ejecutar. Si todo salió bien, debe aparecer la consola de nuestro programa y veremos que Code se detiene en el breakpoint que establecimos anteriormente. La barra lateral muestra las variables locales, una sección de inspección y la pila de llamadas. Abajo aparece la consola de depuración que permite enviar comandos a gdb, y arriba está la barra para controlar la ejecución, con los mismos atajos de teclado que Visual Studio:

vs-code2

Como vemos, Visual Studio Code es un entorno muy agradable de usar y bastante completo, ya que a pesar de ser nuevo (apareció en 2015) se ha desarrollado con bastante rapidez. Perfecto para aprender y dar los primeros pasos programando en C bajo Windows.

Próximos pasos

Hemos configurado Visual Studio Code para compilar, ejecutar y depurar de forma visual y sencilla un programa con un sólo archivo fuente, usando directamente el compilador cc. El próximo paso que podrías seguir es editar el archivo tasks.json para usar make en vez de cc y poder compilar programas más complejos (en MinGW el ejecutable se llama mingw32-make.exe). ¿Puedes descubrir cómo?

El rol del idioma inglés

¿Se puede ser un buen programador sin hablar inglés?

Es una pregunta interesante. Supongo que sí, pero en mi experiencia personal el no saber inglés hubiera resultado una desventaja importante.

El hecho es que el inglés, por distintas razones, es el idioma universal de las ciencias y los negocios, como en un momento lo fue el francés. El inglés te abre las puertas a un mundo de 1500 millones de hablantes que producen las innovaciones científicas y tecnológicas más importantes.

Las últimas investigaciones, estándares, documentaciones y libros se publican en su mayoría absoluta en inglés, y lamentablemente muchos nunca son traducidos. Si quieres participar en un equipo de trabajo internacional, en un proyecto open source, un foro o una lista de correos, el inglés también es un requisito fundamental.

La dificultad del inglés

¿Es dificil aprender inglés? Yo diría que sí, porque al ser un lenguaje germánico tiene muchas diferencias con el español en su sintaxis, semántica, estructura de la oración, conjugación de los verbos… Aprender inglés es aprender otra forma de pensar.

Ni hablar del “slang“, esas expresiones propias de cada idioma y cada región que no tienen una traducción literal, como hanging out – ¿¿colgando afuera?? No, pasando el rato –. Sólo se pueden ir aprendiendo con el tiempo y la práctica

Tal vez lo más complicado del inglés es la pronunciacion. A diferencia del español, el inglés no tiene una pronunciación fija, sino que el sonido de una letra cambia dependiendo de las letras que la preceden y la siguen, así que no queda más remedio que ir aprendiendo de memoria las cientos de combinaciones posibles. Para complicar más las cosas, la pronunciación varía mucho entre el inglés americano y el británico, e incluso entre distintas regiones de un mismo país.

Por otro lado, hay cosas que son más fáciles que el español. Por ejemplo, no existe la tilde, así que no tienes que preocuparte por escribir bien los acentos. Y la mayoría de las palabras son de género neutro (the house, the sun, the sea, the city), otra cosa menos que memorizar.

Recursos para aprender

Por suerte son muchos los recursos que hay para aprender. Lo mejor son los cursos presenciales. Una parte importante de mi aprendizaje fueron los cursos que recibí como parte de mi educación secundaria y universitaria. El gobierno de la ciudad de Buenos Aires ofrece cursos gratuitos de idiomas en el programa Lenguas en los Barrios, y hay infinidad de academias de idiomas, muchas dedicadas exclusivamente al inglés.

También hay muchos cursos online gratuitos que puedes conseguir con cualquier buscador y son muy buenos. La desventaja es que no tienes un profesor que te guíe y corrija en cosas como la pronunciación, y además requieren mucha disciplina para seguir el curso hasta el final.

Otra opción muy buena son las aplicaciones como Duolingo, el cual recomiendo altamente, ya que es excelente para aprender la pronunciación y memorizar las palabras. Duolingo está disponible para iPhone, Android, Windows Phone, y además la página web tiene funciones extra como explicaciones y tablas de conjugación que no están presentes en la aplicación móvil.

Todo complementado siempre por la práctica constante. La lectura, la música y la televisión ayudan muchísimo a la memoria, por lo que es imprescindible incorporarlas a un aprendizaje integral.

Conceptos básicos de criptografía: cifrado simétrico

Hace ya bastante tiempo, por la década de los 1990, la web apenas comenzaba y solía suceder que un programa podía tener una vida feliz sin tener ninguna función de criptografía.

Pero hoy cualquier programa medianamente complejo necesita en algún momento comenzar a utilizar el cifrado para proteger los datos del usuario en su almacenamiento o transmisión en la red, sin embargo es un tópico que sigue siendo confuso para muchos programadores cuando lo enfrentan por primera vez.

Cifrado César

Un algoritmo de cifrado simétrico usa la misma clave para cifrar y descifrar los datos. Uno de los primeros algoritmos conocidos fue el Cifrado César, llamado así porque fue usado por el mismísimo Julio César hace más de dos mil años en comunicaciones militares. Para ello, sustituía cada letra del alfabeto con la letra tres lugares más adelante. Al llegar a la Z, volvía a comenzar por la letra A, igual que las agujas de un reloj, en lo que se llama aritmética modular. Un ejemplo de este cifrado es el siguiente:

Original: Z A P A T O
Cifrado:  C D S D W R
Clave:    3

Aparentemente el Cifrado César tuvo éxito en su momento, ocultando los mensajes de los espías enemigos. Hoy no es más que un juego de niños, aunque increíblemente hay criminales con pocas luces que sigen cayendo por usarlo.

Vigenère

Una mejora al cifrado César fue el cifrado Vigenère, atribuido a Blaise Vigenère pero que realmente fue inventado por Giovan Battista Bellaso en 1553. En vez de sustituir todas las letras por un número fijo, se usa una palabra como clave que indica cuántos lugares se mueve cada letra. Si el mensaje es más largo que la clave, ésta se repite. Por ejemplo utilizando la clave “ABCD” que indica mover cada letra 1, 2, 3 y 4 lugares:

Original: Z A P A T O
Clave:    A B C D A B
          1 2 3 4 1 2
Cifrado:  A C S E U Q

En el ejemplo de cifrado César vimos que la letra D se repetía dos veces, proporcionándonos la información de que se trata de una letra frecuentemente usada en el idioma de mensaje, posiblemente una vocal. Eso sumado a las pocas combinaciones posibles de claves hace trivial su descifrado.

El cifrado Vigenère oculta mucho mejor la información del mensaje original, representó un reto durante siglos y su dificultad aparente le ganó el apodo de le chiffre indéchiffrable. Pero ya para el siglo 19 comenzó a ser roto rutinariamente, y una computadora moderna lo puede romper en milisegundos.

One-time pad

¿Qué pasa si en vez de usar una palabra repetida, usamos letras al azar? Por ejemplo:

Original: Z A P A T O
Clave:    K M W B T P
Cifrado:  K N M C N E

Este pequeño cambio, aunque parezca increíble, ha vuelto nuestro mensaje inviolable. ¿Por qué? Porque si cada letra de la clave es aleatoria, y todas las letras de la clave son aleatorias, el texto cifrado también es completamente aleatorio, independientemente de cual haya sido el mensaje original.

De hecho, podemos probar todas las claves posibles de 6 letras y “descifrar” las palabras ZAPATO, CONEJO, PIEDRA, PELOTA, o cualquier otra combinación posible de 6 letras, y ninguna tiene mayor posibilidad que otra de ser la correcta. Sólo la combinación del texto cifrado y la clave correcta permiten dilucidar el mensaje original.

Más aún, ni siquiera conocer parte del mensaje original permite descifrar las partes faltantes, porque el resto del texto cifrado sigue siendo completamente aleatorio. Si a esto añadimos la posibilidad de paddings o mensajes falsos, entonces se vuelve imposible determinar la longitud exacta del mensaje original o si existe siquiera un mensaje real.

Este tipo de cifrado se llama One-time pad, y fue Claude Shannon el primero en demostrar su seguridad perfecta, invulnerable a las computadoras más poderosas aunque se disponga de tiempo infinito.

La administración de las claves

Entonces, ¿por qué no utilizamos todos el one-time pad? De hecho este sistema fue usado por la KGB durante la guerra fría. Y también fue violado.

Aunque es teóricamente perfecto, el One-time pad tiene severas limitaciones prácticas. Primero necesitas una clave aleatoria. Y golpear teclas “al azar” en tu teclado no es el “aleatorio” que estamos buscando, ya que si lo haces durante mucho tiempo inevitablemente empezarán a aparecer patrones repetidos debido a la forma de tu teclado y tus dedos, memoria muscular, etc. Varios One-time pad fueron descifrados debido a defectos en la fuente de aleatoriedad.

Además, la clave debe ser por lo menos tan larga como el mensaje, así que si cifras un mensaje de 1 GB, necesitas generar una clave de 1 GB que ahora tienes que mantener a salvo para que no caiga en las manos de un adversario o se pierda y con ella tus datos desaparezcan para siempre.

Finalmente, como las claves deben ser aleatorias, nunca se pueden reusar. La KGB proporcionaba a sus espías libros de claves en miniatura, que tenían que leer con una lupa. Como era tan inconveniente llevar cada vez más libros encima para cada mensaje, algunos se vieron tentados a reutilizarlos, y de esta forma sus mensajes pudieron ser descifrados.

Y de esto se desprende una lección muy importante: la administración de las claves es tan importante como el algoritmo en un esquema criptográfico. De nada vale tener el algoritmo más sofisticado si las password se almacenan o se transmiten sin cifrar, o si la password de tus usuarios es “12345” [Youtube], reusan la misma en cada sitio cuestionable, o la anotan en un papelito debajo del teclado (cosa que he visto personalmente). Además, siempre está el viejo método de la llave inglesa para “extraer” información.

AES

De esta forma llegamos a los algoritmos de cifrado modernos. Son algoritmos sofisticados que permiten usar un password en vez de un enorme número aleatorio y proveen de mucha más seguridad que un cifrado simple como el César o el Vigenère. Algunos de los más usados son RC4, 3DES, Twofish, Serpent, Blowfish, y finalmente AES, elegido en 2001 como estándar internacional.

El nivel de seguridad de estos algoritmos es enorme. Si se usó  una buena clave, romper por fuerza bruta un mensaje cifrado con AES llevaría millones de veces más tiempo que la edad actual de universo, lo que se denomina computacionalmente imposible.

Aquí podemos elaborar lo que llamaremos la regla de oro de la criptografía: a menos que seas un experto en criptografía de talla mundial y las redes de Feistel sean un tema de conversación diario con tus amigos, nunca implementes tu propio algoritmo de cifrado. Las agencias de inteligencia emplean a algunos de los matemáticos más brillantes del mundo, con acceso a las supercomputadoras más poderosas y fábricas de circuitos especializados. Romper algoritmos amateur es una de las cosas que los chicos de la NSA hacen para divertirse durante el almuerzo.

Crear un algoritmo de cifrado es un tema fuera del alcance del común de los mortales, e incluso los expertos tienen que enviar sus algoritmos a largos procesos de peer review para que otros expertos los analicen en búsqueda de vulnerabilidades, antes de que pasen a ser de uso general.

Y a menos que sepas realmente lo que estás haciendo, tampoco intentes programar tu propia implementación de un algoritmo conocido. Aunque esté perfecto, podría fallar en implementar contramedidas contra ataques de side-channel, el los que se emplea información como los patrones de uso del CPU o las emisiones electromagnéticas del sistema causadas por el algoritmo y que revelan información del mensaje o de la clave. Es el tipo de cosas para las que la NSA tiene presupuesto ilimitado.

En su lugar, usa siempre implementaciones de algoritmos como AES, que sean ampliamente conocidas, probadas y soportadas, prestando siempre atención al eslabón más débil de la cadena: el usuario.

Intercambiando dos variables

Digamos que tenemos dos variables (a, b) y queremos intercambiarlas, es decir que una tome el valor de la otra:

int temp = a;
a = b;
b = temp;

Nada más fácil, ¿verdad? Creamos una variable temporal para poder resguardar el valor de a mientras asignamos a = b, y luego asignamos a b el valor previo de a.

Es necesario crear esta variable temporal para no perder el valor de la primera variable que intercambiamos… ¿o no? Qué tal esto:

a = a ^ b;
b = a ^ b;
a = a ^ b;

Si ejecutamos el fragmento de código en C podemos comprobar que los valores de a y b han sido intercambiados sin haber usado nunca una variable intermedia. ¿Qué está pasando?

La operación OR exclusivo (^) tiene un par de propiedades interesantes que están actuando en este caso. Un número combinado con sí mismo es igual a cero (a ^ a = 0), y un número combinado con cero es igual a sí mismo (a ^ 0 = a).

En la primera línea estamos asignando a = a ^ b. Luego en la segunda línea estamos asignando b = a ^ b, pero recordemos que ahora a = a ^ b, por lo tanto queda b = a ^ b ^ b.

b ^ b se cancela, por lo que efectivamente en la segunda línea estamos asignando b = a.

Igualmente en la tercera línea asignamos a = a ^ b, pero recordemos que antes de la asignación a contiene el valor a ^ b, y b contiene el valor de a, por lo tanto estamos asignando a = a ^ b ^ a, efectivamente a = b.

Este algoritmo se llama XOR swap. Y no es que tenga mucha utilidad práctica, pero es una linda curiosidad del mundo de la computación.

Administrando servicios de Windows

Recientemente tuve que programar una pequeña utilidad para administrar un servicio de Windows, así que pensé recoger aquí algunas informaciones que se encuentran dispersas en varias fuentes para facilitar la tarea.

La manera más fácil de administrar un servicio en .NET es mediante la clase ServiceController del assembly System.ServiceProcess.dll. El siguiente ejemplo muestra cómo reiniciar el servicio de impresión (Spooler):

using System;
using System.ServiceProcess;

namespace ServiceControllerExample
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Reiniciando servicio Spooler");

                ServiceController serviceController = new ServiceController("Spooler");

                serviceController.Stop();
                serviceController.WaitForStatus(ServiceControllerStatus.Stopped);

                serviceController.Start();
                serviceController.WaitForStatus(ServiceControllerStatus.Running);

                Console.WriteLine("Servicio reiniciado, presione Enter para finalizar.");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadLine();
        }
    }
}

Para instanciar ServiceController simplemente debemos usar el nombre del servicio que lo podemos obtener de la consola de administración (services.msc). Si nos equivocamos con el nombre el objeto será creado igual, y los métodos para cambiar el estado pueden fallar por varias razones, así que es una buena idea poner un try…catch alrededor de todo.

Para reiniciar hay que llamar a Stop() y luego a Start(). El servicio debe estar en un estado previo que tenga sentido para la operación. Por ejemplo si llamamos a Start() en un servicio que ya está iniciado se producirá una excepción.

Otra cosa que hay que notar son las llamadas a WaitForStatus(). Los métodos Start() y Stop() son no bloqueantes, así que debemos hacer esto para sincronizar nuestro código.

Obteniendo el directorio de un servicio

Si desde tu servicio accedes a archivos, la primera vez puede llegarte a sorprender que todas las rutas relativas apuntan a c:\windows\system32. Así que para obtener el working directory del servicio hay que usar AppDomain.CurrentDomain.BaseDirectory.

Para obtener el working directory desde otro proceso hay un par de maneras. Mediante Windows Management Instrumentation (WMI), o directamente desde la clave HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NombreDelServicio del registro.

RegistryKey key = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Services\Spooler");
string servicePath = (string)key.GetValue("ImagePath");

Refactoring

El Refactoring es una práctica fundamental en el desarrollo del software, que sin embargo, se deja de lado demasiado a menudo debido a las presiones para cumplir con las fechas de entrega.

No es algo “opcional” que se puede dejar “para cuando haya tiempo”. Al contrario. Es igual a la limpieza del taller mecánico, debe realizarse constantemente, sino se empezarán a perder piezas, herramientas, y la productividad se verá afectada gravemente. Nuestro proyecto comenzará a caer víctima de la ley de la entropía.

¿Y qué es el refactoring? Muy fácil. Consiste en realizar mejoras al código sin modificar su funcionalidad externa. Es decir, sin que el usuario de nuestro código tenga que enterarse de que hubo un cambio. No consiste en introducir nuevas funciones ni arreglar errores, sólo estamos optimizando lo que ya existe.

Quizás sea mejor ilustrar con un ejemplo muy simplificado, uno de mis refactorings favoritos, proveniente del catálogo de Martin Fowler.

Reemplazar Condicionales Anidados con Guards

Es bastante frecuente encontrar código como este:

public bool AvanzarSemaforo()
{
    if(_semaforo.Estado == EstadoSemaforo.OK)
    {
        if(_semaforo.Color != ColorSemaforo.Rojo)
        {
            if(_semaforo.Color != ColorSemaforo.Amarillo)
            {
                return true;
            }
        }
    }

    return false;
}

El problema con este antipatrón que ha sido llamado “punta de flecha” [1] por la forma que toma el código, es que aumenta innecesariamente la complejidad del código, dificultando su comprensión a la hora del mantenimiento.

La solución consiste en invertir las comparaciones booleanas, colocando los casos excepcionales al principio del método en forma de guardas y a continuación el camino normal de la ejecución:

public bool AvanzarSemaforo()
{
    if(_semaforo.Estado != EstadoSemaforo.OK
       || _semaforo.Color == ColorSemaforo.Rojo
       || _semaforo.Color == ColorSemaforo.Amarillo)
    {
        return false
    }

    return true;
}

Como podemos ver, el método es ahora mucho más breve y comprensible.

Programas como Resharper automatizan este tipo de refactorings e incluso los sugieren automáticamente. Sin embargo no es difícil hacerlo de forma manual, siempre teniendo cuidado de no alterar la funcionalidad original, que es el objetivo fundamental de todo refactoring.


[1] Sean Chambers, Simone Chiaretta: 31 Days of Refactoring. pág 38. Enlace: http://lostechies.com/e-books