Contenido


Construya una aplicación simple de juegos de palabras usando Cloudant en IBM Cloud

Comments

IBM Cloud es una nueva plataforma abierta para desarrollar y desplegar aplicaciones de web y móviles. En este artículo, lo llevaré de la mano a través de los pasos para crear una simple aplicación del juego GuesstheWord (Adivina la Palabra) usando IBM Cloud y su ambiente de desarrollo de nube: DevOps Services. Empezará desde cero y terminará con un juego simple que puede jugar en un navegador de web con código de servidor corriendo en la nube.

Al haber concluido los pasos en este artículo, estará listo para desarrollar sus propias aplicaciones IBM Cloud de cualquier tamaño.

Aunque esta aplicación es simple, cubriré aspectos que son importantes al desarrollar aplicaciones más grandes, tales como establecer un buen ambiente de desarrollo para permitir la depuración local. Mi meta es llevarlo de la mano a través del desarrollo de una pequeña aplicación IBM Cloud usando un enfoque que también sea aplicable al desarrollo de aplicaciones IBM Cloud grandes. Al haber concluido los pasos en este artículo, estará listo para desarrollar sus propias aplicaciones IBM Cloud de cualquier tamaño.

Corra la aplicaciónObtenga el código

Qué necesitará para su aplicación

Para continuar, necesitará una cuenta de IBM Cloud y una cuenta de DevOps Services. Así que si no lo ha hecho aún, cree estas cuentas ahora. También, si esta es la primera vez que ha escuchado acerca de IBM Cloud, quizá quiera leer esta corta introducción.

Al embarcarse en un proyecto de desarrollo, es importante elegir las tecnologías correctas. IBM Cloud da soporte a una multitud de tecnologías para desarrollar aplicaciones. De hecho, esta flexibilidad es una de las principales fortalezas de la plataforma porque le permite elegir cuáles son las tecnologías que mejor se adaptan a las aplicaciones que usted quiere desarrollar. Para nuestro juego Guess-the-Word (Adivina la Palabra), usaremos lo siguiente:

  • Node.js— Para el código del lado del servidor, usaremos Node.js. Los servidores de Web que se implementan en Node.js arrancan rápidamente y son fáciles de desarrollar y depurar localmente. También puede ser útil usar el mismo lenguaje, tal como JavaScript, tanto para el código del servidor como del cliente. También usaremos el framework Express con Node.js porque proporciona una funcionalidad útil al implementar el servidor web.
  • Cloudant— Para los datos de servidores persistentes (las puntuaciones de los mejores juegos) usaremos una base de datos Cloudant. Una base de datos NoSQL como Cloudant es fácil de usar con los datos codificados de JavaScript y JSON.
  • HTML, CSS y JavaScript— Se implementará el UI del juego usando HTML, CSS y JavaScript. Con el soporte para HTML5 y CSS3 en los navegadores de web modernos, esta es una elección natural porque permite que nuestro juego pueda correrse en teléfonos y tabletas, así como también en computadoras.
  • Bootstrap y JQuery— También usaremos frameworks Bootstrap y JQuery JavaScript, que proporcionan una buena funcionalidad para el desarrollo de UI de web.
  • Jade— Para ahorrarnos cierta cantidad de escritura, usaremos un lenguaje de plantilla para nuestras páginas HTML. Hay varios lenguajes de plantilla disponibles para Node.js. Yo me decidí por Jade porque a menudo se usa con el framework Express.

Una vez tomadas estas decisiones estamos listos para empezar a codificar.

