Skip to content

Por qué Spring simplifica el desarrollo de nuestras aplicaciones Java

13 mayo 2012

La misión principal de Spring es la de simplificar el desarrollo de aplicaciones Java, pero seguro que habéis leído esta frase muchas veces. Probablemente cada framework basado en Java proclama esta misma idea. Entonces, ¿Por qué Spring es diferente? ¿Qué hace que sea especial y diferente al resto?

Para empezar (y esta es una de las opciones qué más valoro) Spring se acopla a tu aplicación sin obligarte a modificar tu código para utilizar las funcionalidades y beneficios que ofrece. Para usar Spring no es imprescindible implementar un interfaz propio de Spring o heredar de una clase propia (puede que para utilizar cierta funcionalidad avanzada sí sea necesario, pero para un uso habitual no); lo que significa que Spring estará ahí pero tus clases serán Java puro y duro. Como mucho, tus clases tendrán anotaciones propias de Spring, pero no dejan de ser anotaciones por lo que tu clase será reutilizable en cualquier momento, sin cambios. Esta característica con otros frameworks es impensable, ya que para poder utilizar dicho framework habrás tenido que implementar un interfaz propio del framework y a la vez implementar los métodos establecidos en dicho interfaz; métodos que fuera de ese framework no tienen ningún sentido ni utilidad… (no hace falta que mencione ninguno en concreto verdad?). Por tanto, aqui tenemos la primera ventaja: Gracias a Spring, nuestro código Java puede ser más limpio, elegante y reutilizable. Elegante y reutilizable ya que la filosofía de Spring nos guía a programar orientado a interfaces, de modo que toda nuestra aplicación sea altamente modular y posea bajo acoplamiento. Veamos cómo en la Segunda ventaja…

(Antes de empezar he de avisaros que esta entrada no pretende ser una charla técnica, es más, está orientada a ser divulgativa y a mostrar lo que podemos hacer con Spring sin entrar en detalles de cómo hacerlo … por no hablar de que es un pelín extensa 😛 )

Segunda ventaja: Inyección de Dependencias o IoC (Inversion of Control)

¿Inyección de dependencias? Eso tiene pinta de ser un paradigma de programación nuevo y por el nombre suena a que debe ser complicado, no? …  Realmente no lo es, de hecho todos los que hemos programado alguna vez lo hemos utilizado de una forma u otra, simplemente no sabíamos que se llamaba así.

Lo habitual es que nuestra aplicación esté compuesta de dos o más clases que deben interactuar entre ellas para llevar a cabo determinada funcionalidad. Lo normal era que cada objeto fuera responsable de adquirir las referencias al resto de objetos con los que colabora, sus dependencias. Esto, a parte de ser una mala práctica, provoca que nuestras clases se encuentren fuertemente acopladas y que llevar a cabo tareas de Test, sea mucho más complejo. Veamos un ejemplo:

public class Elfo implements Guerrero {
   private Arma arma;

   public Elfo(){
      arma = new Arco();
   }

   @Override
   public void ataca() {
      arma.dispara();
   }
}

Como véis en el ejemplo, Elfo crea su propia instancia de Arma, un Arco. Esto provoca que las instancias de Elfo estén fuertemente acopladas a la clase Arco, lo que obviamente fuerza a que un Elfo sólo pueda utilizar un Arco como arma. ¿Qué ocurre si queremos darle una espada?

Este fuerte acoplamiento nos lleva a otro problema. ¿Qué ocurre si queremos aplicar test unitarios al método ataca()? No tenemos ninguna forma de probar diferentes implementaciones (o stubs o mocks) de la clase Arma, ya que un Elfo utiliza directamente una instancia de clase Arco…

Aquí es donde entra en juego el concepto Inyección de Dependencias: Los objetos reciben sus dependencias en tiempo de creación, de manera que ellos no son responsables de la instanciación e inicialización de esas dependencias. Por eso se dice que las dependencias se inyectan en el objeto que las necesite, porque de esta forma, el objeto no debe preocuparse de crear esas instancias.

Veamos el mismo ejemplo, pero ahora con inyección de dependencias:

