Los principios SOLID datan de principios de siglo —del nuevo, no del viejo—, y establecen unas pautas generales para diseñar software más legible, mantenible y escalable. Hasta aquí, todo bien. SOLID son las 5 siglas, de cinco principios.
Pensamientos, solo eso
Un hobbie se vuelve aburrido cuando se pretende hacer de ello una profesión, cuando se lo quiere formalizar. Esta es una pagina personal, un blog, una forma de distenderme!
domingo, diciembre 10, 2017
Principios SOLID, una conversación
Los principios SOLID datan de principios de siglo —del nuevo, no del viejo—, y establecen unas pautas generales para diseñar software más legible, mantenible y escalable. Hasta aquí, todo bien. SOLID son las 5 siglas, de cinco principios.
jueves, mayo 10, 2012
MVC en Java - Model View Controller - Modelo Vista Controlador
Inicialmente y a grande rasgos, podemos decir que existen dos formas de MVC. Y la diferencia básica entre el primero y el segundo, es que en el primero (versión inicial), no se tiene una variable de referencia a alguna clase del “Modelo” en la capa de la vista, como mencione anteriormente.
Realizaré la presentacion en dos post, el primero, será el MVC inicial y el segundo el que tome en cuenta las relaciones entre el modelo, y la vista, y por que evoluciono de esta forma.
MVC + V1
Algunas consideraciones
... private IControlable controler; public FrmPersona(IControlable controler) { super(); this.controler = controler; initGUI(); } ...
... private IControlable controlador; public Persona(IControlable controlador){ this.controlador = controlador; } ...
Vista - "Las pantallitas"1
La vista tiene como responsabilidad mostrar y tomar datos. Las vistas no conocen nada de enteros, o tipos de dato. Todo para ellas son Strings. Con el desarrollo de las tecnologias web, se pensaba en poner validaciones de formato en esta capa (numerales, etc) para no tener que ir hasta los servidores y disminuir tanto performance como experiencia de usuario, pero con las tecnologias asincronas como ajax, esto pronto dejó de ser nacesario. No realiza ningún tipo de validación de negocio, ya que es el modelo el encargado de realizar dichas validaciones. Cada una de las acciones realizadas es una llamada al controlador para que él sea el encargado de tomar cualquier decisión.... @Override public void setData(Mapdata) { this.txtNombre.setText(data.get(CtrlPersona.NAME)); this.txtApellido.setText(data.get(CtrlPersona.SURNAME)); this.txtEdad.setText(data.get(CtrlPersona.AGE)); } ... @Override public Map getData() { Map data = new HashMap (); data.put(CtrlPersona.NAME, this.txtNombre.getText()); data.put(CtrlPersona.SURNAME, this.txtApellido.getText()); data.put(CtrlPersona.AGE, this.txtEdad.getText()); return data; } ... @Override public void actionPerformed(ActionEvent arg0) { if(arg0.getSource() == this.btnCancel){ controler.cacelAction(); } if(arg0.getSource() == this.btnOK){ controler.oKAction(); } } ...
Controlador - "Eso que entedes vos y nadie más... ponelo si querés...pero no pierdas tiempo.. bla bla...bla... cerveza!"1
- Realizar validaciones de formato
- Subir y bajar variables de sesión
- Redireccionar y hacer el forwared de las pantallas y manejar el ciclo de vida de las Interfaces de usuario o sistemas.
- Capturar tanto las excepciones de negocio, como de formato.
- Tomar y poner información en las interfaces
... { myView = new FrmPersona(this); myModel = new Persona(this); } ... public void oKAction() { Mapdata = myView.getData(); try{ ParameterTool.checkMandatoryFields(data); ParameterTool.checkInteger(AGE, data.get(AGE)); myModel.save(data); }catch(MenorDeEdadException e){ setReturningMessage(e.getMessage()); }catch(IllegalArgumentException e){ setReturningMessage(e.getLocalizedMessage()); } } ...
Modelo - "El diagramita de clases"1
jueves, septiembre 22, 2011
Arquitectura de Software vs. el Caos
La verdad que he tenido ganas de escribir sobre este apartado hace un largo rato ya, pero bueno, es tan larga la tela para cortar que no sé bien por donde comenzar. Hoy... acá... más bien definiré cuales son mis impresiones particulares sobre este tema a nivel general, otro día definiré cuales son, bajo mi puto de vista, las formas de organización de los proyectos más adecuados, y una que otra técnica que nos puede ayudar.
Definir una arquitectura, es casi tan difícil como definir que quiere decir arquitectura. Si la misma IEEE, establece sobre arquitectura que no sabe a priori que es, pero que cuando se la vé se la reconoce. Escuchamos, por ahí, a diario en nuestras empresas, que nos dicen: “esto es problema de arquitectura” o “no se puede escalar... la arquitectura no nos lo permite” o algún que otro enunciado apocalíptico que nos deja pensando.
En el mundo informático, o por lo menos acá en argentina, existe una alta rotación de personal en las empresas informáticas, y tenemos que cambiar de entorno laboral con frecuencia. Y cada vez que que nos sumergimos en un nuevo proyecto, encontramos que abrimos el IDE, hacemos un check out de la aplicación y cuando volvemos con taza de café en mano, empezamos a achinar los ojos y a escrolear el árbol de paquetes en el explorador de proyectos, de la misma manera que un peluquero novato mueve el pelo de un lado al otro sin tener idea de por donde comenzar.
Punto para el caos.
Luego después de unos primeros días de total incertidumbre, y de esfuerzos vanos de nuestros instructores por explicar los inexplicable, realizando capacitaciones teóricas, de lo que escasas veces vamos a encontrar en en la aplicación, nos empezamos a preguntar por que no utilizamos algún ultra-mega-re-contra-probado componente que existe ya en el mercado en lugar de tratar de reinventar la rueda trabajando con nuestro rustico-humilde-eterno-beta componente para realizar la misma tarea?
Punto para el caos.
Bien, ya superamos nuestra angustia, y nuestro sentimiento inicial de junior--, ahora es tiempo de realizar el aporte que dejaremos para siempre como una impronta, como una marca de hierro, en nuestra empresa. ¡Vamos a desarrollar un nuevo modulo de negocio para nuestra empresa! ¡Vamos a sentirnos productivos! ¡Ya estamos en condiciones!. Empezaremos por leer la documentación para entender a que APIs le vamos a “pegar” y las capas sobre las cuales nos “pararemos” para construir. Abrimos el repositorio de documentación, si existe, y ...¡WTF!...vemos que está totalmente vacío o con documentación desactualizada.
Otro punto para el Caos, y podría seguir así por un largo rato.
A esta altura del post, podes estar sintiéndote frustrado, ya que no ves una linea de código, ni documentación técnica que diga como hacer tu arquitectura infalible. Solo viste problemas humanos, sentimientos, emociones, frustraciones. Nada técnico. Púes bien. La mayoría de los arquitectos que he conocido, era personas sumamente capacitadas técnicamente, gurues de la tecnología, hombres que se juntaban a tomar mate con neo en la misma matrix. Pero con, con escasos skills de comunicación y poco human-oriented. Hombres que se sentaban en su propio box en un estado de autismo del cual sacarlo sería pecado capital. Lapidación!
Dies puntos para el caos!
“El silencio de un arquitecto, es el peor enemigo de la escalabilidad de un software”
Somos arquitectos, queremos arquitectear!
Bajo mi puto de vista, cada una de las palabras que vaya a citar acá debe ser tomada en cuenta como un test case, el cual cada diseño que realicemos, cada aporte, cada linea, cada acción debe superar.
¡Responsabilidad!
Todo tiene que tener una responsabilidad acotada y definida, cada clase, cada paquete, cada método, cada proceso, cada documento. Se tiene que poder definir rápidamente los inputs y los outputs, y a que se dedica. Esta es la principal palabra de una arquitectura soñada. Si hacemos un método, nos tenemos que preguntar antes de la primera linea de código, ¿a que se va a dedicar este método? En lugar de escribir una cascada de ifs de 100 lineas de código. Ningún método, clase, paquete, etc, etc, debe ser superman, y hacerlo todo. Si tenemos métodos de 300 lineas de código, algo estamos haciendo mal. ¿Estamos trabajando Orientado a objetos, o estamos estoreando lineas de código en un archivo? ¿Cada capa se ocupa de lo que tiene que hacer?
¡Narcisismo!
¿Es nuestro arquitectura narcisista? A la cual podemos ver como un espejo y decirnos lo buen programadores que somos. Lo genios, intelectuales, que utilizamos reflection, recursividad o algún otro recurso “mágico” para realizar una tarea. ¿Son estas tecnologías necesarias? Imaginemos que después de nosotros va a venir otro programador que se va a tener que que pelar los dedos con F5 para poder debuggear nuestro código, en idas y vueltas. ¿Tenemos una arquitectura de 100 capas que nos dará una futura y muy lejana escalabilidad y reutilización? Pero si nuestra empresa tiene una alta rotación de personal, y los requerimientos siempre corren contra el reloj... “the new guy”... va a realizar todos esos métodos? Primero que eso... va a conocerlos? O va a buscar un workaround de código que le permitirá cumplir con los plazos del burndown?. Estudiando nuestra empresa, y sus características, sabremos como se comportará nuestra arquitectura en el futuro. Complejidad innecesaria = narcisismo.
¡Aburrimiento!
Toda idea que se nos cruce para realizar un componente, es probable que ya haya sido pensada. Debe existir por ahí. Bien, frente a una cuasi igualdad de características técnicas, ¿cual de todos los componentes utilizar? ¡el más nuevo, lo nuevo es mejor!
10 punto más para el caos!
Trabajamos en una empresa inmersa en un mercado laboral, con un conocimiento circundante, ¿debemos realmente malgastar tiempo de un recurso en capacitación sobre ese nuevo componente, que desconocemos, del cual existe escasa documentación, o que no tiene una comunidad de soporte amplia al rededor del mundo? O debemos escoger, ese que en una entrevista laboral al preguntar al postulante si ya tiene experiencia en el, nos conteste con una sonrisa y un rotundo - ¡Si! Es probable que ese componente tenga una comunidad amplia al rededor del mundo, con actualizaciones constantes, con documentación en nuestro idioma y cientos de blogs con tips para realizar una tarea. Lo demás, lo nuevo, lo aprendamos en casa, allí podremos hacer pruebas en nuestro sandbox personal sin afectar el proyecto. No agreguemos factores de riesgo, por mas aburridos que estemos.
Comunicativa
¿Es nuestra arquitectura capaz de darse a entender por si misma? De tal forma que solo nos necesite como meros heraldos de presentación. Que al abrir el proyecto nos brinde una idea general de donde esta cada cosa. Que a la hora de que alguien tenga que escribir un método sepa cual es la clase, o la capa en la cual debe ir. ¿Documentamos lo que hacemos? Los frameworks y componentes que mayor éxito tienen en el mercado son aquellos que mejor documentados están. Nadie quiere perder preciosas horas de investigación averiguando que tenia en la cabeza el programador a la hora de hacer el código. Siempre nos repetimos a nosotros mismos, y muchas veces sin razón alguna, más allá de la falta de documentación, que sería mas fácil hacerlo de nuevo que continuar el trabajo de otros. Las wikis suelen ser herramientas muy útiles a la hora de mantener tan “viva” nuestra documentación como nuestro código.
El conocimiento es una de las bases del poder, y teniendo en cuenta esto, existen personas en las empresas que buscan ser los “únicos” que entiendan la forma de hacer las cosas. Pero después, estas personas se marchan buscando nuevos horizontes laborales, y el conocimiento se pierde, y la semilla del caos ha sido sembrada. Es por ello, que documentar no solo se transforma en una ventaja competitiva, si no también en una necesidad de supervivencia.
Autocrítica
Nada es perfecto, todo es perfectible en el tiempo. Pero al igual que un rió, el código fluye. Los requerimientos cambian, el conocimiento se actualiza. Debemos criticar con periodicidad nuestro código. Lo que la industria llama “Refactorizar”. Esto es como agregarle agua a un pozo tapado con tierra. Siempre nos va a dar lugar para agregar un poco más, y va a hacer a nuestro código mas solido. De lo contrario, la deuda técnica se incrementará dia a día, y solo nuestro esfuerzo servirá para pagar los intereses de esta deuda. Nos debemos preguntar, esta clase se tendría que llamar así? ¿Estos métodos subclaseados, podrían subirse al parent en el árbol de herencia? Estos métodos de la misma clase comparten muchos código, ¿no debería sacarlo a uno private y parametrizarlo? Debemos crear ciclos de desarrollo-refactorizacion-desarrollo etc. Es como el chequeo médico para determinar la salud de nuestra arquitectura.
Eutanasica
Debemos entender que cualquier arquitectura que diseñemos tendrá un ciclo de vida. Se realizará para un momento determinado del tiempo. Con un conocimiento sobre el mercado, una visión empresarial y un nivel de conocimiento técnico determinado. Las grandes arquitecturas viven por años, aquellas que son chequeadas, analizadas, y tratadas periódicamente ante cualquier síntoma. Otras, no soportan la deuda técnica y se cancerizan rápidamente en el lapso de uno o dos años. Nos debemos preguntar, ¿donde estaremos en seis meses a este paso? ¿Podemos liderar el mercado técnico con esta arquitectura?¿podemos alcanzarlo?¿Ha cambiado la visión de la empresa? ¿hemos aprendido suficiente? Si estas preguntas no pueden ser resueltas rápidamente, o si no nos gusta la respuesta, es hora de ir preparando una “muerte digna” de nuestra arquitectura. Ir planificando una migración, dejar un grupo de soporte, mientras una nueva esta en camino. No esperar hasta que el agua nos llegue al cuello.
Son varios los items de la check list, pero es un principio.
Conclusión
Pensar en una arquitectura como algo meramente técnico, es partir desde bases erróneas. Por supuesto que un arquitecto debe ser una persona técnicamente idóneo, ya que debe entender lo que su equipo técnico esta sugiriendo, y saber tomar decisiones técnicas todos los días. Pero pensar que eso es los más importante, o que es lo único que debe tener, es concebir que el mejor albañil que conocemos es capaz de diseñar el empire state. Debemos entender que en este edificio abstracto que vamos a diseñar será habitado por personas, y no mayoritariamente por clientes, si no más bien por los desarrolladores, y toda clase de staff informático con lo que convivimos diariamente. Abramos las puertas, preguntemos como quieren vivir. Revisemos nuestra empresa, nuestro proyecto.
martes, febrero 22, 2011
martes, junio 08, 2010
UML: Diagrama de Clases, ejercicio 1
Ejercicio:
El objetivo, es realizar el código java del diagrama que figura a continuación. Los métodos, salvo aquellos de la agregación, pueden contener solo la firma, no hace falta la lógica.
Respuesta
by Charli QuirogaClase Vehículo
import java.util.List;
public abstract class Vehiculo implements Desplazable {
private double velocidadPromedio;
private int velocidadMaxima;
private List ruedas;
public Vehiculo() {
super();
}
public double getVelocidadPromedio() {
return velocidadPromedio;
}
public void setVelocidadPromedio(double velocidadPromedio) {
this.velocidadPromedio = velocidadPromedio;
}
public int getVelocidadMaxima() {
return velocidadMaxima;
}
public void setVelocidadMaxima(int velocidadMaxima) {
this.velocidadMaxima = velocidadMaxima;
}
public List getRuedas() {
return ruedas;
}
public void setRuedas(List ruedas) {
this.ruedas = ruedas;
}
public void agregarRueda(Rueda rueda) {
if(!ruedas.contains(rueda))
ruedas.add(rueda);
}
public boolean quitarRueda(Rueda rueda) {
return ruedas.remove(rueda);
}
public abstract void romperInercia();
}
Interfaz Desplazable
public interface Desplazable {
public abstract void esquivarObstaculo();
}
Clase Rueda
public class Rueda {}
Clase Barco
public abstract class Barco extends Vehiculo{}
Clase Auto
public abstract class Auto extends Vehiculo{
public static final int N_RUEDAS = 4;
}
Clase Moto
public abstract class Moto extends Vehiculo {
public static final int N_RUEDAS = 2;
public void esquivarObstaculo() {}
}
Clase Boing747
public class Boing747 extends Vehiculo{
private static int viajes;
@Override
public void romperInercia() {}
@Override
public void esquivarObstaculo() {}
public static int getViajes() {
return viajes;
}
public static void setViajes(int viajes) {
Boing747.viajes = viajes;
}
public void despegar() {}
public void aterrizar() {}
public static void agregarViaje() {}
}
Clase BarcoAVela
public abstract class BarcoAVela extends Barco {}
Clase FordFalcon
public class FordFalcon extends Auto {
@Override
public void romperInercia() {}
@Override
public void esquivarObstaculo() {}
}
Clase HondaXR600
public class HondaXR600 extends Moto {
@Override
public void romperInercia(){}
@Override
public void esquivarObstaculo(){}
}
Clase HondaXR25
public class HondaXR25 extends Moto{
@Override
public void romperInercia(){}
public void esquivarObstaculo(int metros){}
}
Más info sobre Diagramas de Clases en la etiqueta Diseño
viernes, mayo 21, 2010
UML, Asociacion y Agregacion
Ahora veamos el codigo de la clase Persona (Nota: imagínense los generics por que blogspot los toma como tags, así que no aparecen)
import java.util.List;
public class Persona {
private String nombre;
private String apellido;
private Foto foto;
private List lugaresFrecuentes;
private List comunicaciones;
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}
//Asociacion Foto
public Foto getFoto() {return foto;}
public void setFoto(Foto foto) {this.foto = foto;}
//public List getLugaresFrecuentes() {return lugaresFrecuentes;}
//public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}
//Agregacion
public void agregarLugar(Lugar lugar){
lugaresFrecuentes.add(lugar);
}
public boolean quitarLugar(Lugar lugar){
return lugaresFrecuentes.remove(lugar);
}
//Asociación
public void setComunicaciones(List comunicaciones) {
this.comunicaciones = comunicaciones;
}
public List getComunicaciones() {
return comunicaciones;
}
}
Las diferencias principales son que:
- ¡La Agregación son siempre colecciones, o arrays! O algo que sirva de contenedor para "agregar" más de un objeto, aunque agreguemos uno solo. (si no sería settear y no agregar, add)
- La Agregación cuenta con dos métodos: uno para "agregar" un solo objeto a la lista, y el otro para quitarlo de la misma.
- La agregación puede, como no, tener los metodos setter y getter, mientras que la Asociación siempre los tiene, que ponen y obtienen una variable de referencia del mismo tipo de la variable de instancia o de clase, en este caso List
.
Bueno, espero haber limpiado alguna duda, y abrir otras ;) Saludos.
jueves, mayo 13, 2010
UML, Agregacion y Composicion
Empecemos, debemos recordar siempre que una de las mayores criticas que recibe UML, es que ha logrado salvar muchas ambigüedades... Pero no todas!!! aun quedan conceptos que se prestan a dobles interpretaciones, no se si este será uno de ellos, pero por lo discutido parece que sí. Por otro lado, podemos hacer un poco de historia, recordando que primero existió la asociación, después surge la Agregación para representar un relacion estructural contenedor/contenido y luego como una "extensión" de esta ultima nace la Composición.
Para explicar mi punto de vista voy a echar mano, al diagrama de clases que ya he utilizado en otro post y después voy a poner el código de la clase Persona, que es la que se lleva toda la carga de la discusiónEl código hace referencia, solo a este modelo, y es bien detallado, hasta con cosas innecesarias, o meramente teóricas, pero lo que busco es fijar una posición, concreta y definitiva, en el tema de las relaciones.
Algo importante a tener en cuenta, es que un objeto existe (digamos que esta vivo, pero esto no es técnicamente correcto por que no es un hilo) mientras existe una variable de referencia que "apunte" (tampoco correcto, por que java no tiene punteros, je) a dicho objeto en memoria. Es decir que se convertirá en elegible para ser borrado por el garbage collector, cuando no exista una variable que "apunte" a dicho objeto.
import java.util.LinkedList;
import java.util.List;
public class Persona {
private String nombre;
private String apellido;
private List perfiles = new LinkedList();
private List lugaresFrecuentes = new LinkedList();
//Setters and Getters
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}
// OJO no confundir estos son solo setters y getters de las propiedades
public List getPerfiles() {return perfiles;}
public void setPerfiles(List perfiles) {this.perfiles = perfiles;}
public List getLugaresFrecuentes() {return lugaresFrecuentes;}
public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}
La clase comienza normalmente con la declaración de las variables de instancia. Donde perfiles y lugaresFrecuentes son dos colecciones, pero tranquilamente podrían ser arrays. que se transformarán en contenedores de elementos. Al ser propiedades tienen getters y setters (accessors y mutators), que nada tienen que ver con la agregación y la composición.
Ahora veamos cuales son los métodos que caracterizan a la relación de AGREGACIÓN
public void agregarLugarFrecuenta(Lugar lugar){
if(!lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.add(lugar);
}
}
public void removerLugarFrecuenta(Lugar lugar){
if(lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.remove(lugar);
}
}
La primera característica es que la clase contiene dos métodos uno que agrega elementos a la coleccion y otro que los elimina de ella. He acá algo importante... los objetos son pasados por parametro, no han sido instanciados dentro del método, es decir no hemos realizado el new del objeto. Ha "nacido" en cualquier otra parte y se lo hemos pasado por parámetro al método para ser agregado a la lista lugaresFrecuentes. En otras palabras, el objeto Persona podria morir, y el objeto ahun podría mantener una referencia activa en alguna otra parte de nuestro codigo por lo tanto sus ciclos de vida no estrían atados. No nace ni muere, dentro de la Persona.
¿Cual es la Diferencia con la COMPOSICIÓN?
public void agregarPerfil(){
Perfil p = new Perfil();
perfiles.add(p);
}
//sobrecarga
public void agregarPerfil(String nombre){
Perfil p = new Perfil(nombre);
perfiles.add(p);
}
public void removerPerfil(int index){
perfiles.remove(index); // aca lo quitamos de la lista
}
Bueno... la composición también tiene los métodos para agregar y borrar. Pero..."el new del objeto se realiza dentro del método agregar"
En cuanto al método remover, no existe nada de extraordinario, simplemente quitamos un elemento de la lista.
Volviéndonos Paranoicos de la Teoría
Profundizando la paranoia y jugando con la teoría; para que atemos definitivamente los ciclos de vida, la variable lugaresFrecuentes no debería ser una propiedad, y la clase Perfil debería ser una Inner Class.
Persona persona = new Persona();
Persona.Perfil perfil = persona.getPerfil(...);
agregarPerfil
. La clase Perfil existiría mientras exista la instancia de persona. (ciclos de vida atados)Pero de nuevo, y no me voy a cansar de decirlo... esto es un extremo!!, es solo para conversar entre amigos, o vanagloriarse con algún profesor, no tiene nada de practico, ni de real, salvo para casos específicos.
Paranoia de la Paranoia
¿Creían que ya habíamos terminado? aun se puede ser más paranoico!!!! mucho se ha discutido sobre estos temas, y mucho fue paranoia teórica. Lo siguiente, es algo que les llevará a sus amigos o profesor a decir, "...bueno pero eso ya es una locura":
Sobreescribiremos el método finalize() de la Clase Persona, que es un método que todas las clases heredan de Object, y que se invoca justo antes de que un objeto sea borrado de la memoria por el garbage collector de java.
public void finalize(){
for(Perfil p : perfiles){
p = null;
}
}
En el desreferenciamos cada uno de los elementos de la lista un segundo antes de que el objeto de tipo Persona desaparezca de la memoria, una milésima de segundo, o algo asi!!! atando definitivamente el nacimiento y muerte, el ciclo de vida, de un elemento contenido con su contenedor.
Pero de nuevo!!! LA PARANOIA EN EL CÓDIGO NO ES BUENA!!! solo sirve en aquellas noches de borrachera entre programadores, en las cuales el boliche cerró y pinta quedarse en casa con amigos.
Yo rescataría de todo este biri-biri aquello de "el new se realiza dentro del método" y nada más!!!