Paso 1. Escriba el código del servidor

  1. Empecemos por implementar la parte núcleo del servidor Node.js para que podamos probarlo antes de implementar el UI. Podríamos usar Eclipse para la codificación, pero al momento de la escritura, el soporte para Node.js en Eclipse sigue siendo un tanto cuanto básico, especialmente en lo que respecta a la depuración. Por lo que usaremos un utilitario denominado node-inspector para depurar nuestro código de servidor Node.js. Siéntase en la libertad de usar su editor de texto favorito para el código a continuación:
     /** * Server for the GuessTheWord app */ var express = require('express'); var app = express(); var http = require('http'); var host = "localhost"; var port = 3030; // Set path to Jade template directory app.set('views', __dirname + '/views'); // Set path to JavaScript files app.set('js', __dirname + '/js'); // Set path to CSS files app.set('css', __dirname + '/css'); // Set path to image files app.set('images', __dirname + '/images'); // Set path to sound files app.set('sounds', __dirname + '/sounds'); // Set path to static files app.use(express.static(__dirname + '/public')); // Bind the root '/' URL to the hiscore page app.get('/', function(req, res){ res.render('hiscores.jade', {title: 'Hiscores'}); }); // Bind the '/play' URL to the main game page app.get('/play', function(req, res){ res.render('main.jade', {title: 'Guess the Word'}); }); var server = app.listen(port, function() { console.log('Server running on port %d on host %s', server.address().port, host); }); process.on('exit', function() { console.log('Server is shutting down!'); });
  2. Guarde este código en el archivo denominado server.js, después cree una carpeta denominada views para contener los dos archivos Jade (hiscores.jade y main.jade), a los que se les hace referencia en el código superior y que se muestran abajo. Estos archivos Jade definen los contenidos de las dos páginas web que usa el juego.
  3. El archivo hiscores.jade muestra las puntuaciones altas. Esta es la página inicial del juego y se liga al URL de la raíz '/'.
     doctype html html(lang="en") head title= title link(rel="stylesheet", href="css/bootstrap.css", type="text/css") link(rel="stylesheet", href="css/hiscores.css", type="text/css") body(style="background-image:url(/images/background.jpg)") div(class="container") h1(id="header") High Scores table(id="hiscore_table") tr() th(class="table-header") Score th(class="table-header") Name th(class="table-header") Date div(style="padding-top:30px;") a(class="btn btn-default", href="/play") Play! script(src="js/jquery.js", type="text/javascript") script(src="js/bootstrap.js", type="text/javascript") script(src="js/hiscores.js", type="text/javascript")
  4. El archivo principal de .jade es la página donde se juega el juego. Se liga al URL '/play'.
     doctype html html(lang="en") head title= title link(rel="stylesheet", href="css/bootstrap.css", type="text/css") link(rel="stylesheet", href="css/main.css", type="text/css") body(style="background-image:url(/images/background.jpg)") div(class="container") h1(class="game-text") Guess the secret word! div(class="row") div(class="col-xs-8") div(id="word-description") div(class="col-xs-4") div(id="score") Score: div(class="row") div(class="col-xs-8") div(class="word-area") table() tr() div(class="col-xs-4") div(id="power") Power: div(class="row") div(class="col-xs-8") div(id="help-text", class="game-text") Click on a ?-box above and type a letter div(class="col-xs-4") div(class="row") div(class="col-xs-12") button(id="skip-button" class="btn btn-info btn-xs") Skip this word div(class="col-xs-12") button(id="help-letter-button" class="btn btn-info btn-xs") Give me a letter audio(id="tick-sound", src="sounds/Tick.mp3") audio(id="skip-sound", src="sounds/Falcon.mp3") audio(id="applause-sound", src="sounds/Applause.mp3") script(src="js/jquery.js", type="text/javascript") script(src="js/bootstrap.js", type="text/javascript") script(src="js/main.js", type="text/javascript")

Como podrá ver, estos archivos Jade hacen referencia a muchos archivos estáticos, tales como los archivos CSS y JavaScript. Agregaremos esos posteriormente, pero primero, corramos la prueba de lo que tenemos hasta ahora.

Paso 2. Corra y depure el código del servidor

  1. Si aún no ha instalado Node.js localmente, ahora es el momento de hacerlo. Descárguelo de Nodejs.org y siga las instrucciones. Instalamos Node.js localmente para poder correr y depurar el código del servidor localmente antes de desplegarlo a IBM Cloud.
  2. También necesita instalar los módulos Express y Jade para Node.js. La forma más sencilla de hacerlo es primero crear un archivo package.json en la carpeta raíz que especifica las dependencias a estas bibliotecas.
     { "name": "GuessTheWord", "version": "0.0.1", "description": "GuessTheWord package.json file", "dependencies": { "express": ">=3.4.7 <4", "jade": ">=1.1.4" }, "engines": { "node": ">=0.10.0" }, "repository": {} }

    Ahora puede instalar Express y Jade abriendo un indicador de la línea de comando en la carpeta raíz e introduciendo el siguiente comando:

     > npm install

    Para cuando lea esto, pueden haber versiones de Express y Jade disponibles que sean versiones más nuevas que las versiones que se muestran arriba. Desde luego puede usar mejor estas versiones. Siempre y cuando las dependencias de la aplicación se mencionen en package.json, se usarán las mismas versiones de las bibliotecas cuando las desarrolle localmente y las despliegue posteriormente a IBM Cloud. Esto es bueno porque se evitan las sorpresas provocadas por las diferentes versiones de biblioteca que se usan en diferentes ambientes.

  3. Haga una primera corrida de su aplicación con el siguiente comando:
     > node --debug server.js
  4. Abra un navegador de web y vaya a http://localhost:3030/. Image shows http://localhost:3030
  5. Antes de proceder al desarrollo del juego, asegurémonos de que puede depurar la aplicación. Primero, instalamos el inspector de nodo. Abriremos una nueva línea de comando y escribamos el siguiente comando:
     > npm install -g node-inspector
  6. Dado que lanzamos la aplicación con el indicador --debug, ahora podemos arrancar el inspector de nodo de esta forma:
     > node-debug server.js

    Esto abre un depurador JavaScript en su navegador de web preestablecido, que deberá ser ya sea Chrome u Opera. Si ya tiene otro navegador de web de manera predeterminada, puede usar mejor el siguiente comando:

     > node-inspector

    Abra http://127.0.0.1:8080/debug?port=5858 en Chrome u Opera para empezar a depurar. Si no ha usado este depurador con anterioridad, quizá quiera leer esta introducción.