public class Elfo implements Guerrero {
   private Arma arma;

   public Elfo(Arma a){
      arma = a;
   }

   @Override
   public void ataca() {
      arma.dispara();
   }
}

Como véis, aún pareciendo lo mismo, el panorama cambia ampliamente. En esta ocasión, las instancias de Elfo no crean una instancia de Arma, por tanto podrán utilizar cualquier arma que se les asigne desde el constructor, ya que todas las armas deben implementar el interfaz Arma. Aquí se aprecia nuevamente la ventaja de programar orientado a Interfaces… (os suena polimorfismo?? :P). Este tipo de inyección de dependencias se conoce con el nombre de: Inyección por constructor.

Lo más importante es que la clase Elfo, no está acoplada a ninguna implementación concreta del interfaz Arma, por tanto no importa que arma utilice siempre y cuando ese arma implemente el interfaz Arma. Si un objeto sólo conoce a sus dependencias mediante su interfaz (no por su implementación), podremos cambiar la implementación de esa dependencia como consideremos necesario sin que el objeto sea consciente de esos cambios y, por tanto, sin que le afecten.

Pero, ¿y si en mitad de una batalla queremos cambiar el arma de nuestro guerrero? Aqui entra en juego el segundo tipo de inyección de dependencias: Inyección por setter.

public class Elfo implements Guerrero {
   private Arma arma;

   public Elfo(Arma a){
      arma = a;
   }
 //Nuevo metodo setter
   public void setArma(Arma a) {
      arma = a;
   }
 @Override
   public void ataca() {
      arma.dispara();
   }
}

Como vemos, ahora la inyección de dependencias no la estamos realizando únicamente en tiempo de construcción, si no que puede realizarse en cualquier momento durante la ejecución de la aplicación, lo que nos permitirá cambiar las instancias concretas de Arma cuando sea oportuno.

Vale, muy bien, es todo muy bonito, pero si la propia clase Elfo no crea e inicializa sus instancias de Arma, ¿quién lo hace? ¿cuándo? ¿cómo? …..   Obviamente esta acción debe llevarse a cabo por una tercera parte. Una parte encargada de que cada objeto reciba las dependencias que requiere para su correcta compilación y ejecución. Y aquí es donde entra en juego Spring. Él va a ser el encargado de completar ese puzzle de dependencias según nosotros le indiquemos, él va a realizar toda las inyecciones que sean necesarias para que nuestra aplicación funcione. Por tanto Spring será el encargado de: Inicializar todas nuestras clases (llamando a sus constructores) e inyectar todas las instancias requeridas. Y lo que es más importante, todo esto lo hará sin que nosotros tengamos que tocar ni un punto y coma de nuestra implementación de Elfo o Arma…

Tercera ventaja: Aspectos (AOP)

¿Qué es la programación orientada a aspectos? Teoría en base a este concepto hay mucha, muchisima, pero si resumimos mucho y vamos a buscar la esencia sobre la que se apoya AOP, podríamos decir que aplicar aspectos a nuestro código se basa en añadir funcionalidad extra a nuestras clases y/o métodos sin alterar ni el comportamiento ni el código original del método o clase. (Esta definición totalmente informal es mía, por tanto aquí podéis discrepar todo lo que consideréis oportuno 😉 )

Hay muchas actividades que resultan comunes a la mayoría de aplicaciones software, por ejemplo: tareas de logging, seguridad, control de transacciones… Cualquiera que haya programado una aplicación más o menos grande sabe que antes o después debes enfrentarte a ellas, pero: ¿Debe nuestra aplicación participar activamente en estas funciones (o aspectos)? ¿No sería mejor que nuestra aplicación se enfocara únicamente en su objetivo principal y dejara que esta funcionalidad la llevara a cabo una tercera parte? Obviamente la respuesta es sí. Si estamos programando un método que se encargue de obtener un listado de todos los clientes de la base de datos, este método sólo debe preocuparse de obtener ese listado…si el usuario tiene permisos o no para hacerlo no es tarea suya el comprobarlo, o si debe dejar trazas de log, tampoco debe ser tarea del propio método.

