ryhmrt’s blog

フィリピンから日本に戻った意識低い系プログラマの雑記

フィリピン滞在に有益そうな情報

最近なぜかフィリピンに行くという知り合いが多いので、フィリピン滞在に有益そうな情報を少し考えてみました。

私がフィリピンにいたのは2016年6月までで、基本的にはマカティから外には出ずに活動しておりました。その範囲で見聞きしたり実体験した情報です。

持っていくもの

とりあえず最低限これだけあればなんとかなります。

  • クレジットカード(キャッシングできるやつ)
    • 海外キャッシングの枠は国内キャッシング枠より低かったりするので注意。
    • 詳しくは後述。
  • 携帯電話
    • ネット接続は必須です。迷ったときでもネットで地図をみれば安心。
    • 詳しくは後述。

あると良いもの

  • 英語で書いてある写真付きの身分証(例えば国際免許)
    • ビルに入ったりするときに身分証を求められたりするのですが、英語で書いてないといけません。
    • パスポートはおいそれとは出したくないので、別の身分証があると安心感が増します。

ホテル

ホテルは多少高くついてもなるべく治安の良いところを選ぶべきだと思います。田舎の方では場所による治安の差はそんなに無いと思いますが、都市部では気をつけたいところです。新宿の表通りと裏通りの治安感を思い浮かべていただければ何となく雰囲気は浮かぶかと思います。

最近はフィリピンも都市部はGoogleMapsのStreetViewでカバーされてますので。通りがどんな感じか、開けた通りでお店があって夕方から夜にかけてもそれなりの人通りがあるところなのかどうかなど、調べておくと安心です。

ビザ

日本人は事前の手続きをしなくとも、ビザなしで30日間の滞在許可がおります。滞在許可期間内に出国するチケットさえあれば、よほどのことが無い限り入国拒否をされることはないはずです。

帰りの日程がはっきりと決まっていない場合も、仮の滞在スケジュールを滞在許可期間内で立てて、それに合わせて帰りのチケットを持っておく必要があります。JetStartはオプション料金を少し払うと安いチケットでもスケジュール変更可能になるのでよく使ってました。

30日を超えて60日以内の滞在をする場合は、事前に日本のフィリピン大使館で短期滞在ビザを取っておくと、フィリピンで滞在延長手続きをせずに済んで便利です。

滞在延長手続きは、自分でイミグレのオフィスに行くか、旅行代理店に頼むかになります。何度か自分でもやりましたが、イミグレまで行くのもかったるいですし、手続きにも時間がかかるので、オススメは代理店です。

現金の扱い

フィリピンの通貨はフィリピンペソです。さっき見たら1円=0.47ペソでした。

以下の種類のお札と硬貨があります。1ペソ=100センタボ

  • 1000ペソ札
  • 500ペソ札
  • 200ペソ札
  • 100ペソ札
  • 50ペソ札
  • 20ペソ札
  • 10ペソ硬貨
  • 5ペソ硬貨
  • 1ペソ硬貨
  • 25センタボ硬貨
  • 10センタボ硬貨
  • 5センタボ硬貨

割とどこでも円からペソに換金できますし、ほぼマーケット情報に出ているレートと同じ条件で換金できるので、なるべく円を現金で持って行くのがお得です。

足りなくなったらPLUSやCirrusのマークがある銀行のATMでクレジットカードのキャッシングを利用できます。一回の取引上限は10,000ペソとかだと思いました。

日本で換金して持っていくのは非常に換金効率が悪いのでやめましょう。

余ったペソは10,000ペソを上限に国外に持ち出せます。空港スタッフがX線スキャンでチェックしてイチャモンをつけてくるので、もしペソが余って持って帰りたい人は気をつけるようにしてください。

通信手段

ごく短い滞在であればローミングで済ませてしまうのもありです。料金は各通信会社のページに載っていると思います。

ネットの使用頻度や滞在日数によっては、SIMフリーの携帯を持っていて(向こうで買っても良い)、ローカルの回線を取得すると安く済むかもしれません。

空港では各回線業者がプリペイドのSIMを売ってますので、携帯を渡してSIM入れてネットの設定までやってもらうこともできます。かわいいお姉ちゃんだったらついでに番号ゲットしてしまえばいいと思います。

空港からの移動手段

5つ星ホテルに滞在するなら迎えを頼めると思いますが、迎えがないならば空港からの移動はタクシーを使うことになると思います。空港で見かけるタクシーにもいくつかありまして、

  • ボックスタイプの車を使って行き先のエリアごとに料金が決まっている固定料金(Fixed Rate)タクシー
  • 黄色い車体の空港メータータクシー
  • 白い車体の市中メータータクシー
  • レンタカー

料金が安い順に言えば、基本的に白、黄色、固定の順です。ただし、ぼったくり遭遇率もその順に高いので、メーターのタクシーに乗るときは、乗る前に「Meter?」とか言ってメーター使うかどうか確認して、走り出したらメーター動き始めたかどうか確認すると良いです。固定料金のタクシーはそうそう問題は起きないと思います。

尚、運ちゃんは英語を解しますが、日本人の発音が通じない可能性は大いにありますので、行き先の名前と住所は紙に書いておいて渡すと良いと思います。

日常生活の心得

  • スキミングの話をたまに耳にします。カードの利用履歴を監視して、何かあればすぐにカード会社に連絡しましょう。
  • 都市部では治安の悪いエリアがどこなのか把握して、特に日が落ちてからは近寄らないようにしましょう。
  • チップ文化は基本的にありません。請求された分だけ払いましょう。
  • お腹に自信の無い方は飲み物や食べ物に警戒しましょう。
  • 悪いお姉ちゃんやオカマに捕まらないようにしましょう。
  • フィリピンはゴキブリ天国です。慣れましょう。

長期滞在に向けて

長期滞在ではコンドミニアム(マンション)を借りることになると思います。自分で探すのも良い経験になりますが、知り合いの一人は日系の不動産から仲介してもらってました。英語がそこまで得意じゃ無い方はオーナーと直接やりとりするのはかったるいと思いますので、仲介屋を通すとそこら辺も安心できるかと思います。

携帯は後払いの契約型のものの方が安くなりますし、いちいちロードする必要もなくなるので便利です。個人的な経験からは、外人で国内に住居と職があればすんなりと回線契約できるのではないかと思います。

銀行口座も持っていると便利です。フィリピンでは他行の口座とはやりとりできませんが、自行のATMからはいつでも手数料なしで引き出せます。会社の口座がある銀行支店で店長とかとフレンドリーに話をしていればすんなり開設できるのではないかと思います。

最後に

慣れたと思った頃にヘマをする人が多いらしいので、海外で気を引き締め続けるのを忘れずに、と諸先輩が仰ってました。

フィリピンでの移動手段について

先月末から日本に戻りましたが、日本の交通網の発達は素晴らしいなあと改めて思ったりしています。

参考までにフィリピンの交通事情がどんなものなのか私の主観的な情報をここに記しておきます。

タクシー

フィリピンの短期滞在者が一番お世話になるのがタクシーではないかと思います。料金は日本と比べるとずっと安いです。初乗りが日本円で100円とかそんなもの。

空港からの移動も、ホテルやら知り合いやらの出迎えがなければタクシーを使うことになると思います。空港からの移動で気をつけるのは、声高に客引きをしているのは基本的にボッタクリだということです。タクシーと言って客を引きつつ、実はレンタカーだったりもします。空港から出ている正規のタクシーは、黄色い車体のメーター制(市中のメータータクシーよりちょっと割高)のものと、行き先によって値段が固定になっているボックスタイプのクーポンタクシー(基本的にメーターより高くつく)の2つです。参考までにマニラ空港からマカティ市内までの料金ですと、利用するターミナルにもよりますが、200ペソから600ペソほどの間に収まると思います。これを大きく上回るようだとボッタクリかと。

空港からの移動は以下の順に優先して利用しております。

  1. メータータクシー
  2. クーポンタクシー
  3. ボッタクリ

メータータクシーが一番安いので、できればそれを使いたいのですが、到着時間によってはに長蛇の列ができている場合があります。その場合でもクーポンタクシーは割と空いていることが多いので、そっちに行きます。急ぎの用事がある場合は仕方がないので、ボッタクリの中からどうにか我慢出来る値段のところを探すことになります。

裏技として、空港の到着エリアから出発エリアに移動して、客を空港まで送り届けた後の市中タクシーを拾うという手もあります。しかし、市中のタクシーは空港では客を拾ってはいけないことになっていると思いましたので、やるなら荷物が少ないときなどで、目立たないようにやるべきかと。

ちなみに、空港からマカティ市内に抜ける際、Skywayという高速道路を使うと、20ペソを別途払うことになります。

フィリピンのタクシーは、市中でつかまえた正規のライセンスのものであっても油断はなりません。走り出した時にきちんとメーターが回っていることを確認しないと、後から法外な料金を請求してくる悪質なドライバーもおります。乗車拒否も日常茶飯事で、道中に渋滞があったり、雨天時で稼ぎどきともなると、乗車時に通常のメーター料金よりも高額で交渉をしないといけない場合もあります。メーター+50ペソというのが割とよく出る条件ですが、ケースバイケースです。

稀なケースだとは思いますが、タクシー運転手が強盗に様変わりするなどとの話もあるようです。

尚、陸路全般に言えることですが、渋滞が酷いため、それを計算に入れて移動する必要があります。

レンタカー

田舎方面に行く場合はタクシーに頼れなくなってきますので、レンタカーを使うという選択肢も出てくるかと思います。

フィリピンではレンタカーを借りると基本的に運転手がついてきます。小ぶりなセダンタイプならば、運転手込みで1日1万円とか、そんなものではないかと思います。

自分で運転するという選択肢もないわけではありませんが、日本とは車線が逆ですし、運転マナーも悪いため、短期滞在で運転に挑戦するのは自殺行為かと思います。

バス

現地で一番メジャーな長距離移動手段がバスだと思います。だいたいの町にはバスで行けるのですが、ぱっとバスを見ても行き先はよくわからないと思いますし、車内のアナウンスは現地の言葉ですので、かなりの慣れが必要です。

時間や路線によってはかなり混み合いますので、大きな荷物を持っていると辛い場面もあるかと思います。コストパフォーマンスは良いです。

バン

ボックスタイプの車が一定の区間を往復していて、バスと同じように利用することができます。バスよりも行き先がわかりにくく、難易度が高いです。きちんと営業許可を取っているものと、白タクのような無法営業のものがあるようです。料金的にはバスとそんなに変わらないのではないかと思います。

Uber / Grab Taxi

私は両方ともほとんど使いませんでしたが、高評価をしている人もいました。

個人的にはいい思い出がありません。Uberの運転手は素人ばかりで、スマホのナビに失敗するとすんなりと目的地に着けないことがままある。Grab Taxiは基本的にメータータクシーをつかまえるためのサービスですが、繁忙時には結局これを使っても捕まえられないですし、暇な時間帯はこんなのがなくとも流しのタクシーを簡単に捕まえられるのであまりメリットが感じられません。

両方共オンラインで車両情報が追跡されるので、セキュリティ上安心できるということはあるかと思います。

電車

フィリピンの電車網は、首都マニラ圏に、山手線のような環状の路線と、それを東西に突っ切る短い中央線があるような感じです。

激しく混みますし、上記以外に細かい路線網がないので使い勝手は悪いです。ただし料金は安い。

最近ではIC乗車券なんかも導入されてたりするらしい。

空路

日本のように陸路で素早く移動する手段がありませんので、長距離移動は空路に頼るのが賢明です。群島国家なので、そもそも陸路で行けないということもあるかと思います。

Philippine Airlines と Cebu Pacific がメジャーです。クオリティは Philippine Airlines の方が安定しているように感じます。料金は Cebu Pacific が格安フェアをよくやっていて、そのチケットが取れればかなりお得です。通常の料金はどちらもそんなに変わらないと思います。

海路

飛行機を使うまでもないような距離での海峡越えなど、海路を使う場面もあるかと思います。

短距離ではバンカと呼ばれているボートを使いますが、日本で使われているような高速艇と比べると遅くて乗り心地も悪いです。

長距離ではフェリーになるかと思いますが、どうしても自分の車を運びたいといったことがなければ空路を選ぶのが無難です。

Jacksonのデフォルトタイムゾーン

今週に入ってからSpringMVCでWebAPIをごりごり書いているのですが、いざ日付型を扱うというところになってちょっとはまったのでメモ書き。

謀ったなJackson

SpringMVCのJSON処理は標準でJacksonを使うようになっています。

Jacksonで日付型をフォーマットするためには

    @JsonFormat(pattern = "yyyy/MM/dd")
    private Date date;

とかやるわけなんですが、これだとタイムゾーンがGMTで計算されて変になったりします。

    @JsonFormat(pattern = "yyyy/MM/dd", timezone = "Asia/Tokyo")
    private Date date;

とか書くこともできるんですが、さすがにこれを一々指定するのは気が重い。

@JsonFormat のJavaDocのtimezone部分を見ると、

TimeZone to use for serialization (if needed). Special value of DEFAULT_TIMEZONE can be used to mean "just use the default", where default is specified by the serialization context, which in turn defaults to system defaults (TimeZone.getDefault()) unless explicitly set to another locale.

とか書いてあるので、

TimeZone.setDefault(TimeZone.getTimeZone("Asia/Tokyo"));

と、アプリの初期時にやっておけば良いと思ったそこの貴方は残念賞。

Jacksonで明示的にデフォルト指定をしない場合のタイムゾーンは "GMT" 固定です。

com.fasterxml.jackson.databind.cfg.BaseSettings を見ると、昔は TimeZone.getDefault() を使っていたのかな、と思うようなコメントアウト(!!)があって目を疑います。

    private static final TimeZone DEFAULT_TIMEZONE = 
            //  TimeZone.getDefault()
            /* [databind#915] 26-Sep-2015, tatu: Should be UTC, plan to change
             * it so for 2.7
             */
            TimeZone.getTimeZone("GMT");

エスパーするとしたら、タイムゾーンの環境依存で発見しにくいバグに悩まされて、デフォルトをGMT固定に変更したとかでしょうか...

尚、Jacksonの公式WikiにあるFAQの日付処理のトピックでは、一番最初に「タイムゾーン何も指定しなければGMTだから、よろしく」と書いてありました。 http://wiki.fasterxml.com/JacksonFAQDateHandling

これで勝てねば貴様は無能だ

以下のようなクラスをプロジェクトの適当な場所に作ればOKです。

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .timeZone("Asia/Tokyo")
                .dateFormat(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
}

上のコードではついでにデフォルトの日付フォーマットも変更してます。

参考: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config-message-converters

ページ遷移時にAPIを叩いてデータを読み込む with react-router-redux 4.0.0

react-router-redux を 4.0.0 にしたらメソッド名とか中の処理とかけっこう変わってました。

前に書いたURLのフック処理がいろいろ駄目になっていたので、4.0.0でどんな処理になっているのか、ざっと追って、新しくコードを書き直してみました。

react-router-redux が何をやっているのか

最新の 4.0.0 では react-router-redux がラッピングした history オブジェクトを React Router に渡すようになっています。

このラッピングされた history は listen イベント登録が書き換えられており、store に格納されているURLが変更されると、その情報をパラメータに listener がトリガーされるようになっています。

流れを3ステップで説明すると以下のようになります。

  1. オリジナルの history のURL変更イベントで LOCATION_CHANGE アクションを dispatch する
  2. routerReducer が LOCATION_CHANGE を受けとって、新しい URL 情報を store に格納する
  3. react-router のURL監視用 listener が呼び出され、ルーティングが書き換わる

3.0.0からの違い

以下のコードは react-router-redux の README.md にあるもの。

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import { Router, Route, browserHistory } from 'react-router'
import { syncHistoryWithStore, routerReducer } from 'react-router-redux'

import reducers from '<project-path>/reducers'

// Add the reducer to your store on the `routing` key
const store = createStore(
  combineReducers({
    ...reducers,
    routing: routerReducer
  })
)

// Create an enhanced history that syncs navigation events with the store
const history = syncHistoryWithStore(browserHistory, store)

ReactDOM.render(
  <Provider store={store}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <Route path="foo" component={Foo}/>
        <Route path="bar" component={Bar}/>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('mount')
)

以前は syncHistory で middleware が返ってきましたが、4.0.0 の syncHistoryWithStore は react-router-redux がラッピングした history を返してくるので注意が必要。

これを使わずにオリジナルの history を react-router に渡してしまうと、細かいところで変なことが起こります。要注意。

前のバージョンで syncHistory が返していた middleware は、routerMiddleware として別物になってオプション扱い。

というのも、この middleware は URL 変更のアクションを受けとって history に対して操作を行うためにあるのですが、そんな回りくどいことをせずに history を直接呼べば middleware 登録をする必要はないでしょうという話だと思います。

以下のコードは README.md に載っているもので、Redux のアクションを使ってURL遷移をするサンプルコードです。

import { routerMiddleware, push } from 'react-router-redux'

// Apply the middleware to the store
const middleware = routerMiddleware(browserHistory)
const store = createStore(
  reducers,
  applyMiddleware(middleware)
)

// Dispatch from anywhere like normal.
store.dispatch(push('/foo'))

しかし、history を直接使うならば以下のようにシンプルにできます。

import { browserHistory } from 'react-router'

browserHistory.push('/foo')

あと、前のバージョンでは index.js に全てがずらずらっと(とは言っても短いですが)書かれていたのが、4.0.0 ではファイルが細切れになっています。

ページ遷移のフック処理

現状、ページ遷移をフックしてAPIを呼び出す処理は以下のようになっています。

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import { match } from 'react-router';
import { UPDATE_LOCATION } from 'react-router-redux';
import { loading, updateData } from 'actions/common';
import reducer from 'reducers';

const dataFetchMiddleware = routes => store => next => {
    // Utility method for API call
    function updateDataFromAPI(location) {
        match({ routes, location }, (error, redirectLocation, renderProps) => {
            if (error || redirectLocation) {
                return;
            }
            // Find API
            const route = renderProps.routes[renderProps.routes.length - 1];
            if (route.fetchAPI) {
                // Call API if it's available
                api(renderProps.params, renderProps.location.query, data => {
                    store.dispatch(updateData(data));
                    store.dispatch(loading(false));
                });
            } else {
                Promise.resolve(loading(false)).then(store.dispatch);
            }
        });
    }
    // Return core middleware function
    return action => {
        // Fetch data on update location
        if (action.type === LOCATION_CHANGE) {
            next(loading(true));
            updateDataFromAPI(action.payload);
        }
        return next(action);
    };
}

export default function configureStore(initialState, routes) {
    return createStore(reducer, initialState, applyMiddleware(thunkMiddleware, loggerMiddleware, dataFetchMiddleware(routes)));
}

URLとAPIのマッピングは routes の定義に書くことにしました。

match というユーティリティが react-router にあり、routes 定義と location を渡すと、マッチしたルーティング情報を返してくれます。

末端の route 定義に fetchAPI というキーでデータ取得のための関数を定義するようにして、それをここで取得するようにしました。

注意点は、match が onEnter を呼び出しますので、onEnter で副作用のあることをしないように。そもそも、onEnter はリダイレクト処理くらいしかやってはいけないのだと思います。

gulpのビルドをエラー時にリスタートさせたら不評だった

コンパイルエラーが発生したときにgulpのwatchが終了して、リスタートするのが面倒なので、ビルドコマンドを無限ループに入れることに。

そして、コンパイルエラーが起きたら通知があったら良いだろうと、以下のようなコマンドを実行してみました。Macで動きます。

$ while true; do gulp build-watch; say 'compile failed, build watch will restart in 5 seconds'; sleep 5; done

直後にHipChatで受けとったメッセージ:

@RyoheiMorita Can you shut that up? LOL

何か負けたような気がして悔しかったので以下のようなコマンドに改良して提案しました。

$ while true; do gulp build-watch; say oops; osascript -e 'display notification "compile failed, build watch will restart in 5 seconds" with title "gulp build-watch"'; sleep 5; done

ページ遷移時にAPIを叩いてデータを読み込む with react-router-redux

react-router-redux 4.0.0 向けに新しいのを書きました

-- 以下は古いもの --

Redux way では描画に必要なデータは props 経由で渡すことになります。 画面遷移時にデータの読込どうしようかと少し悩みましたが、今のところ、URLの変更を検知して、そのURLに対応したAPIを叩くという方向で進めています。

React RouterRedux の繋ぎとして react-router-redux を使っていまして、今のところ以下のような感じです。

import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import { syncHistory, TRANSITION, UPDATE_LOCATION } from 'react-router-redux';

import reducer from 'reducers';

import { loading, updateData } from 'actions/common';
import findAPI from 'apis';

const dataFetchMiddleware = store => next => {
    // Action type for initial load
    const INITIAL_LOAD = 'INITIAL_LOAD';
    // Utility method for asynchronous action dispatch
    function dispatchAsync(dispatch, action) {
        Promise.resolve(action).then(dispatch);
        return action;
    }
    // Utility method for API call
    function updateDataFromAPI(location) {
        // Call API
        findAPI(location, store)(data => {
            store.dispatch(updateData(data));
            next(loading(false));
        });
    }
    // Dispatch initial action asynchronously
    dispatchAsync(store.dispatch, {type:INITIAL_LOAD, payload:location});
    // Return core middleware function
    return action => {
        // Handle first screen load
        if (action.type === INITIAL_LOAD) {
            updateDataFromAPI(action.payload);
            return next(action);
        }
        // Activate loading screen before transition
        if (action.type === TRANSITION) {
            // This loading action is for user's action
            next(loading(true));
            // Dispatch original action to next middleware asynchronously to freeze screen before transition
            return dispatchAsync(next, action);
        }
        // Fetch data on update location
        if (action.type === UPDATE_LOCATION) {
            // This loading action is for browser's history action
            next(loading(true));
            updateDataFromAPI(action.payload);
            // Dispatch original action to next middleware asynchronously to freeze screen before transition
            return dispatchAsync(next, action);
        }
        return next(action);
    };
}

export default function configureStore(initialState, history) {
    const loggerMiddleware = createLogger();
    const reduxRouterMiddleware = syncHistory(history);
    return createStore(reducer, initialState, applyMiddleware(thunkMiddleware, loggerMiddleware, dataFetchMiddleware, reduxRouterMiddleware));
}

store生成呼び出しは以下のようになってます。

import createBrowserHistory from 'history/lib/createBrowserHistory';
import configureStore from 'configure-store';

const browserHistory = createBrowserHistory();
const store = configureStore(initialState, browserHistory);

push 等のアクションからURL遷移する場合は、 TRANSITION が処理された後に UPDATE_LOCATION が処理されます。このとき React Router は最初の TRANSITION アクションでルーティングを変更してしまうようなので、TRANSITION が処理される前にローディング処理のアクションを投げています。

ブラウザの履歴操作でURL遷移する場合は TRANSITION が無く UPDATE_LOCATION だけが処理されます。そのため UPDATE_LOCATION が処理される前にもローディング処理を入れています。

loading(loadingStatus){type:'DISPLAY_LOADING', value:bool} といったアクションを返すメソッドです。最終的にこいつを処理する reducer がローディング中を示す state の値を書き換えます。ローディング中は props が変更されても画面が書き換わらないように、上っ面の shouldComponentUpdate でごにょごにょしてます。

ローディング処理の呼び出し後にURL遷移のアクション呼び出しを dispatchAsync(next, action); とかやっているのは、ローディングのアクションを処理してから先に一度レンダリング処理をして、画面をフリーズさせたかったからです。普通に呼び出すと、両方が処理されてからレンダリングが発生するので、データが無い状態で遷移先の画面が描画されてしまいます。

新規の生成したアクションの呼び出しが所によって next だったり store.dispatch だったりするのは、このミドルウェアの上にロガーがいるので、そいつに出すとうざいなと思った物は next に渡しているという次第です。ミドルウェアの順序重要。

最初の方で dispatchAsync(store.dispatch, {type:INITIAL_LOAD, payload:location}); と呼び出しているのは、一番最初のデータ取得処理をキックするためです。なんか汚い感じがしますが、とりあえず動いてます。

JavaScript疲れを脱する - React編 というブログエントリを読んでみた

最近 React + Redux でSPAをやっていて、パフォーマンスとかいろいろ問題が出てきています。 試行錯誤を繰り返す中、チームメンバーが "Getting Out of JavaScript Fatigue - React Edition" というブログ記事を紹介してくれました。

Reading Hacker News comments on JavaScript frontend articles is a depressing task these days. The majority is complaining: Tooling too complex, bundling too complex, Too many different frameworks, best practices change too quickly.

出だしから「最近 Hacker News でフロントエンドJavaScript関連のコメントを見ると気が滅入る」とか書いてあって共感を覚えます。

そして、Reactに関するむず痒い思いをを端的に表すものとして一つのコメントを紹介しています。

When React first started getting popular all you read about was how simple the API was and how it was Easy to Reason About™. Fast forward to today and you need to have working knowledge of WebPack, ES6, Redux, immutable.js, Babel, and a bevy of other dependencies to be aligned with the React ecosystem's ever-evolving best practices.

自分は最近になってSPAを本格的に始めたのですが、Gulp、ES6、Babel、Less、React、Redux、その他React/Redux関連ライブラリと、一気にいろんなものを導入しました。確かに疲れます。

さて、そんなReact界の問題に対してブログではこう言っています。

When people hype patterns or libraries, they do not tell you the most important thing: When you don't need it.

みんな良い手法とかライブラリとか言うけど、どんな場面では使う必要がないか、という一番大切なことが抜けているとのことです。

この点で react-howto は素晴らしいとのこと。私はまだちゃんと読んでませんが、確かに順番に勉強するべきものが示してあって、必須ではないものについては問題が起きたら導入しろとか書いてあります。

ブログポストはこの react-howto をいくつかの点から補足するという位置づけの様です。

以下、内容に関するざっくりとした意訳メモ。

  • Reactは本当に必要か
    • 他のフロントエンド技術に精通していてそれに満足しているとか、単純なCRUDを普通に作るならReactはいらないだろう
    • 逆に、既存のSPAフレームワークに不満があったり、これから新しくフロント周りをイケてる感じにやりたいとか、もしくは単純に新しもの好きな人ならReact使ってもいいんじゃない
  • オフィシャルチュートリアルの後に手を付けるべきもの
    • 既存のWebアプリがある場合
      • インタラクティブ性の高い独立した小さなコンポーネントをReactで置き換えてみよう
    • Web開発をこれから始めようとする人は
      • Reactそのものに注力するために、これみたいな非常にシンプルなテンプレから始めるべき
  • JSXを使うか否か
    • 無駄に議論されてるけれど、JSXを使うかどうかは大した問題じゃないので好きにしたら良いよ
  • 三ヶ月で全てが古びてしまうのではないか?
    • 短期間で劇的な変化があることは無いだろう
    • ReactそのもののAPIは既に十分以上に安定している
    • 一つの問題に対して大量のライブラリが作られるようならば、それは解決が簡単な些細な問題ということだから気にしなくて良い
    • Reduxについてだって、Fluxの基本的なコンセプトの確立からすれば些細な向上でしかない
  • 技術に対する正しいマインドセット
    • 新しいhotな技術が次々に生まれてくるけれど、それらはある特定の問題を解決するために生まれたものである
    • あなたが抱えている問題はあなたしかにしかわからないのだから、coolな人達が開発した技術だからという理由だけでそれに頼ってはいけない
    • きちんと自分の問題を把握して、それに合った解決策を探すべきだ
    • 頭に中でチームが直面している問題を整理しておく
    • 新しい技術がbuzzってきたときは、その品質や、作者が直面した問題が自分の問題と同じようなものなのかを良く確認する
    • 開発者が心がけるべきことは "生産性の極大化" であって、"ベストプラクティスを実践すること" でも "coolなものを試すこと" でもない

最近自分が新しい技術に保守的なのを少し反省して、チームを活性化させるためにも新しい物を取り込もうという動きを強めているのですが、慎重さも捨てないように戒めていきたいと思いました。

老害化しているようにも感じますが、若者に向けては、基本をしっかり学んで些細なことに惑わされないようにと願う次第です。