Blaapps - Servidor de Aplicaciones

Post on 12-Jun-2015

501 views 0 download

description

Blaapps es un Framework LigeroFue mi Proyecto de Fin de Carrera, y esta es la presentación con la que lo defendí.

Transcript of Blaapps - Servidor de Aplicaciones

SERVIDOR DEAPLICACIONES DISTRIBUIDAS

Víctor Jiménez Cerrada golo@capitangolo.nethttp://www.blaapps.org

Hola! Soy Víctor Jiménez Cerrada, desarrollador de BlaappsBlaapps es un framework para desarrollar apliaciones distribuidas.

Q & A

Conclusiones

Demo

Blaapps

Servidores de Aplicaciones30"

Q & A

Conclusiones

Demo

Blaapps

Servidores de Aplicaciones

Para entrar en contexto, veamos qué son los servidores de aplicaciones...

SERVIDORES DE APLICACIONES

En la actualidad existen diversos servidores de aplicaciones...

OBJETIVO: REDUCIR COSTES

Tareas Comunes:

•Persistencia

•Colas de mensajes

•Seguridad

•Conexiones

•...

Aplicación

Aplicación

Aplicación

Una empresa utiliza el servidor de aplicaciones para reducir costes de desarrollo.El servidor de aplicaciones realiza tareas comunes para varias aplicaciones.

UN POCO DE HISTORIA…

1800-19601970's 1980's 1990's

Tarjetas Perforadas

∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎ ∎

Hardware

En las primeras máquinas se utilizaban tarjetas perforadas para darle las instrucciones.

UN POCO DE HISTORIA…

1800-19601970's

1980's 1990's

Programación Estructurada

open file;while (reading not finished) { read some data; if (error) { }}process read data;

Hardware

La PE permitió dar instrucciones en un lenguaje más humano.Se sigue trabajando con la máquina.

UN POCO DE HISTORIA…

1800-19601970's

1980's 1990's

Sistemas Operativos

Hardware

open file;while (reading not finished) { read some data; if (error) { }}process read data;

S.O.

Con la difusión de los sistemas operativos el desarrollador se abstrae del Hardware.

UN POCO DE HISTORIA…

1800-1960 1970's1980's

1990's

Programación Orientada a Objetos

HardwareS.O.

La POO permite crear abstracciones aún más cercanas a la forma de pensar humana.

UN POCO DE HISTORIA…

1800-1960 1970's 1980's1990's

Frameworks

HardwareS.O.

Fra

me

wo

rk

La mayoría de las apps realizan las mismas tareas:Conexión a base de datos, gestión de las acciones del usuario...Un Framework implementa estas funciones para el desarrollador. El desarollador sólo se centra en su aplicación.

OBJETIVO: REDUCIR COSTES

Tareas Comunes:

•Persistencia

•Colas de mensajes

•Seguridad

•Conexiones

•...

Aplicación

Aplicación

Aplicación

Los servidores de aplicaciones son Frameworks.De nuevo, el objetivo es reducir costes.A parte de que se desarrolla menos código, desarrollar se hace más fácil, por tanto se necesitan menos expertos.

OBJETIVO: REDUCIR COSTES

Si mi plataforma es tan fácil de desarrollar, que hasta un mono puede aprenderla...

OBJETIVO: REDUCIR COSTES

Por el precio de un experto, puedo pagar a varios monos.

Q & A

Conclusiones

Demo

Blaapps

Servidores de Aplicaciones

Ahora hablemos de Blaapps

Muchas veces veo los Servidores de Aplicaciones como grandes dinosaurios: Grandes y pesados.Tienen muchas funcionalidades, son muy robustos y por ello son ideales para aplicaciones empresariales...

Sin embargo Blaapps, es como una rana feliz.

BLAAPPS

• Ligero

• Rápido

• Fácil de utilizar

•Modular

Es ligero y muy rápido. (Arranca en menos de 3 segundos)Es fácil de utilizar (Ahora lo veremos)Y es flexible, puede aumentar de funcionalidad mediante módulos...

BLAAPPS

BLAAPPS CORE

Sistemas mínimos:

• Cargador de Módulos

• Configuración

• Registros

•Mensajería

•MBean Server

Blaapps está formado por 4 sistemas principales...

BLAAPPS MODULES

Funcionalidades extra:

•Objetos Remotos (RMI)

• Persistencia (JPA)

De momento hay desarrollados dos módulos...

¿CÓMO SE USA?Blaapps Core

Antes hemos comentado que Blaapps es fácil de usar, veámoslo...

@Module(! name = "HiWorld",! description = "An example module",! version = @Version(revision=5) // 0.5.0.0)public class HiWorld {

! @Log ! private Logger log;

! @AfterDeployment! public void sayHello() {! ! log.info("Hello world!");! }

! ...}

Esto sería un Módulo de blaapps.

@Module(! name = "HiWorld",! description = "An example module",! version = @Version(revision=5) // 0.5.0.0)public class HiWorld {

! @Log ! private Logger log;

! @AfterDeployment! public void sayHello() {! ! log.info("Hello world!");! }

! ...}

@Module(! name = "HiWorld",! description = "An example module",! version = @Version(revision=5) // 0.5.0.0)public class HiWorld {

! @Log ! private Logger log;

! @AfterDeployment! public void sayHello() {! ! log.info("Hello world!");! }

! ...}

Inyección de dependencias

@Module(! name = "HiWorld",! description = "An example module",! version = @Version(revision=5) // 0.5.0.0)public class HiWorld {

! @Log ! private Logger log;

! @AfterDeployment! public void sayHello() {! ! log.info("Hello world!");! }

! ...}

Ciclo de vida de un módulo.

blaapps librariesblaapps librariesblaapps libraries

blaapps

HiWorld.jar

bin

conf

deploy

lib

blaapps-launcher.jar

blaapps libraries

blaapps.properties

Meteríamos esa clase en blaapps/deploy/HiWorld.jar

$ cd blaapps/bin$ java -jar blaapps-kernel-launcher.jar ../conf/

y arrancaríamos blaapps...

$ cd blaapps/bin$ java -jar blaapps-kernel-launcher.jar ../conf/Loading Libraries/opt/blaapps/bin/../lib[...]Libraries LoadedINFO [Blaapps-Core]: Starting Deployer...INFO [Blaapps-Core]: Loading Module HiWorldINFO [HiWorld]: Hello World!INFO [Blaapps-Core]: Module HiWorld LoadedINFO [Blaapps-Core]: Deployer Started

y arrancaríamos blaapps...

$ cd blaapps/bin$ java -jar blaapps-kernel-launcher.jar ../conf/Loading Libraries/opt/blaapps/bin/../lib[...]Libraries LoadedINFO [Blaapps-Core]: Starting Deployer...INFO [Blaapps-Core]: Loading Module HiWorldINFO [HiWorld]: Hello World!INFO [Blaapps-Core]: Module HiWorld LoadedINFO [Blaapps-Core]: Deployer Started.quitINFO [Blaapps-Core]: Deployer Shutdown...INFO [Blaapps-Core]: Unloading ModuleINFO [Blaapps-Core]: Module HiWorld UnloadedINFO [Blaapps-Core]: Deployer Stopped$

y arrancaríamos blaapps...

• @Module

• @Version

• @Dependency

CORE ANNOTATIONSDeployer

Tres son las anotaciones necesarias para definir la metainformación de un módulo...

Logger log = Logger.getLogger(“HiWorld”);log.info(“Hola Mundo!”);

INFO [HiWorld]: Hola Mundo!

CORE ANNOTATIONSRegistros

Se puede obtener un logger programáticamente...

@LogLogger log;log.info(“Hola Mundo!”);

INFO [HiWorld]: Hola Mundo!

CORE ANNOTATIONSRegistros

Pero Blaapps también puede crearlo por nosotros...

@Inbox("evento")private void onMessage(Message message)

@Inbox("evento")private MessageStorage inbox;

CORE ANNOTATIONSMensajería

Las colas de mensajes están formadas por dos partes: Los buzones de recepción y de envío.Los buzones de recepción se pueden crear mediante la anotación @Inbox.

MailBoxMBean mailbox = ! ! ! ! MainDeployerFactory.getServerMessageQueue();

Message message = new Message(this, true, atmnt1);

mailbox.sendMessage(“evento”, message);

CORE ANNOTATIONSMensajería

Para enviar un mensaje al servidor, utilizamos el enviador del servidor...

@Confprivate Properties conf;

• Configuración por defecto

defaults.properties

• Configuración del usuario

carpeta "conf"

CORE ANNOTATIONSConfiguración

Blaapps permite cargar la configuración de un módulo con @Conf@Conf junta la configuración por defecto de ese módulo con la definida por el usuario.

@ManagementServerprivate MBeanServer server;

public PersistenceModule() {! ObjectName persistenceName = new ObjectName(name);! server.registerMBean(this, persistenceName);}

• clase ManagementProxy

CORE ANNOTATIONSConfiguración

Blaapps inicia un MBeanServer para registrar elementos de gestión.Todos los módulos publican una interfaz de gestión.La clase ManagementProxy permite utilizar de manera fácil un MBean.

¿CÓMO SE USA?Blaapps Modules

Pasemos a ver los módulos de blaapps

MODULE ANNOTATIONSPersistencia

• JPA Annotations

@PersistenceContext@Entity

@Module( !name = "test",! ! ! ! version = @Version(revision=5),! ! ! ! description = "Testing persistence",! ! ! ! dependency = @Dependency(! ! ! ! ! ! parentName = "Blaapps-Persistence",! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! policy = DependencyPolicy.REQUIRED! ! ! ! ))public class Module01 {

! @PersistenceContext! private EntityManager em;!

Primero vamos a hablar del módulo de persistencia.Permite usar JPA en un módulo para acceder a una base de datos.Acepta las anotaciones JPA.

• JPA Annotations

@PersistenceContext@Entity

@Module( !name = "test",! ! ! ! version = @Version(revision=5),! ! ! ! description = "Testing persistence",! ! ! ! dependency = @Dependency(! ! ! ! ! ! parentName = "Blaapps-Persistence",! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! policy = DependencyPolicy.REQUIRED! ! ! ! ))public class Module01 {

! @PersistenceContext! private EntityManager em;!

Persistencia

Para poder usar las clases del módulo de persistencia, tenemos que indicarlo como dependencia.

MODULE ANNOTATIONSObjetos Remotos

• RMI Objects

@BStateless@BRemote

El módulo de objetos remotos ofrece un mecanismo sencillo de publicación de clases RMI

@Module(! name="test-remote-1",! ! ! ! version=@Version(revision=5),! ! ! ! description = "Testing Remote",! ! ! ! dependency = @Dependency(! ! ! ! ! ! ! parentName = "Blaapps-Remote",! ! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! ! policy = DependencyPolicy.REQUIRED! ! ! ! ))public class Module01 {!! ! ...

Objetos Remotos

En el módulo en el que definamos los objetos RMI, tenemos que indicar Blaapps-remote como dependencia.

public interface DummyRemote! ! ! ! ! ! ! ! extends Remote, Serializable {

! int getFive() throws RemoteException;

}

@BStateless(DummyRemote.class)public class DummyRemoteObject implements DummyRemote {

! @Override! public int getFive(){! ! return 5;! }!

}

Objetos Remotos

En este módulo definimos una interfaz pública y una clase que la implementa.La clase debe ser compatible con RMI.Marcamos con @BStateless el interfaz público que implementa.

@Module(! name = "test-remote-2",! ! ! ! version = @Version(revision=5),! ! ! ! description = "Testing Remote",! ! ! ! dependency = {! ! ! ! ! ! @Dependency(! ! ! ! ! ! ! ! parentName = "Blaapps-Remote",! ! ! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! ! ! policy = DependencyPolicy.REQUIRED),! ! ! ! ! ! @Dependency(! ! ! ! ! ! ! ! parentName = "test-remote-1",! ! ! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! ! ! policy = DependencyPolicy.REQUIRED)! ! ! ! })public class Module02 {

! @BRemote("test-remote-1")! private DummyRemote dummy;

! @AfterDeployment! public void testRemote(){! ! if (dummy.getFive() == 5) {! ! ! // Remote Module Works

! ! }! }

Objetos Remotos

En otro módulo, donde queramos usar el objeto remoto recién definido,marcamos como dependencias "Blaapps-remote" y el módulo anterior.

Objetos Remotos

@Module(! name = "test-remote-2",! ! ! ! version = @Version(revision=5),! ! ! ! description = "Testing Remote",! ! ! ! dependency = {! ! ! ! ! ! @Dependency(! ! ! ! ! ! ! ! parentName = "Blaapps-Remote",! ! ! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! ! ! policy = DependencyPolicy.REQUIRED),! ! ! ! ! ! @Dependency(! ! ! ! ! ! ! ! parentName = "test-remote-1",! ! ! ! ! ! ! ! version = @Version(revision=5),! ! ! ! ! ! ! ! comparator = Comparation.EQUAL,! ! ! ! ! ! ! ! policy = DependencyPolicy.REQUIRED)! ! ! ! })public class Module02 {

! @BRemote("test-remote-1")! private DummyRemote dummy;

! @AfterDeployment! public void testRemote(){! ! if (dummy.getFive() == 5) {! ! ! // Remote Module Works

! ! }! }

Con la anotación @BRemote inyectamos una referencia a un objeto remoto

3 RETOS

• Aislamiento

• Inyección de Dependencias

•Nuevas Instancias

Durante el desarrollo de blaapps el equipo de desarrollo se ha encontrado con 3 grandes retos.El primero de ellos fue el asegurar el aislamiento entre módulos.

AISLAMIENTOProblema

Usuarios Jabber

collections-commons-3.2.1.jar

collections-commons-2.1.1.jar

Si dos módulos utilizan distintas versiones de la misma librería o clase,se tiene que asegurar el que cada módulo utilice su versión.

AISLAMIENTOClassLoaders

Usuarios JabberUsuarios ClassLoader Jabber ClassLoader

Blaapps ClassLoader

Bootstrap ClassLoader

lib lib

Una forma de solucionarlo es encerrando a cada módulo en un hilo con su propio class loader.

AISLAMIENTOClassLoaders

Usuarios JabberUsuarios ClassLoader Jabber ClassLoader

Blaapps ClassLoader

Bootstrap ClassLoader

lib lib

lib

Problema: ¿Qué pasa si blaapps utiliza una versión diferente de la librería?

AISLAMIENTOClassLoaders

Usuarios JabberUsuarios ClassLoader Jabber ClassLoader

Blaapps ClassLoader

Bootstrap ClassLoader

lib lib

lib

Problema: ¿Qué pasa si blaapps utiliza una versión diferente de la librería?

AISLAMIENTOClassLoaders

Usuarios JabberUsuarios ClassLoader Jabber ClassLoader

Blaapps ClassLoader

Bootstrap ClassLoader

lib lib

lib

Problema: ¿Qué pasa si blaapps utiliza una versión diferente de la librería?

AISLAMIENTOClassLoaders

Usuarios JabberUsuarios ClassLoader Jabber ClassLoader

Blaapps ClassLoader

Bootstrap ClassLoader

lib lib

lib

Problema: ¿Qué pasa si blaapps utiliza una versión diferente de la librería?

AISLAMIENTOIsolationClassLoader

Usuarios JabberUsuarios IsolationClassLoader

Jabber IsolationClassLoader

Blaapps IsolationClassLoader

Bootstrap ClassLoader

lib lib

lib

Solución: Creamos un classloader propio que invierta el orden en el que se buscan las clases.

AISLAMIENTOIsolationClassLoader

Usuarios JabberUsuarios IsolationClassLoader

Jabber IsolationClassLoader

Blaapps IsolationClassLoader

Bootstrap ClassLoader

lib lib

lib

Solución: Creamos un classloader propio que invierta el orden en el que se buscan las clases.

AISLAMIENTOIsolationClassLoader

Usuarios JabberUsuarios IsolationClassLoader

Jabber IsolationClassLoader

Blaapps IsolationClassLoader

Bootstrap ClassLoader

lib lib

lib

Solución: Creamos un classloader propio que invierta el orden en el que se buscan las clases.

AISLAMIENTOIsolationClassLoader

Usuarios

Permisos

Usuarios IsolationClassLoader

Permisos IsolationClassLoader

Blaapps IsolationClassLoader

Bootstrap ClassLoader

Usuarios

UsuariosPermisos

Además, si un módulo depende de otro, su classloader mantiene sus clases, y una copia de las clases de otro módulo.Se tiene que forzar a los módulos a interactuar con sus interfaces públicos.Problema: ¿Qué pasa si se tiene que usar una misma versión de una clase en dos módulos?

AISLAMIENTOSharedClassLoader

Usuarios

Permisos

Usuarios IsolationClassLoader

Permisos IsolationClassLoader

Usuarios

UsuariosPermisos

Shared ClassesUsuarios Shared Clases Permisos Shared Clases

Solución: Se mantiene un espacio de clases compartidas, donde el desarrollador puede publicar clases.Las clases compartidas sólo se cargan una vez en memoria.

AISLAMIENTOSharedClassLoader

Usuarios

Permisos

Usuarios IsolationClassLoader

Permisos IsolationClassLoader

Usuarios

UsuariosPermisos

Shared ClassesUsuarios Shared Clases Permisos Shared Clases

Solución: Se mantiene un espacio de clases compartidas, donde el desarrollador puede publicar clases.Las clases compartidas sólo se cargan una vez en memoria.

AISLAMIENTOSharedClassLoader

Usuarios

Permisos

Usuarios IsolationClassLoader

Permisos IsolationClassLoader

Usuarios

UsuariosPermisos

Shared ClassesUsuarios Shared Clases Permisos Shared Clases

Solución: Se mantiene un espacio de clases compartidas, donde el desarrollador puede publicar clases.Las clases compartidas sólo se cargan una vez en memoria.

EntityManager em = new EntityManager(?????);

• ¿Quién gestiona la configuración?

INYECCIÓN DE DEPENDENCIAS

Si el desarrollador es el responsable de crear conexiones a la base de datos, también tiene que gestionar la configuración.Blaapps se encarga de crear conexiones a datos, pero, ¿cómo obtiene el desarrollador una?Uno de los retos de Blaapps ha sido facilitar la creación de este tipo de objetos.

EntityManager em = Persistence.getEM();

INYECCIÓN DE DEPENDENCIAS

Inversión del control

Una Factoría.Problema: Genera código acoplado.

EntityManager em;

public void setEm(EntityManager em) {! this.em = em;}

INYECCIÓN DE DEPENDENCIAS

Inversión del control

Inversión de control.Problema: ¿Cómo sabe Blaapps que tiene que inyectar?

@PersistenceContextEntityManager em;

INYECCIÓN DE DEPENDENCIAS

Programación Orientada a Aspectos

Inyección de dependencias -> POAProblema: ¿Cómo hacer un set a ese campo?

for (Field field : clazz.getDeclaredFields()) {! if (! ! field.isAnnotationPresent(PersistenceContext.class)!&&! ! EntityManager.class.isAssignableFrom(field.getType())! ) {! ! field.setAccessible(true);! ! field.set(obj, createEntityManager());! }}

INYECCIÓN DE DEPENDENCIAS

API Reflection

Solución: API Reflection

NUEVAS INSTANCIASNotificando clases cargadas

ClassLoaderEjecuciónloadClass()

lib.jar

Blaapps necesita saber cuándo se cargan nuevas clases, y se crean nuevos objetos.De esta manera, registra componentes e inyecta campos.Blaapps sabe cuándo se carga una clase, se lo chiva el ClassLoader.El ClassLoader manda un mensaje cada vez que se carga una clase.

NUEVAS INSTANCIASNotificando clases cargadas

ClassLoaderEjecuciónloadClass()

lib.jar

MessageQueue

classLoaded()

Blaapps necesita saber cuándo se cargan nuevas clases, y se crean nuevos objetos.De esta manera, registra componentes e inyecta campos.Blaapps sabe cuándo se carga una clase, se lo chiva el ClassLoader.El ClassLoader manda un mensaje cada vez que se carga una clase.

NUEVAS INSTANCIASNotificando clases cargadas

ClassLoaderEjecuciónloadClass()

lib.jar

MessageQueue

classLoaded()

Deployer Deployer Deployer

Blaapps necesita saber cuándo se cargan nuevas clases, y se crean nuevos objetos.De esta manera, registra componentes e inyecta campos.Blaapps sabe cuándo se carga una clase, se lo chiva el ClassLoader.El ClassLoader manda un mensaje cada vez que se carga una clase.

NUEVAS INSTANCIAS

?Notificando nuevas instancias

Pero... ¿Cómo sabemos cuándo se crea una instancia de un Objeto?No hay ninguna forma de saberlo.Bueno, una sí, si nos lo dice el propio objeto...

NUEVAS INSTANCIASJavassist

ClassLoaderEjecuciónloadClass()

lib.jar

public class Class {! public Class(){

! }}

Javassist

inject()

Code

MessageQueue

newInsance()

En lugar de cargar en memoria la clase directamente, usaremos javassist.Javassist es una librería que nos permite alterar los bytecodes de una clase.Cada vez que se carga una clase, se añade un código al principio constructor.Cuando se ejecuta, se lanza una notificación de que se ha creado la instancia.

NUEVAS INSTANCIASJavassist

ClassLoaderEjecuciónloadClass()

lib.jar

public class Class {! public Class(){

! }}

Javassist

inject()Code

En lugar de cargar en memoria la clase directamente, usaremos javassist.Javassist es una librería que nos permite alterar los bytecodes de una clase.Cada vez que se carga una clase, se añade un código al principio constructor.Cuando se ejecuta, se lanza una notificación de que se ha creado la instancia.

Q & A

Conclusiones

Demo

Blaapps

Servidores de Aplicaciones

Demo T

ime!

Q & A

Conclusiones

Demo

Blaapps

Servidores de Aplicaciones

LO APRENDIDO

• Funcionamiento Interior de Java

• ClassLoaders

• Threads

• Programación orientada a Aspectos

• Integración continua

• Maven, JUnit, Bitten, Trac

FUTURO

• Estabilidad

• Funcionalidad

• Comunidad

• α → β → RC → GA

• Pruebas de unidad

• Librerías externas

FUTUROEstabilidad

Actualmente se considera que blaapps está en estado Alpha.Se plantea pasar a Beta en la siguiente versión.

• Escritorio

•Web

• ¿Comunidad?

FUTUROFuncionalidad

La funcionalidad futura pasará por ampliar horizontes.Facilitar el desarrollo de todo tipo de aplicaciones. Servidor, web y Escritorio.Pero será la comunidad, aquellos que usen y desarrollen blaapps, los que decidan por dónde irá el proyecto.

FUTUROComunidad

http://www.blaapps.org

La comunidad ya dispone de una página web donde colaborar.

BLAAPPS

•Modular

• Ligero

• Rápido

• Fácil de utilizar

Blaapps es ligero y flexible. Y además utiliza tecnologías estándar.Migrar de Blaapps a un servidor mayor no es problema.Modificar Blapps para que escale no es problema.En definitiva, es ideal para proyectos que empiezan. Crea algo muy rápido, y luego hazlo crecer.

BLAAPPS

•Modular

• Ligero

• Rápido

• Fácil de utilizar

STARTUPS

Blaapps es ligero y flexible. Y además utiliza tecnologías estándar.Migrar de Blaapps a un servidor mayor no es problema.Modificar Blapps para que escale no es problema.En definitiva, es ideal para proyectos que empiezan. Crea algo muy rápido, y luego hazlo crecer.

Víctor Jiménez Cerrada golo@capitangolo.nethttp://www.blaapps.org

SERVIDOR DE APLICACIONES DISTRIBUIDAS

(BLAAPPS)

¡GRACIAS!