PrEDA: minimizando tiempo en el sistema

2017-11-22 - Categorías: PHP / PrEDA
Gantt

La gestión de los proyectos es la clave: puede marcar la diferencia entre el éxito o el desastre. La gestión de las tareas no se puede hacer de cualquier forma. Por esto que se han estudiado y se han establecido muchas estrategias. No cualquier software puede ser un buen gestor de proyectos. Por esto que existen estudios que lo integran, técnicas de programación.. y sobretodo en informática, que existen multitud de estrategias, ya que dentro de los ordenadores esto se aplica constantemente.

Los pasos clásicos a seguir son los siguientes:

  • Se establecen las tareas, fijando especificaciones.
  • Se estudian bien los tiempos que va a llevar cada tarea.
  • Se establece la estrategia para proceder.
  • Se resuelve el órden, con lo cual, aquí se obtienen las fechas de finalización de cada tarea y el tiempo total.
  • Se ejecuta el proyecto.

Como es obvio, en el primer paso se cierran especificaciones y cualquier modificación posterior invalida el algoritmo, y hay que recalcular todo.

A modo de code-kata traigo hoy una estrategia voraz para organizar un proyecto con el objetivo de minimizar el tiempo de espera de las tareas en el sistema. Suponiendo que todas las tareas son igual de importantes, se trata de hacer que esperen en total lo mínimo posible. Se trata de una estregia voraz porque simplemente se elige la siguientes tareas que menos tiempo se tarde en terminar, sin rectificar ni volver atrás. Así se terminarán primero las que menos se tarde, y más rápido se irán entregando las tareas. Otra cosa es el beneficio o la importancia que pueda tener cada tarea, pero para esto hay otro algoritmo 😉

Continuar leyendo..

Symfony: cómo montar un programador de tareas en menos de 1 hora

2017-11-21 - Categorías: PHP / Symfony
Symfony logo

Cuando has valorado bien un proyecto, y es tal el nivel de personalización que se quiere alcanzar, no queda más remedio que hacer un desarrollo artesanal, o a la larga te arrepentirás. Ya que partir de un CMS prefabricado es, a veces, más que una ayuda un lastre. Cuando quieres la máxima flexibilidad, velocidad en las modificaciones.. y por supuesto, la máxima calidad.. tienes que ir al desarrollo sobre frameworks. Ya hablé sobre esto en otro post anterior..

Hoy vengo a empezar con una serie de plugins o bundles para Symfony, hoy con uno para programar tareas. Ya sea para enviar emails transaccionales, para programar tareas de marketing, crawleos de sitios web, generar sitemaps, o lo que sea que quieras automatizar.. Aquí verás como en un rato tienes montado un estupendo programador de tareas.

Con este programador de tareas ya tienes el panel de control hecho. Es decir, te evitas la construcción del panel, y podrás ir al siguiente paso en menos de una hora. Que será directamente el ir a crear las tareas tal y como las necesites para tu proyecto 🙂

Continuar leyendo..

Magento: guardando variables globales, de configuración o del core

2017-11-13 - Categorías: Magento
Magento logo

Puede ser que necesitemos en Magento alguna forma de almacenar datos globales, es decir, que no son relacionados con ningún otro elemento individual.

Todo o casi todo en Magento tiene atributos: los productos, clientes, pedidos, direcciones, facturas, abonos, etc.. Pero para almacenar estos atributos globales tenemos dos opciones, o los guardamos como variables de configuración o como variables del core de Magento.

La diferencia es que las variables de configuración se cachean y las del core no. Muchas de las variables de configuración se pueden gestionar desde el panel de control en Sistema > Configuración. Si modificamos mediante código las variables de configuración no se refrescarán los datos, sin embargo si modificamos las variables mediante el panel de control casi todas se refrescan en el momento. Sin embargo con las variables del core esto no pasa.. conforme se guardan se tienen actualizadas al consultarlas de nuevo. Usar variables del core provoca más consultas a la base de datos, sin embargo, las variables de configuración se actualizan sólo cuando se refresca la caché de variables de configuración.

Continuar leyendo..


PrEDA: grafos, el algoritmo de Dijkstra

2017-10-29 - Categorías: PHP / PrEDA
Grafos, mapas y matrices de adyacencia

Después de haber repasado los fundamentos de los grafos: cómo se almacenan mediante matrices o listas de adyacencia, cómo se mantienen conectados mediante el algoritmo de Prim o Kruskal.. llegamos al algoritmo de Dijkstra.

