Mi cursada - UNQ‎ > ‎Clases‎ > ‎Bitácoras‎ > ‎

Bitácoras 2011 S1


Lunes 02/05/11 - Aplicaciones web con Pharo & Seaside

publicado a la‎(s)‎ 2 may. 2011 16:10 por Javier Fernandes   [ actualizado el 9 may. 2011 16:15 por gisela decuzzi ]

Smalltalk & Pharo & Seaside

En esta clase vamos a ver un enfoque bastante radical o diferente a los que veníamos viendo para la construcción de aplicaciones web. Para eso vamos a ver un framework llamado web Seaside, para el smalltalk "Pharo".
Pharo es un proyecto "fork" de squeak, y según nuestra opinión, uno de los proyectos con más actividad en la actualidad de smalltalks.
Eso nos da cierto soporte, e ideas nuevas al smalltalks como los traits, etc.


Primeros Pasos con Seaside

Abrimos entonces una imagen de ejemplo que ya contiene seaside.
Vimos que existe una ventana llamada "Seaside Control Panel" que permite controlar el webserver embebido. Ah si, claro, seaside trae un webserver embebido, llamado "Comanche" (de apache).
Entonces vimos como levantar y bajar seaside, y con un browser interactuamos con el:

  • http://localhost:8080/browse : muestra un listado de todas las aplicaciones seaside
  • http://localhost:8080/config : permite controlar la configuración de seaside.

Nota de color:

Seaside además trae una herramienta llamada "Pier", que es un "Content Management System". Ver


Primer Componente

Entonces vamos a comenzar a trabajar definiendo nuestra propia aplicación.

// TODO: ver como creó un nuevo component. De donde heredó, etc.

Listo, ya tenemos nuestro componente, pero cómo usarlo ? Cómo hacer que sea accesible al usuario, a través de wicket ?

Para eso tenemos que:
  • Agregar un método de clase "canBeRoot" = true en la clase de mi componente.
  • Luego, ir a la configuración de seaside http://localhost:8080/config
  • Y tenemos que agregar un "Dispatcher", que es básicamente como un "alias", donde le decimos a seaside que cuando el usuario pida cierta URL, eso muestre nuestro componentes. Para eso
    • Dispatcher -> "Add"
    • //TODO:

Vemos entonces que el dispatching se hace a un "componente" y no necesariamente a una "página", como en wicket.
Entonces acá vemos que Seaside es un framework "orientado a componente". Pero a diferencia de wicket, todo es un componente. Y no existe la idea central de navegación entre páginas. O, la página, como concepto principal de la aplicación.


Ejemplo Más Interesante

Pasamos entonces a un ejemplo más completo/interesante que el simple "hola mundo"
Vemos entonces que el objeto que recibíamos como parámetro del renderOn, era de tipo WARenderCanvas
Miramos un poquito esta clase, para ver qué podemos hacer.
Cada uno de los métodos de esta clase, se los llama "brushes". Así es la metáfora de seaside.
Con esto métodos, vamos a ir "construyendo" o declarando cómo va a ser el contenido del canvas, y por ende, al final, el html a generar.

Implementamos entonces el ejemplo de un Contador.

remderContentOn: html
    html text: html class name.
    html break.
    html anchor: 'Contador
   
Vemos entonces que "text", "break" y "anchor" son estos famosos "brushes".
Y entonces vemos que estos métodos, nos devuelven, de hecho un objeto, al cual podemos enviarle mensajes, para así especificarles detalles, que luego se utilizaran para generar el html.

Ejemplo:

remderContentOn: html
    html text: html class name.
    html break.
    html anchor
        callback: [];
        with: 'Contador


Vemos que el caracter punto y coma ';' nos permite encadenar mensajes al mismo objeto. Así en este ejemplo arriba estamos enviando los mensajes "callback" y "width" al mismo objetos respuesta de "anchor".

Modelo de Componentes


Acá se ve una particularidad de la idea de componente en seaside.
El anchor, por ejemplo, no es un objeto, sino que resulta de enviar el mensaje "anchor" a WACanvas.

Entonces, el modelo de componentes en seaside se dá más por el uso de las clases que nos dá seaside y sus brushes, y a la descripción de la pantalla en forma programática.
Esto en contraposición con otras tecnologías declarativas, como vamos a ver en flex (a través de un xml especial).
Y también a diferencia de los modelos basados en "transformaciones". Como el templating (evaluación de pedacitos de html con variables que se reemplazan luego), o como el XSLT, que permite transformar un xml a partir de otro xml que tiene una descripción de las transformaciones a hacer.


Callbacks y estado conversacional

Avanzamos con el ejemplo
Hicimos entonces un nuevo componente CIUContador
Con un atributo "count" (getter y setter)

renderContentOn: html
    html text: self count asString.
    html break.
    html anchor
        callback: [self answer];
        with: 'Volver


Y desde el componente anterior hacemos que el link nos muestre el Contador:

remderContentOn: html
    html text: html class name.
    html break.
    html anchor
        callback: [self call: CIUContador new];
        with: 'Contador


Ahora desde el componente inicial, ya podemos ir a nuestro nuevo componente.
Peero, cada vez que vamos y volvemos se instancia un nuevo componente, porque estamos haciendo CIUContador new.

Entonces, para modificar el contador vamos a completar el nuevo componente con dos nuevos links para incrementar y decrementar el contador.

renderContentOn: html

        html anchor callback: [self incrementar]; with: '++'.
    html text: self count asString.
        html anchor callback: [self decrementar]; with: '--'.

    html break.
    html anchor
        callback: [self answer];
        with: 'Volver


Ahora con este cambio, vemos que, al igual en wicket, seaside maneja transparente, automática y mágicamente, el request del browser al server y se encarga de llamar a nuestro bloque que le pasamos como "callback".
En nuestro ejemplo invocamos los métodos incrementar/decrementar que modifica el estado (la variable count). Y simplemente seaside vuelve a mostrar la misma instancia del componente.


El "Odioso" Problema del Back Button

Vimos que ahora con el comportamiento de "incrementar/decrementar" estamos manteniendo estado entre los diferentes requests.
Ahora, qué pasa si empezamos a usar el botón "back" del navegador ?
Cosas raras!
Porque el navegador no vuelve a pedir la página anterior, sino que muestra lo que el se acordaba (caché).
Esto hace que lo que vemos en el browser esté desincronizado con el estado en el server (la instancia del control)
Para solucionar eso agregamos un método "states" al componente.

states
        ^Array with: self
   
Este método nos permite devolver un array con objetos a recordar "por seaside", cuando alguien "va para atrás".
En este caso hace que se acuerde de todo el objeto.


Vimos que este problema es muy conocido en el desarrollo web. Y que existen diferentes técnicas para resolverlo, como [tratar] de invalitar la caché del browser, etc.

Continuations

 Modificamos entonces en el ejemplo la clase CIUEjemplos para agregar un link a un nuevo componente CIUCalculador:

remderContentOn: html

    html text: html class name.
    html break.
    html anchor
        callback: [self call: CIUContador new];
        with: 'Contador


    html break.

    html anchor
        callback: [self call: CIUCalculadora new];
        with: 'Calculador


Y entonces creamos un nuevo componente CIUCalculadora, pero esta vez heradamos de ????

Entonces implementamos el método "go"

go
     |sumando1 sumando2|
   sumando1 := (self request: 'Ingrese el primer sumando') asNumber.
   sumando2 := (self request: 'Ingrese el segundo sumando') asNumber.
   self inform: (sumando1 + sumando2) asString.

Como vemos, no tiene el canvas, con lo cual no puede "escribir html".

Y vemos entonces en el browser algo bastante mágico al hacer click en el link Calculadora !

  • Al usuario se le presenta una pantalla con un input y el mensaje "Ingrese el primer sumando". Al hacer submit ...
  • se le mostró una nueva segunda pantalla con otro input y el mensaje "Ingrese el segundo sumando". y al hacer submit..
  • se le mostró una tercer pantall con el resultado de la suma.
