目次


Bluemix 上で Cloudant を使用してシンプルなワード・ゲームを作成する

Comments

Bluemix は、Web アプリケーションやモバイル・アプリケーションを開発してデプロイするための新しいオープン・プラットフォームです。この記事では、Bluemix と、Bluemix のクラウド・ベースの開発環境である DevOps Services を使用して、言葉を当てるシンプルな GuesstheWord ゲーム・アプリケーションを作成する手順を説明します。ゼロから開発を初めて、クラウド上でサーバー・コードを実行して Web ブラウザーでプレイできるシンプルなゲームを完成させます。

この記事の手順を完了すると、どんなサイズの Bluemix アプリケーションでも自分で開発できるようになります。

このアプリケーションはシンプルなものですが、これよりも大規模なアプリケーションを開発する際に重要となる側面についても説明します。そのような側面の 1 つとしては、ローカルでデバッグ可能な優れた開発環境を構築することが挙げられます。記事で目標としているのは、大規模な Bluemix アプリケーションの開発にも適用できる手法を使用して、小規模な Bluemix アプリケーションの開発を行う方法を説明することです。この記事の手順を完了すると、どんなサイズの Bluemix アプリケーションでも自分で開発できるようになります。

アプリケーションに必要となるもの

この記事の手順に従うには、Bluemix アカウントと DevOps Services アカウントが必要です。これらのアカウントをまだ作成していない場合は、今すぐ作成してください。また、これまで Bluemix について聞いたことがなければ、このリンク先の簡単な概要を読むことをお勧めします。

開発プロジェクトに着手するときには、適切なテクノロジーを選択することが重要となりますが、Bluemix では、数多くのアプリケーション開発テクノロジーがサポートされています。実のところ、この柔軟性が、このプラットフォームの大きな強みの 1 つとなっています。なぜなら、開発するアプリケーションに最適なテクノロジーを自由に選択できるためです。この記事で作成する、単語を推測する GuesstheWord ゲームには、次のテクノロジーを使用します。

  • Node.js— サーバー・サイドのコードには、Node.js を使用します。Node.js で実装された Web サーバーは起動するのに時間がかからないだけでなく、ローカルで開発してデバッグするのも簡単です。また、サーバー・サイドとクライアント・サイドの両方のコードに同じ言語 (JavaScript など) を使用できるという利点もあります。さらに、Node.js と一緒に、Web サーバーを実装する際に役立つ機能を提供してくれる Express フレームワークも使用します。
  • Cloudant— Cloudant データベースは、サーバー・データ (ゲームのハイスコア) を永続化するために使用します。Cloudant のような NoSQL データベースであれば、JavaScript や JSON でエンコードされたデータを使用して簡単に扱うことができます。
  • HTML、CSS、および JavaScript— ゲームの UI は、HTML、CSS、JavaScript を使用して実装します。最近の Web ブラウザーでは HTML5 と CSS3 がサポートされているので、これは当然の選択と言えます。これらのテクノロジーを使用することで、このゲームを PC 上だけでなく、スマートフォンやタブレット上でも実行できるためです。
  • Bootstrap と jQuery— Web UI 開発に有用な機能を提供することから、Bootstrap および jQuery といった JavaScript フレームワークも使用します。
  • Jade— 入力する手間を省くために、HTML ページにはテンプレート言語を使用します。Node.js に使用できるテンプレート言語はいくつかありますが、Express フレームワークでよく使われていることから、Jade を選びました。

使用するテクノロジーが決定したら、コーディングに取り掛かれます。