Con este algoritmo, que nos sirve tanto para grafos dirigidos como no dirigidos, podemos saber cuál es el camino de menor coste desde un nodo origen a todos los demás. Usa la estrategia de programación voraz, mediante la cual, vamos construyendo la solución sin tener que volver atrás en cada decisión que vamos tomando.

Las aplicaciones de este algorimo son muchas más que los algoritmos predecesores. Por ejemplo, para calcular rutas en un mapa de carreteras, para conectar llamadas telefónicas mediante circuitos virtuales, enrutamiento de paquetes de red, coger varios autobuses/trenes/aviones minimizando coste o tiempo, buscar el mejor camino hasta el punto de recarga de un robot aspiradora, y un largo etcétera..

Estructura del algoritmo

Se basa en la selección arbitraria de un nodo origen, en el uso de un conjunto de nodos pendientes de estudiar, un vector especial que almacena el coste de llegar a cada nodo, y un vector de predecesores que guarda el nodo anterior para llegar a cada posición.

Mediante estas estructuras de datos, vamos estudiando las aristas entre nodo y nodo. Así de esta manera, se van recalculando el vector de los costes y el de los predecesores. En este ejemplo se parte del nodo inicial 0. Y se van estudiando nodo a nodo, los caminos posibles hasta el siguiente nodo en estudio. Cuando ya hemos estudiado todos los nodos, tendremos el camino de menor coste a cualquier nodo desde el nodo origen.

Por ejemplo

En este caso está configurado el script para generar grafos dirigidos:

0 --> 1(3)
1 --> 3(4) --> 2(1)
2 --> 5(2) --> 3(1)
3 --> 1(1) --> 4(4)
4 --> 6(1)
5 --> 3(5)
6 --> 4(1)
INITIAL> Not used nodes: 1-2-3-4-5-6
INITIAL> Special: 3-INF-INF-INF-INF-INF
INITIAL> Predecessor: 0-#-#-#-#-#
>>>> Found min edge! $adjacentList[0][1]=3
>>>> Next min node to use is 1
Not used nodes: 2-3-4-5-6
Special: 3-4-7-INF-INF-INF
Predecessor: 0-1-1-#-#-#
>>>> Found min edge! $adjacentList[1][2]=1
>>>> Next min node to use is 2
Not used nodes: 3-4-5-6
Special: 3-4-5-INF-6-INF
Predecessor: 0-1-2-#-2-#
>>>> Found min edge! $adjacentList[1][3]=4
>>>> Found min edge! $adjacentList[2][3]=1
>>>> Next min node to use is 3
Not used nodes: 4-5-6
Special: 3-4-5-9-6-INF
Predecessor: 0-1-2-3-2-#
>>>> Found min edge! $adjacentList[2][5]=2
>>>> Next min node to use is 5
Not used nodes: 4-6
Special: 3-4-5-9-6-INF
Predecessor: 0-1-2-3-2-#
>>>> Found min edge! $adjacentList[3][4]=4
>>>> Next min node to use is 4
Not used nodes: 6
Special: 3-4-5-9-6-10
Predecessor: 0-1-2-3-2-4
FINAL> Special: 3-4-5-9-6-10
FINAL> Predecessor: 0-1-2-3-2-4

El resultado final son los dos vectores de las dos últimas líneas. El vector especial, nos indica el coste hasta el nodo i. Por ejemplo, veamos el camino desde el nodo 0 al 4. Tiene un coste de 9 unidades y su camino se construye de atrás a adelante 4-3-2-1-0, mediante el vector predecesor. Es decir, el camino de mínimo coste posible es el 0-1-2-3-4. Si estudiamos las opciones podemos ver que así es.

El código

<?php define('NUMBER_OF_NODES', 7);
define('NUMBER_OF_EDGES_PER_NODE', 2); 
define('IS_DIRECTED_GRAPH', true); 

$adjacentList = array(); 
fillRandomCosts($adjacentList); 
printToScreen($adjacentList); 

$special = $predecessor = array(); 
dijkstra($adjacentList, $special, $predecessor); 

echo 'FINAL> Special: '.implode('-', $special).PHP_EOL
    .'FINAL> Predecessor: '.implode('-', $predecessor).PHP_EOL;

function dijkstra($adjacentList, &$special, &$predecessor)
{
    // Fill C with not used nodes.
    $C = array();
    for ($i = 1; $i < NUMBER_OF_NODES; ++$i) {
        $C[] = $i;
    }

    // Fill special distances.
    for ($i = 1; $i < NUMBER_OF_NODES; ++$i) {
        $special[$i] = distanceFromTo($adjacentList, 0, $i);
        if ($special[$i] < INF) { 
            $predecessor[$i] = 0; 
        } else { 
            $predecessor[$i] = '#'; 
        } 
    } 
    
    echo 'INITIAL> Not used nodes: '.implode('-', $C).PHP_EOL
        .'INITIAL> Special: '.implode('-', $special).PHP_EOL
        .'INITIAL> Predecessor: '.implode('-', $predecessor).PHP_EOL;

    // Study nodes in C to update $special and predecessor vectors.
    while (count($C) > 1) {
        $v = selectNextNodeThatMinimizesSpecial($adjacentList, $C, $special);
        $C = array_diff($C, array($v));

        if ($v == -1) {
            echo 'IMPOSSIBLE TO FIND DIJKSTRA WITH ALL NODES! Cannot achieve all nodes!'.PHP_EOL;
            exit;
        }

        foreach ($C as $w) {
            if ($special[$w] > $special[$v] + distanceFromTo($adjacentList, $v, $w)) {
                $special[$w] = $special[$v] + distanceFromTo($adjacentList, $v, $w);
                $predecessor[$w] = $v;
            }
        }

        echo 'Not used nodes: '.implode('-', $C).PHP_EOL
            .'Special: '.implode('-', $special).PHP_EOL
            .'Predecessor: '.implode('-', $predecessor).PHP_EOL;
    }
}

function selectNextNodeThatMinimizesSpecial($adjacentList, &$C, &$special)
{
    $minCost = INF;
    $minNode = -1;

    for ($i = 0; $i < NUMBER_OF_NODES; ++$i) {
        foreach ($C as $node) {
            if (!in_array($i, $C)
            and isset($adjacentList[$i][$node])
            and $adjacentList[$i][$node] < $minCost) { 
                echo '>>>> Found min edge! $adjacentList['.$i.']['.$node.']='.$adjacentList[$i][$node].PHP_EOL;
                $minCost = $adjacentList[$i][$node];
                $minNode = $node;
            }
        }
    }

    echo '>>>> Next min node to use is '.$minNode.PHP_EOL;

    return $minNode;
}

function distanceFromTo($adjacentList, $from, $to)
{
    if (isset($adjacentList[$from][$to])) {
        return $adjacentList[$from][$to];
    } else {
        return INF;
    }
}

function fillRandomCosts(&$adjacentList)
{
    for ($i = 0; $i < NUMBER_OF_NODES; ++$i) {
        $added = false;
        while (!$added) {
            for ($j = 0; $j < NUMBER_OF_EDGES_PER_NODE; ++$j) {
                $adjacentNode = rand(0, NUMBER_OF_NODES - 1);
                if ($adjacentNode != $i and $adjacentNode != $j) {
                    $adjacentNodeCost = rand(1, 5);
                    $adjacentList[$i][$adjacentNode] = $adjacentNodeCost;
                    if (!IS_DIRECTED_GRAPH) {
                        $adjacentList[$adjacentNode][$i] = $adjacentNodeCost;
                    }
                    $added = true;
                }
            }
        }
    }
}
function printToScreen($adjacentList)
{
    for ($i = 0; $i < NUMBER_OF_NODES; ++$i) { echo $i; foreach ($adjacentList[$i] as $key => $value) {
            echo ' --> '.$key.'('.$value.')';
        }
        echo PHP_EOL;
    }
}


PrEDA: grafos, el algoritmo de Prim

2017-10-26 - Categorías: PHP / PrEDA
Grafos, mapas y matrices de adyacencia

Hoy vuelvo a traer otro code-kata, siguiendo con la serie de algoritmos de programación relacionados con los grafos. Esta vez se trata del algoritmo de Prim, que sirve para calcular el árbol de recubrimiento de mínimo coste de un grafo.

Es decir, tenemos un grafo que se compone de nodos, que se interconectan mediante aristas. Dichas conexiones entre nodo y nodo, tienen un coste. Entonces queremos hallar la forma de interconectar todo con el mínimo coste. Una aplicación directa de esto puede ser para una red de ordenadores, eléctrica, tuberías, carreteras, etcétera.. mediante este algoritmo puedes obtener la forma de mantener conectados todos los nodos del grafo con el mínimo coste.

Continuar leyendo..

PrEDA: grafos y mapas, ahora guardando en una lista de adyacencia..

2017-10-23 - Categorías: PHP / PrEDA
Grafos, mapas y matrices de adyacencia

Continuando con el post de ayer sobre cómo crear una matriz de adyacencia a partir de un mapa aleatorio, traigo otro code-kata. Es el mismo ejercicio de ayer, pero hoy para sacar en claro cómo almacenar un grafo en una lista de adyacencia.

¿Porqué una lista o matriz de adyacencia va a ser mejor o peor? Dependerá de cada grafo. Si el grafo es muy denso, porque tiene muchas aristas entre nodo y nodo, está demostrado que es mejor usar una matriz. Pero si el grafo es poco denso es mejor usar una lista de adyacencia.

Continuar leyendo..

PrEDA: grafos, generando mapas aleatorios y su matriz de adyacencia..

2017-10-22 - Categorías: PHP / PrEDA
Grafos, mapas y matrices de adyacencia

Vuelvo de nuevo a traer otro code-kata. Esta vez estoy tratando de sacar en claro cómo generar matrices de adyacencia para trabajar con los grafos asociados a mapas. En este escenario tenemos un mapa, que se genera aleatoriamente. En cada casilla tenemos un coste de movernos a dicha casilla. Sólo podemos movernos a la casilla adyacente, como si se tratara del movimiento de un peón de ajedrez.

Así pues, si estamos en la casilla (0,0) sólo podremos movernos a la (0,1), (1,1) y la de abajo, la (1,0). Así que ese coste de ese movimiento se representa por el valor del mapa generado. Y ese coste se guarda en la matriz de adyacencia como valor de la arista.

Continuar leyendo..

¿Por qué tener un blog? ¿Sirve para algo?

2017-10-15 - Categorías: General / SEO

Últimamente he pensado mucho sobre los blogs. He quitado los anuncios del mío. He preguntado y leído mucho, sobre SEO, branding, SEM, mailing, redes sociales, etc.. para buscar la respuesta a si debemos mantener un blog. Qué relación hay entre todos los canales de entrada a tu negocio de Internet. Así que, aquí estoy de nuevo escribiendo los resultados de esta experiencia.

La pregunta que se hace mucha gente es.. ¿Por qué mantener un blog? Esta pregunta te puede derivar a varias relacionadas como.. ¿En qué me beneficia tener un blog? ¿Me beneficia? ¿A mi empresa le interesa tener un blog? ¿Me interesa tener un blog personal?

Continuar leyendo..

Estudiando logs de CloudFront con GoAccess

2017-10-13 - Categorías: Amazon Web Services / General / GNU/Linux
Vista de GoAccess

Quizá tienes que estudiar los registros de visitas de un proyecto que está en una nube, detrás de un CloudFront de Amazon Web Services. En este proyecto tenemos guardados los registros de las peticiones web que tenemos a los servidores. A veces es interesante revisarlos a este nivel.

Es decir, que tenemos registros de las visitas, anonimizados, por ejemplo con Google Analytics. Pero pasan muchas más cosas por debajo de Google Analytics que sólo quedan reflejados en los registros de los servidores. Así que resulta que queremos saber absolutamente cuáles han sido todos los registros. Queremos saber qué IPs son las que más nos visitan. Qué consultas al servidor son las que están provocando errores de servidor, los 500, incluso antes de que lleguen los robots que nos indexan. Qué IPs son de robots que nos están crawleando, o indexando, y un largo etcétera. Probablemente aquí veamos las IPs de los robots de Google, Bing, Yahoo que nos visitan en busca de información de la web..

Continuar leyendo..

PrEDA: el algoritmo de ordenamiento Mergesort

2017-10-09 - Categorías: PHP / PrEDA
Números

De nuevo con otro code-kata ya estoy por aquí de nuevo. Se trata ahora de un algoritmo más sencillo que los anteriores. El Heapsort se apoya en montículos para su ordenamiento. El Quicksort hace un pivotaje algo complejo para hacer la división del vector en dos más simples. En este caso, el Mergesort, hace un ordenamiento más simple.

Mergesort aplica la estrategia de divide y vencerás para hacer el ordenamiento. Con esto, tenemos que un vector de números desordenado se divide en dos. Estos dos subvectores se ordenan por separado usando Mergesort recursivamente. Y al tenerlos ordenados, se fusionan en un vector final cogiendo elementos de uno u otro vector en orden creciente.

Continuar leyendo..

© 2024 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.