Esta funcionalidad extra que cruza por varios puntos de nuestra aplicación (logging, seguridad, etc.) es lo que se conoce como Cross-cutting concerns. La programación orientada a aspectos nos va a permitir mantener dos principios básicos en un buen diseño: SoC y DRY.

SoC (Separation of Concerns) y DRY (Don’t repeat yourself) nos ayudarán a crear e implementar clases y métodos que sigan el patrón 1:1, es decir, “Una determinada funcionalidad debe estar implementada en un sólo sitio de nuestra aplicación y sólo debe llevar a cabo esa funcionalidad“.

Por ejemplo, ¿qué ocurriría en nuestra clase Elfo si quisiéramos que cada vez que un elfo ataque, se escriba una traza indicando qué elfo ha atacado?

Podríamos hacer lo siguiente:

public class Elfo implements Guerrero {
   private Arma arma;
   private String nombre;

   public Elfo(Arma a, String n){
      arma = a;
      nombre = n;
   }
 //Nuevo metodo setter
   public void setArma(Arma a) {
      arma = a;
   }
 @Override
   public void ataca() {
      arma.dispara();
      System.out.println("Yo "+nombre+", He disparado !!!!");
   }
}

Y si ahora queremos que no sólo la clase Elfo escriba trazas cada vez que ataque, sino que también la clase Enano debe escribir trazas tras atacar a un enemigo… ¿Modificamos también la clase Enano para añadir las trazas?

Obviamente si seguimos por ese camino, vamos a llegar inevitablemente a un muy mal diseño de nuestro código, que desembocará en dos síntomas inequívocos de que necesitamos aplicar SoC y DRY (y por ende AOP):

  1. Tangling (o enmarañamiento de nuestro código): Los métodos cada vez realizan más tareas a parte de la tarea principal; lo que conlleva que el código sea más dificil de leer, revisar, comprender, depurar, mejorar…
  2. Scattering (dispersión del código): Una determinada funcionalidad está dispersa por múltiples clases y/o métodos lo que implica que cualquier tarea de refactorización de código se va a hacer muy tediosa y originará fallos y errores que no tenemos contemplados (si la aplicación es muuuy grande y el código está muy enmarañado y disperso, quizás no conozcamos los efectos secundarios que puede tener un determinado cambio en el código)…

Aquí es donde Spring aplica su “magia” de AOP de una manera muy elegante; nosotros simplemente tenemos que decirle a Spring lo siguiente: “Tras la ejecución del método ataca() del interfaz Guerrero, ejecutame el método loggingAtaque() de la clase Logging”.

La clase Logging será una clase que nosotros habremos creado y que se encargará únicamente de realizar trazas de log de diversos métodos de nuestra aplicación. ¿No es mucho más legible y elegante nuestro código ahora? Y fijáos ni siquiera hemos tenido que modificar la clase Elfo, o la clase Enano… porque obviamente ese horrible System.out.println() que habíamos escrito anteriormente ya no sería necesario.

Un ejemplo más claro en el que se demuestra que utilizar AOP con Spring es una gozada, es el ejemplo de la seguridad. Retomemos nuestro método encargado de listar los clientes almacenados en la base de datos, ¿tiene sentido hacer esto?:

public ArrayList<Cliente> listClientes(){
   if (usuarioEnSession.tienePermisos()){
      //Codigo para conectarse a BD y devolver los clientes...
      //....
   }else{
      throw new NotAuthorizedException();
   }
}

Es decir, cada vez que queramos que un método acceda a la base de datos, ¿¿el método debe encargarse de controlar si el usuario tiene permisos?? Nuevamente, queda mucho más elegante hacer algo del estilo a lo siguiente:

Oye Spring, mira: “Antes de ejecutar el método listClientes() de la clase ClienteDAO, ejecuta el método tienePermisos(usuarioEnSession) de la clase Seguridad”.

De esta forma nuestro código de listClientes() quedaría:

public ArrayList<Cliente> listClientes(){
 //Codigo para conectarse a BD y devolver los clientes... 
 //....
}

Mucho más limpio, ¿no?

Realmente una vez que te acostumbras a programar orientado a aspectos…se hace muy dificil entender y tratar de encontrar una respuesta a la pregunta: ¿Para qué voy a utilizar AOP en mi código?

