J2EE (Solo expertos)

mouffetard dijo:
... Lo importante es que los diseñadores y desarrolladores del sistema tengan suficiente experiencia para lograr sistemas eficientes y robustos...

Esto es cierto, pero como hariamos aquellos que iniciamos con cierto framework o plataforma, cuales creen ustedes deberían ser los proyectos que sirvan como "entrenamiento", aunque la verdad ningun proyecto es sencillo aunque asi lo parezca

Gracias.
 
jindix, algo recomendable es fundamentarse bien. La mayoría de las veces los grupos de desarrollos tienden a tomar ejemplos de código e implementar en su aplicación inmediatamente, sin reparar en conceptualizarse con el framework, leer los detalles fundamentales desde la conversión de tipos de datos Java - Base de datos, y resto de cosas que le parecen "chichis" pero que son trasendentales. Ejecutan las cosas a la empirica, prueba / error hasta que funciona por una vez en la maquina local. Esto hace mucho daño al desarrollo de la aplicación, una buena solución es tener un buen director de desarrollo, experimentado y capaz de guiar bien al grupo mientras se fortalece en dichas plataformas. Si el director de desarrollo experimentado no es posible tenerlo por falta de presupuesto, o cualquier otro motivo no queda más que dar el mejor esfuerzo e ir pagando las consecuencias de la novatada.

De mi parte tengo una pregunta, es un problema común presentado en el desarrollo, y estoy casí seguro que más de uno lo ha enfrentado de algún modo. Se trata de la paginación de los resultados de una consulta, es decir, consultas de muchos elementos son generalmente fraccionadas por un factor (generalmente 10). ¿Qué soluciones han encontrado para esto?, en el mercado colombiano he visto varias:

1. Consultan todos los elementos, guardan el manojo de datos en sesión y los van accesando entre diferentes request. Esta solución es logicamente desastroza si de verdad hay una cantidad de elementos consultados. Además, teniendo en cuenta que la aplicación puede tener alta concurrencia, imaginense una buena cantidad de usuarios, cada uno con este lista guardado en su sesión
smiley%20-%20depressed.gif
...

2. Algunos le dejaron la tarea al DAO, aplicando la sintaxis de acuerdo a cada motor de base de datos, para reducir el tamaño de la consulta y comenzarse desde / hasta donde se requiera.

3. La más sensata hasta el momento, de las que he visto, quizas hay mejores. Hibernate permite manejar este problema, además super importante para los que necesitamos abstracción con el motor de base de datos.

A continuación les pongo diagrama estático UML - más conocido como diagrama de clases - ¿qué solución podría ser mejor? ...

Como anoto en el diagrama, estoy inconforme con manchar la interface de negocio con información no funcional para llevar el conteo de la página, o quizas estoy envolatado con los conceptos y la información de la paginación es funcional? ... cualquier opinión bienvenida y agradecida de antemano. Gracias.

PD:
Adjunto 1: Imagen formato PNG del diagrama.
Adjunto 2: Para los que tengan argouml es un proyecto (la versión usada de Argo es 0.18.1).
 

Archivos adjuntos

  • paginacion.png
    paginacion.png
    9.8 KB · Visitas: 140
  • page.zargo.zip
    8 KB · Visitas: 125
En una empresa de desarrollo, yo haría proyectos internos que necesite, por ejemplo, recursos humanos, contabilidad, la misma gerencia etc..., con nuevos frameworks que se quieran explorar. Con esta alternativa tendríamos dos ventas: el riesgo económico es mucho más bajo pues lo asume la misma empresa y no un cliente, la experiencia se desarrolla en forma real, no con ejemplos que muchas veces no cubren muchos casos de uso importantes.
 
El_Rulas dijo:
2. Algunos le dejaron la tarea al DAO, aplicando la sintaxis de acuerdo a cada motor de base de datos, para reducir el tamaño de la consulta y comenzarse desde / hasta donde se requiera.

3. La más sensata hasta el momento, de las que he visto, quizas hay mejores. Hibernate permite manejar este problema, además super importante para los que necesitamos abstracción con el motor de base de datos.

Yo me iría por la 3 en caso que el volumen de datos sea pequeño. Hibernate manejaría los datos en Cache y por lo tanto disminuiría el impacto en memoria del servidor de aplicaciones y en procesamiento del servidor de base de datos.