Paso 3. Implemente el código de cliente

  1. Ahora creemos los archivos faltantes a los que hacen referencia los archivos Jade. Se pueden descargar todos los archivos binarios (JPG y MP3) del proyecto concluido de GuessTheWord (Advina la Palabra) de DevOps Services, que contiene todos los archivos a los que se hace referencia en este artículo. La forma más sencilla de descargarlos es ir a la pestaña EDIT CODE, dar un clic derecho en la carpeta que lo contiene y Exportar los contenidos como un archivo zip para la descarga. Image shows creating the missing files
    Image shows creating the missing files

    Por supuesto también puede elegir crear sus propias imágenes y sonidos para darle un toque más personal al juego.

  2. Los siguientes archivos constituyen las bibliotecas JQuery y Bootstrap JavaScript. También pueden descargarse del proyecto GuessTheWord DevOps Services, o de Internet.
    1. Descargue a la carpeta public/js:
      • jquery.js (la última versión de la biblioteca JQuery JavaScript)
      • bootstrap.js (la última versión de la biblioteca Bootstrap JavaScript)
    2. Descargue a la carpeta public/css:
      • bootstrap.css (la última versión del archivo CSS para Bootstrap)
  3. Ahora cree los siguientes dos archivos CSS, que definen los estilos utilizados en el juego:
  4. Corra la aplicación localmente de nuevo para ver que entren en vigor estos cambios. Vaya a la carpeta raíz de la aplicación (asegurándose que sea la carpeta del repositorio Git local a la que está conectada), después corra:
     > node-debug server.js

    El juego ahora deberá verse mucho mejor que antes:

    Image shows game creation progress
  5. Posteriormente, vamos a escribir el JavaScript del extremo del cliente que implementa la lógica del juego. Vamos a esperar un poco antes de implementar hiscores.js dado que el poblar la lista de las puntuaciones altas requiere de una base de datos, algo que agregaremos posteriormente. En lugar de eso cree un archivo public/js/main.js con los contenidos que se encuentran en este fragmento de código, que contiene básicamente toda la lógica de juego. Se encarga de obtener una palabra en inglés aleatoria con una descripción del servidor, manejando información del teclado por el jugador, puntuación de conteo, poder de administración, etc.

    Como podrá ver, la función getNewSecretWord() invoca un servicio /randomword en el servidor web para obtener la palabra secreta.

  6. Vamos a implementar este servicio agregándole el siguiente código al server.js (después de las declaraciones de las variables iniciales).
     /** * Lookup the word in the wordnik online dictionary and return a description for it. * @param word {String} Word to lookup description for * @param cb_description {function} Callback with the description as argument. * If the word was not found in the dictionary the description is empty. */ function wordLookup(word, cb_description) { http.request( { host: "api.wordnik.com", path: "/v4/word.json/" + word + "/definitions?limit=1&api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5" }, function (res) { var str = ''; res.on('data', function(d) { str += d; }); res.on('end', function() { var wordList = JSON.parse(str); cb_description(wordList.length > 0 ? wordList[0].text : ""); }); }).end(); } app.get('/randomword', function(request, response) { http.request( { host: "api.wordnik.com", path: "/v4/words.json/randomWord?hasDictionaryDef=false&minCorpusCount=0&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=5&maxLength=-1&api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5" }, function (res) { var str = ''; res.on('data', function(d) { str += d; }); res.on('end', function() { var wordObj = JSON.parse(str); wordLookup(wordObj.word, function(descr) { var randomWordObj = { word : wordObj.word, description : descr }; response.send(JSON.stringify(randomWordObj)); }); }); }).end(); });

    Este código liga el URL /randomword al código que usa Wordnik.com, un diccionario en línea en inglés, para obtener una palabra aleatoria. Después llama a wordLookup(), que hace otra llamada a Wordnik API para poder obtener una descripción de esa palabra. Finalmente, la palabra secreta y su descripción se codifican como JSON y se devuelven como respuesta a la solicitud de HTTP.

    Nota: La llave API que se incluye en el fragmento de código anterior es para una cuenta gratuita compartida por muchas personas, por lo que sólo puede usarse en una muy pequeña escala. Para evitar esta restricción, puede registrarse en Wordnik y obtener su propia llave API.

  7. En este punto, pudiera querer correr unas cuantas sesiones de depuración localmente para ir paso por paso en el código del extremo del cliente y del servidor para verificar que el juego funcione como se espera. Image shows verifying that the game works as expected
    Image shows verifying that the game works as expected

    El JavaScript del lado del cliente se depura usando el depurador Chrome integrado. Se depura el servidor del lado del servidor JavaScript usando el inspector de nodo como se describe anteriormente. Note que el inspector de nodo usa el mismo depurador Chrome para la depuración del lado del servidor de Node.js JavaScript.

    Si fuera a escribir todo el código JavaScript anterior a mano, función por función, probablemente haría una depuración extensiva localmente.-->

