Tratando de Ser Paciente con esta Pasión

Hola! ante todo no pretendo aburrirlos con una introducción!

Soy simplemente un desarrollador que , si encuentro un tema interesante sobre el que me parece que pueda aportar mi experiencia, trataré de sumar , tratando de hacer alguna breve reseña al respecto.

Gracias por leer!

jueves, 18 de agosto de 2016

Tres Simples formas de Evitar Usar IF en nuestro Código




Primero, quizas algunos se pregunten por qué esta mal usar IFs ?


Existen varias razones para no usarlos, pero tratare de ser preciso y consistente para luego pasar a lo que nos aplica que es como reemplezar, en la medida que se pueda esta forma de decisión:

1.- Mas allá que el "if" es la forma inicial de plantear estrategias de decisión dentro del código, estamos haciendolo de una forma es muy posible que, a menos que sean necesarios, posiblemente encapsule comportamiento que no corresponda a la clase que lo aloja y que quede en un lugar donde luego tengamos que modificar relativamente seguido si los cambios o escenarios cambian.

2.- Hablando puramente de objetos, y que el paradigma es “intereactuan los objetos solo a a travez de métodos”, el if es una forma en la cual estamos saliendo de este paradigma , para meternos en una idea mas procedural. Si quisieramos ser mas "objetosos” deberiamos salir de este tipo de implementación.

3.- Subjetivamente, El código queda feo; Saca legibilidad y aumenta las chances de errores.


Dado que java dentro de los puristas de objetos es bastante vapuleado y con razón, tratare en este articulo mostrar 3 técnicas que nos permitirán evitar los "if" en nuestro código para este lenguaje, logrando además hacerlo más mantenible.


Si bien son approachs muy especificos los que planteo, ya que decidí volcar el articulo a un hecho meramente implementativo, lo que muestro esta basado en los patrones conocidos ( Strategy, State, etc). El objetivo es que mas alla de los nombres puedan ver algunas simples ideas que mejoran la implementación.

Primero la base de Todo: Polimorfismo.



Dado que lo que queremos es tener elección de comportamiento en función de las condiciones que se den , lo que estamos queriendo hacer es hablar de unificar tipos de comportamientos bajo una jerarquia, en la cual bajo una interfaz/clase abstracta decidamos en la clase concreta implementar el comportamiento deseado.


Para mejorar esta idea nadie mejor que leer sobre el principio de Liskov, y mejor aun leer sobre SOLID.


Como ejemplo usaré este esquema, que lo iremos usando en el resto de los ejemplos. El concepto de negocio sobre el que trabajaré es:
Dado distintos tipos de clientes, queremos realizar la cobranza de los mismos.


Podemos tener Un Cliente , con los siguientes Tipos:

  • ClienteSimple
  • ClientePyme
  • ClienteGrande


Tendríamos que tener una interfaz:


public interface CobranzaClientes{
void realizarCobranza();
}


Tendriamos las siguientes implementaciones:


public class CobrarClienteSimple implements CobranzaClientes{
public void realizarCobranza(){
// Forma de Cobrar Para Clientes Simples
}
}
public class CobrarClientePyme implements CobranzaClientes{
public void realizarCobranza(){
// Forma de Cobrar Para Clientes Pyme
}
}
public class CobrarClienteGrande implements CobranzaClientes{
public void realizarCobranza(){
// Forma de Cobrar Para Clientes Grande
}
}

Ahora pasemos a las técnicas:

1.A-Estrategia por Mapas (Opción Sin Java 8)

Asumamos que en función del tipo de Cliente, por ahora un String , realizamos la tarea de cobranza según el tipo de cliente.
Es entonces la solución posible a partir de una Factory (o alguna herramienta de IOC, que nos cargue un mapa) nos proveera conceptualmente funcionalidad similar a lo siguiente:


public class FactoryCobranzas{
public static Map getMapaCobranza(){
Map cobranza = new HashMap<String,CobranzaClientes>();
cobranza.put(“ClienteSimple”, new CobranzaClienteSimple());
cobranza.put(“ClientePyme””, new CobranzaClientePyme());
cobranza.put(“ClienteGrande””, new CobranzaClienteGrande());
return cobranza;
}
}


Entonces en tu clase que recibe cada cliente para efectuar la cobranza sería, evitando los ifs:


private Map cobranzaStrategy = FactoryCobranzas.getMapaCobranza();


public void efectuarCobranzaPorCliente(Cliente cliente){
cobranzaStrategy.get(cliente.getTipo()).realizarCobranza();
}


