BUENAS
PRÁCTICAS EN J2EE. SEGUNDA PARTE.
VERSION
PARA IMPRIMIR
(Primera parte en
../articulos/art6/art6-1.html
Versión original en español en
../articulos/art7/art7-1.html
Enlace a la versión original en inglés)
Informe de
The Middleware Company
Traducido
y abreviado con permiso por
Dr.
Vicent-Ramon Palasí Lallana.
Gerente General de Aurum Solutions.
http://www.aurumsol.com
Diciembre 2003
5.
DESPLIEGUE
El despliegue es una de las etapas finales del desarrollo
de software. En ella, se copian todos los archivos que se
necesitan para ejecutar una aplicación del entorno
de desarrollo al de producción. El resultado de la
etapa de despliegue es una aplicación ejecutable ubicada
en un entorno de producción.
5.1. Buena práctica número 12. Siga
la especificación estándar J2EE para empaquetado
La especificación J2EE describe los artefactos necesarios
para el proceso de despliegue y su ubicación en el
servidor, permitiendo así la portabilidad de las aplicaciones
y sus componentes. A continuación, se muestra una
lista de módulos que incluye la especificación:
-
Una aplicación J2EE se empaqueta
en un archivo EAR (Enterprise Archive), que es un archivo
JAR estándar
con una extensión .ear. Para crear un archivo EAR,
se combinan módulos EJB, Web y de aplicación
con los descriptores de despliegue adecuados para cada uno
de ellos.
Un módulo EJB es una colección de Enterprise
Javabeans, empaquetados conjuntamente en un archivo .jar.
Este archivo contiene todas las clases necesarias para los
Enterprise Javabeans, incluyendo clases de soporte y un descriptor
de despliegue EJB (llamado “ejb-jar.xml”).
Un módulo Web se empaqueta en un archivo JAR que
tiene una extensión .war. Este archivo está compuesto
de servlets, JSPs, applets, clases de soporte, documentos
estáticos (HTML, imágenes, sonidos, etc) y
un descriptor de despliegue Web (llamado “web.xml”).
Un módulo de aplicación es un archivo JAR
estándar que contiene tanto clases Java como un descriptor
de despliegue de aplicación cliente (llamado application-client.xml).
Los descriptores de despliegue son archivos
de configuración
XML que contienen toda la información necesaria para
desplegar los componentes de un módulo así como
las instrucciones para combinar los diversos componentes
dentro de una aplicación.
Dada la complejidad del empaquetado, se debería aplicar
una herramienta de verificación J2EE, como la que
proporciona el SDK J2EE, sobre el archivo EAR resultante
antes del despliegue. Una herramienta de verificación
comprueba que el contenido del despliegue esté bien
formado y que sea consistente con las especificaciones de
EJB, servlets y J2EE.
5.2. Buena práctica número 13. Utilice
herramientas que ayuden en el despliegue
A pesar de la excelente documentación que explica
el proceso de despliegue, éste puede llegar a ser
agotador, complejo y difícil de depurar. Afortunadamente,
hay una variedad de herramientas que lo facilitan.
Aunque la mayoría de entornos de desarrollo (IDEs)
proporcionan un soporte adecuado para el despliegue, no se
debería
depender de estas tecnologías propietarias. Por el contrario,
es preferible crear un guión que permita el despliegue
sobre cualquier plataforma, aunque ésta no soporte
el IDE.
Para ello, Ant es la herramienta usada por la mayoría
de los mejores programadores, ya que ofrece una serie de
ventajas para desplegar aplicaciones J2EE. Usando Ant, se
pueden desplegar aplicaciones de forma
tan sencilla como ejecutar un comando. Ant tiene tareas incorporadas
para crear archivos JAR, WAR y EAR. Además, puede
automatizar también la copia de los archivos a su
ubicación correcta en el servidor
J2EE. La diferencia más importante entre un IDE y
un guión (como los de Ant) para despliegues de gran
tamaño es que el último se puede repetir fácilmente.
Además,
como un guión no requiere intervención manual,
es una opción mucho más sólida para
desplegar en un entorno de producción.
5.3. Buena práctica número 14. Respalde sus
datos y su entorno de producción
Debería tener precaución extrema cuando trabaje
con máquinas de producción. Hay pocas cosas
que causen un daño mayor que hacer cambios a un entorno
de producción. Se puede evitar mucho sufrimiento si
se hacen copias de respaldo. Planifique respaldar sus entornos
de producción y de desarrollo. Es fácil de
hacer y es lo que se debe hacer.
Asegúrese de que sus copias de respaldo incluyan
archivos de aplicación, de configuración y
de datos. Respalde con regularidad y
también antes de cada despliegue. Así, en caso
de problemas, podrá recuperar fácilmente el último
estado bueno.
6. AFINACIÓN (TUNING)
Quizás la etapa más descuidada en la mayoría
de los proyectos de desarrollo es la de afinación.
Esto es sorprendente, pues una de las causas más comunes
de fracaso en grandes proyectos de software es un pobre rendimiento.
Aunque muchos programadores llevan a cabo algo de afinación
no estructurada, muy pocos construyen y ejecutan un plan
de rendimiento que funcione. Aunque parte del problema se
debe a la falta de buenas herramientas de afinación,
esta situación está cambiando. Algunos vendedores
están comenzando a incluir buenos servicios de perfilado
en Java así como ayudas para la resolución
de problemas.
6.1. Buena práctica número 15. Construya
un plan de rendimiento
Es necesario comenzar con un plan sólido de rendimiento.
A continuación
se detallan los componentes clave de dicho plan:
Criterios. Se debe asegurar que se capturan todos los criterios
importantes de rendimiento. Se debería ser lo más
específico posible sobre cargas, tiempos y configuraciones.
-
Interesados. Se debería determinar
las personas que deben aprobar el plan y las que deben aprobar
el producto
acabado. Se debería nombrar a un director del plan
para que alguien sea responsable del rendimiento de la aplicación.
-
Mitigación de riesgos. El plan
de rendimiento es un buen lugar para comenzar a planificar
cómo se mitigan los riesgos cuando algo sale mal.
Cronograma. Se necesita reservar tiempo suficiente para
implementar el plan de rendimiento. Se debería reservar
un poco de tiempo durante cada iteración de diseño
para solucionar los cuellos de botella asociados a cada caso
de uso. También se debería reservar un periodo
de tiempo al final del ciclo de desarrollo, normalmente combinándolo
con las pruebas.
-
Herramientas. Se debería definir
qué herramientas
se usarán para analizar y afinar el rendimiento. Estas
herramientas ayudarán a simular cargas, perfilar el
rendimiento de la aplicación, analizar los resultados
y afinar servidores de software individuales como, por ejemplo,
motores de bases de datos.
-
Entornos. Si se necesitan simular cargas
grandes, se necesitará una
red extensa para hacerlo y un software para ejecutarlo. Otra
opción es alquilar a consultores tiempo en este tipo
de entornos.
-
Personal. Necesita asegurarse de que
cuenta con los recursos humanos necesarios para el plan,
desde personal de programación a administradores
de bases de datos y especialistas en hardware.
Casos claves de prueba. Se deberían construir los
casos críticos de prueba por adelantado.
Después de que se ha construido el plan de rendimiento, éste
debe ser aprobado por los interesados, se debe asegurar que
se contará con los recursos y se debe ejecutar el
plan. Normalmente las metodologías
iterativas incluyen etapas que enfatizan el diseño
de una solución, su construcción, pruebas y
despliegue. Un análisis de rendimiento sólido
se extiende por todas estas etapas.
Resumiendo, los problemas tardíos de rendimiento
han hecho fracasar muchos proyectos, pero si se cuenta con
un plan sólido, se tendrá más probabilidades
de salir ileso. La planificación de rendimiento es
costosa pero las alternativas pueden ser catastróficas.
6.2. Buena práctica número 16. Gestione
las fugas de memoria
En este documento, una fuga de memoria (“memory leak”)
es aquella memoria que la aplicación ya no necesita,
pero que el recolector de basura (“garbage collector”)
no libera. En sentido estricto, esto no es realmente una
fuga: es simplemente que el programador no da la información
suficiente al recolector de basura para que haga su trabajo.
La recolección de basura en Java funciona identificando
objetos que son alcanzables por la máquina virtual
de Java, como se muestra en la figura 2. De forma periódica
(por ejemplo, cuando la cantidad usada de memoria sobrepasa
un cierto límite), la máquina virtual invoca
al recolector de basura (GC). En la ejecución del
programa, algunos objetos referencian a otros, creando un
grafo dirigido. El recolector de basura examina todos los
objetos en memoria y ve si son alcanzables desde el objeto
raíz, es decir, si hay un camino en el grafo desde
ese objeto raíz a cada objeto. Con esta información,
el recolector de basura marca los objetos como alcanzables
o no y libera todos los objetos que no son alcanzables.
Figura
2. El recolector de basura de Java funciona determinando
los objetos que son alcanzables. Una flecha indica una
referencia de un objeto a otro.
Consecuentemente, si se ha dejado una referencia a un objeto
en algún lugar, el objeto no puede ser liberado, pues
puede ser alcanzado de alguna forma. Las fugas de memoria
pueden ocurrir de muchas formas diferentes, pero sus causas
son solamente unas pocas:
-
Limpieza descuidada de referencias. Puede
ocurrir una fuga de memoria cuando un objeto
primario crea
otro objeto
y, entonces, varios objetos adicionales crean referencias
a este último. Si no se “limpian” estas
referencias cuando se libera el objeto primario, entonces
se tendrá una fuga de memoria.
Diferentes ciclos de vida. Cuando un objeto con un ciclo
de vida largo gestiona otro con un ciclo de vida corto, hay
potencial para una fuga de memoria.
Mal manejo de excepciones. Algunas veces, las excepciones
pueden evitar el código de limpieza. Por esta razón,
debería colocar este código en los bloques
finally.
La mayoría de fugas de memoria en Java están
comprendidas en una de las tres categorías anteriores.
Estudiemos algunos casos especiales de fugas:
La colección con fuga. Este tipo de fuga de memoria
sucede cuando se coloca un objeto en una colección
y nunca se elimina de la misma. Con una caché, esto
sucede cuando nunca se eliminan datos viejos de la misma.
El patrón de diseño “Publish-Subscribe” permite
que un objeto que declara un evento publique una interfaz
y los suscriptores reciban notificación cuando el
evento ocurre. Cada vez que un objeto se suscribe a un evento,
es colocado en una colección. Si desea que el recolector
de basura libere el objeto suscriptor, deberá cancelar
la suscripción cuando haya acabado con ella.
Singleton. Este tipo de fuga de memoria
ocurre cuando se tiene un singleton con un ciclo de vida
largo que referencia
un objeto con un ciclo de vida corto. Si no se pone la referencia
a null, entonces el recolector de basura nunca liberará el
objeto de vida corta.
-
La función costosa que apenas se usa. Muchas
aplicaciones tienen funciones, como Imprimir, que pueden
ser extremadamente
costosas pero que son usadas en pocas ocasiones. Si se referencia
estas funciones desde objetos con ciclos de vida largos,
es mejor limpiar explícitamente las referencias entre
los usos.
El estado de sesión. Cuando se maneja estado de sesión,
se está sujeto a fugas de memoria, porque es difícil
determinar cuando finaliza la sesión con un determinado
usuario.
Estas son las fugas típicas. Seguramente, usted encontrará otras.
Como las fugas de memoria son muy difíciles de encontrar,
vale la pena comprender los patrones asociados con las mismas
y aplicar a esas áreas un mayor escrutinio.
Cuando se descubra una fuga, se debería usar una plataforma
que ayude a identificarla.
Resolución de fugas
Para resolver los problemas de memoria, se deberían
seguir los siguientes pasos:
-
Reproducir el problema. El primer paso
(y el más
importante) es crear un caso de prueba que reproduzca
el problema. Para ello, puede comenzarse activando la recolección
de basura después de ejecutar los casos de prueba.
Cuando se examine el uso total de memoria respecto al tiempo,
se formará un gráfico con picos y valles. Los
picos ocurren antes de que el sistema active la recolección
de basura. Los valles aparecen después de la recolección
de basura y representan el uso verdadero de memoria en el
sistema. Si los mínimos en los valles aumentan a un
ritmo constante, como en la figura 3, se ha encontrado una
fuga de memoria.
Figura
3. El eje vertical representa el uso de memoria y el
horizontal, el tiempo. El aumento en los valles entre
recolecciones de basura (GC) indica una fuga.
-
Aislar el problema. Después
de reproducir el problema, se debe intentar aislar el problema
acotando el caso de prueba.
Con frecuencia, se encuentra la fuga de esta forma, sin necesidad
de más investigación.
-
Encontrar los objetos que molestan. El
siguiente paso es usar un perfilador de memoria para localizar
los objetos
en memoria en los que se encuentra la fuga. Así, se
comienza identificando bloques de memoria anormalmente grandes.
Entonces, se comprueba el número de instancias de
estos bloques y, a continuación, se
activa la recolección
de basura para los mismos, volviendo a contar el número de
instancias de nuevo. Así se
puede determinar si el sistema está liberando los
objetos como debería.
-
Encontrar y reparar referencias a esos objetos. Cuando
se ha identificado el objeto causante de la fuga, se pueden
encontrar referencias al mismo y repararlas, lo que implica
asignarlas a null o bien realizar otros pasos de
limpieza (cerrar un archivo, eliminar una referencia de una
colección,
etc.). La limpieza debería realizarse en un bloque
finally y no en el cuerpo principal de un método,
para asegurarse de que se ejecuta incluso cuando las
excepciones interrumpen la ejecución del programa.
Prevenir futuros casos del problema. Cuando
sea posible, se deberían eliminar las causas de
los problemas que causaron las fugas para evitar que se
repitan en el futuro.
6.3. Buena práctica número 17. Concéntrese
en las prioridades
Una forma de la regla 80/20 dice que, típicamente,
80% de la ejecución de un programa ocurrirá en
un 20% del código. Por ello, es importante concentrar
los recursos de desarrollo en las áreas que probablemente
tengan un mayor impacto sobre el rendimiento. Para ello,
debemos considerar:
El análisis de puntos calientes (Hot spot analysis)
determina las secciones de código más activas
para que los programadores concentren en ellas sus esfuerzos
de optimización.
-
Las medidas de rendimiento pueden localizar
casos de prueba que son críticamente lentos de forma
que pueda variar la ejecución para que pase por las
secciones de código con mayor importancia en el rendimiento,
con el fin de poderlo optimizar.
La automatización de las pruebas de rendimiento permite
establecer criterios sólidos de rendimiento para los
casos de prueba y resolver problemas cuando se violan esos
criterios. Para ello, se puede usar JUnitPerf (http://www.clarkware.com/software/JUnitPerf.html)
o cualquier herramienta de automatización de pruebas
de rendimiento.
La clave de una afinación efectiva es una asignación
eficiente de recursos. Es decir, se debería invertir
la mayor parte del tiempo en afinar las áreas de la
aplicación que producirán el mayor beneficio.
Lo contrario también es cierto: no se debería
invertir tiempo intentando optimizar cada elemento de código
que se escribe, excepto si se sabe que es crítico
para el rendimiento. Esto no quiere decir que se deba escribir
código descuidado, sino que debe usarse el código
más simple que funcione, como mínimo hasta
que las pruebas manuales o automáticas de rendimiento
confirmen que es necesario optimizarlo.
7. ENTORNOS
Aunque este documento de buenas prácticas se concentra
en el desarrollo de software, en este apartado se estudiarán
buenas prácticas para los entornos de desarrollo y
producción.
7.1. Buena práctica número 18. Elija
adecuadamente su entorno de producción
Para despliegues de gran tamaño, se necesita diseñar
el entorno de producción tan cuidadosamente como la
aplicación. Las alternativas de despliegue que
tienen mayor impacto sobre el desarrollo de la aplicación
son los siguientes:
Clustering contra standalone. Si la implementación
de la aplicación usa la técnica de clustering,
cada parte de la aplicación J2EE deberá soportar
esta técnica.
Distribución de capas en las diferentes máquinas. Las diferentes arquitecturas J2EE se corresponden con diferentes
arquitecturas en n-capas. A continuación, se dan unas
indicaciones para elegir la arquitectura más adecuada.
Capas de una aplicación
Las capas ayudan a organizar la lógica de la aplicación.
Pueden facilitar el mantenimiento, aumentar la flexibilidad
y resolver problemas de despliegue. El catálogo de
patrones J2EE reconoce de tres a cinco capas, dependiendo
de los requerimientos de cada aplicación:
Capa del cliente. Esta capa soporta la interfaz de usuario,
que es normalmente HTML, la cual puede extenderse con applets
en Java o lenguajes de guión.
Capa de presentación. Esta capa es responsable de
construir una clara separación entre modelo, vista
y controlador.
-
Capa de negocio. Esta capa contiene lógica
de negocio. EJB puede ser una implementación de esta
capa.
Capa de integración. Esta capa proporciona lógica
que se usa para acceder a sistemas complejos de legado. Los
servicios Web y las arquitecturas de colas pertenecen a esta
capa.
Capa de recursos. Son recursos las bases de datos o aplicaciones
no J2EE. Un recurso puede diseñarse específicamente
para J2EE o puede ser una aplicación independiente
que requiera una capa de integración.
Diferentes configuraciones de despliegue
La figura 4 nuestra una configuración común
de despliegue, en la que se incluyen
dos muros de fuego (“firewalls”) para aumentar
la seguridad. La zona entre los dos muros de fuego (llamada
la zona desmilitarizada
o DMZ) contiene sistemas que necesitan una seguridad moderada
y buen tiempo de acceso. Como los clientes externos deben
atravesar el muro de fuego para llegar a la capa de presentación,
los modelos que usan HTTP son la mejor opción para
esta configuración.
Figura
4. Diseño con cinco capas. Usualmente se utilizan dos muros
de fuego.
Aún así, es importante remarcar que se debería
adaptar el entorno a los requerimientos de cada aplicación.
Las arquitecturas complejas pueden escalar bien y ofrecer
buena disponibilidad, pero estos beneficios tienen un costo.
Por otra parte, algunos despliegues no necesitan capa de
integración y otros pueden desplegar las capas de
presentación y de negocio en una única máquina.
Por ello, se puede optar por un entorno sencillo, como el
que muestra la figura 5, que produce una configuración
fácil de manejar y sorprendentemente robusta. Con
el lenguaje Java y mainframes que son compatibles con Unix,
se puede obtener un rendimiento sorprendentemente bueno con
esta configuración. La ventaja de esta opción
es que el sistema resulta más sencillo de diseñar
y desplegar. Su inconveniente es que la lógica de
negocio no está protegida detrás de un segundo
muro de fuego.
Figura
5. Este despliegue incluye un servidor que contiene conjuntamente
las capas de presentación y de negocio. Este servidor
está dentro del muro de fuego externo pero fuera del
muro de fuego interno.
Cuando se requiere alta disponibilidad y un entorno más
escalable, se puede usar clustering. Es
importante elegir una plataforma que soporte clustering en
cada una
de las capas más importantes. Además, necesita
elegir entre clustering horizontal o vertical. Estas son
las opciones con las que cuenta:
-
Con una única CPU, puede añadir máquinas
virtuales de Java adicionales y hacer balance de carga entre
ellas.
Conforme aumenta la carga, puede añadir CPUs adicionales
y hacer clustering con múltiples máquinas virtuales
de Java usando enrutamiento de conexiones, tolerancia a fallos
y balance de carga.
Puede hacer clustering con múltiples máquinas,
con el servidor de aplicaciones proporcionando tolerancia
a fallos, clustering, balance de carga y enrutamiento de
conexiones.
Considere el escenario en la figura 6. Este escenario despliega
cuatro capas, con las capas de presentación, negocios
y recursos implementando clustering. Además, se coloca
el contenido Web estático en una caché, lo
que ahorra comunicaciones costosas y puede mejorar dramáticamente
el rendimiento. Una ventaja de este diseño es que
no tiene un único
punto de fallo, siempre que la implementación proporcione
hardware de red redundante.
Figura
6. En un despliegue con clustering se obtiene
escalabilidad añadiendo hardware
y se aumenta la disponibilidad añadiendo
redundancia.
Por supuesto, conforme el entorno se hace más complejo,
también se aumenta la complejidad de su administración.
Conforme se añaden clusters y capas, se debe trabajar
duro para que la administración del sistema global
siga siendo sencilla.
7.2. Buena práctica número 19. No
restrinja sus opciones de despliegue en tiempo de diseño
Cuando sea posible, debería mantener la máxima
flexibilidad mientras se construye el sistema. De esta manera,
si necesita cambios en el despliegue, estará preparado
para adaptarse a ellos. Esto requiere prestar una gran atención
al diseño de la aplicación, de lo que nos ocuparemos
a continuación.
Gestión del estado de sesión
Se puede usar una amplia variedad de técnicas para
manejar el estado de sesión en aplicaciones Java del
lado del servidor. Con independencia de la que use, debería
asegurarse de que soporta estado distribuido de sesión.
-
Se puede usar la API J2EE de manejo de sesión,
que es la mejor opción si el estado de sesión
es ligero. Tenga presente que esta implementación
no soporta cantidades masivas de datos, así que debería
hacer que la cantidad de datos de la sesión sea pequeña.
-
Se puede diseñar una arquitectura que asegure que
todas las comunicaciones de un único cliente
se producen siempre con el mismo servidor. Esta solución
se conoce como el bit pegajoso (“sticky
bit”).
Se pueden usar beans EJB de entidad o beans de sesión
con estado para implementar una gestión propia de
estado distribuido. Si lo hace así, debe asegurarse
de que cuenta con una estrategia para borrar periódicamente
viejas conversaciones, si ello es necesario.
Cada una de estas soluciones puede implementarse de forma
que mantenga adecuadamente un estado distribuido de sesión.
Caché
Cualquier solución de caché que desarrolle
para la aplicación debe soportar también acceso
distribuido. Por esta razón, es mejor usar patrones
de diseño y software preexistente para la mayoría
de necesidades de caché. Además, tenga presente
que el clustering puede degradar el rendimiento de la caché por
dos razones:
La invalidación distribuida de datos “sucios” implica
una sobrecarga en las comunicaciones.
Con N cachés diferentes, hay menos probabilidad de
obtener una correspondencia en la caché, excepto si
se implementa una solución “de bit pegajoso”.
Muros de fuego
Asegúrese que entiende donde va a ubicar cada capa
de la solución en relación a los muros de fuego.
Cuando sea posible, use soluciones que no limiten sus opciones
de despliegue. Por ejemplo, el cliente debería comunicarse
con el servidor de presentación estrictamente usando
HTTP o HTTPS. Incluso los clientes pesados o los applets
de Java pueden usar estos protocolos si se programa con un
poco de cuidado.
7.3. Buena práctica número 20. Cree
un entorno de desarrollo que responda
De todos los componentes que se necesitan para desarrollar
software altamente complejo, ninguno contribuye más
a la productividad del programador y a la calidad del código
resultante que el entorno de desarrollo. El tiempo invertido
en crear este entorno normalmente se recupera multiplicado
por muchas veces en el transcurso del proyecto de desarrollo.
Debería considerar los siguientes temas:
Tenga un repositorio único. Para asegurarse de que
todos los programadores trabajan con la misma base de código,
es esencial usar un sistema de gestión de código
fuente. Herramientas como PVCS, Source Safe o Perforce permiten
a los programadores asignar versión a los archivos
y compartirlos. Debería usar estas herramientas con
los archivos fuente y con todos los otros archivos de aplicación,
incluyendo archivos de construcción, de guión,
DDL’s, imágenes y documentos de diseño.
Además, asegúrese de hacer frecuentemente copia
de respaldo del repositorio.
Integre con frecuencia. La integración empeora exponencialmente
con el tiempo. Una integración continua ahorra tiempo
total de integración, permitiendo una mayor productividad
a los programadores. Incluso los proyectos más grandes
pueden integrarse diariamente.
-
Automatice por completo el proceso de construcción. Los
programadores no deberían hacer nada más
complejo que escribir un único comando para ejecutar
el proceso de construcción desde
cero. Para ello, pueden usarse herramientas de líneas
de comando como Make y Ant. El proceso de construcción
debería ser capaz de tomar una máquina completamente
limpia, descargar el código del sistema de gestión
de código fuente, construir todos los archivos necesarios,
empaquetarlos y desplegarlos, todo ello en un único
paso.
Reproduzca el entorno de producción. Uno de los problemas
más difíciles de resolver es cuando el código
se ejecuta correctamente en una máquina pero falla
en otra. Esto se debe normalmente a diferentes parámetros
de configuración en el entorno. Para evitar estos
problemas, los entornos de desarrollo deberían ser
tan similares al de producción como sea posible. Esto
se aplica a hardware, software, sistemas operativos y máquinas
virtuales de Java.
-
Cree un entorno autónomo. En las
pruebas, los programadores hacen una serie de suposiciones.
A veces, estas suposiciones
demuestran ser falsas y se desperdicia tiempo intentando
resolver problemas que realmente no existen. La corrupción
de datos es un ejemplo. Para evitar estos problemas, cada
desarrollador debería tener su propio entorno y espacio
de datos a los cuales accede en exclusiva.
-
Use un conjunto base de datos. Para probar
correctamente el código, el personal de programación
y de prueba necesita usar datos conocidos como insumo del
proceso
de pruebas. Estos datos se modifican rápidamente cuando
se ejecuta el código. Para permitir que los programadores
comiencen siempre con datos conocidos, es necesario que exista
un conjunto base de datos que se instale fácil y rápidamente
en el esquema de base de datos que usa el programador.
Como con todas las buenas prácticas, considere las
que funcionan para usted y descarte el resto. Estas sugerencias
pueden mejorar dramáticamente su experiencia de desarrollo.
8. OTROS.
8.1. Buena práctica número 21. Utilice
un framework MVC comprobado
El patrón MVC es un patrón de diseño
de vital importancia. MVC está compuesto de tres módulos
diferentes, llamados Modelo, Vista y Controlador (de ahí su
nombre). El Modelo está compuesto por el estado y
los datos que la aplicación representa. La Vista es
la interfaz de usuario que muestra información sobre
el modelo y que representa el dispositivo de entrada que
se usa para modificarlo. Finalmente, el Controlador es lo
que une a los dos anteriores. Hace corresponder las peticiones
que llegan del cliente con las acciones correspondientes
y dirige las respuestas a las vistas adecuadas. Estas funciones
de los componentes MVC pueden verse en la figura 7.
Figura
7. Interacción con el patrón MVC y dentro de él.
Puede conseguir algunos resultados espectaculares sin más
que separar la arquitectura de la aplicación entre
los tres componentes MVC. Algunos de los beneficios del patrón
MVC son:
Múltiples vistas. La aplicación puede mostrar
el estado del modelo en una variedad de formas y hacerlo
de forma dinámica.
-
Modular. El modelo y la vista están
flojamente acoplados así que pueden cambiarse
por completo de forma independiente sin necesidad de mucha
reprogramación.
Adecuado para el crecimiento. Se pueden añadir y
actualizar controladores y vistas conforme cambia el modelo.
Para implementar un framework MVC, hay una serie de opciones.
Puede implementar uno propio o puede aprovecharse de una
solución preexistente de código abierto o de
un vendedor específico, permitiendo una implementación
más rápida y una solución MVC más
robusta y mantenible.
Compruebe la calidad de nuestro desarrollo offshore.
Aurum Solutions tiene experiencia en desarrollo offshore en
J2EE y .NET de alta calidad y reducidos costos para empresas
europeas y norteamericanas. Conozca nuestro
desarrollo offshore haciendo
clic aquí o
en la página Web ../../offshore.html.
Cursos de Aurum Solutions relacionados con el tema de este
artículo:
“Buenas prácticas en arquitecturas J2EE”
“Buenas prácticas en programación en Java”
“Gestión de proyectos informáticos”
“Análisis y diseño orientado a objetos”
“Programación en n-capas”
“Programación MVC”
“Patrones de diseño”
“Persistencia para Java”
“Enterprise Javabeans”
“Servlets y JSP”
“Herramientas de pruebas para Java”
|
|