Conteúdo


Desenvolva um jogo de palavras simples usando o Cloudant no Bluemix

Comments

O Bluemix é uma nova plataforma aberta para desenvolver e implementar aplicativos remotos e da web. Neste artigo, eu repassarei as etapas para criar um aplicativo simples, que é um jogo de adivinhar a palavra, usando o Bluemix e seu ambiente de desenvolvimento baseado na nuvem: o DevOps Services. Você irá começar do zero e terminará com um jogo simples que pode ser utilizado em um navegador da web com o código do servidor executando na nuvem.

Quando tiver concluído as etapas indicadas neste artigo, você estará pronto para desenvolver aplicativos de qualquer tamanho no Bluemix.

Embora esse aplicativo seja simples, abordarei aspectos que são importantes ao desenvolver aplicativos maiores — por exemplo: configurar um bom ambiente de desenvolvimento para possibilitar a depuração local. Meu objetivo é apresentar a você o desenvolvimento de um aplicativo pequeno no Bluemix usando uma abordagem que também se aplica ao desenvolvimento de aplicativos de grande porte no Bluemix. Quando tiver concluído as etapas indicadas neste artigo, você estará pronto para desenvolver aplicativos de qualquer tamanho no Bluemix.

Execute o aplicativoObtenha o código

O que será necessário para o aplicativo

Para acompanhar, você precisa de uma conta do Bluemix e uma conta do DevOps Services . Portanto, crie essas contas agora, caso ainda não tenha feito isso. Além disso, se você está ouvindo falar do Bluemix pela primeira vez, é conveniente ler esta breve introdução.

Ao iniciar um projeto de desenvolvimento, é importante escolher as tecnologias corretas. O Bluemix suporta várias tecnologias para desenvolver aplicativos. Na verdade, essa flexibilidade é um dos principais pontos fortes da plataforma, porque permite escolher quais tecnologias são mais adequadas para os aplicativos que você deseja desenvolver. Para o nosso jogo de adivinhar a palavra, usaremos o seguinte:

  • Node.js— Para ver o código no lado do servidor, usaremos o Node.js. Os servidores da web implementados no Node.js iniciam rapidamente e é fácil desenvolver e depurar localmente. Também pode ser conveniente usar a mesma linguagem, como JavaScript, para o código no lado do servidor e no lado do cliente. Também usaremos a estrutura Express com o Node.js, porque ela fornece uma funcionalidade útil ao implementar um servidor da web.
  • Cloudant— Para os dados persistentes do servidor (as maiores pontuações no jogo) usaremos um banco de dados Cloudant . Um banco de dados NoSQL como o Cloudant é fácil de usar com JavaScript e dados codificados em JSON.
  • HTML, CSS e JavaScript— A UI do jogo será implementada usando HTML, CSS e JavaScript. Com o suporte para HTML5 e CSS3 em navegadores da web modernos, esta é uma opção natural, porque permitirá que o jogo seja executado em telefones e tablets, bem como em computadores.
  • Bootstrap e JQuery— Também usaremos as estruturas Bootstrap e JQuery JavaScript, que fornecem funcionalidades interessantes para o desenvolvimento de UIs da web.
  • Jade— Para digitar menos, usaremos uma linguagem de modelo para as páginas HTML. Há várias linguagens de modelo disponíveis para Node.js. Optei peloJade porque ele é usado frequentemente com a estrutura Express.

Depois de tomar essas decisões, estamos prontos para começar a codificar.

Etapa 1. Escreva o código do servidor

  1. Vamos começar implementando a parte principal do servidor do Node.js, para poder testá-lo antes de implementar a UI. Podemos usar o Eclipse para a codificação, mas, na atualidade, o suporte para o Node.js em Eclipse ainda é básico, principalmente em termos de depuração. Portanto, usaremos um utilitário chamado node-inspector para depurar o código do servidor de Node.js. Fique à vontade para usar o seu editor de texto preferido para escrever o código abaixo:
    /**
     * 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. Salve esse código em um arquivo chamado server.jse, em seguida, crie uma pasta chamada views para conter os dois arquivos de Jade (hiscores.jade e main.jade), referenciados no código acima e mostrados abaixo. Esses arquivos de Jade definem o conteúdo das duas páginas da web usadas pelo jogo.
  3. O arquivo hiscores.jade mostra as pontuações mais altas. Essa é a página inicial do jogo e está ligada à URL de raiz '/'.
    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. O arquivo main.jade é a página em que o jogo é jogado. Está ligado à 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 se pode ver, esses arquivos Jade referenciam vários arquivos estáticos, como arquivos CSS e JavaScript. Incluiremos isso mais tarde; primeiramente, testaremos o que foi feito até agora.

Etapa 2. Execute e depure o código do servidor

  1. Se você ainda não instalou o Node.js localmente, este é o momento de fazer isso. Faça o download a partir de Nodejs.org e siga as instruções. Instalamos o Node.js localmente para poder executar e depurar o código do servidor localmente antes de implementá-lo no Bluemix.
  2. Também é necessário instalar os módulos Express e Jade para Node.js. A forma mais fácil de fazer isso é primeiramente criar um arquivo package.json na pasta raiz que especifica as dependências para essas 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": {}
    }

    Agora é possível instalar o Express e o Jade abrindo um prompt de linha de comando na pasta raiz e inserindo o comando a seguir:

    > npm install

    No momento em que você lê este artigo, é possível que existam versões do Express e do Jade disponíveis mais recentes que as versões mostradas acima. Evidentemente, é possível usar essas versões. Desde que todas as dependências do aplicativo sejam mencionadas no arquivo package.json, as mesmas versões das bibliotecas serão usadas quando você desenvolver localmente e quando implementar no Bluemix mais tarde. Isso é bom porque evita surpresas causadas pelo uso de bibliotecas diferentes em ambientes diferentes.

  3. Execute o aplicativo pela primeira vez com o seguinte comando:
    > node --debug server.js
  4. Abra um navegador da web e acesse http://localhost:3030/. Image shows http://localhost:3030
  5. Antes de continuar o desenvolvimento do jogo, vamos garantir que podemos depurar o aplicativo. Primeiramente, instalamos o node-inspector. Abra uma nova linha de comando e digite o comando a seguir:
    > npm install -g node-inspector
  6. Como nós lançamos o aplicativo com o sinalizador --debug , agora podemos iniciar o node-inspector da seguinte forma:
    > node-debug server.js

    Essa ação abre um depurador JavaScript no navegador da web padrão, que deve ser o Chrome ou o Opera. Se o seu navegador da web padrão é outro, é possível usar este comando:

    > node-inspector

    Abra http://127.0.0.1:8080/debug?port=5858 no Chrome ou no Opera para começar a depurar. Se você ainda não tiver usado esse depurador, é conveniente ler esta introdução.

Etapa 3. Implemente o código do cliente

  1. Agora vamos criar os arquivos ausentes referenciados pelos arquivos de Jade. Todos os arquivos binários (JPG e MP3) podem ser transferidos por download a partir do projeto GuessTheWord concluído no DevOps Services, que contém todos os arquivos referenciados neste artigo. A forma mais fácil de fazer o download desses arquivos é acessar a guia EDIT CODE , clicar com o botão direito na pasta que os contém e exportar o conteúdo como um arquivo zip para download. Image shows                             creating the missing files
    Image shows creating the missing files

    Evidentemente, também é possível optar por criar suas próprias imagens e sons para dar um toque mais pessoal ao jogo.

  2. Os arquivos a seguir constituem as bibliotecas de JQuery e Bootstrap JavaScript. Eles também podem ser transferidos por download a partir do projeto GuessTheWord do DevOps Services ou a partir da Internet.
    1. Faça o download para a pasta public/js:
      • jquery.js (a versão mais recente da biblioteca de JQuery JavaScript)
      • bootstrap.js (a versão mais recente da biblioteca de Bootstrap JavaScript)
    2. Faça o download para a pasta public/css:
      • bootstrap.css (a versão mais recente do arquivo CSS para o Bootstrap)
  3. Agora crie os dois arquivos CSS a seguir, que definem os estilos usados no jogo:
  4. Execute o aplicativo outra vez, localmente, para ver essas mudanças entrarem em vigor. Acesse a pasta raiz do aplicativo (certificando-se de que seja a pasta à qual o repositório Git local está conectado) e, em seguida, execute:
    > node-debug server.js

    Agora o jogo deve ter uma aparência um pouco melhor que a de antes:

    Image shows                             game creation progress
  5. Em seguida, vamos escrever o Javascript do lado do cliente que implementa a lógica do jogo. Aguardaremos um pouco antes de implementar hiscores.js , já que o preenchimento da lista de pontuações mais altas requer um banco de dados — algo que incluiremos depois. Em vez disso, crie o arquivo public/js/main.js com o conteúdo encontrado neste fragmento de código, que basicamente contém toda a lógica do jogo. Ele trata das ações de selecionar aleatoriamente a partir do servidor uma palavra em inglês com uma descrição, manipular a entrada de teclado realizada pelo jogador, contar os pontos, gerenciar a energia, etc.

    Como se pode ver, a função getNewSecretWord() chama um serviço /randomword no servidor da web para obter a palavra secreta.

  6. Vamos implementar esse serviço incluindo o código a seguir ao server.js (depois das declarações de variáveis iniciais).
    /**
     * 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();
    });

    Esse código liga a URL /randomword URL ao código que usa o Wordnik.com, um dicionário online de inglês, para obter uma palavra aleatória. Em seguida, ele chama wordLookup(), que faz outra chamada à API do Wordnik para obter a descrição da palavra em questão. Por fim, a palavra secreta e sua descrição são codificadas como JSON e retornadas como resposta da solicitação de HTTP.

    Observação: a chave de API incluída no fragmento de código acima se destina a uma conta grátis compartilhada por muitas pessoas, para que só possa ser usada em pequena escada. Para evitar essa restrição, é possível registrar-se no Wordnik eobter a sua própria chave de API.

  7. Nesse ponto, é conveniente executar algumas sessões de depuração localmente para verificar o código do lado do cliente e do lado do servidor, para se certificar de que o jogo funcione conforme o esperado. Image shows                             verifying that the                     game works as expected
    Image shows verifying that the game works as expected

    O JavaScript é depurado usando o depurador integrado ao Chrome. O JavaScript no lado do servidor é depurado usando o node-inspector, conforme o descrito anteriormente. Observe que o node-inspector usa o mesmo depurador Chrome para a depuração de Javascript do Node.js no lado do servidor.

Etapa 4. Crie um projeto no DevOps Services

Agora que o aplicativo está funcionando, podemos executar e depurar localmente, e a próxima etapa é armazenar o que escrevemos até agora em um repositório do DevOps Services. Isso proporciona diversos benefícios, tais como:

  • O código é armazenado na nuvem; é mais seguro armazenar na nuvem que em um computador local.
  • Outras pessoas podem contribuir para o desenvolvimento do aplicativo.
  • Podemos ativar a implementação automática no Bluemix.
  1. Efetue sign in no DevOps Services e clique em Start coding para criar um projeto para o nosso aplicativo. A escolha entre o Jazz SCM e o Git SCM é arbitrária e normalmente depende do sistema SCM com o qual você está mais familiarizado. Escolheremos um repositório Git para o nosso projeto e marcaremos a caixa de seleção Deploy to Bluemix , já que implementaremos o nosso aplicativo no Bluemix. Selecione uma organização e um espaço do Bluemix e, em seguida, clique em CREATE. Image shows creating the project
    Image shows creating the project
  2. No início, o novo projeto estará vazio, com exceção de dois arquivos padrão. Para adicionar seu código ao projeto, clique em EDIT CODE e, em seguida, arraste e solte os arquivos do sistema de arquivos para a hierarquia de arquivos do projeto (a árvore mostrada à esquerda).

    Se você escreveu o código usando o Eclipse, é possível arrastar e soltar os arquivos diretamente a partir do Eclipse Project Explorer. Observe que, em seguida, você deve selecionar as pastas e os arquivos individuais sob o projeto Eclipse (não o projeto em si) e arrastá-los e soltá-los no nó superior (destacado em vermelho) na hierarquia de arquivos do projeto. Observe também que o Eclipse oculta alguns arquivos — por exemplo: o arquivo .project. Portanto, talvez você tenha que arrastar e soltar alguns arquivos a partir do seu sistema de arquivos.

    Agora a hierarquia de arquivos do projeto deve mostrar todos os arquivos do seu aplicativo.

    Observe que, apesar de você ter acabado de copiar os arquivos do seu computador local para um projeto do DevOps Services, as mudanças que você fez ainda não foram confirmadas e enviadas por push para o repositório Git. Isso significa que ninguém mais pode ver os arquivos que você incluiu. A hierarquia de arquivos mostrada no projeto do DevOps Services é como a sua área de trabalho pessoal, semelhante ao sistema de arquivos local, com exceção de que está armazenado na nuvem.

  3. Se você clicar no ícone do repositório, verá várias mudanças não confirmadas, uma para cada arquivo que você incluiu. Os arquivos aparecem como "Unstaged". o termo do Git que designa uma mudança que ainda não foi confirmada no repositório. Image shows repository icon
  4. Para confirmar as mudanças, execute o comando Stage the change em cada arquivo: Image shows stage button

    Essa ação faz os arquivos passarem de Unstaged para Staged. Todas as mudanças mostradas sob Staged serão confirmadas como um único conjunto de mudanças quando você clicar em COMMIT. Nesse caso, queremos incluir todos os arquivos em um único conjunto de mudanças; no entanto, mais tarde é conveniente confirmar algumas mudanças como um conjunto de mudanças e outras como outro conjunto. Cada conjunto de mudanças deve agrupar mudanças que estão relacionadas sob o ponto de vista lógico.

    Sua mensagem de confirmação na caixa de diálogo Commit deve descrever o conjunto de mudanças e, talvez, informar o motivo da mudança.

    Image shows                             commit
    Image shows commit
  5. Ao clicar em SUBMIT, o conjunto de mudanças é confirmado no Git e aparece como um único conjunto de mudanças sob a seção Commits. Image shows committed changes, not yet pushed
    Image shows committed changes, not yet pushed
  6. A última etapa é enviar esse conjunto de mudanças por push para a ramificação principal para que outros possam buscá-lo lá. Clique em PUSH e, em seguida, clique em OK para enviar as mudanças por push. Image shows pushed changes
  7. Nesse ponto, a sua cópia local do código é redundante. Considere a possibilidade de excluí-la. Se você continuar a desenvolver na sua cópia local, lembre-se de fazer upload de todos os arquivos modificados para o projeto do DevOps Services e entregar as mudanças da mesma forma que você acabou de fazer. É possível trabalhar dessa forma, mas isso pode ser confuso e trabalhoso.

    Uma abordagem mais prática seria abandonar totalmente o desenvolvimento local e editar o código usando o editor da web no DevOps Services ou configurar um repositório Git local conectado ao repositório Git do DevOps Services. Optei pela segunda alternativa porque queremos ter a capacidade de desenvolver e depurar localmente, algo que ainda não se pode fazer usando o editor da web do DevOps Services.

    Há duas formas de configurar um repositório Git local conectado ao repositório Git do DevOps Services. Se você usa um IDE como o Eclipse ou o Visual Studio, é possível usar o plug-in do Git desses IDEs para importar o repositório de Git do DevOps Services para o IDE. Se você desenvolve em um ambiente que não tem um plug-in do Git, é possível usar o Git a partir da linha de comando. Nos dois casos, é necessária a URL referente ao repositório Git do DevOps Services. É possível obter essa URL na página de visão geral do projeto DevOps Services.

    Para obter a página de visão geral a partir da guia EDIT CODE , clique no link do projeto, no canto superior esquerdo.

    Image shows project overview page

    Em seguida, clique no link Git URL :

    Image shows Git URL
    Image shows Git URL
  8. Depois de clonar essa URL em um repositório Git local, é possível continuar a desenvolver o aplicativo localmente e confirmar as mudanças diretamente no repositório Git do DevOps Services Git sem passar pela interface da web do DevOps Services. Se você usar o Eclipse e o plug-in do EGit, a visualização do projeto será semelhante à captura de tela abaixo. Se o seu Eclipse ainda não contém o plug-in do EGit, é fácil instalar. Se você é iniciante no EGit, consulte o guia do usuário.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

Etapa 5. Implemente o seu aplicativo no Bluemix

Nesse ponto, é uma boa ideia fazer uma primeira implementação no Bluemix, só para garantir que esteja funcionando antes de continuar desenvolvendo o jogo.

  1. A implementação é controlada por um arquivo chamado manifest.yml; portanto, precisamos criar esse arquivo na pasta raiz do seu aplicativo.
    ---
    applications:
    - name: GuessTheWord
      framework: node
      runtime: node08
      memory: 64M
      instances: 1
      host: GuessTheWord
      path: .     
      command: node server.js

    Essas configurações instruem o Bluemix a implementar o nosso aplicativo. Por exemplo, especificamos o tempo de execução (Node.js), a quantidade de memória a ser reservada para o aplicativo e o nome do host a ser usado na URL do aplicativo implementado. Observe que o nome do host deve ser globalmente exclusivo — sendo assim, é necessário escolher um nome do host diferente de "GuessTheWord."

  2. Não importando se você cria esse arquivo no editor da web do DevOps Services ou no seu ambiente de desenvolvimento local, não se esqueça de enviar o novo arquivo por push para o repositório Git do DevOps Services.
  3. Para iniciar uma implementação, clique no botão BUILD & DEPLOY no projeto do DevOps Services. Image shows the Build & Deploy tab
    Image shows the Build & Deploy tab

    Em seguida, alterne o comutador na parte superior da página de OFF para SIMPLE para implementar no Bluemix.

    Image shows auto-deploy buttons
  4. Assim que você faz isso, o DevOps Services tenta implementar seu aplicativo no Bluemix. Image shows simple auto-deploy enabled
    Image shows simple auto-deploy enabled

    Além disso, uma nova implementação ocorrerá automaticamente sempre que alguém envia mudanças por push para o repositório Git do DevOps Services. Isso é conveniente porque sempre nos dá acesso à versão mais recente do aplicativo que foi implementada (por exemplo: para executar testes).

  5. Depois de aproximadamente 30 segundos, você deve ver que o aplicativo foi implementado sem erros. Image shows auto-deploy message
    Image shows auto-deploy message
  6. Para acessar o aplicativo implementado no Bluemix, clique no link acima da lista. Image shows link to deployed application
    Image shows link to deployed application

Etapa 6. Solucione os problemas da implementação no Bluemix

Ao tentar acessar o aplicativo implementado, provavelmente você verá a seguinte mensagem:

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

Isso não é bom. Evidentemente, há um problema em alguma parte. Parece que está relacionado à execução do aplicativo no Bluemix, já que ele executou localmente sem problemas.

Isso ilustra um ponto importante: os aplicativos podem ser implementados com êxito mas, mesmo assim, podem não estar disponíveis quando você tenta acessá-los. O indicador de status verde e um resultado de OK na lista Recent Auto-Deployments significam apenas que o aplicativo foi implementado com êxito e iniciado. No entanto, ele pode, por exemplo, finalizar logo depois de iniciar e não estar disponível quando você tenta acessar a URL dele no Bluemix.

Para solucionar esses tipos de problemas, seria bom poder depurar o código do servidor no Bluemix. Provavelmente isso será possível no futuro, mas no momento o Bluemix não suporta isso. Entretanto, é possível fazer o seguinte:

  1. Examinar os arquivos de log no DevOps Services para ver o que deu errado. Além disso, às vezes é possível obter informações adicionais usando a ferramenta cf CLI do Bluemix. Por exemplo:
    > 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

    Vemos aqui que o estado do aplicativo é crashing, ou seja, ele foi finalizado de alguma forma. Um servidor da web nunca deve ser finalizado — portanto, precisamos descobrir por que o nosso termina ao executar no Bluemix.

  2. No DevOps Services, na guia EDIT CODE , há um botão DEPLOY , mas não clique nele ainda. Image shows the Deploy button

    Esse botão é para a implementação manual do conteúdo da sua área pessoal de projeto do DevOps Services no Bluemix. Isso é útil ao solucionar problemas, porque permite incluir a criação de log temporária ou outros experimentos que você não deseja confirmar na ramificação principal. Antes de clicar em DEPLOY, precisamos buscar todos os conjuntos de mudanças recebidos para atualizar a sua área de projeto no DevOps Services em relação à ramificação principal.

  3. Acesse a página Git Status e clique no botão FETCH . Os conjuntos de mudanças recebidos são mostrados sob a seção Commits . Clique no botão MERGE para mesclar os conjuntos de mudanças recebidos na sua área de projeto no DevOps Services.
  4. Agora podemos fazer uma implementação manual clicando no botão DEPLOY . Quando o aplicativo tiver sido implementado no Bluemix, você verá isto Image shows that manual deployment is ready
    Image shows that manual deployment is ready
  5. Click the root folder page link in the above message to view manual deployment information. Image shows that app deployed on Bluemix is not running
    Image shows that app deployed on Bluemix is not running

    Nós vemos um indicador vermelho, confirmando que o aplicativo não está executando. Clique no link Logs para visualizar os logs produzidos pelo aplicativo antes de ele ser finalizado.

    Image shows                             log files
  6. Abra o arquivo stdout.log . Image shows contents of the file stdout.log
    Image shows contents of the file stdout.log

    Por meio desse log, provavelmente você entenderá de imediato o que está errado. Nosso servidor da web tenta usar um nome do host (localhost) e número da porta (3030) codificados permanentemente. Isso funciona bem ao executar o servidor localmente, mas não no Bluemix.

  7. Uma solução é incluir o código a seguir logo depois da declaração das variáveis host eport no arquivo server.js:
    if (process.env.hasOwnProperty("VCAP_SERVICES")) {
      // Running on Bluemix. 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;	
    }

    O Bluemix usa uma variável de ambiente chamada VCAP_SERVICES para passar informações sobre o ambiente para o servidor. O host eport são exemplos de informações desse tipo. Observe que a instrução if acima não será executada quando executarmos o servidor localmente porque VCAP_SERVICES não está configurado. Portanto, mesmo depois dessa mudança, podemos executar e depurar nosso aplicativo localmente.

  8. Vamos enviar essa mudança por push para o repositório Git e deixar que a implementação automática faça o seu trabalho. Vemos que a implementação foi bem-sucedida. 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. Se clicarmos agora no link do aplicativo implementado, teremos motivo para uma pequena comemoração. Image shows GuessTheWord game running on Bluemix
    Image shows GuessTheWord game running on Bluemix

    Voilà! Nosso jogo está executando no Bluemix.

  10. Agora, faça uma pausa muito merecida e jogue o jogo. Veja quantas palavras é possível adivinhar antes de ficar sem energia.

Etapa 7. Inclua um serviço de banco de dados

A sua pontuação foi alta? Parabéns!É uma pena que não seja salva, para que os outros vejam como você é bom em adivinhar palavras. Vamos consertar isso persistindo as pontuações em um banco de dados. Talvez você pense que usar um banco de dados para salvar uma quantidade tão pequena de dados é um exagero. Nós não poderíamos manter a lista de pontuações altas em um arquivo de texto no servidor? Sim, mas isso não é uma boa ideia, porque é possível que o servidor do Bluemix seja executado em máquinas físicas diferentes (devido ao balanceamento de carga). Portanto, não é recomendável persistir dados usando arquivos; em vez disso, deve-se usar algum tipo de serviço de nuvem para persistência.

Há várias opções de soluções de armazenamento em nuvem, mas vamos manter a simplicidade. Vamos incluir o serviço de banco de dados Cloudant no nosso aplicativo:

  1. Acesse o aplicativo da web Bluemix clicando no botão MANAGE na guia BUILD & DEPLOY . Image shows the Manage button
    Image shows the Manage button
  2. Isso nos leva ao aplicativo GuessTheWord no Bluemix. Podemos ver que o aplicativo está executando, mas não há serviços associados a ele. Clique em Add a service para adicionar um novo serviço. Na seção Data Management do catálogo do Bluemix, escolha Cloudant JSONDB. Image shows Cloudant icon in Bluemix
  3. Clique em Create and add to app para acessar o diálogo a seguir. Image shows dialog for adding the Cloudant database service
    Image shows dialog for adding the Cloudant database service

    Se você já tem uma conta do Cloudant, é possível inserir o nome de usuário, a senha e a URL https://<username>.cloudant.com. Do contrário, primeiro é necessário se registrar para ter uma conta do Cloudant antes de continuar.

    Ao clicar em CREATE, o aplicativo será reiniciado, e isso deve levar apenas alguns segundos.

  4. Agora você deve ver que tem um banco de dados Cloudant como serviço do seu aplicativo Bluemix. Image shows Cloudant added as a service to our Bluemix application
    Image shows Cloudant added as a service to our Bluemix application

Etapa 8. Use o banco de dados Cloudant

  1. Abra um navegador e efetue login na UI do Cloudant: https://<username>.cloudant.com.
  2. Crie um banco de dados chamado guess_the_word_hiscores. Em seguida, clique no botão para criar um novo índice secundário. Armazene-o em um documento chamado top_scores e dê ao índice o nome top_scores_index. Image shows creating secondary index in Cloudant DB
    Image shows creating secondary index in Cloudant DB
  3. A função mapa define quais objetos do banco de dados são categorizados pelo índice e quais informações referentes a esses objetos queremos recuperar. Usamos a pontuação como chave do índice (o primeiro argumento para emit) e, em seguida, fazemos emit de um objeto contendo a pontuação, o nome do jogador e a data em que a pontuação foi obtida. Esta é a implementação em JavaScript da função de mapa, que pode ser copiada e colada.
    function(doc) {
     emit(doc.score, {score : doc.score, name : doc.name, date : doc.date});
    }
  4. Vamos escrever o código necessário para armazenar pontuações no banco de dados Cloudant. Desta vez, utilizaremos o editor da web do DevOps Services. Será necessário decidir qual biblioteca do Node.js será utilizada para acessar o Cloudant. Eu escolhi a biblioteca nano .

    Clique no arquivo package.json na hierarquia de arquivos do DevOps Services e, em seguida, inclua a linha "nano" : "*", conforme mostrado abaixo. Essa ação incluirá a versão mais recente da biblioteca nano no seu aplicativo.

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

    Assim como acontece com o host e a porta, o Bluemix usa a variável de ambiente VCAP_SERVICES para informar o seu aplicativo sobre o serviço de banco de dados Cloudant (onde está executando, quais credenciais devem ser usadas para fazer login nele, etc.). Inclua as linhas em itálico abaixo no arquivo server.js, substituindo <username> e<password> pelo nome de usuário e senha do 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 Bluemix. 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 se pode ver, o código acima também irá funcionar quando o aplicativo não for executado no Bluemix. Ao executar localmente, o aplicativo pode usar o banco de dados Cloudant como usa quando está executando no Bluemix.

  5. Agora vamos manipular duas novas URLs no nosso servidor:
    • /hiscores (para obter as pontuações mais altas a partir do banco de dados)
    • /save_score (para salvar uma nova pontuação alta no banco de dados)

    O código é mostrado abaixo:

    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. Ainda não temos chamadas para essas novas URLs, mas, mesmo assim, podemos testar a conexão com o banco de dados chamando as URLs acima diretamente de um navegador.

    Clique em Git Status, envie todas as mudanças por push para o repositório Git do DevOps Services e aguarde até que o aplicativo seja implementado no Bluemix. Em seguida, insira o código a seguir em um navegador, substituindo guesstheword na URL pelo nome do host que você escolheu para o aplicativo.

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

    Você deve ver uma mensagem de êxito. Insira a URL a seguir, novamente substituindo guesstheword pelo nome do host do seu aplicativo.

    http://guesstheword.mybluemix.net/hiscores

    A entrada que você acabou de incluir deve aparecer codificada em JSON.

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

    Isso mostra que o código para utilizar o banco de dados está funcionando corretamente.

  7. Agora vamos criar o arquivo JavaScript que falta para preencher a tabela de pontuação na página principal do jogo. No editor da web, clique com o botão direito na pasta public/js e selecione New > File. Image shows creating a file in the web editor

    Dê ao arquivo o nome hiscores.js e o conteúdo a seguir.

    /**
     * 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);

    Esse código preenche a tabela com as pontuações mais altas recuperadas do banco de dados. Envie as mudanças por push para i repositório Git do DevOps Services e aguarde até que o aplicativo seja implementado novamente no Bluemix. Agora, ao acessar o aplicativo, deveremos ver a entrada de pontuação falsa que incluímos no banco de dados anteriormente:

    Image shows high-score table
    Image shows high-score table
  8. Agora só falta corrigir alguns detalhes finais para que a pontuação seja salva quando o jogo acabar. No arquivo main.js, localize a linha a seguir:
    // TODO: Save name and score in DB

    E substitua por:

    saveScore(name, score);

    Inclua a função saveScore() :

    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. Para terminar, crie um diálogo "Game Over" no Bootstrap incluindo o seguinte como o primeiro div no arquivo 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. Envie as mudanças por push, aguarde a implementação automática e, em seguida, use o jogo uma vez para confirmar que a sua pontuação seja salva no banco de dados e apareça na tabela da página principal. Image shows the final game
    Image shows the final game

Conclusão

Neste artigo, você desenvolveu um jogo GuesstheWord usando o IBM DevOps Services e o implementou no Bluemix. Você viu como o código pode ser desenvolvido do editor da web ou no Eclipse (ou outro IDE) e, em seguida, enviado por push para o repositório Git do IBM DevOps Services. Você também viu como configurar a implementação automática para que o aplicativo seja reimplementado assim que as novas mudanças sejam enviadas por push. Você também aprendeu a depurar o aplicativo localmente e a solucionar os problemas que podem ocorrer quando o aplicativo executa no Bluemix. Agora você está pronto para desenvolver seus próprios aplicativos no Bluemix.


Recursos para download


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Cloud computing
ArticleID=980264
ArticleTitle=Desenvolva um jogo de palavras simples usando o Cloudant no Bluemix
publish-date=07112014