Mostrando entradas con la etiqueta desarrollo. Mostrar todas las entradas
Mostrando entradas con la etiqueta desarrollo. Mostrar todas las entradas

8 de julio de 2011

[PHP] Verificación de entradas en arrays multidimensionales (2/2)

conjuntoEntradas() {
  [PHP] Verificación de entradas en arrays multidimensionales (1/2)
  [PHP] Verificación de entradas en arrays multidimensionales (2/2)
}


Llegado al punto que al no ser las dos opciones comentadas en el primer post de esta serie de mi gusto por el motivo que ya expuse, además estar desfavorecidas frente a otras, por su menor rendimiento en velocidad de ejecución, podría haber optado por tirar por el derecho y decidir utilizar la función isset(), es decir la que en el comentario de la documentación de función is_null(), se dejaba claro que era la más óptima entre estas tres opciones.

No obstante, durante mi búsqueda de como hacer la verificación de la existencia de claves dentro de los arrays multidimensionales, me tope con otra función, que por nombre y definición (Verifica si el índice o clave dada existe en el array) debería ser la más apropiada para realizar dicho menester; estoy hablando de la función array_key_exists().

No obstante, en los comentarios de la documentación de array_key_exists(), alguien y había comentado la diferencia de velocidad de ejecución con isset(), siendo de nuevo, favorable para ésta última.

Aún habiendo este comentario, yo quería hacer mis pruebas, ya que al final del comentario, se menciona que la diferencia de rendimiento no es tan grande en un sistema operativo Mac o Linux, como lo es un MS Windows; además la prueba del comentario se realiza sobre un array unidimensional y no multidimensional, que son con los que yo me iría encontrando en mis implementaciones y por otra parte, me entró la vena friki por realizar la prueba sobre un profiler, y como ya había utilizado en una vez anterior, el elegido fue Xdebug, utilizando, con el mismo motivo, el visor KCachegrind; así que manos, la obra.

Primero la implementación de las funciones que me permitirán discernir entre las dos distintas formas de verificar la presencia de claves en arrays multidimensionales con la función array_key_exists().

function aa_verificacion_a_una_instruccion_fallo_2d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave2.5', $var1['clave1.3'])) {
        }
    }
}

function ab_verificacion_por_dimension_fallo_2d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                (array_key_exists('clave2.5', $var1['clave1.3']))) {
        }
    }
}

function ba_verificacion_a_una_instruccion_fallo_3d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1'])) {
        }
    }
}

function bb_verificacion_por_dimension_fallo_3d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']) ) {
        }
    }
}

function ca_verificacion_a_una_instruccion_fallo_4d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}

function cb_verificacion_por_dimension_fallo_4d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave3.0', $var1['clave1.3']['clave2.1']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}


function da_verificacion_a_una_instruccion_fallo_3d_sobre_4d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.1'])) {
        }
    }
}

function db_verificacion_por_dimension_fallo_3d_sobre_4d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave3.1', $var1['clave1.3']['clave2.1']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}
Aunque se podía intuir con total certeza que la verificación a una instrucción, directamente haciendo referencia a la clave en la dimensión que se quiere verificar, será más óptima que la verificación dimensión por dimensión hasta llegar a la profundidad de la dimensión que realmente se quiere comprobar; opté por realizar la prueba y así poder ver de manera cuantificable la diferencia que había, y tener que tragarme mis gustos y optar por hacer la comparación con isset(), haciendo referencia a posiciones de memoria inexistentes si las dimensiones de menor profundidad a al que se quiere verificar, ya no existen, como a comenté en la primera entrada de esta serie. Los resultados obtenidos fueron estos:

 Diagrama de llamadas a funciones de comparación de la dos maneras de utilizar array_key_exists()

Diagrama de llamadas a funciones de comparación de la dos maneras de utilizar array_key_exists() de menos a mayor % utilizado 

Bueno, una vez hecho un poco el ganso, tocaba realizar la comprobación definitiva, comparar la eficiencia de ejecución entre array_key_exists() e isset(), así que esté fue el script que utilicé:
function aa_usando_array_key_exists($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}

function ab_usando_isset($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (isset($var1['clave1.3']['clave2.1']['clave3.0']['clave4.1'])) {
        }
    }
}

function ba_usando_array_key_exists_fallo_dimension_anterior($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.5']['clave3.0'])) {
        }
    }
}

function bb_usando_isset_fallo_dimension_anterior($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (isset($var1['clave1.3']['clave2.1']['clave2.5']['clave4.1'])) {
        }
    }
}
Y los resultados obtenidos fueron estos:


Diagrama de llamadas a funciones de comparación entre la utilización de array_key_exists() e isset()


Diagrama de llamadas a funciones de comparación entre la utilización de array_key_exists() e isset() de menos a mayor % utilizado

Así que como dice el dicho, “una imagen vale más que 1000 palabras”, la eficiencia queda demostrada.

Para concluir solo me queda aclarar un aspecto que alguno le debe descuadrar; se trata de ¿porqué en el caso de la utilización de isset() no tengo ninguna pega por lo que he comentado con el resto? Me refiero al hecho de no gustarme hacer referencias a posiciones de memoria inexistentes. Pues bien, el caso de isset() lo veo sustancialmente distinto, ya que por definición la función sirve para “determinar si una variable esta definida y no es NULL”, así que aparte de considerar que lo que va a hacer es verificar la existencia o inexistencia de una posición de memoria (en términos de definición de posiciones de memoria alocadas en tu programa), si la posición no existe no aparece ningún mensaje de notificación informando de ello, claro está sin anteponer @ a la llamada de la función; así que no me da la sensación de estar realizando algo que no es del todo correcto.


Hasta la próxima enfermos.

19 de junio de 2011

[PHP] Verificación de entradas en arrays multidimensionales (1/2)

conjuntoEntradas() {
  [PHP] Verificación de entradas en arrays multidimensionales (1/2)
  [PHP] Verificación de entradas en arrays multidimensionales (2/2)
}

Ya hace un tiempo que empecé un desarrollo de unas de mis pajas mentales con el conocido framework Web MVC (Model View Controller) denominado Zend Framework. Desde que empecé este desarrollo, el cual he tenido que interrumpir en algunas algunas ocasiones por ciertas obligaciones las cuales me gusté o no tengo que darle preferencias, además de solo poderle dedicar parte de los días que no me empleo en la empresa en la cual estoy contratado a tiempo completo, y digo parte, porque me es imposible no dedicar una parte de esos días a descansar, atender asuntos personales, buscarme la vida por otras partes o hacer otros hobbies muy necesarios para mí, me han ido surgiendo dudas sobre ciertos aspectos del lenguaje PHP; uno de ellos ya lo dejé plasmado en una entrada en este mismo blog hace algún tiempo.

Cuando empecé a descubrir las cosas que me ofrece el propio framework, a día de hoy aún me queda alguna cosa que funcionalidad más bien no por descubrir, sino por utilizar y conocer bien como se utiliza, me dí cuenta que a medida que iba desarrollando mis idas de olla, podría ir modularizando ciertos componentes, que me podrían servir para futuras pajas mentales, además de poder utilizar de manera extensiva en el desarrollo de esta; es decir lo que resumiríamos en arquitecturar código de programación para favorecer el reaprovechamiento mediante creación de componentes genéricos; algo así como ya han hecho los propios desarrolladores de dicho Zend Framework, de ahí que haya acabado en eso, en un framework.

Con todas esta paranoia que me dio y me continúa dando, por el reaprovechamiento basándome en la modularización; una de las cosas que más utilizo es la configuración de los componentes mediante ficheros de configuración, ya sean INI o XML, para poder reutilizarlos sin tener que escribir código de programación.

Zend Framework, ofrece unas clases para leer este formato de ficheros, y alguno más, y después poder obtener un array multidimensional de clave=>valor para posteriormente poder tratar el contenido desde PHP de una manera sencilla. De hecho el propio framework utiliza estos formatos para especificar las configuraciones de la aplicación web que se va a desarrollar y también para configurar parte de sus componentes.

Al empezarlo a utilizarlos en mis componentes y ver que necesitaba, en muchos casos, verificar la existencia de ciertos parámetros obligatorios en los ficheros de configuración, y esto lo tenía que hacer con la verificación de la existencia de claves dentro de los arrays multidimensionales, descubrí que desde PHP se ofrecen varias funciones o maneras de poder verificar la existencia de valores dentro de arrays, así que la paranoia de la optimización se apoderó de mi, provocando una curiosidad, necesaria por hacer cada componente algo más óptimo, por saber cual de ellas tiene un mayor rendimiento en cuanto a velocidad de proceso.

En los comentarios que dejan los usuarios en la documentación de PHP, en varias de las funciones que se pueden utilizar para verificar la existencia de claves, ya se puede saber que algunas de ellas son más óptimas que otras, por ejemplo, la función is_null(), tiene un rendimiento mucho peor que la comparación directamente con NULL, pero esta tiene un rendimiento más bajo si la comparamos con isset(), no obstante de todos estas funciones, aunque nos podrían servir para verificar la existencia de una clave, a mí, particularmente, no me gusta mucho tener que hacer referencia a valores que no van a existir si la clave no existe, que sería lo que tendríamos que hacer con is_null() y con la comparación con NULL, pongamos un ejemplo:

Defino un array que voy a utilizar para todos mis ejemplos y pruebas, dentro de este conjunto de entradas

$var1 = array(
        'clave1.0' => 'valor1.0', 
        'clave1.1' => 'value1.1',
        'clave1.3' => array (
            'clave2.0' => 'value2.0', 
            'clave2.1' => array(
                'clave3.0' => array(
                    'clave4.0' => 'value4.0'
                )
            )
        )
    );

Si quisiéramos verificar la existencia de una clave, con las dos maneas que he comentado, tendríamos que hacer lo siguiente:

if (is_null($var1['clave1.4'])) {
      print "La clave1.4 no exise \n";
  }

  if($var1['clave1.4'] === NULL) {
      print "La clave1.4 no exise \n";
  }

Funcionar, funciona pero no me gusta, porque para la verificación accedemos a una posición del array inexistente, por lo cual se genera para ambos caso el siguiente mensaje de notificación (eso si tenemos el PHP configurado para que notifique los errores del nivel NOTICE):

  PHP Notice: Undefined index: clave1.4 in /path/al/script.php on line NN

Aunque dicho mensaje podríamos provocar que no apareciese anteponiendo @ delante la función o delante la variable en el caso de la comparación con NULL.


Hasta la próxima enfermos.

19 de marzo de 2011

[PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)

conjuntoEntradas() {
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)
}


El rendimiento

Hasta aquí podía apaliar una de mis inquietudes, que era el nivel de integridad de los atributos de un objeto para cada una de las maneras de tratar los parámetros de los métodos y su asignación a estos, pero todavía me quedaba otra pendiente, que era saber el rendimiento de cada una de estas formas.

Ya se que en el rendimiento de una aplicación están involucrados muchos factores y cuando tu escribes un código, el orden de ejecución de las instrucciones puede ser alterado por el compilador con el objetivo de optimizar el código para una ejecución más eficiente, no obstante siempre que programa y me encuentro delante de los ojos que el orden de ciertas instrucciones podría ser cambiado, a priori por una más optima, si no me aleja enormemente de lo que estoy haciendo, hago el refactoring, o sino me lo marco con @todo; ya sé que ha veces esto puede ser un poco de maniático o de paranoico, pero es algo intrínseco en mi personalidad junto con la concepción de que las pequeñas cosas forman el todo, por lo que si ese pequeño cambio puede llegar a optimizar una mil millonésima parte de la ejecución, lo aplico de todas formas, siempre pienso “mejor eso que nada”.

Bueno dejando de lado mis paranoias, os dejo la modificación del código de la prueba anterior de manera que me permitiera analizar la carga de ejecución de cada manera de pasar parámetros y de asignación de estos atributos.

class A {
    private $arrValor;
    private $arrValorToRef;
    private $arrReferencia;
    private $arrRefToRef;
    

    public function setArrayByValue(array $setArr) {
        $this->arrValor = $setArr;            
    }

    public function setArrayByValueToRef(array $setArr) {
        $this->arrValorToRef = &$setArr;            
    }

    public function setArrayByRef(array &$setArr) {
        $this->arrReferencia = $setArr;
    }

    public function setArrayByRefToRef(array &$setArr) {
        $this->arrRefToRef = &$setArr;        
    }

}


$numIt = 1000000;
$arr = array('key0' => 'value0');
$objA = new A();

for ($it = 0; $it < $numIt; $it++) {
    $objA->setArrayByValue($arr);
    $objA->setArrayByValueToRef($arr);
    $objA->setArrayByRef($arr); 
    $objA->setArrayByRefToRef($arr);
}

La modificación del script de prueba está clara, solo he dejé en los métodos de las clases declarada la asignación del parámetro al atributo, que es lo que quería comparar a nivel de coste de ejecución, y en la ejecución del script iterar unas cuantas vueltas dentro de un bucle la llamada a los cuatro métodos.

Para saber el coste de ejecución lo que hice es ejecutar el script en un profiler, concretamente el de xdebug; hice dos pruebas, una con 1.000.000 iteraciones y otra con 3.000.000 de iteraciones; ¿porqué tantas? para que el profiler pudiese medir con mayor precisión la diferencia entre cada llamada y ¿porqué dos veces?, para ver si los valores se obtenidos daban valores diferenciales similares entre las llamadas de los distintos métodos.

El resultado que obtuve fue el siguiente:

 Gráfico de llamadas a los métodos con 1.000.000 de iteraciones


Tabla de porcentaje de tiempo de carga sobre el total de llamada a los métodos con 1.000.000 de iteraciones

Gráfico de llamadas a los métodos con 3.000.000 de iteraciones

Tabla de porcentaje de tiempo de carga sobre el total de llamada a los métodos con 3.000.000 de iteraciones

Después de los resultados obtenidos a partir de los ficheros generados por el profiler con la ejecución del script, y haber sacada los gráficos y las tablas anteriores de cada ejecución con el visor kcachegrind, me decidí a poner los valores en un hoja de cálculo para poder analizar de manera más cómoda los resultados.

 Valores de los resultados, medias y diferencias entre ellos

Como podemos observar, y era de esperar, el método más eficiente es pasar el parámetro por referencia y asignar la referencia al atributo, ya que no se hace ninguna copia del array pasado por parámetro. Lo más curioso es que el siguiente más eficiente es el método que se pasa el parámetro por valor y se asigna por valor (setArrayByValue), estando por delante de los otros dos, yo, si no hubiese hecho esta prueba, hubiese intuido que éste sería el menos eficiente, ya que debería estar haciendo dos copias del array, una cuando lo pasa por parámetro y la otra cuando lo asigna a la variable, mientras que los otros dos deberían tener costes similares ya que hacen una copia del array.

Conclusiones

