2015年12月10日 (木)

react + redux + react-router のサーバサイドレンダリングを試してみた

こんにちは、ジャバスクリプターの三宅です。
react + redux + react-router を用いたアプリケーションのサーバサイドレンダリングの情報が見当たらなかったので試してみました。

React はご存知の通り、Facebookが開発を行っている、JavaScript フレームワークです。
React は View 部分のみのフレームワークとなり、フロントエンドアプリケーション全体は別途考える必要があります。
Facebook は Flux というアーキテクチャを提唱しており、Redux はその実装となります。
React Router は、React アプリケーションでルーティングを行うためのライブラリでです。
react や redux、react-router の基本的な使い方は、公式ドキュメントや様々なブログで紹介されているので今回は、サーバサイドレンダリングの部分に絞って解説します。

アプリケーション全体のコードは、GitHub にアップロードしています。
動作サンプルのように、簡単なメモアプリケーションで、リクエスト時に初期値を生成して初回ロードに含めるような動作になります。
下の Heroku Button を使って、自身の Heroku アカウントにデプロイして動作を確認することができます。

Deploy

ローカルで動作させる場合は、リポジトリをクローンして、以下のコマンドを実行してください。

cd react-study
npm install
npm run-script build
npm start

環境

以下の環境やバージョンで動作を確認しています。
どのライブラリも開発が活発で、APIの変更を伴うバージョンアップも頻繁に行われています。
そのため、過去のサンプルコードが動かないということがよくあります。。

  • ランタイム
    • Node.js: v5.1.0
    • npm: 3.3.12
  • Babel関連
    • babel-core: 6.2.4
    • babel-polyfill: 6.2.4
    • babel-preset-es2015: 6.2.4
    • babel-preset-react: 6.2.4
    • babel-preset-stage-2: 6.2.4
  • React関連
    • react: 0.14.3
    • react-dom: 0.14.3
    • redux: 3.0.4
    • react-redux: 4.0.0
    • react-router: 1.0.1
    • history: 1.13.1

react-router が依存する history の最新バージョンは 1.15.0 ですが、react-router が deprecated の API を利用しており、Warning が発生するので上記のバージョンを利用しています。
react-router の v1.10 で対応が予定されているようです。
また、redux-router という、redux と react-router を接続するライブラリもあるのですが、まだ β 版である事、複雑な設定が必要である事から、今回は利用していません。

なぜサーバサイドレンダリング??

アプリケーションの説明の前に、なぜサーバサイドレンダリングが話題になっているのかについて少し触れたいと思います。
シングルページアプリケーションでは、サーバサイドでは API サーバとしてブラウザから要求されたデータを返す、クライアントサイドでは JavaScript を用いて DOM を構築する、という構成になりますが、以下の問題があります。

  • 初期ロード時間
    • JavaScript がブラウザにダウンロードされ、評価されてからレンダリングが開始される、また評価後にサーバにデータを取得してレンダリングを行うため、初回ロードがどうしても遅くなります。特に、非力なスマートフォンなどでは顕著になります。
  • SEO
    • Google はクローラが JavaScript を解釈してくれるため問題はありませんが、そうでないクローラに対してはコンテンツのない Web ページとしてインデックスされてしまします。

そのような問題を解決するために、React では URL やデータの状態に基づく HTML をサーバサイドでレンダリングし、ブラウザで動作するクライアントサイドのアプリに、その状態を引き継ぐことができるようになっています。
Ember.js も次のバージョンからサーバサイドレンダリングがサポートされ、Angular 2 にも取り入れようという話が出てきているようです。

サーバサイドで HTML の出力

Express のミドルウェアとして次のように定義しています。

import express from 'express';

import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RoutingContext } from 'react-router';
import { Provider } from 'react-redux';
import uuid from 'node-uuid';
import moment from 'moment';

import routes from '../../client/routes';
import configureStore from '../../client/store/configure-store';


var router = express.Router();

router.get('/', (req, res, next) => {

  match({
    routes,
    location: req.originalUrl
  }, (err, redirectLocation, renderProps) => {
    if (err) {
      next(err);
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      const initialState = {
        memos: [{
          id: uuid.v4(),
          text: 'Initial Text',
          date: parseInt(moment().format('X'))
        }]
      };

      const store = configureStore(initialState);

      const markup = renderToString(
        <Provider store={store}>
          <RoutingContext {...renderProps} />
        </Provider>
      );

      res.render('main', {
        title: 'react-study',
        markup: markup,
        initialState: JSON.stringify(initialState)
      });
    } else {
      let err = new Error('Not Found');
      err.status = 404;
      next(err);
    }
  });

});