ステップ 1. サーバー・コードを作成する

  1. UI を実装する前にサーバーをテストできるように、まずは Node.js サーバーのコア部分を実装します。コーディングには Eclipse を使用することもできますが、この記事を執筆している時点で、Eclipse での Node.js のサポートは、特にデバッグに関しては基本的なものでしかありません。そこで、Node.js サーバー・コードをデバッグできるように、node-inspector というユーティリティーを使用します。皆さんが以下のコードを作成するときには、自分の好きなテキスト・エディターを自由に使用してください。
    /**
     * 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. 上記のコードを server.js という名前を付けたファイルに保存した後、views という名前のフォルダーを作成し、そこに、上記のコードで参照している 2 つの Jade ファイル (hiscores.jade と main.jade) を格納します。この 2 つの Jade ファイル (以下を参照) は、ゲームで使用する 2 つの Web ページそれぞれのコンテンツを定義します。
  3. hiscores.jade ファイルは、ゲームの初期ページとしてハイスコアを表示し、ルート URL「/」にバインドされます。
    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. main.jade ファイルは、ゲームをプレイするページで、URL 「/play」にバインドされます。 '/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")

ご覧のように、この 2 つの Jade ファイルは、CSS ファイルや JavaScript ファイルなど、多数の静的ファイルを参照します。これらの静的ファイルは後で追加することとして、先に、ここまでで作成したコードをテストしましょう。

ステップ 2. サーバー・コードを実行してデバッグする

  1. Node.js をローカルにインストールしていない場合は、この時点でインストールしてください。それには、Nodejs.org からダウンロードして、インストール手順に従います。Node.js をローカルにインストールする理由は、サーバー・コードを Bluemix にデプロイする前に、ローカルで実行してデバッグできるようにするためです。
  2. Node.js 用の Express および Jade モジュールもインストールする必要があります。これらのモジュールをインストールする最も簡単な方法として、まず、ルート・フォルダー内に package.json ファイルを作成し、このファイルでこれらのライブラリーへの依存関係を指定します。
    {
    	"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": {}
    }

    これで、ルート・フォルダーでコマンド・ライン・プロンプトを開いて以下のコマンドを入力すれば、Express と Jade をインストールすることができます。

    > npm install

    皆さんがこの記事を読む頃までに、上記に示されているバージョンよりも新しいバージョンの Express および Jade を使用できるようになっているかもしれません。その場合はもちろん、新しいバージョンを使用することができます。package.json にアプリケーションのすべての依存関係が記載されている限り、ローカルで開発するときにも、後で Bluemix にデプロイするときにも、同じバージョンのライブラリーが使用されます。このように package.json に依存関係を記載しておくと、環境によって異なるバージョンのライブラリーが使用されているために発生する、驚くような問題を避けることができるので、この方法をお勧めします。

  3. 以下のコマンドで、アプリケーションを初めて実行します。
    > node --debug server.js
  4. Web ブラウザーを開いて、http://localhost:3030/ にアクセスします。 http://localhost:3030 にアクセスすると表示されるページのスクリーン・ショット
  5. ゲームの開発に進む前に、アプリケーションをデバッグできることを確かめましょう。そのためにはまず、node-inspector をインストールします。新しいコマンド・ラインを開いて、以下のコマンドを入力してください。
    > npm install -g node-inspector
  6. --debug フラグを使用してアプリケーションを起動したので、以下のコマンドで node-inspector を開始することができます。
    > node-debug server.js

    上記のコマンドを実行すると、デフォルトの Web ブラウザーに JavaScript デバッガーが開きます。このコマンドを使用する場合は、デフォルトの Web ブラウザーが、Chrome または Opera のいずれかでなければなりません。別の Web ブラウザーをデフォルトとして使用している場合は、代わりに以下のコマンドを使用することができます。

    > node-inspector

    Chrome または Opera で http://127.0.0.1:8080/debug?port=5858 を開いて、デバッグを開始します。このデバッガーを使用した経験がないとしたら、このリンク先の概要を読むことをお勧めします。

ステップ 3. クライアント・コードを実装する

  1. 次は、Jade ファイルで参照されるファイルのうち、不足しているファイルを作成しましょう。すべてのバイナリー・ファイル (JPG および MP3) は、完成版の GuessTheWord DevOps Services プロジェクトからダウンロードすることができます。このプロジェクトに、この記事で参照するファイルのすべてが含まれています。これらのファイルをダウンロードする最も簡単な方法は、「EDIT CODE (コードの編集)」タブで、ファイルが含まれているフォルダーを右クリックし、「Export (エクスポート)」を選択して、ダウンロード用の zip ファイルとしてフォルダーの中身をエクスポートするという方法です。 不足しているファイルを作成するための操作画面のスクリーン・ショット
    不足しているファイルを作成するための操作画面のスクリーン・ショット

    もちろん、独自の画像とサウンドを作成して、より個人的な味わいをゲームに加えることもできます。

  2. 以下のファイルは、jQuery および Bootstrap という JavaScript ライブラリーで構成されています。これらのファイルも、GuessTheWord DevOps Services プロジェクトからダウンロードすることや、インターネットからダウンロードすることができます。
    1. 以下のファイルは、public/js フォルダーにダウンロードします。
      • jquery.js (最新バージョンの jQuery JavaScript ライブラリー)
      • bootstrap.js (最新バージョンの Bootstrap JavaScript ライブラリー)
    2. 以下のファイルは、public/css フォルダーにダウンロードします。
      • bootstrap.css (最新バージョンの Bootstrap 用 CSS ファイル)
  3. 次に、以下の 2 つの CSS ファイルを作成して、ゲームで使用するスタイルを定義します。
  4. アプリケーションをもう一度ローカルで実行し、以上で行った変更が適用されていることを確認します。カレント・ディレクトリーをアプリケーションのルート・フォルダー (ローカル Git リポジトリーが接続されているフォルダーであることを確認してください) に変更して、以下のコマンドを実行します。
    > node-debug server.js

    ゲームの外観が前よりも多少良くなっているはずです。

    ゲーム作成の途中段階での外観のスクリーン・ショット
  5. 今度は、ゲームのロジックを実装するクライアント・サイドの JavaScript を作成します。hiscores.js を実装するのは、もう少し待つことにします。というのも、ハイスコアのリストにデータを取り込むには、データベースが必要となるためです (データベースは後ほど追加します)。代わりに、public/js/main.js ファイルを作成して、このコード・スニペットの中身を追加します。これで基本的に、すべてのゲーム・ロジックがこのファイルに含まれることになります。このコードは、サーバーから無作為に英語の単語をその説明と一緒に取得し、プレイヤーによるキーボード入力を処理し、スコアをカウントし、電源を管理するなどの処理を行います。

    コードを見るとわかるように、getNewSecretWord() 関数は、秘密の単語を取得するために、Web サーバー上で /randomword サービスを呼び出します。

  6. このサービスを実装するには、以下のコードを server.js に追加します (最初の変数宣言の後に追加してください)。
    /**
     * 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();
    });

    このコードは、オンライン英語辞書の Wordnik.com を使用して無作為に単語を取得するコードに /randomword URL をバインドした後、wordLookup() を呼び出します。これによって、Wordnik API に対する別の呼び出しが行われ、取得した単語の説明も取得されます。最後に、秘密の単語とその説明が JSON としてエンコードされて、HTTP リクエストのレスポンスとして返されます。

    : 上記のコード・スニペットに含まれる API キーは、多くの人々が共有する無料アカウント用なので、少ししか使用することができません。この制約を回避するには、Wordnik に登録して、独自の API キーを入手してください。

  7. この時点で、いくつかのデバッグ・セッションをローカルで実行し、クライアント・サイドとサーバー・サイドのコードをステップ・スルーして、ゲームが期待通りの動作をすることを確認しておくとよいかもしれません。 ゲームが期待通りの動作をすることを確認している画面のスクリーン・ショット
    ゲームが期待通りの動作をすることを確認している画面のスクリーン・ショット

    クライアント・サイドの JavaScript をデバッグするには、Chrome の組み込みデバッガーを使用します。サーバー・サイドの JavaScript をデバッグするには、前に説明した node-inspector を使用します。node-inspector も同じく Chrome デバッガーを使用して、サーバー・サイドの Node.js JavaScript をデバッグすることに注意してください。

ステップ 4. DevOps Services プロジェクトを作成する

アプリケーションをローカルで実行してデバッグできるようになったので、次のステップではこれまで作成したコードを DevOps Services リポジトリーに保管します。DevOps Services リポジトリーに保管することには、以下のように、いくつもの利点があります。

  • ローカル・コンピューターよりもセキュアなクラウドに、コードが保管されます。
  • 他の人がアプリケーションの開発に貢献できます。
  • Bluemix へのオート・デプロイメントを有効にできます。
  1. アプリケーションのプロジェクトを作成するには、DevOps Services にサインインして「Start coding (コーディングを開始)」をクリックします。Jazz SCM または Git SCM のどちらを選ぶかは、自由に決められます。一般には、どちらの SCM システムのほうが使い慣れているかによります。このサンプル・プロジェクトでは、Git リポジトリーを選択します。このアプリケーションは Bluemix にデプロイすることになるので、「Deploy to Bluemix (Bluemix にデプロイする)」チェック・ボックスにチェック・マークを付けてください。Bluemix 組織とスペースを選択したら、最後に「CREATE (作成)」をクリックします。 プロジェクトを作成する画面のスクリーン・ショット
    プロジェクトを作成する画面のスクリーン・ショット
  2. 新規に作成されたプロジェクトは、いくつかのデフォルト・ファイルを除き、最初は空の状態になっています。プロジェクトにコードを追加するには、「EDIT CODE (コードの編集)」をクリックし、ローカルのファイル・システムからプロジェクトのファイル階層 (左側に表示されるツリー) にファイルをドラッグ・アンド・ドロップします。

    Eclipse を使用してコードを作成した場合は、Eclipse のプロジェクト・エクスプローラーから直接ファイルをドラッグ・アンド・ドロップすることができます。その場合は、(プロジェクト自体ではなく) Eclipse プロジェクトに含まれる個々のファイルとフォルダーを選択して、プロジェクトのファイル階層の最上位ノード (赤でマークされています) にドラッグ・アンド・ドロップする必要があることに注意してください。また、Eclipse では一部のファイル (.project ファイルなど) が非表示にされるので、ローカル・ファイル・システムからドラッグ・アンド・ドロップしなければならないファイルがあることにも注意が必要です。

    現時点で、プロジェクトのファイル階層に、アプリケーションのすべてのファイルが表示された状態になっていなければなりません。

    注意する点として、ローカル・コンピューターから DevOps Services プロジェクトにファイルをコピーしただけでは、変更がコミットされて Git リポジトリーにプッシュされることはありません。つまり、追加したファイルは、他の誰にも表示されないということです。DevOps Services プロジェクトの下に表示されるファイル階層は、クラウドに保管されているという点を除き、ローカル・ファイル・システムと同様の個人的な作業領域だと思ってください。

  3. リポジトリー・アイコンをクリックすると、いくつものコミットされていない変更 (追加したファイルごとに 1 つ) が表示されます。ファイルは「Unstaged (未ステージ)」として表示されます。未ステージとは、リポジトリーにまだコミットされていない変更を意味する Git の用語です。 リポジトリー・アイコンのスクリーン・ショット
  4. 変更をコミットするには、ファイルごとに「Stage the change (変更をステージ)」コマンドを実行します。 ステージ・ボタンのスクリーン・ショット

    これによって、ファイルは「Unstaged (未ステージ)」から「Staged (ステージ済み)」に移されます。「Staged (ステージ済み)」に表示されるすべての変更は、「COMMIT (コミット)」をクリックすると、単一の変更セットとしてコミットされます。このサンプル・プロジェクトでは、単一の変更セットにすべてのファイルを追加する必要がありますが、後で、一部の変更を 1 つの変更セットとしてコミットし、他の変更を別の変更セットとしてコミットしなければならない場合もあります。各変更セットには、論理的に同類の変更が 1 つのグループとしてまとめられることになります。

    「Commit (コミット)」ダイアログに表示されるコミット・メッセージに、変更セットの説明が示されます。場合によっては変更の理由も示されることがあります。

    コミット操作をする画面のスクリーン・ショット
    コミット操作をする画面のスクリーン・ショット
  5. 「SUBMIT (サブミット)」をクリックすると、変更セットが Git にコミットされて、「Commits (コミット)」セクションに単一の変更セットとして表示されます。 コミットされて、まだプッシュされていない変更のスクリーン・ショット
    コミットされて、まだプッシュされていない変更のスクリーン・ショット
  6. 最後のステップは、この変更セットをマスター・ブランチにプッシュして、他の人がそこからファイルを取得できるようにすることです。「PUSH (プッシュ)」をクリックしてから「OK」をクリックすることで、変更をプッシュします。 プッシュされた変更のスクリーン・ショット
  7. 現時点で、コードのローカル・コピーは重複することになります。したがって、これを削除するかどうかを検討しなければなりません。ローカル・コピーで開発を続ける場合は、変更したすべてのファイルを DevOps Services プロジェクトにアップロードして、上記と同じ方法で変更を配布することを忘れないでください。こうすれば、ローカル・コピーで開発を続けることもできますが、混乱しやすく、多少面倒な作業になる場合があります。

    それよりも現実的な手法は、ローカル開発を完全に辞めて、DevOps Services の Web エディターを使用してコードを編集するか、DevOps Services の Git リポジトリーに接続したローカル Git リポジトリーをセットアップするかのどちらかです。ここでは 2 番目の方法を選ぶことにしました。それは、ローカルで開発してデバッグできるようにしたいためです。DevOps Services の Web エディターでは今のところまだ、ローカルでの開発とデバッグには対応できません。

    DevOps Services の Git リポジトリーに接続したローカル Git リポジトリーをセットアップするには、いくつかの方法があります。Eclipse や Visual Studio などの IDE を使用している場合、これらの IDE 用の Git プラグインを使用して、DevOps Services の Git リポジトリーを IDE にインポートすることができます。Git プラグインが用意されていない環境で開発しているとしたら、コマンド・ラインから Git を使用することができます。いずれの場合も、DevOps Services の Git リポジトリーの URL が必要です。この URL は、DevOps Services プロジェクトの概要ページから入手することができます。

    「EDIT CODE (コードの編集)」タブからプロジェクトの概要ページにアクセスするには、左上隅のプロジェクト・リンクをクリックします。

    プロジェクトの概要ページへのリンクのスクリーン・ショット

    次に、「Git URL」リンクをクリックします。

    Git URL へのリンクのスクリーン・ショット
    Git URL へのリンクのスクリーン・ショット
  8. この URL をローカル Git リポジトリーに複製した後は、ローカルでアプリケーションの開発を続けて、DevOps Services の Web インターフェースからではなく直接 DevOps Services の Git リポジトリーに変更をコミットすることができます。Eclipse と EGit プラグインを使用する場合、プロジェクト・ビューは、以下のスクリーン・ショットのように表示されます。Eclipse に EGit プラグインが含まれていないとしても、このプラグインは簡単にインストールすることができます。EGit を初めて使用する場合は、ユーザー・ガイドを参照してください。Git リポジトリーに保管されているアプリケーションのファイルが表示された Eclipse プロジェクトのスクリーン・ショット
    Git リポジトリーに保管されているアプリケーションのファイルが表示された Eclipse プロジェクトのスクリーン・ショット

ステップ 5. アプリケーションを Bluemix にデプロイする

ゲームの開発を続ける前に、この時点で Bluemix への初めてのデプロイメントを行って、正常にデプロイできることを確認しておくとよいと思います。

  1. デプロイメントは、manifest.yml という名前のファイルによって制御されるため、このファイルをアプリケーションのルート・フォルダーの中に作成する必要があります。
    ---
    applications:
    - name: GuessTheWord
      framework: node
      runtime: node08
      memory: 64M
      instances: 1
      host: GuessTheWord
      path: .     
      command: node server.js

    上記の設定は、Bluemix に対し、アプリケーションをデプロイする方法を指示します。例えば、ランタイム (Node.js)、アプリケーションに確保するメモリーの量、そしてデプロイしたアプリケーションの URL で使用するホスト名を指定します。ホスト名は、グローバルに一意でなければならないことに注意してください。したがって、皆さんは「GuessTheWord」以外のホスト名を使用する必要があります。

  2. このファイルを DevOps Services の Web エディターで作成するか、ローカル開発環境で作成するかに関わらず、必ず新規に作成したファイルを DevOps Services の Git リポジトリーにプッシュすることを忘れないでください。
  3. デプロイメントを開始するには、DevOps Services プロジェクトで、「BUILD & DEPLOY (ビルドおよびデプロイ)」ボタンをクリックします。 「BUILD & DEPLOY (ビルドおよびデプロイ)」ボタンのスクリーン・ショット
    「BUILD & DEPLOY (ビルドおよびデプロイ)」ボタンのスクリーン・ショット

    次に、Bluemix にアプリケーションをデプロイするために、ページの上部にあるスイッチを「OFF (オフ)」ら「SIMPLE (簡易)」に切り替えます。

    オート・デプロイメント・ボタンのスクリーン・ショット
  4. スイッチを切り替えると同時に、DevOps Services が Bluemix へのアプリケーションのデプロイメントを試行します。 簡易オート・デプロイメントが有効にされた状態のスクリーン・ショット
    簡易オート・デプロイメントが有効にされた状態のスクリーン・ショット

    また、誰かが変更を DevOps Services の Git リポジトリーにプッシュするたびに、新たなデプロイメントが自動的に行われます。このようにオート・デプロイメントが有効になっていると、例えばテストを実行するのに、常にデプロイ済みのアプリケーションの最新版にアクセスできるので便利です。

  5. 約 30 秒後に、エラーが発生することなく正常にデプロイされたアプリケーションが表示されます。 オート・デプロイメントが有効に設定されたときのメッセージのスクリーン・ショット
    オート・デプロイメントが有効に設定されたときのメッセージのスクリーン・ショット
  6. Bluemix でデプロイ済みアプリケーションにアクセスするには、リストの上にあるリンクをクリックします。 デプロイ済みアプリケーションへのリンクのスクリーン・ショット
    デプロイ済みアプリケーションへのリンクのスクリーン・ショット

ステップ 6. Bluemix デプロイメントをトラブルシューティングする

デプロイしたアプリケーションにアクセスしようとすると、おそらく以下のメッセージが表示されます。

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

このメッセージが表示されるのは、よくありません。明らかに、どこかに問題があります。ローカルではアプリケーションを正常に実行できたので、この問題は、Bluemix 上で実行されているアプリケーションに関連していると考えられます。

このことは、重要なポイントを示しています。つまり、アプリケーションは正常にデプロイされていても、アプリケーションにアクセスできない可能性があるということです。「Recent Auto-Deployments (最近のオート・デプロイメント)」リストに示されている緑色のステータス・インジケーターと「OK」という結果が意味しているのは、アプリケーションが正常にデプロイされて起動されたということだけです。例えば、起動された直後に終了してしまう可能性もあります。その場合、アプリケーションの Bluemix URL にアクセスしようとしても、アプリケーションを使用することはできません。

このような問題をトラブルシューティングするには、Bluemix 上でサーバー・コードをデバッグできると便利です。将来的には可能になると思いますが、今のところ、Bluemix 上でのサーバー・コードのデバッグはサポートされていません。それでは、どのようにすれば良いのでしょうか。

  1. 何が問題かを突き止めるには、DevOps Services 内のログ・ファイルを調べてください。また、Bluemix の cf CLI ツールを使用することで、追加情報を入手できることもあります。以下に一例を示します。
    > 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

    上記の出力では、アプリケーションの状態が「crashing」と示されています。これは、何らかの理由でアプリケーションが終了したことを意味します。Web サーバーが終了されることはないので、Bluemix 上で実行された場合にアプリケーションが終了してしまう理由を突き止める必要があります。

  2. DevOps Services の「EDIT CODE (コードの編集)」タブに、「DEPLOY (デプロイ)」ボタンがあります。このボタンは、まだクリックしないでください。 「DEPLOY (デプロイ)」ボタンのスクリーン・ショット

    このボタンは、個人の DevOps Services プロジェクト領域の内容を、手作業で Bluemix にデプロイする場合に使用します。トラブルシューティングする際には、このボタンが役立ちます。それは、手作業でデプロイすることによって、master ブランチにはコミットしたくない一時的なロギングやその他の実験を追加できるためです。「DEPLOY (デプロイ)」ボタンをクリックする前に、master ブランチから受信されるすべての変更セットを取得して、DevOps Services プロジェクト領域を最新の状態にする必要があります。

  3. 「Git Status (Git ステータス)」ページにアクセスして、「FETCH (取得)」ボタンをクリックします。受信される変更セットは、「Commits (コミット)」セクションに表示されます。「MERGE (マージ)」ボタンをクリックして、受信されるこれらの変更セットを DevOps Services プロジェクト領域にマージしてください。
  4. これで、「DEPLOY (デプロイ)」ボタンをクリックして、手作業でデプロイできる用意ができました。アプリケーションが Bluemix にデプロイされると、以下のメッセージが表示されます。 手作業でのデプロイメントの準備ができたことを示すメッセージのスクリーン・ショット
    手作業でのデプロイメントの準備ができたことを示すメッセージのスクリーン・ショット
  5. 上記のメッセージに示されているルート・フォルダー・ページへのリンクをクリックすると、手作業でのデプロイメント情報が表示されます。 Bluemix にデプロイされたアプリケーションが実行されていないことを示すメッセージのスクリーン・ショット
    Bluemix にデプロイされたアプリケーションが実行されていないことを示すメッセージのスクリーン・ショット
  6. 赤いインジケーターによって、アプリケーションが実行されていないことが確認されます。「Logs (ログ)」リンクをクリックして、アプリケーションが終了する前に生成したログを表示してください。 各種ログ・ファイルのスクリーン・ショット
  7. stdout.log ファイルを開きます。 stdout.log ファイルの内容のスクリーン・ショット
    stdout.log ファイルの内容のスクリーン・ショット

    このログを見れば、瞬時に問題を理解できるはずです。このログから、Web サーバーはハード・コーディングされたホスト名 (localhost) とポート番号 (3030) の使用を試行していることがわかります。サーバーをローカルで実行する場合は、これで問題ありませんが、Bluemix 上で実行する場合はその限りではありません。

  8. この問題を解決するには、server.js ファイルで、host および port 変数宣言の直後に以下のコードを追加します。
    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;	
    }

    Bluemix は、VCAP_SERVICES という環境変数を使用して、サーバーに対して環境に関する情報を渡します。hostport は、そのような情報の例です。サーバーをローカルで実行するときには、VCAP_SERVICES が設定されないため、上記の if 文は実行されません。したがって、この変更を加えた後でも、アプリケーションをローカルで実行してデバッグすることができます。

  9. この変更を Git リポジトリーにプッシュして、オート・デプロイメント機能にデプロイメントの処理を行わせます。すると、デプロイメントが正常に完了したことが示されます。 ハード・コーディングされたホストとポートを使用しないように変更したアプリケーションのオート・デプロイメントの結果のスクリーン・ショット
    ハード・コーディングされたホストとポートを使用しないように変更したアプリケーションのオート・デプロイメントの結果のスクリーン・ショット
  10. デプロイ済みアプリケーションへのリンクをクリックすると、ちょっとしたお祝いをしたくなる理由が見つかります。 Bluemix 上で実行中の GuessTheWord ゲームのスクリーン・ショット
    Bluemix 上で実行中の GuessTheWord ゲームのスクリーン・ショット

    見事、Bluemix 上でゲームが実行状態になりました。

  11. トラブルシューティングのご褒美として、これで、休憩してゲームを楽しめます。バッテリーが切れるまで、いくつの単語を当てられるか試してみてください。

ステップ 7. データベース・サービスを追加する

高いスコアが出ましたか?おめでとうございます!スコアが保存されず、あなたが単語を当てるのがどんなに得意なのかを世間に公表できなければ残念です。そこで、これからスコアをデータベースに保存できるようにします。皆さんの中には、この小さなデータを保存するのにデータベースを使うまでのことはないと思う方がいるかもしれません。単純に、サーバー上のテキスト・ファイルにハイスコアのリストを保持するという方法もありますが、この場合、それは賢明な方法ではありません。それは、Bluemix サーバーは常に同じ物理マシン上で稼働するわけではないからです (ロード・バランシングのため)。したがって、ファイルを使用してデータを永続化することはお勧めできません。代わりに、ある種のクラウド・サービスを使用して、データの永続化に対処します。

クラウド・ストレージ・ソリューションには、いくつもの選択肢がありますが、話を複雑にしないで、ここでは Cloudant データベース・サービスをアプリケーションに追加します。

  1. Bluemix Web アプリケーションにアクセスするには、「BUILD & DEPLOY (ビルドおよびデプロイ)」タブで、「MANAGE (管理)」ボタンをクリックします。 「MANAGE (管理)」ボタンのスクリーン・ショット
    「MANAGE (管理)」ボタンのスクリーン・ショット
  2. これによって、Bluemix に GuessTheWord アプリケーションが表示されます。このアプリケーションは実行中になっていますが、このサービスに関連付けられているサービスは 1 つもありません。新しいサービスを追加するために、「Add a service (サービスを追加)」をクリックします。Bluemix カタログの「Data Management (データ管理)」セクションで、「Cloudant JSONDB」を選択します。 Bluemix に表示された Cloudant アイコンの画像
  3. このサービスをクリックし、ダイアログでは「Create (作成)」をクリックします。すると、アプリケーションが再起動されますが、これにはわずか数秒しかかからないはずです。続いて追加されたサービス上で「Show Credentials (資格情報の表示)」をクリックします。 Cloudant データベース・サービスを追加するためのダイアログの画像
    Cloudant データベース・サービスを追加するためのダイアログの画像

Cloudant アカウントは、生成されたユーザー名とパスワードを使用して自動的に作成されます。以下のステップでデータベースにアクセスするためのコードを作成する際に、url フィールドの値が必要になるので、この値をコピーします。

ステップ 8. Cloudant データベースを使用する

  1. Cloudant NoSQL DB サービスをクリックし、「Launch (起動)」をクリックします。これにより、Cloudant Web UI が表示されます。この Web UI ではデータベースを構成および管理することができます。 「Launch (起動)」ボタンの画像
  2. guess_the_word_hiscores という名前の新規データベースを作成します。次に、ボタンをクリックして、新しい 2 次インデックスを作成します。top_scores という名前の文書に保管し、インデックスに top_scores_index という名前を付けます。 Cloudant DB に 2 次インデックスを作成する画面のスクリーン・ショット
    Cloudant DB に 2 次インデックスを作成する画面のスクリーン・ショット
  3. map 関数は、インデックスで分類するデータベース内のオブジェクト、そしてそれらのオブジェクトに関して取得する情報を定義します。スコアをインデックス・キー (emit の 1 番目の引数) として使用した後、スコア、プレイヤーの名前、そのスコアを出した日付が含まれるオブジェクトに対して emit を実行します。以下に、map 関数の JavaScript 実装を示します。これをコピー・アンド・ペーストしてください。
    function(doc) {
     emit(doc.score, {score : doc.score, name : doc.name, date : doc.date});
    }
  4. 次は、Cloudant データベースにスコアを保管するために必要なコードを作成しましょう。今回は、DevOps Services の Web エディターを使用します。Cloudant にアクセスするために使用する Node.js ライブラリーを決める必要があります。この例では nano ライブラリーを使用することにしました。

    DevOps Services のファイル階層で、package.json ファイルをクリックします。次に、以下に示す行 "nano" : "*" を追加します。この行によって、アプリケーションに最新バージョンの nanoライブラリーが組み込まれます。

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

    ホストとポートの場合と同じく、Bluemix は VCAP_SERVICES 環境変数を使用して、Cloudant データベース・サービスに関する情報 (このサービスが実行されている場所、ログインするために使用する資格情報など) をアプリケーションに指示します。以下のコードでイタリック体になっている行を server.js ファイルに追加してください (訳注: コードはイタリック体になっていませんが、対象行は var cloudant = { の行から、この波括弧を閉じている行 }; までと、コメント行 // Also parse out Cloudant settings. から最後の行 var db = nano.db.use('guess_the_word_hiscores'); までのようです)。URL ストリング ("<url>”) は、先ほどサービスの資格情報からコピーした値に置き換えます。

    var express = require('express');
    var app = express();
    var http = require('http');
    
    var host = "localhost";
    var port = 3030;
    var cloudant = {
    		 		 url : "<url>" // TODO: 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['cloudantNoSQLDB'][0].credentials;  
    }
    var nano = require('nano')(cloudant.url);
    var db = nano.db.use('guess_the_word_hiscores');

    おわかりのように、上記のコードはアプリケーションが Bluemix 上で実行されていない場合も動作します。ローカルで実行されている場合、アプリケーションは Bluemix 上で実行されているときと同じように Cloudant データベースを使用することができます。

  5. ここで、以下の 2 つの新しい URL をサーバー内で処理してみましょう。
    • /hiscores (ハイスコアの上位データをデータベースから取得する場合に使用)
    • /save_score (新しいハイスコアをデータベースに保存する場合に使用)

    そのためのコードは、以下のとおりです。

    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. これらの新しい URL に対する呼び出しは含めていませんが、ブラウザーから上記の URL を直接呼び出すことで、データベース接続をテストすることはできます。

    「Git Status (Git ステータス)」をクリックして、すべての変更を DevOps Services の Git リポジトリーにプッシュし、アプリケーションが Bluemix にデプロイされるまで待ちます。デプロイが完了したら、以下の URL をブラウザーに入力します。この URL に含まれる guesstheword は、アプリケーション用に選択したホスト名で置き換えてください。

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

    成功のメッセージが表示されるはずです。ここでも、以下の URL の guesstheword をアプリケーションのホスト名で置き換えて、この URL を入力してください

    http://guesstheword.mybluemix.net/hiscores

    追加したエントリーが、JSON にエンコードされて表示されます。

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

    このコードは、データベースを使用するためのコードが正しく動作していることを示しています。

  7. 今度は、ゲームのメイン・ページに表示されるスコア表にデータを取り込むための JavaScript ファイルを作成します。Web エディターで、public/js フォルダーを右クリックして「New (新規)」 > 「File (ファイル)」の順に選択します。 Web エディターでファイルを作成する画面のスクリーン・ショット

    新しく作成するファイルには hiscores.js という名前を付けて、以下の内容を追加します。

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

    上記のコードは、スコア表に、データベースから取得したハイスコアを取り込みます。変更を DevOps Services の Git リポジトリーにプッシュして、アプリケーションが Bluemix へ再デプロイされるまで待機してください。これで、アプリケーションにアクセスすると、以前にデータベースに追加した適当な値のスコアがエントリーとして表示されるはずです。

    ハイスコア表のスクリーン・ショット
    ハイスコア表のスクリーン・ショット
  8. ゲームが終わると得点が保存されるようにするためには、いくつかの修正が必要です。main.js ファイルで、以下の行を見つけてください。
    // TODO: Save name and score in DB

    この行を、以下の行で置き換えます。

    saveScore(name, score);

    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. 最後に、Bootstrap の「ゲーム・オーバー」ダイアログを作成するために、main.jade ファイルの最初の div として、以下のコードを追加します。
    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. 変更をプッシュし、オート・デプロイメントが完了するのを待ってから、ゲームをプレイして、スコアがデータベースに保存されてメイン・ページのスコア表に表示されることを確認します。 最終的なゲーム画面のスクリーン・ショット
    最終的なゲーム画面のスクリーン・ショット

まとめ

この記事では、IBM DevOps Services を使用して GuesstheWord ゲームを作成し、このアプリケーションを Bluemix にデプロイしました。このプロセスの中で、Web エディターまたは Eclipse (あるいは別の IDE) でコードを開発し、そのコードを IBM DevOps Services の Git リポジトリーにプッシュする方法を説明しました。また、変更がプッシュされると同時にアプリケーションが再デプロイされるように、オート・デプロイメントをセットアップする方法も説明しました。さらに、アプリケーションをローカルでデバッグする方法、アプリケーションを Bluemix 上で実行するときに発生する可能性がある問題をトラブルシューティングする方法もわかったはずです。これで、独自の Bluemix アプリケーションを開発する準備は万端です。


ダウンロード可能なリソース


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=979191
ArticleTitle=Bluemix 上で Cloudant を使用してシンプルなワード・ゲームを作成する
publish-date=11062014