Como vemos evitamos de hacer "if" validando el tipo , y ademas si surgiese un nuevo tipo de ciente, por el momento es solo agregar un campo mas al mapa, y no cambiamos nuestro fuente.


Notar que la Key en este caso puede ser un String, pero podría ser un Enum u otro identificador que nos permita seleccionar la ram de funcionalidad que pretendamos. Ademas notar lo útil del concepto de programar orientado a Interfaces, y no a implementaciones.


1.B-Estrategia por Mapas (Opción Con Java 8)

La clase Factory nos quedaria , mucho mas simple y sin agregar quizas el esquema de Jerarquia clases, lo cual es aplicable si a lo que se quiere aplicar es mas simple en logica :


public class FactoryCobranzas{
Function cobranzaClienteSimple = () -> ;// Hacer cosas de Cobranza Simple
Function cobranzaClientePyme = () -> ;// Hacer cosas de Cobranza Pyme
Function cobranzaClienteGrande = () -> ;// Hacer cosas de Cobranza Grande
public static Map getMapaCobranza(){
Map cobranza = new HashMap<String, Function>();
cobranza.put(“ClienteSimple”, cobranzaClienteSimple);
cobranza.put(“ClientePyme””, cobranzaClientePyme);
cobranza.put(“ClienteGrande””, cobranzaClienteSimple);
return cobranza;
}
}


Esta solucion es similar en un punto en aplicacion , aunque para mi pierde un poco en legibilidad:
cobranzaStrategy.get(cliente.getTipo()).apply();

2.-Estrategia por Reflection



Esta estrategia, ademas de un fuerte elemento de “Convention over Configuration” , basado en el mismo criterio que en el anterior, hacemos algo a mi gusto mas rustico, usando reflection,  pero no por ello deja  que evitemos usar if:


private String packageWhereStrategyExists = “com.ar.paquete.”;


public void efectuarCobranzaPorCliente(Cliente cliente){
CobranzaClientes cobranzaCliente =  (CobranzaClientes) Class.forName(packageWhereStrategyExists+ cliente.getTipoCliente()).newInstance();
cobranzaCliente.realizarCobranza();
}


Esto podria usarse tambien con Enums en el tipo:
String className = packageWhereStrategyExists+ cliente.getTipoCliente().name();
Class.forName(className).newInstance();
cobranzaCliente.realizarCobranza();


Un problema que podemos observar en este approach , es que si la clase que instanciamos posee colaboradores, los mismos no se crean ni vendran por este medio, por lo que se podria deducir que este acercamiento es para modelar logicas no muy complejas .
Un detalle que acerco es no tener miedo a la meta-programacion que se vislumbra en este ejemplo. Es una herramienta que hay que conocer y no abusar, con implementaciones mas simples en otros lenguajes ( como ruby) pero no por eso temerle por su complejidad, como ocurre en java.

3.-Estrategia Por Enums:



Si definimos un Enum de Cobranza:


public enum TipoCliente{
   ClienteSimple("ClienteSimple") {
@Override
public void realizarCobranza() {
            new CobranzaClienteSimple().realizarCobranza();
}
},
   ClientePyme("ClientePyme") {
@Override
public void realizarCobranza() {
            new CobranzaClientePyme().realizarCobranza();
}
},
   ClienteGrande("ClienteGrande") {
@Override
public void realizarCobranza() {
            new CobranzaClienteGrande().realizarCobranza();
}
};
   
//….. Otras implementaciones que necesitemos
   // Este es el secreto para que los campos del enum implementen la funcionalidad!
   public abstract void realizarCobranza();
}


En este caso no necesitamos tener la interfaz ( aunque es recomendable) y en la clase Cliente, el tipo corresponde a este Enum , entonces:
public void efectuarCobranzaPorCliente(Cliente cliente){
cliente.getTipoCliente().realizarCobranza();
}


Para este tipo de estrategia son validos hibridos como con el mapa adentro de la clase del Enum.

Conclusión



En cualquiera de los 3 escenarios planteados, nos enfocamos que la necesidad de enfrentar el uso de distintos tipos de estrategia de realizar tareas, no nos lleve a romper el paradigma de objetos, usando abusivamente la herramienta “IF”. Vemos tambien es que si nos habituamos cuando es valido a evitar este uso, usualemente lograremos un codigo mas escalable, mas limpio y focalizado en la implementación y no en cómo llamar a la implementación.


Como corolario, es bueno tambien pensar llegar a este tipo de soluciones son las herramientas finales que usamos cuando vemos que nuestros test llegaron al “verde” y nos encontramos en la etapa de mejorar implementaciones; Hacerlo antes es riesgoso, no invalido, pero si factible de sobre-implementacion.