En este punto he de reconocerle un gran mérito a Spring. Nunca había llegado a comprender completamente qué significa (a efectos prácticos) la AOP hasta que comencé a utilizarla con Spring y mira que durante mis años en la carrera y en diversas asignaturas de doctorado trataron de venderme la AOP como el no va más.

Como véis aunque el término suene un poco intimidatorio, su aplicación es realmente sencilla y muy lógica, de esas cosas que una vez que las ves piensas: ¿Cómo nadie había pensado en esto antes?

Pero, dejemos por hoy la AOP y pasemos a ver otra ventaja muuuy interesante que nos aporta Spring:

Cuarta ventaja: Eliminar el código ‘boilerplate

Seguro que habéis leído u oído muchas veces esta palabra referida al código fuente: boilerplate. Este término inglés se refiere al código que es necesario para nuestra aplicación, pero que resulta muy pesado escribirlo una y otra vez. No hay que confundirlo con código inutil, ya que este código ‘boilerplate‘ es necesario, nuestra aplicación lo requiere y sin él no funcionaría, sin embargo, es verdaderamente molesto tener que estar escribiendolo en cada método que lo necesitamos (o hacer copy/paste cada vez…).

Un claro ejemplo de este tipo de código lo encontramos a la hora de utilizar JDBC en Java para consultar datos de una base de datos: Obtén la conexión, abre la conexión, prepara tu query, configura sus parámetros, ejecuta tu query, procesa los resultados, cierra las conexiones, procesa las excepciones….. os suena verdad? Al final resulta que para ejecutar una simple Select, debemos escribir unas 20 líneas de código 15 de las cuales serán siempre iguales. Pero no sólo pasa esto con JDBC, tenemos este mismo comportamiento si utilizamos REST o JMS en Java.

En este caso Spring elimina este código ‘boilerplate‘ mediante el uso de Templates o Plantillas de Código. De esta forma, en Spring existen plantillas para JDBC, JNDI, JMS, REST, …. todas las API que tengan código susceptible de ser repetitivo, tendrán su correspondiente plantilla en Spring.

En el caso de JDBC, tenemos la plantilla JdbcTemplate, que se encargará de encapsular todo el código repetitivo de las conexiones a base de datos, para que nosotros nos centremos en lo que realmente nos interesa: La query y los resultados que obtenemos. De esta forma le diremos a Spring: “Mira, ejecútame esta query y los resultados (en caso de que haya alguno) me los mapeas a este objeto mediante este método”. Pero esto es para el caso en el que los resultados que devuelve nuestra query estén compuestos por cierto número de filas y columnas, si el resultado es mucho más simple, todo se simplifica, por ejemplo:

int num_clientes = new JdbcTemplate(datasource).queryForInt("select count(*) from clientes");

Como véis las plantillas en Spring nos permitirán que nuestro código sea mucho más limpio y elegante, a la vez que evitamos tener que procesar todas esas Excepciones de tipo SQLException, que por otra parte nunca he sabido muy bien qué hacer con ellas… Si en algún momento de la ejecución de tu código se lanza una SQLException… Cómo se supone que debe actuar nuestro código?? Es decir, son excepciones no recuperables…una vez que salta una, no podemos hacer mucho: “DUPLICATE PRIMARY KEY”  …. no tenemos muchas opciones, como mucho avisar al usuario con un mensaje de error pero poco más…. entonces mi pregunta es: ¿Por qué estamos obligados a capturarlas? ¿Por qué no son ‘unchecked‘ exceptions? …. Pero bueno, ese ya es otro tema… (Por cierto, Spring también ha pensado en esto y nos permite mapear todas las excepciones a un conjunto de excepciones propias de tipo ‘uncheked’)

……………………………………………………………………………..

Y llegados a este punto he de decir que no trabajo para SpringSource ni VMware (aunque no estaría nada mal), ni me pagan por escribir todo esto; simplemente quería compartir con todos vosotros mis pensamientos y sentimientos sobre Spring y animar encarecidamente a todos los que queráis probarlo a hacerlo, porque cuanto más te adentras en el funcionamiento de Spring…más te engancha; y si antes os preguntábais: ¿Y para qué sirve Spring? o ¿Para qué voy a utilizarlo? …. veréis como la cosa cambia a: ¿Cómo NO voy a utilizar Spring?