Paso 4. Cree un proyecto DevOps Services

Ahora que tenemos una aplicación en operación que podemos depurar localmente, nuestro siguiente paso es guardar lo que hemos escrito hasta ahora en el repositorio DevOps Services. Esto proporciona un número de beneficios, incluyendo:

  • El código se almacena en la nube, que es más segura que la computadora local.
  • Otras personas pueden contribuir al desarrollo de la aplicación.
  • Podemos permitir el despliegue automático a IBM Cloud.
  1. Inicie una sesión en DevOps Services y haga clic en Start coding para crear un proyecto para su aplicación. La elección entre Jazz SCM y Git SCM es arbitraria y dependerá típicamente de con qué sistema SCM está familiarizado. Elegiremos un repositorio Git para nuestro proyecto y marcaremos el cuadro Deploy to IBM Cloud dado que estaremos desplegando nuestra aplicación a IBM Cloud. Seleccione una organización y espacio IBM Cloud, después haga clic en CREATE. Image shows creating the project
    Image shows creating the project
  2. Su nuevo proyecto inicialmente estará vacío, excepto por un par de archivos previamente definidos. Para agregar su código al proyecto, haga clic en EDIT CODE, después arrastre/suelte los archivos de su sistema de archivos a la jerarquía de archivos del proyecto (el árbol que se muestra a la izquierda).

    Si escribió el código usando Eclipse, puede arrastrar/soltar los archivos directamente de Eclipse Project Explorer. Note que después debe seleccionar los archivos y carpetas individuales bajo el proyecto Eclipse (no el propio proyecto) y después arrastrarlos/soltarlos al nodo superior (marcado en rojo) en la jerarquía de archivos de proyecto. También note que Eclipse oculta algunos archivos, por ejemplo, el archivo .project, por lo que aún tendrá que arrastrar/soltar algunos archivos de su sistema de archivos.

    Su jerarquía de archivos de proyecto ahora deberá mostrar todos los archivos de su aplicación.

    Note que a pesar de que usted acaba de copiar los archivos de su computadora local al proyecto DevOps Services, los cambios que hizo aún no están comprometidos no se han enviado al repositorio Git. Esto significa que nadie más puede ver los archivos que usted agregó. Piense en la jerarquía de archivos que se muestra bajo su proyecto de DevOps Services como su área de trabajo personal, esto es muy parecido a su sistema de archivos local excepto que se guarda en la nube.

  3. Si da un clic en el icono del repositorio verá el número de cambios comprometidos para cada archivo que agregó. Los archivos se muestran como "Unstaged,"que es la terminología Git para un cambio que no se ha comprometido aún al repositorio. Image shows repository icon
  4. Para comprometer los cambios, ejecute el comando Stage the change en cada archivo: Image shows stage button

    Esto pasa los archivos de Unstaged a Staged. Todos los cambios que se muestran bajo Staged se comprometerán como un sólo cambio establecido cuando hace clic en COMMIT. En este caso, queremos agregar todos los archivos en un sólo conjunto de cambios, pero posteriormente puede querer comprometer algunos cambios como un conjunto de cambios y otros cambios como otro conjunto de cambios. Cada conjunto de cambios deberá agrupar los cambios que pertenecen lógicamente unos con otros.

    Su Commit message en el diálogo de Commit deberá describir el conjunto de cambios y quizá proporcionar una razón para el cambio.

    Image shows commit
    Image shows commit
  5. Cuando hace clic en SUBMIT, el conjunto de cambios se compromete a Git y aparece como un sólo conjunto de cambios bajo la sección Commits. Image shows committed changes, not yet pushed
    Image shows committed changes, not yet pushed
  6. El paso final es mandar (push) este conjunto de cambios a la rama maestra para que otros puedan tomarla desde allí. Haga clic en PUSH, después haga clic en OK para mandar sus cambios. Image shows pushed changes
  7. En este punto, su copia local del código es redundante y debe considerar borrarla. Si continua desarrollándolo en su copia local, recuerde subir todos los archivos modificados a su proyecto de DevOps Services y entregar los cambios de la misma forma que lo hizo. Es posible trabajar de esta forma pero puede ser confuso y un poco engorroso.

    Un enfoque más práctico es el de ya sea abandonar totalmente el desarrollo local y editar el código usando el editor de web en DevOps Services, o establecer un repositorio de Git local conectado al repositorio Git de DevOps Services. Yo elegí la segunda alternativa porque queremos ser capaces de desarrollarlas y depurarlas localmente, algo que aún no es posible usando el editor de web de DevOps Services.

    Hay un par de formas para establecer un repositorio Git local conectado al repositorio Git de DevOps Services. Si usa un IDE tal como Eclipse o Visual Studio, puede usar el plugin de Git para estos IDEs para importar el repositorio de Git de DevOps Services al IDE. Si lo desarrolla en un ambiente donde no se cuenta con un plugin Git, puede usar el Git de la línea de comando. En cualquier caso, usted necesita el URL para el repositorio Git de DevOps Services. Usted puede obtener este URL de la página de visión general de su proyecto de DevOps Services.

    Para llegar a la página de la visión general del proyecto de la pestaña EDIT CODE, haga clic en el vínculo del proyecto de la esquina superior izquierda.

    Image shows project overview page

    Después haga clic en el vínculo Git URL:

    Image shows Git URL
    Image shows Git URL
  8. Una vez que ha clonado este URL en su repositorio Git local, puede continuar desarrollando la aplicación globalmente y comprometer los cambios directamente al repositorio Git de DevOps Services sin tener que pasar por la interfaz de web de DevOps Services. Si usa el plugin de Eclipse y de EGit, su vista de proyecto tendrá una apariencia parecida a la pantalla que se muestra abajo. Si su Eclipse no contiene ya el plugin de EGit, es fácil de instalar. Si usa EGit, por primera vez consulte la Guía del Usuario .Image shows an Eclipse project showing the files of the application stored in a Git repository
    Image shows an Eclipse project showing the files of the application stored in a Git repository

