chigichan24のお気持ち表明

おきもちを表明している

AndroidのToolbarをいい感じに触る

ググったときに???みたいな記事が多い気がしたのと,タイピング練習のつもりで記事を書きます.講義が習ったことをちんたら喋ってて暇だった

あるアプリケーションをリファクタしていたら,ToolbarにActivityで直接setTitleするコードがありました.動的になんか差し替えるならまだしも,基本的に静的なテキストはxmlで記述する方針で書いていたのでリファクタします.ついでに,onClickまわりもいい感じにします.

f:id:chigichan24:20180126130510p:plain

こういうやつです.

コード上からsetTitleを消しさる

google先生で適当にぐぐるthemeをいじって...とか書いてありますが,そんなことしなくていいです. 確かにxmlファイル上で参照android:textでは設定できないけど...

xmlns:app="http://schemas.android.com/apk/res-auto"を記述してapp:で参照すれば良いです.つまり,

コード上で下のように書いていたものを

toolbar.setTitle("HogeFuga");

xmlで下のように書けば良い

<android.support.v7.widget.Toolbar
            app:title="HogeFuga"

これでsetTitleをなくすことができました.これと同じ要領でアイコンも指定できます.

コード上からsetNavigationOnClickListenerを消し去る

ただのonClickであれば,android:onClickでdatabindingするといい感じにうぇい(語彙力)して終わりですが,Navigationのクリックを取るのはちょっと工夫が入ります.

同じ要領でapp:navigationOnClickListener みたいなのはなく,android:onClick取ってきたらToolbar全体にクリックリイベントを挿す羽目になるので,どうにかします.

BindingAdapter

BindingAdapterでクリックイベントをbindingします.これがjavaであれば,

@BindingAdapter("navigationOnClick")
public static void setNavigationOnClick(Toolbar toolbar, View.OnClickListener clickListener){
    toolbar.setNavigationOnClickListener(clickListener);
}

とすれば良いです.これをkotlinに素直にすると,

object CustomBinder {
    @JvmStatic
    @BindingAdapter("navigationOnClick")
    fun onNavigationClick(toolbar: Toolbar, clickListener: View.OnClickListener) = toolbar.setNavigationOnClickListener(clickListener)
}

となりますが,これは非常にダサい上に@JvmStatic警察に捕まります(?)

なので,Toolbarの拡張関数として書いて,いい感じにすると,

@BindingAdapter("navigationOnClick")
fun Toolbar.onNavigationClick(clickListener: View.OnClickListener) = setNavigationOnClickListener(clickListener)

となっていい感じにかわいい感じ(?)になって,xmlでは

app:navigationOnClick="@{viewModel::onBackButtonClicked}"

こんな感じに指定して,コードでonBackButtonClickedの中身を書けばスッキリします.

これで,コードがスッキリした感じになりながら目的を達成できました.おわり.

失敗から学ぶAndroid設計

この記事は呉高専エンジニア勉強会 Advent Calendar 2017 の 19日目の記事として書かれています.

qiita.com

こんにちは.

高専エンジニア勉強会OB chigichan24です.

最近はもっぱらAndroidのことを考えながら寝床につき,夢の中でバグと格闘して朝を向かえるという生活をおくっているのですが,そんな中思ったことを幾つか紹介したいなぁと思います.

とりあえずモットーは,「人を恨まずコードを恨め」(インターン先で聞いた)なので,書いた人をどうこう言うんじゃなくてエンジニアならコードで語れや👊みたいな部分に心を打たれ,それ以降この言葉を大切に生きてます.

ところでお前は誰だ.

そうですよね.OB(詐称)なのでまじでお前誰だよ状態ですよね.

ぷろぐらみんぐをはじめてまだ一ヶ月なので右も左もわかりません😉

端的に説明すると euglena1215という人がいるのは皆さんご存知だと思いますが,彼の同級生とだけ覚えておいてください.

私は彼にこのアドベントカレンダーを埋めないとお前覚えとけよ(意訳)(要約)(自己解釈) と言われたので怯えながら書いてます.

今日の話

今日は私が開発に関わったアプリSyncPodについて,ちょっとお話しようと思います.

play.google.com

そもそも

私がこの開発に携わり始めたとき,既に幾つかの機能が実装されていた状態でした.

これをいい感じにリファクタしながら,機能追加する感じで頑張ろうと思ってました.

今までの設計

このアプリ,特に設計もせずにどんどん機能追加していきました.ましてや,MVVMのような高尚なアーキテクチャの上でも動いていなかったので,結構大変な感じになってました.

このアプリの現状をまとめると,こんな感じになってます.

f:id:chigichan24:20171219160244p:plain:w500

もう,嫌な予感しかしないですね...

さて,実際に起きた問題と共に振り返って見ましょう.

問題1 複数のAPIを捌く問題

問題

このアプリではYouTubeのアプリっぽいことをするので,YouTubeAPIを使っています. YouTubeAPIは動画情報であったり,検索であったり,と複数の用途でAPIが別れているらしいです.

つまり,複数のAPIを併用して使う必要があるわけです.*1 今回のアプリでは2つのAPIを使っていました.

で,今回のSyncPodではそのうちの1つのAPIをラップしてアプリに特化したAPIサーバを立てています.

ところがところが...

2つのAPIの戻り値がほとんど一緒なんです!!!???

一緒なのに別のAPIであることを意識しながら,しかも呼び出し方が2つで異なっていてもう次に追加する時はどうするんじゃい状態です.

f:id:chigichan24:20171219210521p:plain:w500

一方は1,もう一方は2から呼び出しています.

そもそもこれが起きる原因として,

  • smartUIになっている.
  • どのAPIからデータが決まるかを意識してViewがアップデートされている.

の二点が考えられると思います.

解決策

  • smartUIを解決する. smartUIとは,日本語に直訳すると"賢いユーザインタフェース".これは皮肉として使われています.

UIはただ表示するだけ,それだけを責務として持つのがいいと思います.UI(View)の仕事は

  • これ表示して!!とかあれ表示して!!!て言われるのを言われるがまま表示すること.
  • ユーザのタップ情報とか,スクロールの情報を受け渡すこと.

の二点だと思います.それゆえ,Viewつまりは,Activity,Fragmentは完結に表現できるはずです.smartにはならないはずなんです.

つまり,smartUIを解決すると,ViewからAPIを呼ぶことなんてまずありえなくなります

  • どのAPIからデータが決まるかを意識しない.

UseCaseにおいて,このAPIからデータが来るからここを...とやっていると規模が小さい時はなんとかなりますが,規模がでかくなると収集がつかなくなります. 特に,APIだけでなく,データというのは様々な場所に格納されています(ex. 端末内のデータベース.メモリ.API).それらがどこに所属するか?というのはUseCaseで考えることなのでしょうか?

私はNoだと思います.APIに限らずデータがどこに保存されているかなんて,考える必要はないと思います.それを体現するのがRepositoryパターンです

概念図としてはこんな感じです.

f:id:chigichan24:20171219212054p:plain:w500

UseCaseはRepositoryから上方向に流れてくる情報だけを考えれば良いです. 欲しい情報をRepositoryに渡せば,どこに保存されているのかを考えることなく情報を使えるようになります.

実際には,その下でLocalStoreなのか,RemoteStoreなのかまた,それらが若干の依存を持ちながら取得されるのか(例えばTokenが発行されているか否かで処理が変わるのようなもの)というのをUseCaseから見るとよしなに処理して結果を戻します.

このようにすれば,APIが複数あるからどうこうとか,冗長だからどうこうのような問題は全て解決されます.

ここで,注意すべきはUseCaseで処理するべきなのか,それともRepositoryの下で処理すべきなのかを適切に見極めることです. これは非常に難しい問題です(私自身も考えるのが苦手)が,ここをうまく分けることができると良いです.よくある議論としては,validationはどこでやるべき処理なのかというのが挙げられます.

問題2 コピーアンドペーストが引き金で...

問題

コピーアンドペーストは世界の様々な開発者のノウハウを一秒で実現できる方法ですが,適切に見極めないと事件を起こします.

事件の例として,

  • 冗長になる.

  • 拡張性が無くなる.

  • なんで動いているのかわからなくなる.

といった問題があります.これは今回の開発においても発生しました.

今回コピペが多発していたのはサーバとやり取りをするためのHTTP Requestに関する部分です.SignInやSignUpなどはリクエストパラメータが変わるだけで本質的にはPOST操作であります.しかし,二,三行しか異ならないのにファイルが分けてある部分があったりしました.

また,コピペ部分のコードを弄る必要が出てきたときに挙動が意味不明すぎて手間取ったこともありました.

解決策

これを見た私はまず共通化を図りました.冗長だった部分つまりは,HTTP Request部分をabstractな感じにしてそれを使うclassに継承させました.

しかし後に,さらに問題が発生しました.

それは,非常にクリティカルな問題でした.よくよく考えると,コピペのコードを使っているメリットとは??となりました.

Webに転がっている記事は文量を最低限に抑えるために,かなり簡潔に書かれています.それゆえ,そのままコピペするといろいろ問題が置きます.

よくよく考えてみれば,こんなの一から実装するのではなくokHttp + Retrofitのような解決策が最適だったはずです.

変に固執して頑張るのではなく,なにが最もこの問題を将来的にも解決できるかを意識するのが大切です.

問題3 Android4.x 系だけで動かなくなる

問題

まあ有名なAndroidバージョンレベル低いとなぜか動かなくなる系の問題です.これはまじで殺意が湧きます

じゃあこういう問題と直面したときにどうやってバグを特定するのが最善だったのでしょうか? 適切に依存を分けることができていれば,もっと容易に特定できたはずです(実際には,Wiresharkでパケット解析しながら突き詰めていきました.).

ちなみに,踏んだバグはAndroid5.x以上はURLにUTF-8そのままで行けたのですが,4以下だと適切にエンコードをしなければならなかったようです.

解決策

端的に言うと,Layerをキチンと分け,その上で一方向に依存するようにつくるということです.

方向が一方向であれば,あっちいってこっちいってみたいに原因を探さなくてもすぐに原因究明できます.私はMVVMを今回は採用していきたいと思います.

そして

最終的にはこのような感じでアプリを改修したいと考えています.

f:id:chigichan24:20171219220821p:plain:w500

おわりに

いかがだったでしょうか?私自身設計を一から考える機会はあんまり経験したことがなく.そう考えるメリットってなんだろうて感じることが多くありました.しかし,そうしないと起きる不都合を実際に経験するとその大事さを身にしみて体感しました.

このアプリはまずAndroidからこの設計方針に沿って再実装します.

さらに,いずれiOSにも対応します(断言).そういう設計ができているのか?また自問自答し,メンバーと話し合い良い設計を見つけていきたいです.

最後の最後に.

このアプリはSyncPodといいます. ぜひぜひぜひぜひぜひぜひぜひぜひぜひぜひダウンロード・インストールして遊んで私に連絡してください!!!!!!!!!!!

play.google.com

*1:そもそもそれは本当なのか?という問題があります.それを自分自身が確認していないので本当なのか知らないですが,まあそうなんでしょう.そう信じてます.

高専からmastに編入してみて

この記事は mast Advent Calendar 2017 の 19日目の記事として書かれています.

adventar.org

こんばんは.はじめまして.おひさしぶりです.

mast15に三年次編入した @chigichan24 です.

ほかのアドベントカレンダーこんなのとかこんなのを書いてます.暇な人は見てみてください.

今日は,高専から筑波大学の情報学群 情報メディア創成学類に編入してみて感じたこと,高専との比較とかそういう観点でエントリを書いていきたいと思います.

対象はmastに興味がある人,特に来年から編入でmastな人mastに編入してみたい人編入生って何考えてんの?と思っている人とかです.

そもそもお前は何者?

🐷🍜で有名な高専をなんとか5年間で卒業しました.

高専の時は制御情報工学科という,簡単に言うとロボットを作れるようになりましょうみたいな学科で,機械・電気電子・制御・情報 みたいな4軸を中心に勉強してました.

高専の時からプログラミングは人並みにはやっていて,いろいろ作ったり,作ったり,作ったりしてました.

mastに編入してからは,機室の隅っこでコミュ障しながら授業聞いてます.

mastってなに?

情報メディア創成学類は、情報通信技術の基礎教育の上に、ネットワーク上を流通するコンテンツを生み出し・活用する技術(コンテンツ・テクノロジー)や、コンテンツの蓄積や流通を支える技術(ネットメディア・テクノロジー)を学ぶために創設された学類です。コンテンツそのもので勝負するクリエータを養成する学類ではなく、技術力で社会にインパクトを与えるエンジニアを養成する学類です。

公式のサイト にそう書いてあります.こうらしいです.

まずどうやって編入するの?

受験をします.

合格すると入れます(それはそう)

そこら辺の入試科目とかは過去のエントリを読んで下さい.

chigichan24.hatenablog.com

単位はどうなるの??

これはリアルで大事な問題です.

編入のオリエンテーションみたいなので説明されますが,単位変換という一大イベントを行わなければなりません.

単位変換は高専や他大学で取得した単位を筑波大学の(主に)1,2年次の単位に変換するための申請です.

この単位変換,普通に候補を出すだけでも厳しいのですが,追い打ちをかけるように 期限が凄い短くて一週間後に出せ.みたいな超短いスパンで支援係の人 と連絡するので大学の支援係とまず仲良くなれす.

変換の方法としては,1 対 1 に対応する科目ってなかなか少ないので,多 対 1 ,多 対 多 で変換していきます.しかし,注意点として多 対 1とか 多 対 多 をする時は結構渋られる上にちゃんとシラバスの内容が見られるので,変なノリで変換しているとつっこまれます.

また,一応制約としては高専4,5年生の単位のみ可能と言われていますが,そんなん守ってたらプログラミングなんて高専1年生でやったわとか,線形代数なんて高専2,3年生でやったわ💢💢💢みたいな気持ちになり,変換できなくなるのでそこら辺は容赦なく変換に入れても大丈夫です.

あとこれはmastに限った話かもしれませんが,見る先生によって単位認定のゆるさが違う(?) ので根気よくチャレンジするのが大事です.

周りに聞いてみた所,高専出身者だと70前半から70後半位変換されてました.

大学からの編入の人でも70近く変換されていたので,大学からだからつらいみたいなのはあんまり無いんじゃないかなと思います.

変換で大事なのはなるべく必修を変換することと,卒研や実験の単位はワイルドカードになりやすいので適切に使うことです.

無理な変換をして卒研を一単位添えるみたいなテクがあったりします.

また,四年生になるための条件として,

100単位以上取得する.かつ,3年次の実験の単位を取得する.

というのがあります.

つまり,70単位認定されるとあとは残りの30単位を3年生で取得する必要があります.

これくらいなら多分大丈夫です.

mastの雰囲気は?

まず高専との大きな違いは女の子がたくさんいることです.

これはそもそも大学に入ったときに思ったのですが,世界の男女比は本当に1:1なんだなぁと実感しました.

高専のときは40人のクラスに対して2人と男子校みたいな感じでしたが,mast15は20人くらいなんですかね(?)まあ体感多いです.

でも人の慣れというのは怖いもので,編入学した当初は

「やべぇ.女子おおい.ウケる.」

みたいな感じでしたが最近はこれに慣れてきました.良くないですね(?)

クラスのひとたちはみんな編入生に優しいです.他の大学とくらべて受入人数が多いからかなんなのかわかりませんが,とにかく排除される感じは少なくとも私自身は感じていません.普通にクラスの飲み会とかに誘ってくれます.優しい!!!!!

あとはみんなクリエイティブです.DNGにAREとして入っている人とかの影響や学類そのものの特性からか,ものづくりをしてアウトプットしている人が多い印象を受けます.

3年生の最初の段階でpublicationが大量にあって国際学会何本か通してますみたいな人もいたり,そうでなくてもこういう作品作ってきましたみたいな人もいてびびります.

このものづくり精神というか,何かをアウトプットするという考えは非常に高専に似ているなぁと思います.

情報科学類(coins)と情報メディア創成学類(mast)

編入をする上で筑波で情報系な学類に行こうと思うとこの2つの選択肢で悩むと思います.

個人的な見解はコンピュータサイエンス,基礎理論を固めるぜ👊みたいな人はcoins

プログラミングはあくまでツールでそれを使ってどう表現するか?みたいな人はmast

がいいのかなぁと思ってます.まあもちろんcoinsでmast っぽいことはできると思うし,逆もまたしかりです.

具体例を挙げるなら,例えばデータベースシステムみたいな科目があったとします.

coinsではデータベースの構造(B Treeで〜〜)みたいな話とか,第二正規形が...みたいな話とかが中心だと思われます.

一方mastでは,もちろん上のような話もありますが,それを踏まえた上で,実際にデータベース設計してついでにwebアプリケーションを作ってみよう!!みたいな流れになります.これが決定的な差だなぁと思います.

勉強内容以外の違いは,ワイワイしてるというか横のつながりが強そうのはmastの方な気がしてcoinsなんか横のつながりがうすそう(偏見),それもまた高専の雰囲気に近いなぁと思ったりしてます.

大学の授業スタイルと高専の授業スタイル

大学の授業は基本的にスライドベースで進んでいきます.資料は適当なサービスの上で公開されるので各自ダウンロードするなり,印刷するなり適当にします.

出席も高専みたいに名前呼ばれるわけではなく,PIN式なので楽です.

また,PCを普通に開いて許されるので適当にググりながら授業聞いたり,気になった部分をプログラム書いたりメモったり,Twitterで授業を実況したりできます.プログラミングをする内職がはかどります.

大学に入ると授業がつらいと編入する前は聞いたこともありましたが,特にそうつらいと思った科目は今のところ無いです.ただ,mastはものを作ってアウトプットすることそのものが課題になることも多いので,そういう時は計算機室に深夜2時とかでも人がたくさんいることもあります.

レポートも高専のときのように理不尽に手書きを強要されることは無いので楽です.TeXつかえるので字が汚い私は非常にありがたいです.もちろん4bitCPUの回路図を手書きさせられたり,百数十点もある実験データを手でプロットさせられ,それを結ぶ曲線を自在定規で引いたり,A0用紙に手書きで設計図をドラフターで書かされたりすることは無いです.

全部適切なツールを使ってよしなにすれば大丈夫です.

mastのうーんって思う点

扱っている範囲が広すぎてめちゃくちゃコンピュータサイエンスを究めたいみたいな人にとってはつらいかもしれません.coinsのほうが良いと思います.

最近の私

最近はもっぱら同じ三年次編入のたお くんを一方的にライバル視しながら,頑張っています.

彼は,mastらしい感じでいろいろ考え,実績を残しています(ついでにイケメンでずるい)

私はあんまり見た目のインパクトがあるような実績とか活動をできていないですが,

  • とにかくプログラムを書く.
  • インターンで技術を磨く(LINE,Fringe81,リブセンス,コロプラ) 記事
  • コンテストに参加する(ISUCON,ICPC,MashUp Award) 記事 記事
  • 高専のときの卒論が英訳されどっかの学会に行く(らしい)

また,最近は友人とAndroidアプリを作りました.よかったら入れてみてください.

play.google.com

みたいな地味な方向性で頑張っています.今後も私らしく私らしい戦い方をしてmastでいろんなことを学んで行きたいな!!と思ってます.

これからもみなさんよろしくお願いします.

まとめ

学びたいことがあるなら編入したほうが楽しい!!