Después de lo visto tengo claro que para mantener la integridad y el encapsulamiento de los atributos de una clase en PHP, tengo que pasarlo por parámetro y asignarlos por parámetro, ya que si todo son referencias (parámetro y asignación al atributo), como ya suponía, los valores pueden ser modificados desde fuera; además después, de lo observado, también tengo claro que de nada sirve pasar el parámetro o asignarlo al atributo por referencia, ya que no introduce optimización ninguna, es más, el rendimiento disminuye, ya que la ejecución es más costosa.
Además de todo esto, me puedo despreocupar de que ciertas referencias queden apuntando espacios de memoria liberados, ya que el interprete garantiza la destrucción de los espacios de memoria, solo cuando no haya ninguna variable que pueda referenciar a éste.


Hasta la próxima enfermos.

12 de marzo de 2011

[PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)

conjuntoEntradas() {
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)
}


Introducción

Realizando mis jugueteos con la programación en PHP, una de las cosas que necesitaba hacer era pasar arrays a objetos de clases creadas por mi mismo; en algunas de estas clases he considerado oportuno mantener los valores que se pasan por parámetro a través de un array en uno de los atributos de la clase debido a que me pueden ser necesarios para realizar operaciones futuras con o sobre esos valores.

Hasta aquí nada nuevo, ya que es una práctica muy utilizada; pero a mí, que no soy, para nada, un “ninja” del PHP, me hizo pensar que realmente sucedía al pasar un array por parámetro de las distintas maneras que permite el lenguaje, valor o referencia y la manera de asignarlo a un atributo, valor o referencia. Por mis conocimientos, sabía los distintos comportamientos que podían suceder pero, al no estar seguro de cual sería el que se aplicaría en PHP, y si teniendo lo muy claro en otros lenguajes donde tu puedes controlar las posiciones de memoria con referencias y, con mayor control, con punteros, como es el caso de C y su hermano C++.

Como después de buscar y revisar un poco la documentación y algunos enlaces de cuatro búsquedas por Internet no me continuaba sin quedar del todo claro, decidí hacer un script PHP muy simple que me permitiera observar el comportamiento del lenguaje antes esta común situación.
La pequeña prueba
El script que cree, hace lo siguiente:
  1. Declara una clase con:
    • Tres atributos; uno para almacenar el parámetro que se pasará a a cada uno de los tres métodos declarados.
    • Tres métodos, cada uno recibe un array por parámetro, pero uno lo recibe por valor y los otros dos por referencia; la diferencia entre los dos métodos que reciben el array por referencia está en su interior, además de que cada uno asigna el array a un atributo distinto, uno lo asigna el valor y otro asigna la referencia.
      Cada método, además de asignar el array a un atributo, realiza una modificación (añade un nuevo valor) en el array pasado por parámetro.
    class A {
        private $arrValor;
        private $arrValorToRef;
        private $arrReferencia;
        private $arrRefToRef;
        
    
        public function setArrayByValue(array $setArr) {
            $this->arrValor = $setArr;
            $setArr['keyMarkClassAValue'] = 'valueMarkClassA';
            $this->arrValor['keyClassA'] = 'valueClassA';
        }
    
        public function setArrayByValueToRef(array $setArr) {
            $this->arrValorToRef = &$setArr;
            $setArr['keyMarkClassAValueToRef'] = 'valueMarkClassA';
            $this->arrValor['keyClassA'] = 'valueToRefClassA';
        }
    
        public function setArrayByRef(array &$setArr) {
            $this->arrReferencia = $setArr;
            $setArr['keyMarkClassARef'] = 'refMarkClassA';
            $this->arrReferencia['keyClassA'] = 'refClassA';
        }
    
        public function setArrayByRefToRef(array &$setArr) {
            $this->arrRefToRef = &$setArr;
            $setArr['keyMarkClassARefToRef'] = 'refToRefMarkClassA';
            $this->arrRefToRef['keyClassA'] = 'refToRefClassA';
        }
    
    }
    
  2. Declara una array con un valor en su interior, el que se utilizará para pasarlo a los tres métodos de un objeto, de la clase declarada, creado.
    $arr = array('key0' => 'value0');
    
  3. Se van realizando dumpeos del array utilizado como parámetro y del objeto a medida que se van ejecutando los métodos para observar comportamiento.
    print "Contenido del array \$arr antes de asignarlo a la clase: \n";
    var_dump($arr);
    print "\n";
    
    $objA = new A();
    $objA->setArrayByValue($arr);
    
    print "Contenido del array \$arr despues de asignarlo a la clase por valor: \n";
    var_dump($arr);
    print "\n";
    
    $objA->setArrayByRef($arr);
    
    print "Contenido del array \$arr despues de asignarlo a la clase por referencia: \n";
    var_dump($arr);
    print "\n";
    
    $objA->setArrayByValueToRef($arr);
    $objA->setArrayByRefToRef($arr);
    
    print "Contenido del object de A despues de asignarle el array (valor y referencias): \n";
    var_dump($objA);
    print "\n";
    
    $arr['newKey'] = 'newValue';
    
    print "Contenido del object de A despues de ejecutar \$arr['newKey'] => 'newValue': \n";
    var_dump($objA);
    print "\n";
    
    unset($arr);
    
    print "Contenido del object de A despues de ejecutar un unset() del array: \n";
    var_dump($objA);
    print "\n";
    

