Inversión de Control: El Patrón de los Frameworks

Leyendo un artículo de Martin Fowler, sobre el tema Inversión de Control (en inglés), comenzando por el final, la etimología de la frase (entendido como el origen del concepto), se comenta que, en un principio (sobre los años 80) la gente se refería a una nueva forma de hacer las cosas como el Principio de Hollywood, teniendo presente la famosa frase de los cineastas: “no nos llames, nosotros te llamaremos”.

Si pensamos en las librerías, en cualquier lenguaje, ya sean módulos, paquetes u objetos, siempre alcanzamos una funcionalidad encapsulada dentro de una forma específica a la que se la puede llamar para realizar una acción. Pero esto cambia radicalmente en los frameworks, u entornos de desarrollo, ya que estos entornos, normalmente, realizan un cierto trabajo, y te permiten extender esa funcionalidad base, con ciertas reglas, a través de código que se escribe.

Se podría pensar en los frameworks como piezas de software que permiten agregar una funcionalidad extra desarrollada por el programador que usa el framework, a modo de addon, plugin o extensión. Pero no es eso. Las extensiones (o llámese como se quiera) son trozos de código, que opcionalmente se puede ejecutar en un programa completamente funcional. Como es obvio, ningún framework es completamente funcional sin agregar ningún código por parte del programador.

Por lo tanto, la inversión de control es más una base sobre la que construir un elemento, es nuestra arquitectura de soporte, mientras que la base sobre la que se programa un plugin es un elemento completo y funcional que se extiende mediante el plugin, pero que no depende de él.

Este es otro de los grandes elementos en los que se basa la Ingeniería del Software al decir que, lo importante, es la lógica de negocio o el sistema en sí que se quiere desarrollar, dejando la parte de arquitectura de soporte y el trasfondo sobre el que se ejecuta la solución al framework.

Si aún se tiene alguna duda, puede que con este ejemplo se disipen (o aumenten :-P ), tomado del artículo de Martin Fowler comentado antes, tenemos un trozo de código en Ruby tal que así:

puts '¿Cómo te llamas?'
nombre = gets
procesa_nombre(nombre)
 
puts '¿Qué buscas?'
busqueda = gets
procesa_busqueda(busqueda)

En este trozo de código todo está bajo control, el sistema se ejecuta de forma lineal, pide la información en el momento en el que se le ha escrito y descrito y el código se ejecuta, secuencialmente, de forma predecible.

Ahora veremos otro ejemplo:

require 'tk'
 
root = TkRoot.new
nombre_etiqueta = TkLabel.new() { text "¿Cómo te llamas?" }
nombre_etiqueta.pack
 
nombre = TkEntry.new(root).pack
nombre.bind("FocusOut") { procesa_nombre(nombre) }
 
busqueda_etiqueta = TkLabel.new() { text "¿Qué buscas?" }
busqueda_etiqueta.pack
 
busqueda = TkEntry.new(root).pack
busqueda.bind("FocusOut") { procesa_busqueda(busqueda) }
 
Tk.mainloop()

Aquí hay una gran diferencia en el flujo de ejecución, ya que los mensajes se ejecutan en el orden que el framework los llama, según la interacción del usuario. En este caso, el framework controla la ventana, los eventos que se suceden sobre los elementos gráficos y, en el caso de que haya un evento, si hemos desarrollado código para atender a ese evento, es el framework el que llama a nuestro código. Eso es inversión de control.