viernes, 30 de diciembre de 2011

Mis Libros del 2011


Puesto que queda un solo día y ya no llego a terminar el libro actual, creo que ya puedo dar por finalizada la lectura del año.
Conformando la siguiente lista:
  1. "El Evangelio Según Jesucristo", José Saramago.
  2. "Wagner para principiantes".
  3. "Evangelios Apócrifos", Editorial Libertador.
  4. "El guardián entre el centeno", J.D. Salinger.
  5. "Ajeno a la tierra", Richard Bach.
  6. "Mapas en un espejo. El ahorcado: cuentos de espanto",  Orson Scott Card.
  7. "Le Petit Nicolas", Gosciny ?
  8. "La Guerra del Paraguay", ?
  9. "Cuentos de Terror", H.P. Lovecraft.
  10. "Utopía", Tomas Moro.
  11. "El Manifiesto del Partido Comunista", Karl Marx & Frederick Engels.
  12. "La Torre Oscura VII: libro 1", Stephen King.
  13. "Cita con Rama", Arthur C. Clarke.
  14. "La Torre Oscura VII: libro 2", Stephen King.
  15. "La Rebelión de las Masas", José Ortega y Gasset.
  16. "La Agonía y el Éxtasis: vida de Miguel Ángel", Irving Stone.
  17. "El Universo en una Cáscara de Nuez", Stephen Hawking.
  18. "O povo brasileiro", Darcy Ribeiro.
  19. "Uno", Richard Bach
  20. "Juan Manuel de Rosas: el maldito de la historia oficial", Pacho O'Donnell.
  21. "How to brew: everything you need to know to brew beer right the first time", John J. Palmer.
  22. "Beer School: bottling success at the brooklyn brewery", Steve Hindy & Tom Potter.
  23. "The Complete Joy Of Home Brewing", Charlie Papazian.

Y de yapa, los libros del 2010:

  1. "El juego de Ender", Orson Scott Card.
  2. "Reflexiones sobre la no violencia", Gandhi.
  3. "El espíritu de la naturaleza", Emerson.
  4. "Las Aventuras de Tom Sawyer", Mark Twain.
  5. "Coup de Coer".
  6. "Autour de la Lune", Jules Verne.
  7. "Les Trois Mousquetaires", Alexandre Dumas
  8. "La guerre des boutons".
  9. "Papillon", Henri Charriere.
  10. "Desobediencia Civil y Otras Propuestas", Thoreau, Gandhi, M Luther King, etc.
  11. "Cuento de Navidad", Charles Dickens.
  12. "Walden, la vida en los bosques", Henry David Thoreau.
  13. "Amo y Servidor y otros cuentos", León Tolstoi.
  14. "La muerte de Iván Ilich", León Tolstoi.
  15. "El Extranjero", Albert Camus.
  16. "El invencible", Stanlislav Lem.
  17. "El Anticristo", Nietzsche.
  18. "Mitología Inca".
  19. "Espejos", Eduardo Galeano.
  20. "El libro de los abrazos", Eduardo Galeano.
  21. "Las enseñanzas de Don Juan", Carlos Castaneda.
  22. "Las Matanzas del Neuquén", Curruhuinca Roux.
  23. "La Torre Oscura 5, Lobos de Calla 1", Stephen King.
  24. "La Torre Oscura 5, Lobos de Calla 2", Stephen King.
  25. "La Torre Oscura 6, La Canción de Susana", Stephen King.

lunes, 26 de diciembre de 2011

Enigmas de Código

Siguiendo con el tema de "cuando el código toma el control", traigo un pequeño desafío de la ciencia.

Para qué sirve este if ?

public class FacebookDBHistory {
    DBClientAPI dbClient;