El encapsulamiento

Con la salida que genera el script podemos llegar a ciertas conclusiones sobre lo que sucede con la asignación del array pasado por parámetro a los atributos del objeto, con las distintas maneras que se permiten, y ver si realmente el atributo del objeto mantiene una referencia a esa posición de memoria o copia el valor, desde el punto de vista de utilización habitual del lenguaje, es decir sin buscar saltarnos lo establecido, ya que al referirme que se puede estar copiando el valor del array a otra posición de memoria, me refiero a la percepción que se tiene como desarrollador, dejando de lado el funcionamiento interno del interprete, ya que este podría estar optimizando el rendimiento de la ejecución demorando la copia de los valores a una nueva posición de memoria hasta el momento antes de que alguno de los valores de la variable sufra una modificación, garantizando e esta manera la integridad de los valores de cada variable.

El resultado obtenido es el siguiente:
  1. Parámetro por valor y asignación por valor. Variable pasada por parámetro y atributo utilizan su propio espacio de memoria.
  2. Parámetro por valor y asignación por referencia. Variable pasada por parámetro es copiada a un nuevo espacio de memoria ya que cuando se asigna por referencia al atributo (su dirección de memoria), los cambios en los datos de cada variable son independientes.
  3. Parámetro por referencia y asignación por valor. Variable pasada por parámetro, supuestamente no es copiada, ya que se está pasando por referencia, pero al asignarla al atributo es cuando se realiza una copia de los datos de esta variable a nuevo espacio de memoria que será donde apuntará el atributo al que se está asignando.
  4. Parámetro pasado por referencia y asignación por referencia. No hay copias de los datos a nuevos espacios de memoria por lo que, tanto la variable pasada por parámetro como el atributo apuntan al mismo espacio de memoria.

Con las cuatro pruebas anteriores se puede deducir que las referencias en PHP son tratadas como en otro lenguaje, como C/C++ (donde el control de la memoria depende totalmente del desarrollador), pero con algo menos de liberta, ya que el lenguaje controla el número de variables que apuntan al mismo espacio de memoria y bajo la existencia de una sola, se imposibilita su liberación impidiendo que una variable haga referencia a un espacio de memoria destruido (caso b), además de también imposibilitar la liberación solicitada explícitamente (unset).

Esto ya me permitía saber que sucedía, en PHP, con los arrays, cuando son utilizados como parámetro en una función/método y en las asignaciones a nuevas variables, pudiendo decidir como hacerlo, si por valor o por referencia, en función de lo que realmente quiero hacer con ellos.
Este tipo de dudas siempre se me plantean con los lenguajes, donde el control de la memoria se hace automáticamente mediante un garbage collector, ya que en algunos, como Java, que aunque no existe el concepto de referencia y valor, si que existen los immutable objects en el mismo JDK, provocando un comportamiento distinto, en objetos de ciertas clases, delante de estos casos.

