jueves, 19 de mayo de 2022

ordenamiento bubble sort, quicksort y sin implementar en java.

version en video.


 

ordenar es poner las cosas siguiendo un orden(que viva la redundancia) por ejemplo podemos ordenar un numero de mayor a menor (5,4,3,2,1) o de menor a mayor (1,2,3,4,5) y en programacion existen muchos metodos de ordenamiento siendo uno de los mas sencillos de implementar bubble sort.

Bubble Sort.

es un método de ordenamiento donde iterativa mente vamos por toda la lista de elementos comparando el valor actual con el anterior (y rotandolos cuando no estan en orden) esto se hace cuantas veces como se necesite hasta que ido por todo el arreglo sin tener que rotar nada (significando esto que ya esta en orden).

es un algoritmo muy sencillo y tambien muy ineficiente en promedio toma O(n*n)  *1

en java se puede implementar de la siguiente manera.


 public static void main(String args[]) {
      int[] array = {13, 14, 42, 54, 56, 38, 97, 24, 57};
      bubbleSort(array);
      printArray(array);
  }

  public static boolean printArray(int[] input) {
      if (input.length == 0) {
          return false;
      }
      for (int i = 0; i < input.length; i++) {
          System.out.println(" " + input[i]);
      }
      return true;
  }

  public static boolean bubbleSort(int[] input) {
      if (input.length < 2) return false;
      boolean isInOrder;
      do {
          isInOrder = true;
          for (int i = 1; i < input.length; i++) {
              if (input[i - 1] < input[i]) {
                  int temporal = input[i - 1];
                  input[i - 1] = input[i];
                  input[i] = temporal;
                  isInOrder = false;
              }
          }
      } while (!isInOrder);
      return true;
  }


otro algoritmo muy conocido y que es creo de los que mas se usa es 

 

Quick Sort 


quicksort(ordenamiento rápido) y gusta bastante por que:

  • es rápido en promedio toma O(nlogn)
  • toma menos tiempo si los registros estan parcialmente ordenados(es verda en muchos casos)
  • optimiza bien el uso de cache *3

yo para entender  este algoritmo tuve que ver este video donde se explica muy bien *3.

el algoritmo es mas o menos asi.

  • usted empieza con un array (posiblemente desordenado)
  • tiene un metodo para ordernarlo(quicksort) que recibe este array, un minimo que es 0 el inicio del array y el tamaño del array(el intervalo que va ordenar)
  • este metodo despues de revisar que el min sea menor que el maximo llama a otro metodo que se encarga de encontrar una "particion" y mientras lo hace organiza los mas pequeño que la particion a la izquierda y lo mas grandes a la derecha (ordena no todo sino simplemente lo mayor y menor que donde esta la particion)
  • luego teniendo el index de esa particion se vuelve a llamar el metodo inicial dos veces una del inicio a la particion, y otra de la particion(el index de la misma hasta el tamaño original)
  • esto se sigue repitiendo recursivamente hasta que se acaba organizando todo.

entrando mas en detalle en el metodo que hace la particion se encarga de lo siguiente.

  • setea una variable i con el inicio/minimo y una variable j con el maximo/final
  • determina un pivote o elemento en el array para comparar(al inicio o al final del array generamente por facilidad, pero tambien se puede en en cualquier punto.
  • empieza a aumentar el i mientras lo que se encuentre sea menor que el pivote(osea que ya esta organizado con respecto al pivote), y a disminuir j mientras lo que se encuentre sea mayor que el pivote(osea que ya esta organizado en relacion al pivote)
  • si i es menor que j, es decir encontraron uno mayor y uno menor donde no debian estar estos se intercambian.
  • esto se repite y al final el pivote se pone en el "medio"(cambiando la variable en la poscision del pivote y la j) de manera de que queden menores a la izquierda y mayores a derecha del mismo
  • se retorna j, ya que en la poscision de j esta el pivote solo queda organizar las otras dos mitades usandolo.

en java una forma de implementar quicksort seria la siguiente.


public class mainClass {

    public static void main(String[] args) {
        int[] input = {1, 10, 10, 8, 6, 10, 1};
        quickSort(input, 0, input.length);
        printArray(input);
    }

    public static boolean printArray(int[] input) {
        if (input.length == 0) return false;
        System.out.println("");
        for (int i = 0; i < input.length; i++) {
            System.out.print(input[i] + " ");
        }
        return true;
    }

    public static void quickSort(int[] input, int min, int max) {
        if (min < max) {
            int j = partition(input, min, max);

            quickSort(input, min, j);
            quickSort(input, j + 1, max);
        }
    }

    public static int partition(int[] input, int min, int max) {
        int i = min;
        int j = max;
        int pivot = input[min];

        while (i < j) {
            do {
                i++;
            } while (i < input.length && input[i] < pivot);
            do {
                j--;
            } while (input[j] > pivot);
            if (i < j) {
                switchTheVariables(input, i, j);
            }
        }
        switchTheVariables(input, min, j);
        return j;
    }

    public static void switchTheVariables(int[] input, int a, int b) {
        int temporal = input[a];
        input[a] = input[b];
        input[b] = temporal;
    }

}

 implementar quicksort o bubble sort tan literal es interesante como ejercisio pero creo que tiene mas sentido utilizar el ordenamiento que ofrece el lenguaje, para ordenar en java podemos hacerlo asi

 


import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;

public class runjava {
    public static void main(String []args){
        Integer[] arrayInt={1,3,2,1,5,3,1};
        Arrays.sort(arrayInt);
        printArray(arrayInt);

        List<Integer> listInt=new ArrayList<Integer>();
        listInt.add(1);
        listInt.add(3);
        listInt.add(2);
        listInt.add(1);
        listInt.add(5);
        Collections.sort(listInt);
        System.out.print(listInt);

    }

    public static <A> boolean printArray(A[] array){
        if(array.length==0) return false;
        for(int i=0;i< array.length;i++){
            System.out.print(" "+array[i]);
        }
        return true;
    }
}

y si tuvieramos que implementar basados en un criterio propio x(por ejemplo ordenar un arreglo de string que sabemos son entero) o usando un campo especifico de una clase, o cualquier logica que quisieramos podriamos crear un comparator para informarle a java como queremos que ordene y hacerlo asi.


 import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class runJava{
    public static void main(String[] args) {

        Comparator<String> customComparator = ((a, b) -> {
            Integer aInt = Integer.valueOf(a);
            Integer bInt = Integer.valueOf(b);
            return aInt > bInt ? 1 : aInt < bInt ? -1 : 0;
        });
        List<String> listInt = new ArrayList<String>();
        listInt.add("1");
        listInt.add("3");
        listInt.add("2");
        listInt.add("1");
        listInt.add("5");
        Collections.sort(listInt);
        System.out.print(listInt);

    }

}

 

Referencias.

1. bubble sort https://www.geeksforgeeks.org/bubble-sort/

2. quicksort explicacion. https://www.youtube.com/watch?v=7h1s2SojIRw

3. por que gusta quicksort https://cs.stackexchange.com/questions/3/why-is-quicksort-better-than-other-sorting-algorithms-in-practice 

4. https://www.opinionatedgeek.com/codecs/htmlencoder

lunes, 28 de marzo de 2022

Scrum, metodologias agiles

Version en video


 

Es una metodología ágil para el desarrollo de software como otras metodologías ágiles nació por la inspiración del manifiesto ágil un manifiesto que se creó casi que como consecuencia del desarrollo por cascada ( primero se planea, luego se desarrolla y por último se prueba) . Se dice que el desarrollo por cascada no funcionaba bien para proyectos de software porque hay mucho descubrimiento en el desarrollo y cambios sobre la marcha inesperados es bastante más parecido al método científico ( hipótesis, ensayo, error o éxito, ajuste y repetir).

Donde he trabajado siempre se dice que se usa scrum, como para determinar cómo se organizan las personal. también he escuchado de conocidos que trabajan en tecnología que lo usan en sus empresas,  por lo que mi impresión es que esta es una metodología para el desarrollo de software muy aceptada actualmente.

scrum busca ciclos cortos de trabajo que se llaman sprint, la idea es dividir el trabajo de manera que se puedan mostrar cosas completas al final de ese sprint, los sprint son cortos en teoría tanto como sea posible para tener una duración de entre 1 y 4 semanas (donde 2 semanas es lo común).

el trabajo se divide en historias de usuario de manera que se puedan hacer por partes, y que estas partes tengan valor para el negocio por ejemplo una historia puede ser “permitir que un usuario pueda recuperar su contraseña” (ese es el título la descripción podría tener como se quiere que se recupere, bajo que condiciones, como se va determinar que se culminó la tarea etc) y una buena historia tiene algunas características (me parece util este acronimo) el acronimo invest.

I: independent (la historia se debe poder cumplir por sí sola)
N: negotiable ( se puede negociar la historia hasta antes de empezar)
V: valuable ( debe ser valiosa para el negocio, generar valor si se completa)
E: estimable ( se debe poder estimar para calcular que tanto esfuerzo va tomar)
S: small ( debe ser lo suficientemente pequeña para que se pueda hacer un sprint)
T: testable ( se debe poder probar de alguna manera que la historia se completo)

qué criterios debe tener si o si los define el equipo pero la historia no deja de ser una forma de dividir y hacer el trabajo por partes manejables

los equipos en scrum están compuestos por el product owner que viene siendo un representante del negocio en el equipo que entiende las necesidades y se las prioriza al equipo( define qué se debe hacer primero) , un scrum master que es una persona que hace de contrapeso al product owner para disminuir la presión que hay sobre el equipo y ayuda a remover bloqueos, y el equipo de desarrollo que es el que se encarga de implementar las soluciones.De estos 3 el scrum master veo como común que se lo pasen por la galleta (que no pongan a ninguna persona con ese rol en el equipo).

el equipo se recomienda que sean 7 +- 2 personas (entre 5 y 9 personas) este conteo son las persona que hacen historias(hacen el backlog del sprint) por lo que si el product owner hace historias cuenta en este rango sino no, lo mismo para el QA( persona que vela por la cálida y hace pruebas) si afecta la capacidad del equipo cuenta sino no, más personas son contraproducente por que aumentan el costo de la comunicación exponencialmente ( entre más gente esté metida en algo más difícil es sincronizar el trabajo, decidir y organizar ) y menos personas tal vez sean muy pocas para conseguir algo significativo en un tiempo razonable además de ser capaces de hacer cosas si alguien sale de vacaciones por ejemplo. En lo personal me gustan mucho más los equipos tirando hacia el lado de pequeño cuando un equipo crece me parece inevitable que se empiezan a tomar temas variados y se pierde la concentración como equipo en algo específico.

el equipo va varían en composición según el producto algunos equipos van a ser solo desarrolladores backend, otros sólo front-end, otros mixtos entre backend y frontend, otros serán científicos de datos etc.

un último detalle aparte de la metodología creo que es importante que en un equipo haya confianza, que la gente se lleve relativamente bien, que todos se puedan concentrar en el trabajo del equipo y esto he visto que se se posibilita cuando.

  • se respetan las curvas de aprendizaje.
  • se saca tiempo para permitir hacer mejoras técnicas ( o deuda tecnica)
  • Se hacen actividades de integración.
  • todos los integrantes trabajan para un solo proyecto ( en ciertos caso se da que una persona tiene x capacidad en un equipo y y en otro, yo creo que eso es contraproducente)
  • se hacen discusiones técnicas en grupo
  • se hace programacion par/mob programming devez en cuando,para iniciar una persona o seguido si al equipo no le molesta

se piden y se respetan las opiniones de todos, aunque se llegue a compromisos


por el contrario cuando esas cositas se dejan de hacer pues el rendimiento y el ambiente empeoran. no se deja de ser humano por más metodologia o processo

fuentes:
opiniones personales y primeros 3 capitulos de:
Scrum the basics de linkeding learning
https://www.linkedin.com/learning/scrum-the-basics

lunes, 14 de febrero de 2022

3 patrones de diseño tipo wrapper ( proxy, adapter y decorator)

version en video:


https://youtu.be/bswx9qvuCdg

 

Estaba realizando una transformacion que necesitaba una cache que otra persona del equipo estaba haciendo(en paralelo), entonces pensé en un proxy que se encargara de cargar ese cache y retornare la información que necesitaba(desde un cache quemado en memoria) mientras otra persona hacia el desarrollo.

luego cuando se realizo la integración real la función del proxy se convirtió en transformar el string json que devolvía la cache a una clase que yo pudiera usar con sus valores. 

en la revisión del código me dijeron eso no es un cache, eso es un adapter. y tenían toda la razón aunque ambos son wrappers tienen sus diferencias, de hay nació este articulo.

Proxy

un proxy se usa para encapsular otro servicio o método(usualmente un servicio externo al no tenemos acceso directo) el proxy se encarga entonces de agregar algún comportamiento al método del otro servicio antes o después de llamarlo.con la salveda de que para que sea proxy debe tener la misma interfaz que el servicio origina ( osease que los métodos reciban y devuelvan el mismo tipo mediante una interfaz) por esto el error de arriba (el cache devolvía un string(cadena de texto) pero luego el proxy malo retornaba una clase). algunos ejemplo de proxy pueden ser.

  • virtual proxy: se encarga de cargar otro servicio solo cuando se vaya a usar ese recurso, para hacer un lazy load(carga perezosa) por que el otro servicio es pesado de subir y puede que no siempre sea necesario.
  • proxy de segurida: se usa para restringir acceso a cierto recurso a algún usuario.
  • proxy de loggeo: para loggear o imprimir en pantalla informacion que recibe o responde un servicio.

Adapter.

Es otro tipo de wrapper que se usa cuando no queremos la interfaz original del servicio base, en la historia anterior ese servicio no era un proxy sino un adapter pues estaba encargado de transformar un json como string del cache original en un clase kotlin. (este tipo de transformacion por ejemplo si el servicio original retorna un xml pero nosotros queremos integrarnos con json se les llama adapter)

imagen de: https://zh.wikivoyage.org/wiki/File:FTT102017.jpgFile:FTT102017.jpg - 来自维基导游的旅行指南

Decorator

este es el mas complejo de los 3, un decorador es como un proxy dentro de otro, dentro de otro ......

image de: https://www.publicdomainpictures.net/es/view-image.php?image=19582&picture=munecas-rusas

Muñecas rusas Stock de Foto gratis - Public Domain Pictures

 

la funcion del decorator es posibilitar encadenar comportamiento(en un orden personalizable) conservando la misma interfaz (decorar) y es frecuentemente usado en aplicaciones tipo stream.

en mi caso no entendía como funcionaba el decorator hasta que hice un ejemplo que se puede encontrar en https://github.com/chalimbu/decorator-java/tree/feature/solucionEjercisio1 aqui hice un decorador bobo para entender el concepto una clase que imprime en pantalla y unos decoradores para agregarle un mensaje(la fecha, una tag de error o info) al mensaje original por medio de decoradores que se construye en el Main.java. recomendado ver el ejemplo en el siguiente orden.

  •  https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/Logger.java
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/decorators/SystemLogger.java
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/decorators/SystemLoggerDecorator.java -> el decorador que sirve para encapsular los otros 3 siguientes.
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/decorators/SystemLoggerDateDecorator.java
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/decorators/SystemLoggerErrorDecorator.java
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/decorators/SystemLoggerInfoDecorator.java
  • https://github.com/chalimbu/decorator-java/blob/feature/solucionEjercisio1/src/com/decorator/Main.java -> usando las clases definidas antes.

 estos 3 patrones tienen sus diferencias y su similitud que todos se encargan de servir de envoltura para otro servicio.

fuente:

la información viene de https://refactoring.guru/design-patterns/decorator donde se explica muy bien.

martes, 4 de enero de 2022

Notacion big O

version en video:


 

La notación de big o es una forma de medir y comparar el tiempo de ejecución de algoritmos.
Esta notación se puede usar para comparar dos implementaciones de algoritmos y posiblemente escoger la implementación más rápida.
hay que ser cuidadoso con esto en proyectos más halla de ejercisios por que para mi sigue siendo más prioritario hacer un código más mantenible y fácil de entender que un código que sea más rápido o teóricamente mas rapido(en mi caso por ejemplo me gusta mucho la programación funcional y la inmutabilidad para entender el código como bloques funcionales que reciben una entrada y retornan la misma salida para misma entrada, otro tema).
con esta aclaración igual creo que en el libro cracking the coding interview de gayle dan un ejemplo analogía muy bueno para entender el impacto de big o. Imaginemos que tenemos que transferir un archivo a un amigo y tenemos dos opciones.
transferir el archivo por internet(mandándolo por ejemplo por un correo electrónico).
llevar el archivo físico en un avión(por ejemplo en un disco duro)

en el primer caso transfiriendo el archivo por internet, entre mas grande el archivo más tiempo nos va tomar transferirlo por tanto tenemos una relación lineal.
tiempo transferencia = tiempo para transferir cantida * tamaño archivo + tiempo inicial, esto en notación de big O lo podríamos representar como O(n) entre mas grande el archivo mas tiempo nos 

tomaría y esto aumenta linealmente.
para el caso 2 llevar el archivo en un avión sin importar que tan grande es el archivo(podrían ser terabytes) el avión va tardar lo mismo (o una constante) en big O representamos esto como O(1)




este ejemplo creo que es muy bueno para entender la relevancia de la notación big O que nos muestra las diferencias de ejecución para cantidades enormes de datos, por ejemplo en general podemos decir que O(1) es mejor que O(n) pero si queremos transferir un archivo pequeño seguramente no lo vayamos hacer por un avion.