export default router;

match は react-router が提供するメソッドで、リクエストの URL と ルーティング定義に基づいた renderProps を算出してくれます。
RoutingContext に renderProps を渡すことで、URL の状態に一致したアプリケーションを取得することができます。
Provider は redux が提供するコンポーネントで、initialState が設定された store を与えることで、その store の状態に基づくアプリケーションを所得できます。
renderToString メソッドで HTML を取得し、jade のテンプレートに渡してレンダリングしています。

extends layout

block content
  div#app!= markup
  script.
    window.__INITIAL_STATE__ = !{initialState};
  script(src="/javascripts/bundle.js")

jade のテンプレートは上記のようになっています。
生成した HTML である markup と initialState を渡すようにしています。
通常の変数の渡し方だとエスケープされてしまうので、!= を用いてエスケープされないようにしています。

ブラウザでの初期値の設定

initialState の値をもとに、サーバサイドレンダリングされた HTML と、ブラウザのアプリケーションの状態を一致させます。

import React from 'react';
import { render } from 'react-dom';
import { Router } from 'react-router';
import { createHistory } from 'history';
import { Provider } from 'react-redux';

import routes from '../../client/routes';
import configureStore from '../../client/store/configure-store';


const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);

render(
  <Provider store={store}>
    <Router history={createHistory()} routes={routes} />
  </Provider>,
  document.getElementById('app')
);

サーバサイドで生成された HTML には react によってチェックサムが設定されており、ブラウザで render メソッド実行時にアプリケーションの状態、すなわち DOM が一致しているかどうかの確認が行われます。
もし、不一致があれば、ブラウザが保持するアプリケーションの状態に再レンダリングされます。

サーバサイドとクライアントサイドのソースの共通化

今回のサンプルでは、react に関連するアプリケーションは /src/client 以下にまとめています。
react-dom のメソッド - サーバ上では renderToString 、ブラウザ上では render - の実行部分以外では、サーバサイドとクライアントサイドは完全に同じソースコードを利用しています。
今回は記述していませんが、UI コンポーネントのテストも容易に行うことができるようになると思います。

まとめ

非常に簡単なアプリケーションですが、react + redux + react-router を用いたアプリのサーバサイドレンダリングを解説してみました。
今回クライアントサイドのアプリケーションはサーバから初期値を受け取った後は独立して動くようにしていますが、どのタイミングでクライアントサイドとサーバサイドのデータを一致させるかは、React アプリを構築する上で重要な部分になってくると思います。
また、アプリケーションが保持するデータをすべてピュアなオブジェクトとしています。もし、immutable.js を使うのであれば、immutable オブジェクトのシリアライズ、デシリアライズを実装する必要があるでしょう。

実際に React を用いたアプリケーション開発で考えるべきことについては、今後も検証を進めていきたいと思います。

2015年12月 4日 (金)

Javaの勉強会にいってきたよ!

こんにちは、なかやまです。

先月Javaの勉強会に遊びにいってきたので、そのアウトプットです。

1

 

最近はSalesforceと、Playframework(Java)の開発を半分ずつしてます。

2

 

11月にJavaの大きなイベントがあるようなので、行ってみたくなりました!

3

 

去年まではiPadでお絵かきして、ブログにアップしていたのですが、今年はノートスタイルに切り替えました。勉強会で机がある席だとめちゃくちゃ嬉しいです。

4

 

まずは、11/14の JavaOne報告会から!

5

Javaone_1

ダークカナリアリリース、こんな仕組みがあるんですね。本番に影響でないテスト環境。すばらしい。

 

Javaone_2

 最近はSalesforceばっかりやってたので、コンパイルとか懐かしい。

Javaone_3

JavaOneの写真をちら見しましたが、楽しそうでした!

 

次に11/28のJJUG!

6

 

イベントは午後からだと思っていたので、基調講演を聴き逃しました。。

Jjug_1

jstackつかってみます! 

Jjug_2

Jjug_3

 

Jjug_4

Java歴浅くても聴きやすいセッションが多かったので、来年はがっつり参加したい。

 

 

 

最後にお知らせ。

会社の勉強会を12/22に企画してます!

7

1回目はハンズオンでモクモクしましたが、今回はHeroku・IoT周りのお話になりそうです。興味がある方は遊びにきませんか!

8

・flectのDoorkeeper

https://flect.doorkeeper.jp/

イベントページは鋭意作成中です、来週には出来上がるはず。

もう少しお待ちください!

2015年11月27日 (金)

HerokuのRouting機能はErlangでできている。

どうも。 最近、ブログを書こうにも動作検証の時間が取れずに困っていた、おっぴーです。

ということで、なにか良いネタはないかなぁ、と思っていろいろ探していたところ、Herokuのプラットフォームからフリーソフトウェアが生まれたことを発見、というか気付きました。

動作確認などはできていないのですが、PaaSの裏側をつくる仕組みとして興味がそそられる方もいるんじゃないか、と思いましたので、ここで紹介いたします。 (少しは動かせよ、という話ですが。。。)

フリーソフトウェアの名前は、Vegur(ベーグル、に近い発音のようです)といい、アイスランド語で道という意味らしいです(たぶん。 CowboyというErlangで書かれた軽量のWebサーバーをベースに開発されており、VegurもErlangで実装されています。

長年、HerokuのRouting機能をになってきたと同時に、最近、新しく発表されたHeroku PrivateSpacesにも利用されている技術であるとのことです。 たしかに、弊社のブログを遡っていると、もともとHerokuにアクセスしたときのレスポンス時のHeaderにもVegurという文字列が含まれておりました

HTTP/2(SPDY)やQUICなど新しいプロトコルには対応していないようですが、これからHerokuのサービスが向上してゆくごとに進化していってくれると思われます。 このほかできることのすべては、HerokuのDevCenterに記載されている、と説明されており、 ちゃんとDevCenterでドキュメント化をすすめているHerokuさんの面目躍如、と言った感じでしょうか。

Herokuはこうした基盤まわりではErlangのヘビーユーザーでもあるらしく、Erlangの勉強をされたい方もプロダクトとして目を通しておくのも良いのではないかと思います。

今回は、時間がないのでこの辺で。

  • 参考情報
  • https://engineering.heroku.com/blogs/2015-10-21-vegur-free-software/

2015年11月26日 (木)

Herokuサポートのご紹介

こんにちは、最近米俵2俵のお米の重みを体感した浅野です。

Herokuサポート、なかなか利用する機会がなくてどんなものか情報が少ないですよね。 (私自身も今回のプロジェクトで初めて使いました) ということで、簡単にどんなことができるかを紹介していきます。

エンタープライズ契約で使っているアカウントなので、個人でHerokuを使っている方と表示されているものが違うかもしれません。

サポート依頼はどこから出せるの?

  1. Herokuのトップページのメニューから「Support」を選択し、Supportページを開きます。
  2. 次に、「Get help now」を選択し、 Helpページを表示します。

Supportindex_2


これで、サポートのトップ画面が表示されます。このページの「Open a ticket」からサポートチケットを起票できます。 とはいえ、HerokuはDevCenterの情報が充実しているので、まずDevCenterの情報を確認してください。(DevCenterに書いている情報をよく読めば解決できた、は結構あります。)

サポートチケットの起票

サポートチケットの記入はこんな感じです。

Supportticket0


まずは、「What can we help you with?」で問い合わせ対象を選択します。 現時点では、下記の6つが選択できます。

  • Application Issue
  • Heroku Postgres or Redis Issue
  • Add-on Issue
  • Billing, Payments or Account Issue
  • Product Feedback
  • Security Vulnerability Reports or Legal Issue

あとは、この選択した種類に応じてHerokuアプリケーション、対象となるDB・アドオン、問い合わせの優先度等を入力していきます。

「May Heroku staff access your applications's production environment?」はHerokuの担当者が問題解決の為に対象環境(ソースコード、アドオン)に対してのアクセスを許可するかのチェックです。問題の種別によっては、許可すると、問題解決までの時間が短縮されるかと思いますので状況に応じて選択してください。

詳細の記述は、Github Flavored Markdownが使えるので、楽ちんですね。Web上に上がっている画像であれば通常通り貼り付けられます。

サポート依頼をウォッチする

サポート依頼を送ると、チケットがクローズされるまでサポートトップ画面の「Your Support Requests」にそのチケットが表示されます。ここからチケットの質問内容・Herokuサポートからの応答等が確認できます。

Supportticket1_2


ここで、Herokuサポートと直接やり取りを行えます。 直接問い合わせを行っていた方の印象では、応答速度は中に人が入っている割には速いとのことでした。

サポート依頼をシェアする

このチケット画面の右上に「Share Ticket」というボタンがあります。このボタンから、このチケットを同じ組織の別ユーザと共有することができます。 この操作で、他のメンバーもこのチケットへアクセスすることができます。 こんな感じで共有したいユーザをチェックします。

Supportticketshare


(シェアしないと、「例のみんなが困ってたのHerokuサポートに依頼だしました、URLここです」とURLを送られてもアクセス権がなくて見られないのです)

シェア機能は、便利だなーと思いつつも、組織アカウントに紐づく問い合わせなら、ダッシュボードの組織アカウントの中に導線が作られて自動的に見られるようになれば…と感じております。

過去の問い合わせを参照する

過去の問い合わせの参照は、サポートトップ画面の「Ticket history」を選択します。 これを選択するといわゆる一覧画面に遷移します。

Supporthistory_2


以下の4つのチケットの状態でフィルタをかけることができます。

  • All
  • In Progress
  • Awaiting my response
  • Closed

と、こんな感じがHerokuサポートでできる事の一覧でした。

実際の案件でのやり取りだったので、お見せできずボカした箇所が多々ありましたがどんな感じか雰囲気だけでも掴んでいただければ幸いです。

もっとこんな事できるよ!などあれば是非コメントをお願いいたします。

2015年11月13日 (金)

Babel 6をいろいろ試してみた。

こんにちは、三宅です。
ECMAScript6を書くジャバスクリプターの強い味方「Babel」の大きなバージョンアップが10/29に行われました。

6.0.0 Released

ちなみに、このブログを書いている時点ではバージョンが6.1.19となっていて、かなりのスピードでアップデートが行われているようです。

Babel 6は次世代のJavaScript開発のプラットフォームとなることを目標に、かなり破壊的な変更が行われています。
中でも、以下の変更は大きな影響があると考えています。

  1. トランスフォームなどの機能をモジュールとして提供する形態へのアーキテクチャの変更
  2. プラグインAPIの変更

1についてはBabel単体は何もせず、トランスフォーム等を行うプラグインを追加する必要があるようになっています。
2はこれまでBabel 5.xで提供されていた機能の範囲を利用していた人には大きな影響はないかもしれませんが、他のでデベロッパが開発したプラグインを利用していた人は、Babel 6への対応が行われているかの確認が必要になるでしょう。

個人的には、Babelの方向性の変更は良いと思っているのですが、しばらくは5.xのようにトランスパイラとして使いたい…という事で、これまで利用していたgulpやBrowserifyなどの様々な形態で、問題なく利用できるかどうか試してみました。

babel-experiment

ES6のコードには、Modules、Arrow Function、Class、Template Stringsを含んでいます。
そのコードに対して、CLI、Browserify + babelifyによるES5への変換、Mochaによるテストの実行、またgulpfile.js自体のES6の記述と、gulpを通したbabelとmochaの実行を行いました。
それぞれ、簡単に説明していきます。

babel-cli

Babel 6ではCLIから利用する際は、babel-cliを用いるようになりました。
ローカルにbabel-cliをインストールし、/node_modules/.bin/babelを利用しています。

babel cli/src -d cli/dist

Browserify

フロントエンドのコードを書くときにはほぼ必須のBrowserify。
トランスフォームにbabelifyを指定して実行しています。

browserify -t babelify browserify/src/index.js -o browserify/dist/index.js

Mocha

テストランナー。
コンパイラとして、babel-coreを指定しています。

mocha --compilers js:babel-core/register --reporter nyan mocha/test

gulpfile.jsとgulpタスクの実行

gulpfile.babel.jsという拡張子にすることで、ファイルの読み込み前にbabel-core/registerが呼ばれトランスフォームされてから実行されます。
gulpタスクの実行は、今まで通り gulp ${taskname} で大丈夫です。


今までプロジェクトで利用したことのある、問題なく変換・テスト等を実行することができました。

.babelrcの記述

5.xではCLIやgulp-babelでの実行時にオプションを渡して実行していましたが、6からは.babelrcで設定を記述することが推奨されているようです。
.babelrcはpackage.jsonと同じ階層、プロジェクトルートに配置します。CLIやgulp-babelでの実行、mochaやbrowserifyのオプションとして指定した場合でもすべて、その設定を読み込んで実行されます。

{
  "presets": ["es2015", "stage-2", "react"]
}

今回の.babelrcはこのような記述となっています。
Babel/FAQを参考に、Babel 5.xと同じ出力結果を得ることのできるよう「es2015」、「stage-2」、「react」のプリセットを指定しています。
プラグインを利用する場合は、.babelrcに以下のようにpluginsを追加します。

"plugins": ["transform-react-jsx"]

Babel 6になって大きな変更が行われましたが、自分の利用している範囲では問題なく動きそうで一安心です。
毎日アップデートが行われていてまだドキュメントが完全に整備されていないなど、まだ安定しているとは言いがたい状態ですが、今後どのように進化していくのか楽しみでもあります。
今回の記事が、Babel 6への移行の方法や、Babel 5.xを使い続けるかの判断の助けになればと思います。

2015年11月 6日 (金)

会社でハロウィンやってみた。

こんにちは、なかやまです。

今日は技術よりな話ではなくて、ごめんなさい。

先月末のハロウィンで会社でやったイベントについてお話させてください~

_01

 

もともとハロウィンの文化がなかった会社。

仮装はさておき、お菓子があったら幸せだよね、と思う。

_02

 

お菓子を山盛りにして、みんなで食べたいです!とお話しして、予算をゲット。

2015_11_06_13_40_06

 

Herokuといえば、折鶴!(無理やり混ぜ込んだ感ですが)

何か折り紙できたらいいよね!と考える。

_03

 

みんなに協力してもらい、星の折り紙をおることになりました!

_09

ストライプの折り紙で折ると、星の中にも星がでてきておしゃれになりました。
2015_11_06_11_03_55

 

クモも作ってもらいましたが、ストライプ柄で作るとなんとかわいいこと!!

2015_11_06_13_13_27

 

かぼちゃのでかい置物がおきたかったので、Amazonで注文。

空気を入れるのに苦労しました。

ゴミ袋を利用すると、あっという間に入るそうです!

_08

 

膨らませると、130cmになります。

2015_11_06_11_03_37

 

上野の二木にお菓子を買いにいきました。

あめ1kgとか、こんな機会でもないと買わないですね。

_05

 

たくさんのお菓子。

2015_11_06_10_57_43

 

さらにチロルチョコにプリントしてくれるサービスがありまして、

そこで会社のロゴ入りのチロルチョコを作りました。これもかわいくできましたよ!

_06


2015_11_06_10_54_40

 

お昼休みに、かわいい袋にお菓子をつめる。

100袋を目指しました!

2015_11_06_10_58_41

 

そして盛り付けた図。

2015_11_06_10_53_21

 

会社の受付はこんな感じになりました!

2015_11_06_10_56_05

 

 

最初はどうなるかと思いましたが、いい感じに楽しむことができました!

次は200袋作りたいですね。

ハッピーハロウィン~

2015年10月29日 (木)

Wercker v2(Ewok)でSpringBootのビルド時間を短縮する

ブログには久しぶりの登場、浅野でございます。 戻り鰹の漁にいっており、ブログが更新できておりませんでした。

さて、今回のネタは久しぶりのWerckerネタ。ターゲットは以下の条件全てに当てはまる方です。

  • JVM系の言語を使っている
  • Werckerをv1のころから使っていて、v2へ移行している
  • Werckerは、v1ではキャッシュがあってビルドで余分な時間かかんなかったのになーと懐かしんでいる

これで大体わかるかと思うのですが、v2(Ewok)でキャッシュが使えるようになってました。 情報ソースは公式サイトのこちら。(Werckerをキーワードに検索するとV1の情報とごっちゃになってしまってわかりづらいので v2の情報だけに絞り込むには、ewok をキーワードに追加するといいらしいです)

キャッシュを有効にする

環境変数 $WERCKER_CACHE_DIR のパスがキャッシュとして使えるディレクトリです。 このディレクトリ配下に、gradleがダウンロードするファイルを格納すると、次回以降のビルド時にはダウンロードが省略されてビルド時間が短縮されます。 その設定はこんな感じ。

- script:
    name: setup gradle local cache
    code: |-
        mkdir -p $WERCKER_CACHE_DIR/.gradle
        ln -sf $WERCKER_CACHE_DIR/.gradle ~/.gradle

こうする事で、SpringBootベースのWebアプリケーションのビルド時間が約4.5分から約2.5分と2分前後の短縮になりました。 この $WERCKER_CACHE_DIR がキャッシュ用ディレクトリになるのは、v1でも同じでした。過去に蓄積したノウハウがそのまま使えるのは嬉しい限りですね。 (前の案件は、Wercker v1を使っていて、その時にwerckerでmavenのpomをキャッシュする方法を参考にSBTのビルド時間を短縮した、というのがあり、今回もそれをほぼそのまま踏襲できました。)

この手順は、今回題材にしたgradle以外のビルドツールでも使えるかと思います。 ただ公式サイトに書いてある通り、 npm-install, bundle-install, pip-install に関してはデフォルトでキャッシュが効くので対応不要です。

それでは、みなさんもよきCIライフを!

2015年10月20日 (火)

DynoTypeが2ヶ月前に増えていたのご存知ですか?

はい、どうも。 最近、料理をサボりがちのおっぴーです。

じーちゃんも目を見開いて喜んだPrivateSpacesの登場がフレクトの社内でも話題になっております。 現在はPrivateβ版ということでGAになるのが楽しみですね。

こうしたHerokuのサービスについて、公式で最新情報を知る一番の方法は、Herokuの公式ブログをみることですね。 普段からこのブログの内容に目を通したい人は、ここからフィードの購読登録しておくのがお薦めです。

また、サービスの変更履歴はつどtwitterにも流れているので、こちらをフォローするもよい方法ですね。

個人的には「最近、Herokuは積極的にサービスをアップデートしているな!」と感じており、そのすべてをこのブログでご紹介したいと思いつつ、紹介しきれていない、というのが実情です。

今回は、ご紹介できなかったことの1つとして新たなDynoTypeが増えました!というお話です。 約2ヶ月も前のお話ですが、お付き合いくださいませ。

以前、PeformanceDynoのスケールアップについて速報としてお伝えしたあと、ほとんど間をおかずに発表された内容です。 しかもその際に、

「とくに2XDynoとPXDynoの間を埋める性能の新Dynoの登場があるとうれしい」

と書いていたのですが、それを実現するようなアップデートで発表された時はびっくりしたものです。 このアップデートにより、performance-mというDynoが登場し、いままでperformance Dynoと呼ばれていたDynoはperformance-l(える?と読むのかな)という名前になりました。

dyno type memory compute price
standard-1x 512MB 1-4X $25/mo
standard-2x 1GB 2-8X $50/mo
performance-m 2.5GB 12X $250/mo
performance-l 14GB 50X $500/mo

フレクトではBtoB向けのシステム構築の際でも、Herokuをよく利用しています。 こうした時にシステム構築で、重要なのは、選択肢の多さです。 選択肢が多いほど、良い選択をするのは大変なのですが、一方で、提案内容の幅が広がり顧客が達成したいことにあわせたご提案がしやくすなります。

今回のDynoTypeが増えたという件については、HerokuはAWS上に構築されるPaaSなので、おそらく技術的な課題はあまり多くなかったのではないか、と勝手に推測しています。 というのも、AWSには多数のインスタンスタイプがあり、ハードウェアまわりのパフォーマンスのスケールアップはお手の物、対応するインスタンスタイプをHerokuが増やしただけと考えられるからです。

こうしたことからDynoTypeへの対応は、技術的な興味がそそられるものではないかもしれませんが、上記のとおりHerokuの用途を広げ提案の幅を広げてくるという点からビジネス的には大きな価値を感じています。

わたしとしても、個人の開発者としては無料でできることが広がった方がうれしい気持ちはあるのですが、実際のビジネスにおいては提案の幅が広がり、安定したパフォーマンスを実現できるDynoが増やしてほしいというニーズのほうが大きいからです。

そして、アップデート内容を見ていると、Herokuが私たちのビジネスに寄り添った考え方をして、サービスをアップデートしてくれている、という安心感がもっています。 また、今後もサービスを拡張していってくれる期待感ももっています。

実際にHerokuを利用して、エンタープライズ系のシステムづくり取り組んでいるフレクトとしては、Herokuのこうしたアップデート内容が今後も続くように期待しております。

ということで今回は新しいDynoTypeが増えました、というお知らせでした。

「こんなことを調べて書いてほしい!」などありましたら、コメントをいただけるとうれしいです。 可能限り調査して回答編をブログとしてアップしたいと思います。

2015年10月16日 (金)

Angular2.0を見すえたAngularJSアプリケーション開発

こんにちは、JavaScripterの三宅です。
最近AngularJSを用いたアプリケーションを開発する機会が多いのですが、その際の考え方や実装の方針について書いていきます。
説明に使うソースコードはここで確認することができます。

Angular1.xとAngular2.0

現在、angular.ioでAngular2.0の開発が進められています。
正式なリリース日は発表されていないのですが、2015年末から2016年初めと言われています。
現時点ではまだα版でありまだ仕様が決定していないのですが、Angular1.xと比較し別のフレームワークと言えるほどの大きな変更が加えられます。
特に以下の変更はアプリケーションのアーキテクチャによっては、移行に際して大幅な改修が必要になることが予想されます。

  • TypeScript/ECMAScript6の採用
  • Controllerや$scopeの廃止によるコンポーネントベースへの変化
  • 双方向データバインディングの廃止

現時点でα版の2.0を採用することは現実的でなはいのでAngular1.xを用いることになるのですが、新しくアプリケーションを開発する際は上記を意識したアーキテクチャとすると、将来2.0がリリースされた際にスムーズに移行できるのではないかと考えています。
今回は、上記の3点を踏まえてどのような考え方で実装しているかを簡単に紹介していきます。

TypeScript/ECMAScript6の採用

AngularJSに限らず、新しいプロジェクトではほぼECMAScript6(ES6)を用いて開発しています。
ES6で追加された機能が魅力的であることに加え、Babelなどのトランスパイラの充実、Node.jsのES6のサポートなど、ブラウザ、サーバサイド共にES6を利用できる環境がほぼ整ったと考えているためです。
AngularJSは独自のモジュール機構を有しているため、JavaScriptファイルを全て結合してからトランスパイルする手法を取ることが多いのですが、Angular1.3.14からCommonJSが採用されたため、Browserifyなどのモジュール管理の仕組みを用いることも可能だと思います。

class MyAppComponent {
  constructor(PersonDataStore) {
    this.PersonDataStore = PersonDataStore;

    this.person = PersonDataStore.person;
  }
}

上記はControllerをES6のClass構文を用いて定義したものです。

angular.module('app').controller('MyAppComponent', MyAppComponent);

controller()メソッドの引数として定義したクラスを渡すと、Controllerとして登録することができます。
クラスのconstructor()の引数であるPersonDataStoreはServiceで、DIを行っています。現在のプロジェクトでは、いわゆるminify対策としてng-annotateを使っていますが、使わないのであれば、constructor()内に以下を追記することで対応可能です。

MyAppComponent.$inject = ['PersonDataStore'];

コントローラを利用する際は、ng-controller="MyAppComponent as app"のようにController As構文を用います。
これにより、Viewから$scopeを介さずに直接Controllerを参照でき、クラスで定義したプロパティやメソッドを利用することができます。

コンポーネント志向

Angular2.0はReact.jsの同様のコンポーネント志向のフレームワークとなります。
データとロジックをカプセル化したコンポーネントを定義し、それを組み合わせていくことでアプリケーションを構築するイメージです。
アプリケーション全体の状態やデータを保持するルートコンポーネントを起点としたツリー構造となります。
React.jsではコンポーネントのデータは親コンポーネントから与えられ、通常不変となります。コンポーネントの状態が変更された際はその配下のコンポーネントは全て再描画されます。
React.jsはVirtual DOMを用いて差分だけを実際に再描画することでパフォーマンスを担保しています。Angular1.xはその仕組みを持たないので変更が起こった際に再描画を行うのは現実的ではありませんが、ツリー構造であること、ルートコンポーネントが状態を持つことを意識することで、データの流れが把握しやすくなります。

class GreetingComponent {
  constructor($scope) {
    this.name = null;

    $scope.$watch('name', (newValue) => {
      this.name = newValue;
    });
  }
}

function createGreetingComponent() {
  return {
    controller: GreetingComponent,
    controllerAs: 'greeting',
    template: '<h1>Hello {{greeting.name}}</h1>',
    scope: {
      name: '=appName'
    }
  };
}

angular.module('app')
.directive('appGreeting', createGreetingComponent);

Angular1.xのDirectiveを用いてコンポーネントを作成したコードです。

<app-greeting app-name="{{parent.value}}"></app-greeting>

Directiveを利用する際は、上記のように記述します。
app-nameはコンポーネントが親コンポーネントから与えられるデータで、Directiveの$scopeのプロパティとなります。
GreetingComponentのconstructor()でクラスのプロパティにその値を代入し、コンポーネントの内部ではその値を利用します。

$scope.$watch('name', (newValue) => {
  this.name = newValue;
});

constructor()内で、$scopeのnameプロパティを監視する記述です。再描画の代替として親コンポーネントから与えられた値が変更された際に、そのイベントをトリガとして明示的にクラスのプロパティをアップデートします。
ブラウザにレンダリングされる値は、Angularの双方向データバインディングによってクラスのプロパティがアップデートによって更新されます。

双方向データバインディングの廃止

Angular1.xの特徴とも言える双方向データバインディングはAngular2.0では廃止されます。
双方向データバインディングは非常に便利ではあるのですが、個人的には以下の理由から限定的な範囲で利用するようにしています。

  • 複数のController間やネストしたスコープ間でモデルを共有した際にいつ、どこで値が変更されたのか把握できず、バグの温床になる
  • モデルの更新方法によっては(setTimeout()など)画面の更新が行われず、コンポーネントを定義する際に外部の状態を意識する必要がある

 

class Person {
  constructor(name) {
    this.name = name;
  }
}

class PersonDataStore {
  constructor() {
    this.person = new Person('Alice');
  }
}

angular.module('app')
.service('PersonDataStore', PersonDataStore);

サンプルでは、データを保持するServiceを定義しています。ルートコンポーネントがデータの参照を保持し、それを配下のコンポーネントに伝達するような構成としています。

class TextFieldComponent {
  constructor($scope, PersonDataStore) {
    this.PersonDataStore = PersonDataStore;
    this.text = $scope.text;
  }
  didChange() {
    this.PersonDataStore.person.name = this.text;
  }
}

function createTextFieldComponent() {
  return {
    controller: TextFieldComponent,
    controllerAs: 'textField',
    template: '<input type="text" ng-model="textField.text" ng-change="textField.didChange()"></input>',
    scope: {
      text: '=appText'
    }
  };
}

angular.module('app')
.directive('appTextField', createTextFieldComponent);

ng-modelの双方向バインディングによってTextFieldComponentのtextプロパティは入力によって更新されますが、そのスコープはコンポーネントの内部に閉じています。
ng-changeによって呼び出される、didChange()メソッドによって変更された値でDataStoreが保持するオブジェクトのプロパティを明示的に更新しています。
各コンポーネントも親から渡されたDataStoreの参照を$scopeに保持していますが、その変更をViewに反映するのは各コンポーネントの責務となります。
GreetingComponentは$scope.nameが変更された際に自身のnameプロパティにその変更を反映しViewを更新していますが、TextFieldComponentは特にアクションを行いません。親コンンポーネントから渡されたデータは、初期値の設定にしか用いないようになっています。
このように、DataStoreからルートコンポーネントを経由し、その配下のコンポーネントというような一方向のデータフローのアーキテクチャとすることで、モデルの値の変更を制御しやすくなると考えています。


今回は簡単なサンプルで、コンポーネントベース、一方向のデータフローのアーキテクチャに基づくAngularJSアプリケーションの考え方を説明しました。
実際の開発ではui-routerの利用やサードパーティのライブラリを用いる場合など、そのまま適用できないケースもあるとは思います。
また、CSSも合わせてコンポーネント志向の設計とする必要が出てきます。
ただコンポーネントベースの考え方は、 Angular2.0だけでなくReact.jsでも取り入れられていること、HTML/JavaScript/CSSを一つのコンポーネントとして定義するWeb Componentsの策定が進んでいることなどから、今後のフロントエンドアプリケーションのスタンダートになってくると予想されます。
AngularJSを用いない場合でも、今回説明した考え方は有効だと思います。

2015年10月 9日 (金)

【Herokuお絵かき】じーちゃん!東京リージョンできたよ!

こんにちは、中山です。

今日はHerokuが東京リージョンにやってきたのお話になります。

Tokyo_01

 

9月のことでした。

インターネット中のたろうはHerokuに関するニュースを見つけたようです。

Tokyo_02

 

なんと、Herokuが東京リージョンにやってくるようです!

Introducing Heroku Private Spaces: Private PaaS, delivered as-a-Service

Tokyo_03

 

たろうは、じーちゃんが東京リージョンに来てほしいって言ってたことを思い出しました。

Tokyo_04

 

じーちゃん!このニュースをみて!

東京リージョンでHerokuが使えるんだって!!

Tokyo_05

 

でもおかしいな。

アプリを作るときに東京リージョンの指定ができなかったことを思い出しました。

Tokyo_06

 

うーん。

じーちゃんからはニュースを読んでみるのじゃと言われる。

Tokyo_07

 

 Private Spacesでつかえるとのこと。

Tokyopdf_08

 

どうやったらPrivate Spacesに参加できるのかな?

Tokyo_09

 

記事を読むとHeroku Enterpriseの一つとして使えるようです。

Tokyo_10

 

Heroku Enterpriseってなんだろう?

Tokyo_11

 

Heroku Enterpriseの契約をすると、こんなことができるようです。

・Herokuの困ったことを日本語で問い合わせ可能

・アプリを作る上でのアカウントの細かい権限管理

・複数のアプリの一括請求

などなど。

Tokyo_12

 

hobby環境で開発しているたろうには、遠い存在のようです。

Tokyo_13

 

じーちゃん曰く

BtoC向けのWebサービスをHeroku使って日本で展開したいなら

どんぴしゃじゃー!!!

とのことでした。

Tokyopdf_14

 


大事なことなので2回言いました

Tokyo_14

 

 

今日のお絵かきはこんな感じで、おしまい。

Tokyo_15

 

 

おしらせ。

2015/12/3〜4にSalesforceの大きなイベントがありますよ。

エンジニア向けなのは、12/4の虎ノ門ヒルズフォーラムですね!

http://eventjp.salesforce.com/

忘れないように参加登録しておきましょう!

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart