AnkoでLayout XMLを殺した

そういえば先月頭にRettyさんでAnkoについてLTしたのでスライド置いておきますね。
speakerdeck.com

あ、ちなみに本稿は特にAnkoの解説は行ってないポエムです。

Ankoとは

Kotlin製DSL。Viewを書くのに利用します。
XMLでView書いた場合の以下のような問題を感じてJetBrainsのエンジニアが開発したのがAnko。

  • 型安全じゃないし
  • null安全じゃないし
  • 似たようなことを毎回かかなきゃいけないし
  • XMLをパースする分パフォーマンス悪いし
  • コードの再利用できないし

こんな感じでViewを書けます

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}

Javaで書いた場合との差が冒頭に貼ったスライドに書いてあるので、興味ある人は見てください。

なにこれ魔法!?🎩

Kotlinの拡張関数とプロパティを利用してます。 拡張関数を引数にとる関数がどうたらこうたら。これも冒頭のスライドに書いてあるので興味のある人は見てください。

XML全部殺してフルAnkoにした

mints-Android-LayeredArchitecture 暇な時に開発してるアプリのViewをすべてAnkoで書いてみました。 (まだ改善できそうなところは多い)

(追記)
HEADではもう、LayoutXMLとDatabindingを利用する形に書き換えてしまった。

ActivityやFragmentとは別のファイルにViewをまとめる

AnkoでViewを書いてる部分

class MainUi : AnkoComponent<MainActivity> {
    private lateinit var viewPager: ViewPager

    override fun createView(ui: AnkoContext<MainActivity>): View = with(ui) {
        verticalLayout {
            val tabLayout = tabLayout {
                tabMode = TabLayout.MODE_SCROLLABLE
                tabGravity = TabLayout.GRAVITY_FILL
                setSelectedTabIndicatorColor(getColor(ctx, R.color.colorPrimary))
            }.lparams(width = matchParent, height = wrapContent)

            viewPager = viewPager {
                id = 1
                offscreenPageLimit = 2
            }.lparams(width = matchParent, height = matchParent)

            tabLayout.setupWithViewPager(viewPager)
        }
    }

    fun showPages(fm: FragmentManager, pages: List<PageAdapter.Page>) {
        viewPager.adapter = PageAdapter(fm, pages)
    }
}

利用側

class MainActivity: AppCompatActivity() {
    private val ui = MainUi()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ui.setContentView(this)
    }
}

XMLを書かなくていいのは結構いいですね。今回は一人での実装だったのでただの予想ですが、コードレビューでXMLを読むのが辛いのですが、Ankoなら多少軽減されるかも。 もっと細かい単位でAnkoComponentを実装していけばコードのreuseができそう。

MacBook Pro 13-inch with TouchBar

仕事用のMacBookPro 13inch TouchBar付きが届いたのでその感想。

tl;dr

  • 薄い軽い、持ち運ぶ気になった
  • ストロークの浅いキーボードなかなか打ちやすいぞ
  • TouchIDが最高なことはみんなしってるだろ?
  • TouchBarに最適化されたソフトウェア結構いいかも
  • TouchBarカスタマイズして便利なショートカットつくれるぞ!
  • escは常に左上にあるから困らねーぞ!
  • functionキーはfn押せばでてくるぞ!
  • キーボードだとかモニタだとかじゃらじゃらつけないんでUSB Type-Cだけなのはこまらんぞ!

ボディ

前モデルに比べて軽く、薄くなった。
多少のさだが、結構体感できるほどに違う。これは正義。
今後は通勤時にも持ち運びしてもいいかなと思う。

キーボード

MacBookとおなじようなキーボード。
慣れてみるとこれがなかなかいい。
扱い始めて数十分後にはもとのキーボードのストロークの深さが気に食わなくなった。

TouchID

TouchIDが最高なことなんてiPhone/iPadつかってる人にはわかりきったことだよね。

TouchBar

よい。 BetterTouchToolsで独自のボタンをつくれるので、AndroidStudioでよく使うコマンドを割り当てたりした。
f:id:lvla:20161218235750j:plain

ソフトウェアがTouchBarに対応している場合もなかなかおもしろい。
たとえばSafariであれば、favorites画面でbookmark barに設置しているものがTouchBarに出ていたり f:id:lvla:20161218235730j:plain メディアの再生を(safariがフォアグラウンドになくても)TouchBarで操作できたり f:id:lvla:20161218235710j:plain これ地味に便利ね。safariでなにかメディアを再生してるときに話しかけられた場合、safariにきりかえて...タブひらいて...ってやらなきゃいけなかったのが面倒だったので(面倒だったのでそもそも止めないことも多かった)

Escapeない

気にならない。
物理ボタンではなくなったが左上には常に表示されている。

Functionキーない

以前よりワンストローク増えてしまうが、fnを押せばTouchBarにFunctionキーが表示されるので困らない。
コマンド類は前述したようにTouchBarのカスタマイズで最適化できる。

TrackPad

カーソルスピード高く設定して使ってるので広くなっても特に恩恵はない。
誤タッチを気にしてるひともいるみたいだけど、ちゃんとパームリジェクション効くから落ち着けって。

とはいうものの、右下クリックをSecondaryClickに割り当ててると困る。
右下に手のひらが置かれてる状態でクリックするとSecondaryClickとして検出される。
諦めて2FingerClickでSecondaryClickにした。は〜。

USB Type-Cしかない

困らない。
外部キーボード??外部モニタ??キーボードもモニタもMBPにすでについてますよ!!
検証端末の接続もこまらない。Nexus5XはもともとUSB Type-Cです。
iPhoneはケーブルかわないとですね。は〜だるい。

電源

MagSafeはその名の通り安全で最高だった。
ただUSB Type-Cにもいいところはある。

  • 右からでも左からでも給電できる
  • バイルバッテリーから給電できる

バイルバッテリーから給電できるの最高でしょう?

総評

満足

Kotlin拡張関数は怖くない、その実態を紐解く。

Kotlin未経験Javaエンジニアに拡張関数を説明すると「怖い」と言われることがあります。 おそらく、クラスを継承する事なく拡張できることが黒魔術的に見えるがゆえの感想なのではないでしょうか。 本稿では拡張関数の実態を知ることで、拡張関数をもっと身近に感じてもらいたいと思います。

拡張関数とはなにか

拡張関数はクラスを継承せずに機能を追加するための機能です。 下記のようにfun Type.functionName(...)とすることでそのTypeに新たに関数を追加する事ができます。

fun String.println() {
    println(this)
}

拡張関数は通常の関数と同じように呼び出すことが可能です。

"Hello World".println() // out: Hello World

拡張関数はどのように実現されているのか

StringExtension.ktファイルに実装した下記コードをコンパイルすると、StringExtensionKt.classが生成されます。

fun String.println() {
    println(this)
}

ではStringExtensionKt.classJavaデコンパイルしてみましょう。

public final class StringExtensionKt {
   public static final void println(@NotNull String $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      System.out.println($receiver);
   }
}

ファイル名Ktクラスに拡張関数と同名のstaticメソッドが生成されていることから、拡張関数がただのstaticメソッドであることがわかると思います。 ここまで分かってしまえば何も怖いものはありませんね。

private拡張関数

以下のようなFooクラスがあるとします。

class Foo {

}

これに対してFooExtensionファイルにprivate拡張関数を実装しましょう。

private fun Foo.doSomething() {
    
}

class Foo {
    init {
        doSomething()
    }
}

さて、ここで一つ疑問が出てきました。先程の例と同様であれば以下のようにFooExtensionKtクラスにprivate staticメソッドが生成されるはずです。 となるとFooExtensionのprivate staticメソッドをFooから呼び出せる事はおかしいですね。

public final class FooExtensionKt {
   private static final void doSomething(@NotNull Foo $receiver) {
   }
}

実際にコンパイルしてみると以下のようになりました。

public final class FooExtensionKt {
   private static final void doSomething(@NotNull Foo $receiver) {
   }

   public static final void access$doSomething(@NotNull Foo $receiver) {
      doSomething($receiver);
   }
}

doSomethingへアクセスするためのブリッジメソッドが生成されています。 ここでFoo.classもデコンパイルしてみましょう。

public final class Foo {
   public Foo() {
      FooExtensionKt.access$doSomething(this);
   }
}

なんと、private拡張関数を呼び出していた部分はブリッジメソッドの呼び出しに変わっています。 どうやらコンパイル時にブリッジメソッドが生成され、Kotlinからのprivate拡張関数呼び出しはこのブリッジメソッド呼び出しに置き換えられるようです。

では、もしFooがJavaクラスだった場合はどうでしょうか。 この場合そのprivateメソッドはまったくの役立たずになります。Javaからはただのstaticメソッドとしか見えない上にprivateであればアクセスする方法が無いからです。 コンパイル時に生成されるブリッジメソッドへのアクセスもコンパイル前では不可能です。

おわりに

どうでもいいですが、今回はバイトコードもそこそこ読みました。 普段全く読むことがないのでバイトコードを読む力はあまりないですが、これを機にちょくちょく見ていこうかなと思います。 Android StudioであればTools -> Kotlin -> Show Kotlin Bytecodeで即座に読むことが出来ますので、是非活用してみてください。

eurekaに入社して半年たった

eurekaに入ってから半年が経過。 pairsAndroidアプリを開発してる。 どういう会社だとか書くのは面倒なのでやったことだけ軽くリストアップ。

やったこと

  • Orma導入
  • Kotlin導入
  • Dagger導入
  • Architecture改善

Orma導入

SQLiteいじるのにActiveAndroidを使っていた。ActiveAndroidは遅いし開発とまってるし、使い続けてもメリットは無いなということでOrmaへの移行を行った。
Ormaは速い。
クエリビルダはカラム単位でメソッドを自動生成してくれる。文字列を使ってカラム名を指定とかする必要がない。Typoによるバグは出ないし、テーブル定義でカラム名が変更されたらクエリビルダにも変更が加わるのでコンパイルが通らなくなる。
マイグレーションはリネーム以外は自動。
素晴らしいですね。

pairsはテーブル数多いしカラムも多かったのでそれなりに大変だった。
まったく根拠のない推測だけど、いまどきのネイティブアプリはDBそんなに複雑なものは無いと思うので大体の場合は大変ではないともう。

Kotlin導入

個人で一番書いている言語。仕事でも書きたいなと思ってた。
個人的にKotlinで気に入っている機能はnull安全と関数リテラル
NPEが起こりうるコード書けない仕様になってる。
関数を変数に代入したり関数に渡したりできる。

チームに「Kotlinどう?」って聞くと、拒否反応は出なかった。
Kotlin勉強会を開いたり社内LT大会でKotlinを布教した。

フルKotlinにする予定は今のところない。ViewのみJavaで書いて、PresenterやModelはKotlinで書いてる。
追記: 結局Kotlin最高だなとなってそういった制限は撤廃された。

Dagger導入

後述するArchitectureの改善するにあたってDaggerがないと厳しい感じだったので導入。

Architecture改善

API周り・DB周りのインターフェースがstaticメソッドで、テストが書きにくかった。

class FooDao {
    public static List<Foo> findAll() {
        return App.getOrma().selectFromFoo().toList();
    }

    public static void save(Foo foo) {
        App.getOrma.insertIntoFoo(foo);
    }
}
class FooClient {
    public static Observable<Foo> fetch() {
        return Client.getRetrofit()
                .create(FooService.class)
                .fetch()
                .doOnNext(new Action1() {
                    public void call(Foo foo) {
                        FooDao.save(foo);
                    }
                });
    }
}

リクエストの度にRetrofit#createをコールするので処理に無駄が多かった。
DB周りはOrma移行のときに改善するチャンスがあったが、移行と改善を並行させたら絶対コケると思ったのでインターフェースは全く変えてなかった。

依存する物(Service/Orma)はすべてコンストラクタで受け取るように変更。
ClientはRetrofitが生成したServiceを叩くだけのクラスに。
DaoはOrmaを叩くだけのクラスに。
RepositoryはClientで通信してDaoでINSERTする、Daoを叩いてSELECTする。
UseCaseは必要なRepositoryを使ってビジネスロジックをもつ。
PresenterはUseCaseとViewの架け橋的存在。

といった感じに。

最近は施策もやった。
あとはちょこちょこリファクタリングしたり、勉強会ひらいたり、AssociateEngineerやインターン生にレクチャーしたり。

エンジニア向けニュースアプリをつくってます。

mintsについて

play.google.com

エンジニア向けのニュースアプリつくってます。下記サービスのクライアントです(menthas作者様に感謝🙏🏻)。

Menthas.com

テクノロジーに関するニュースを扱っているサービスはたくさんありますが、よりエンジニア向けに特化された記事というものはないですよね。大体ガジェットやテック企業のニュースになってしまいます。 その点、menthasはライブラリやフレームワークの話などを集めてきてくれるのでとても重宝しています。

開発

github.com

開発は2016年3月からやっていました。 ある程度完成したところで興味が失せてしまって放置していましたが、8月に公開しました。 そこからまた興味が失せてしまっていましたが、1ヶ月程前に設計を変えて実装しなおすことに決め、アップデートを行いました。

この先考えてること

  • JobSchedulerをつかってみたいので、バックグラウンドで記事を先読んでオフラインでも記事を読めるようにしようかな
  • MVVMもやりたいから差し替えようかな

あまり文章を書くのは得意ではないので、使用した言語とアーキテクチャとライブラリをざらっとかいておきます。

言語

Kotlin

アーキテクチャ

CreanArchitecture + MVP

ライブラリ

Rx

RxJava
RxAndroid
RxBinding

ORM

Orma

Network

OkHttp3
Retrofit2

DI

Dagger2

Image

Picasso

Debug

Timber
Stetho

View

AdvancedRecyclerView
ParallaxViewPager

Resoure

Koresource

Json

Gson

Parcelable

PaperParcel

Test

Robolectric
Knit
MockWebServer
KMockito

build.gradle

未経験者がエンジニアとして働く選択肢

未経験だけどエンジニアになりたい/なったという声をいくつか聞いたので自分の例を書いてみる。

自己紹介

  • 2014年3月 某大学経済学部卒業
  • 2014年9月 受託開発会社に入社
  • 2016年6月 eurekaに入社

適当に大学生活を送っていたので、なんの志もなかった。やれることと言えば営業くらいだろうと思って就職活動をするも、なんの魅力も見いだせなかったので就職先を得ないまま卒業。
その後急にエンジニアになることを決めて受託開発会社に入社。
PSVitaゲーム開発、Webアプリ、Androidアプリ開発を経て受託開発から抜けだしてサービス開発をしたいと思うようになりeurekaに転職。pairsのAndroidアプリのデータベースとかアプリの設計を改善してる。

エンジニアになろうと決めた

プログラミングには元から興味があった。
某MMO RPGのサーバーをローカルでエミュレーションしたり、Minecraftのサーバーを建てて友人同士でワイワイやってたのが理由。
エンジニアはブラックとは聞いていたが、興味のない事を一生だらだらやるより良いだろうと思った。ブラックでも技術さえ獲得すればより良い環境に行くこともできるだろうしとも思った。

企業選び

有名なプロダクトつくってるような所は未経験の募集なんてやってないので諦めましょう。
SIer(業務システムの開発を請け負う企業)とか受託でゲームとかアプリ作ってる所は未経験でも結構募集してる。

私の場合、業務システムの開発はつまらないなと思ったのでSIerは除外した。 ゲーム・スマートフォンアプリ・業務ソリューションと幅広く受託してる会社を選びました(1社しか受けてないですが)。

ブラック企業ホワイト企業の区別の付け方はわかりません。請負で開発している以上、残業の量はプロジェクトによるし。
SIerの友人は200~300時間働いたりしてたけど、プロジェクト変わったらやたら暇になったと言っていた。
私も受託開発会社での最後のプロジェクトは、立ち上げ時260時間働いたりしたけどそれ以降はほとんど定時に帰っていた。
ブラックかホワイトかってのも個人の価値観によるしね。260時間でも楽しかったので全く苦じゃなかった。

この時は「未経験者を募集している会社でスキルを身につけて、好きなゲームを作っている所に転職しよう」とか考えてた。
実際はゲームよりもアプリを作ることにハマってWeb系の会社に転職しましたが。
まぁそんな心持ちでいいんじゃないかな。やりたいことがあってそのための1Stepと捉えての就職なんてのもありなんじゃないでしょうか。

勉強

未経験者歓迎と書いてあっても全く勉強しないで入るのは辛いだけなので勉強しましょう。
私はスッキリわかるJava入門を購入しました。
これでJavaという言語の文法とオブジェクト指向(なんかプログラミングする上での概念とでも思ってください)を学んでいった。 文法を覚えるだけでは英語を喋れないのと同様、プログラムミングも文法を覚えただけでは全く書けないので書く事が重要。 上記の本は練習問題が随所にあったので良かった。

Javaを選んだのはよく聞く名前だったからっていうのと、てきとーにぐぐったらJavaにしとけって書いてあったから。私も未経験者におすすめを聞かれたらJavaと答える。理由は間口が広いから。

数学が云々とかよく書かれてますが、やることによる。
数学が出来ないと全く何も出来ない層もあるだろうし、まったく数学を使わない層もある。
数学が分かるほうが選択肢が広がるのはたしか。

入社・研修

未経験者も受け入れておいて研修無い企業はやばいので弾こう。

私の場合は2ヶ月の研修期間があったが、タイミングが悪かったのかちゃんとした内容の研修は受けれず危機感を覚えた。
翌年の4月に入ってきた新入社員(半数が未経験)は良い研修を受けていたようです。

業務

  • いまオレはこの会社で最底辺に属し、最も使えない人間である
  • なんでもかんでも聞いたら「こいつこんなこともわからないのか…」とお荷物扱いされる

というネガティブな思考の上で仕事をしていた。心がもたないのでこういう考えは捨てたほうが良い。
未経験を募集している時点で企業がその人を教育するのは当たり前のことだし、わからないことを教えてくれない後輩/部下ってのも困る。

  • 何から何まで分からないなら、その事をしっかり伝えておくこと
  • 10分くらい自分で考える
  • 10分たっても分からなかった分かりそうな人に聞いてみる
  • 人の書いたコードを真似て覚える
  • 日々情報を集める

その後こんな感じで仕事してたらいつの間にかAndroidアプリを一人で作らされて、アプリ開発にのめり込みだして転職して今に至るって感じです。

26歳で未経験で入社してきた人だっているし、営業からエンジニアにジョブチェンジした人だっているし、ディレクターからジョブチェンジした人だっています。 大卒じゃないと無理なんてこともなくていろんな学歴の人がいます。
挑戦する気さえあればやってやれないことはないので興味があれば挑戦してみては?