martes, 26 de mayo de 2009

La Misión

El otro día en una compra-venta de autos encontré un pedazo de madera, sobre el escritorio del vendedor, que tenía el siguiente poema de Gabriela Mistral:
Donde haya un árbol que plantar, plántalo tú
Donde haya un error que enmendar, enmiéndalo tú
Donde haya un esfuerzo que todos esquivan, hazlo tú
Sé tú el que aparta la piedra del camino
Esto se escapa habitualmente a mis publicaciones, sin embargo, me sentí plenamente identificado por él, así que decidí compartirlo por acá. Lamentablemente, aún no logro encontrar ninguna referencia al material de Gabriela Mistral para poder leerlo completamente.

jueves, 21 de mayo de 2009

Proceso de Selección - Parte II

Siguiendo con el proceso de selección, la segunda pregunta que he hecho a los candidatos como parte del proceso de entrevista es la siguiente.

Considerando la siguiente jerarquía de excepciones qué excepciones son válidas para completar la declaración del método foo() en la clase B (donde está la X).


  class A {
  :
  public foo(...) throws D {
    :
  }
  :
}

class B extends A {
  :
  public foo(...) throws X {
    :
  }
  :
}

En términos generales, esta pregunta intenta evaluar los conceptos básicos de herencia en la Programación Orientada a Objetos. Muchos de los candidatos se sienten intimidados e intentan responder (pocas veces exitósamente) aunque no tengan claro el concepto.

Para poder responder la pregunta, lo primero que hay que tener claro es la herencia. Mirando la declaración de excepciones se puede concluir que:

  • D es una excepción de tipo C
  • E es una excepción de tipo D y de tipo C

El concepto importante acá (en relación a la herencia) es que no necesariamente esto se pude intepretar al revés, es decir, que C es una excepción de tipo E. Una manera simple de ver esto es, por ejemplo, en la siguiente herencia:

Lo que se puede concluir inmediatamente es que:

  • Un perro es un animal
  • Un labrador es un perro

Sin embargo, no necesariamente aplica en el sentido inverso, por ejemplo, un perro no necesariamente es un labrador.

Tomando en cuenta todos estos elementos, las excepciones válidas para ser declaradas en X son D y E. Básicamente, D porque es equivalente en términos de la firma al método de la clase base y E porque es una excepción de tipo D también. Esto es lo que se conoce como Especialización.

martes, 5 de mayo de 2009

Te declaro por un rato...

Hace tiempo me tocó subirme al carro de la programación en Java y, en especial, programación J2EE con toda la parafernalia asociada (mdb´s, ejb´s, etc.). Yo tengo una base en programación de software sobre lenguajes estructurados (C, Pascal) y Orientados a Objetos (C++) principalmente. Adicionalmente, por inquietud profesional, es decir, por los pitutos que he realizado, tengo experiencia en lenguajes del mundo Microsoft previos a .net (Visual Basic 6.0, ASP, etc.) y, ahora último, C#. Estos últimos conocidos como "El Lado Oscuro" por mis pares amantes de las infraestructuras del tipo LAMP. En este camino de descubrimiento de las ventajas y bondades de la programación en Java, uno de los aspectos que más me molestó es la insoportable sintaxis y/o estándar de facto relacionado a la programación J2EE para el uso de recursos y/o objetos determinados.

Un claro ejemplo de esto es el uso de mecanismos de Log en estos ambientes. Una sintaxis típica de una instrucción de Log en este contexto se ve como sigue:

  :
FactoryManager.getLogFactory().getLogger().Log("Ha ocurrido un error");
  :

A simple vista, no tiene mucha complejidad este código, sin embargo, si vemos un código que haga uso extensivo de esta sintaxis se vería así:

FactoryManager.getLogFactory().getLogger().Log("Comenzado proceso de Analisis");
FactoryManager.getLogFactory().getLogger().Log("Analizando Bloque 1");
  :
FactoryManager.getLogFactory().getLogger().Log("Analizando Bloque 2");
  :
FactoryManager.getLogFactory().getLogger().Log("Proceso de Analisis Terminado");
FactoryManager.getLogFactory().getLogger().Log("Bloques Correctos " + ....);
FactoryManager.getLogFactory().getLogger().Log("Bloques con Error " + ....);

Desde mi punto de vista, este código tiene los siguientes problemas:

  • Genera más código del necesario (en lo visual y en bytes).
  • Es innecesariamente complejo dado que no facilita procesos de mantención asociados, en este caso, a la clase Log, LogFactory y FactoryManager. Básicamente, porque un cambio menor en cualquiera de ellas, podría rápidamente impactar las 7 líneas anteriores. Peor aún cuando el código sobre el que se está operando tiene miles de líneas.
  • No hace ni fomenta un correcto control de errores para la obtención del LogFactory ni para la recuperación del objeto Logger (aunque debieran ser implementaciones con un Singleton y/o variables static, cualquiera de estas dos podría retornar un error y la sintaxis no lo refleja ni aborda).

Para evitar estos problemas, mi recomendación es el uso de variables de referencia, es decir, variables temporales destinadas única y exclusivamente a resolver los problemas anteriores. Estas variables no tienen ningún impacto en la lógica implementada.

El código anterior podría reescribirse como sigue:

LogFactory oLF = FactoryManager.getLogFactory();
Logger oLog = oLF.getLogger();

oLog.Log("Comenzado proceso de Analisis");
oLog.Log("Analizando Bloque 1");
  :
oLog.Log("Analizando Bloque 2");
  :
oLog.Log("Proceso de Analisis Terminado");
oLog.Log("Bloques Correctos " + ....);
oLog.Log("Bloques con Error " + ....);

Si incorporamos la validación de condiciones de error para los objetos indicados antes, el código quedaría como sigue:

LogFactory oLF = FactoryManager.getLogFactory();

if( oLF == null ) {
  // Determinar qué hacer en esta condicion de error
}

Logger oLog = oLF.getLogger();
if( oLog == null ) {
  // Determinar qué hacer en esta condicion de error
}

oLog.Log("Comenzado proceso de Analisis");
oLog.Log("Analizando Bloque 1");
  :
oLog.Log("Analizando Bloque 2");
  :
oLog.Log("Proceso de Analisis Terminado");
oLog.Log("Bloques Correctos " + ....);
oLog.Log("Bloques con Error " + ....);

Desde mi perspectiva este código es más claro, fácil de mantener y visualmente simple. En el caso de clases que se utilicen reiteradamente y que el uso del log sea una obligación, si el acceso al "Logger" no presenta grandes problemas, una clase podría definir internamente una referencia al Log para ser utilizada por todos los métodos de la misma como sigue:

class A {
  LogFactory oLF = null;
  Logger oLog = null;

  public A() { // Constructor
    oLF = FactoryManager.getLogFactory();

    if( oLF == null ) {
      // Determinar qué hacer en esta condicion de error
    }

    oLog = oLF.getLogger();
    if( oLog == null ) {
      // Determinar qué hacer en esta condicion de error
    }
  }

  void metodoUno(...) {
    :
    oLog.Log("Ejecutando Metodo Uno");
    :
  }

  void metodoDos(...) {
    :
    oLog.Log("Ejecutando Metodo Dos");
    :
  }
}

Lo anterior no aplica para clases con métodos estáticos y/o escenarios en donde el destino del "Log" es dinámico (archivos, base de datos, e-mail, etc.).

Otro ejemplo que me ha tocado ver en donde lo anterior aplica y produce mejoras sustanciales es en el contexto de la programación de Servlets. En lo personal, he encontrado pocas justificaciones para hacer uso de esta tecnología (en vez de JSP), sin embargo, reiteradamente aparece sintaxis como la siguiente:

public class MiServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  public void init(ServletConfig servletConfig) throws ServletException {
    super.init(servletConfig);
  }

  protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
    httpServletResponse.getWriter().write("<tr ....");
    httpServletResponse.getWriter().write(" <td ....");
    httpServletResponse.getWriter().write(" </td ....");
    httpServletResponse.getWriter().write(" <td ....");
    httpServletResponse.getWriter().write(" </td ....");
    httpServletResponse.getWriter().write("</tr");
  }
}

Y que, aplicando lo descrito anteriormente, se puede dejar como sigue:

protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {

  java.io.PrintWriter oPage = httpServletResponse.getWriter();

  oPage.write("<tr ....");
  oPage.write(" <td ....");
  oPage.write(" </td ....");
  oPage.write(" <td ....");
  oPage.write(" </td ....");
  oPage.write("</tr");
}

Generando un código bastante más simple y manejable desde mi punto de vista.