vue.js + Cordova + Kotlin + SpringBoot + MySQL というスタックでSPAを作ってみて

タイトルの通りのスタックでSPAを作成したので得た知見とかを書きます。
iPhoneとAndroidのアプリとしてリリース済みです。
vue.jsは1.0系です。

# それぞれの技術を採用した動機

## Cordovaを採用した動機
開発チームが小規模なためiPhoneとAndroidの両方を別々に開発していくのは辛いという問題がありました。
HTML5によるハイブリッドアプリにすることで少ない開発リソースで複数のプラットフォームをサポートできるようにするためCordovaを採用しました。

## Vue.jsを採用した動機
別にReact.jsでもRiot.jsでも良かったのですが、自分がしばらくVueを使っていたため多少ノウハウがあることや、ラーニングコストが低そうなことからVueを選択しました。
ちなみに、開発開始時には既にVue2.0のリリースが見えていたため、最終的にVue2.0に移行することを考えていましたが、意外と違いが多く、リリースまでに移行することは断念しました。vue本体のバージョンアップにはそれほど変更を必要としないのですが、vue-routerなど周辺ライブラリが大きく変わっています。

## Kotlinを採用した動機
WebSocketが扱える、パフォーマンスが期待できる、静的型付けなのでリファクタリングしやすいといったメリットがあるので採用しています。
というのが建前で、ぶっちゃけrailsでもphp+nodejsでもなんでもよかったです。
使いたかっただけ。

## Spring-Bootを採用した動機
KotlinのHTTPフレームワークとしてはもはやデファクトスタンダードと思われます。
JetBrainsがSpringBootをうまく扱えるようにIntelliJのKotlinプラグインなどを調整してくれています。

# 使ってみて

## Cordova

### プラグイン機能と公開リポジトリのおかげで様々なネイティブ機能を簡単に実装できました。

特にプッシュ通知や決済関連の機能はプラグインでやってくれるのでネイティブコードの実装は０でした。
いくつかの機能はネイティブで実装する必要がでてきましたが、今回の開発で実装したネイティブコードは1K未満です。

### 非エンジニアが直接UIを編集することで開発効率を上げられた

HTML/CSSを理解できる非エンジニアが直接UIを編集できたため開発効率を上げられました。
これはCordovaのおかげだけでなく、Vue.jsでテンプレートがロジックと分離されていて、ほぼ通常のHTMLであるおかげもあると思います。

### 広告SDKがfileスキームに未対応で困った

Cordovaは基本的にhttpではなくfileスキームのURLで動作します。このため、URLにスキーム名の省略表記(URLを://で始めるやつ)を使っているとロードに失敗します。
回避策として、最初はローカルサーバーを起動して無理やりhttpスキーム上で動くようにする方法を取りましたが、これによりGeolocation APIが動かなくなりました。Geolocation APIはhttpsでしか動かない仕様です。仕方ないのでGeolocationの処理はネイティブで動くプラグインを導入してこの問題も回避しました。
更に、起動時にロード時間が倍以上に遅くなるという問題も発生しました。
なんか色々辛すぎるので、この段階でダメ元で広告代理店にSDKをfileスキームで動くようにできないかお願いしたところ、さくっと修正くれました。感謝。最初から修正依頼しておけばよかったです。

### プラグイン開発のOSSコミュニティの盛り上がりがあまりない

プラグインはたくさんあって助けられることは多いのですが、結構需要がありそうなプラグインでもGitHubを覗くとあまり開発が活発ではない場合が多く、不安になる場面が何度もありました。
特に困ったのが、Androidではアップロードするファイルを選択するのにネイティブの実装が必要になるのですが、そのためのプラグインでまともに動作するものがなかったことです。仕方ないので、ほとんど更新されていないプラグインをフォークして作り直す必要がありました。

## Vue.js

vuexやvue-router,vue-loaderも使っています。

### 品質が高い
ドキュメントが充実しており、フォーラムもあるため、調べれば大抵のことは分かりました。
開発終盤までバグに悩まされるようなこともほとんどなく、快適に開発できました。
vue自体はかなり品質が高いように感じられました。

### 一度だけvue-routerのコード変更が必要な事態が発生した

vueの問題ではないですが、一度困ったのがSafariのバグに起因するHistory API使用時の問題です。
これはプルリクがあったので勝手にマージしてnpmにpublishしたものをpackage.jsonに記述して凌ぎました。
既に本体で対応されているかは謎です。

Safariのバグ: https://bugs.webkit.org/show_bug.cgi?id=156115

CordovaではfileスキームなのでHistory APIを使っていないのですが、開発中はhttpスキームなので対応する必要がありました。

### コア開発者が少ない問題

vue.jsは本当によくできていて開発速度も十分なのですが、コア開発がほぼEvanさん一人というところに少し不安を感じました。
ただ、vue2.0が出てからドキュメントだけでなくコードのプルリクなども増えた印象がありますので、これから改善しそうです。
GitLabもvue.jsを採用するなど、vue.jsの広がりを感じます。

参考：
[Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/)

## Kotlin + SpringBoot

この組み合わせでREST　APIサーバーを構築しています。
Thymeleafなどのテンプレートエンジンは使っていません。

開発上大きな問題はありませんでしたが、SpringBootはKotlinに最適化されているわけではないので、記述的に冗長になったり気持ち悪さを感じる部分はそこそこありました。
例えば、@AutowiredでDIする場合は変数をnullableなvarにしなくてはならないことや、Kotlinのnullableではなく、代わりにJavaのOptionalを使わなくてはならない場合があることなどです。

また、KotlinがJavaとしてどのように解釈されるのかがイメージできていないと、どのように記述すべきなのかや、エラーの理由が分かりにくい場合があるかもしれません。

## また最初から作るとしたら検討したいところ

### 通信手段
APIはREST APIにしているわけですが、REST APIでうまく通信するためにクライアントでaxiosのラッパーを作ったりサーバー側で面倒なフィルターを作ったりする必要がありました。
またURI設計に悩まされることも多々。
公開するAPIというわけでもなければ、grpcなども検討した方がいいかもしれません。
(その場合Spring Bootという選択肢は微妙になりますが)
ただgrpcにするとリバースプロキシでキャッシュとか難しくなりそうなんで、うまいこと両方の利点を得られるような方法がないかも模索したいです。

# その他
__devnekoはサーバーサイドKotlinを応援しています！！__
__devnekoはvue.jsを応援しています！__

__ぜひご検討を。__