基礎からやさしく学べるブログだよ☆2015年9月14日月曜日APKをパソコンにコピーするときはpecoを使うと捗るAPKファイルを取り出せ!!そもそもどうやって取り出したらいいのか気になっている人はここを読んでも仕方がない。Googleを呪ってくれ。Android端末にあるAPKファイルをPCにもってきたいことはたまにある。)このコマンドを実行すると、端末にインストールされているAPKがずらーっと表示されて、そのなかから対象のapkを文字列で絞り込んで、pullすることができます。構想から開発、クロスプラットフォーム化まで詳細に書いてあっておもしろい。勝手な解釈の多い意訳。Ruben最近はみんな写真撮ってスマホの中にいれてるよな。友達の撮った自分の写真を全部もらったことある?ないでしょ、めんどくさいもん。みんなのそれぞれのスマホで順に記念撮影したりするでしょ?写ってるのは同じ人なのにね(笑)そもそも友達から自分の写っている写真をもらったとしてもさ、イベント毎に写真を整理するのもめんどうだよね〜。そこでMomentsをつくろうって思ったの。友達同士で写真交換しやすくするアプリをつくるぞ!ってな。交換方法どうしようどうやって写真をやりとりするのがいいか考えたんだけど、これだというものがなかったから、Bluetoothとか位置情報とか顔認識とか色々試したよ。近くにいる人とはBluetoothか位置情報を使って交換できるんだけどさ、問題があるよね。Bluetoothは交換する端末同士でONにしないといけないし、AndroidとiPhoneの間だとあんまりうまく動かない。位置情報は混雑した場所だとうまくいかないでしょ。試作バージョンで、顔認識を使ったサジェスト機能を作ってみたんだ。「撮った写真のなかに友達が写っていたら、友達はその写真が欲しいはずだし、そのイベントの他の写真も欲しいはず〜。」といった感じで交換をサジェストするの。Facebookには顔認識の技術あるし、まじツイてたね。最近Facebookの人工知能研究チームががんばっているんだよ。MomentsではFacebookのタグサジェストで使っている最新の顔認識技術を使っているよ。これは世界でもまじすごいやつな。Facebookのタグはちゃんと設定からOFFにできる。プライバシー保護の観点でね。Momentsも自分で選択しない限りは勝手に写真がアップロードされないようにしたよ。友達とシェアしたい写真だけがアップロードされればいいからさ。顔認識っていう正解の「方法」をみつけたけど、まだまだ正解の「UI」はわからなかったんだよな。UIの改善を高速に繰り返す必要があったわけ。そこで開発のフローを短縮し、毎週実際のユーザと一緒に検証してみた。詳細は以下のページで。https://medium.com/@laurajavier/2b5362430125んで、そのために開発プロセスの最適化を行ったんだ。ビジネスロジックはサーバとクライアント側に分かれてるでしょ?でもそうすると製品を変更するとき、両方を変える必要があるよね。サーバとクライアントの両方ともが同時に高速に変更されるとマジ大変なわけ。片方だけが高速に変更されるほうがずっとマシだよね?そこでサーバのロジック部分を全部クライアントにもってきちゃう。いうサイクルが最速で回せるでしょ?すごいよね。俺たちはアプリは「サクサク」でなきゃ許せないんだよね。「送信中でーす」のぐるぐるをできるだけ無くしたい。え?どうやるかって?ユーザの更新がサーバに保存される前に、もうユーザに表示しちゃえばいいのさ!「たぶんちゃんと送れるだろう」と考えているという意味で、これを「楽観的UI」と呼んでるぜ。プロダクト作り始めたあとから、楽観的UIにしようと思っても工数かかるしバグだらけになるのがオチだ。俺らははじめからこの設計思想に基づいたってわけ。楽観的UIにするのなかで、ある大きな決定がされたんだ。クライアントでデータモデルを定義サーバーでは型を持たないデータとして保存クライアントでは型を持ったオブジェクトとして保存(まだサーバに保存されていないような楽観的UIのためのオブジェクト=「楽観的オブジェクト」も含む)この決定がどんな効果をもたらすのか感じてもらうために、例を挙げよっか。あるユーザ「アリス」が撮った1枚のバナナの写真。これを別のユーザ「ゴリラ」に見てもらえるように、同期を開始したとしよう。このときアリス側では2つのモデルオブジェクトがつくられる。「写真」と「通知」だ。「通知」はこんな感じになるかな。},アリスは新しく同期した写真を自分のフィード画面でみることができるし、その写真が表示されるべき場所にはどこにでも(これから開く画面も含めて)ちゃんと表示される。みたいにしているおかげね。訳者注)Fluxの要約(日本語)http://www.infoq.com/jp/news/2014/05/facebook-mvc-flux「通知」と「写真」のオブジェクトは型付けされて、楽観的オブジェクトとしてキャッシュに保持される。他の「ユーザー」オブジェクトとか「Moment」オブジェクトに紐付けられて、いい感じのViewModelに変形されて実際の表示に用いられる。訳者注)ViewModelはAndroidでいうところのListAdapterのItemのようなものかもちろん楽観的オブジェクトとサーバにあるオブジェクトで、そこから生成されるViewModelは同じになるよ。クライアントは楽観的オブジェクトをキャッシュに入れて表示。クライアントは楽観的オブジェクトを「型」と「内容」という汎用的なBLOBに変換し(変換はモデル定義から自動生成されたコードによって行われる)、サーバーに送信。サーバーはBLOBを保存し、実際に保存されたBLOBを返す。クライアントはそのBLOBを型のあるオブジェクト(=実際にサーバに保存されたオブジェクト)に変換する。クライアントはキャッシュ内の楽観的オブジェクトを実際に保存されたオブジェクトで上書きする。これによってサーバー/クライアント間でデータモデルの型を安全に持ち回しつつ、高速に開発と検証を繰り返すことができる。今度はゴリラがアプリを開く。クライアントは新しいオブジェクトの取得を開始する。毎日、様々な人によって、たくさんの新しいオブジェクトがつくられる。ゴリラはこれらのうち、ごく小さな部分にしか興味はない(おそらくジャングルのことやバナナのことだろう)。この興味の部分を「キュー」をフォローするという形で表現する。あるキューのメンバーであるユーザはそのキューに属するオブジェクトはすべて見ることができる。オブジェクトは生成されるときに1つのキューに属し、所属先のキューを変更することはできない。Momentsアプリの中のそれぞれのMomentは各1つのキューと対応している。Momentに参加しているユーザはキューのフォロワーである。このMomentに同期される写真全てはこのキューに置かれる。クライアントはGraphQLクエリで書かれた差分同期方式を使い、最後のクエリ発行以降に生成もしくは更新されたオブジェクトのみをダウンロードする。この場合、ゴリラは新しい「通知」とアリスによって作られたバナナの「写真」オブジェクトのみをダウンロードすることになる。このシステムではクライアントにUI上のもたつきをみせることなく、必要十分なデータのみを裏側でダウンロードさせることができる。これで「サーバを変えたらクライアントも変える」というアプリあるあるな話を無くすことができた。開発フローが短縮化され、毎週ユーザテストができるようになった。あとついでに、通信できないような状況でもアプリがちゃんと動くようになった。クロスプラットフォーム当初から、iOSとAndroidを一緒にリリースすることを目標としていた。いえiOSから開発を始めたので、あとからAndroidをがんばった感じね。開発速度を上げるために、両プラットフォームに共通している部分は共有コードとして書きたい!普通はサーバ側で共通コードを書くんだけど、クライアント側でそれをやりたいんだ。それにはいろんな方法があるんだけど。俺たちは高速に試行できて、パフォーマンスもよくって、Nativeアプリとして使い心地がいいやつがよかった。試したところ、UIはプラットフォームのコードで書いて、ビジネスロジックは共有して使えるようにC++で書くことにした。イニシエよりC++は高パフォーマンスだがメモリ管理がめんどくさくて高度な抽象化ができない言語として知られている。モデルのような一方向のデータの流れを取り入れた。genAllPhotosSyncedFromUserからなる。いうのは実行命令を出して結果を待たずに値を返すようなことを指す。コードの可読性を維持するため、生データをimmutableなViewModelに変換するまでの処理は関数型っぽく書いてある。処理速度のボトルネックを分析し、変更されていない中間結果を再計算するのを避けるようにキャッシュをつくった。それによって、パフォーマンスも犠牲にすることなく、保守性の高い関数型コードを用いることができた。UserFilter('my_uid')).toViewModels();みたいに書いてるってことかな?「中間結果をキャッシュする」というのは生データをViewModelに変換する間のどこかの状態でどこかにメモリキャッシュしてあるということでしょうかね。C++の共有ライブラリを使うと、C++とプラットフォームの言語とをつなぐコードを生成する必要がある。オープンソースで、開発はDropbox。こいつでC++で書いたViewModelをJavaに変換する。俺たちはこのコードジェネレータをちょっといじった。生成されるJavaのモデルがImmutableでParcelableになるようにした。Referenceをキャッシュしておいて、変更された時のみ生成するようにした。iOSのViewModelではObjective-CのいいとこでC++を薄いラッパーを書くだけで使えちゃった。これらのデザインによって俺たちはC++とJavaをつなぐ定型文的なコードの部分を意識することなく、ビジネスロジックやUIそれ自体に集中することができた。今までのところ、iOSとAndroidの共有しているビジネスロジックのコードの割合は日々増えてきてる。それぞれのプラットフォームでざっと1/3の行数がC++の共有コードだった。この結果として俺たちは新しい機能を追加するときも、少ない工数&少ないバグでできちゃうし、Nativeアプリとしての使い心地の良さと高パフォーマンスも維持できている。2つのプラットフォームに割く時間を柔軟に変更することが出来たため、両OS同時にリリースすることが出来たんだ!ひゃ〜、今日アメリカでMomentsがiOSとAndroid同時リリースできてホントわくわくしてるよぉ。みんなこのアプリが役に立つとわかってくれるといいな〜フィードバックくれよな〜。これからも高速に開発して、どんどんよくしてくぜ。あとFacebookの今後の人工知能研究にもわくわくしてる......きっと斬新ですごいことができるようになる......よ。僕らの人工知能研究がどんな感じかは、以下のビデオをみてね。共有2015年6月11日木曜日ぼくのインデントインデントは無ではないみんなで1つのファイルを編集していると、インデントで殴り合いになることがある。TAB派とSPACE派だ。多くのエディタではデフォルトでTABもSPACEも表示しない。そのためこのような悲しい戦いが繰り返される。私はこの憎しみの連鎖に終止符を打ちたい。起床時に3回唱えよう。実機で開いている画面からActivityのクラスを特定する裏ワザ裏ワザではないソースが見れるでっかいアプリを試しに動かしている時に、この画面はどのActivityクラスなんじゃ?と思うことがある。入れ歯型の歯ブラシがあったらガシガシ噛むだけで歯が磨けるんじゃね?とちょうど同じくらいの頻度で思う。裏ワザ紹介!!!!1そんなときはUSBでAndroid端末とPCをつなぎ、以下のコマンドを実行する。Activityのスタックが表示される。grepが使えないWindowsなキミはおとなしくfindstrでもつかってな。共有レイアウトはどこからやってくるかレイアウトの旅レイアウトをどこで設定して、どこで読み取って、どこでインスタンス化しているのかの話。Inflateインフレ・デフレという言葉が示すように、Inflateとはなにかをでっかくすることだ。AndroidでInflateといえば、レイアウトデータをレイアウトインスタンスにふくらませることだ。レイアウトデータレイアウトデータはxmlだ。/></<LinearLayout>こんなかんじ。それをGorillaProject/res/layout/my_cool_layout.xmlのような場所にいい感じの名前で格納する。LinearLayoutのインスタンスが格納される。LinearLayoutのインスタンスだ。inflateでは、xmlファイルという指示書に従って、Viewのインスタンスをnewしていくというわけだ。InflateなんてないじゃんあるActivityでは、こんなふうに書かれている。setContentView(R.layout.my_cool_layout);}こういうときはsetContentViewのなかでInflate処理しているんだよ。Inflateを内部的に呼び出している関数はたくさんあるよ。アプリをつくろうぜってなっても、なにから考えればいいかわからんね。AndroidのBluetoothの扱いに興味を持つ人がいてもいいんだろうけどそういう人はこことか読まない。目に見えるものを考えるよね。Activityいわゆる画面。1つの画面が1つのActivityだ。こいつのなかにモノをつっこむことで、アプリはできあがるのだ。Fragment昔はなかったんだけど、いまは必須なやつ。Activityの中を小分けにするやつ。弁当箱で言うと「ばらん」で分けられた区域のこと。注意しないといけないのは、こいつは非表示にしたり切り替えたりできるってこと。おかず区域の「からあげ」をタップすると、ご飯区域の「白米」が「チャーハン」になる感じな。Activityのなかに直に置くこともできるし、Fragmentの中に置くこともできる。「からあげ」や「白米」や「チャーハン」のこと。Viewは入れ子にできるものがある。これは「からあげおにぎり:だ。白米の中にからあげを入れることができる。からあげのなかに白米をいれることはできないように、入れ子に出来ないViewもある。実体があるのがViewだ。それらの入れ物がActivityとFragmentだ。FragmentはActivityの中に置くことができる。レイアウトヒエラルキーだね。