やっとお披露目できる状態になりましたよ〜
今までのtree-mapsも内容的にそれほど悪くなかった(と思っている)のですが、流石にjQuery + Knockout.jsを何とかしたいのと、GAE/Javaのスピンアップ速度の遅さを何とかしたいと思っていました。
そこで去年くらいからこそこそと勉強していたのですが、ようやく今回リリースできそうな段階まで持っていく事ができたので、リリースしてみました。多分動くと思ったので、リリースしてやりました!
※ 今回はかなり長文です。
※ 技術要素をつらつら書いていますが、精密な言葉は使っていません。あまり突っ込まないで下さい。
- 新tree-maps
- インフラ
- バックエンド
- フロントエンド
- データソース
- 新tree-mapsはどう変わったか
- 新機能について
- バグ等の解決していないこと
- これから開発するかもしれない機能
- GAEで欲しいもの
- 雑感
新tree-maps
↓↓↓↓↓↓
↑↑↑↑↑↑
こんな感じです。GAEにはバージョンという概念があり、旧tree-mapsのアプリもいつでも動かす事ができます。
もし旧tree-mapsを使いたい場合、トップページの下部か、左サイドナビの「旧tree-maps」リンクから使う事ができます。
インフラ
インフラはGAE(Google App Engine)のまま、変更はありません。
が、しかし、ランタイムを変更しました。今まではJavaでしたが、今回はGolang(GO言語)にしました。
Golangは何を解決したのか
Golang選択の理由は非常にシンプルで、Javaよりも高速で、Javaよりもコンテナのスピンアップ速度が遥かに高速だからです。
どれくらい高速なのかは以前以下の記事を書きましたので、合わせてどうぞ。
www.bunkei-programmer.net
今回Golangをランタイムとして使ってみて、以下の感想を持ちました。
ランタイム | 書きやすさ | スピンアップ速度 | 処理速度 |
---|---|---|---|
Java | ◎ | ☓☓☓ | ◯ |
Golang | ☓ | ◎ | ◎ |
本当はJavaで書きたかったのですが、Javaのスピンアップの速度の遅さが半端ではなく、他のメリットを全て帳消しにする程のものだったので、Golangを採用しました。JavaはIDE支援が超強力なので、目茶苦茶書きやすいのです(完全に個人の主観ではありますが)。
スピンアップが遅いとコンテナが起動するまでの速度が遅い=画面が表示されるまでが遅いという事になるので、ユーザの離脱率が跳ね上がるわけです。Golangをランタイムにする事で、それを大幅に軽減する事ができます。単純に動作速度もトップクラスの速度なので、Ajaxでjsonを取得するリクエストをガンガン投げても高速にレスポンスを返すこともできます。
スピンアップ・スピンダウンとは
念のため説明しておくと、GAEのインフラは、一定時間サイトにアクセスが無いと、なんと(仮想)サーバが削除されます。これはリソース(物理的なメモリ消費量
ディスク使用量・電力・通信量)を出来る限り節約するためです。このサーバごと削除される事をスピンダウンと言います。
スピンダウンしている状態からサイトにアクセスされると、Google内部ではサーバの構築・アプリケーションやフレームワークの起動が行われます。このGoogle内部のサーバ構築をスピンアップと呼びます。サーバはフルマネージドで恐らくVMWare的な仮想環境上で管理されており、プログラマブルにサーバのインスタンスの生成・削除が行われます。
この考え方は今AWSで流行っているAWS Lambdaと同等です。GAEがアプリケーション単位なのに対し、AWS Lambdaは関数単位という違いはあります。
バックエンド
まず、リニューアル前のバックエンドについて説明します。
フレームワーク
No | 使用フレームワークの変遷 |
---|---|
1 | Seasar Slim3 |
2 | Play framework v1 |
3 | Servlet v2.6 |
実は3回フレームワークを変更しています。Slim3はすぐやめたので実質カウントする必要はないですけどね。
最初はPlayのv1系で頑張ってGAEを開発していたのですが、途中で開発が全くされなくなり、音沙汰もなくなってしまい、終いにはデプロイコマンドが失敗する状態にまでなってしまいました。GAE上でスピンアップからPlayの初期化速度も非常に遅く嫌気が指していたので、デプロイ失敗を機に素のServlet、しかもv2.6系に回帰しました。
Servletに回帰した事でスピンアップ後のアプリの起動完了までの速度は大分速くなりました。が、フレームワークの利便性が無くなり、開発は厳しくなりました。
そしてリニューアルです。使用言語はGoogleのGolangなので、Golangのフレームワークを選定する事になります。前述のスピンアップ速度調査記事ではGin(ジン)を選択していましたが、今回新tree-mapsではecho(エコー)フレームワークを選択しました。
echo選択の理由は、Ginよりも更にシンプルで高速(多分)で、何よりGithub上のコミット数がGinよりも多く、これは開発が活発に行われているな!と確信したので、echoにしました。まあGinもechoも対して機能の違いは無いので、どちらを選んでもいいと思います。
とまあフレームワークのお話をしましたが、正直バックエンド側はルーティング以外何もしていません。。。今回バックエンドが行っているはなんと以下だけです。
- ルーティング
- リダイレクト(実はプロットをprotとtypoしていたのは内緒)
- htmlテンプレート(divが一個あってgooglemapのjsとadsenseのjsをロードする程度)
.goファイルの数はなんと2ファイルだけです。しかもトータルで300行で収まるくらいです。最近の開発ではサーバ側はjson生成器みたいなものなので、これでよいのです。下手にhtml生成をサーバ側で頑張らない方針なのです。
ビルド
単にgoapp deployのみです。変に頑張ってはいません。
フロントエンド
カオスを極めるフロントエンド
さて、問題のフロントエンドです。バックエンド重視からフロントエンド重視にトレンドは推移し、未熟極まるフロントエンドがここ数年で常軌を逸した進化をしており、沢山のフレームワークが現れ、あっという間に廃れていきます。それは今も尚続いています。
javascript界隈
javascriptのフレームワークの栄枯盛衰は以前より少し収まり、以下で落ち着いたと思われます。
※ FW = フレームワーク(framework)
FW名 | 学習コスト | メリット | デメリット |
---|---|---|---|
React | 高 | ビューのみなので他の技術要素との組み合わせがし易い。 | FWではないので他機能の組み合わせが必要。 |
Angular | 高 | フルスタック。全部入りなのでライブラリの組み合わせで迷わない。 | angular wayの縛りの強さ。 |
Vue | 中 | 他FWのいいとこ取りで学習コストが低い。小中規模に強い。 | 大規模は厳しい? |
jQuery | 低 | デザイナが片手間にできるほど簡単。 | もう時代に則さない。大規模は地獄。 |
大体こんな感じではないでしょうか。他FWも沢山ありますが、メインはこれらに絞られた感がしています。ReactとAngularについては正直結構学習コストは高いです。Reactはビューのみなので学習コストは低い!という声もありますが、アプリはビューだけでは済まないので、他ライブラリ等を総合すると、結局学習コストは高いと思います。
Angularについては、Angular v1系から言われていますが、依然として学習コストは高いです。が、フルスタックなので、Reactほど他ライブラリとの組み合わせに疲弊する機会は少ない???ので、学習したなりのリターンはありそうです。
一方Vue.jsですが、javascript界隈の壮絶で地獄の栄枯盛衰を横目に、最近非常に注目を浴びて急上昇しています。ReactやAngularよりも学習しやすく、小〜中規模に優しいため、参入障壁が低めなので、人気が爆発してきています。最近ようやくレガシーIEの排除も本格的に進み、今までレガシーIEのせいでVue.jsの採用を見送り、Knockout.jsを選択していた人もいると思いますが、その呪縛も薄れ、Vue.jsを採用しやすくなったのも、人気上昇の要因の一つだと思われます。
jQueryは、デザイナとの協業を考えると、根絶する事は不可能に近いと思います。特に外部にデザインを発注する場合、jQuery必至になりがちです。jQueryプラグインの資産も膨大で、jQueryに依存し過ぎてしまっているので、jQueryの脱却はほぼ無理なのでしょうね・・・とはいえjQueryのお手軽さは非常に優秀で、ReactやAngularやVue.js等と違って開発環境構築は不要で、jquery.jsをロードするだけでサクッと開発が始められます。ちょっとしたデモなら、jQueryが活躍する場面は多いです。
CSS界隈
一方CSSは静かだと思いきや、SCSS、LESS、Stylus、SASS等が登場したり、BEM等の記法論争があったり、実は水面下で激しい論争が繰り広げられていました。それらも少し落ち着きつつあるようで、どうやらメインストリームはPostCSSになりそうな感じですね(賛否両論あると思います)。
ビルド界隈
フロントのビルドについては、Gruntは廃れ、Gulpとwebpackの2強の状態はそれほど変わっていないと思われます。強いて言えばGulpを排除してwebpackのみで完結するパターンが増えていると思いますが、まだまだgulpも使われているようです。
AltJS
残念ながらCoffeeScriptはHubotスクリプト以外ではほぼ見なくなりました。元々AltJSは歴史が浅く、論争も少ない方なので、CoffeeScriptの衰退以外はほぼ変わっておらず、メインストリームは以下だと思われます。
名称 | メリット |
---|---|
Babel | 静的型付け無しで、利用例は多くお手軽に導入できる。 |
TypeScript | 静的型付け有りで、Microsoftが開発しているので採用しやすい。 |
その他にはGoogleのDartもありますが、これはメインストリームとは言い難い状況のようです。とりあえずBabelかTypeScriptのどちらかを選択しておけば間違いは無い感があります。
UIフレームワーク界隈
flexboxベースのUIフレームワークが増えてきていますが、依然としてBootstrap、Foundationが多いと思われます。Material Design Liteはスクロール周りにバグ?を抱えていたりして採用しづらいです。最近ではReactやAngularにベッタリなUIフレームワーク、例えばmaterial-ui、Blueprint、Angular Material、OnsenUI、ionic等も続々登場しています。
新tree-mapsではどうしたか
さて、論争を説明したところでようやく本題に戻ります。(それだけフロントエンド界隈が激しいので技術選定も悩みました)
新tree-mapsでは大まかに以下を選定しました。
種別 | 名称 |
---|---|
アーキテクチャ | シングルページアプリケーション |
ビルド | webpackのみ。 |
AltJS | Babel。ES2015,ES2017 |
FW・ライブラリ | react, react-router, axios |
CSS | PostCSS, sugarss |
UIフレームワーク | material-ui |
reacを選択しました。はい。
Angularと迷ったのですが、私が迷っていたタイミングではまだAngular2が正式リリースされておらず、タイミングが微妙だったのと、リリース当初のAngura2は微妙な空気があったので、Reactとなりました。Vue.jsも迷いましたが、会社の業務の採用例的にも今回はReactに軍配が上がりました。reactなので、今回はSPAにしています。
UIについては、最初はFlexboxベースのbulmaを使っていたのですが、欲しいコンポーネントが足りないので見送り、マテリアルデザイン全開で、採用例も多いmaterial-uiにしました。コンポーネントも多く、これは素晴らしいです。
CSSについては、そもそもmaterial-uiがデザインのほとんどを吸収してくれるので、ちょっとしたCSSが書ければ何でもいい、生cssでも全然問題無いのです。まあPostCSSが流行ってきているので、折角なのでPostCSS+sugarssにしました。残念ながら今回cssはたった1ファイル、しかも140行しか無いのですけどね。。。
苦労した点
props???
今回React + Babelなわけですが、jsx記法は思ったよりすんなり入れました。キモい感はしますが、別にいいんじゃない?程度の感覚です。jsxのキモさよりも、reactのpropsを理解するのに少し時間がかかりました。stateは単純に現状の状態、例えばテキストボックスの入力値やラジオボタンの選択値がstateに当たるわけですが、propsとは???と中々理解が進みませんでした(今もですが)。
this???
以下は実際のtree-mapsのジオコーディングするボタンのコンポーネントですが、「は?何このthis。どこに対するthisなんだよwwww」「this.handleSubmitのhandleSubmitって何だよ。関数なのかプロパティなのか解らねーよ!」というような感じで、どこの事を指しているのか、どこの何を呼ぼうとしているのか、がさっぱり解らず、かなり苦労しました。。。賢い方たちはこれを瞬時に理解できるようで、羨ましいです。
<RaisedButton label={'ジオコーディングする'} secondary={true} icon={<FontIcon className="muidocs-icon-custom-github"/>} onTouchTap={this.handleSubmit} disabled={this.state.buttonDisabled} style={{width: '100%'}} />
bind地獄
bindについても最初は「はあ!?何だこれ。bindだらけになるじゃねえか!!!」と思っていました。
this.handleFunc1 = this.handleFunc1.bind(this); this.handleFunc2 = this.handleFunc2.bind(this); this.handleFunc3 = this.handleFunc3.bind(this); ・・・以下thisを使う関数毎に書く・・・
実際にplot画面では20個近くの↑こんな感じのbindが並びました。で、java脳な私は「こんなのアノテーション一発で済ませろよボケェ!」と思っていたら、ありました。ボケェなのは自分でした。
github.com
今回は自分だけが開発するアプリなので、class定義に@autobindしてしまい、bind地獄から解放されました。
redux
reactのpropsやbindなど、基礎の理解が全然進まず、FBの公式チュートリアルをこなしても、いざ「これを作ろう!」と思った時にチュートリアルでやった事が全然活かせず、四苦八苦していました。
結局state管理については各コンポーネント内で行っており、reduxは使いませんでした。reduxを使うとバケツリレーを避けられるというメリットを知りつつ、react-routerを動かすのに苦労したりして、結局勉強する間もなかった(言い訳)ので、採用には至りませんでした。
今になって思いますが、あると凄く嬉しいですね。。。たかがメニューの選択値をAppBarに表示するのだって、reduxが無いとバケツリレーを凄く頑張らないといけないし、グローバルな状態管理は無いと恐らく破綻するなあ、という予感が今頃しています。
しかし今まさに行われているreduxのmiddleware論争は熾烈を極めつつあり、結構ガッツリ変わりそうな予感がしているのですよね。この辺は今丁度ホットな戦場なので、好きな方は是非論争に参加してみて下さい。。。
material-ui
最初はBootstrap的に扱えるのかなあ〜、とか楽観視していたのですが、違いました。
「書き方が解らねえ・・・解らねえぞ!!!」
たかがボタン一つ表示する方法も解らない。最初は絶望しました。今となっては理解できて便利に使っていますが、最初の絶望感は半端ではありませんでした。
<RaisedButton label={'ジオコーディングする'} secondary={true} icon={<FontIcon className="muidocs-icon-custom-github"/>} onTouchTap={this.handleSubmit} disabled={this.state.buttonDisabled} style={{width: '100%'}} />
↑前述の例ですが、「RaisedButtonって何?どこでどうやって定義してるの?」「アイコンどうやって表示するの?」「イベント貼るのどうやるの?」「何かスタイルの定義が効かないんだけどなんで?」等、様々な困難が待ち受けていました。
結局、RaisedButtonはmaterial-uiが事前に用意してくれている、htmlを出力するコンポーネントで、それをimportすると使えるようになります。
import RaisedButton from 'material-ui/RaisedButton';
iconの行を見ると一瞬「は?ぶちのめすぞ!!」等と思いますが、iconというpropsに、FontIconというコンポーネントを渡しているだけなのです。javaで言うと、RaisedButtonというクラスに対してsetIcon(FontIcon fontIcon) しているだけなのです。
イベント定義についてはもう「リファレンス見ろ」なわけですが、thisというのはReact.Componentクラスを継承したクラス、つまり今自分がいるクラスの事で、javaでいうと、自分のクラスのメソッドを呼んでいるだけです。handleSubmitはプロパティではなくメソッドです。
classNameでスタイルを定義しても効かない問題ですが、これは単純で、material-uiのコンポーネントの中にはインラインでcssを定義しているものがほとんどなので、classNameよりも優先されるインラインcssに負けてしまい効かない、という事でした。これは抜け道が用意されていて、propsにstyleを使うと、initialStateより優先してstyleを使ってくれるので、結果的にデフォルトのインラインcssに勝つ事ができます。react-sidebarではこの問題に嵌まりました。。。嵌ったおかでで色々学べたのですけどね。
SPA???
もう全然解らん。意味解らん。というのが最初の感想でした。
簡単に言うと、昔frameでhtmlを切り替える手法(古すぎるか・・)がありましたが、あれです。ajaxで各ページを読み込んでいるのではないです。コンポーネントを切り替えてもhttpリクエストは走りません。しかしこれだけだと、ブラウザのアドレスバーのURLは変わりません。
そこでPushStateを使います。PushStateによって「ブラウザのアドレスバーのURLを変える」「ブラウザの閲覧履歴を追加する」という2つの事を行う事ができます。実際はhttpリクエストせず画面遷移もしていませんが、擬似的に画面遷移した時と同じ事をしているのです。
PushStateでURLを変える事は解りました。という事は、サーバサイド側でそのURLを受け付ける事ができるルーティングが必要になります。ここでまた困惑します。サーバサイドのルーティングですが、対象ページのURLのルーティング設定はしますが、全て同じhtmlを返却します。「/」でアクセスされても、「/plot/」でアクセスされても、全て同じhtmlを返します。結局のところhtml内ので「id="hoge"」に対してreactがコンポーネントをガッツリ描画するので、同じhtmlを返せばいいのです。
サーバサイドのhtmlテンプレートエンジンで頑張っていた部分の大部分は無くなり(headタグ内は必要)、全く同じhtmlを返す事になります。そこから先はreactがhtml生成を頑張ります。つまり、サーバサイド側は本当にやる事が無くなります。
これでメニュー変更が画面遷移もhttpリクエストも無く実行する事ができ、PushStateでアドレスバー更新・履歴追加も行い、/plot/等でアクセスされてもサーバサイドのルーティングによってindex.htmlが返る。つまりこれがSPAなわけです。実際サイトを使って頂くと解ると思いますが、「くっそ動作が軽い」「一体どこでhttpリクエストしてるんだ!?」と思う程軽快です。時間がかかるのはせいぜいjsの初期ロード程度です。
webpackによって複数のjsは1ファイルにまとめられ、cssはjs内に隠蔽され、最終的にhtmlのbodyタグ内はdivタグ1個と、bundleされたjsを1ファイル読み込むだけになりました。当然bundle.jsはファイルサイズが大きめになりますが、deflateしてgzip圧縮転送したり、エッジキャッシュを効かせればそれを軽減できます。
データソース
所謂データベース等ですが、全く未使用です。制限が厳しすぎるが性能劣化が無いDatastoreがありますが、今回未使用です。
現状では特に使う部分はありませんね。
新tree-mapsはどう変わったか
技術要素の刷新によって一体tree-mapsはどう変わったのでしょうか。
高速になった
高速になるというのは、言うのは簡単ですが、実際にそれを行うのは非常に難しいです。処理速度は技術要素に依存する面も強いので、古い技術を使っているとそもそも高速になりにくい部分もあります。今回は以下を解決する事で、サイトの高速化を図りました。
スピンアップ
ランタイムをGolangに変更したい事で、スピンアップが激遅問題は解決しました。これでいつアクセスしても常に超高速です。
SPA
SPAにした事で画面遷移が無くなり、サーバサイド側で行う事が減ったので、画面が表示されるまでの速度と画面上の操作は非常に高速になりました。
bundle
webpackによって1ファイルのjsに全て押し込めた事で、ロードするjsの量が減り、更にdeflate + エッジキャッシュによってjsの読み込みも高速化しています。httpリクエスト数も減ったので、キャッシュが有効ならhttpリクエスト数も非常に少なくなります。
機能追加のし易さ
reactもある程度使っていると、「あ、これjQueryでは厳しいけど、reactだとできるわ」という部分が出てきます。特に「チェックボックスがこういう状態で、テキストエリアがこういう状態の時、ボタンは非活性になる」等の、複雑な状態が絡む処理はreactは圧倒的に楽です。jQueryと違ってdomの状態を気にする事も無く、単にstateの値だけで判断でき、stateの状態が全てのイベントとリンクしてくれるので、これはバグも起きにくいなと感じました。
モバイルファースト
material-uiを使っていると強制的にモバイルファーストになります。旧tree-mapsではTwitterのbootstrap v3で一応レスポンシブ対応していましたが、モバイルは全然意識していませんでした。今回はmaterial-uiなので、Androidのスマホを使っている方には見慣れたUIだと感じると思います。
Googleもこのモバイルの波を意識し、ついにPCサイトよりモバイルサイトの方に軸を変更してきているので、例えそのサイトがモバイルで使われる類のものでなくてもモバイルファーストでなくてはならないのです。
これってtree-mapsのようなどう考えてもPCでしか使われないサービスにとってはモバイルの存在は邪魔でしかなく、モバイルファーストの強制も何だかなあ、という感じがします。実際GAで見ても、PCが95.6%で、残りがモバイル等です。これでモバイルファーストを強制されるのはねえ・・・
新機能について
ジオコーディング・逆ジオコーディング
ジオコーディング or 逆ジオコーディング実行後、入力・変換された緯度経度を使って即座にgoogle mapに描画するようにしました。
プロット画面
マーカーの色を選択できるようにしました
以前から要望がありましたが、googlemap標準の薄い赤のピンだけでなく、黄・緑・白・青・紫を選択できるようにしました。
通常の赤いピン以外の表示ですが、google earth等のgoogleのアイコンを利用する事で、赤いピンと同等の描画速度を実現しました。google製のピン以外では処理速度が遅く、正直使い物になりませんでした。
中心点を選択できるようにしました
入力された緯度経度の1行目を中心点とみなすか・みなさないかを選択可能にしました。更に中心点のアイコンをgooglemapでお馴染みにのピンではなく、独自の家マークアイコンに変更する事ができるようにしました。更に、中心点はプロット時にぴょんぴょんアニメーションするようになり、より目立つようにしました。
中心点から半径nメートルの円を描く
他のサイトで円を描く機能を持つサイトがあるので、パクってみました。
この機能の使い道としては、中心点を基準に円を描くので、中心から見て半径nメートルに含まれるピンの位置を視覚的に確認できる、といったものを想定しています。
ちなみに円の色と円の半径を変更可能です。
元の位置に戻る
プロットしていて迷子になった事はありませんか?沢山の緯度経度をプロットしていて、地図をスクロールしていると「あれ?最初の位置ってどこだっけ、戻りたいんだけどなあ」と思う事ってあると思います。そんな時、「元の位置に戻る」ボタンをクリックしてみて下さい。クリックすると、最初にプロットした時の位置・ズームの状態が復元されます。
クラスターに対応
これは旧tree-mapsにもありましたが、使い方がいまいち解らないという声がありました。
簡単に説明すると、現実世界に例えると、例えばビルがあってそのビル内の部屋毎に緯度経度を入力したとします。それをプロットしまうと、ビル内の部屋は全て同一の緯度経度なので、完全に同じ位置に複数のピンが重なって表示される事になります。
すると、見た目はピンが1件しか無いように見えるのに、実際は100件重なってました〜、なんて事がおきます。それを回避するため、一点の範囲に存在するピンをまとめ、その範囲に含まれるピン数を表示する、というピンのまとめ表示をする事で、重なってしまう問題を解決します。
これは地図のズームを引いた場合、例えば日本全体を表示した場合に如実に現れます。東京都にピンを1万件配置しても、日本全体が見えるくらいまで引いてしまうと、ピンが目茶苦茶重なってしまいますね。その時クラスター表示なら、まとめて表示してくれるので、ちゃんと視覚的に(数値で)確認する事が可能になるわけです。
クラスターのサイズ、ピンをまとめる範囲を変更できるようにしていますが、デフォルトの40pxが最も扱いやすいまとめ範囲だと思ったので、とりあえず40pxのまま使うとよいと思います。範囲を狭めるとクラスター同士が重なってしまったりするので、40pxというのは絶妙な範囲なのです。
ヒートマップに対応
これはtree-maps開発ブログの方で既に告知しましたが、ヒートマップに対応しました。
クラスター表示より沢山の緯度経度を扱う事ができます。試しに20万件の緯度経度で試してみましたが、地図自体は軽快に動作しました(但し地図描画するまでが遅い・・・)。
使い道は・・・ユーザにおまかせします。
バグ等の解決していないこと
隠さずに全部書いてしまいますよ。
スクロール位置が持続される
例えばトップページで下の方までスクロールします。その状態で左サイドナビで他のメニューを選択します。するとあら不思議、選択したメニューのスクロール位置がトップページのスクロール位置になっています。スクロール位置まで記憶されているのです。
以下を参考にしみたのですが、効かないのです。。。
github.com
使用しているreact-routerはv3.0.0なのですが、どなたか解決方法をご存知の方がいれば教えて頂きたいです。。。
SNSのタイトルがおかしい
厳密には、URLは正しいがタイトルは一つ前の画面のものになっている、です。
react-document-metaを使って、メニュー切替時にtitleタグ・meta descriptionを差し替えているのですが、差し替え後のtitleタグが取れていません。綺麗な解決方法は思いついていませんが、reduxを導入し、メニュー切替時にstateにtitleタグを保存し、snsボタン描画時はそのstateからtitleタグを取得する、みたいにすれば上手くいきそう?と模索中です。
DMS => DEG変換機能
特定のフォーマットに従っていないと変換できません。
以前はjavaでゴリゴリしていたのですが、golangであのゴリゴリをするのが面倒だったので、ライブラリを使ってごまかしています。。。優先度低めでいずれ直します。
サーバサイドレンダリング(SSR)
多分やりません。少なくともGolangではやりたくありません。。。node.jsだったら、これくらいの規模のアプリならやってもいいかな?と思います。
これから開発するかもしれない機能
グループプロット
これはアンケートをした時にも書いていますが、プロットをグループ単位で行えるようにしたいと考えています。
例えば、とあるイベントで、男性グループと女性グループがいるとして、人間全てに緯度経度データを持っているとします。その時、視覚的に「男性の場合はピンを青色に」「女性の場合はピンを赤色に」というグルーピングをしたい場合、現状のtree-mapsではできません。
男女だけでなく、「今日の緯度経度」「昨日の緯度経度」を同じ画面で確認したい場合も、グループを分けて色が異なるピンでプロットする事ができれば、視覚的に確認する事ができます。
これは個人的に非常に有用な機能だと思っているので、開発する予定です。
入力値の保存・復元
例えばtree-mapsのプロット機能を使う際に、必ず中心点を使う、更に色も毎回同じにしている、等という場合、毎回のその選択するのは煩わしいですね。それを解決するため、ローカルストレージに状態を保存し、次回画面表示時に使えるようにしようと考えています。
プッシュ通知
chromeでプッシュ通知ができるので、新機能通知機能ができるかな?等と適当に考えています。
アプリ化
アンケートで「webアプリかネイティブアプリかどっちがいい?」と聞いたのですが、ほぼwebアプリでした。理由は「環境構築が不要」でした。という事で旧tree-mapsと同様に今回もwebアプリとしています。
もしネイティブアプリであればもっと沢山の緯度経度を扱えると思いますが、環境構築(アプリのインストール)が鬼門の場合があります。会社でtree-mapsを使う場合にネイティブアプリだと、「許可されていないアプリのインストールは許可されない」等の壁が立ちはだかります。するとそもそもtree-mapsを使う事すらできない場合があるので、webアプリだと助かる場合が多いようです。
とはいえアプリ化すると嬉しい人もいると思うので、Electronでアプリ化できるかな〜?、等と安易にアプリ化を模索しています。
GAEで欲しいもの
GAE/node.jsが切実に欲しい
です。正直Golang+echoでは開発がし辛い事は間違い無いので、多少の速度を犠牲にしてもnode.jsにしたいです。
一応flexible environmentでnode.jsは動かせますが、それはもうStandardなGAEではなく、GCE上で動くGAEで、有料です。私が望んでいるのはflexible environmentではない真のGAE、フルマネージドなnode.jsランタイムなのです。これからの開発ではnode.jsが増え続けると思われるので、もしあれば皆使うと思うのですけどね。
あと、一応ですが、去年GCPに東京リージョンが出来たので、GAEで東京リージョンが選択できるようになりました。東京リージョンに変更する事で得られるメリットについては以下の記事をご覧下さい。
www.bunkei-programmer.net
雑感
もうね、FacebookのザッカーバーグCEOの以下の言葉通りです。
(本当は「完璧を目指すよりまず終わらせろ」という意味です。。。」
グループプロット機能を開発してからリリースしてもよかったのですが、それだとリリースするタイミングが遅くなります。それに、色々と開発してみたい機能はあるので、いつまで経っても正式リリースに至らない事だってあります。
特に技術要素については顕著で、次から次へと有用なフレームワーク・ライブラリが登場してしまうので「よーし、今回はこの機能を使うぞ!」→「ん?なんと!こんな凄いライブラリが出たのか!」等とやっていると、本当にいつまで経っても完成に至りません。以前以下の記事を書きましたが、プログラムを書く人にとって技術要素は甘い罠なのです。
www.bunkei-programmer.net
これはビジネスにも言えると思います。新しい技術要素を使ったり導入する事が目的となってしまい、利益を生み出す事の優先度が下がってしまう事がよくあります。確かに最新機能を使う事でインフラ維持費が減ったり保守コストが下がったりしますが、手段を目的としたくはありませんね。単にreactやangularが流行っているから導入するのではなく、それを使って何が解決できるのか、何を解決しようとしているのか、それらが自分達が抱えるどんな問題を解決してくれるのか、を考えて技術選定したいですね。
そして今回サイトの高速化と利便性向上と開発のし易さを解決するためreactを勉強しましたが、私のナメクジレベルの脳みそでは学習コストはかなり高いと感じました。もし自分がreact未経験者のチームを抱える事になったら、結構厳しいなと感じています。また、デザイナとの協業は難しいなと感じました。そもそもwebpackの使い方等のレクチャーが必要だったり、react以前の壁が高いのです。
reactをやるためにはjsxが動かないといけない、jsxを動かすにはbabel等が必要になる、babelを使うにはwebpack等が必要になる、webpackを動かすにはnpm・yarnを使う必要がある、npm・yarnを使うためにはnode.jsのインストール(nodebrewなど)が必要になる、node.jsを扱うには、ローカルにインストールするかdockerなどを使う・・・というように、あれをするためにはこれが必要になる、という事がフロントエンドには多く、そもそもやりたい事をやるところまで辿り付くのが大変です。
勿論webpackを使わない等の省略する選択肢はありますが、現実的にそれらを省略するのはトレンドから明らかに外れてしまう恐怖等があったりして、結局世間で言われているベストプラクティスのようなものに頼る事になります。すると学習コストがどんどん積み上がり、結局採用には至らない、なんて事も多いのではないかと思います。
結局今回私はその学習コストを支払ったのですが、「ああ、これが数年前に言われていた日本は遅れているという事か」という事が今頃はっきりと解りました。jQueryの世界とreactの世界は全く異なり、開発スタイルも大きく異なります。jQuery(しかもv1系くらいの頃の)の開発では如何に無駄で効率の悪い開発をしていたのか、如何にバグを誘発する開発をしていたのか、を身をもって知る事になりました。
ReactやAngular未経験者はいつかこれらを学習する必要があると思いますが、学習する際は詳しい人が側にいると非常に捗ると思います。特に両者は関連する技術要素が非常に多く多岐にわたるので、協力者がいると全く学習効率が違うと思います。私はサーバサイド側の人間で一人でこそこそ勉強していたわけですが、沢山嵌まり、沢山ググりました。そのコストは大きかったです。とはいえ問題にぶつかり、それを何とか解決に至らせるという能力を養う事には繋がりましたが、フロントエンドに関してはそれはあまりおすすめしませんね・・・それだけフロントエンドの世界がカオスなのです。
かといってカオスな世界を避けてしまうと、気づいた頃には自分の持つ技術要素が時代遅れで取り返しが付かない状況になったりする恐怖があります。もういっそ技術を捨て、SEやマネジメント方面へ行く選択肢もありますが、「自分の所有スキルが化石化してしまったので、仕方なくSEやマネジメントを始める」なんて動機でキャリアチェンジするのも怖いですよね。
・・・・などという事をボケーっと考えながら勉強していたのですが、真実を話すと、react採用の一番の理由は別に「あれを解決したい」とかじゃないんですよね・・本当は「世間の、それも日本ではなく世界のトレンドから取り残されて化石化するのが怖い」というのが一番の理由です。フロントエンドだけでなく、docker周りも避けてしまうとマズイなあという事も認識しています。
まだまだ勉強が足りていませんが、おっさんになったからといって勉強を避け、化石にならないようにしたいと思っています。これからIT業界はますます既存のSEの存在意義等が問われていくと思っていて、技術を知らない=存在価値の低下は必至だとも私は思っているので、頑張りたいですね。
なんだかtree-mapsの話とかけ離れてしまいましたが、こんな事を考えながらtree-mapsの開発をしていました。今回大きな告知なのでこっちのブログに書きましたが、移行は以下のtree-maps開発ブログに書いていきますので、今後ともよろしくお願いします!
tech.tree-maps.com