Y ya sabéis cualquier mejora, sugerencia, propuesta, duda… será siempre bien recibida 😉

Anuncios
15 comentarios leave one →
  1. Charts permalink
    5 junio 2012 20:09

    wOAAAOO!!, justamente andaba buscando a alguien que explicara, el ¿por que de spring? y tu has dado justo en el clavo, ojala y te animaras a ayudarnos a los novatos como yo a conocer mas sobre spring. Gracias!!

  2. 22 noviembre 2012 18:14

    Gracias, la explicacion fue increible

  3. Vicluar permalink
    23 febrero 2013 19:55

    Excelente la explicación sobre las ventajas de Spring. Muchas gracias!

  4. 17 abril 2013 19:55

    Muy buen artículo. Gracias por tu aportación.

  5. Benn Sandoval permalink
    25 abril 2013 06:59

    Awesome…Very useful

  6. 25 julio 2013 18:29

    muchas gracais, excelente tu articulo 🙂

  7. Leonel Pedrozo permalink
    22 octubre 2013 00:59

    Excelente aporte. Algo de esta forma en términos sencillos estaba buscando. Exitos

  8. antonio permalink
    26 febrero 2014 11:12

    Increible! muchas gracias por tu ayuda y contribucion al mundo de la programacion.

    • rekkeb permalink*
      27 febrero 2014 20:04

      A ti por leer lo que escribo 😉

  9. Oscar permalink
    27 marzo 2014 15:22

    Excelente explicación, con ejemplos sin tantos detalles técnicos que permiten ver claramente algunas de las ventajas de usar Spring

  10. Daniel permalink
    4 julio 2014 21:07

    excelente post!, se agradece un monton. 🙂

  11. Vito permalink
    7 febrero 2015 17:30

    Excelente explicación, muchas gracias por tu dedicación y compartir tus conocimientos.

  12. 14 julio 2015 00:25

    Muy buen articulo, Gracias y Felicitaciones

  13. Ana Hernandez permalink
    12 octubre 2015 18:30

    Excelente artículo. felicidades. Espero poder tener la oportunidad de seguir tu pista.

  14. 22 noviembre 2016 15:44

    Buen artículo. Me convenciste.
    Trabajé por muchos años desarrollando Web con Java. Fuí pionero a nivel internacional. Construí mis propios Frameworks en mis tiempos, porque simplemente no existían.
    Todos esos problemas y muchos otros los resolvi de maneras ingeniosas y elegantes, y cuando llegaron los primeros Frameworks los odié, me parecían formas muy complicadas y enredadas de resolver cosas que yo tenía plenamente resultas y de maneras más sencillas, simplemente con buenos e ingeniosos diseños, claro, echando mano de la tecnología, como XML, XSLT, bases de datos XML, DHTML, RMI, Reflexion, etc.
    Por ese tiempo fue que me fui alejando del desarrollo para tomar otras posiciones más de gestión.
    Recuerfo que con 3 o 4 JSPs de no más de 100 líneas de código te podía construir aplicaciones muy complejas como eComerce, Procurement, Kioscos de RH. Todo el contenido se generaba On Fly, incluso tenía generadores de CRUD. Era invencible a la hora de desarrollar, incluso contra equipos completos que comenzaban a experimentar con las primeras herramientas gráficas como IBM Visual Studio for Java u otras como Java WebDynpro de SAP.
    Ahora me arrepiento de no haber publicado nada de esa infraestructura ya la perdí y por un proyecto personal ahora estoy de regreso al desarrollo y estoy en el dilema de usar todas esas cosas que nunca me agradaron como los Struts, Spring, Hibernate, Groovy, etc., mayormente porque necesito que posteriormente otros programadores le puedan dar mantenimiento y agregar nueva funcionalidad.
    Gracias por tu artículo, me dio buenas razones para abrirme a otras posibilidades.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: