雰囲気でマイクロサービス入門をやってみた
ごんげお兄さんのエントリーを見て、興味あったのでやってみた。
TL;DR
- お兄さんのエントリー通りやると、雰囲気が分かるので超お勧め
- 動かしてからドキュメント眺めたらいいと思う
- GCP初めての人は$300のクレジットが貰えるぞ!
ありがたいなぁ。
補足
僕の環境はArch Linuxでかつ、GCPを触るのが初めてだったこともあって、いくつか追加の作業が必要だったのでそれだけ書いておく。最初にGCPのアカウントを開設して$300のクレジットを貰っておくように。
コマンドラインツールのインストール
AURにある。
$ yaourt -S google-cloud-sdk $ gcloud auth login # /opt以下に入るのでsudoで実行 $ sudo gcloud components install kubectl
初めてのコマンド前に認証が必要。ターミナルのコマンドからブラウザが起動してターミナルに処理が戻るの初めて見たかも知れない。
結構頑張ってついて行ってるのに、out-of-dateフラグ立てられてるのがかわいそう。僕もheroku-cliパッケージでたまに立てられるので気持ちは分かる。
コマンドラインツールの設定
リージョンやらプロジェクトやら色々設定しておいたほうが毎回オプションを渡さなくて済む。configの設定については https://cloud.google.com/sdk/gcloud/reference/config/set を眺める。
$ gcloud config set project micro-sample-XXXXX
Container Registry 有効化
dockerのimageをpushする際、Container Registryというサービスにpushするのだけど、これは有効化されてないとpushできない。ブラウザのコンソールから有効化するとよい。
環境変数の設定
対象のコードではBACKEND_SERVICE_NAME
という環境変数を使ってるので、その設定がいる。暗号化の仕組みも用意されてそうだった。バックエンドのIPを見たら設定しておく。たぶんドキュメントとかにコマンドラインとかから渡す方法が書いてあるんじゃないのって思ってるんだけど、どうなんすかね?
2017/10/06 追記
お兄さんにDNSあるよって教えてもらったので、そっちを使うほうが良さそう。IP変わるのでおっしゃる通りすぎる。コメントを参照のこと。ハマりどころがあって勉強になったぞ!!!!!!!1
ドキュメントによればKubernetes 1.3からDNSがビルトインされたようで、Serviceの名前がfooでKubernetesのネームスペースがbarの場合、foo.barで対象のServiceのクラスタIPが解決できる模様。ネームスペースやDNSの様子は以下のコマンドで眺められた。
$ kubectl get namespaces NAME STATUS AGE default Active 19m kube-public Active 19m kube-system Active 19m $ kubectl get svc --namespace=kube-system NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE default-http-backend 10.31.249.157 <nodes> 80:31925/TCP 21m heapster 10.31.247.113 <none> 80/TCP 21m kube-dns 10.31.240.10 <none> 53/UDP,53/TCP 21m kubernetes-dashboard 10.31.245.255 <none> 80/TCP 21m $ kubectl get svc --namespace=default NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.31.240.1 <none> 443/TCP 22m micro-sample-service-backend 10.31.244.62 <none> 8000/TCP 17m micro-sample-service-frontend 10.31.249.64 XX.XX.XX.XXX 80:32186/TCP 21m
ということで、バックエンドはmicro-sample-service-backend.default
で引けることになる。
ちなみにPodの中にはresolv.confが用意してあって、ドキュメントに書いてあるように以下のような定義になっている。
$ kubectl get pods NAME READY STATUS RESTARTS AGE micro-sample-backend-deployment-3300239719-22qdm 1/1 Running 0 38m micro-sample-backend-deployment-3300239719-mpjh9 1/1 Running 0 38m micro-sample-frontend-deployment-836517767-3vgzv 1/1 Running 0 10m micro-sample-frontend-deployment-836517767-vbbrp 1/1 Running 0 10m $ kubectl exec -ti micro-sample-frontend-deployment-836517767-3vgzv -- cat /etc/resolv.conf nameserver 10.31.240.10 search default.svc.cluster.local svc.cluster.local cluster.local c.micro-sample-XXXXX.internal google.internal options ndots:5
なのでネームスペースがdefaultの場合は、micro-sample-service-backend
だけでも引けるわけだけど、ネームスペースがいつもdefaultとは限らないので、ネームスペースと組み合わせた名前で指定しておくのがいいと思う。
追記終わり。
...
containers:
- name: micro-sample-frontend
image: gcr.io/micro-sample-XXXXX/micro-sample-frontend:v0.1
env:
- name: BACKEND_SERVICE_NAME
#value: 10.31.XXX.XXX
value: micro-sample-service-backend.default
ports:
...
Podの削除
せっかくなので、Podを消してみると不死鳥のように蘇る様子を見ることが出来る。
$ kubectl get pods NAME READY STATUS RESTARTS AGE micro-sample-backend-deployment-3300239719-ghw8q 1/1 Running 0 5m micro-sample-backend-deployment-3300239719-h8nwp 1/1 Running 0 5m micro-sample-frontend-deployment-602895698-qrwfk 1/1 Running 0 4m micro-sample-frontend-deployment-602895698-ts2kr 1/1 Running 0 4m $ kubectl delete pod micro-sample-backend-deployment-3300239719-ghw8q pod "micro-sample-backend-deployment-3300239719-ghw8q" deleted $ kubectl get pods NAME READY STATUS RESTARTS AGE micro-sample-backend-deployment-3300239719-h8nwp 1/1 Running 0 6m micro-sample-backend-deployment-3300239719-ppzf9 1/1 Running 0 9s micro-sample-frontend-deployment-602895698-qrwfk 1/1 Running 0 5m micro-sample-frontend-deployment-602895698-ts2kr 1/1 Running 0 5m
ありがたいなぁ。
電源が入ってないiPhoneやAndroid端末を見つける技術
本日、Android端末を落とした。多分タクシーに乗っているときだと思うけど、ちょうど領収書をもらってなくて、タクシー会社名も分からなければ車両番号も分からないという状態で困っていた。幸いにも世の中は便利になっていて、iPhoneやAndroid端末の位置を調べたりできるのだけど、僕の場合は気づいた時間の1時間前ぐらいから場所が拾えなくなっていた。つまり電波が入ってないか、電源が切られている状況で、普通に端末を探す方法は使えなかった。なので、ロックしてメッセージを出したり、着信音を強制的に鳴らしたり、リモートでデータを消したりとかそんなことはできない。そんな時にどうして見つけ出したかという話を書いておく。
TL;DR
- タクシーの領収書は必ずもらいましょう。
Google Mapのタイムラインを使いましょう。
探し出した流れ
Google端末を探すで表示される位置は結構ラグがあるみたいで、1時間前にある場所はよく分からないマンションの前を指し示していた。あーこれは後の乗客にパクられたかなと思っていたのだけど、タイムラインから表示してるような旨のメッセージが出ていたので、Google Mapのタイムラインから今日の移動経路を見てみると隣町の警察署で止まってる感じだった。え、位置情報違うじゃんって思いながらも、3時間ぐらい警察署の位置で止まってるような表記だったので、警察署に電話して落とし物係に繋いでもらい、この時間帯にこういう端末が届けられてないかという確認をしたら、それっぽいものがあるとのことだった。どうも照会するのにSIMの製品番号が必要だったので、携帯ショップに行って事情を説明すると、電話番号の入力で警察署にあることが分かり、拾得物番号、受理番号、SIMの製品番号などをメモしてもらって、警察署に電話を折り返して照会したら端末があるとのことだった。あとは受け取りに向かい、身分証明とメモを渡して、サインを書けばOKだった。イースタンモータース東京とかいうタクシー会社の運転手さんが届けてくれたとのことで、有り難しだった。まあなんでタイムラインで表示されている位置が変な場所なら、諦めて紛失届を警察に出して枕を濡らしながら待つとよい。
追記
あーなんか貼ってあったりするよね。取ってあるかなあ。参考になるー。てかあれかな警察署で保護された時点で電源切られるのかな?find my iphoneだけで探せないのは不便ね。(ロケーション履歴は使ってるけどー
— そすす/そうすけ (@snkm3) 2017年9月13日
なるほど38点のところもあるんですね。話変わりますが、Google Mapのタイムラインを使うのもいいですけど、タクシー乗ったら絶対領収書もらうべきですw
— とはえ (@tohae) 2017年9月13日
疑問
そういえば電源はどの時点で切られたのか?警察署?タクシーの運転手さん??警察署に行った段階で必ず電源切られるとなるとなかなか厳しいのかもしれない。
近況報告
僕の知り合いへ向けての報告です。7月中旬に海外から住所不定無職として日本に帰ってきました。7月中は実家に帰省していて、8月に関東へ戻ってきて日本の住所を得た結果、現在のステータスは無事に住所一定無職です。正確には7月末日付の退職でした。
元々自分の好きなことでもやりながらしばらくはフラフラするかーと思っていたんですが、8月はプライベートな問題で色々ゴタゴタしていたこともあり、あっという間に9月になった感じでした。自分が使う用の画像ビューアが欲しくて、絶賛車輪の再発明中ということで、暇があればコードを書いたりしてましたが、太陽フレアの影響もあり、そろそろ職探しでもするかーという気持ちになってきたので、職探しします。ずっと新規サービスばっかり開発してきたのですが、今後は開発者やデザイナーを後押しするようなツールやサービスを開発してご飯を食べていきたいなと何となく思っています。
恥ずかしながら転職するのは初めてなのだけど、職歴って前にLinkedInにまとめたやつがあって、こんなんでいいのかな?
https://www.linkedin.com/in/terunori-togo/
とりあえず無職になって思ったことは健康保険の任意継続の便利さは異常。
相談
ところで画像ビューアをElectronで作ってんですが、img.src切り替えるとメモリ積まれていってて、色んなリークを疑って最小構成にしても起こったんですが、Chrominumが抱えてるバグが直ってないだけなんですかね?そんなこんなでQtのgolangのbindingを見つけたんで、そちらで作り直してる感じですが、最新版の5.9.1でもImageのソースを切り替えるとメモリリークするバグにぶち当たり最高なので、Qtやりましょう。
例のヤツ
Arch LinuxのHeroku CLIパッケージのメンテナになるまでにやったこと
メンテナになったと言えば聞こえは非常にいいのだけど、つまるところArch Linux用のHeroku CLIパッケージがなかったので作って公開して使えるようになったということだったりする。まあサイトにはメンテナとして名前が載ってるし、メンテナなんだろうと思う。何らかのOS用のパッケージ配布自体は初めてで、作る上で色々と人々に教えを乞うたら、Arch Wikiには書いてなかった気がすることも教えてもらえたのでまとめておくことにした。
成果
何はともあれ、成果になります。
モチベーション
パッケージを作っていた時点のGo/NodeベースのHeroku CLIのドキュメントには、Apt以外で管理する場合、スタンドアロンバージョンを使うように書いてあり、自分でファイル管理をしないといけなかった。とにかくパッケージとしてシュッとインストールしたり、アンインストールしたかった。作っていた時点と言ってるのは今はドキュメントが変わっているからで、それについてはあとの方で触れようと思う。
パッケージの作り方
Arch LinuxではPKGBUILDというファイルを使ってパッケージのビルドの手順をシェルスクリプトで書いていく感じになるのだけど、まず最初はArch Wikiをよく読むとよい。パッケージに関してもArch Packaging Standardsとして基本的な作成方針がまとめられている。他にも基本的な作り方であれば、ググれば見つかるのでそういう類の情報は書かない。勢い良くブラウザバックして別のページを探すとよいと思う。
Arch packaging standards - ArchWiki
最初作ろうとしたもの
僕が作り始めた当初はGolang/Nodeで書かれたHeroku CLI v5がGithubのmasterで開発されていた。プラグイン機構がNodeで実現されてるからだと思う。Nodeベースのv6系もリリースはされてはいたが、v6ブランチ上で開発されていたのとGolangのコードがまだあったため、masterで開発されているGolang/NodeのHeroku CLIをパッケージ化しようと試みた。ただHeroku CLIはそれ自身に自動アップデートの機構をもっているため、バージョン指定でバイナリを取得できず、ステーブルという形でのダウンロードになってしまって、どのバージョンなのか分からない状態だった。VCSなどから直接コードを持ってきてビルドするタイプのパッケージは、gitコマンドなどからバージョンを取得してパッケージのバージョンを動的に決めていたので、それを真似してダウンロードしてきたバイナリの実行結果からバージョン情報を解析してバージョンをつける方式をとった。
最初のレビュー
基本的なことは既に述べたようにPackaging Standardsを読めば分かるわけだけど、不安がある人はBBSとかでレビューしてもらいましょうと書いてあったので、作ったPKGBUILDのレビューをお願いしてみた。そうするとWikiに書いてなかったようなアドバイスを色々ともらえた。
- ダウンロードしたものの検証にはsha512を使ったほうが良いこと
- 検証をSKIPする指定は、VCSなどからのソースビルドをするようなパッケージに使うこと
- pkgver()はVCSを使うパッケージ用なので使うのはやめたほうがよいこと
- バージョンを固定できないため、VCSで使うような方法をワークアラウンドとして採用してるみたいだけどセキュリティホールになるので、バージョンが固定されたアーカイブを探したほうが良いこと
- ライセンスファイルのコピーの正しい方法
- installコマンドを使ったほうが良いこと
- メッセージを出すためにはprintじゃなくてechoやcatとヒアドキュメントを使うこと
- ~/.local/shareなどのHOMEをいじるようなメッセージは出さないこと
- HOMEをいじるような場合はスクリプトを用意し、かつ"${XDG_DATA_HOME:-~/.local/share}“のようにXDG_DATA_HOMEを使うこと
- ソースとバイナリはライセンスが違う場合があること
それでバージョンを固定するには自分でビルドするしかないなと思ったのだけど、Golang/Nodeで書かれているため、普通のgo buildとかではなく、Makefileと格闘するハメになった。
Herokuへの問い合わせ
Makefileでやるのはビルドできなすぎて辛すぎたので、Heroku Supportで問い合わせしてバージョン固定でバイナリをダウンロードできないのか聞いてみた。そうするとNodeバージョンを使うと良いよというアドバイスと共に、Heroku CLIのドキュメントを見てと言われたので眺めてたら、全体的にアップデートされ、ArchやBSDは自動アップデートなしのNodeバージョンを使ってくれという感じになっていた。GithubのmasterもNodeベースに切り替わっていてGolangの実装は全てなくなっていた。CLIのコア部分はcli-engineというFrameworkに依存してたので、Golangの実装はv6で使ってなかったのかも知れないし、以前から切り替える計画があったのかもしれないけど、問い合わせてから2-3日でやるのはさすがに強い。これが世界のやっていきですかという気持ちになった。結果としてNodeのライブラリとしてバージョンを指定してインストールするパッケージを書けば良くなった。
2回目のレビュー
1回目のレビューの時と違い、Nodeのライブラリをパッケージとして提供してるものは既にあったので、探してマネをした。ただAURで公開されてるライブラリは正しいやり方をしてないものも多いし、PKGBUILDのオートジェネレータがおかしなビルド方法を提供していたりるので、気をつけたほうが良さそうだった。既にコミュニティパッケージになっているものを参照してリリースにこぎつけた。正直Nodeとnpmがあれば普通にインストールできるのだけど、Node使う環境にいない人にとっては、依存を解決して全部入れてくれるし多少は便利かなと思ってリリースすることにした。レビューのスレッドを一応貼っておく。
[SOLVED] PKGBUILD review request: heroku / Creating & Modifying Packages / Arch Linux Forums
最終的なPKGBULDの様子。
今の悩み
めちゃめちゃHeroku CLIのリリーススピードが早くて、一日に2回リリースされたりとかザラだったりする。そんな感じなので最新バージョンに違いが出やすくて、マイナーバージョンの違いでもOut-of-dateフラグ、つまり古いぞフラグをパッケージにつけるマンがいる気配を感じている。僕はどうしたらいいんだろうか。
まとめ
とにかくHeroku強い。世界のやっていきを見た。
英語をやっていくためのDuo3.0デスクトップアプリを作った話
以前、英語をやっていくためのDuo3.0アプリを作り直した話 - 解せぬ日記で書いたとおりReactNativeで作ったモバイルアプリを使ってDuo3.0をやってきたわけだけど、それをやっていると今度はデスクトップアプリが欲しくなってきた。やっぱりタイピングはそっちのほうが早く時間も節約できる。僕は普段、ArchLinuxを使ってて、仕事ではMacOSXを使っているので、気がついたらElectronを使って作ってた。Duo3.0アプリ芸人みたいな様相を呈してきたけど、僕はボキャビルがしたいだけなんだ。
成果
以下、成果になります。
ソースコードも置いとく。小さいのでElectronやってみたい人が雰囲気を眺めるには良いかも知れない。
TL;DR
Electronに関してはサンプル程度だが前に書いたこともあり、中身はJavascriptとHTMLで書くということで、React入れて、ロジックとJSX書いて、トランスパイルして、JS読み込むという感じなのでシュッとアプリを書くには非常によい。
実装に関して
難易度
今回はデスクトップアプリとはいえ、メニューバーに常駐したりするわけでもなく、アプリ自体のメニューとかも別にどうでも良かったので、Electronで実装されてるAPIにはあまり触れてない。MenuItemとかTrayとかそういう類のやつ。たぶんこの辺を触り始めると、これぞElectronという特有の知識が必要になって、難易度も上がるんだろうと思う。そこを触らないのであれば、APIを眺めることもあまりないと思う。
アプリサイズ
これはよく言われてることで、そのままビルドすると異常なサイズになる。普通にやってしまうとnode_modulesとかも一緒にいれてしまうのが原因で、いちいちnode_modulesやら必要ないものは外す必要がある。最初、何も考えずにビルドしたら400MBぐらいあってウケた。色々含めないようにして100MBぐらいになった。音声ファイルが40-50MBぐらいあるので、まあそんなもんかなという感じ。
音声の再生
これはもうHTML5使えるからめちゃめちゃ楽でaudioタグを使って終わり、何も難しいことはない。FlutterやReactNativeでは大変だったので有り難し。
Diff
モバイルアプリを使ってて見にくいなーと思ったのが、一瞬でどこ間違ったか分からないことだった。間違った箇所を確認するのに時間を取られてしまい、効率的ではない。ということで、diffを導入して、差分で間違ったところだけを赤くするようにした。diffライブラリを使っていて、addedのステータスの単語を赤く表示している。ただこれ回答側に余分な単語、例えば冠詞がないのに冠詞をつけていた場合は、何も表示されないのでなんとかしたいが、いいUIが思いつかない。とりあえずaddedだけでも必要十分な気がしたので、これでやっていってる。
まとめ
全体としてシュッと出来たなという感じ。フロントエンドマンならもっと早くできるんだろう。2ヶ月前ぐらいに作って、これ使ってやりまくってたら、45セクションを2日で終わらすみたいなこともできるようになってきて、めでたい。何気にセンテンスのjsonを別の例文に変えても使えるので、新しく覚えたい例文とか足していってもいいかもしれないですね。
やっていき。
英語をやっていくためのDuo3.0アプリを作り直した話
先日、Flutterで英語をやってくためのDuo3.0アプリを作ってみた話 - 解せぬ日記というのを書いたわけだけど、そのアプリに音読用の機能が欲しいなということで追加を検討した結果、Flutterで作ったものをReact Nativeで作り直した。
成果
以下、成果になります。
ソースコードも置いとく。スタイルやらちょっと整理したい。
TL;DR
React NativeはJavascriptとReactという慣れた言語で書けることや割とライブラリとかもあって良い反面、iOSとAndroidでAPIを分けたりしてる部分があったりして、そこがすごく気になった。コードを無理に共通化しようとすると分岐が出てきて、なんとなくそのうちやっぱSwiftやJavaで作り直したほうがいいねとなるかもしれない。Dartという言語で新しいFrameworkを学ぶ必要があり、対応してるAPIはまだ少ないものの僕個人としてはFlutterが実現しようとしてることのほうが好きだし、コードも楽しく書けた気がする。シンプルなものはFlutterでiOSとAndroidを動かし、それなりの表現がしたいものはSwiftやJavaで個別に作るみたいな流れが好ましい。FlutterはGoogleが作ってる新しいOSのFuchsiaのUIレイヤーに採用されるみたいで、コミットも活発だし期待したい。
作り直した背景
音読機能を追加するにあたり、音声を流すための調査をした。その結果、Flutterには現在のところ音声ファイルを扱えるAPIが存在しないということが分かった。正確にはメンテする人がいないということでオープンなリポジトリからはAPIを削除したとのこと。Privateリポジトリに移したから使いたい人やメンテしたい人はgoogleグループに連絡くれとのことだったのだけど、前に公開されてたコード読んだ感じ、結構難しかったのでReact Nativeで作り直すことにした。
React Nativeを選んだ背景には、音声ファイルを扱えるライブラリがあったこと、AndroidとiOSのアプリをビルドできたこと、そしてReactとJavascriptをもう少し触っとこうと思ったことがある。個別に作りたいアプリじゃないし、iPhoneを使ってる妻も使えるようにということで、FlutterだったりReact Nativieを選んでる。
実装で詰まった部分
ReactとJavascriptで書けるので、まあなんとか書けたものの設定やらなんやらで割とハマった。thisを束縛したりとかはReactでお馴染みだったので、React書ける人ならビルド周辺以外はハマることは少ないような気はする。ライブラリも結構色々あって探せばなんかありそう。
Buildの設定
React NativeのCLIから作られるアプリの中にはAndroidとiOSのディレクトリがあり、それぞれBuildに使うための設定ファイル群が生成される。僕はAndroidをサンプル程度のものしか作ったことがなくて、あまり知識がないのだけど、React Nativeは結構Androidのビルドの仕組みなどの知識を要求してくる感じだった。iOSはまだBuildしてないが、Info.plistなどが生成されてるし、まあ多分同じなんだろうと予想している。
build.gradleにはAndroidのSDKやBuildツールのバージョンが書かれていて、Android Studioをインストールした時に入るSDKのバージョンによってはSDKやBuildツールの対象バージョンをインストールするか、設定ファイル自体を対応するバージョンに書き直す必要がある。React NativeのCLIファイルが作るファイルは全てSDKが23でBuildツールが23.0.1だったので、もしかしたら書き直すことの方が多いかもしれない。多分基本的なことなので、トラブルシューティングにも書いてない。
けどよくよく考えれば、公開するために署名やProfileなどの話は避けて通れないし、どちらにしろBuildに関しては抑えておく必要はありそう。
音声ファイルの置き場所
これも考えれば当たり前なのだけど、AndroidをBuildするときに全部がbundleされるわけじゃなさそうで、音声ファイルが参照できなかった。そこでres/rawに入れたのだけど、ここってディレクトリ管理できないっぽくて、そのまま直下に置いた。assetsとして管理すればディレクトリ管理もできそうなので、Androidマン頼む教えてくれ。自分でドキュメント読めという話かもしれない。
APIの分岐
これはハマったというより悩んだという感じだったのだけど、iOS用のコンポーネントが用意されてたり、Android用のAPIが存在してたりして、一つのソースでやろうと思うとまあそうだよねって思うものの、非常に考えさせられた。当然、個別に用意されてるものを使ったほうが実装が楽だったりで便利そうな感じはすごくしたのだけど、そうすると再利用できる部分はどんどん減っていく。それで行き着く先は、個別に作ったほうがいいんじゃね?ってなりそうだなと思ったんだけど、そんなことないよって実際作ってる人がいれば話を聞いてみたい。
まとめ
無事に音読用の機能を追加できた。とりあえずこれでオフラインでも英語の勉強には困らなそう。人の目を盗んでは一人でブツブツ言うということもできそうだ。どっかの綾瀬はるか似がDuo 3.0やってるって言ってたし、Javascript界隈に詳しいっぽいので、色々ReactとかJavascriptの書き方教えてくれると嬉しい。多分Flutterが音声ファイルを流すためのAPIに再度対応したらFlutterの方に機能追加して、そっちをメインにすると思う。FlutterはGoogleが作ってる新しいOSのFuchsiaのUIレイヤーに採用されるみたいで、コミットも活発だし多分追加してくるだろうと予想してる。
やっていき。
Flutterで英語をやってくためのDuo3.0アプリを作ってみた話
前回、FlutterとDartをしばらくやってみると言ってたこともあって、土日にアリアンデルに籠りながら、Flutterをやっていた。アリアンデルというのはダークソウル3のDLCのことですので、アリアンデルの絵画世界に興味がある人は一緒にやりましょう。
TourとかDart bootstrapとかを眺めたり、実際に動かしながら見ていたわけだけど、途中から眠くなって、アプリでも作りながら困ったらドキュメントに戻ればいいかーといつもの雑さでアプリを作り始めた。 最近、Duo3.0をやってるので、オフラインでもディクテーションとか暗記(覚えれば音読をいつでもできる)とかできるといいよねって思って、Duo3.0アプリにした。
成果
以下、成果になります。
アリアンデルに篭りながらFlutterをやった結果です。ご査収ください。 pic.twitter.com/D9uf96krc2
— レベルがあまりに低い (@terut) November 15, 2016
ソースコードも置いとく。
TL;DR
FlutterのUIはシンプルなものなら割と作りやすいと思う。HTMLっぽさがあってとっつきやすかった。ただその分、オブジェクトを生成しまくってて大丈夫なんかなとも思った。完全にFlutterという言語を書いてる気分で、AndroidやiOSのこと知らなくてもそれなりのものは書けそう。
StatelessとStatefulなWidgetがあって、Reactiveな仕組みが導入されてるのはやっぱり良い。Stateを変えるとWidgetを生成し直しているようで、差分更新って書いてあった気がする。Reactにインスパイア受けてるってことで、ReactNativeに似ているような気がした。
困ってもExamplesが結構充実してるのでなんとかなることもあるんだけど、ドキュメント、Examples、テストコードで見当たらないとググったところでほとんど情報が出てこないのが最高。ただ最終的には実装の詳細が見れるので、まあ良いかなとも思う。
実装で詰まった部分
基本的にはStatelessかStatefulなWidgetどちらかを選んで実装していく。setStateのコールバック内でデータを設定すると、再レンダリングが走る感じ。ReactNativeとかもそんな感じだったような? よく分からないことだらけで、細かくあげるとキリがないので、幾つか載せておく。
画面遷移
まず画面遷移からしてよく分からんかった。最初にRoutingの設定をするんだけど、実際の呼び出しでは引数を渡せなさそうな感じで、これオブジェクト渡したい場合どうするんだろうってなった。多分現時点では渡せなくて、GithubのIssueに次のマイルストーンのタグがついてたからそういうことなんだろう。 人によってはRoutingを"/section/$section_id"とかして、Hookを使って自分でパースしたりしてたけど、マジで言ってる?ってなって他の方法を探した結果、名前で遷移するだけじゃなく、Routeオブジェクトを生成して遷移できそうだったので、そっちでWidgetオブジェクトを初期化して遷移することにした。 マジで言ってる?とか思った割に僕もWayfaringとかで同じことしてるんで、何も言えないことに後で気づいた。
実際のコードは以下のような感じ。
// 1. 設定するパターン。これだと引数が渡せない。 void main() { final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ '/': (BuildContext context) => new SectionList(), '/sentences': (BuildContext context) => new SentenceList(), }; runApp(new MaterialApp( title: 'Duo 3.0', initialRoute: "/", routes: routes )); } // 適当なハンドラで遷移 。pushNamedはFutureオブジェクトを返すんだけど、評価後のオブジェクトにWidgetオブジェクトが返ってくるわけじゃないので、詰み。 void _handleSectionSelected(Section section) { Navigator.pushNamed(context, "/sentences"); }
// 2. Routeオブジェクトを使うパターン。引数が渡せる。 void main() { runApp(new MaterialApp( title: 'Duo 3.0', home: new SectionList(), )); } // 適当なハンドラで遷移 void _handleSectionSelected(Section section) { final route = new MaterialPageRoute<Null>( builder: (BuildContext context) => new SentenceList(section: section), ); Navigator.push(context, route); }
InputのonSubmittedが発火不可
InputオブジェクトにはonChangedとonSubmittedってコールバックがあって、打ち込まれたセンテンスの判定に使うかーと思ってたら、キーボードのReturnをDoneに変える方法が分からなくて詰んだ。onSubmittedはDoneを押した時に発火するっぽい。エミュレートできそうなperformActionってメソッドがあったけど、なんかうまくいかなかった。 あとInputはPlaceholderを入れられるんだけど、Inputだけで使うとPlaceholderの文字が残り続ける。なんで、普通にFormオブジェクトとInputFormFieldを使うのが良さそうだった。InputFormFieldはvalidatorを設定できるのだけど、初期表示時と入力するたびにチェックが走ってウケる。この辺はExamplesかテストコードを眺めると使い方が分かる。
日本語が表示不可
日本語表示しようとしたら表示できなかった。これはフォントを変えりゃイケそうってことで、TextStyleで色とかフォントファミリーとか選べるので、それで設定すれば良い。何となくHTMLぽさが少しある気もする。
final text = new Center(new Text( "sample", style: new TextStyle(fontFamily: "Hiragino Kaku Gothic ProN"), ), );
まとめ
ドキュメントもExamplesも充実してるし、テストコードを見ればハマりながらもなんとか実装できる。どれにもない場合は、コード読んで自分で考えるしかない。ググってもマジでほとんど何も出ない。 Rectiveな仕組みをデフォルトでサポートしてるのは非常に良い。Androidは確か既にサポートしてた気がするので、iOSも是非お願いしたい。Reactっぽさがすごいあるので、その辺に慣れてる人は入りやすいと思う。 完全にFlutterという言語を書いてる気分で、AndroidやiOSのこと知らなくてもそれなりのものは書けそう。 使ってるうちに音出したいなーと思ったんだけど、"Remove sound.dart"というコミットを発見してウッてなってるのが今。
Flutterに興味が出た人はこちらも参考にするといいかもしれない。
話は変わるが、この間"やっていき宣言"なるものが行われ、いいなーと思ったので、おっさんだけどやっていくことにした。
異常に怠惰なので気を抜くと気持ちだけ、一発にもならない何かみたいなので終了してしまうのが正直なところではあるが、気負わずやっていき。