Paso 5. Despliegue su aplicación a IBM Cloud

En este punto, es una buena idea hacer un primer despliegue a IBM Cloud, sólo para asegurar que este está funcionando antes de continuar desarrollando el juego.

  1. El despliegue se controla por un archivo denominado manifest.yml, por lo que necesitamos crear este archivo en la carpeta raíz de su aplicación.
     --- applications: - name: GuessTheWord framework: node runtime: node08 memory: 64M instances: 1 host: GuessTheWord path: . command: node server.js

    Estas configuraciones le dicen a IBM Cloud como desplegar nuestra aplicación. Por ejemplo, especificamos el tiempo de ejecución (Node.js), la cantidad de la memoria por reservar para su aplicación y el nombre del host que queremos usar en el URL de su aplicación desplegada. Note que el nombre del host deberá ser único en su género globalmente, por lo que necesita elegir un nombre de host distinto a "GuessTheWord."

  2. Ya sea que cree este archivo en el editor de web DevOps Services o en su ambiente de desarrollo local, no olvide empujar el nuevo archivo al repositorio Git de DevOps Services.
  3. Para empezar un despliegue, haga clic en el botón BUILD & DEPLOY en su proyecto de DevOps Services. Image shows the Build & Deploy tab
    Image shows the Build & Deploy tab

    Después alterne el interruptor en la parte superior de la página de OFF a SIMPLE para desplegar a IBM Cloud.

    Image shows auto-deploy buttons
  4. Tan pronto como haga esto, DevOps Services intenta desplegar su aplicación a IBM Cloud. Image shows simple auto-deploy enabled
    Image shows simple auto-deploy enabled

    También, se tendrá un nuevo despliegue automáticamente cada vez que alguien actualice los cambios al repositorio del Git de DevOps Services. Esto es conveniente porque nos permite siempre tener acceso a la última versión desplegada de la aplicación para correr pruebas, por ejemplo.

  5. Después de 30 segundos aproximadamente, usted deberá ver que se despliegue la aplicación sin errores. Image shows auto-deploy message
    Image shows auto-deploy message
  6. Para acceder a la aplicación desplegada en IBM Cloud, haga clic en el vínculo arriba de la lista. Image shows link to deployed application
    Image shows link to deployed application

Paso 6. Diagnostique los problemas en el despliegue de IBM Cloud

Cuando intente acceder a su aplicación desplegada probablemente verá el siguiente mensaje:

404 Not Found: Requested route ('guesstheword.mybluemix.net') does not exist.

Esto no parece estar bien. Obviamente hay un problema en alguna parte y parece estar relacionado con la aplicación que corre en IBM Cloud dado que corrió bien localmente.

Esto ilustra un punto importante: Se puede desplegar exitosamente una aplicación pero aún no estar disponible cuando se trate de acceder a la misma. El indicador verde de estatus y un resultado OK en la lista de Recent Auto-Deployments sólo significa que la aplicación se desplegó exitosamente y se inició. Sin embargo, puede, por ejemplo, terminar poco tiempo después de empezar y no estar disponible cuando se trata de acceder a su URL de IBM Cloud.

Para resolver los problemas de estos tipos de problemas, sería bueno poder depurar su código de servidor en IBM Cloud. Probablemente esto será posible en el futuro, pero IBM Cloud aún no soporta esto. Lo que puede hacer, sin embargo es:

  1. Echar un vistazo a los archivos de registro dentro de DevOps Services para descubrir qué salió mal. También, a veces puede obtener información adicional usando la herramienta de IBM Cloud cf CLI. Por ejemplo:
     > cf app GuessTheWord Showing health and status for app GuessTheWord in org mattias.mohlin@se.ibm.com / space dev as mattias.mohlin@se.ibm.com... OK requested state: started instances: 0/1 usage: 64M x 1 instances urls: GuessTheWord.mybluemix.net state since cpu memory disk #0 crashing 2014-04-24 01:10:37 PM 0.0% 0 of 0 0 of 0

    Aquí vemos que el estado de la aplicación está en un estadocrashing, lo cual significa que terminó de alguna forma. Un servidor web nunca debe terminar por lo que necesitamos encontrar por qué termina la nuestra al correr en IBM Cloud.

  2. En DevOps Services en la pestaña EDIT CODE, hay un botón DEPLOY, pero no haga clic en el mismo aún. Image shows the Deploy button

    Este botón es para el despliegue manual de los contenidos de su área de proyecto personal de DevOps Services a IBM Cloud. Esto es muy útil en la resolución de problemas porque le permite agregar un inicio de sesión temporal u otros experimentos que usted no quiere para comprometerse con la rama maestra. Antes de hacer clic en DEPLOY, necesitamos hacernos cargo de todos conjuntos los cambios entrantes para actualizar el área del proyecto DevOps Services con la rama maestra.

  3. Vaya a la página Git Status y haga clic en el botón FETCH. Los conjuntos de cambios entrantes se muestran bajo la sección Commits. Haga clic en el botón MERGE para fusionar estos conjuntos de cambios entrantes en su área de proyecto DevOps Services.
  4. Ahora podemos hacer un despliegue manual mediante un clic en el botón DEPLOY. Cuando se ha desplegado la aplicación a IBM Cloud, verá esto: Image shows that manual deployment is ready
    Image shows that manual deployment is ready
  5. Haga clic en el vínculo de la página de la carpeta raíz en el mensaje anterior para ver la información del despliegue manual. Image shows that app deployed on IBM Cloud is not running
    Image shows that app deployed on IBM Cloud is not running

    Vemos un indicador rojo, confirmando que la aplicación no está corriendo. Haga clic en el vínculo Logs para ver los registros producidos por la aplicación antes de terminarse.

    Image shows log files
  6. Abra el archivo stdout.log. Image shows contents of the file stdout.log
    Image shows contents of the file stdout.log

    A partir de este registro, probablemente comprende inmediatamente lo que está mal. Nuestro servidor de web trata de usar un nombre de host de codificación fija (localhost) y un número de puerto (3030). Esto funciona muy bien al correr el servidor localmente, pero no en IBM Cloud.

  7. La solución es agregar la siguiente pieza de código justo después de la declaración de las variables host y port en el archivo server.js:
    if (process.env.hasOwnProperty("VCAP_SERVICES")) { // Running on IBM Cloud. Parse out the port and host that we've been assigned. var env = JSON.parse(process.env.VCAP_SERVICES); var host = process.env.VCAP_APP_HOST; var port = process.env.VCAP_APP_PORT; }

    IBM Cloud usa una variable de ambiente denominada VCAP_SERVICES para transmitir información del ambiente al servidor. El host y port son ejemplos de dicha información. Note que la declaración if anterior no se ejecutará cuando corramos el servidor porque VCAP_SERVICES no se establece entonces. Por lo tanto, podemos correr y depurar nuestra aplicación localmente incluso después de este cambio.

  8. Mandemos este cambio al repositorio Git y permitamos que el despliegue automático haga su trabajo. Vemos que el despliegue tuvo éxito. Image shows auto-deploy of changes to not use a hardcoded host and port
    Image shows auto-deploy of changes to not use a hardcoded host and port
  9. Si ahora hacemos un clic en el vínculo de la aplicación desplegada, tenemos motivos para una pequeña celebración. Image shows GuessTheWord game running on IBM Cloud
    Image shows GuessTheWord game running on IBM Cloud

    ¡Allí está! Ahora nuestro juego está corriendo en IBM Cloud.

  10. Ahora tómese un merecido descanso y juegue el juego. Vea cuántas palabras puede adivinar antes de quedarse sin energía.

Paso 7. Agregue un servicio de base de datos

¿Logró una buena puntuación? ¡Felicidades! Muy mal que no se haya guardado para ver qué tan bueno es para adivinar palabras. Fijemos esto persistiendo las puntuaciones en una base de datos. Puede pensar que una base de datos es demasiado para guardar tan pocos datos ¿No se podría sólo conservar una lista de puntuaciones elevadas en el servidor? Sí, pero no es una buena idea porque el servidor IBM Cloud quizá no siempre corra en la misma máquina física (en virtud del equilibrio de carga). Por lo tanto, no se recomienda persistir datos usando archivos, sino más bien usando algún tipo de servicio de nube para la persistencia.

Hay un número de soluciones de almacenamiento de nube de donde elegir, pero mantengamos las cosas simples. Agreguemos un servicio de base de datos de Cloudant a su aplicación:

  1. Vaya a la aplicación de web de IBM Cloud haciendo clic en el botón MANAGE en la pestaña BUILD & DEPLOY. Image shows the Manage button
    Image shows the Manage button
  2. Esto nos lleva a la aplicación de GuessTheWord en IBM Cloud. Podemos ver que nuestra aplicación está en operación, pero no hay servicios asociados con la misma. Haga clic en Add a service para agregar un nuevo servicio en la sección Data Management del catálogo IBM Cloud, elija Cloudant JSONDB. Image shows Cloudant icon in IBM Cloud
  3. Haga clic en Create and add to app para obtener el siguiente diálogo. Image shows dialog for adding the Cloudant database service
    Image shows dialog for adding the Cloudant database service

    Si ya tiene una cuenta Cloudant, puede introducir su nombre de usuario, clave de acceso y el URL https://<username>.cloudant.com. De otra forma primero se tendrá que registrar para obtener una cuenta Cloudant antes de proceder.

    Cuando hace clic en CREATE, la aplicación reiniciará, lo que sólo deberá tomar unos cuantos segundos.

  4. Ahora deberá ver que tiene una base de datos Cloudant como un servicio de su aplicación IBM Cloud. Image shows Cloudant added as a service to our IBM Cloud application
    Image shows Cloudant added as a service to our IBM Cloud application

Paso 8. Use la base de datos Cloudant

  1. Abra un navegador e inicie una sesión en Cloudant UI: https://<username>.cloudant.com.
  2. Cree una nueva base de datos denominada guess_the_word_hiscores. Después haga clic en el botón para crear un nuevo índice secundario. Guarde en un documento denominado top_scores y nombre el índice top_scores_index. Image shows creating secondary index in Cloudant DB
    Image shows creating secondary index in Cloudant DB
  3. La función del mapa define qué objetos en la base de datos se categorizan por el índice y qué información queremos recuperar para esos objetos. Usamos la puntuación como la llave de índice (el primer argumento para emit), posteriormente emit un objeto conteniendo la puntuación, el nombre del jugador y la fecha en la que se logró la puntuación. Posteriormente encontramos la implementación JavaScript de la función del mapa, misma que puede copiar/pegar.
     function(doc) { emit(doc.score, {score : doc.score, name : doc.name, date : doc.date}); }
  4. Escribamos el código necesario para almacenar puntuaciones en la base de datos Cloudant. Esta vez usaremos el editor de web de DevOps Services. Necesitará decidir qué biblioteca Node.js usar para acceder a Cloudant. Yo elegí la biblioteca nano .

    Haga clic en el archivo package.json en la jerarquía de archivos de DevOps Services, posteriormente agregue la línea "nano" : "*", como se muestra abajo. Esto incluirá la última versión de la biblioteca nano en su aplicación.

     "dependencies": { "express": ">=3.4.7 <4", "jade": ">=1.1.4", "nano" : "*" },

    Al igual que en el host y puerto, IBM Cloud usa la variable del ambiente VCAP_SERVICESpara decir a nuestra aplicación sobre el servicio de la base de datos Cloudant (dónde está corriendo, qué credenciales usar para iniciar la sesión en la misma, etc.). Agregue las líneas marcadas en itálicas abajo al archivo server.js, reemplazando <username> y <password> con su nombre de usario y clave de acceso de Cloudant.

    var express = require('express'); var app = express(); var http = require('http'); var host = "localhost"; var port = 3030;  cloudant = { username : "<username>", // : Update password : "<password>", // : Update url : "https://<username>.cloudant.com" // : Update };if (process.env.hasOwnProperty("VCAP_SERVICES")) { // Running on IBM Cloud. Parse out the port and host that we've been assigned. var env = JSON.parse(process.env.VCAP_SERVICES); var host = process.env.VCAP_APP_HOST; var port = process.env.VCAP_APP_PORT;  // Also parse out Cloudant settings. cloudant = env['user-provided'][0].credentials; } nano = require('nano')('https://' + cloudant.username + ':' + cloudant.password + '@' + cloudant.url.substring(8));  db = nano.db.use('guess_the_word_hiscores');

    Como lo podrá ver, el código anterior también funcionará cuando la aplicación no corra en IBM Cloud. Cuando corra localmente, la aplicación puede usar la base de datos de Cloudant de la misma forma que opera en IBM Cloud.

  5. Ahora manejemos los dos nuevos URLs en nuestro servidor:
    • /hiscores (para obtener las altas puntuaciones de la base de datos)
    • /save_score (para guardar una nueva puntuación alta a la base de datos)

    El código se muestra a continuación:

     app.get('/hiscores', function(request, response) { db.view('top_scores', 'top_scores_index', function(err, body) { if (!err) { var scores = []; body.rows.forEach(function(doc) { scores.push(doc.value); }); response.send(JSON.stringify(scores)); } }); }); app.get('/save_score', function(request, response) { var name = request.query.name; var score = request.query.score; var scoreRecord = { 'name': name, 'score' : parseInt(score), 'date': new Date() }; db.insert(scoreRecord, function(err, body, header) { if (!err) { response.send('Successfully added one score to the DB'); } }); });
  6. No tenemos ningunas llamadas a estos nuevos URLs aún, pero aún podemos probar la conexión de la base de datos invocando los URLs anteriores directamente de un navegador.

    Haga clic en Git Status, mande (push) todos los cambios al repositorio Git de DevOps Services y espere para que se despliegue la aplicación a IBM Cloud. Después escriba lo siguiente en un navegador, reemplazando guesstheword en el URL con el nombre del host que usted elija para su aplicación.

     http://guesstheword.mybluemix.net/save_score?name=Bob&score=4

    Usted deberá ver un mensaje de éxito. Introduzca el siguiente URL, una vez más reemplazando guesstheword con su nombre de host de la aplicación.

     http://guesstheword.mybluemix.net/hiscores

    La partida que acaba de agregar deberá aparecer codificada en JSON.

     [{"score":4,"name":"Bob","date":"2014-05-07T12:12:31.093Z"}]

    Esto nos muestra que nuestro código para usar la base de datos está trabajando correctamente.

  7. Ahora creemos el archivo JavaScript faltante para poblar la tabla de puntuación en la página principal de nuestro juego. En el editor de web, dé un clic derecho en la carpeta public/js y seleccione New > File. Image shows creating a file in the web editor

    Póngale un nombre al archivo hiscores.js y dele los siguientes contenidos.

     /** * Hiscores */ function createTableRow(name, score, date) { var dateObj = new Date(date); var formattedDate = dateObj.toLocaleDateString() + " " + dateObj.toLocaleTimeString(); return '<tr> <td>' + score + '</td><td>' + name + '</td><td>' + formattedDate + '</td></tr>'; } /** * Populate the hiscore table by retrieving top 10 scores from the DB. * Called when the DOM is fully loaded. */ function populateTable() { var table = $("#hiscore_table tr"); $.get("/hiscores", function (data) { var hiscores = JSON.parse(data); hiscores.forEach(function (hiscore) { var html = createTableRow(hiscore.name, hiscore.score, hiscore.date); table.last().after(html); }); }); } $(populateTable);

    Este código puebla la tabla con las principals puntuaciones recuperadas de la base de datos. Mande (push) los cambios al repositorio Git de DevOps Services Git y espere hasta que se redespliegue la aplicación en IBM Cloud. Ahora cuando accedemos a la aplicación, podremos ver el registro de la puntuación falsa que agregamos previamente a la base de datos:

    Image shows high-score table
    Image shows high-score table
  8. Sólo tenemos unas cuantas cosas finales que arreglar para que se guarde la puntuación cuando se acabe el juego. En el archivo main.js, localice la siguiente línea:
     // TODO: Guarde el nombre y la puntuación en DB

    y reemplácelos por :

     saveScore(name, score);

    Add the saveScore() function:

    function saveScore(name, score) { $.ajax({url: "/save_score?name=" + name + "&score=" + score, cache : false}).done(function(data) { window.location.replace("/"); // Go to hiscore page }); }
  9. Finalmente, cree un diálogo Bootstrap "Game Over" agregando lo siguiente como el primer div en el archivo main.jade:
     div(id="name-dialog", class="modal fade") div(class="modal-dialog") div(class="modal-content") div(class="modal-header") h4(class="modal-title") div(class="modal-body") div(class="divDialogElements") label(for="name-input", style="display:table-cell; width:100%") Enter your name: input(class="xlarge", id="name-input", name="xlInput", type="text", style="display:table-cell; width:100%") div(class="modal-footer") button(type="button", class="btn btn-ok") OK
  10. Mande (push) los cambios, espere el auto despliegue, después juegue el juego una sola vez para confirmar que se guarde su puntuación en la base de datos y que aparezca en la tabla en la página principal. Image shows the final game
    Image shows the final game

Conclusión

En este artículo, se ha construido un juego GuesstheWord (Adivina la Palabra) usando IBM DevOps Services y se ha desplegado la aplicación en IBM Cloud. Ha visto la forma en la que se puede desarrollar el código en el editor de web, o en Eclipse (u otro IDE), y después se envía al repositorio Git de IBM DevOps Services. También ha visto la forma de establecer un despliegue automático para que se redespliegue la aplicación tan pronto como se actualicen los nuevos cambios. También ha aprendido la forma de depurar su aplicación localmente y cómo resolver los problemas que pueden ocurrir cuando la aplicación corre en IBM Cloud. Ahora ya está listo para desarrollar sus propias aplicaciones IBM Cloud.


Recursos para Descargar


Comentarios

Inicie Sesión o Regístrese para agregar comentarios.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Cloud computing
ArticleID=979225
ArticleTitle=Construya una aplicación simple de juegos de palabras usando Cloudant en IBM Cloud
publish-date=07112014