En la mayoría de los paradigmas de programación, podemos encontrar sistemas que nos permiten auto organizar el código en pequeñas piezas o para incorporar liberías/bibliotecas de terceros a nuestro código. Al combinar todo lo anterior resulta una pieza de código más grande y compleja.
Desde un inicio Javascript utilizó el sistema de carga de módulos llamado CommonsJS (CJS) y es parte integral de Node.js hasta la version v8.5.0 donde se incorpora un nuevo sistema de carga de módulos, ESM. A partir de la version v13.2.0 de Node.js fue estabilizado e incorporado como un nuevo estándar.
James Beswick (Principal Developer Advocate for the AWS Serverless Team) escribió un artículo titulado Using Node.js ES modules and top-level await in AWS Lambda ,donde detalla el por qué y en qué casos deberías usar ESM como cargador de módulos de Javascript en el contexto de un AWS Lambda. Uno de los motivos más importantes de usar ESM, es que la carga en frío de un lambda tarda casi un tercio en comparación con CommonsJS.
Dejo aquí la comparativa entre CJS y ESM donde en el p99 (carga en frío) la partida se reduce a un tercio mejorando el rendimiento en un 43,5%. Para esta prueba, todas las métricas de ESM salieron por debajo (mejores en tiempo) de las de CJS es simplemente marginal (alrededor de 2-5ms).
Primero que todo se deben ajustar un par de atributos en el archivo package.json
para indicar que el módulo es del tipo ESM.
1 | { |
Con este ajuste le indicamos al cargador que trate los archivos como ES módulos según su extensión, es decir, con el atributo type
y valor en module
todos los archivos con extensión .js
serán tratados como ESM. Si por alguna razón quieres mezclar ambos mundos debes hacerlo de forma explícita usando como extensión .cjs
. Por el contrario, si no utilizas el atributo type
o lo dejas con valor commonjs
, todos los archivos con extension .js
serán tratados como CJS y si quieres utilizar ESM estos deben tener extension .mjs
.
1 | import { DateTime } from "luxon"; |
El handler debe estar expuesto de esa forma para que sea cargado como ESM. Se puede apreciar que ya no usamos la sentencia require
para cargar una dependencia externa (en esta caso luxon
) y en su reemplazo utilizamos import
.
Algunos detallitos que he ido aprendiendo en el camino y que no está muy explícito en la documentación, es que los imports
de nuestros archivos, es decir, el código que está dentro del proyecto, deben ser cargados y nombrados con su extensión, dejo un ejemplo:
1 | import { DateTime } from "luxon"; // <-- Sin la extension (lib) |
1 |
|
Espero les sea útil para sus desarrollos de lambdas con Node.js
. Más adelante ire dejando nuevos artículos con ejemplos e ideas para implementar con AWS Lambdas. Pase y deje su comentario.
]]>Escuchando Subterranean Homesick Alien del disco OK Computer
Hola, se que no he escrito en mucho tiempo, muchísimo tiempo.
Partiré diciendo que me cambie de sistema de blog desde Jekyll (ruby… puaj) a Hexo (nodejs) solo por salir de una tecnología que simplemente no va conmigo y tampoco le he dado el suficiente tiempo para entenderlo. Hexo es una plataforma para generar contenido estático (blog) a partir de archivos markdown, está desarrollado sobe NodeJS y todos sus componentes (plugins y themes) siguen la misma línea. Debo decir que hay muchos componentes que están bien des-actualizados y muchos de ellos con documentación en algo que parece ser Chino.
Ha pasado muchas cosas desde la última vez que escribí, tuvimos un estallido social en Octubre del 2019 y luego nos remeció una pandemia que nos estuvo encerrados un buen tiempo. De alguna forma ambos eventos forzaron al trabajo remoto y muchas empresas nos vimos obligados a adaptarnos a la nueva forma de trabajar y relacionarnos entre los diferentes equipos.
En pandemia no había mucho que hacer (fuera de la casa) así que aplicamos creatividad y aprendí a hacer Pan Amasado y pan con Masa Madre (al igual que muchos). Esto debido a que en esos días salir a comprar el pan era de riesgo vital.
En mitad de la pandemia nos cambiamos de casa apenas se dió la oportunidad (los permisos de mudanza estaban cerrados). Ya instalados en el nuevo HQ comenzó la nueva aventura de colegio virtual. No fue fácil y menos para la Vale, no generó un vínculo con sus profesores a través de una pantalla. Por otro lado la Javi se adaptó de una forma increíble a los quehaceres del colegio.
Afortunadamente para nuestro rubro, la pandemia aceleró muchos procesos informáticos y como mencioné mas arriba, presionó para que el trabajo remoto se consolidara como LA nueva forma de trabajo. Muchas compañías necesariamente tuvieron que crear nuevos sistemas y aplicaciones para atender a sus clientes o darles la posibilidad de no ir a hacer un tramite presencial (no se podía), lo que de alguna forma benefició a muchas empresas de desarrollo.
Estando encerrado aprendí cosas muy básicas sobre mantenimiento de guitarras (no quiero decir lutheria porque estoy a años luz de ese conocimiento) para justamente echarles una “manito de gato” a mis guitarras. Fue tanto el entusiasmo que me armé una guitarra que compre en Amazon, un kit DIY Do it yourself estilo PRS.
Por supuesto que no fue fácil y creo que las dos etapas críticas fueron pegar el mástil al cuerpo y la “pintura”, en ese orden de complejidad. Digo “pintura” pero en realidad es una técnica de teñido de la madera con tinturas basadas en anilina y agua. Les dejo parte del proceso:
Ahora esa guitarra es una de mis favoritas por varias razones, tiene un sonido único como hecha para tocar metal, es cómoda y tiene un sustain exagerado. Por lo demás es escala 24 1/2 al igual que todas las otras guitarras que tengo. Cosas que le faltan, aparte de un buen guitarrista XD, mejorar la entonación y cambiar el puente porque lo rompí y no hay repuesto. Afortunadamente la cuerda mas difícil de todas la G
quedó perfectamente entonada para el calibre de cuerdas que usa esa guitarra.
Eso es todo por hoy… iré agregando mas contenido a mi blog que dicho sea de paso tiene 19 años (ni yo me lo creo).
]]>Un año más, que se va,
un año más, cuántos se han ido.
Un año más, que más da,
cuántos se han ido ya…
Esta canción es casi un himno patrio de fin de año y no hay fiesta donde no se toque esta canción, que dicho sea de paso, ha sido interpretada por varias bandas. Aquí les dejo un link para que lean acerca de la historia de ésta canción.
Este año ha sido particularmente extraño en lo que a negocios y pega se refiere. Tuvimos elecciones presidenciales y que durante lo que dura la “incertidumbre”, los proyectos y las inversiones en tecnología se aletargar paralizan bastante. Una vez pasada la “incertidumbre” (para bien o para mal) se vuelven a activar los proyectos. En Symbiose SpA hemos sentidos esos embates del mundo económico y político aunque no tengamos que ver con ninguno de los dos.
En lo técnico quizás lo mas novedoso ha sido programar en nuevos frameworks y lenguajes. Uno de los nuevos frameworks con los que he tenido que sufrir lidiar ha sido Angular + TypeScript. Solo les puedo comentar que este último lenguaje ha sido vilipendiado de la peor forma en el trabajo y básicamente por lo odioso que es el “compilador” y los mensajes de error que salen en la consola de desarrollo del browser (sólo si es que salen). Hace mucho tiempo que no rabiaba tanto con algo que me gusta hacer.
En comparación, usando AngularJS como framework, es bastante mas legible y decente los errores que salen en la consola y los errores típicos son los dolores de cabeza que te da Javascript, que de alguna u otra forma, muchos developers tenemos interiorizados.
Sin lugar a duras en temas tecnológicos el uso de contenedores ha sido protagonista en el desarrollo de microservicios y la aceptación de esta arquitectura que viene de hace hace un par de años. En este ámbito Docker ha sido una de las plataformas que se mantiene en la pelea de la “containerización” junto a Kubernetes.
El uso que le damos a diario a estas herramientas van de la mano con Continuous Integration y Continuous Delivery evitando así HH preciadas de los desarrolladores peleando contra los servidores de aplicación, bases datos y cuanta aplicación ofrezca pelea. Para resumir este punto, que mejor que utilizar la palabra AUTOMATIZACIÓN.
Para finalizar lo técnico, sigo acumulando horas de vuelo SpringFramework y toda sus componentes orientados a crear microservicios y ambientes cloud. Cada release nueva de estos componentes traen un montón de nuevas funcionalidades que nos hace la vida mas fácil a la hora de pensar en soluciones Cloud. Kudos para los developers de SpringFramework.
Un hobby que había dejado totalmente en el olvido era el de leer. Tenía mi Kindle juntando polvo en algún rincón hasta que me puse la meta de leer al menos 1 libro al mes (empezando como en septiembre) y puedo decir que me fue bastante bien. Les dejo un listado de libros interesantes que pude leer o terminar de leer durante el año pasado:
Cabe destacar todos estos libros son de escritores Chilenos y que por cierto disfruté cada uno en su ámbito. El libro de Patricio Bañados es como estar tras bambalinas de TVN en los tiempos donde nuestro país paso por un periodo triste de su historia. Pero lo mas interesante es cuando superamos el periodo de la dictadura y las historias de codazos, volteretas y bajezas políticas se hacen presente en la vida del Relator.
Los libros de Ciencias de José Maza, Gabriel León y María Teresa Ruíz todos tienen la característica de un lenguaje muy simple y de fácil comprensión. Todos ellos muy entretenidos. Ciencia Pop tiene muchas anécdotas científicas y descubrimientos que se han hecho de casualidad (como la mayoría de los descubrimientos científicos). Somos polvo de estrellas y Hijos de las estrellas nos invitan a reflexionar sobre el origen del universo, sobre el origen de la vida y de qué estamos hechos, literalmente… Polvo de estrellas.
Sobre la Naturaleza del Software, también es un libro de fácil lectura con muchas anécdotas del mundo informático. También invita a reflexionar sobre la evolución de la Ingeniería Informática, los errores recurrentes en esta área, de lo joven que es esta rama de la ingeniería y las comparaciones odiosas con otras ramas. Destaca a grandes personajes que han participado en la evolución del cómo se construye software hasta el día de hoy.
En proceso de lectura aún:
Sobre “Contacto” de Carl Sagan, es un libro lleno de detalles y abundante en información de los personajes… muy muy descriptivo (a veces aburre un poco). Lo que me chocó es que uno espera una cierta similitud con la película Contacto y dicha similitud no es tal. La película la habré visto al menos una docena de veces y siempre emociona el momento en que empieza a escuchar los pulsos que provienen de la estrella Vega o al final cuando les habla apasionadamente a los niños sobre el universo. El libro es totalmente diferente o mejor dicho… la película es “basada” en la novela original de Carl Sagan.
Lo mismo me pasó con “Yo, Robot”, la película es también una de mis favoritas y con el libro no pega ni junta, aunque la trama del libro es la misma que se trata en la película y tiene que ver con el conflicto que hay con las 3 leyes de la robótica, pero en muchas situaciones diferentes a la película. El libro contiene un conjunto historias cortas que hablan de la forma en que los robots interactúan con los humanos en situaciones límite exigiendo al máximo las 3 leyes de la robótica. Interesante libro!
Alguna sugerencia de lectura para este año? déjenlo en los comentarios.
Feliz 2018 para todos! Bienvenido 2018!
y si… voy a escribir mas este año :D
]]>Estoy de mudanza de blog, adiós Octopress bienvenido Jekyll.
Una de las razones que me empujó a cambiarme de sistema de blog, es que Octopress esta sacando la versión 3 desde el 15 de enero del 2015, esta algo abandonado (ver los commits).
La pregunta era… ¿ hacia donde migro ?
Octopress se basa en Jekyll y la organización de los artículos es básicamente la misma. Pero no todo es tan fácil. Octopress tiene un conjunto de plugins que facilitan y ayudan a embellecer los artículos, por ejemplo, para destacar código fuente, citas, imágenes y video.
Jekyll de alguna u otra forma también tiene plugins para lo mismo, el problema es que hay que modificar todos los artículos donde fueron usados los plugins de Octopress y modificarlos al gusto de Jekyll.
Siguiente problema, elegir un lindo (?) tema para el blog, después de un largo recorrido buscando, encontré Minimal Mistakes, bien lindo, personalizable, con gran capacidad de extender y todas esa funcionalidades que a los developers nos enamoran (pero que jamás usamos al 100%). De todas formas, la instalación de este tema no fue sencillo, demasiadas configuraciones y cosas que no andan a la primera y la documentación, que es bien buena, no dice las cosas clave.
Algunas características de Jekyll son:
Si ve errores, considere que el blog esta en rodaje y sea amable… reporte el bug.
]]>jEnv es una herramienta de linea de comandos que ayuda a mantener múltiples instalaciones de Java (versiones y/o sabores) y permite cambiar las versiones por linea de comandos para poder mantener diversos entornos de desarrollo.
Una de las funcionalidades interesantes de jEnv es que configura las variables de entorno de java JAVA_HOME al vuelo según una pequeña configuración que se agrega al proyecto. Más adelante veremos algunas gracias de jEnv.
La instalación es bien sencilla y la pueden revisar en la página oficial de jEnv, acá dejo un resumen:
1 | $ git clone https://github.com/gcuisinier/jenv.git ~/.jenv |
Ahora debes ejecutar (dependiendo de tu shell) lo siguiente:
1 | $ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile |
1 | $ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc |
Reiniciamos el terminal y/o cargamos las nueva variables de entorno de nuestra shell y primero probamos que todo funcione correctamente con el siguiente comando:
1 | $ jenv --version |
Si el comando te responde con la versión de jEnv es porque esta todo correctamente instalado.
Luego tenemos que agregar las diferentes versiones de java que tengas instaladas en tu sistema de la siguiente forma:
1 | $ jenv add /path/to/java6-oracle/java_home |
Una ves que hayas concluido la configuración de las diferentes versiones de Java de tu sistema, puedes listarlos con el siguiente comando:
1 | $ jenv versions |
Y aparecerá algo como esto:
1 | system |
Ahora corresponde configurar cual de todas esas instalaciones será la que funcionará de forma global, es decir, la configuración por omisión de Java. En este ejemplo se configura la versión oracle64-1.7.0.79 como global.
1 | $ jenv global oracle64-1.7.0.79 |
Tambien se puede configurar de forma mas genérico, es decir, la última versión de java 7, por ejemplo:
1 | $ jenv global 1.7 |
Con esto siempre tomará la versión mas nueva de java 7 que tengan previamente configurada.
Para delegar la configuración de las variables de entorno de java a jEnv, debemos activar el plugin export de la siguiente forma:
1 | $ jenv enable-plugin export |
Nota: para que funcione correctamente el plugin, se debe eliminar la configuración de las variables de entorno que se tengan en los perfiles de bash (.bashrc) , zsh (.zshrc) o de su shell favorita.
Luego deben reiniciar su terminal o volver a cargar los perfiles de su shell y probar:
1 | $ echo $JAVA_HOME |
Debería aparecer algo como lo que sigue:
1 | /home/pcollaog/.jenv/versions/1.7 |
Y si vemos la versión de java debería aparecer algo como esto:
1 | $ java -version |
Si por alguna razón necesitas tener una versión especifica de Java en un proyecto de código fuente, debes configurar (estando dentro del directorio principal del proyecto) de la siguiente forma:
1 | $ jenv local 1.7 |
Este comando creará un archivo en el directorio en el que te encuentras (directorio base de tu código fuente) llamado .java-version y cuyo contenido será la versión de java especificada. Con esto todos los subdirectorios (a partir de donde se encuentras este archivo) estarán configurados con la versión de java seleccionada. Si tienes correctamente configurado el plugin export, jEnv hará el trabajo sucio de configurar la variable JAVA_HOME.
Sus comentarios son bienvenidos!
]]>Les dejo una imagen de como se activa este nuevo namespace en el STS.
Veamos un ejemplo simple de cómo usar namespace C.
Supongamos la siguiente clase:
1 | public class SimpleSPImpl extends StoredProcedure |
1 | <bean id="bean_id" class="com.example.SimpleSPImpl"> |
Ahora usando el namespace c quedaría algo mas simple:
1 | <bean id="bean_id" class="com.example.SimpleSPImpl |
Como pueden notar en el ejemplo, el namespace C permite configurar los constructores de los beans y tiene dos formas básicas, por valor y referencia. Para inyectar una instancia preconfigurada se debe usar el sufijo -ref para hacer alusión a que es una referencia. Si se desea inyectar un valor, sólo se usa el nombre del argumento del constructor.
Como siempre sus comentarios son bienvenidos.
]]>Primero que todo, un par de definiciones básicas y características antes de partir.
Esta es la jerarquía de excepciones de mas alto nivel que encontramos en Java.
Generalmente este tipo de excepciones son lanzadas por la aplicación y se generan a partir de errores en tiempo de Runtime. Este tipo de excepciones representan errores en el código y que la aplicación no es capaz de controlar. Algunos de errores causados y que lanzan este tipo de excepciones, por ejemplo, argumentos inválidos pasados a un método (argumentos null pueden causar NullPointerException), otro error común son la excepciones del tipo IndexOutOfBoundsException y que son lanzadas cuando se quieren obtener elementos de una lista y el índice que se entrega está fuera del tamaño del arreglo. Como podrán ver, son errores de programación y que generarán defectos en momento de correr la aplicación (no así al compilar).
Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program’s logic and cannot be reasonably recovered from at runtime.
Gosling, Arnold and Holmes, The Java Programming Language
Las excepciones de tipo Unchecked son subclases que heredan desde RuntimeException. Además este tipo de excepciones no tienen la obligación de ser declaradas con la cláusula throws en la cabecera del método. Otra característica es que tampoco se tiene la obligación de atraparlas con un catch como se muestra en el ejemplo siguiente:
1 | /** |
Este tipo de excepciones representan condiciones inválidas en el contexto de la línea de ejecución y que están fuera del control de dicho contexto, como por ejemplo, problemas con la base de datos, problemas de red, acceso a los archivos. También pueden ser condiciones de ingreso al sistema en donde el sistema no tiene ninguna participación, como por ejemplo, ingresar un nombre de usuario y contraseña incorrectos.
Contexto de ejecución ó scope: Corresponde al las líneas de código que están encerradas en un bloque de código, como por ejemplo, un método, un try/catch, bloque estático, etc.
Este tipo de excepciones deben ser declaradas en la firma del método. Además deben ser atrapadas dentro de los bloques de código donde se invoque un método que contenga la clausula throws.
Todas las excepciones de este tipo son subclases que heredan desde Exception, como por ejemplo:
Otra característica de este tipo de excepciones es que existe una probabilidad de recuperación de la ejecución y el método puede realizar alguna acción correctiva y/o informativa (log) en el bloque catch o simplemente relanzar la excepción y confiar en que el método invocante la atrape y haga algo con ella.
Para enviar el stacktrace al sistema de log (systemout) pueden usar los métodos de Throwable y en específico al método printStackTrace.
Un pequeño ejemplo de checked exception:
1 | /** |
Las excepciones de tipo Error son excepciones en las que el sistema no puede hacer nada con ellas, son clasificadas como errores irreversibles y que en su mayoría provienen desde la JVM, como por ejemplo: IOError, NoClassDefFoundError, NoSuchMethodError, OutOfMemoryError y VirtualMachineError por mencionar algunos de los errores.
Para iniciar esta última parte, comenzaré con algunos ejemplos de malas prácticas con las que siempre nos encontramos cuando programamos, les dejo unas pocas:
1 | try { |
En el ejemplo de arriba claramente no se hace nada con la excepción dentro del try, lo recomendable es que si de verdad no vas a hacer nada con la excepción, al menos debes enviarla a tu sistema de Logger favorito con algún nivel de debug aceptable para poder revisar el log. Siempre se recomienda hacer algo en el bloque catch ya que ocurrió un error que debe ser controlado.
1 | try { |
Es similar ejemplo 1 pero lo que se hace es relanzar la excepción atrapada hacia el método invocante. La recomendación es que nunca hagas eso ya que se presta para confusión al leer el código fuente y en la practica se estarían ejecutando dos bloques catch para la misma excepción (el directo y el del método invocante).
1 | try { |
Es recomendable que nunca atrapen todas las excepciones en un bloque catch y básicamente porque uno pierde la noción de por qué se produjo la excepción. Además en ese bloque también se atrapan las excepciones de tipo Runtime y ya mencionamos que estas excepciones significan errores en tu programa y que deben ser depurados (no escondidos debajo de la alfombra). Lo mejor es atrapar cada una de las excepciones y darle un tratamiento a cada una, si necesitan agrupar usen la herencia/jerarquía de las excepciones.
1 | try { |
Ese bloque de if’s compuestos se debe transformar en varios catch para cada una de las excepciones lanzadas. No usen un control de errores manual, es mejor usar las herramientas que te provee el lenguaje.
1 | try { |
No abusar de las checked exceptions ya que hacen nuestro código confuso y poco mantenible. Si bien es cierto, es la herramienta que nos provee el lenguaje, no abusemos de ella y convirtamos los bloques catch en pseudo programas y rutinas anexas a la lógica de negocio (que es la que vale).
1 | private void foo() throws Exception { |
Nunca lancen Exception como una excepción de su lógica de negocio y es que básicamente los catch están pensados en atrapar excepciones particulares y al lanzar Exception (de la mas alta jerarquía) jamás entrarás al bloque catch que corresponda y que pueda gestionar el error. Por otro lado el programador pierde la visibilidad de los errores particulares que debe gestionar.
1 | private void foo() throws Exception { |
Jamás se debe hacer esto, jamás!. Esto romperá todo tu programa ya que al lanzar la excepción RuntimeException esta llegará sin control a la capa mas alta provocando un error. Recuerden que ese tipo de excepciones son errores sin recuperación y justamente estamos tratando de hacer lo contrario gestionar los errores de lógica de negocio.
Esta sección del post quizás sea el más polémico ya que no hay receta perfecta para el manejo de excepciones y daré mis consejos (personales), puede que estén de acuerdo como puede que no.
Les recomiendo siempre mantener un árbol de excepciones que representen los errores (de negocio y de ejecución) de tu aplicación. Para que sea mas simple la mantención del árbol de excepciones, usen polimorfismo, herencia y todas las herramientas que ofrece OOP. En este punto siempre hay detractores de los árboles de excepciones con la excusa de su mantención.
Contraria a mi propuesta de manejo de errores, existen quienes mantienen sólo 1 excepción y a dicha excepción le agregan atributos y cuanta metadata puedan agregar. Qué se consigue finalmente con ese esquema de errores, es llenarte de IF por todos lados mirando los atributos que contiene la instancia de excepción y haciendo todo un control de errores manual.
Quedan muchas cosas por mencionar de las excepciones y ahondar mucho mas en cómo diseñar y construir un árbol de excepciones, creo que sera materia para otro artículo. Demás esta decirles que esta abierta la discusión. Los comentarios bienvenidos sean.
]]>En Java las constantes por lo general se declaran en estilo uppercase usando como separador de palabras el underscore ALGO_COMO_ESTO, en este ejemplo, se pueden notar que agregan un underscore al principio (No lo haga!). Generalmente se usa underscore al principio para nombrar los atributos de una clase, de esta forma no usas this para identificar un atributo de clase.
Si va hacer algún tipo de control sobre una exception, pués hágalo. En este ejemplo sólo se captura la exception y se vuelve a lanzar. Si realmente quiere hacer eso, no haga el *catch] de la exception, déjela salir libremente.
Si esta programando y al final de su algoritmo, le queda algo parecido a lo que sale en la imagen, recapacite, tome aire y refactorice su código. Hay algunas alertas que se pueden ver fácilmente con la estética del código, es decir, al cómo queda escrito (forma, silueta). Hay algunos desarrolladores que les encanta tener sus líneas de código hasta el infinito, lo que dificulta su lectura cuando tienes una pantalla distinta a la del desarrollador.
Otro ejemplo más:
Algunos consejos que te ayudarán a darte cuenta de errores en tu código de forma visual, aquí los dejo:
Estos son mis ajustes en el STS/Eclipse:
Si esta escribiendo código Java, por favor no cometa este error. Si va a declarar una variable, hágalo en el lugar donde se utilizará, de esta forma los refactoring de código son mas simples. Por otro lado, estéticamente queda feo tu código. Ahora si entramos en el micro manejo de memoria, posiblemente estas reservando memoria que no utilizarás en todo el método. En este ejemplo, se declaran muchas variables con un valor, pero que pasa si salta una exception? o algún control de flujo que no considere todas las variables?, habrás perdido innecesariamente un par de bytes.
Nunca, pero nunca, asignes a una variable el valor de una constante, no tiene ningún sentido. Además en este ejemplo, podrán notar que hay código que no tiene ningún sentido, nameCombobox nunca jamás en la vida va a ser null por lo tanto ese if esta de sobra. Escriba código que realmente es útil y que funciona.
Hay algunas cosas que no tienen una explicación razonable, como instanciar un objeto para luego no utilizarlo. Esto sólo provoca perdida de preciados bytes y ciclos de procesador.
Creo que califica en la misma descripción de arriba, escriba código que funcione.
Si va a utilizar StringBuffer hágalo de la forma correcta, se merece un mínimo de respeto dicha clase.
Evite el código que está de más, la API de commons-lang StringUtils.isEmpty() evalua que sea null y vacío. Ahora bien en el código podrían utilizar de la misma API StringUtils.isNotEmpty() y con eso le sacan el signo ! y todo queda mas bonito, por su puesto que la primera parte del if vuela también del código.
Finalmente esto se traduce en:
1 | if (StringUtils.isNotEmpty(codeAdditional)){ |
Espero les sirvan estos anti-ejemplos de código fuente. A medida que siga revisando código iré agregando algún otro post con mas código para el bronce. La discusión esta abierta por si quieren agregar algún otro tip.
]]>PD: Las variables han sido renombradas para proteger a los verdaderos autores, cualquier coincidencia con la realidad es casualmente cierta y verídica.
Aún recuerdo cuando entré a trabajar como informático y me recibieron con este artículo. (ping @ferchik)
Pues aquí mi grano de arena para que este artículo no se pierda. Aquí va el artículo.
Para algunas personas que sólo han tenido un contacto breve con la Programación Extrema, pareciera que la XP convoca a la muerte del diseño de software. No solamente se ridiculiza a la actividad de diseño como “Big Up Front Design”, sino que técnicas como UML, marcos flexibles e incluso patrones son menospreciados o simplemente ignorados. De hecho la XP involucra mucho diseño, pero lo hace de una manera diferente a la de los procesos de software establecidos. La XP ha rejuvenecido la noción de diseño evolutivo con prácticas que permiten a la evolución ser una estrategia de diseño viable. También brinda nuevos retos y habilidades pues los diseñadores necesitan aprender cómo hacer diseño simple, cómo usar refactorización para mantener el diseño limpio y cómo usar patrones en un estilo evolutivo.
La Programación Extrema (XP por sus siglas en inglés) desafía muchos de los presupuestos comunes acerca del desarrollo de software. La más controversial es el rechazo a un esfuerzo significativo en el diseño previo, en favor de un estilo más evolutivo. Para sus detractores, esto es un retorno al desarrollo “codificar y corregir” - usualmente denostado como hackear. Para sus fans esto es frecuentemente visto como un rechazo a técnicas de diseño (tal como el UML), principios y patrones. No preocuparse por el diseño, si escuchas tu código un buen diseño aparecerá.
Me encuentro en el centro de este debate. Gran parte de mi carrera ha involucrado lenguajes gráficos de diseño -el Unified Modeling Language (UML) y sus seguidores- y patrones. Realmente he escrito libros tanto sobre UML como sobre patrones. ¿Significa mi adhesión a la XP una renuncia a todo lo que he escrito sobre esos temas, limpiando mi mente de todas esas nociones contrarrevolucionarias?
Bueno, no puedo prolongar más el suspenso. La respuesta corta es no. La larga es el resto de este artículo.
Voy a describir dos estilos de cómo se diseña en desarrollo de software. Quizá el más común es el diseño evolutivo. Esencialmente, evolutivo significa que el diseño del sistema crece conforme se implanta el sistema. El diseño es parte del proceso de programación y conforme el programa evoluciona el diseño cambia.
En su uso común, el diseño evolutivo es un desastre. El diseño acaba siendo la agregación de una sarta de decisiones tácticas ad-hoc, cada una de las cuales hace el código más difícil de modificar. Se podría alegar que eso no es diseño, ciertamente suele llevar a un diseño pobre. Como indica Kent, el diseño está para permitir cambiar el software fácilmente a largo plazo. Conforme el diseño se deteriora, igualmente se deteriora la capacidad de cambio. Se tiene el estado de entropía de software, conforme pasa el tiempo el diseño empeora y empeora. Esto no solo hace el software más difícil de cambiar, también facilita la generación de bugs y dificulta el encontrarlos y eliminarlos con seguridad. Esta es la pesadilla de “codifica y corrige”, donde los bugs devienen exponencialmente más costosos de arreglar conforme el proyecto avanza.
El diseño planeado es todo lo contrario, y contiene nociones nacidas de otras ramas de la ingeniería. Si usted quiere construir la casa de su perro, puede simplemente tomar unas tablas y construir una forma ruda. Si quiere construir un rascacielos, no puede hacerlo de la misma manera - se caería antes de terminar siquiera la mitad. Así que empieza con dibujos ingenieriles, hechos en un estudio ingenieril como en el que trabaja mi esposa en el centro de Boston. Conforme hace el diseño ella se figura todo el asunto, en parte por análisis matemático pero principalmente usando códigos de construcción. Los códigos de construcción son reglas acerca de cómo diseñar estructuras con base en la experiencia de qué es lo que funciona bien (y algo de matemáticas). Una vez hecho el diseño, su compañía ingenieril puede pasar el diseño a otra empresa que lo construya.
El diseño planeado en software debería funcionar de la misma manera. Los diseñadores piensan los grandes problemas con anticipación. No necesitan programar porque no están construyendo el software, sólo lo están planeando. Así que pueden usar técnicas de diseño como el UML que deja de lado algunos de los detalles de la programación y permite a los diseñadores trabajar a un nivel más abstracto. Una vez hecho el diseño, pueden pasarlo a otro grupo (o a otra compañía) que lo construya. Ya que los diseñadores están pensando en una escala mayor, pueden evitar las series de decisiones tácticas que llevan a la entropía del software. Los programadores pueden seguir la dirección del diseño y, dado que siguen el diseño al pie de la letra, tener un sistema bien construido.
Ahora bien, el diseño planeado ha estado allí desde los 70s, y mucha gente lo ha usado. Es mejor en muchas formas que el diseño evolutivo de codificar y corregir. Pero tiene algunas fallas. La primera es que es imposible pensar en todos los problemas que se necesitan tratar cuando se programa. Es inevitable que al programar se encuentren cosas que ponen en entredicho el diseño. Si los diseñadores ya acabaron y ya están en otro proyecto, ¿qué pasa? Los programadores empiezan a codificar en torno al diseño y la entropía aparece. Aún si el diseñador no se ha ido, lleva tiempo organizar los problemas de diseño, cambiar los dibujos y alterar el código. Usualmente se hace una corrección rápida por la presión de tiempo. Entropía (otra vez).
Además frecuentemente hay un problema cultural. Los diseñadores se han formado por su habilidad y experiencia, pero están tan ocupados trabajando en diseños que ya no tienen tiempo para programar. Sin embargo las herramientas y materiales de desarrollo de software cambian rápidamente. Cuando dejas de programar no solo pierdes los cambios que ocurren en este flujo tecnológico, también pierdes el respeto de los que sí programan.
Esta tensión entre constructores y diseñadores también existe en la construcción, pero es más intensa en el software. Es intensa porque hay una diferencia clave. En construcción hay una división clara de habilidades entre los que diseñan y los que construyen, pero en software no es tanto así. Cualquier programador trabajando en ambientes de alto diseño necesita ser muy hábil. Lo suficientemente hábil para cuestionar los diseños del diseñador, especialmente cuando el diseñador sabe menos acerca de las realidades diarias de la plataforma de desarrollo.
Ahora bien, estos problemas pueden corregirse. Podríamos manejar la tensión humana. Quizá podemos conseguir diseñadores tan hábiles para tratar con la mayoría de los problemas y tener un proceso suficientemente disciplinado para cambiar los dibujos. Aún hay otro problema: los requerimientos cambiantes. Ese es el problema número uno, causante de dolores de cabeza en los proyectos de software en que he participado.
Una manera de controlar los requerimientos cambiantes es añadir flexibilidad en el diseño de modo que se pueda cambiar fácilmente conforme cambian los requerimientos. Esto requiere perspicacia en la clase de cambios esperados. Un diseño puede planearse para tratar con áreas de volatilidad, pero mientras eso ayuda con cambios de requerimientos previstos, no ayuda (y puede dañar) con cambios imprevistos. Así que los requerimientos tienen que entenderse lo suficientemente bien para separar las áreas volátiles, y en mi experiencia eso es muy difícil.
Algunos de estos problemas de requerimientos se deben a la falta de un entendimiento claro de los mismos. Mucha gente se enfoca en los procesos de ingeniería de requerimientos con la esperanza de que esto prevendrá la necesidad de cambiar el diseño más tarde. Pero aún esta receta puede no llevar a la cura. Muchos requerimientos cambiantes imprevistos ocurren debido a cambios en el negocio. Esos no pueden prevenirse, no importa cuan cuidadoso sea el proceso de ingeniería de requerimientos.
Esto hace sonar imposible al diseño planeado. Ciertamente estos son grandes retos. Pero no me inclino a afirmar que el diseño planeado es peor que el evolutivo, bajo el estilo “codifica y corrige”. De hecho prefiero el diseño planeado. No obstante estoy consciente de los problemas del diseño planeado y busco una dirección nueva.
La XP es controversial por muchas razones, pero una de las banderas rojas clave de la XP es que aboga por el diseño evolutivo en lugar del diseño planeado. Como sabemos, el diseño evolutivo no puede funcionar debido a decisiones ad-hoc y la entropía de software.
El meollo para entender este argumento es la curva de cambio del software. La curva del cambio dice que mientras más avanza el proyecto, es exponencialmente más caro hacer cambios. La curva del cambio se expresa usualmente en términos de las fases “un cambio hecho en el análisis por $1 cuesta miles en producción”. Esto es irónico ya que la mayoría de los proyectos aún trabajan en un proceso ad-hoc que no tiene una fase de análisis, pero las exponenciaciones aún están allí. La curva exponencial del cambio significa que el diseño evolutivo no puede funcionar. También explica por qué el diseño planeado debe ser hecho cuidadosamente porque cualquier error encara la misma exponenciación.
La suposición fundamental de la XP es que es posible aplanar la curva del cambio lo suficiente como para hacer que funcione el diseño evolutivo. Este aplanamiento es a la vez permitido y explotado por la XP. Esto es parte del enganche de prácticas en XP: específicamente no puedes hacer todas las cosas que explotan la curva aplanada sin hacer las cosas que permiten aplanarla. Esta es una fuente común de controversia sobre la XP. Mucha gente critica la explotación sin entender la habilitación. Frecuentemente las críticas surgen de la propia experiencia de los críticos que no hicieron las prácticas habilitadoras que permiten funcionar a las prácticas explotadoras. Como resultado se quemaron y cuando ven la XP recuerdan el fuego.
En el centro de las prácticas habilitadoras están las de Pruebas e Integración Continua. Sin la seguridad dada por las pruebas el resto de la XP sería imposible. La integración continua es necesaria para mantener al equipo en sincronía, de modo que puedas hacer un cambio sin preocuparte de integrarla con otra gente. Juntas, estas prácticas pueden tener un gran efecto en la curva del cambio. Me acordé de esto otra vez aquí en ThoughtWorks. La introducción de Pruebas e Integración Continua ha marcado un mejoramiento en el esfuerzo de desarrollo. Ciertamente suficiente para cuestionar seriamente la afirmación de la XP de que necesitas todas las prácticas para lograr una gran mejoría.
La refactorización tuvo un efecto similar. La gente que refactoriza su código de la manera disciplinada sugerida por la XP encuentra una diferencia significativa en la efectividad comparada a hacer una reestructuración relajada más ad-hoc. Esa fue ciertamente mi experiencia una vez que Kent me enseñó a refactorizar propiamente. Después de todo, sólo un cambio así de fuerte me habría motivado a escribir un libro entero sobre el tema.
Jim Highsmith, en su excelente resumen de la XP, usa la analogía de un conjunto de escalas. En una bandeja está el diseño planeado, en la otra la refactorización. En propuestas más tradicionales el diseño planeado domina porque se supone que no puedes cambiar de idea más tarde. Conforme baja el costo del cambio puedes hacer más con tu diseño más tarde como refactorización. El diseño planeado no se esfuma, solo que ahora hay un balance entre los dos acercamientos. Para mi, siento que antes de la refactorización estaba diseñando con una sola mano.
Estas prácticas habilitadoras de integración continua, pruebas y refactorización, crean un nuevo ambiente que hace plausible el diseño evolutivo. Sin embargo algo que aún no imaginamos es el lugar del punto de equilibrio. Estoy seguro de que, a pesar de la impresión externa, XP no es sólo prueba, codifica y refactoriza. Hay espacio para el diseño antes de codificar. Algo de esto ocurre antes de que se haya código, la mayor parte ocurre en las iteraciones antes de codificar una tarea particular. Pero hay un nuevo balance entre diseño up-front y refactorización.
Dos de los más grandes gritos de batalla de la XP son los eslogans “Haz la cosa más simple que pueda funcionar” y “No lo vas a necesitar” (conocido como YAGNI por sus siglas en inglés). Ambos son manifestaciones de la práctica XP del diseño simple.
La manera en que usualmente se describe YAGNI, es que no deberías añadir hoy código que sólo será usado por alguna característica que será necesaria mañana. En principio esto suena simple. El problema viene con cosas tales como marcos (frameworks), componentes reusables, y diseño flexible. Tales cosas son complicadas de construir. Se paga un costo up-front extra para construirlas, en la expectativa de que recuperarás ese costo más tarde. Esta idea de construir flexibilidad up-front es vista como la parte clave del diseño de software efectivo.
Sin embargo el consejo de la XP es que no construyas componentes flexibles y frameworks para el primer caso que necesite esa funcionalidad. Deja crecer esas estructuras como se necesiten.
Si quiero una clase Money hoy que maneje adición pero no multiplicación entonces solo construyo adición en la clase Money. Aún si estoy seguro de que necesitaré multiplicación en la iteración siguiente, y entiendo cómo hacerlo fácilmente, y creo que sería realmente rápido hacerlo, aún así lo dejaré para la siguiente iteración.
Una razón de esto es económica. Si tengo que trabajar por una característica que sólo se necesitará mañana, estoy comprometiendo esfuerzo de características que necesitan hacerse para la iteración actual. El plan de entrega dice qué es lo que necesita trabajarse ahora, trabajar en cosas del futuro es contrario a los acuerdos de los desarrolladores con el cliente. Hay un riesgo de que las historias de la iteración pudieran no hacerse. Aún si estas historias de la iteración no están en riesgo depende del cliente decidir que trabajo extra debe hacerse -y que podría no incluir aún la multiplicación.
Este contraincentivo económico es reforzado por la posibilidad de que pudiéramos no hacerlo bien. Como sea que estemos seguros de que esta función trabaja, aún podríamos equivocarnos -especialmente si aún no tenemos requerimientos detallados. Trabajar en la solución errónea anticipadamente es aún peor despilfarro que trabajar en la función correcta con anticipación. Y los XPertos generalmente creen que es más probable que nos equivoquemos (y yo concuerdo con esa opinión).
La segunda razón por el diseño simple es que un diseño complejo es más difícil de entender que un diseño simple. Por lo tanto cualquier modificación al sistema se hace más difícil por la complejidad añadida. Esto agrega un costo en el periodo que va de cuando el diseño más complicado se añadió a cuando se necesitó.
Ahora bien, para mucha gente este consejo no tiene sentido, y tienen razón. Tienen razón si te imaginas en el mundo de desarrollo convencional donde las prácticas habilitadoras de la XP no existen. No obstante, cuando el balance entre diseño planeado y evolutivo cambia, entonces YAGNI se convierte en una buena práctica (y sólo entonces).
Para resumir, no debes gastar esfuerzo añadiendo cosas que no serán necesarias hasta una iteración futura. Aun si el costo es cero, no debes porque eso incrementa el costo de modificación. De cualquier manera sólo puedes comportarte así si estás usando XP o alguna práctica similar que baje el costo del cambio.
Así que queremos nuestro código tan simple como sea posible. Eso no suena difícil de sostener, después de todo ¿quién quiere ser complicado? Pero desde luego esto trae la pregunta “¿qué es simple?”
En XPE Kent da cuatro criterios para un diseño simple, en orden de importancia:
El que corran todas las pruebas es un criterio muy simple. No duplicación también es muy directo, aunque muchos de los desarrolladores necesitan guía para lograrlo. El truco tiene que ver con revelar la intención. ¿Qué significa eso exactamente?
El valor básico aquí es claridad de código. XP pone en alto el código fácil de leer. En XP “código astuto” es un término de abuso. Pero para algunas personas, el código que revela la intención es otra astucia.
En su artículo en XP 2000, Josh Kerievsky señala un buen ejemplo de esto. El atiende al que posiblemente es el código XP más público - JUnit. JUnit usa decoradores para añadir funcionalidad opcional a los casos de prueba, tales como sincronización concurrente y código batch set up. Separando este código en decoradores permite al código general ser más claro de lo que podría ser.
Pero uno se pregunta si el código resultante es realmente simple. Para mí lo es, pero estoy familiarizado con el patrón Decorator. Pero para muchos que no lo están esto es muy complicado. Similarmente JUnit usa métodos enchufables los cuales, he notado, la mayoría de la gente los encuentra cualquier cosa menos claros. ¿Así que debemos concluir que el diseño de JUnit es simple para diseñadores experimentados pero complicado para los menos experimentados?
Yo creo que el meollo en eliminar la duplicación, tanto el “Una vez y sólo una vez” de la XP y el DRY (Don’t Repeat Yourself) del Programador Pragmático es uno de esos obvios y maravillosamente poderosos buenos consejos. El solo seguirlo puede llevar muy lejos. Pero no es todo, y la simplicidad es aún algo complicado de hallar.
Recientemente me vi envuelto en hacer algo que bien podría estar sobrediseñado. Lo arreglamos refactorando y removiendo algo de su flexibilidad. Pero como uno de los desarrolladores dijo “es más fácil refactorizar sobrediseño que refactorizar sin diseño”. Es mejor ser un poco más simple de lo que necesitas ser, pero no es un desastre ser un poco más complejo.
El mejor consejo que he escuchado sobe todo esto vino del tío Bob (Robert Martin). Su consejo fue no demorarse mucho sobre cual es el diseño más simple. Después de todo se puede, se debe y se refactorará más tarde. Al final la disposición a refactorizar es más importante que saber que la cosa más simple ya está.
Este asunto surgió recientemente en la lista de correo XP, y vale la pena traerlo a colación, ya que estamos viendo el rol del diseño en la XP.
Básicamente la cuestión empieza con el punto de que la refactorización toma tiempo pero no añade funcionalidad. Como el punto del YAGNI es que se supone que se debe diseñar para el presente y no para el futuro, ¿es esto una violación?
El punto de YAGNI es no añadir complejidad innecesaria para las historias actuales. Esto es parte de la práctica del diseño simple. Refactorizar es necesario para mantener el diseño tan simple como puedas, así que debes refactorizar cuando notes que puedes simplificar las cosas.
El diseño simple explota las prácticas de la XP y es también una práctica habilitadora. Sólo si has hecho pruebas, integrado continuamente y refactorizando puedes practicar el diseño simple efectivamente. Pero al mismo tiempo, mantener el diseño simple es esencial para mantener la curva del cambio plana. Cualquier complejidad innecesaria hace al sistema difícil de cambiar en toda dirección excepto la que anticipaste con la complicada flexibilidad añadida. Sin embargo la gente no es buena anticipando, así que es mejor esforzarse por la simplicidad. No se obtiene la cosa más simple la primera vez, así que necesitas refactorizar para acercarte a la meta.
El ejemplo JUnit me lleva inevitablemente a los patrones. La relación entre patrones y la XP es interesante y es una cuestión común. Joshua Kerievsky arguye que los patrones son subestimados en la XP y lo sustenta elocuentemente, así que no lo repetiré. Pero vale la pena tomar en cuenta que para mucha gente los patrones parecen estar en conflicto con la XP.
La esencia de este argumento es que los patrones frecuentemente se sobreutilizan. El mundo esta lleno del legendario buen programador, fresco de su primera lectura del GOF que incluye 16 patrones en 32 líneas de código. Recuerdo una tarde, alimentada por una muy buena cerveza, trabajando con Kent en un artículo que sería llamado “Patrones de No Diseño: 23 trucos baratos”. Estábamos pensando en cosas como usar una declaración if en lugar de una estrategia. La broma tenía una razón, los patrones son frecuentemente sobreutilizados, pero eso no los hace tan mala idea. La cuestión es cómo los usas.
Una teoría es que las fuerzas del diseño simple te llevarán a los patrones. Muchas refactorizaciones hacen esto explícitamente, pero aún sin ellas siguiendo las reglas del diseño simple llegarás a los patrones aun si no los conoces previamente. Esto puede ser cierto pero, ¿es la mejor forma de hacerlo? Seguramente es mejor si sabes toscamente a dónde vas y tienes un libro que te guíe en lugar de tener que inventarlo tú mismo. Yo ciertamente aún uso el GOF cuando siento que surge un patrón. Para mí el diseño efectivo implica que necesitamos saber si vale la pena pagar el precio de un patrón -eso es su propia habilidad. Similarmente, como sugiere Joshua, necesitamos estar más familiarizados acerca de cómo llegar a un patrón gradualmente. En este respecto la XP trata la manera en que usamos patrones diferente a la manera en que algunas personas los usan, pero ciertamente no elimina su valor.
Leyendo algunas de las listas de correo tengo la sensación de que mucha gente ve a la XP como desalentadora de patrones, a pesar de la ironía de que la mayoría de los proponentes de la XP también han sido líderes del movimiento de los patrones. ¿Será que ellos han visto más allá de los patrones, o tienen a los patrones tan embebidos en su pensamiento que ellos ya no lo notan? No sé la respuesta para otros, pero para mí los patrones aún son vitalmente importantes. XP puede ser un proceso de desarrollo, pero los patrones son una columna vertebral del conocimiento de diseño, conocimiento que es valioso cualquiera que sea el proceso. Procesos diferentes pueden usar patrones de diferente manera. XP enfatiza no usar patrones hasta que sea necesario y evolucionar el camino hacia un patrón vía una implementación simple. Pero los patrones son todavía una pieza clave de conocimiento a adquirir.
Mi consejo a los XPeros en el uso de patrones es:
Pienso que la XP debería enfatizar aprender más sobre patrones. No estoy seguro de cómo encajaría esto en las prácticas de la XP, pero estoy seguro que Kent puede encontrar la manera.
¿Qué queremos decir con arquitectura de software? Para mí el término arquitectura conlleva una noción de los elementos centrales del sistema, las piezas que son difíciles de cambiar. Un fundamento sobre el cual debe construirse el resto.
¿Qué rol juega la arquitectura cuando usamos diseño evolutivo? De nuevo los críticos de la XP afirman que la XP ignora la arquitectura, que la ruta de la XP es ir hacia la codificación rápida y confiar en que la refactorización resolverá todos los problemas de diseño. Interesantemente tienen razón, y eso bien puede ser una debilidad. Ciertamente los más agresivos XPeros - Kent Beck, Ron Jeffries y Bob Martin - están poniendo más y más energía en evitar cualquier diseño arquitectónico. No pongas una base de datos hasta que realmente sepas que la necesitas. Trabaja con archivos primero y refactoriza a la base de datos en una iteración posterior.
Yo soy conocido por ser un XPero cobarde, y como tal tengo que discordar. Yo creo que hay lugar para una amplia arquitectura inicial. Cosas tales como establecer temprano cómo separaremos la aplicación, como interaccionaremos con la base de datos (si hace falta una), qué estrategia usar para manejar el servidor web.
Esencialmente creo que muchas de estas áreas son patrones que hemos aprendido a través de los años. Conforme crece el conocimiento de patrones, se debe tener una idea razonable de cómo usarlos. De cualquier modo la diferencia clave es que no se espera poner en piedra estas decisiones arquitectónicas tempranas , o bien el equipo sabe que ellas pueden errar sus decisiones tempranas y deberán tener el valor de arreglarlas. Otros cuentan la historia de un proyecto en que, cerca de la implantación, deciden que no necesitaban más EJB y lo quitaron del sistema. Fue una refactorización considerable, se hizo tarde, pero las prácticas habilitadoras lo hicieron no sólo posible, sino valioso.
Cómo habría funcionado esto de la otra manera. Si decides no usar EJB, ¿habría sido más difícil añadirlo luego? ¿No debes pues empezar con EJB hasta que hayas tratado cosas sin él y encontrado su falta? Es una pregunta que implica varios factores. Ciertamente trabajar sin un componente complejo incrementa la simplicidad y hace las cosas ir más rápido. Sin embargo algunas veces es más fácil sacar algo que meterlo.
Mi consejo es empezar estimando la arquitectura probable. Si ves un gran montón de datos con múltiples usuarios, adelante, usa una base de datos desde el primer día. Si ves lógica de negocio compleja, pon un modelo del dominio. De cualquier modo en deferencia a los dioses del YAGNI, cuando dudes ve al lado de la simplicidad. También prepárate para simplificar tu arquitectura tan pronto veas que parte de la misma no está dando nada.
De todas las preguntas que me hacen sobre mi compromiso con la XP una de las más grandes es respecto a mi asociación con el UML. ¿No son los dos incompatibles?
Hay un número de puntos de incompatibilidad. Ciertamente la XP menosprecia los diagramas en gran medida. Aunque la posición oficial es en la línea de “úsalos si son útiles”, se puede leer entre líneas “los verdaderos XPeros no diagraman”. Esto se refuerza con el hecho de que gente como Kent no se sienten cómodos con los diagramas, de hecho nunca he visto a Kent dibujar voluntariamente un diagrama de software en ninguna notación fija.
Yo creo que el asunto viene de dos causas separadas. Una es el hecho de que algunas personas encuentran los diagramas útiles y otras no. El peligro está en los que piensan que quienes no los usan deberían usarlos y viceversa. En lugar de eso deberíamos aceptar que algunos usen diagramas y otros no.
El otro problema es que los diagramas tienden a asociarse con procesos pesados. Tales procesos gastan mucho tiempo en dibujar diagramas que no ayudan y pueden dañar. De manera que pienso que la gente debe ser guiada en cómo usar bien los diagramas y evitar las trampas, en lugar del mensaje “solo si tienes que” de los XPertos.
Aquí esta mi consejo para usar bien los diagramas.
Primero piensa para qué los estás dibujando. El principal valor es la comunicación. Comunicación efectiva significa seleccionar las cosas más importantes y descuidar las menos. Esta selectividad es la clave para usar bien el UML. No dibujes cada clase -sólo las importantes. Para cada clase, no muestres cada atributo y operación -sólo los importantes. No dibujes diagramas de secuencia para todos los casos de uso y escenarios -sólo… ya lo entiendes. Un problema común con el uso de los diagramas es que la gente intenta hacerlos extensos. El código es la mejor fuente de información extensa ya que el código es lo más fácil de mantener en sincronía con el código. La exhaustibilidad de los diagramas es la enemiga de su comprensión.
Un uso común de los diagramas es explorar un diseño antes de empezar a programarlo. Frecuentemente se tiene la impresión de que tal actividad es ilegal en XP, pero eso no es cierto. Mucha gente dice que cuando se tiene una tarea difícil vale la pena juntarse para tener una sesión de diseño rápido. De cualquier manera cuando hagan tales sesiones:
El último punto merece extenderse. Cuando se hace un diseño up-front, inevitablemente encontrarás que algunos aspectos del diseño están mal, y eso sólo se descubre cuando lo programas. Eso no es un problema dado que entonces cambias el diseño. El problema viene cuando la gente piensa que el diseño está hecho y entonces no aprovechan la oportunidad de devolver al diseño el conocimiento adquirido al programar.
Cambiar el diseño no necesariamente implica cambiar los diagramas. Es perfectamente razonable dibujar diagramas que te ayuden a entender el diseño y entonces hacerlos a un lado. El dibujarlos ayudó y eso es suficiente para que valga la pena hacerlos. Pero no tienen que ser artefactos permanentes. Los mejores diagramas UML no son artefactos.
Muchos XPeros usan tarjetas CRC. Eso no entra en conflicto con el UML. Yo uso una mezcla de CRC y UML todo el tiempo, usando la técnica que sea más útil para el trabajo en mano.
El consejo de documentación sobre la marcha viene de estos problemas observados:
El último aspecto de usar UML es para documentación en una situación de relevo, tal como cuando un grupo ocupa el lugar de otro. Aquí el punto XP es que producir documentación es una historia como cualquier otra, y así su valor de negocio es determinado por el cliente. Otra vez la UML es útil aquí, los diagramas son selectivos para ayudar a la comunicación. Recuerda que el código es el repositorio de información detallada, el diagrama actúa para resumir y resaltar asuntos importantes.
Bueno, podría decirlo públicamente -no he captado el punto de esta cosa, metáfora. La he visto funcionar, y funcionó bien en el proyecto C3, pero eso no significa que yo tenga una idea de cómo hacerla, ni menos cómo explicar cómo hacerla.
La práctica XP de la metáfora se originó a partir de la propuesta de Ward Cunningham de un sistema de nombres. El punto es que vienes con un bien conocido conjunto de nombres que actúan como vocabulario para hablar acerca del dominio. Este sistema de nombres juega en el modo en que nombras las clases y métodos en el sistema.
He construido un sistema de nombres construyendo un modelo conceptual del dominio. Lo he hecho con los expertos del dominio usando UML o sus predecesores. He encontrado que hay que ser cuidadoso al hacerlo. Se necesita mantener un conjunto de notación mínimo y tienes que guardarte de dejar que cualquier asunto técnico se cuele en el modelo. Pero si lo haces, he encontrado que puedes usarlo para construir un vocabulario del dominio que los expertos del dominio puedan entender y usarlo para comunicarse con los desarrolladores. El modelo no empareja con el diseño de clases perfectamente, pero es suficiente para dar un vocabulario común de todo el dominio.
Ahora, no veo ninguna razón por la que este vocabulario no pueda ser metafórico, tal como la metáfora C3 en que la nómina se convirtió en una linea de ensamblaje de fábrica. Pero tampoco veo por qué el basar tu sistema de nombres en el vocabulario del dominio sea tan mala idea. Ni me inclino a abandonar una técnica que funciona bien para mi obteniendo los nombres del sistema.
Frecuentemente se critica a la XP sobre la base de que se necesita al menos algún esbozo de diseño de un sistema. Los XPeros frecuentemente responden con la respuesta “esa es la metáfora”. Pero yo aún no creo haber visto una explicación convincente de la metáfora. Este es un hoyo real en la XP, y uno que el XPero necesita sortear.
En la última década, el término “arquitecto de software” se ha vuelto popular. Es un término que me resulta difícil de usar. Mi esposa es ingeniero estructural. La relación entre ingenieros y arquitectos es … interesante. Mi favorito es “los arquitectos son buenos para las tres B’s: bulbos, bushes [arbustos], birds [pájaros]”. La idea es que los arquitectos salen con todos esos dibujos bonitos, pero son los ingenieros quienes tienen que asegurarse de que realmente puedan ponerse en pie. Como resultado he evitado el término arquitecto de software; después de todo si mi esposa no puede tratarme con respeto profesional quién puede hacerlo.
En software, el término arquitecto significa muchas cosas. (En software cualquier término significa muchas cosas.) En general, sin embargo conlleva ciertos problemas, como “no soy un mero programador -soy un arquitecto”. Esto puede traducirse como “ahora soy un arquitecto -soy demasiado importante como para programar”. La cuestión es si separarte del mundano esfuerzo de programar es algo que debes hacer si quieres ejercer liderazgo técnico.
Esta cuestión genera demasiada emoción. He visto gente enojarse mucho al pensar que no tienen más el rol de arquitectos. “No hay lugar en XP para arquitectos experimentados” es el grito que frecuentemente escucho.
Tanto como en el rol del diseño en sí, no creo que sea el caso que la XP no valore la experiencia de o las buenas habilidades de diseño. En realidad muchos de los proponentes de la XP - Kent Beck, Bob Martin, y desde luego Ward Cunningham - están entre de quienes he aprendido mucho acerca de lo que es el diseño. De cualquier manera esto significa que sus roles difieren de lo que mucha gente ve como un rol de liderazgo técnico.
Como ejemplo, citaré a uno de nuestros líderes técnicos en ThoughtWorks: Dave Rice. Dave ha estado en varios ciclos de vida y se ha puesto el sombrero extraoficial de líder técnico en un proyecto de 50 personas. Su rol como líder significa gastar mucho tiempo con los programadores. El trabaja con un programador cuando éste necesita ayuda, siempre anda merodeando para ver quién necesita ayuda. Una señal significativa es cuando se sienta. Como un trabajador de mucho tiempo en ThoughtWorks, él podría muy bien tener la oficina que quisiera. Compartió una por un tiempo con Cara, la gerente de entregas. Sin embargo en los últimos meses se mudó a las bahías abiertas donde trabajan los programadores (usando el estilo abierto “war room” que la XP favorece). Esto es importante para él porque de este modo ve lo que está pasando y está disponible para dar la mano donde se necesite.
Aquellos que saben XP se darán cuenta de que estoy describiendo el rol explícito de Coach. En verdad uno de los varios juegos de palabras que hace la XP es que llama a la figura de primer técnico el “Coach”. El significado es claro: en XP el liderazgo técnico se muestra enseñando a los programadores y ayudándolos a tomar decisiones. Es uno que requiere buena habilidad de gentes tanto como buenas habilidades técnicas. Jack Bolles en XP 2000 comentó que hay poco espacio ahora para el maestro solitario. Colaboración y enseñanza son las claves del éxito.
En una cena en una conferencia, Dave y yo hablábamos con un oponente a la XP. Conforme discutíamos lo que hacíamos, las similaridades de nuestro enfoque eran marcadas. Todos nosotros gustábamos del desarrollo adaptativo e iterativo. Las pruebas eran importantes. Así que nos tenía perplejos su oposición. Entonces vino esta declaración en la línea de “lo último que quiero es que mis programadores refactoren y manoseen el diseño”. Ahora todo estaba claro. La laguna conceptual me la explicó Dave “si él no confía en sus programadores ¿por qué los contrata?”. En XP la cosa más importante que puede hacer el desarrollador experimentado es pasar cuantas habilidades pueda a los desarrolladores junior. En lugar de un arquitecto que toma todas las decisiones importantes, tienes un coach que enseña a los desarrolladores a tomar decisiones importantes. Como Ward Cunningham señaló, así él amplía sus habilidades y añade más a un proyecto de lo que cualquier héroe solitario podría.
En la XP 2000 Enrico Zaninotto dió una plática fascinante en la que discutió la relación entre los métodos ágiles y la manufactura moderna. Según él, uno de los aspectos clave de ambos enfoques es que atajan la complejidad al reducir la irreversiblidad del proceso.
Desde esta vista una de las principales fuentes de complejidad es la irreversibilidad de las decisiones. Si puedes cambiar tus decisiones, no es tan importante que sean correctas - lo que hace tu vida mucho más sencilla.
La consecuencia para el diseño evolutivo es que los diseñadores deben pensar en cómo evitar la irreversibilidad en sus decisiones. Más que tratar de tomar la decisión correcta ahora, busca una manera de posponerla (hasta que tengas más información) o toma la decisión de tal modo que seas capaz de revertirla después sin demasiada dificultad.
Esta determinación de mantener la reversibilidad es una de las razones de que los métodos ágiles pongan tanto énfasis en sistemas de control de código fuente y de ponerlo todo en esos sistemas. Mientras que esto no garantiza la reversibilidad, particularmente para decisiones de vida larga, proporciona un fundamento que da confianza al equipo, aun si rara vez se usa.
Diseñar para la irreversibilidad también implica un proceso que hace que los errores se muestren pronto. Uno de los valores del desarrollo iterativo es que las iteraciones rápidas permiten a los clientes ver el sistema conforme crece, y si se comete un error en los requerimientos, puede ser localizado y corregido antes de que el costo de la corrección sea prohibitivo. Esta misma localización rápida es importante para el diseño. Esto significa que tienes que poner las cosas de modo que las áreas potencialmente problemáticas sean rápidamente verificadas para ver qué problema sale. También significa que hay que hacer experimentos para ver qué tan difíciles pueden ser los cambios futuros, aun si no haces el cambio ahora - efectivamente desechando un prototipo de una rama del sistema. Varios equipos han reportado tratar un cambio futuro en modo prototipo temprano para ver qué tan difícil sería.
Aunque me he concentrado mucho en las prácticas técnicas en este artículo, una cosa que es muy fácil de pasar por alto es el aspecto humano.
Para funcionar, el diseño evolutivo necesita una fuerza que lo lleve a converger. Esta fuerza sólo puede venir de la gente -alguien en el equipo tiene que tener la deteminación para asegurar que la calidad del diseño permanezca alta.
Este deseo no tiene que venir de todos (aunque es bueno si así pasa), usualmente sólo una o dos personas en el equipo toman la responsabilidad de mantener el diseño íntegro. Esta es una de las tareas que usualmente caen bajo el término ‘arquitecto’.
Esta responsabilidad significa vigilar el código base, por si cualquier área del mismo se está enredando, y entonces actuar de inmediato para corregir el problema antes de que se salga de control. El encargado del diseño no tiene que ser el mismo que lo arregla - pero tiene que asegurarse de que alguien lo arregle.
La falta del deseo de diseñar parece ser una razón importante por la que el diseño evolutivo falla. Aun si la gente está familiarizada con las cosas de las que he hablado en este artículo, sin ese deseo no habrá diseño.
¿Podemos usar la refactorización para tratar todas las decisiones de diseño, o hay algunos asuntos tan diseminosos que son difíciles de añadir después? Actualmente, la XP ortodoxa dice que todas las cosas son fáciles de añadir cuando las necesitas, así que YAGNI siempre se aplica. Me pregunto si hay excepciones. Un buen ejemplo de algo que es controversial de añadir es la internacionalización. ¿Cuesta tanto añadirla después que deberías empezar con ella desde un principio?
Podría fácilmente imaginar que hay algunas cosas que caerían en esta categoría. Sin embargo la realidad es que aún tenemos muy pocos datos. Si tienes algo que añadir más tarde, como internacionalización, eres muy consciente del esfuerzo que tomará hacerlo. Eres menos consciente del esfuerzo que realmente habría tomado, semana tras semana, ponerlo y mantenerlo antes de que fuera necesario. También estás menos consciente del hecho de que bien podrías haberlo puesto mal, y así de todos modos tendrías que hacer algo de refactorización.
Parte de la justificación del YAGNI es que muchas de estas necesidades potenciales terminan no siendo necesarias, o al menos no en el modo que esperabas. El esfuerzo que ahorras no haciendo ninguna de ellas es menor al esfuerzo requerido para refactorizar las que realmente necesitas.
Otra cuestión a tener en cuenta es si realmente sabes cómo hacerlo. Si has hecho internacionalización varias veces, sabes los patrones que necesitas emplear. Como tal es más probable que lo hagas bien. Añadir estructuras anticipatorias es probablemente mejor si estás en esa posición, que si eres nuevo en el problema. Mi consejo sería que si sabes cómo hacerlo, estás en la posición de juzgar el costo de hacerlo o no hacerlo después. No obstante si no lo has hecho antes, no sólo no eres capaz de calcular el costo lo suficientemente bien, es menos probable que lo hagas bien. En ese caso deberías dejarlo para después. Si lo añades entonces, y lo encuentras doloroso, probablemente aún así estarás mejor de lo que estarías si lo hubieras instalado antes. Tu equipo es más experimentado, conoces mejor el dominio y entiendes mejor los requerimientos. A menudo en esta posición ves lo fácil que hubiera sido con una retrospectiva 20/20. Añadirlo antes puede ser mucho más difícil de lo que crees.
Esto trae a colación la cuestión del orden de las historias. En Planning XP, Kent y yo abiertamente manifestamos nuestro desacuerdo. Kent está a favor de dejar que los valores de negocio sean el único factor de orden de las historias. Después de un desacuerdo inicial, Ron Jeffries ahora coincide. Yo todavía no estoy seguro. Yo creo que hay un balance entre valores de negocio y riesgo técnico. Esto me llevaría a proveer al menos algo de internacionalización pronto para mitigar este riesgo. No obstante esto sólo es cierto si la internacionalización fuera necesaria para la primera entrega. Llegar a la entrega tan rápido como sea posible es vitalmente importante. Cualquier complejidad adicional debe hacerse después de la primera entrega si no se necesita para la primera entrega. El poder del código empacado y funcionando es enorme. Esto enfoca la atención del cliente, aumenta la credibilidad y es una fuente masiva de aprendizaje. Haz todo lo que puedas para adelantar esa fecha. Aún si es más esfuerzo añadir algo después de la primera entrega, es mejor entregar antes.
Una de las dificultades del diseño evolutivo es que es muy difícil decir si el diseño está realmente ocurriendo. El peligro de entremezclar diseño con programación es que puede haber programación sin diseño - esta es la situación donde el Diseño Evolutivo diverge y falla.
Si estás en el equipo de desarrollo, entonces sabes si el diseño está ocurriendo por la calidad del código base. Si el código base se vuelve más complejo y difícil de trabajar, no se está haciendo suficiente diseño. Pero este es tristemente un punto de vista subjetivo. No tenemos métricas confiables que nos permitan medir objetivamente la calidad del diseño.
Si esta falta de visibilidad es dura para personas técnicas, es más alarmante para miembros del equipo no técnicos. Si usted es un gerente o cliente ¿cómo puede decir si el software está bien diseñado? A usted le interesa porque un software pobremente diseñado será más caro de modificar en el futuro. No hay una respuesta fácil para esto, pero aquí van unas pocas sugerencias:
De ninguna manera, pero la naturaleza del diseño ha cambiado. El diseño XP busca las siguientes habilidades:
Esta es una selección pusilánime de habilidades, pero siempre ha sido difícil ser un buen diseñador. La XP no lo hace realmente más fácil, al menos para mí. Pero creo que la XP nos da una nueva forma de pensar acerca del diseño efectivo porque ha hecho el diseño evolutivo una estrategia plausible otra vez. Y yo soy un gran fan de la evolución -¿de otro modo quién sabe qué podría ser yo?
En los últimos años he recogido y robado muchas buenas ideas de mucha buena gente. La mayoría de ellas están perdidas en la turbiedad de mi memoria. Pero recuerdo haber pinchado buenas ideas de Joshua Kerievski. También recuerdo muchos comentarios útiles de Fred George y Ron Jeffries. Tampoco puedo olvidar cuantas buenas ideas siguen viniendo de Ward y Kent.
Siempre estoy agradecido de todos aquellos que hacen preguntas y señalan errores de tecleo. Me ha dado flojera mantener una lista de estos a reconocer, pero incluyen a Craig Jones, Nigel Thorne, Sven Gorts, Hilary Nelson, Terry Camerlengo.
He aquí una lista de las principales actualizaciones de este artículo
Traducción: Alejandro Sierra, marzo de 2003, revisada en septiembre de 2004.
]]>El año que recién pasó ha sido uno de los más complicados que me ha tocado en todo ámbito.
A principios de año nos dimos unas merecidas vacaciones en familia con destino La Serena, disfrutamos de unos lindos y temperados días. La Javi conoció la piscina y se largo a nadar (con alitas) sola.
Un hecho que nos pilló total y absolutamente de sorpresa fue la muerte de la mamá de la @guzyy Maruca, estábamos planificando un viaje para que viniera a conocer a la Valentina cuando naciera en un par de meses más. Fue un mes duro para la familia.
A mediados de año nuestra segunda hija, Valentina que llegó para revolucionar nuestras vidas. Si no sabe por qué, lea este post Mi valentina. Hemos aprendido (con la @guzyy y @javicollaov) a llevar este tema adelante y preparándonos para lo que se nos viene por delante, tratando de anticipar y planificar al corto plazo.
Mientras tanto, disfrutar al máximo a nuestra hija Valentina con cada logro, por muy pequeño que sea, desde sonreír hasta tomar algún objeto con su mano o tratar de sentarse sola.
La Javiera por su parte, ha aprendido muchas cosas y le interesan muchas otras que ni si quiera se pueden imaginar, como por ejemplo, los planetas, las estrellas o por qué la sangre es roja o qué son los anticuerpos. Está en la etapa en que todo se transforma en un:
…¿y po qué?
Ya que la Javi tiene gustos un tanto “científicos”, la lleve a conocer, en un tour de fin de año, El Planetario (que esta de pelos),el Museo Ferroviario de Santiago, El Museo Nacional de Historia Natural, el Museo de Ciencia y Tecnología. Aprendió sobre los planetas, estrellas y galaxias, además fuimos a conocer la ballena (que la encontró fome porque eran puros “huesitos”) y fuimos a experimentar con la luz, el sonido y la física.
La Javi acompañó a la @guzyy durante unos meses en el post-natal ayudando con su propio estilo de hacer las cosas. Aprendió a escuchar música rock y su grupo favorito es “el de los martillos” por Pink Floyd y The Wall. Fanática de 31 Minutos y no nos perdimos el show que dieron con Radio Guaripolo donde pudimos disfrutar (yo más que ella seguramente) de Fredy Turbina y la canción Mi Equilibrio Espiritual.
En el trabajo, me tocó compartir con un selecto grupo de egipcios a los que estimo mucho, vaya para ellos un abrazo (@rodchile, @lecaros, @solemoris, Camilo no más, la Caroline, Don Richie,el responsivo @rosoristico, @perrefe, @pabloc6, ordenados en orden de desaparición XD). Con ellos compartimos la creación de un nuevo producto, compartimos muchas reuniones donde definimos desde nuestro punto de vista, que era lo mejor para dicho producto, desde lo mas geek/nerd técnico hasta los colores y estilos del sitio. Vivimos discusiones épicas y desayunos con choriqueques. Lamento personalmente que algunos de ellos ya no estén en nuestro equipo de trabajo, por diversas razones. En este equipo además aprendimos a querer a nuestro amigo hubot quien todos los días nos daba ánimos para poder seguir trabajando.
Sin duda me quedaron muchas cosas que nos pasaron este año que no puse aquí, pero no quiero dejar la oportunidad de dar a conocer.
Fui testigo de matrimonio de @rodchile con @sarahfriedland y ahora forman una linda y koalesca familia.
Con la @guzyy conocimos la Fundación Ser de la que estamos muy agradecidos, hemos aprendido mucho sobre el mundo de los niños con necesidades especiales. Conocimos otros papás que enfrentan los mismos desafíos que nosotros y con los que hemos podido compartir ideas, consejos y la sonrisa de sus hijos.
Si no es un geek, por favor no continúe leyendo, le advierto que no entenderá un carajo de lo que voy a escribir. Ahora bien si lo hace… después no se queje XD
Que tengan todos un Feliz Año 2014 y a echarle pa adelante (que pa atrás no cunde).
]]>Primero debemos agregar los siguientes imports al archivo app.js y la estrategia (plugin de autenticación) a utilizar. Además se agregan los archivos UserModel.js y security.js extensión del modelo de User y métodos de validación del request respectivamente:
1 | var passport = require('passport'); |
Ahora configuramos Express para que pueda utilizar Passport como administrador de sesiones de usuario. Es necesario que express use su propio administrador de sesiones y además debe ser inicializado antes que el de passport.
1 | app.use(express.cookieParser('your secret here')); |
Luego agregamos mecanismos de autenticación, serialización y deserialización a passport:
1 | passport.use(new LocalStrategy(User.authenticate())); |
Ahora extendemos el modelo de usuario para agregar nuestros atributos (si es es necesario, por ahora lo dejaremos vacío):
1 | var mongoose = require('mongoose'); |
Hay un archivo que se llama security.js que contiene una función que valida si el request solicitado está autenticado por passport, si está autenticado lo “deja pasar” (next), de lo contrario lo redirecciona al template de login.
1 | exports.ensureAuthenticated = function ensureAuthenticated(req, res, next) { |
Nos queda asegurar las urls o recursos que necesitemos con la función ensureAuthenticated en el archivo app.js. La idea es que sea lo menos intrusivo posible. Hay dos formas de hacerlo, la primera es intrusiva (y no recomendada aunque puede utilizarse con fines específicos) y se debe realizar por cada request en los archivos que contienen los Controllers:
1 | exports.authenticationExample = function(req, res) { |
La segunda es interceptando los request y validando según algún patrón, que es nuestro caso. Esta configuración esta en app.js donde se declaran las rutas a los Controllers:
1 | app.all('/api/*', security.ensureAuthenticated); |
Con esto interceptamos todos los request que van a la API y los que van a /todos y los hacemos pasar por la función de autenticación de request. Con esto evitamos poner dichas líneas de autenticación en cada controller.
Finalmente nos queda la última parte respecto de la autenticación y es configurar el login y el logout. Para el login usamos la API de passport y delegamos el trabajo de autenticación de la siguiente forma (configuración):
1 | /** |
El logout es más sencillo y lo único que hay que hacer es invalidar el request, destruir la sesión del usuario y redireccionar al login.
1 | app.get('/logout', function(req, res) { |
Me queda pendiente en la próxima parte del tutorial explicar cómo consumir estos servicios usando angular y desplegar los templates.
]]>Me animé y empece a usar Node.js para hacer algo simple y así tratar de entender el cómo funciona. Para hacer algo mas sabrosa la experiencia agregué algunos ingredientes adicionales, un framework para desarrollo web llamado Express, Mongoose para modelar los documentos que van a ir a parar a MongoDB, Passport para autenticar los request (control de usuarios y permisos), uso de templates con EJS y finalmente para la vista usamos el framework AngularJS. Como podrán ver es un stack de tecnologías basadas en Javascript.
Para iniciar voy a explicar algunas partes del código que personalmente me costó entender e implementar. Algunos de esos puntos fueron la integración con passport para la autenticación de los request, control de usuario y uso de datos en sesión.
Cuando utilizamos nodejs siempre hay un archivo principal donde se configura toda la plataforma, en este caso el archivo es llamado app.js. Voy a ir mostrando ciertas partes del código (si quieren ver el código, esta disponible en github):
1 | var express = require('express'); |
Lo primero es incluir el módulo de express y luego los Controllers de la aplicación. Veamos el código de IndexController
1 | exports.index = function(req, res) { |
Este es el Controller mas simple de la aplicación, lo único que hace es exponer mediante exports la función index cuya responsabilidad es desplegar la página principal de la aplicación. Lo demás está en el controlador de la API que será llamada desde dicha página (usando ajax).
1 | var Todo = require('../model/TodosModel'); |
Este controlador expone la API REST con la que se comunicará la pagina principal, haciendo llamadas ajax a los distintos métodos. En esta pieza se hace un require de otro script que representa el Model, en este caso es un document para MongoDB.
Aquí mostraré como se modeló el documento principal de la aplicación Todo
1 | var mongoose = require('mongoose'); |
Primero se incluye el módulo de mongoose que nos permitirá modelar los documentos para MongoDB. Luego se crea un schema para modelar y se le agregan los atributos que va a poseer y sus respectivas validaciones. Por ejemplo, el atributo date es de tipo Date y valor por omisión la fecha de hoy.
Además este schema contiene una referencia a otra Collection para dejar relacionado el usuario creador en sus Todos.
Finalmente para que la aplicación funcioné, hay que indicarle a node.js que las urls que se soliciten hay que enviarlas a alguien que las atienda, en este caso, los controladores y sus funciones.
1 | app.get('/login', function(req, res) { |
No hay mucho que explicar, a buen programador pocas lineas de código, las urls que ahi aparecen son ruteadas a los controladores o se implementa el callback inline, como por ejemplo las urls de login y logout. Los controller que digan security o passport, serán materia del próximo post.
Quedan algunos temas sin tocar en este capítulo, falta que revisemos la integración con AngularJS, el despliegue de los templates con EJS y la integración con passport para autenticar y autorizar los request.
Si tienen preguntas, bienvenidas sean.
]]>Primero instalaremos las herramientas que nos permitan administrar distintas versiones de nodejs. Una muy buena alternativa es instalar nvm (node version manager) algo siminar a rvm (ruby version manager).
1 | $ curl https://raw.github.com/creationix/nvm/master/install.sh | sh |
Este script instala nvm en el directorio $HOME/.nvm , luego se deben asegurar que los scripts de nvm se inicien con el terminal o shell que usen. En mi caso uso zsh y debo agregar la siguiente linea al final del archivo .zshrc (si usas bash debes agregarla en el archivo .bashrc):
1 | [[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh # This loads NVM |
Luego reiniciar la consola o cargar tu archivo de inicio:
1 | $ source ~/.zshrc |
ó
1 | $ source ~/.bashrc |
Ejecutamos los siguientes comandos para comprobar que nvm funciona correctamente.
1 | $ nvm |
1 | $ nvm ls-remote |
##Instalar la versión v0.11.8 de node.js
1 | $ nvm install v0.11.8 |
##Comprobar la instalación de node.js
1 | $ node --version |
Este es le mes (Octubre) de la Concientización del Síndrome de Down. Esta es una campaña impulsada por Happy Down Chile.
Happy Down Chile es una red de apoyo, orientación e información para todas aquellas familias que tienen una PERSONA con Síndrome de Down en su núcleo.
Apoya la campaña y si quieres… ayuda a educar a tus cercanos sobre el Síndrome de Down, de ésta forma ayudaremos a que la inclusión de estas personas sea mas fácil.
Les dejo los datos de la campaña para que la sigan en Facebook y Twitter
]]>Versión en inglés en Chris Eppstein en Coderwall
]]>Una de las cosas interesantes que tiene javassist es que no es necesario tener una clase con una interfaz definida, tal como se usa en JDK Dynamic Proxy o con ProxyFactoryBean (aunque también lo tiene usando cglib) para poder crear el Proxy.
Otra de las características de javassist es que posee mecanismos para mitigar la baja de rendimiento al utilizar el patrón Proxy, internamente maneja cache e intervención a nivel de bytecode para optimizar su uso.
Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it. Unlike other similar bytecode editors, Javassist provides two levels of API: source level and bytecode level.
Vamos al ejemplo:
1 | public class CalculadoraProxyFactory { |
Como podrán ver, el uso del ProxyFactory de javassist es muy parecido a los otros (ProxyFactoryBean y JDK Dynamic Proxy), además usa un nuevo concepto llamado MethodFilter
que permite agregar un filtro para los nombres de los métodos, con la finalidad de que el proxy sólo funciona cuando el método isHandled retorna true, de lo contrario hará una llamada directa a la clase RealSubject.
Veamos la implementación de MethodFilter para este ejemplo:
1 | final class SumaMethodFilter implements MethodFilter { |
Esta clase es la que contiene la lógica de negocio del proxy, es parecida a los interceptores (MethodInterceptor) de SpringFramework para el uso de ProxyFactoryBean o de InvocationHandler para JDK Dynamic Proxy.
1 | final class CalculadoraMethodHandler implements MethodHandler { |
Para hacer la prueba, realicé dos test unitarios, uno usando las mismas clases que he usado en los otros ejemplos y una nueva clase calculadora que no tiene una interfaz definida, con la finalidad de probar la funcionalidad de manipulación de bytecode en tiempo de runtime de javassist (crea una intrefaz a partir de la información de la clase).
1 | public class ProxyFactoryJavassistTest { |
Y finalmente la salida a la consola del test unitario es la siguiente:
1 | ------------------------------------------------------- |
En otro post, trataré de profundizar en la librería javassist ya que desde hace mucho la vengo mirando como dependencias de varios frameworks y aplicaciones (Hibernate, jboss, Spring Framework) y me llama la atención el cómo poder generar bytecode utilizando una API. La otra librería que hace algo similar es cglib y que Hibernate usó en los inicios del proyecto, aunque al parecer ya va en retroceso (también le echaré un vistazo).
Nota: Si ven en los debug de Hibernate algo como NombreDeClase_$$_javassist_0
son los proxys que arma Hibernate con javassist para las entidades que se cargan en modo lazy.
Por ahora voy a mostrar como configurar un Proxy Dinámico con SprinFramework, configuraciones y par un de conceptos.
Los interceptores son clases que contienen la lógica de negocio del Proxy, es el símil a el InvocationHandler
de la API de Java. Estas clases deben ser implementadas desde la interfaz Interceptor
que es la de mas alta jerarquía o de su herencia, MethodInterceptor
o ConstructorInterceptor
. Estas últimas clases pertenecen a la librería de aopalliance versión 1.0 en el package org.aopalliance.intercept
.
Para poder agregar las 2 funcionalidades (loggear los parámetros de entrada y validar que no sean negativos), implementaremos 2 Interceptores con la finalidad de aislar las lógicas de negocio de cada uno.
1 | public class ValidateArgumentsInterceptor implements MethodInterceptor { |
1 | public class LoggerArgumentsInterceptor implements MethodInterceptor { |
Ahora que tenemos los Interceptores, juntamos todo en la configuración del contexto de Spring.
1 |
|
Donde:
CalculadoraImpl
implemente una interfaz conocida, en este caso, Calculadora
.Para poder probar las funcionalidades realicé el siguiente test unitario:
1 |
|
Y finalmente la salida de la consola:
1 | ------------------------------------------------------- |
Espero les sirva, comentarios bienvenidos sean.
]]>Primero tienen que conocer la definición de proxy y sus posibles usos, que ya fueron descritas en un post anterior, puedes revisarlo antes de continuar: Patrones de Diseño: Proxy
Primero debemos conocer las clases que hacen posible la implementación de Dynamic Proxy en la API de Java, estas son java.lang.reflect.Proxy
y java.lang.reflect.InvocationHandler
, además debes tener conceptos básicos de Reflexión (sólo para la invocación de métodos).
Para crear un objeto Proxy debes utilizar la clase java.lang.reflect.Proxy
de la siguiente forma:
1 | Object obj = Proxy.newProxyInstance(classLoader, interfaces, handler); |
Donde:
Esta interfaz debe ser implementada y tenemos el método invoke que hará las veces de interceptor, es aquí donde debemos escribir nuestra lógica de negocio.
1 | public interface InvocationHandler { |
Veamos un ejemplo práctico de la implementación de un proxy dinámico usando la API de Java:
1 | public interface Calculadora { |
Ahora veamos la implementación de Calculadora:
1 | public class CalculadoraImpl implements Calculadora { |
Supongamos que estas clases ya están creadas y necesitamos agregar un par de funcionalidades sin tener que tocar el código ya existente. La primera funcionalidad es validar que los números a y b sean mayores a 0 y la segunda funcionalidad es loggear los parámetros de entrada.
1 | public class CalculadoraProxyFactory implements InvocationHandler { |
Como podrán ver en el ejemplo, en el método invoke se hace el control y el log sobre los argumentos que entran al método suma del RealSubject. Además para simplificar la creación del Proxy, se implementó un method-factory que crea el proxy dinámico (método proxyFactory).
Ahora el test unitario que prueba el funcionamiento del Proxy:
1 | public class CalculadoraProxyFactoryTest { |
La salida de este test a la consola con maven es la siguiente:
1 | ------------------------------------------------------- |
Espero que les haya sido útil, en un próximo post escribiré sobre otras formas de crear Proxy. Deje su comentario.
]]>Ayer Viernes 12, Javiera pudo ver por fin a su hermanita, la primera reacción fue la esperada, no quería acercarse a verla y mucho menos tocarla. Con el paso del tiempo se fue acercando, tocando, hablándole, teniéndola en upa y culminando con un reto porque se había hecho caquita, “Valentina no avisaste!”.
Son tantas las alegrías al recibir a un hijo en tus brazos, luego de vivir dentro de la mamá casi 9 meses, que no hay post que lo abarque por completo. Al igual que las preocupaciones, lo que se viene por delante, complicaciones, todo lo que se pueda pasar por la cabeza mientras sostienes a tu hija con tan solo algunos segundos de vida.
Con @guzyy emprenderemos un nuevo desafío que aún no estamos seguros de cómo lo lograremos, pero si de algo estamos seguros, es de que no fallaremos. Este camino será largo y sinuoso, no libre de complicaciones pero Valentina tendrá a sus padres para lo que necesite.
Nuestra hija Valentina nació con una conocida alteración genética y que presenta un error genético en el Cromosoma 21, en vez de tener 2 cromosomas como todos, tiene 3, por eso es conocida como trisomía 21 o más comúnmente conocida como Síndrome de Down.
Para nosotros (y personalmente ha sido una de las noticias más duras que he debido enfrentar) fue una noticia terrible y desconcertante que no esperábamos, todos sus exámenes salieron bien durante todo el embarazo, pero las probabilidades (aunque muy bajas) jugaron en contra de nuestras expectativas.
El resultado del examen genético dura un mes y es concluyente, así que no nos queda otra que esperar todo este tiempo.
Quiero también agradecer la preocupación que han tenido en la CSM por la condición de Valentina, el apoyo y consejos que nos han entregado en especial a Manuel Rojas que nos contó su experiencia desde lo mas profundo.
Gracias también a todos los buenos deseos y buena onda en twitter y facebook.
Finalmente también quiero agradecer a la familia y a los amigos que han estado en este feliz y difícil momento, vaya un abrazo para ellos y agradecimientos infinitos por su apoyo.
]]>El patrón Proxy esta clasificado dentro de los Patrones Estructurales, es también conocido como, Embajador, Apoderado (surrogante). Veamos primero su definición:
Un proxy fuerza a que un método de un objeto RealSubject sea indirectamente ejecutado a través de un objeto Proxy, el cual actúa como delegado o sustituto del objeto RealSubject. Los objetos Proxy son usualmente declarados sin que el Cliente sepa de que se trata de un Objeto Proxy.
Les dejo un diagrama de clases de cómo se implementa este patrón.
Partamos con la interfaz que deben cumplir tanto RealSubject como el SubjectProxy
1 | public interface Subject { |
Veamos la implementación del RealSubject
1 | public class SubjectReal implements Subject { |
Finalmente la implementación del SubjectProxy
1 | public class SubjectProxy implements Subject { |
Nuestro cliente (quien consumirá a Subject) será un test unitario:
1 | public class SubjectTest { |
Esto imprimirá lo siguiente en la consola (systemOut)
1 | Access Denied |
La explicación al Access Denied esta dada porque el patrón Proxy se utilizó como control de acceso al método doOperation. Sólo si el username es admin se ejecutará dicho método.
Veamos un Segundo Test Unitario
1 | public class SubjectTest { |
Esta es la salida:
1 | doOperacion proxied |
En este caso, el usuario admin puede ejecutar la operación y la primera vez que lo haga se conectará un objeto remoto o difícil de crear (simulado para el ejemplo). Luego una vez conectado, podrá ejecutar la operación.
Nuevamente el usuario admin ejecutará la operación por segunda vez y el SubjectProxy ya posee una conexión al objeto remoto, aquí simplemente ejecutará la operación.
Espero les haya gustado y les sirva en sus proyectos, en el siguiente post les comentaré sobre Dynamic Proxy de Java.
Referencias:
Nota: Busquen el error en wikipedia español si lo encuentra me lo comenta ;)
]]>