Hasta la próxima enfermos.

29 de enero de 2011

Borrados suaves


Después de haber dado con la característica de "borrados suaves" (Soft Deletions) de las BBDD de Lotus Notes, me puse a mirar a lo largo de los días, entre los pocos minutos de "relax" que quedan entre las constantes intervenciones, a mirar y probar un poquito el funcionamiento de esta característica, ya que parece que se puede usar de manera intrínseca en las BBDD de Lotus Notes de la versión 8.5.
El objetivo del que partía en dedicarle esos poco minutos era el de valorar el coste (en horas de trabajo), de ponerla a funcionar, que nos requeriría dotar a las prehistóricas BBDD que pululan por la empresa.
Mis intuiciones, parecieron estar por el buen camino, cuando descubrí esta Technote. Una vez que la leí, todo parecía indicar de podríamos hacer que las prehistóricas BBDD pudiesen “borrar suavemente”, sin a penas la necesidad de tener que modificar su implementación.
Visto esto, antes de empezar a modificar la “genética de los dinosaurios”, quise hacer un test sobre una simple nueva BBDD; así que a continuación dejo el simple test que realicé.

  1. Creé una nueva simple BBDD utilizando una de las plantillas que vienen con la instalación del cliente Lotus Notes (Microsoft Office Library).

    Dialogo de creación de una nueva BBDD de Lotus Notes

    No obstante antes de aceptar la creación, me puse a revisar las opciones avanzadas.

    Dialogo de creación de una nueva BBDD de Lotus Notes

    Como se puede observar en la imagen anterior, es posible activar, en su creación, el “borrado suave” y el tiempo en el que será posible recuperar los documentos eliminados, es decir que estarán en la “papelera”, antes de ser eliminados por completo.

  2. Con la BBDD creada, metí algo de información para empezar a hacer las pruebas.

    La BBDD con la información de de test que he metido

  3. Sin haber activado el "Soft Deletions", eliminé un documento (con los nombres tan explícitos que les puese a cada una de la entrada de datos ya podeis ver quien era el candidato).

  4. Activé el "Soft Deletions", y repetí la operación del paso 3, esta vez con otro documento (como el anteior documento borrado, se puede intuir de cual se trata).

  5. Lo siguente fué realizar la modificación en el diseño de la BBDD que indica la Technote.

    Abrí la BBDD con el designer (cliente de Lotus Notes para desarrollar nuevas aplicaciones Lotus) y cree la vista, del tipo indicado, que va a permitir visualizar los documentos eliminados “suavemente” y cuyo periodo de cuarentena no ha vencido, es decir que no haya caducado y por lo tanto no se ha eliminado definitivamente.

    Dialogo de creación de una nueva vista

    Árbol de recursos de la BBDD con la nueva vista creada (Basura)

  6. Guardé los cambios en el diseño dela BBDD y cerré el designer.

  7. Abrí de nuevo la BBDD en el cliente de Notes, viendo que aparecía la vista creada anteriormente, que había denominado Basura.
    Pinché en la vista y en ella, pude visualizar el documento que había borrado, después de haber activado el “Soft Deletions”, por otra parte y esperando que así pasara, el documento que había eliminado antes activarlo no aparecía en lugar alguno.

  8. Para rematar el test también probé de eliminar, ahora que el “Soft Deletions” estaba activado y la vista estaba creada, el documento que había creado para ser eliminado bajo esta situación y como era de esperar, el documento se había eliminado pero era visible a través de la vista “Basura”.

  9. Por último también comprobé, como también era de esperar, que pasado el periodo de vencimiento del borrado, es decir el tiempo que se había indicado que permanecerían los documentos eliminados antes de su destrucción permanente, los documentos habían desaparecido de la vista “Basura”.


Hasta la próxima enfermos.