Gracias!

lunes, 4 de abril de 2016

Mantener la sesion de ssh aún saliendo del Server, La Solución ? Screen .

Que problema tuve ?

En estos dias tuve que luchar con algunos procesos batch que los debia correr por script, algunas veces largos y el problema es ; ¿ como hacerlos si me tengo que desloguear, por ende se corta el script ?

La Solución: 

Screen permite crear instancias de bash dentro de la misma consola que estan usando , la misma permanece viva por mas que se deslogueen.

Nota: el comando directo contra Screen es Ctrl A ( es como un comando hacia la consola, como un menú)  Por comodidad lo llamare simplemente "scr"

Como funciona:

Para comenzar :

$> screen 

se crea la nueva y corran un log

Bueno ahora si desean volver a la consola original : scr + d  

Para volver : screen -x

Para crear una nueva pantalla , ya dentro de screen : scr + c

Pueden poner a correr un top

para pasar de pantalla en pantalla dentro de screen ( para adelante) : scr + n 
para pasar de pantalla en pantalla dentro de screen ( para atras) : scr + p

Si alguna la desean matar por que ya no les sirve : scr + k
( esto es por cada una que tengan viva.)

y Repito lo más util, es que si se desloguean .. cuando vuelvan a loguearse , lo que tenian en tal pantalla de screen , seguira corriendo.


Para que sirve ?
* Para correr scripts , varios.
* Acceder directo a un log que permanezca corriendo en vez del tail


Que disfruten!

sábado, 6 de febrero de 2016

Preocuparnos por la estimación nos vuelve mejores desarrolladores



Creo que se ha escrito mucho sobre estimación de tareas. Metodologías, formas , intenciones, colores, juegos de Azar. Mucho.
Ahora , no he leido todavía las razones por las cuales nos conviene estimar bien a nosotros, los que estamos involucrados mas directamente en el proceso de construcción de software.

Pero primero, qué entiendo por estimación? al menos desde el punto de vista de sistemas; es predecir en función de nuestro buen juicio sobre ciertas tareas que estamos realizando cuanto tiempo nos demandará realizarlas. Debido a que justamente nuestro "buen juicio" es un atributo muy maleable, se han creado distintos métodos para darles una conciencia de mensurabilidad a este criterio ó "buen juicio".


Aparte es sumamente influenciable por cuestiones internas ( "Hoy tengo ganas de trabajar ? ", "Discuti con mi novia / esposa /hijos / padres", "Mi jefe es o se hace, que lo codee él", etc, etc) y cuestiones externas ( "esto tiene que ser entregado para ayer, como venimos ?", "Aparecio un cliente mas, que nos dará un incremento en el tráfico de la herramienta del 500%; estamos preparados para manejar este flujo? deberíamos...", "El proceso requiere para que evolucione mejor un refactor, ya que nos dimos cuenta que esta grilla la vamos a reutilizar, conviene  que sea mas inteligente").

Dados los factores , externos e internos, impactan en un alto grado de falla en nuestro buen juicio en cuanto a los tiempos de implementación, lease estimación y además, son demasiados. Es necesario como desarrolladores , asi como conocer nuevas herramientas y frameworks ( es un must para mantenernos actualizados) debemos conocer esta herramienta soft de la cual somos únicos responsables de mejorarla y conocer sus alternativas.

Solo nosotros conocemos lo que nos  implica llegar a un deadline, debemos poder en un punto poder conocer que grado de imprevisibilidad nos manejamos, y al menos manejar, dar visibilidad sobre los riesgos de dicha cuestión. Saber que nos implica hacer algo y que factores nos afectan nos podrán dar la capacidad para desenvolvernos independientes y la fiabilidad de las personas en quien confía en nosotros un desarrollo.

Una vez que entendemos los factores , deberíamos tener y haber logrado mucha mas firmeza y claridad a la hora de defender nuestra estimación.Para poder defenderla y hacerla menos discutible, debemos entender todos los temas que nos afectan, y eso nos llevará a lograr ganarnos esa confianza.

Nuestra estimación debe estar fuertemente basada en argumentos. No podemos hablar sin fundamentos. No podemos validar nuestra postura sin un test que lo avale; ups ! perdón , se me escapo el TDD developer que soy.. pero , acaso ..no es así ?; Entonces busquemos firmeza en nuestras aseveraciones conociendo y hechando mano a que cuestiones nos afectan para poder ser mejores estimando. Porque cuando mejores somos estimando, mejores desarrolladores somos ( al menos , entre las infinitas cualidades que existen para hablar de ser un buen desarrollador, habremos ganado una muy intangible y poderosa ), ya que conocemos claramente el alcance de hacia donde iremos/llegamos, que impacto vamos a tener en nuestro producto y a futuro mas dueños de nuestras decisiones en cuanto a tiempos.