En caso de tener gran volumen de datos, la 3 no es factible, pues los datos serian tantos que no cabrían en memoria principal, o si caben, la agotarían para poder ser utilaza en procesos "útiles". La alternativa sería un DAO con la sintaxis SQL apropiada para el motor. La portabilidad se podría lograr con el tag <sql> si no recuerdo mal de los mappings de Hibernate, o con un archivo de configuración externo.
 
Me imagino que muchos van a decir que descubrí el agua tibia, pero empecé a probar JSF con JDeveloper 10.1.3 (Developer Preview) y por fin siento que el programador Java va a ser realmente productivo en lo referente a desarrollo de interfaces para clientes WEB.

Definitivamente este es un avance, que aunque suena a sacrilegio, estábamos envidiando del mundo ASP.NET. El famosísimo code-behind, que en secreto envidiábamos, ahora está disponible en Java y como dicen por ahí “new and improved”. Nosotros lo llamaremos backing bean y por fin nos dará facilidad, productividad y separación clara y limpia entre el código de los componentes View/Model/Controller.

Estoy por revisar MyFaces, un conjunto de “controles” JSF que parecen bastante prometedores. De otra lado están las ADF Faces de Oracle, que seguramente proveerán excelente integración con fuentes de datos (data binding).

Si alguien tiene experiencia con el tema, que por favor comparta con todos las experiencias positivas y, sobre todo, las experiencias negativas y como evitarlas.
 
Interesante ;)

Como lo venía diciendo hace ratos, esta cuestión es super positiva para los desarrolladores J2EE, por ejemplo Sun tiene un diseñador gráfico excelente para hacer las pantallas, y genera un código muy limpio. Sin embargo el código JSF es supremamente simple, hacerlo manualmente es realmente muy fácil. JSF también se convertirá en estándar para J2EE 1.5 lo que actualmente lo convierte en la mejor opción frente a Struts (para proyectos por comenzar desde luego).

En la experiencia que tengo, les puedo decir que la implementación de SUN le faltan muchas cosas a las que uno se enfrenta en el mundo real, sólo con propósitos de aprendizaje pueden comenzar con usandola, para una aplicación de la vida real les recomiendo irse por alguna implementación más completa, entre las versiones libres la mejor que encontré fue MyFaces. Honestamente no encontré una razón válida para comprar una de Oracle o BEA. Algunos de los problemas que me solucionó MyFaces que no tenía la implementación de de SUN:

1. Tiles

2. Cuando estén mirando código de las páginas se verán tentados a que el mensaje de error esté acompañado del nombre del campo. El primer candidato es el indicado por el LABEL asociado al inputText (select o el control que sea). Esto lo hace MyFaces. La implementación de SUN no.

3. Quizas necesitarán controles especiales: Tree (arboles), Popup (menú emergente) entre otros. Sun no trae este tipo de controles, MyFaces ya los tiene y usted los puede colocar client side, server side indicandolo en un parámetro.

Eso son algunas de las cosas que recuerdo y hay más desde luego. Cada una de estas cosas se pueden solucionar en la implementación de Sun pero toca hacer cosas especiales, escribir MessageListeners propios y cosas por el estilo. Pienso que si ya está hecho y soportado por alguien para que escribirlo de nuevo? ... una buena noticia es que ustedes pueden utilizar absolutamente todo lo de la implementación de Sun, las demás cosas son sólo extensiones, la especificación es respetada y código ya escrito bajo la implementación de Sun funciona perfectamente en MyFaces.

Cualquier otra inquietud sobre este framework con gusto.
 
ALERTA CON HIBERNATE !

Estimados colegas:

Actualmente estoy en un proyecto en el que estamos migrando de Hibernate a JDBC puro. Inicialmente se tomó la decisión de programar en este framework, motivados por el manejo de caches, programación descriptiva, transparencia con sintaxis SQL, abstracción de base de datos, etc ... sin embargo notamos que el acceso a colecciones grandes es algo bastante ineficiente. Les voy a comentar algunas anecdotas con este framework (tengamos en cuenta que el contexto es una aplicación con un acceso bestial de usuarios).