    public FacebookDBHistory() {
        if (dbClient == null) {
            dbClient = DBClientFactory.getDefaultDBClient();
        }
    }

????

Cuando el código toma el control

Cuando el código toma el control, el programador pasa a ser la preza. Cada linea es una potencial fiera a punto de atacarlo.


Como un laberinto, con código inutil, código malisioso, e incluso extra código que está allí solo para enloquecerlo.

El terror se apodera de los programadores, y el sistema se convierte en una especie de cueva oscura y aterradora, donde nadie quiere entrar. Y si no hay otra, intentarán adentrarse lo menos posible, y por el menor tiempo posible.

Casi como un juego de Jenga (Yenga), el programador entrará, hará los suyo, en la medida en que el código se lo permita, y volverá a su tranquilidad mental. Claro, mientras nadie detecte que todo esto nada solucionó.

Y digo "en la medida en que el código se lo permita", no por casualidad. He aquí la clave que da título al post.
Cuando el código toma el control, el programador pierde su libertad. La libertad de crear. Ya no hace lo que quiere, no moldea y diseña su sistema según la que cree es la mejor forma, sino que hace "lo que puede". Lo que se puede con el código. Lo que el código le dejó hacer.

Quien está en control entonces ?

Ese programador se torna esclavo de su código.

Y entonces pasan cosas como estas, que son las que despiertan estos terribles pensamientos que dan origen a este post:

SentimentSet sentset = null;   
            if (sentset == null || sentset.isLang(afb.getLang()) == false) {
                sentset = db.LoadSentiment(afb.getLang());
            }


Recuerden.. quizás hoy sea un buen día para enfretar su código y volver a tener el control ! :)


Comprimiendo Código

Breve.
Esto...
    public boolean isRetweet()
    {
        boolean rtn = false;
        NodeList entries = doc.getElementsByTagName("retweet");
        if (entries.getLength() > 0) rtn = true;
        return rtn;
    }

Es de hecho esto...

    public boolean isRetweet()
    {
        return doc.getElementsByTagName("retweet").getLength() > 0;
    }

Factor de compresión 4:1
La pregunta que uno se haría es por qué diantres uno escribiría el método de 4 lineas en primera instancia.

sábado, 29 de octubre de 2011

Chiche nuevo - Refractómetro

Esta semana me llegó el refractómetro que había comprado por ebay a un chino capo al otro lado del mundo. En realidad el tipo es de hong kong. Ya medio que me había olvidado después de haberlo comprado como unas dos o tres semanas atrás, entre tantas cosas se me había olvidado, y oh felicidad al escuchar que había llegado. Paso algunas fotitos
La verdad que se pasó el tipo este. Llegó todo perfecto, casi sin intervención. Lo habían recomendado bastante en la lista de cerveceroscaseros. Lo pagué unos 25U$S, mas unos 9U$S de envío. Si redondeamos a 150$ igualmente es baratísimo comparando con el precio de venta de mercadolibre que ronda los 350$. Será un buen negocio importarle cosas al chino y venderlas ? chan! :) Acá el link Todavía no pude probarlo porque necesito agua destilada y además lo mejor sería probarlo con una nueva cocción, pero bueno, ahora con la llegada de Azul deberá esperar. Lo mismo que el corte de los barriles. Pero sigo con muchas ganas de cocinar, y principalmente de ampliar el equipo y eventualmente el año que viene dedicarle un lugar especial a esto para poder cocinar en forma más frecuente. Con suerte en la primer parte del año, si se dan las cosas a un nuevo hogar :) Y a todo esto sigo leyendo y meditando como darle forma a este proyecto. Bueno, no hay mucho más que contar sobre esto. Ah si.. que el otro día probé la cerveza "Grosa", obsequio de un gran amigo de trabajo. La verdad que muy buena. Es la cerveza nacional más parecida a la Leffe que probé hasta ahora. Con unos 10º de alcohol, parecía la leffe 9. Además probé una nacional artesanal estilo barley wine, del sur del país, pero no le llega ni a los talones a la barley de Antares, que sigue siendo mi cerveza preferida. Salud'ines!

martes, 6 de septiembre de 2011

Refactorizando I: mala decisón de agrupamiento de lineas de código

Hola, hoy en refactorísima vamos a ver una ejemplo típico de programación estructurada y mala práctica de diseño que lleva a la ilegibilidad, e inmantenibilidad del código a largo plazo.

Hé aquí un pedazo de código, que más allá de que es nefasto por que opera con char's haciendo sumas y restas, etc, tiene un problema de legibilidad.

protected void parseLAC(String s, int i) {
     int c2 = s.charAt(i + 6) - 0x30;
     int c1 = s.charAt(i + 7) - 0x30;
     int c0 = s.charAt(i + 8) - 0x30;
    
     int cx = s.charAt(i + 9) - 0x30;
     if (c2 > 9) c2 -= 0x07;
     if (c1 > 9) c1 -= 0x07;
     if (c0 > 9) c0 -= 0x07;
     if (cx > 9) cx -= 0x07;
     lac = (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

En realidad vemos varios problemas.
Primero: el código no está formateado en la convención estandard. Eso nos va a traer un problema, y nos va a hacer perder tiempo. Porque el ojo ya está acostumbrado a encontrar patrones de código y ubicarse rápidamente.

Entonces, como refactorizar es todo lo contrario a la actividad de un héroe. Es decir, es una actividad engorrosa, complicada, donde fácilmente uno la pueda manquear*, tenemos que proceder con cautela. Tranquilizarnos e ir paso a paso. Aunque parezcan pasos ridículos o que no van a resolver el problema completo.
Refactorizar es una laaaaarga tarea de pequeños pasos.

El primero entonces en nuestro caso va a ser formatear el código:

protected void parseLAC(String s, int i) {
    int c2 = s.charAt(i + 6) - 0x30;
    int c1 = s.charAt(i + 7) - 0x30;
    int c0 = s.charAt(i + 8) - 0x30;

    int cx = s.charAt(i + 9) - 0x30;
    if (c2 > 9) {
        c2 -= 0x07;
    }
    if (c1 > 9) {
        c1 -= 0x07;
    }
    if (c0 > 9) {
        c0 -= 0x07;
    }
    if (cx > 9) {
        cx -= 0x07;
    }
    lac = (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

Ahí está mejor.
Parece más cantidad, pero eso es mejor, porque nos va a forzar a tratar de reducir la cantidad de lineas.

El segundo problema que se ve rápidamente es que las variables tienen nombres siniestros. Eso, todavía no lo camos a poder resolver, porque para eso deberíamos entender el dominio, y qué significado tiene cada número.

Pero.. capaz, con suerte eliminamos las variables y entonces no necesitamos nombres :)

Tercera cosa en la que meditamos: qué hace este código ?
Parece que parsea caracteres del string "s" que recibe por parámetro, y luego las combina con una operación binaria para terminar asignando el resultado a la variable de instancia lac.

Entonces, reordenamos el código, algo bien sutíl, pero voy a juntar todos los pedazos de código que me parecen iguales. De hecho sin siquiera prestar atención a qué hacen todavía.
En esto caso subo la declaración de int cx junto a las demás:
Y separo la última linea.

protected void parseLAC(String s, int i) {
    int c2 = s.charAt(i + 6) - 0x30;
    int c1 = s.charAt(i + 7) - 0x30;
    int c0 = s.charAt(i + 8) - 0x30;
    int cx = s.charAt(i + 9) - 0x30;

    if(c2 > 9) {
        c2 -= 0x07;
    }
    if(c1 > 9) {
        c1 -= 0x07;
    }
    if(c0 > 9) {
        c0 -= 0x07;
    }
    if(cx > 9) {
        cx -= 0x07;
    }

    this.lac = (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

Ahora, acá está el cuarto problema que detectamos y el del objetivo de este post:

Estas lineas de código estan agrupadas, adrede, bajo un criterio prehistórico, el de ordenamiento por función del código, y no por sentido de dominio
.

Qué quiere decir ?
Fácil, que el tipo que lo escribió creyó que al estructurar todo su código de la misma manera sería fácil mantenerlo o vaya diós a saber qué.
Entonces su código se ordena:
  • Primero declaro todas las variables.
  • Luego las asigno.
  • Luego las opero, por ejemplo si tengo que aplicarles alguna regla como la del if.
  • Luego las uso al final para computar el lac.
Este criterio tiene problemas, porque el cuerpo del método pierde cohesión. No se puede ver como un conjunto de nodos o pasitos (que podría mover así como están a métodos o procedimientos). Ahora los pedacitos de funcionalidades estan todos acoplados a todo el método.

Porque, si pensamos el cuerpo del método como pasos o funcionalidades. Llamémoslas: A, B, C.

Para cada funcionalidad voy a necesitar quizás realizar lógica propia del lenguaje como:
  • declarar variables (decl)
  • inicializar (init)
  • preprocesamiento (pre)
  • procesamiento (proc)
  • post-procesamiento (post)
Si estructuro el código basado en estas actividades, en lugar de en las funcionalidades (A,B, C). Voy a atravezarlas a todas quedanso su código entre mezclado:

decl A
decl B
decl C

init A
init B
init C

pre A
pre B
pre C

proc A
proc B
proc C

post A
post B
post C

Acá se ve que cada comportamiento queda diseminado en todo el cuerpo del método.
Y qué pasa si ahora me gustaría reutilizar la lógica de B ?
Estoy al horno.

En cambio si estructuro el código en base a la funcionalidad y no a la sintaxis del lenguaje, de esta forma más cohesiva:

decl A
init A
pre A
proc A
post A

decl B
init B
pre B
proc B
post B

decl C
init C
pre C
proc C
post C

Voy a poder llevarme cualquier de esas funcionalidades a métodos:

doA()
doB()
doC()

Si están encadenadas de hecho podría dejar eso bien explícito

doC(doB(doA()))

Reduciendo el código del método a una simple linea que al usar métodos con nombres significativos sería mucho más autoexplicativa que todo el código original.

Además, si encuentro en otro caso que las funcionalidades A, B y C, tienen código repetido, y que podría encontrarles una abstracción e implementarlo una única vez, es mucho más fácil ver esto cuando A, B y C están cada una declarada en forma cohesiva (junta) a que cuando estan diseminados.

Ej:

{
     do ("A")
     do ("B")
     do("C")
}

def do (algo) {
     decl algo
     init algo
     pre algo
     proc algo
     post algo
}

Acá refactorizamos para tener un único método con la lógica que antes estaba repetida. Y desde nuestro método lo invocamos para cada funcionalidad (A, B, y C).


Además cuando trabajamos con la conveción nefasta, suele suceder que como agrandamos el scope de las variables, ahora estan disponibles a todo el método. Entonces suena tentador que alguien las reutilice. Complicando la lectura y la refactorización.
Que las mezcle, o que agregue lineas entrelazadas, o de diferentes funcionalidades. Ocasionando el famoso código spaghetti.


Si aplicamos esto que vimos entonces, para refactorizar deberías juntar las funcionalidades.
Una buena forma de relacionar funcionalidades es por el acceso a las variables.

Entonces veamos, la variable c2:
  • se declara e inicializa en la línea 1
  • luego no se utiliza hasta 6 (porque en el medio estan las inicializaciones de las otras variables). Donde se ajusta el valor en base a una validación
  • luego, no se usa hasta la última linea donde se utiliza para calcular el lac
Si miramos las demás variables vamos a notar que les sucede lo mismo.
Refactorizamos entonces reordenando:

protected void parseLAC(String s, int i) {
     int c2 = s.charAt(i + 6) - 0x30;
     if (c2 > 9) {
         c2 -= 0x07;
}

     int c1 = s.charAt(i + 7) - 0x30;
     if (c1 > 9) {
         c1 -= 0x07;
     }

     int c0 = s.charAt(i + 8) - 0x30;
     if (c0 > 9) {
         c0 -= 0x07;
     }

     int cx = s.charAt(i + 9) - 0x30;
     if (cx > 9) {
         cx -= 0x07;
     }

     this.lac = (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

Cada vez se ve más grande el código. No asusteis, las cosas empeoran antes de mejorar :)
Ya juntamos la declaración de cada variable con su modificación. Pero no así su uso, porque claro, para asignar el valor a lac, necesitamos todas las variables ya preparadas.

Como verán, la última variable, es decir cx queda "linda", es decir cumple la regla, porque se declara y se utiliza enseguida.
Las demás no, por lo que ya mencioné. Ejemplo c2.

Eso me molesta. Eso debería molestarles.
Como reglas generales de declaración de variables que tienen que ver con todo esto que mencioné antes, podemos decir que:
  • Hay que tratar de declarar las variables lo más tarde posible. Es decir, justo cuando las voy a utilizar. Y no antes de necesitar "por las dudas" o para agruparlas o para ordenarlas, etc.
  • Declarar las variables SOLO dentro de los bloques donde se van a utilizar, y no fuera de ellos. Un contraejemplo es declarar las variables fuera del for o el while.
  • Además de que estaríamos agrandando el ciclo de vida de la variable, y por ende dejándo alocada memoria por más tiempo del debido. El problema más importante que ocasiona no seguir estas prácticas es la poca legibilidad del código.
Entonces tratemos de resolver esto.

Si analizamos los bloques ahora vamos a ver que son bastante similares.
Las asignaciones de las variables son iguales, salvo que cambia el índica del caracter a extraer del string:
Ejemplo:

    int c2 = s.charAt(i + 6) - 0x30;
    int c1 = s.charAt(i + 7) - 0x30;

Lo mismo sucede con los ifs:

    if(c2 > 9) {
        c2 -= 0x07;
    }
    if(c1 > 9) {
        c1 -= 0x07;
    }

Entonces si generalizamos ambos comportamientos:

    int variable = s.charAt(indice) - 0x30;
    if(variable > 9) {
         variable -= 0x07;
    }

Y lo más importante, este comportamiento lo puedo unir y decir que su objetivo es, dado un String de entrada y un índice, retornar el valor numérico del caracter transformado (con vaya a diós a saber qué hace eso).

Entonces vamos a crear un método parseChar(String, int posición) para eso:
Y de paso hacemos un inline del if lo cual reduce lineas y lo hace ver más declarativo.

protected int parseChar(String s, int charIndex) {
     int parsed = s.charAt(charIndex) - 0x30;
     return parsed > 9 ? parsed - 0x07 : parsed;
}

Ahora lo utilizamos desde el método original:

protected void parseLAC(String s, int i) {
     int c2 = this.parseChar(s, i + 6);
     int c1 = this.parseChar(s, i + 7);
     int c0 = this.parseChar(s, i + 8);
     int cx = this.parseChar(s, i + 9);

     this.lac = (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

Y ahora nos gusta más. Porque el código es mucho más conciso. Hay menos lineas entre la declaración de las variables y su utilización.
Además, al tener un nivel de abstracción, se hace más legible el objetivo del método. Sin apabuyarnos con todos esos ifs raros.

Acá vemos claramente que se parsean caracteres de diferentes posiciones del string. Y luego se utilizan.

Sin embargo, sigue teniendo la naturaleza estructurada de: declarar variables... usarlas.
Tratemos de resolver eso.

Vamos a esconder la operación de los números, encontrándole una abstracción: un factory method. Es decir un método que construye el objeto lac.

protected void parseLAC(String s, int i) {
     int c2 = this.parseChar(s, i + 6);
     int c1 = this.parseChar(s, i + 7);
     int c0 = this.parseChar(s, i + 8);
     int cx = this.parseChar(s, i + 9);

     this.lac = lac(c2, c1, c0, cx);
}

protected int lac(int c2, int c1, int c0, int cx) {
     return (c2 << 12) | (c1 << 8) | (c0 << 4) | cx;
}

Y eso nos sirvió para que la linea que utiliza las variables quede más chiquita, con lo cual ahora podemos hacer un inline de las variables.
Es decir, eliminarlas y usar directamente el valor de retorno del método parseChar en la última linea (y única ahora).

protected void parseLAC(String s, int i) {
     this.lac = lac( this.parseChar(s, i + 6),
     this.parseChar(s, i + 7),
     this.parseChar(s, i + 8),
     this.parseChar(s, i + 9));
}

Y ahí ya quedamos más conformes con nuestro código.

Sin embargo... pucha.. todavía molesta!
Molesta que tengamos todos esass llamadas a parseChar iguales, solo cambiando su índice.

Entonces buscámos una abstracción. Qué se supone que estamos haciendo acá ?
Parece que el lac se construye con ciertos caracteres del String que viene como parámetro y el índice. Todos caracteres consecutivos!
Ahí está la clave.
Si vemos cada parseChar() en forma individual, tenemos este código que nos quedó.

Pero ahora intentamos agruparlos. Que tienen en común ?
Que, en lugar de "parse el 1, parsea el 2, parsea el 3... etc," podría decir parseá los caracteres desde el 1 al 6, por ejemplo.

Y vamos a hacer eso en nuestro caso.
Vamos a agrupar la lógica de parsear los parámetros a un único método, en lugar de varias llamadas.
Entonces ese nuevo método nos va a devolver la colección de resultados. En este caso va a ser un array con todos los ints. Un int[]

Y después vamos a necesitar crear el lac a partir del array que tienen todos los números.
Quedaría algo así:

protected void parseLAC(String s, int i) {
    this.lac = this.lac(this.parseChar(s, i + 6, i + 9));
}

El nuevo método parseChar, recibe un string y dos números: el índice desde, y el índice hasta (inclusive).
Que son los extremos que antes teníamos así:

    this.parseChar(s, i + 6),
     this.parseChar(s, i + 7),
     this.parseChar(s, i + 8),
     this.parseChar(s, i + 9));

Sin embargo, este nuevo parseChar reutiliza el parseChar individual que teníamos antes así

protected int[] parseChar(String string, int from, int to) {
     int[] parsed = new int[to - from + 1];
     for (int i = 0 ; from <= to; i++, from++) {
     parsed[i] = parseChar(string, from);
     }
     return parsed;
}

Como verán, lo que hace es crear un array de int's y realiza las varias invocaciones al método anterios, asignando el resultado a las posiciones del array.
Luego lo devuelve.

En fin.
El nuevo cuerpo del método queda:

protected void parseLAC(String s, int i) {
    this.lac = lac(parseChar(s, i + 6, i + 9));
}

No se ustedes, pero yo ya estoy bastante conforme con eso. No, en realidad podría podría hacer esto último. Porque molesta estar sumando la i dos veces.

protected void parseLAC(String s, int i) {
    this.lac = lac(parseChar(s, i, 6, 9));
}

Pero ya no lo voy a mostrar en código ese, porque me cansé :P

Ergo, pudimos refactorizar a la forma que mostraba conceptualmente arriba de

    doC(doB(doA)))

en esto caso:

    crearLac( parsearLac(string...)))

Pudiendo encontrar abstracciones mucho más chiquitas, y por esto mismo ir construyendo métodos más ricos, es decir que hacen más cosas, sin embargo con pocas lineas (una linea en este ejemplo).

Como consecuencia, ahora podemos reutilizar cada uno de los métoditos que hicimos en otras partes de la clase.

Porque claro, no es que ahora hay una sola linea. Lo que hay es abstracción y claridad.

Pasó acá la solución completa con todos los métoditos:


protected void parseLAC(String s, int i) {
    this.lac = lac(parseChar(s, i + 6, i + 9));
}

protected int[] parseChar(String string, int from, int to) {
    int[] parsed = new int[to - from + 1];
    for (int i = 0 ; from <= to; i++, from++) {
        parsed[i] = parseChar(string, from);
    }
    return parsed;
}

protected int parseChar(String s, int charIndex) {
    int parsed = s.charAt(charIndex) - 0x30;
    return parsed > 9 ? parsed - 0x07 : parsed;
}

protected int lac(int[] numbers) {
    return (numbers[0] << 12) | (numbers[1] << 8) | (numbers[2] << 4) | numbers[3];
}


Eso es todo amiguitos!!

Recuerden que todo código se puede llevar a esta forma !

Saludines!

miércoles, 8 de junio de 2011

Evolución Vegetal

Bien sabido es, que la especie humana requirió millones de años de evolución hasta llegar a su punto actual. Acá, algún negativo, podría acotar la pregunta retórica de "tanto tiempo para esto?". Pero al margen de eso, si hay algo interesante en esto de la evolución, es que es un proceso de prueba y error. Y acá, el punto importante es el error.

No vamos a meternos a explicar los detalles de la evolución en términos genéticos, pero vamos a resumir en el hecho de que, los organismos simplemente, al reproducirse, a veces se la mandan, y a esto se le llama "error". Si bien uno en principio, de negativo nomás, escucha "error", y piensa en que calculó mal la cantidad de huevos para hacer el bizcochuelo, y por ende ahora se quedó sin bizcochuelo. O que calculó mal la cantidad de litros de pintura, y ahora quedó la habitación a medio terminar. O en "disculpe señor pero hubo un error y vamos a tener que cobrarle una comisión de uso de su tarjeta...". Y una cantidad innumerable de "errores" de nuestra sociedad actual, que siempre desencadenan alguna consecuencia nefasta para nuestra persona.

La idea de error en la evolución sería mejor expresada, y menos peyorativa, si pensamos como "una diferencia no intencional". Es decir que el resultado, es distinto del esperado. Nótese que no decimos nada acerca de si esta diferencia es buena o mala. Porque en definitiva, buena o mala para qué ? en qué contexto ?.

En fin. A veces esas diferencias, son justamente ventajas. Por ejemplo, se contaba la historia de un cierto bicho, como un insecto volador, que comenzó a mutar (en sucesivas generación), obviamente por "error" y entonces su color pasó a ser blanco.
Como vivía en una zona volcánica, que solía estar cubierta de cenizas bastante parecidas a ese blanco, los otros bicharracos ya no lo podían ubicar. Entonces, nadie se lo morfaba.
Eventualmente, el volcán dejó de estar en actividad, y ahora el bicho blanco se posaba sobre los arboles oscuros, y era una invitación para los demás hambrientos habitantes de la zona, que no dudaban en darse un manjar.
Eventualmente, a lo largo de los años, de nuevo, por esa de las cosas, el bichito pasó a color negro, y así de nuevo los demás animalitos tuvieron que cambiar su dieta.

Entonces, a veces, la evolución ayuda a las especies. Otras veces la condena. Pero ya no tengo ejemplo de eso, porque no tengo bicho que me la cuente.

Pero acá vamos a hacer un alto, porque no hay que pifiarla. Que eventualmente el bicho salga beneficiado, no quiere decir que estaba planificado. No quiere decir que ellos o alguien más se estuvo rompiendo la cabeza pensando en qué cosa cambiarle al pobre bicho para hacerlo "evolucionar". Simplemente sucede, y a veces es para bien o para mal del pobre animalito.

Por eso es que tomó tanto tiempo llegar a "esto".

Ahora, otro punto importante de la evolución, es que se va ramificando. Y no necesariamente una linea de evolución es mejor que otras.
El tema es que nosotros los humanos nos creemos los más capos, o tenemos algún tipo de complejo de inferioridad a nivel especie, que hace que todo el tiempo resaltemos los defectos de los otros pobres animalitos.
En definitiva, a lo que voy es que, el ser humano es el resultado (intermedio) de una linea de evolución, pero no es la definitiva, ni la mejor, ni la única.

Y acá finalmente, luego de tanto introducción entro al tema del post.

Cuán diferente podría ser la vida si hubieramos evolucionado de otra forma. O en una sociedad evolucionado de otra forma ?

Y pensaba, que, en nuestro narcisimo, siempre despreciamos a las pobres plantas, porque estan ahí quietitas, no hablan, no se mueven. No sirven para cuidar la casa, porque ni siquiera ladra, ni muerden (habría que ver si existe algún tipo de planta carnivora gigante que sirva de custodio). En fin, lo que se dice comúnmente como que "no sirven ni pa' espiar".

Y así nos olvidamos de la mayor ventaja que tiene la planta por sobre nosotros. Que no necesita comer!

Su necesidad se reduce a dos recursos que podríamos pensar que son gratuitos o casi inacabables: la luz del sol, y ciertos minerales de la tierra.

Pensar que si nosotros solo necesitáramos de eso, muchas cosas no existirían, como: la industria ganadera, la industria cerealera, los supermercados, los kioskos. Y por ende muchos problemas, como "el precio de la carne". O el kilo de tomates a 12$.
De hecho, podría no existir la plata!. Si el sol no se compra!, y la tierra, .. bue. Podría pensarse que en principio, no haría falta comprar y vender la tierra. Cuánta tierra necesitaría un vegetoide de estos?

Sin plata, ya cambia todo. No necesitariamos trabajar!. Al menos no para obtener dinero, lógicamente. Un podría pensar sin embargo en proyectos benéficos a la sociedad, como una especie de lupa gigante para aumentar o concentrar los rayos del sol en pos de más energía. O proyectos hidropónicos para poder vivir en las alturas o en lugares donde no hay mucha tierra.
Pero el punto es que la sociedad tal cual la conocemos no tendría sentido.

Los invito entonces, a pensar diferentes aspectos de nuestra vida si fueramos vetetoides.

Miedo a las interfaces

Mi primer post (no intro) es de programación :S
Igualmente, como todo, tiene un contenido social, y psicológico, pero se va a hacer dificil de entender entre tanta maraña de cosas tecnológicas y conceptos de programación.

La pregunta introductoria al tema es: por qué la gente le tiene miedo al diseño que separa interfaz de implementación ?

Algunos se escudan en la idea de que es sobrediseño hacer esta separación, cuando actualmente solo se desarrola una única implementación.
Cuánto overhead trae este sobrediseño me pregunto ?
Otra pregunta interesante, sería, cuánta penalidad me trae tener que hacerlo después ? Y acá entran muchos factores. Por ejemplo, si trabajo con varios artefactos maven, implicaría reversionar (generar una nueva versión) del artefacto core, y si la dependencia es transitiva a partir de varios otros artefactos, tendré que refactorizar y generar nuevas versiones para cada uno.
Además, de la incompatibilidad de versiones sobre otros clientes que ya codifiqué y liberé.


Otros reniegan del hecho de que al modelarlo con interfaces, se pierde la reutilización de código.

La pregunta acá sería, cuánto código estoy realmente reutilizando ?

Y el otro punto de fondo es: qué tan efectiva es la idea de definir tipos y relaciones entre ellos a través de herencia ?
Está claro, desde el nacimiento de la herencia, que es un mecanismo poco eficaz, para cualquiera de sus dos funciones:
  • reutilizar código
  • definir tipos (función semántica)
Digo desde su creación porque según leí alguna vez en un post, cuando se introdujo esta idea a la implementación de smalltalk, no recuerdo si Alan Kay o Dan Ingalls, decían algo como "no nos convence, pero es lo mejor que pudimos hacer hasta ahora". Dando pié a cuestionamientos sobre este mecanismo.

En un lenguaje sin herencia múltiple, y con checkeos en tiempo de compilación, como java, la interface está directamente asociada con el concepto de polimorfismo, en su estado más puro. Claro, java tampoco tiene duck-typing.

En un lenguaje sin checkeo en tiempo de compilación, esta problemática sería trivial, porque simplemente puedo codificar una nueva impl que entienda los mismos mensajes y ya.
En java, en cambio, yo tengo que establecer el contrato de esos métodos, de antemano.

Entonces, me parece bien recomendar a un desarrollador no-experto, concentrarse en resolver los problemas de a uno, y no meterse a tratar de resolver todo el sistema de golpe. O a meterse en meta-niveles de programación, o meta-tareas.

Ahora, qué tan válido es seguir aplicando ese principio para un programador experimentado ? No está siendo ineficiente, solo por fanatismo ?

De todas estas estructuras mentales (porque, al final, parece que siempre buscamos lo mismo que criticamos, es decir, LA respuesta. LA forma de hacer las cosas que sea invariante, y que siempre aplique a todas las situaciones infaliblemente. El famoso silver bullet, pero conceptual, en este caso.), digo, la más simpática para mí es la de tomarse un minuto para analizar si el concepto que estamos definiendo, es decir el "tipo" merece ser considerado un concepto principal, extensible, o cuya implementación puede tener sentido variar.

Bueno ya. Me perdí un poco del objetivo del post.

Supongo ahora, en retrospectiva, que era cuestionar el por qué las personas le tienen idea a la división de interfaz vs implementación, que es una de esas prácticas que mucha gente hace de memoria. Pero en cambio, no les hacen ruido otras prácticas nefastas como las arquitecturas de DTO, o los dummy beans.

?

Intro

Acá debería contar un poco cual es mi intención al crear un blog. De qué voy a escribir, cuales son mis planes. Planificar, organizar el tiempo, ordernar las ideas, controlar el contenido.

Todas actividades inútiles.
Por qué necesitamos controlarlo todo ? por qué necesitamos estructurar las ideas.
Eso es lo que me veo forzado a hacer todos los días en el trabajo, y también todos, en menor o mayor medida, en cualquier actividad de la vida.
Como: organizarse las actividades de la semana, para ir al banco a pagar las cuentas, o para ir a comprar regalos de cumpleaños (habrá algo más feo que tener que ir a comprar regalos por cumpleaños!, sucede cada año!). Planificar gastos, ahorros, proyecciones para sacar un crédito, para comprar una casa. Planificar las vacaciones. etc.

Por qué habría de hacerlo también en un blog ?

Es lógico entonces que mi blog intente escapar de toda esa persecución paranóica del orden y de la estructura.
Permítanme la primer licencia de haber escrito, a pesar de esto, una introducción al blog.

Igualmente, este punto de vista "nihilista" frente al orden, o si quieren anárquico, no es exáctamente un pseudo ateísmo, o contraposición al orden extremo. Simplemente es contingencial. Traducción, si un día tengo ganas de organizar la información, los posts, las ideas, etc, lo haré. Pero si no, no!.

Por qué "Guardián entre el Centeno" ?
Eso se responde fácil, lean el libro "El Guardián Entre El Centeno", de J.D. Salinger. También se encuentra en castellano como "El Cazador Oculto". Ambas traducciones malísimas al gallego. Si pueden léanlo en inglés entonces como "The Catcher in the Rye".
Si esperaban una explicación directa, no la van a tener. Lean y saquen sus propias conclusiones. Si diera una explicaciónd directa, iría en contra de lo que mencioné más arriba.

Entonces esta es mi "no-introducción" al blog.
Veremos que sale de todo esto !