Que temas nos dan una idea de que sabemos con que grado estamos estimando ?

Voy a tratar de desarrollar en items temas que para mi punto de vista nos dan una evaluación para nosotros del  grado de la calidad de nuestras estimaciones; En la medida que mejor las manejemos, más cerca estaremos de ser precisos.

1.-  Grado de Switch context:
Debemos tener en cuenta siempre el contexto en el que nos movemos. A medida que poseamos mas Señority en nuestra profesión, se nos demandará que estemos menos enfocado en las cuestiones propias de la construcción del proyecto para empezar a ser los referentes de otros ó prestar atención a otros Issues no relacionados al proyecto ( ni hablar si estamos en varios proyectos ). Esto nos afecta claramente la estimación. Tener en cuenta cuanto tiempo pasamos en reuniones antes que enfocados en cómo dar eficiencias al algoritmos, nos da gimnasia en otros temas, pero nos saca foco , tiempo y destreza en esto puntualmente que nos demandan. A la hora de estimar, tener claro esto , y no denostarlo.


2.- Calidad del Producto:
Otra vez calidad ? Hay muchos libros, pienso en "Clean Code" y listo. Pero aquí apunto a lo que cada uno de nosotros entiende por calidad. Si no entendemos el concepto del vamos estamos en problemas y tenemos que empezar a adquirir tal concepto. Si lo entendemos y sabemos por donde pasa, entonces llegamos un punto a saber el status de nuestra "mejor" obra y/ó por donde pasa algo que directamente es una bomba de tiempo. El punto es tener muy claro la deuda técnica que dejamos.

Yo encuentro estos 4 niveles , de peor calidad a mayor:
1.- Código sin testear , con metodos de mas de 20 lineas, y poca modularizacion, Muy acoplado.
2.- Código  testeado, reproducible , aunque con muchas falencias de diseño. Si estamos en objetos se carateriza por muuuchos Ifs.
3.- Testeado , modularizado de a partes, pero con cosas en algún punto repetidas. con funcionalidad de mas.
4.- Testeado. Se usó TDD. Hay los patrones Justos. Arquitectura hexagonal. Una belleza.

En general cada uno de estos niveles, entender los pros y cons, van de la mano del Señority, pero a veces tambien implican mas tiempo. o estamos en un transcurrir del punto 2 al punto 4 ( El refactor de TDD ). Si supimos diferenciar bien nuestros commits, sabremos a que punto llegaremos con tal tiempo. Si la calidad es un compromiso, los commits debe ser nuestra firma. Para poder dar signos de esa firma debemos saber cuando llegaremos a cada compromiso. Esto debe ser claro a la hora de estimar. Cuando la calidad y los puntos de fallos sean casi minimos, contra primeras estimaciones y entregas, es que empezaremos a ganarnos nuestra confianza no solo de nosotros si no de quienes usan nuestro código; Este es el punto donde empezamos a lograr que nuestra estimación no sea cuestionable.

3.- Visibilidad de las tareas, Ser inquisitivos sobre el alcance del proyecto:
Debemos saber qué se pretende y adonde queremos llegar. Trabajar en modo autómata decididamente nos resta a nuestra capacidad. En esta postura solo desarrollamos cosas que no sabemos como funcionan del todo dentro de un contexto de un todo ; Queremos ser un asset que sume al equipo ? indudablemente debemos saber que hacemos y que impacto tiene nuestro trabajo. En función de eso sabremos que grado de entrega haremos , por ende estimaremos mas precisos en función de la necesidad del cliente.


Entiendo que esta lista podría alargarse muchísimo más; ya que la pregunta de fondo que nos podemos hacer es : ¿ Qué cosas son las que nos hacen mejores profesionales en It, y que a la vez nos dejan satisfechos a nosotros con nuestro propio desempeño ? Pero esto es tema quizas de otro post. Por ahora me quedo con la intención , con las ganas de haber logrado que vos , que día a día lidias con la incertidumbre de no saber cuando finalizas tus tareas, apuntes cada día a poder lograr ser más preciso y confiado con tus estimaciones.

Para finalizar, como una vez escuche a una persona que desde mi punto de vista entendía muchísimo por donde venía la mano: " Siempre , no importa el contexto, siempre se puede estimar". Yo agrego: "La precisión nos la dá el contexto"

Gracias!