Hibernate tiene algo interesante "Lazy Loading" (creo que se llama así, sabrán a que me refiero), esto es interesante y aplicable en una aplicación local donde la capa de negocios y web están en la misma maquina, sin embargo cuando se tienen EJB remotos la información toca serializarla (de echo aunque esten en la misma maquina, applications servers como WebPhere serializan todo lo que sale de un EJB). El grave problema de serializar este cuento es que el Lazy Loading trata de hacer su trabajo en plena capa Web cuando están llenando los datos que van a la página, cosa que no funcionará porque ese objeto ya no tiene acceso a los datos porque la conexión (session Hibernate en este caso) ya está cerrada ! y si se tiene clustering / load balancing ni se diga, imposible !! ... una solución inmediata es hacer "Hibernate.initialize(transferObject);", si usted tiene una colección: "Hibernate.initialize(collection);" lo que con antelación rellena el objeto y cuando el EJB lo manda a la capa web ya no hace "Lazy Loading" y la cosa funciona, pero las ventajas de Hibernate van disminuyendo y las ganas de usar JDBC para hacer la cosa más eficiente van aumentando.

Cuando uno inicia un modelo Hibernate jura que solo mapeará tablas simples y pocas relaciones, pero sucede que usted no debería mesclar acceso JDBC, Store Procedure a una tabla que también está accedida por Hibernate porque los datos se vuelven inconsistente: Isolate??? dónde?? ... pero ocurre que en la practica usted le toca empaparse de relaciones para traer descripciones, en otras ocasiones solo quiere un preview para una búsqueda y no quiere traerse todo el "paquete" ... pero Hibernate se lo trae y como el "Lazy Loading" se vuelve un mito en aplicaciones distribuidas le toca decirle a Hibernate que se traiga todo siempre y no puede decirle de algún modo, que sólo vengan los datos de una tabla sin traer sus relaciones, el initialize pobla todo ! ni con HQL respeta la exclusividad.

MORALEJA: Si va a hacer una aplicación local, simple (poco complicada en cuanto a llaves foranas, herencias ...), sin alta concurrencia use Hibernate, de lo contrario no se los recomiendo.
 
El_Rulas dijo:
ALERTA CON HIBERNATE !

Estimados colegas:

Actualmente estoy en un proyecto en el que estamos migrando de Hibernate a JDBC puro. Inicialmente se tomó la decisión de programar en este framework, motivados por el manejo de caches, programación descriptiva, transparencia con sintaxis SQL, abstracción de base de datos, etc ... sin embargo notamos que el acceso a colecciones grandes es algo bastante ineficiente. Les voy a comentar algunas anecdotas con este framework (tengamos en cuenta que el contexto es una aplicación con un acceso bestial de usuarios).

Hibernate tiene algo interesante "Lazy Loading" (creo que se llama así, sabrán a que me refiero), esto es interesante y aplicable en una aplicación local donde la capa de negocios y web están en la misma maquina, sin embargo cuando se tienen EJB remotos la información toca serializarla (de echo aunque esten en la misma maquina, applications servers como WebPhere serializan todo lo que sale de un EJB). El grave problema de serializar este cuento es que el Lazy Loading trata de hacer su trabajo en plena capa Web cuando están llenando los datos que van a la página, cosa que no funcionará porque ese objeto ya no tiene acceso a los datos porque la conexión (session Hibernate en este caso) ya está cerrada ! y si se tiene clustering / load balancing ni se diga, imposible !! ... una solución inmediata es hacer "Hibernate.initialize(transferObject);", si usted tiene una colección: "Hibernate.initialize(collection);" lo que con antelación rellena el objeto y cuando el EJB lo manda a la capa web ya no hace "Lazy Loading" y la cosa funciona, pero las ventajas de Hibernate van disminuyendo y las ganas de usar JDBC para hacer la cosa más eficiente van aumentando.

Cuando uno inicia un modelo Hibernate jura que solo mapeará tablas simples y pocas relaciones, pero sucede que usted no debería mesclar acceso JDBC, Store Procedure a una tabla que también está accedida por Hibernate porque los datos se vuelven inconsistente: Isolate??? dónde?? ... pero ocurre que en la practica usted le toca empaparse de relaciones para traer descripciones, en otras ocasiones solo quiere un preview para una búsqueda y no quiere traerse todo el "paquete" ... pero Hibernate se lo trae y como el "Lazy Loading" se vuelve un mito en aplicaciones distribuidas le toca decirle a Hibernate que se traiga todo siempre y no puede decirle de algún modo, que sólo vengan los datos de una tabla sin traer sus relaciones, el initialize pobla todo ! ni con HQL respeta la exclusividad.

