読者です 読者をやめる 読者になる 読者になる

ryhmrt’s blog

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

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

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

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

タクシー

フィリピンの短期滞在者が一番お世話になるのがタクシーではないかと思います。料金は日本と比べるとずっと安いです。初乗りが日本円で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編 というブログエントリを読んでみた

JavaScript

最近 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なものを試すこと" でもない

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

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

フィリピンでのオフショア開発を振り返って

Philippines

フィリピンでのオフショア開発に携わって、そろそろ4年になろうとしています。

年明けにフィリピンチームの年次考査をやるために考えを巡らせたり、これからフィリピンでオフショア開発を始めるという方に偉そうに相談に乗ったりといろいろあって、一度フィリピンでのオフショア開発についてメモを残して置くことにしました。

まだいろいろと試行錯誤の段階ですが、多少は誰かの参考になったり、今後自分が振り返っていく上で助けになれば良いなと思ってます。

追記:

@kdmsnrさんから立場を最初に書いた方が良いとご指摘いただきました。ありがとうございます。

私は四年ほど前、日本の親会社がフィリピンにオフショア開発の現地法人を立ち上げた時からの管理者です。 現地では日本人が私1名と、現地のエンジニア数名がおります。

オフショア案件に関しては日本の営業と技術者が日本のお客様から要件をヒアリングして、基本的な仕様がまとめってからフィリピンに投げるという流れをとっています。 フィリピンでやっているのは日本語の仕様書を元にシステムを開発して日本に投げ返すという仕事です。 基本的に私の役割はそれに必要な一切合切です。 最近では人事会計から開発までのフルスタックエンジニアとうそぶいております。 (事務関連は実際には外部に委託していますが)

英語

フィリピンは英語が公用語の一つになっている国ですので、現地のプログラマはほぼ全員英語が問題ないレベルで読み書きできます。 英語のドキュメントをバリバリ読んでくれる現地のエンジニアは大変心強いです。

発音についても比較的聞き取りやすい英語を話してくれる人が多いと感じています。 中には癖のある英語を話す人もいますが、ネイティブの英語のように短縮して音が消えまくって、慣れないと単語が聞き取れないということはまずありません。

フィリピン人が日常会話に使う言葉は他にあって、英語は公用語の一つとはいえ半ば外国語、だいたい小学校あたりから習うものです。 受けた教育水準によっては流暢には喋れない人もいます。 しかし、日常的に使われる言葉ではあるので、国民の過半数がカタコトではあれ英語が話せると言って良いでしょう。

英語がそこまで普及していない国だと、英語以外に現地語も勉強しないと生活に困るかもしれません。 フィリピンでは英語さえできればどこに行っても何とかなるので、外人にとっては便利な国です。

オフショアのプロジェクトで現地のプログラマと開発を行うという点のみに関して言えば、カタコトで会話ができれば何とかなるように思います。 実際に私がフィリピンに来た当初はカタコトの英語でプロジェクトを回していました。 資料を一通り英語に翻訳して、カタコトでいろいろ説明し、理解があってるか確認し、タスクを切り分けてGoogle先生の力を借りながらタスク管理システムに英語で登録し、コードレビューをしっかりやって、という感じです。 ただ、ガッツリチームに入り込めないならこれは無理です。 また、何かあったときには翻訳してタスクを振る時間も惜しくなる可能性もありますので、最悪自分でプロジェクトをねじ伏せることができるようでないと厳しいと思います。

私がカタコトでプロジェクトをやっていたときには、プロジェクトのスタッフは外の会社から借りていました。 自分たちで人を雇っていろいろやっていくには、きちんとコミュニケーションが取れないと不安かと思います。 カタコトでもかなりのコミュニケーションが取れる人もいますし、同じ言葉を喋っていても意思の疎通が困難な人もいますので、どれだけ喋れれば良いのかは人にもよるかと思いますが、自分としてはジョークの一つでも飛ばせるようにならないと厳しいと感じています。 まずは面接で意思の疎通が出来ないと雇って良いのか判断がつきませんし、条件面の交渉や契約、雇用後は日常的なケア、年次考査の際には多少タフな話もできなければ対処できません。

直接雇うのか、間接的に雇うのか、メンバーのケアは誰がやるのか、といったことを加味して必要な英語力を想定して、不足があれば予め翻訳をするなり、通訳を頼むなり、準備が必要なのかと思います。

接し方

基本的に現地の社員も日本の社員と同じように接していれば問題ないかと思っています。 人それぞれ他人との接し方にはスタイルがあると思いますので、それは日本人に対しても他の国の人に対してもそう変えられるものではないと考えています。 十分なレベルの教育を受けた従業員を雇って、ちゃんと会話ができる前提で、ですが。

文化の違いに関しては、そう問題になることはないかと感じています。宗教観ですとか、現地の習慣といったものは事前に調べるなりして尊重するべきだと思いますが、実際に各個人と接するに当たっては、それよりも個人の性格の違いといったものが大きいように感じます。

家庭環境などもしっかり把握して置いた方が良いかと思います。 フィリピンでは親の言うことを聞く文化が日本より強く、親がしっかりしていれば子供もしっかりしている傾向は日本より強いように感じます。 育った環境を聞いておくと人となりを把握する参考になるでしょう。 また、家族を大事にするので家庭に問題があれば仕事に支障が出てしまいます。 近況も積極的に探っておくべきかと思います。

仕事への姿勢

与えられた仕事を真面目にこなす傾向は日本人より強いのではないかと感じています。 社会保障も十分ではなく、失業率も高止まりし、職によっての賃金格差も大きい中で、ハングリーさがあるのかと思います。

ハングリーな人の一部はごく短い期間で転職を繰り返すジョブホッパーと言われるような行動を取ります。 辞められるタイミングやチーム体制によっては引き継ぎのコストが痛いですし、チームの士気にも関わりますので、積極的に採用することは避けたいと思いますが、中には非常に有能な人もいるようです。 引き留めるだけの自信があるか、短期で抜けられた場合でもチームやプロジェクトにメリットがあるか、といったことを総合的に判断するべきかと思います。

フィリピン国内では会社や職によって賃金の格差が大きく発生します。 稼げる職に就いて家族を支援しなければならないといった人も多く、仕事の動機として自己実現といったような内的なものよりも、金銭的なものが先に立つ傾向が日本よりも強いのは致し方のないことかと思います。

とは言え、きちんと将来のキャリアプランを描いて十分な賃金が得られていれば、しっかりとしたプロ意識で仕事をしてくれることと思います。 フィリピンにおいて外貨の稼げるIT業界は花形産業です。 みんな希望を持ってこの業界に入ってきますので、情熱を持って仕事に取り組んでもらえる魅力的な職場環境を築きたいものです。

たまに、フィリピンではクリスマスパーティーを開かなければとか、そういったことを耳にしますが、まずは大前提として仕事やキャリアそのものが魅力的でなければいけません。 その上で、従業員間で気持ちの良い関係を築くためにパーティーなどを企画するというのが筋だと思います。

組織

フィリピンでは基本的にトップダウンのピラミッド構造の組織体制で管理する文化が根強いかと思います。 マイクロマネジメントに慣れているのであれば、就業規則や業務上の役割・手順をしっかりと定めて、厳格に運用していけば良いと思います。

自分はプレイングマネージャーという立場上、現場はしっかりと把握していますが、あまり細々と指示は出したくありません。 某ポッドキャストでもマネジメントについてはいろいろ語られていますが、私はしっかりとした理想や方向性を示しながら、サーバント型でいろいろ拾いながら皆を持ち上げていきたいと思っています。 最近ではうちのエースがかなり育って、我がチームのトラックナンバーは既に2になったと言ってくれるようになりました。心強いです。

何にせよ、力強いリーダーシップは必要不可欠です。 ろくに仕事もできない人間が、日本語ができるというだけの理由で上に立ったら、現地のエンジニアも心穏やかではないでしょう。 以前に「さーて、会社どんな風にしようかね」と、何気なく社員に問いかけたら「そんなの知るか、それを決めるのはボスであるあんただ」みたいなことを言われて気が引き締まった思い出があります。

自分が目指すのは、より良い仕事の結果を求めて自由に意見を交換し活動のできる組織です。 若者や、慎ましい性格の人は萎縮してしまう傾向が日本よりも強いと思います。 会社でアホなこと言ってるのはその敷居を下げるための施策だと念じて自分を納得させています。

評価と給与

人材の流動性が日本よりも高い中で、評価や給与に納得がいかなければすぐに職場を変えられてしまうだろうという危機感は常に抱いているべきかと考えています。

うちでは一年に一回、年の初めに年次考査をして、昇給や今後に向けてのアドバイスなどをやっています。 いろいろ悩んだ上で、キャリアの指針や評価の軸を示すために、今期からは職位表を用意しました。 職級を5段階に分け、その中で5段階のレベル設定をしています。 各職級に役割を設定し、その役割をどれくらいのレベルでこなせるかという説明を5段階で付け加えました。

流れとしては、まず職位表について説明し、週末を挟んで自己評価をじっくり考えてもらいました。 その上で私の評価とすりあわせ、次の年にはどのポジションに行きたいか、そのためには何が足りなくて、どう行動すれば良いかといったことを話し合いました。

従業員には額を公開しなかったものの、職位表の各セルには対応する給与レンジを設定しています。 事前にそれぞれの従業員に対して私なりの評価をして、日本側と昇給額についての見込みを伝えてネゴっておきました。 今回は自己評価と私の評価が合っていたため、すんなりと給与額を伝えることができました。 四半期毎にも個人面談をしていますので、今後はその場でも職位表に基づいた評価とアドバイスを実施し、次の年次考査も関係者全員が納得できるように進めていきたいものです。

職位毎の給与額については、公表する事で透明性が高まり会社への信頼感が高まる可能性もありますが、ボロがある段階では不信感の方が出てしまう可能性があると考えました。 現状でポジションに該当する人がいない上位職についてはそこまで額が練られていませんし、世間や会社の状況に応じてテーブルの値をどう変えていくのかも示す必要があるかと思います。

なお、評価とは少し違いますが、周りからのアドバイスを得るためにピアレビューの仕組みを取り入れようと話し合いました。 複数のプロジェクトが走っていると、私が関わらないプロジェクトのメンバーのことで見落としてしまう部分があるかと思いますので、そこを補おうという試みです。

学習

業務外の学習時間は総じて日本のエンジニアよりも少ない傾向にあるように感じます。 理由としては学習機会、学習時間の確保といった問題があるかと思います。

マニラ首都圏は、仕事がここ一カ所に集中している割りに交通網が十分に発達しておらず、ここで働く多くの人々は地方から長い時間を掛けて通勤をすることになります。 通勤途中に勉強が出来るといった環境でもないため、平日は仕事をして帰って寝るだけの生活になってしまう人が多いかと思います。 家にコンピュータがない、インターネットがないといったことも珍しくなく、時間があるからといって学習の環境が整うとも限りません。

日本では有志の勉強会などの催しも多く、会社から勉強の機会や助言が与えられなくとも技術者が自ら学んでいくような風潮がありますが、フィリピンではそういったプロフェッショナルのコミュニティは育っていないようです。

私からは、技術者として長くキャリアを築いていく上で、業務外の学習も意識するようにと、先達からの助言としては伝えています。 しかし会社としてはそれに頼らず、業務時間内に様々なことを身につけ成長していけるように、学習機会を与えキャリア展望を示していく必要があると考えています。

採用

新しく人を雇う際には、まずオンラインの求人サイトに広告を出しています。 応募があった候補者の履歴書を見て、見込みがありそうであれば筆記試験を受けてもらい、それを通過した人に面接を実施します。 最初の面接では履歴書に書かれたことの裏付けや、書かれていない部分の掘り起こしをして候補者の能力を推定します。 面接を通過した方には、半日くらいをかけて実業務に近い形のコーディングをやってもらい、その後最終面接を受けてもらいます。 コーディングでは実務上の技術力やコミュニケーション能力を測り、最終面接ではチームでうまくやっていけそうかどうか、マインドを中心に見ます。 最終的に欲しいと思ったら、オファーを出して、給与交渉です。

うちは小所帯のチームで、専任の人事がおりませんので、採用は全て私と現地のエンジニアで実施しています。 極最初の頃は面接をしながら技術的な質問を即興で出していたのですが、毎回頭を捻るのも疲れてきたので、新しいメンバーに求める技術要素をまとめて、試験問題を作りました。 その後しばらくは、履歴書のフィルタに通過した応募者に試験と面接を両方実施していたのですが、最初に試験を受けてもらって、それを通過した人だけ後日面接に来て頂くという手順に変更しました。 実務をやっている傍らで面接を何度もやっていると時間が取られすぎてしまうのと、試験の結果が芳しくない応募者が思ったよりも多かったという理由からです。

専任の人事がいれば、筆記試験と面接を同時に実施して、多少試験が駄目でも見込みがありそうな人を拾うことが出来るかも知れません。 また、現状では求人を掲載して応募が来た人の中から選考するという受け身の体勢ですが、専任の人事がいれば、求人サイトのスカウト機能を活用して攻めの採用をすることもできるかと思っています。

解雇

フィリピンの労働法は解雇が難しいという点に置いて日本の労働法に感覚が似ているかと思います。

フィリピンでは試用期間が6ヶ月までと定められておりますので、その間であれば、解雇(正確には試用期間中の雇用契約終了)は難しくありません。 試用期間を超えたら解雇は格段に難しくなります。職務怠慢とかなら警告文書を何回か書面で出して、最終的に解雇とか、倫理的に問題のある行動をすれば一発解雇とか、会社が傾いたときに人員整理の対象にするとか、会社側から許される解雇理由はかなり限られています。

日本では試用期間は通常3ヶ月だと思いますので、それと比べれば倍の期間がある形になります。 正社員として期待するものがどれくらいのものなのか、なるべく具体的にイメージして、仕事のパフォーマンスなどについて評価を定期的に提示して、向上が必要であればそれを促し、正社員になるには厳しいとの判断があれば、6ヶ月の試用期間中にきちんと説明した上で雇用契約を終了したいところです。

法律的に言えば、試用期間の打ち切り一週間以上前に契約打ち切りの理由と日付を書いた書面を交付するというのが手順らしいのですが、社員のことを考えれば一ヶ月前には判断をして伝えるのが良いかと思っています。 うちでは1人残念ながら試用期間で打ち切ってしまった人がいましたが、その人は依願退職のレターを出してくれたので、こちらからは契約打ち切りのレターは出しませんでした。 素直で良い若者だったのですが、小さなチームで忙しく仕事をする中、なかなか成長の手助けを出来なかったのが大きな理由だと考えています。 体制のしっかりした会社に入って研鑽に励んでくれと送り出しました。

何にせよ、お互いのことを考え、問題が起きないようにしっかりと話し合うことが大事だと思います。

庶務

会社を運営して行くには、会計、納税、給与支払いなどの間接業務も必要になります。 うちでは会計、納税、給与計算は外部委託して、私は必要な書類にサインして支払いをすれば良い形です。 外部に委託するにしても、基本的な法律や原理原則を把握して、問題が起きないように気を配るべきかと思います。 私はこちらに来る際、フィリピンでの会社運営に関する入門本に一通り目を通しました。 ただ、一番重要なのは、信頼できる会計事務所なりを探すことかと思います。

支払いについては、フィリピンは小切手文化です。 個人で日常的な支払いをする上では現金かクレジットカードになりますが、仕事上では小切手を多用することになります。 日本のように銀行間の送金がオンラインで簡単にできるといった仕組みにはなっていないのが大きな理由だと思います。 私は日本では小切手を使ったことがありませんでしたが、慣れればなかなか便利だと思いました。

自分の身の回りのことについてはあまり人に任せないようにしています。 住居探しは自分で行いました。 フィリピンでは日本と違って賃貸情報がインターネット上で便利に手に入るわけではありません。 インターネット上に出ている少ない情報を元に相場感を掴んで、良さそうなコンドミニアムに当たりを付け、直接コンドミニアムの受付に行って、予算を伝えて仲介屋を紹介してもらいました。

海外生活

海外で生活をする上で気をつけるべき事は、まず身の安全、社会保障、現地の法律といったことかと思います。

フィリピンで何かトラブルがあり裁判になった際には、自国民に有利なように裁判がなされる傾向があると聞きます。 フィリピンは近代的な立法に基づく民主主義国家ですので、民法、刑法について、日本人が感じる違和感はそんなにないと思います。 自分がよその国に滞在している外国人だということを肝に銘じて、慎み深く振る舞えば問題は起きづらいかと思います。

病気や怪我の際は、日本の健康保険に入っていれば、現地でかかった医療費の明細などを提出して支払いを受けることもできるとの話です。 しかし、一度全額を負担する必要がありますし、支払額は日本の医療費を基準に算出されるらしいので、現地で実際にかかった費用がどれだけ賄えるかも不安です。 保険については現地でキャッシュレスの医療サービスが受けられるものに入っているべきでしょう。 尚、クレジットカード付帯の保険は最大で90日間の滞在までの保証になっていると思いますので、注意が必要です。

健康のことでは、海外うつのような話もちらほら耳にします。 健康や生活に不安があるとそういったことも起きやすいかと思いますので、対策としては、安全で住みやすい場所を確保して、食事や睡眠に気を配るのがまず一つかと思います。 現地でのリアルな交友関係も、何かがあったときの助けになるでしょう。 脳科学や心理学の知識は自分の状況を冷静に分析して対策を練る助けになると思います。 あとは酒の力でしょうか。

セキュリティに関しては、私が滞在するマカティのビジネス街に限っては問題を感じたことはありません。 お店やレストランなども多く便利で、東京にいるのとそう変わらない感覚で生活ができるように感じます。 一方でマニラ首都圏には全国から様々な人が集まってきており、きちんとした職を持たず犯罪に走る方もかなりいるようです。 安全な地域を把握して、その中からなるべく出ずに、危険な場所には近づかないこと。 安全だと思う場所でも気を抜きすぎないことが重要かと思います。

マカティでの生活はかなり便利ではありますが、日本ほどではありません。 Amazonで何でも注文するということはできませんし、フィリピンで随一のショッピングモールに行ったとしても品揃えは日本に及びません。 品質の良い物は大概輸入品ですので、関税がかかって高くなります。 コンピュータガジェットなどに関しても日本で買うより割高です。 ローカルマーケットで買えば安いような野菜であってもマカティのスーパーではけっこうな値段がします。 日本にいるのと同じ生活レベルを求めれば、かかる費用は日本にいるより増してしまうでしょう。 ただ、服装については年中半袖シャツで通じるので、安く済むと思います。

インターネットの発達で、海外にいても日本の家族や友人と、少ない費用で簡単にふれあえるようになりました。 フィリピンは日本との時差が1時間しかありませんので、日本の地方にいるのとそう変わらない感覚にも思います。 電子書籍の出版も増え、オンラインで日本語の最新書籍を手に入れることもできます。 日本で開催されているカンファレンスなどはなかなか参加できませんが、講演のビデオが公開されることがほとんどですし、Rebuild.fmのようなポッドキャストもあります。 便利な世の中だなあと思います。

フィリピン

フィリピンはまだまだ様々な問題を抱えていると思います。 貧困はなくなりませんし、政府の手が及ばない危険な地域もあります。 首都圏の交通渋滞は酷くなる一方で、首都圏を中心に乱立したコンドミニアムには不動産バブルといったことも懸念されています。 出生率の低い今の中所得層が高齢化を迎えた際には、日本が直面しているような高齢者介護問題を抱える危険性もあるでしょう。

しかし、高い英語力を誇り、安定したインフレ率を維持し、人口構造はまだきれいなピラミッドを描き、日本との関係も安定しているといった良い側面もたくさんあります。 労働力の供給元としての存在感は今後も増していくでしょうし、消費意欲が高いことから市場の成長も期待できると思います。

フィリピンと言われてピンとこない人も、セブと言われれば旅行先として名前を知っている人もいるでしょう。 最近日本人からは英語学習の場として、英語留学先やオンライン英会話のサービスも注目を浴びているかと思います。 中国一辺倒だった日本のオフショア開発も、賃金上昇や政治的なリスクの高まりからアジア周辺の他の国々に分散するようになり、その候補の一つとしてもあげられるようになっています。

フィリピンは英語力の高い国ですので、IT/BPO産業の主な取引先は英語圏、地理的に近いオーストラリアや歴史的に繋がりの強いアメリカといった国々のようです。 そういった背景から、ベトナムや中国のように日本語でシステム開発の発注ができる現地企業がたくさんあるわけではありません。 日本をターゲットにしているのはうちみたいな日系企業くらいだと思います。

しかし、某ポッドキャストによると、最近のエンジニアは英語を話せないといけないらしいです。 日本人の英語力は問題とならなくなってくることでしょう。 ベトナムでオフショアのマネジメントをした友人からは、通訳を通じてではまだるっこしくなるので、結局はカタコトの英語でのやりとりが発生するとかいう話も聞きました。 こういった風潮は日本からフィリピンに仕事を持ってくる後押しになるかと思います。

この国がもっと盛り上がって、自分の仕事も増えたらいいなあと思ってます。