Vemos entonces que cada pantalla es exáctamente cada una de las lineas del método "go".
Esas líneas de código mágicas, utilizan mensajes especiales como "request" e "inform",  que se podrían pensar como pasos de una secuencia (o wizard). Y esos pasos serían de hecho pedidos al usuario, que requieren su interacción.
Seaside, a través de un feature llamado Continuations, nos permite escribir entonces todo el comportamiento en un único método, pero el se encarga de ir generando diferentes páginas como pasos, y mantener el estado y la navegación.

Lo que va haciendo es pausar la ejecución de cada linea, y cuando el usuario sigue al siguiente paso, continúa la ejecución. Y de ahí viene el nombre.

Jugamos aún más con Continuations

Modificamos entonces el nuevo componente para que como primer paso muestre nuestro contador.
La idea es que ahora el primer sumando no se obtenga mediante el ingreso manual del usuario (request), sino a través de usar nuestro componente "contador"

go

     |sumando1 sumando2|
   sumando1 := self call: CIUContador new.
   sumando2 := (self request: 'Ingrese el segundo sumando') asNumber.
   self inform: (sumando1 + sumando2) asString.

Modificamos entonces el Contador para que el link que antes era "Volver" ahora devuelva el valor actual del contador

renderContentOn: html
        html anchor callback: [self incrementar]; with: '++'.
    html text: self count asString.
        html anchor callback: [self decrementar]; with: '--'.

    html break.
    html anchor
        callback: [self answer: self count]; with: 'Listo'.


Y ahora al ejecutar el ejemplo, vemos que como primer paso nos lleva al contador, donde a través de los links incrementar/decrementar alteramos el contador, hasta que clickeamos "Listo" y eso nos lleva al siguiente paso. Finalmente nos muestra la suma de la Calculador.

CIUAutoCalculadora

Creamos un nuevo componente CIUAutoContador con una variable de instancia "contadores" y el método initialize

initialize
    super initialize.
    self contadores:
        //TODO: completar la inicialización

El renderContentOn

renderContentOn: html
    contadores
        do: [ :c | html render: c. html break ]

    html text: ('El total es:', self suma asString).

Y el método suma:

suma

    ^ self contadores inject: 0 into: [:a :c | a + c count].


Acá vemos cómo se pueden componener fácilmente los componentes seaside.

Diseñando en Seaside

Por último usamos una herencia entre ambos contadores CIUAutoContador y CIUContador.
Pero el punto es que los componentes en seaside con objetos, y se definen por clases, entonces tenemos las mismas herramientas para diseñar que cuando trabajamos con clases y objetos en cualquier otra parte de nuestro sistema.



Pendientes para la clase que viene

  • Componentes Decoradores
  • Formularios



Nota Sobre TPS

A partir de esta clase ya ustedes van a contar con una idea y pantallazo de las ideas de diseño detrás de wicket, jsp+servlets (model2) y seaside.
Esto los habilita a que puedan elegir uno de estos frameworks, para programar el TP 3.
La idea es, a partir de este jueves ya pasar al TP 3 que va a ser el más importante de la cursada.

Por otro lado, para este jueves deben tener ya una propuesta de tema de investigación para el TP 4.
La idea es cerrar ya los grupos y los temas elegidos.

Entonces, resumen

  • Jueves
    • Cerrar TP2
    • Seaside
    • Charlar un ratito sobre las ideas para el TP4
      • No lo cerramos ahí, pero lo encaminamos
  • Lunes que viene:
    • Cerramos TP3: qué van a hacer
    • Cerramos TP4: idem
    • No va a haber teoría nueva, porque nos vamos a concentrar con el TP3

Lunes 25/04/2011 - Web con Apache Wicket Framework

publicado a la‎(s)‎ 25 abr. 2011 12:28 por Nicolas Passerini   [ actualizado el 25 abr. 2011 17:57 por gisela decuzzi ]

Vamos a saltearnos un par de años sin penas ni glorias (a nuestro parecer) de la industria desde que surgió el api de servlets y jsp, como vimos en la clase pasada, para ver un framework un poco más reciente (algo así como 3, 4 años) llamado apache wicket.

Para eso vamos a ir bien a lo concreto e ir mostrándolo mediante código y haciendo evolucionar un ejemplo.
Entonces, lo planteamos en iteraciones:

Iteración 1 : ejemplo básico casi "hola mundo"

  • Crear aplicación básica con el archetype de maven para wicket, siguiendo las instrucciones que estàn en esta página.
  • Mostrar la estructura de la aplicación
    • objeto Application
    • HomePage (el concepto de página es distinto al de JSP).
    • html (wicket:id)
    • Label
  • Arrancar app y mostrarla en el browser.
  • Modificar el html y ver los cambios.
  • F5 crea una nueva página.

Observaciones:
  • el html no se ensucia (diseñador gráfico / programador)
  • orientado a componentes (a la swing)
  • fase de rendering (cada componente procesa su tag).

Iteración 2 : links y ciclo de vida de página 1.

  • agregar otro label que muestre un contador (solo en el html y que explote)
  • agregar links de incrementar/decrementar el contador. Y mostrar:
    • que refresca toda la página completa (se resetea el scroll).
    • abrir en otro tab, contador en cero (wicket se da cuenta del "multitab", además de soportar multisesiones asiladas).


Iteración 3: ajax

  • modificar el boton por un AjaxLink
    • ver que cambia el método.
    • ver que tenemos que guardarnos una referencia y explicitar qué componentes hay que actualizar del lado del cliente.
    • refactorizar para reutilizar código entre acciones (chiche)
  • va a explotar por el setOutputMarkupId (agregarlo)
  • mostrar la magia!
  • poner un system.out para que lo crean ! :)
  • mostrar que no interfiere con otro tab / usuario

Observaciones:
  • no necesitamos nada de javascript
  • ajax está modelado con objetos.
  • wicket se encarga de refrescarlos, solo tenemos que decirle qué componentes.
  • la página sigue siempre viva! la misma instancia! misma variable contador!

Iteración 4: utilizando MVC

  • sacar el contador a un modelo Contador.
    • ver que explota el label de "contador" porque busca la property en HomePage.
      • mostrar que usa convention over configurationm, el id es la property.
    • ver que los labels son diferentes:
      • uno tiene un valor fijo, hardcodeado
      • el otro sale del modelo.

Observaciones:
  • Como la página es un objeto vivo, también su modelo.
  • se parece a la idea de MVC (y luego de MMVC) que vimos en arena.
  • el modelo puede ser un objeto normal POJO (plain old java object)
  • ahora duplicamos la lógica del target ajax :(
    • en Contador.contador vs HomePage.contadorLabel se ve el paralelismo entre modelo-vista. Suena un poco a "duplicidad".
    • Con observers se podría llegar a codificar un mecanismo genérico para actualizar componentes ajax según los eventos del modelo.

Iteración 5: Navegación y ciclo de vida de páginas 2

Paso 1: páginas nuevas sin estado compartido
  • agregar una nueva página que solo muestre un label (no tiene mucho sentido a nivel de negocio, pero es solo para simplificar).
  • agregar un link que vaya a la página nueva con el class
  • en la página nueva, agregar un link de "volver"

Observaciones:
  • Vuelve a una instancia de la página, nueva.
  • Cómo comparto un modelo entre páginas ?

Paso 2: ir a página nueva, pasando estado
  • que el link instancie la página y le pase el contador
  • que la página muestre el contador.
  • que el back vuelva a una instancia nueva... (problemas! ....

Paso 3: volver a la misma instancia de la página original
  • que la nueva página conozca a la original
  • que vuelva a la misma instancia.

Clase Lunes 18/04/2011 - Web III : REST, estado y navegación

publicado a la‎(s)‎ 18 abr. 2011 16:37 por Javier Fernandes   [ actualizado el 25 abr. 2011 12:27 por gisela decuzzi ]

Esquema Stateful


Retomamos el ejemplo de la búsqueda de libros según lo habíamos dejado la clase pasada.

Diagramamos un poco la interacción entre cliente y servidor. Cómo interactuaban los servlets, jsps. Los parámetros que se enviaban y la forma de "guardar" información entre diferentes request.

Vimos que en el primer esquema, el servlet de búsqueda guardaba la lista resultado en la session del usuario.
En realidad esto ya lo vimos la última clase. Y también que trae aparejados varios problemas de concurrencia. Por ejemplo abriendo varios browsers al mismo tiempo, el resultado de la búsqueda "se pisaba".
También está el hecho de que si cada servlet y cada página mete cosas en las session, muy probablemente:
  • la session pase a ser una bolsa de gatos
  • se incremente la probabilidad de que varios atributos de la session colisionen entre diferentes casos de uso, al usar un mismo nombre.
  • comience a crecer y a aumentar su consumo de memoria.
  • en fin, comportamiento errático.
Este esquema se dice que es stateful, ya que en todo momento la aplicación del lado del servidor contiene el estado asociado a cada usuario.

Lo que llamamos "estado" no es exáctamente el estado global de la aplicación, referido a los objetos de negocio compartidos entre todos los usuarios (lease persistencia del dominio).
En cambio nos referimos al estado conversacional que representa la interacción entre el usuario y el sistema. Justamente, la parte más relacionado con el diseño de interfaces de usuario.

Esquema Stateless

Entonces pasamos al segundo esquema, evitando el uso de la session, y permitiendo que el servlet y el jsp se comuniquen a partir del mismo request que comparten (acuérdense que al hacer un forward, el request todavía no se respondió al browser, con lo cual sigue siendo el mismo en el server).

Para esto entonces modificamos el SearchServlet para que "meta" la lista de libros resultado de la búsqueda dentro del request como attribute, haciendo

    request.setAttribute("libros", resultadoBusqueda);

Y ahora el index.jsp en lugar de obtener la lista de resultados, la obtiene del request mismo.

Ahora sí la aplicación, al responder a ese request, pierde toda noción de estado conversacional. Ya que el request muere.
A este tipo de navegación o aplicación se la llama Stateless.

Model 2

Vimos que aparecía un problema con detalle.jsp que nos permitía ver un libro de la lista de resultado. Porque todavía no estaba refactorizada, y dependía de obtener un elemento específico de la lista de resultado de la session.

Y para resolver este problema, volvemos a la idea de Model 2. Donde se establecía la idea de que cada request que hacemos, sería manejado por un servlet, que actuaría de controller.

Este servlet, debería ubicar el libro específico a detallar.

  • Cómo ?
    • Pidiéndolo a la biblioteca
  • Y Cómo lo pediría ? 
    • con algún tipo de identificador único del objeto que haya pasado al html de respuesta y vuelva al server al clickear.
Entonces acá vimos e DetalleServlet.

Stateful vs Stateless

  • Stateless:
    • Ventajas:
      • Escala fácilmente: clustering & disaster recover
      • No sobrecarga el servidor
      • Ventaja: Rest (ver abajo)
    • Desventajas:
      • Nos fuerza a enviar hacia un lado y otro el estado conversacional (ids)
      • No escala en complejidad de funcionalidad: en cierto punto cuando la aplicación tiene casos de uso bien complejos, la solución de pasar ids no escala
  • Stateful:
    • Ventajas:
      • Evita el trabajo manual de enviar y recibir los parámetros del estado conversacional.
      • Nos acerca más a la idea de tener un modelo de objetos vivo en el servidor.
    • Desventajas:
      • No escala
      • Sobrecarga el servidor.
      • Problemas de desincronismo entre browser & server

REST

Vimos luego el ejemplo de detalle.jsp del proyect "rest".
Específicamente el link de "volver" que nos devuele a la página de búsqueda, peeeeero, con la salvedad de que presenta la misma búsqueda original.
Para esto, obviamente debe mantener el estado conversacional, con lo cual este detalle.jsp debe "renderizar" (generar html) el link ya con los parámetros necesarios para la búsqueda en la URL.

Y acá nos frenamos a analizar la URL.

Vimos que al ser GET y recibir los parámetros como parte de la URL (y como la aplicación es Stateless):
  • Nos permite escribir URLs "a mano", y así interactuar con la aplicación directamente.
  • Nos presenta una URL que tiene un significado único en la aplicación. Con su propio estado conversacional.
  • Esto último, nos permite además, guardarnos la URL ("bookmarkearla") y luego accederla nueva y directamente.
A este tipo de aplicaciones y navegación se llama REST: Representational State Transfer.
 

Esta idea aparece con mucha fuerza en el framework ruby on rails.

Como punto intermedio, vimos que muchas aplicaciones actuales presentan una mezcla entre: funcionalidad REST y funcionalidad NO REST.

Generalmente la funcionalidad REST es más bien de consulta o lectura. Para poder navegar contenido a través de la URL. En cambio se hace dificil e incómodo (sino a veces imposible) implementar funcionalidad de interacción más compleja, como crear un cierto objeto de negocio, etc, a través de REST.

Lunes 11 de abril de 2011 - Introducción a la programación Web

publicado a la‎(s)‎ 14 abr. 2011 12:13 por Nicolas Passerini   [ actualizado el 14 abr. 2011 12:31 por gisela decuzzi ]

En esta clase arrancamos contando la arquitectura general de la programación web, algunos de los conceptos que vimos son:
  • Application Clients (y el Web Browser como el más común de ellos).
  • Las motivaciones para hacer web applications y más en general por qué utilizar clientes livianos o ZACs (Zero Administration Client).
  • Una rápida introducción a HTML y CSS.

También comentamos las complejidades de las aplicaciones basadas en estas tecnologías como ser:
  • HTML no es un lenguaje específico para hacer aplicaciones sino que su intención original era mostrar hipertexto con formato.
  • Nuestra aplicación pasa a ser una aplicación distribuida: va a tener una parte corriendo en el servidor y otra parte corriendo en el cliente. Por ahora pusimos toda la lógica en el servidor y lo que le llega al cliente es sólo un documento HTML pero más adelante vamos a repartirlo de diferentes maneras.
  • Los browsers no son uniformes, entonces si queremos que ande en todos ellos muchas veces vamos a tener que manejar código específico para cada plataforma (browser, versión, sistema operativo y a veces hasta el hardware).

En la página del módulo A de la unidad 3 hay apuntes sobre todas estas tecnologías y links a los ejemplos básicos que tenemos disponibles.

Lunes 4 de abril de 2011 - Application Models

publicado a la‎(s)‎ 4 abr. 2011 16:18 por Nicolas Passerini   [ actualizado el 4 abr. 2011 20:34 por gisela decuzzi ]

Una vista un poco más compleja: pantalla de búsqueda

Arrancamos con una laaaarga disertación que no venía al caso sobre por qué preferimos las metodologías ágiles.

Luego contamos el funcionamiento de la pantalla de búsqueda del ejemplo del Videoclub.
De pasada, vemos que las pantallas de edición y creación de socio ahora incorporan dos selectores. Uno de ellos tiene como conjunto de valores un Enum y el otro una Home.

Pasamos a ver cómo está construida esa pantalla. ¿Qué tenemos como modelo en esta pantalla?
Nos dimos cuenta (o al menos Fede se dio cuenta) de que el objeto detrás de esa pantalla es un "buscador", que tiene:
  • Dos atributos que son los filtros de búsqueda (nombre y dirección).
  • Un atributo de tipo lista que representa el resultado de la búsqueda.
  • Un método que ejecuta la búsqueda, tomando los datos de los filtros y actualizando el resultado de forma adecuada. Esto podría hacerse de muchas maneras, en nuestro caso estamos utilizando una busqueda by example.
En el medio, a Javi se le escapó la palabra DAO y eso motivó ooootra disertación; con un poco de esfuerzo, esta no fue tan larga. :)

Binding de propiedades "anidadas"

Un detalle técnico es que los campos de filtrado no están bindeados contra propiedades del buscador. En cambio el buscador tiene una propiedad "example" que es un Socio; y los campos de filtro se bindean contra propiedades de ese objeto Socio.

Mencionamos que habría tres formas de hacer esto:
  • La que tiene el ejemplo: bindear el Panel contra la propiedad "example" y los campos contenidos en él con propiedades del Socio referenciado por example.
  • Propiedades anidadas, de la forma "example.nombre". Esto es muy común en los frameworks de presentación en tecnología Java.
  • Resolverlo a nivel modelo, agregando una propiedad "nombre" al buscador, que maneje la propiedad internamente.
En este ejemplo preferimos la primera estrategia, pero pueden existir casos en los que sea útil alguna de las otras dos.

Tablas

Las tablas nos permiten mostrar muchos objetos del mismo tipo contenidos en una colección y seleccionar uno de ellos.

Eso nos permite bindear dos propiedades de la tabla:
  • Sus contenidos, contra una colección del modelo.
  • El objeto seleccionado.

También podemos ver que los botones de la tabla se deshabilitan cuando no hay un objeto seleccionado, eso se logra con un binding especial (que se fija que la propiedad sea no nula).

Application Model

¿Qué representa ese objeto "buscador"? Es el modelo de la ventana, sin embargo no puede decirse que sea un objeto de dominio como Socio o Película. Lo diferencian fundamentalmente dos condiciones:
  • Tiene otra naturaleza en cuanto a la forma en que aparece, no está (a priori) entre los conceptos que maneja el usuario.
  • Tiene otro ciclo de vida. Los objetos del dominio se crean, se guardan (utilizando probablemente un repositorio persistente), luego se pueden consultar, modificar, etc. En cambio los objetos de aplicación se usan una sola vez, suelen tener el estado conversacional entre un usuario y la aplicación, representan un caso de uso.

El objetivo es tener un objeto que sea totalmente independiente de la tecnología, pero que tenga todo el comportamiento necesario de la aplicación. Es la representación del comportamiento global de la apliación sin la componente tecnológica.

Consideramos que es más importante la separación entre los componentes de la aplicación que dependen de la tecnología (vista, controller) y los que no (modelos de aplicación o de dominio); en lugar de la separación entre los roles (dominio vs. el resto, vista vs. controlador). Y el application model nos da la herramienta para lograr eso.

Esta estrategia nos permite:
  • Tener un modelo rico, en el cual poder programar y diseñar libremente, sin dependencias tecnológicas.
  • Por ser independientes de la vista pueden ser testeados con herramientas para testeo unitario sencillas (sin la complejidad de las herramientas de testeo automático para interfaces de usuario).
  • Por adaptarse a las necesidades de la vista, simplifican el mapeo que realizan los controllers.

El  application model funcionará como buffer entre la vista y el modelo de dominio y nos va a permitir construir esa parte de la aplicación programando con objetos y en nuestro lenguaje de preferencia, en lugar de tener que adaptarse a un framework, tecnología o lenguaje que no tiene la misma potencia como JSP o XML.

Algunas variantes de ese concepto se pueden ver en el artículo sobr formas de vincular una vista con el modelo de dominio.

Clase 3 - 28/3/2011

publicado a la‎(s)‎ 26 mar. 2011 17:26 por Nicolas Passerini   [ actualizado el 28 mar. 2012 8:13 por gisela decuzzi ]

Tercera clase: Validaciones y converters.


0. Algo más de arquitectura.

En los ejemplos que vamos a ver a partir de ahora, vamos a intentar hacer aplicaciones más "reales". Eso implica pensar en persistencia. Como dijimos la primera clase la persistencia no es tema de nuestra materia, sin embargo para poder hacer una aplicación completa tenemos que tener alguna noción de ella.
No nos va a interesar "cómo funciona" la persistencia, pero sí cómo interactuamos con ella desde el resto de la aplicación.

La forma que le vamos a dar nosotros a la interfaz con nuestra persistencia es utilizando objetos Home. Tal vez las hayan escuchado nombrar como DAOs, la idea es similar pero nos gusta más hablar de Homes, una home es el lugar donde "viven" todos los objetos de un mismo tipo. En otros lenguajes como Smalltalk, donde las clases son objetos de verdad, estos podrían ser métodos de clase pero acá necesitamos tener un objeto aparte.

Les estamos pasando unas homes que ya tenemos hechas, basadas en db4o. Si quieren pueden mirar cómo trabajan, pero a los efectos de esta materia no es importante. Las cosas que puedo hacer con una de estas Homes son:
  • agregar o eliminar un objeto (métodos típicos de una colección)
  • actualizar un objeto (esto ya es especial)
  • diferentes tipos de búsquedas, las nuestra tienen buscarPorId, buscarByExample y buscarTodos


Otra relación que tenemos con la persistencia es que muchas veces recae sobre ella el manejo de transacciones. Si bien creemos que esa decisión es discutible es lo que pasa en la amplia mayoría de los sistemas que uno desarrolla y salirse de ese esquema es no sólo complicado sino controversial, por lo tanto vamos a adaptarnos a ello (para los interesados podemos ver otras propuestas en otro momento).

En este caso no va a ser necesario manejar manualmente las transacciones, pero sí tenemos que ser conscientes de que la persistencia es transaccional. Concretamente, si modifico un objeto pero no llamo al actualizar de la home, esos cambios se pierden. En muchos sistemas esa característica se utiliza para implementar la cancelación de las modificaciones que uno hace.

1. Introducción al ejemplo del VideoClub


Cerrado eso pasamos a ver un nuevo ejemplo: Videoclub. Por ahora nos vamos a concentrar en la pantalla que puede crear un socio.

De la implementación de esa ventana podemos ver primero un par de detalles técnicos:
  • Extendemos de Dialog
  • Usa otro tipo de layout: ColumnLayout
  • El botón aceptar es default
  • Setea el título de la ventana

Otra cosa interesante es ver el diseño, que no es muy complejo pero me interesa remarcar: vale diseñar en la UI. En particular estamos acá usando un diseño muy simple, una superclase para poner comportamiento común y un template method para integrar lo general con lo específico.

Y luego algunas cosas un poco más conceptuales relacionadas con el binding:
  • Los labels tienen un valor fijo en lugar de un binding.
  • Un adapter para las fechas.

2. Acciones

Los dos botones invocan métodos sobre el dialog y no sobre el modelo. ¿Qué hacen la acción aceptar? Dos cosas
  • Inserta el objeto
  • Cierra la ventana
Vemos entonces que la aplicación tiene dos tipos de acciones, de vista (cerrar la ventana) y de modelo (crear el socio). En este caso esto se incrementa con un método en la vista que ejecuta ambos, otra opción sería hacer un listener (controller) para las dos cosas. (El motivo que lleva a este diseño lo vamos a ver la semana que viene.)

Es importante destacar que la vista ni el controller (listener) deben tener lógica del modelo, en todo caso lo que hacen es delegar al modelo para que él haga su trabajo. (Una variante sería tener una acción de modelo que dispara un evento y la vista lo escucha.)

3. Adapters.

En general, los datos de la UI tienen formatos distintos a los que tiene el modelo, muchas veces pasa. En los controles simples normalmente la información se ingresa como texto, que luego muchas veces debe ser convertida a números o fechas.

En el caso de Arena, algunas de esas conversiones son hechas automáticamente, lo vimos en el caso del ConversorDeMedidas (convertía Strings a números automáticamente). En este caso el conversor de fechas default no nos sirve, entonces hicimos uno propio. En Arena uno puede hacer sus propios conversores extendiendo de Adapter.

Idealmente uno intenta evitar modificar el modelo para adaptarlo a la vista, los Adapters nos permiten hacer eso.

Ya vimos tres formas de controller: Action, Adapter y binding (los objetos concretos que forman un Binding son un poco más complicados, así que por ahora lo vimos sólo por arriba).

4. Validaciones y error panel.

Al ver el Adapter de fecha vimos que tiraba una UserException en caso que no pueda convertir una fecha. También vemos que se tiran errores desde el modelo. Con eso en mente podemos ver algunos tipos de errores y la forma de manejarlos:
  • Errores de conversión: lo ideal es que esos errores no afecten al modelo, el lugar para hacer esto es lógicamente el Adapter.
  • Errores de validación de datos: por ejemplo "la fecha debe ser posterior a la actual", eso es mejor hacerlo en el modelo, es una regla de negocio.
  • Errores que se producen al ejecutar una acción (en este caso se muestran distinto porque se producen "al ejecutar" y no se validan antes pero es en parte una limitación del framework).

Nuestras ventanas tienen un status, que recolecta todos los errores asociados a la ventana, contra ese estado hay dos bindings:
  • El panel de arriba bindea su contenido con el mensaje de error.
  • La habilitación / deshabilitación de los botones
  • Y también cambia el color.

Esto es un ejemplo de las cosas que se pueden hacer con bindings.

5. Resumen

Una cosa importante que vimos varias veces en esta clase es la relación entre las responsabilidades que asignamos a vista/controller o a modelo:
  • Validaciones que ponemos en un lugar o en otro
  • Lo mismo con las acciones.

Discutir vista vs. controller es menos interesante, pero mantener limpio el modelo es una cualidad importante de un sistema.

Lunes 21/3/2011

publicado a la‎(s)‎ 21 mar. 2011 20:34 por Nicolas Passerini   [ actualizado el 22 mar. 2011 21:16 por gisela decuzzi ]

Excepciones

Arrancamos planteando algunos conceptos básicos de excepciones y de la forma en que las vamos a utilizar:
  • La forma que tienen los lenguajes modernos de indicar que una tarea no se puede llevar a cabo es mediante una excepción. Según esta forma de pensar, siempre que algo no se puede hacer se debe indicar con una excepción.
  • Mencionamos algunas de las ventajas de usar excepciones, como que tienen más información que utilizar booleanos, nulos o códigos de error, permiten ordenarse estructuralmente. De las ventajas destacamos la interrupción del flujo de ejecución.
  • Desde el punto de vista técnico diferenciamos excepciones chequeadas y no chequeadas. Por distintos motivos nosotros en esta materia preferimos usar excepciones no chequeadas.
  • Desde el punto de vista conceptual, diferenciamos excepciones de programa y excepciones de usuario. Mencionamos que al usar el framework Arena, las excepciones de usuario se indican lanzando UserException.
Algunas ideas de diseño:
  • Preferimos que las validaciones del dominio se encuentren en los objetos de dominio (vamos a volver sobre este punto más tarde).
  • Las excepciones permiten que el dominio le indique a la UI cuando se intenta utilizarlo de una forma inadecuada. Específicamente, el dominio tira una excepción de usuario que la UI atrapa para indicarle al usuario el error que cometió.
  • Muchas veces, las excepciones de una aplicación son atrapadas por la interfaz de usuario, por eso van a tener un papel importante en nuestra materia.
Nos quedará para la próxima clase hablar sobre los lugares en donde vamos a poner las validaciones. Por ahora mencionamos la posibilidad de poner validaciones en los setters.

Segunda parte: Construir nuestra primera aplicación siguiendo el patrón Model-View-Controller

A. La vista

Nos basamos en un ejemplo muy sencillito: una calculadora que convierte millas a kilómetros. Ingresás una distancia en millas, presionás un botón convertir y te la convierte a kilómetros. Dado que vamos a trabajar con interfaces orientadas a objetos, comenzamos pensando qué objetos intervienen en esa interfaz. Rápidamente surgen cuatro objetos bien visibles:
  • Una caja de texto que nos permite ingresar una distancia en millas.
  • Un botón que dispara la conversión.
  • Un label que muestra el resultado.
  • Una ventana que contiene a todos los demás.
Si bien son menos obvios, nos dimos cuenta de que estamos usando dos más:
  • Un panel, que agrupa a los otros tres componentes. En realidad entonces la ventana no contiene a los componentes sino únicamente al panel, y este a los componentes. Esto es por una cuestión técnica, en el framework que vamos a usar, las ventanas tienen un panel principal y los demás componentes se agregan a este panel, en otras tecnologías podrían agregarse directamente a la ventana sin necesidad del intermediario.
  • Un layout, que es el que tiene la responsabilidad de "acomodar" los componentes dentro del panel que los contiene. Más adelante vamos a ver qué tipos de layout hay.
Construimos esos objetos en Arena, para eso hicimos una clase que extendiera de MainWindow; eso nos obliga a implementar el método createContents, que describe el contenido de la ventana, y nos quedó así:
    @Override
    public void createContents(Panel mainPanel) {
        mainPanel.setLayout(new VerticalLayout());

        TextBox millas = new TextBox(mainPanel);

        Button convertir = new Button(mainPanel);
        convertir.setCaption("Convertir");

        Label kilometros = new Label(mainPanel);
    }

Y hacemos en la misma clase un main para poder ejecutarlo:
    public static void main(String[] args) {
        new ConversorWindow().startApplication();
    }

Una cosa a tener en cuenta es que en Arena es obligatorio definirle un layout a todos los paneles. También vimos que los componentes de Arena utilizan el patrón Composite.

B. El modelo

Nuestro modelo es muy sencillo: un objeto Converter con dos propiedades: millas y kilometros (con sus respectivos getters y setters) y un método convertir que toma el valor de millas, lo convierte y lo guarda en el atributo kilometros.

Estos son dos patrones que van a seguir muchos de nuestros objetos de negocio:
  • Las características de nuestros objetos que sean visibles por el usuario estarán representadas por pares getter/setter. Cuando nos referimos a un atributo de un objeto, pensamos en un par getter/setter, si eso tiene un field atrás no es importante para nosotros, nos interesa la interfaz y no la implementación.
    Un detalle es que a veces puede aparecer el getter solamente, esto denota un atributo inmutable.
  • Las acciones de nuestros objetos que son ejecutables por el usuario estarán representadas (muchas veces) por métodos que no reciben parámetros y no devuelven nada. Esto puede resultar un poco restrictivo, pero simplifica mucho la relación entre dominio y vista; y toda la información que se necesite intercambiar se puede hacer casi siempre utilizando atributos.

C. El controller

Habiendo hecho vista y modelo pasamos a pensar en el controller. Como verán, en este modelo muy simple hay una relación casi uno a uno entre los conceptos de la vista y los del modelo:
  • Tenemos una ventana para el Conversor
  • Un TextBox para la propiedad millas
  • El Button puede asociarse al método convertir
  • Y el Label muestra el valor de la propiedad kilometros
En la medida de lo posible es una buena práctica mantener este tipo de asociaciones uno a uno entre vista y modelo, porque simplifican mucho establecer la relación entre ambos, que en muchos casos es la parte más complicada de la UI.


La forma preferida de vincular vista y modelo es a través de eventos. Tanto la vista como el modelo pueden tirar eventos y obviamente escuchar los eventos que tira el otro. El patrón detrás del concepto de evento es el observer (o listener) y lo que nos permite es tener una comunicación bidireccional sin producir un acoplamiento.

C1. Asociar un listener a un evento de la vista

El caso más fácil de evento es el que se produce al presionar el botón "convertir". Para asociarle un observer a ese evento utilizamos el mensaje onClick, que recibe algún objeto que implemente la interfaz Action.
La implementación más sencilla de esa interfaz es la clase MessageSend, que recibe un objeto y un nombre de método (sí un String) y lo invoca por reflection.

C2. Disparar eventos desde el modelo

Esta parte depende mucho de las posibilidades que den los distintos lenguajes para manejar eventos. En Java utilizamos los eventos de java.beans, para más información vayan a la página de documentación de Manejo de Eventos en Java.

La forma más simple que tiene el framework Arena para disparar un evento ante la modificación de una propiedad de un objeto del domino es:
  1. Hacer que nuestro modelo extienda de ObservableObject.
  2. Programar nuestros setters utilizando setProperty, en lugar de acceder al atributo directamente:

        public static final String MILLAS = "millas";

        private double millas;

        public void setMillas(double millas) {

            this.setProperty(MILLAS, millas);
        }

    Donde el String "millas" hace referencia al nombre del field millas.

    Naturalmente la constante MILLAS no es necesaria, pero es una herramienta útil para reducir el riesgo de errores al usar tantos Strings (van a ver que el trabajo con reflection produce una proliferación de esos Strings que representan nombres de métodos, atributos o fields).
Nótese la diferencia que hacemos entre fields y atributos. Llamamos field a la variable de instancia, es una cuestión de implementación. Por otro lado con atributo o propiedad nos referimos a un par de métodos getter/setter, es decir es una cuestión de interfaz.

En este caso, como en muchos, la implementación del atributo es a través de un field con el mismo nombre, pero vamos a ver que eso no tiene por qué ser así.

Finalmente, el método setProperty es útil solamente en este caso simple en el que atributo y field coinciden, en los casos más complejos se debe disparar el evento manualmente, invocando a firePropertyChange.

C3. Binding

El siguiente paso sería poner listeners entre el TextBox y la propiedad millas. Lo que este listener tiene que hacer es bastante simple: escucha el evento que se produce al cambiar el valor del TextBox y en ese momento actualiza el atributo millas.

Como este tipo de listeners es muy común, existe un mecanismo de más alto nivel que lo hace más sencillo, denominado binding (es decir: vinculación).

El caso más simple de binding es el que vincula (o "bindea") una característica de la vista (por ejemplo el valor de un TextBox) con una propiedad del modelo. En Arena esto se indica de la siguiente manera:

    TextBox millas = new TextBox(mainPanel);
    millas.bindValueToProperty(Conversor.MILLAS);

Aunque en este caso no es necesario, por defecto el binding es bidireccional, es decir los cambios pueden provenir tanto del modelo como de la vista y ambos valores se van a mantener sincronizados. En nuestro ejemplo vemos ambos tipos de comunicación:
  • Los cambios en el valor del TextBox se propagan a la propiedad millas.
  • Los cambios en el valor de la propiedad kilometros se reflejan en el Label.
Más adelante vamos a ver ejemplos más complicados de binding.

Tareas para las próximas clases

  • Si no lo hicieron es la última oportunidad para repasar sobre patrones. En esta clase mencionamos Observer, Composite, Template Method y Command.
    Si tienen dudas sobre algunas de las tecnologías que usamos (Java, Eclipse, svn) por favor hágannoslo saber así les vamos pasando material al respecto.
  • Para el jueves 31 hay que tener andando el dominio, con sus respectivos tests y validaciones. El que tiene ganas de adelantar algo de UI tanto mejor, pero no es indispensable. Para esto último les tenemos que pasar bien la info sobre las dependencias del maven, en el transcurso del fin de semana van a recibir eso.
  • Los apuntes sobre elementos de Java los van a encontrar en esta página. De eso les recomiendo leer:
  • Por otro lado, recomiendo leer sobre JavaBeans, ya que es una herramienta que va a aparecer en todos los frameworks Java.

Les debemos algún apunte (no dejen que me olvide), pero creo que con esto ya tienen para un rato.




Jueves 17/03/2011

publicado a la‎(s)‎ 18 mar. 2011 15:34 por Javier Fernandes   [ actualizado el 18 mar. 2011 15:46 por gisela decuzzi ]

La idea de la clase era configurar y armar el entorno de trabajo con todas las herramientas necesarias.
En el transcurso de eso nos encontramos con el problema de la baja tasa de transferencia de internet, asi que tuvimos que improvisar un eclipse ya empaquetado con los plugins: subclipse y maven.

Para esto vimos algunas cositas de linux que mencionamos acá rápido, pero los invitamos a buscar en google por más info al respecto:
  • linux es "case sensitive" que quiere decir que dos archivos (o carpetas) no son iguales si sus nombres tienen mayúsculas o minúsculas diferentes.
  • sudo permite ejecutar comandos en modo "super user". Los comandos que instalan cosas como el apt-get requieren ejecutarse de esta forma.
  • apt, de aptitude es un sistema de gestion de paquetes de las distribuciones basadas en debian, como ubuntu. Básicamente sirven para manejar el software en linux, sin necesidad de tener que bajarse el código fuente (en C) de los programas y compilarlos a mano. Para esto se conecta a repositorios públicos en internet, y baja versiones ya compiladas y empaquetadas.
  • chown: de "change owner" sirve para cambiar el usuario propietario de una carpeta o archivo en linux.
  • chmod: sirve para cambiar los modificadores de permisos de los archivos, por ejemplo para darle permiso de ejecución a todos los usuarios "chmod a+x", donde "a" es de "all" (para todos los usuarios) y "x" es "ejecución".

Instalamos entonces un JDK, Java Development Kit.

Para refrescar la memoria:
Java es un lenguaje compilado, que se basa en el concepto de "máquina virtual". A diferencia de C, a partir del código fuente, el compilador de java, genera como output un formato de archivo binario intermedio llamado "bytecode". Este formato es independiente del sistema operativo. Por esto es que se dice que java es "portable", porque un programa compilado puede ejecutarse 'así como está' en cualquier sistema operativo.

Y cómo hace para esto ? Bueno, el bytecode es standard, pero solo lo sabe entender un segundo programa, que es una parte de java, llamada Java Runtime Environment (JRE).

Entonces java tiene dos partes (simplificando muchísimo): un compilador "javac" y un comando para ejecutar los programas compilados "java" (el bytecode).

A esto se lo llama VM, máquina virtual. Y existe una VM, o un JRE para cada sistema operativo, porque la VM sí que tiene cosas nativas.
Entonces, tus programas son portables, pero para eso necesitan de una VM que es dependiente del sistema operativo.

En lugar de hacer tooooodos los programas dependientes del sistema operativo, solo "java" es dependiente y el bytecode actua de lenguaje intermedio compatible con todas las VMs para que vos puedas compilar una sola vez para todos los sistemas operativos.

Un JRE solo contiene la parte de java para ejecutar programas ya compilados (bytecode). Es decir, solo con un JRE no se pueden programar aplicaciones java.

En cambio el JDK, sí trae el compilador junto con todas las clases que vienen por default en java, su código fuente, etc.

Nosotros entonces usamos un JDK.
Este fue el que algunos instalaron con "sudo apt-get install sun-java-jdk6" (o algo así), y otros instalaron manualmente a partir del paquete "jdk***.bin"


Eclipse.

El eclipse a su vez está hecho en java. Así que para que corra, tuvimos que configurarlo para que encuentre el ejecutable "java" del jdk que instalamos previamente. Esto se hace editando el archivo "eclipse.ini" con el parámetro "-vm PATH_A_BIN_JAVA", o con la variable de entorno "JAVA_HOME".

Maven.

Maven es algo parecido al concepto de sistema de paquetes que vimos antes con "apt".
Las aplicaciones java son un conjunto de clases, y para distribuirlas se generan archivos de formato zip, con extension ".jar" (aunque a veces para otros casos específicos se generan otros paquetes).
Es muy común en cualquier aplicación utilizar clases de librerías externas, de frameworks, etc.

Anteriormente, uno debía bajarse esos jars a mano de internet, del sitio del "fabricante", por ejemplo de apache, de jboss, etc.
Y manualmente configurar el proyecto en su IDE, en nuestro caso eclipse, diciéndole que nuestro proyecto usa esas librerías.

Esto traía muchísimos problemas, como ser:
  • Concepto de Proyecto y de Dependencias:
    • Java no tiene, por default un concepto de "proyecto", lo que ustedes ven al crear un nuevo proyecto en eclipse, es puramente un concepto de eclipse. (Vean el     archivo ".project" que deben tener sus proyectos.
    • Con las dependencias pasa lo mismo.
    • Entonces, ambas cosas son dependientes del IDE. Y hay muchos IDEs: eclipse, netbeans, IntelliJ IDEA, JDeveloper, etc, etc. etc
  • Versionado y download:
    • En un equipo de desarrollo puede llegar a haber muchísimos programadores.
    • Si cada uno tiene que bajarse cada libreria, eso podría ser crear inconsistencias (hay muchas versiones de una misma libreria)
    • Además de que cada desarrollador bajaría a su máquina muchísimos jars de internet.
  • Dependencias transitivas:
    • Muchas veces al querer usar una librería (jar) resulta que ese jar también depende de otros jars. Esto se llama dependencia transitiva.
    • En un proyecto normal, se terminar generando un arbol de dependencias que podría ser bastaaante complicado. Si uno tiene que bajar manualmente cada libreria, puede llegar a ser un infierno. Además de que, como no había una forma estandar de que cada libreria defina sus dependencias, uno podía encontrarse que quería usar una librería pero no sabía la version de sus dependencias, y no es lo mismo usar "commons-collections 1.0" que usar "commons-collections 3.1". Seguramente nada funciona.

Entonces, en maven, surge la idea de agregar un concepto único y estandar de definición de "proyecto".
Entre otras cosas permite identificar un proyecto unívocamente a través de: groupId + artifactId + version
Y permite definir las dependencias con eso ID completo.
Tambien soporta dependencias transitivas.

Básicamente, hace todo el trabajo sucio de conectarse a repositorios en busca de los jars y todas las dependencias (incluso las transitivas).
También nos permite publicar nuestros propios artefactos a terceros.


Otra herramienta que vamos a usar es "Subversion"

Es un sistema de control de version (VCS). Sirve básicamente para compartir código, publicándolo en un servidor central. Los programadores pueden entonces checkoutear (bajarse) el código a sus propias máquinas, hacer cambios localmente, y publicarlos a las demás personas, haciendo "commit" (subiendo sus cambios al servidor).
A todo esto, el subversion va guardando todos los cambios, y un historial de estos mismos. Permitiendo volver atrás ante cambios, comparar diferentes versiones, etc.

Por último, vimos que los autores de java.util.Date son:
  • James Gosling (que se dice "padre de java")
  • Arthur van Hoff
  • Alan Liu
Y que ambos deberían cuidar su vida si creen en el concepto de "karma" ;)

Tareas:

  • Programar el dominio de la agenda.
  • El lunes vamos a ver excepciones para poder tener buenos testcases sobre el dominio para el Martes 31/03.


Jueves 14/04/2011 - Continuación Web

publicado a la‎(s)‎ 18 mar. 2011 6:43 por Javier Fernandes   [ actualizado el 18 abr. 2011 14:42 por gisela decuzzi ]

De Html dinámico a Aplicaciones


Retomamos la idea de aplicaciones web.
Vimos que si bien uno puede escribir html manualmente, esto genera archivos estáticos. Donde el contenido sería el mismo para todos los usuarios y en diferentes pedidos que haga un mismo usuario en diferentes tiempos (hoy, mañana, el año que viene, etc.)

Esto presenta una limitación muy grande, obviamente, por lo que no nos permite hacer aplicaciones reales.

Entonces, para construir aplicaciones, es necesario hacer un programa, o una aplicación justamente, que genere ese html dinámicamente, con contenido actualizado / generado.

La forma tradicional y más básica de hacer eso en java es con páginas llamadas JSP y a través de un programa java ya existente llamado webserver.

Qué es un web server ??

Un webserver es:
  • un programa que escucha en un puerto dado (generalmente el 80 es el default):
  • entiende el protocolo HTTP (HyperText Transfer Protocol)
  • "sirve" contenido HTML.

Web servers en java

Como dijimos, el html por sí mismo es estático, entonces en el mundo java existe un concepto de webserver que permite tener aplicaciones "java web", que generan estos html dinámicamente.
Esta tecnología es un standard java definido por sun, y se llama "servlets". Y el web server se dice que es un "servlet container".

Un Servlet, es básicamente,
  • una clase java que implementa cierta interfaz,
  • entiende un pedido HTTP y genera una respuesta.
Por ahora, vamos a decir que los JSP's son algo parecido, solo que nos evitan escribir clases java o meter Strings con código html dentro de una clase java.


Servlets vs JSP

El servlet me permite escribir una clase java, y dentro generar html.
En cambio el JSP, a la inversa, me permite definir un archivo mayoritariamente html, y dentro, incluir algo de código java, para hacer la página dinámica.


Model 2

Tipo de arquitectura o convención para crear aplicaciones web, y estructurarlas de modo de:
  • que no quede un servlet con mucho código html.
  • que no quede un html con mucho código java.
La idea es que:
  • el servlet maneja la lógica:
    • de negocio: como por ejemplo, delegar en los objetos de negocio para buscar los Socios del videoclub.
    • de presentación: actúa de controller, manejando las cuestiones de navegación. Para eso, una vez ejecuta la lógica, redirecciona a un JSP, que...
  • el JSP actúa de "vista": específicando como será el html de resultado, y mostrando los resultados de la operación ejecutada por el servlet. Es decir, mostrando los objetos de negocio.

La intención de este modelo es decirse ser una especie de MVC, donde el servlet es el controller, el jsp es la vista, y el negocio las clases a las que delega el Servlet.
En la práctica este modelo es muy precario, para nosotros, para ser considerado un MVC, comparándolo, por ejemplo, con el modelo de MVC que vimos en una aplicación "cliente pesado", como cuando vimos Arena.


HTTP

Vimos algo de la interacción entre el browser y el server.

Que hay dos tipos de pedidos (requests):
  • GET: envía los parámetros como parte de la url. Por ej: http://www.miserver.com/miapp/miservlet?parametro1=valor1&parametro2=valor2
  • POST: envía los parámetros como cuerpo del paquete HTTP. Esto permite enviar más información, y en forma más "segura", ya que no es visible para el usuario del browser diréctamente.

Vimos que una limitación de esta arquitectura, y que está relacionada con el protocolo HTTP, es que "cada pedido es independiente del anterior".
Y, generalmente en las arquitecturas de aplicaciones web, esto implica que el server no tiene "memoria". Específicamente la arquitectura de servlets, maneja las instancias de cada servlet a su manera. No necesariamente va a existir una única instancia de cada servlet. El servlet container podría generar más de una instancia.
Con lo cual, vemos que eso se diferencia bastante con la idea que vimos en arena, donde cada pantalla estaba conectada directamente con nuestros objetos de negocio.

En este modelo, el servlet es como un "servicio web" de la aplicacion, por donde entran los pedidos de todos los usuario. Es "compartido" para todos ellos.
Entonces, esto hace que cada servlet no pueda saber información de cada usuario en particular.
Y esto nos lleva a separar la lógica (servlet) de los datos (estado de la aplicación, para cada usuario).


FORMS:

Vimos el ejemplo de la búsqueda de libros. En particular, cómo interactúa el browser con el server, para enviar los parámetros de búsqueda. Y como el servidor le responde.
Vimos un poco la estructura de las webapp. La idea de JSTL (Java Standard Tag Library), que permite utilizar tags especiales y además definir los nuestros propios.

Entonces, cómo manejo el estado ??

Session:

En el mundo de los servlets containers, existe entonces la idea de "sesion de usuario". Cada usuario (browser) va a tener una de estas sesiones única. La session es básicamente un mapa, donde vamos a poder agregar objetos nuestros, y recuperarlos.

Así, cada servlet que quiera realizar un comportamiento particular sobre objetos del usuario 'actual', va a tener que acceder a este "session".
Estos objetos que seteamos en la sesión se llaman "atributos".
Y es, además, una forma de mantener estado entre los diferentes servlets y páginas JSPs.

Request - Response:

De nuevo con el ejemplo de la búsqueda de libros, vimos que, una consecuencia de que cada pedido genere una página nueva es uno de los problemas más grandes de la programación web. Porque justamente, en este ejemplo, parecía que en la misma página se estaba actualizando solo el resultado.
Pero en realidad, por debajo, vimos que la respuesta era una página completamente nueva.

Algo importante, entonces es que todos los datos que el browser no envía al servidor, "se pierden".
Además, si el servidor (jsp + servlet), no se toma el trabajo de volver a escribir esos valores en cada control correspondiente (por ejemplo en un textbox), también se perdería!

Para formularios chicos esto no parece ser un gran problema.
Pero para aplicaciones con pantallas complejas y con muchos controles, representa un gran problema.


JSP:

Como acceder al estado desde el jsp ?

Usando EL (Expression Language), tenemos acceso a varios objetos "interesantes" para poder manejar el request.
Ej:
  • ${param} : acceso a los parámetros del request (serían los "campos" del formulario enviandos al submitearlo desde el browser). Ej: ${param.titulo}
  • ${sessionScope} : acceso a la session del usuario actual. Ej: ${sessionScope.libros}
  • ${request}: eso, acceso al request

Vimos que EL utiliza también la convención de Java Beans, esperando que las propiedades del objeto tengan accesors (getters & setters)

Expression Language Scopes:

Cuando escribimos una palabra en EL ${algo} esa palabra se intenta resolver contra un conjunto de scopes automáticamente.
Esto permite ahorrarnos escribir la ruta completa, por ejemplo ${sessionScope.atributo} como ${atributo}
Para esto, hay que entender que hay un "orden de resolución", desde el scope más particular al más general (o compartido).
  • page
  • request (sólo attributes)
  • session
  • application

Lunes 14/3/2011

publicado a la‎(s)‎ 15 mar. 2011 8:21 por Nicolas Passerini   [ actualizado el 15 mar. 2011 11:01 por gisela decuzzi ]

Primera parte: aspectos administrativos de la materia

Arrancamos un poquito tarde porque varios se quedaron en la charla, para colmo no teníamos proyector. Como a las 8:20 comencé contando el resumen de las unidades, que se puede ver en Temario detallado. Hablamos también de la relación entre las unidades y de los objetivos de la materia que nos llevan a esa elección de temas.

Luego contamos los 4 trabajos prácticos que vamos a hacer:
  • El primero será un ABM en el framework Arena, asociado a los temas de la Unidad 2.
  • Luego haremos un TP asociado a la Unidad 3, muy chiquito con el objetivo de tener una visión general de la problemática de la programación web.
  • El tercer TP es el más grande y más importante, está asociado a la Unidad 4 y es donde tienen que tomar una decisión entre hacerlo en Wicket o Seaside.
  • Finalmente vamos a hacer un TP de investigación en el que tienen que (a) aprender una nueva tecnología, (b) realizar un programa de ejemplo en ella donde se vean sus características más interesantes y (c) presentarlo al resto de los compañeros.
Todos los trabajos prácticos son individuales, salvo el último que se puede hacer en parejas. No sé si quedó claro así que lo aclaro ahora: no tomamos un examen parcial, la aprobación de la materia se da únicamente en función de los trabajos prácticos.

También vimos un poco la estructura del site, que tiene 4 partes principales:
  • La Materia, con todas las cuestiones adminstrativas, el programa, nuestros correos, etc.
  • Temario detallado y sus subpáginas tiene todo el material teórico, esto es material de consulta permanente que hay que ir leyendo clase por clase.
  • De Material cuelgan un montón de recursos útiles principalmente para la parte práctica de la materia ejemplos, el software para instalar junto con los instructivos necesarios para hacerlo, etc.
  • Y finalmente en la sección Mi Cursada van a encontrar:
    • esta bitácora que se actualiza todas las semanas y tiene los resúmenes de las clases,
    • la planificación detallada (todavía no la subimos) y
    • una planilla con el estado de la cursada de cada uno de ustedes (también está pendiente).
Otra cosa que se mencionó fue la cuestión de los horarios y fechas, algunas notas al respecto:
  1. Los lunes tenemos poquito tiempo para la teoría así que vamos a tratar de ser bien puntuales para aprovecharlo al mango.
  2. Los jueves vamos a hacer mayoritariamente práctica y el horario no es tan estricto (más bien la salida es menos estricta, es decir: el que tiene la práctica lista se puede retirar).
  3. La idea es que la práctica se hace mayoritariamente en el aula aunque no el 100%. Mi recomendación es que traten de venir seguido (o mejor: siempre). Si bien es posible hacer la práctica en casa, es mucho más difícil porque si te trabás puede que tome un rato conseguir ayuda. En general vamos a tratar de avisar los días que se va a dar un tema específico en la práctica, así se aseguran de estar en clase ese día.
  4. Vamos a ser muy estrictos con las fechas de entrega, la experiencia dice que cuando nos relajamos se nos empiezan a acumular las entregas al final del cuatrimestre y terminamos perdiendo la materia por eso.
Eso nos tomó unos 45' así que a las 9:05 nos metimos en los temas teóricos de la Unidad 1.

Segunda parte: Primeros conceptos de las Interfaces de Usuario.

Hablamos largo y tendido sobre la relación entre el dominio y la interfaz de usuario, y por qué no consideramos que sea necesario programar en capas para poder separar ambos concerns. En el medio definimos diseño, arquitectura, capas y algún concepto más que se me debe estar escapando, también diferenciamos la idea de "niveles de abstracción" de "capas" (dejé pendiente la diferenciación entre layer y tier).

Aclaramos que el objetivo principal de esta materia es diseñar interfaces de usuario y (no lo dije exactamente así pero lo aclaro ahora:) eso incluye tanto el diseño interno como la forma en la que interactúa con el dominio (entendiendo además la diferencia entre diseño de sistemas y diseño gráfico).

El material de lectura para repasar estos temas está en la página de la Unidad 1. La reordené un poquito para que sea más simple, ahora están numerados por prioridad:
  • Los puntos 1 y 2 cubren lo que hablamos en clase, eso es lo mínimo que hay que tener sabido para la próxima clase teórica.
  • 3 y 4 es material complementario que también es útil para ir ampliando nuestra comprensión de la problemática.
  • De la parte que está bajo "Material de Lectura" es muy importante ir leyendo el primero. Como dije, es largo y no espero que lo lean de un día para el otro, pero vayan avanzando con eso como para terminarlo al final del cuatrimestre (no se duerman!).

A todo esto ya eran las 9:45 y entonces tiramos los lineamientos de lo que hay que hacer para la próxima clase:

Tarea para el hogar

  1. Repasar las cosas que vimos en Objetos I / II. En esta materia vamos a utilizar fuertemente algunos patrones de diseño. Por las dudas deberían repasar: Observer/Listener, Composite, Strategy, Command, Template Method y Singleton. Si alguno no lo vieron o no encuentran de dónde repasarlo avisen así tiramos algo de material al respecto. La fuente básica de todo esto es el libro Design Patterns de Gama et. al., ese libro está en biblioteca (aunque también es tan famoso que se pueden buscar los capítulos en Internet).

    Además las primeras tecnologías que vamos a ver van a ser en la plataforma Java, así que los que no cursaron Objetos II o no se sienten duchos con el Java deberían apuntar a ponerse las pilas. Para eso, recomiendo este apunte que escribió Leo Gassman: Java para programadores objetosos.

  2. Lean el material de la Unidad 1 (sigan las recomendaciones de la sección anterior).

  3. Sería bueno ir comenzando a armar tu entorno de trabajo en casa, eso incluye:
    • Si vas a usar tu notebook tanto en casa como en el aula, sería bueno tener un doble booteo con Ubuntu.
    • Si se dan maña con la tecnología pueden arrancar a instalar Java, Eclipse, SVN y Maven. Si se sienten perdidos no se preocupen, el jueves lo vamos a hacer en clase y después va a ser más fácil replicarlo en casa. Lo que sí tienen que tener en cuenta es que en la clase vamos a usar Ubuntu y algunas cosas del tutorial también son específicas del sistema operativo, tienen que pensar si quieren usar Ubuntu o Windows para programar en sus casas. Esto será recién obligatorio para el jueves 31 de marzo

  4. Además dejamos una idea para pensar: ¿Por qué los observers/listeners permiten la comunicación en ambos sentidos entre UI y dominio sin producir un acoplamiento entre ambos?
       


1-10 of 10