MORALEJA: Si va a hacer una aplicación local, simple (poco complicada en cuanto a llaves foranas, herencias ...), sin alta concurrencia use Hibernate, de lo contrario no se los recomiendo.

Es muy cierto....
Cuando todo se encuentra en la misma maquina es una buena solucion....

Utilizar y saber utilizar el Lazy loading es complicado.....
Pero se puede usar y acceder a los objetos relacionados por medio de otros queries---
aunque esto.. por su puesto quita una parte de la funcionalidad de hibernate.. pero en terminos de recursos es mucho mejor aunque se tenga que programar mas:::::
 
PROBLEMA DE LOS CONSECUTIVOS:

Contemos como hemos solucionado este problema en escenarios con alta concurrencia.

1. Código JDBC con transaccionalidad.

2. Secuence Oracle.

3. Store procedure.

4. Store procedure y trigger en el evento BEFORE INSERT.

5. Entity Bean.

6. Variable pública estática tipo "int" dentro de una función synchronize que se va incrementando - count = count + 1; ... No mentiras :)


Teniendo en cuenta que se necesita obtener el número generado para retornarlo al código que llama para que él se entere - lo mostrará en pantalla, lo guardará en sesión para hacer alguna vaina - cuál solución es la más eficiente a su modo de ver? ...

Algo más: Si es posible den una sugerencia independiente de motor de base de datos.
 
PORTABILIDAD ENTRE APPLICATION SERVERS:
(tema para interesados en usar diferentes applications servers para una misma aplicación, o para los que odien el matrimonio).

Si alguno tiene una sugerencia para contruir EAR'S portables. Usa alguna metodología para esto le agradecería que la compartiera. A los que les haya tocado hacer el papel de "DEPLOYADOR". La sugerencia me parece más importante desde el punto de vista de como organizar las "third party libraries", recomendaciones a la hora de programar. Podemos dejar a un lado el asunto de los descriptores, eso es algo de lo que no podemos escapar. Siempre toca hacer los descriptores propios de cada aplications. Pero problemas diferentes a esos pueden solucionarse (creo yo) haciendo las cosas de una manera estándar, sugerencias de mi parte:

1. Usar referencias en los descriptores para llamar a los EJB's y agentes externos. java:/comp/env/ejb/MyEJB.

2. Todo lo que se transporta de EJB's a clientes: Web, Swing es serializable ! lo que contenga el objeto serializable que no sea serializable se le pone un lindo "transient".

3. En lo posible si tienen un AppServer que pase los valores de los EJB's por referencia, configurenlo para que los pase por valor, que es lo más portable. Ejemplo: JBoss. Además les recomiendo cambiar el "classLoader flat" que trae por defecto al "Isolated" que es como se portan los AppServers robustos. ADVERTENCIA: Si tiene una aplicación funcionando en JBoss con las opciones por default que acabo de mencionarle, puede caer fuego del cielo cuando las cambie :).

4. El problema de los JAR's third party es berraco ! .... ustedes repiten los Jar's en cada componente: WAR; EAR, EJB ó cómo han manejado este gallo?

Algunos AppServers no ponen problemas, en las cuestiones anteriormente nombradas pero uno nunca sabe como se portará el otro. Lo mejor es hacer algo un poco más complicado pero que funcione (en lo posible) sin cambio alguno en la otra plataforma.


Cualquier sugerencia es bienvenida.
 
El_Rulas dijo:
ALERTA CON HIBERNATE !
MORALEJA: Si va a hacer una aplicación local, simple (poco complicada en cuanto a llaves foranas, herencias ...), sin alta concurrencia use Hibernate, de lo contrario no se los recomiendo.

Odio decirlo pero I told you so!! :\

A veces mantener las cosas simples es la mejor manera en que una aplicación será realmente de nivel empresarial. Los frameworks nos agilizan el desarrollo pero simultaneamente nos aumentan el riesgo tecnológico.
 
Utilizando MANIFEST.MF

El_Rulas dijo:
PORTABILIDAD ENTRE APPLICATION SERVERS:

4. El problema de los JAR's third party es berraco ! .... ustedes repiten los Jar's en cada componente: WAR; EAR, EJB ó cómo han manejado este gallo?

Lo que yo he hecho es utilizar el atributo Class-Path del MANIFEST.INF del JAR de los EJB. La estructura que utilizo es la siguiente:

Código:
/
 --ejbjar.jar/
                   META-INF/
                                  MANIFEST.MF
                                  ejb-jar.xml
 --app-web.war
 --/lib/
        external1.jar
        external2.jar

entonces, para que mis EJB encuentren las librerias en /lib utilizo:

Código:
[B]MANIFEST.MF:[/B]
Manifest-Version: 1.0
Class-path: /lib/external1.jar /lib/external2.jar

Lo mismo con el manifes del WAR. Así se evita duplicar las librerias.
 
El_Rulas dijo:
PROBLEMA DE LOS CONSECUTIVOS:

3. Store procedure.

Teniendo en cuenta que se necesita obtener el número generado para retornarlo al código que llama para que él se entere - lo mostrará en pantalla, lo guardará en sesión para hacer alguna vaina - cuál solución es la más eficiente a su modo de ver? ...

Algo más: Si es posible den una sugerencia independiente de motor de base de datos.

Stored Procedure:

Recibe los datos para crear el registro y devuelve el número de secuencia asignado. A continuación un código PL/SQL muy burdo:

Código:
  procedure saveXX(argumentos...) returns varchar2
    SELECT sequence.NEXTVAL into mi_temp FROM DUAL;
    INSERT INTO .... (el código para insertar);
    return mi_temp;
  end saveXX;

Las secuencias soportan alta concurrencia y no generan bloqueos, como otros métodos del middler tier si lo hacer, y peor aun, que no son posibles en ambientes con clustering.

Otra alternativa es utilizando JDBC puro para obtener el número de secuencia y luego hacer la operación sobre la base de datos. Se puede crear un DAO que sepa hacer esta operación para soportar portabilidad de RDBMS.

Estas dos operaciones se deben realizar como parte de una sola transacciones, no se pueden extender a través de más de un request :muerto:
 
mouffetard dijo:
Lo que yo he hecho es utilizar el atributo Class-Path del MANIFEST.INF del JAR de los EJB. La estructura que utilizo es la siguiente:

Código:
/
 --ejbjar.jar/
                   META-INF/
                                  MANIFEST.MF
                                  ejb-jar.xml
 --app-web.war
 --/lib/
        external1.jar
        external2.jar

entonces, para que mis EJB encuentren las librerias en /lib utilizo:

Código:
[b]MANIFEST.MF:[/b]
Manifest-Version: 1.0
Class-path: /lib/external1.jar /lib/external2.jar

Lo mismo con el manifes del WAR. Así se evita duplicar las librerias.

¿En que AppServers te ha funcionado esa alternativa? ..
 
mouffetard dijo:
Odio decirlo pero I told you so!! :\

A veces mantener las cosas simples es la mejor manera en que una aplicación será realmente de nivel empresarial. Los frameworks nos agilizan el desarrollo pero simultaneamente nos aumentan el riesgo tecnológico.

Sabia que dirias eso, pero recuerda que hablabamos mas que todo de JSF del cual estás enamorado ahora :). Sin embargo, tienes razón el asunto simple facilita cuando las cosas son bien exijentes en la aplicación, pero en la capa Web vale la pena el riesgo. En la capa de negocios y de persistencia es de pensarlo bien según el escenario.
 
mouffetard dijo:
Stored Procedure:

Recibe los datos para crear el registro y devuelve el número de secuencia asignado. A continuación un código PL/SQL muy burdo:

Código:
  procedure saveXX(argumentos...) returns varchar2
    SELECT sequence.NEXTVAL into mi_temp FROM DUAL;
    INSERT INTO .... (el código para insertar);
    return mi_temp;
  end saveXX;

Las secuencias soportan alta concurrencia y no generan bloqueos, como otros métodos del middler tier si lo hacer, y peor aun, que no son posibles en ambientes con clustering.

Otra alternativa es utilizando JDBC puro para obtener el número de secuencia y luego hacer la operación sobre la base de datos. Se puede crear un DAO que sepa hacer esta operación para soportar portabilidad de RDBMS.

Estas dos operaciones se deben realizar como parte de una sola transacciones, no se pueden extender a través de más de un request :muerto:

Bien. Estos dìas debatiendo este problema de los consecutivos, sucedio algo que me dejo pensando. Investigando soluciones, diferentes opciones para este tipo de problema llegue a echar un vistazo a la aplicación Pet Store de los blueprints de Sun, el cual suponía era una aplicación modelo para una excelente arquitectura J2EE, vaya sorpresa que me llevo y encuentro que el problema de los consecutivos està resuelto empleando Entity Beans !! lo cual es calificado como la peor opción en cuanto a rendimiento. ¿Què piensan de esto? Pet Store es un juguete educativo, pero nada que sea 100% ejemplo para el mundo real? ... tambièn da a pensar que SUN impulsa sus tecnologías sin objetividad alguna? .... Por ejemplo: Las aplicaciones de ejemplo .NET hay que aplaudirles que les preocupó el rendimiento y estas situaciones están escritas en Store Procedures.
 
El_Rulas dijo:
¿En que AppServers te ha funcionado esa alternativa? ..

Me ha funcionado en el OC4J Stand Alone y en el Oracle Application Server 10g. No he tenido la oportunidad de probarlo en ninguno otro, pero es un mecanismo estándar que se supone debe funcionar en general.

Tomado de http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html
Class-Path :
The value of this attribute specifies the relative URLs of the extensions or libraries that this application or extension needs. URLs are separated by one or more spaces. The application or extension class loader uses the value of this attribute to construct its internal search path.

Parece que en WebLogic también funciona http://e-docs.bea.com/wls/docs70/programming/classloading.html

The J2EE specification provides the manifest Class-Path entry as a means for a component to specify that it requires an auxiliary JAR of classes.

En SilverStream de Novell, parece que también: http://developer.novell.com/tech/1229.html

En este artículo de TheServerSide indican que hace parte de la especificación y que por lo tanto los AppServers lo podrian implementar:

Section 8.1.1.2 of the J2EE 1.3 specification mandates explicit support for the bundling of dependent .jar files via the Extension Mechanism Architecture (see the References section). Application servers must load dependent .jar files listed in the Manifest Class-Path entry of a primary .jar file (typically an EJB .jar). This requirement is not mandated for .ear or .war files. The extension mechanism is a valuable technique that should not be overlooked when packaging an application. Whenever possible, be sure to investigate and understand exactly which class loader is used to load dependent jar files.

Espero te sirva.
 
Sip. De echo esa es la solución que actualmente uso: (vease Post No. 1 del foro). Era feliz pensando que era lo estándar para todo. Sin embargo, en el libro "One-on-One J2EE Design and Development" me dejo pensativo con este comentario:

Especially in EJB JAR files, use J2SE 1.3 manifest classpaths to avoid the need to include the
same class definitions in multiple modules. However, remember that not all application servers
support manifest classpaths in EAR or WAR deployment units. Also, remember that manifest
classpaths only affect where a class definition is held, and do not resolve problems resulting
from which class loader first loads a class (for example, the problem of a class loaded by an
EJB class loader being unable to see classes within a WAR in many servers).


Pero la verdad me quedé pensando, cuales serían estos applications? pero al parecer funciona en los más populares. Sería interesante saber cuales son los extraterrestres :).
 
Bueno pues de todo lo que han dicho....
Creo que tienen mucha razon con lo de las aplicaciones locales para Hibernate....
Pero para concurrencia no es necesariamente cierto lo que dicen...

Hibernate por si solo no puede manejar una buena concurrencia... pero para eso existen algunos apoyos....Tal como Spring...
 
Oigan pelaos, buen dato el de Hibernate, precisamente ahora estoy en un dilema. Tengo una aplicación hecha con Struts, hay varias consultas que se realizan en el home del aplicativo, esto significa varias sentencias SQL al tiempo, por un lado los registros consultados son de tamaño mediano, pero la concurrencia de usuarios es bastante alta.

Habia pensado en Hibernate para colocar esas consultas en caché, para que no se sobrecargara el server, como podría solucionar este inconveniente, como les digo son casi 7 consultas a distintas tabla, y hacerlas cada vez que un usuario ingresa no es óptimo, pero usar Hibernate no me garantiza que si vienen demasiados datos o estos son muy grandes, no se reviente la app.

Gracias por su valioso tiempo y por tomarse la molestía de contar sus experiencias.
 

Los últimos temas