Boolean変数/関数にisプレフィックスを付けるのはNG

言語問わずこういったコーディング規約の話は良く議論されるが、担当中アプリでもこの話が出てきた。
Boolean変数/関数にisプレフィックスを付けるのはOKかNGか。
結論から言うとプレフィックスは付けてはいけない。

isはプレフィックスではなく英文としておかしくない時だけ付ける

変数に名前を付けるとき、考えるのはプレフィックスではなく英文としておかしくない命名にするべき。

  • isAnsweredQuestion → be動詞 + 動詞で動詞が被っているのでおかしい
  • answeredQuestion → 動詞 + 名詞なのでOK
  • isEmpty → be動詞 + 形容詞なのでOK

言語が提供するAPIにも付いてない

JavaのFile.exists()もisExists()ではなくexists()とプレフィックスはついてない。
Object.equals()もだ。

そもそもプレフィックスはなぜ付けてた

IDEが発達していなかった時の産物。現在のIDEではむしろコードのノイズになる。

まとめ

  • プレフィックスは過去の産物。できるだけ使わないことを意識する。
  • 命名するときは英語として違和感ない形のほうが本質を捉えた命名にできる。→理解しやすくバグの少ないコードに繋がる。
  • 英語勉強しよう。(私も。英語間違ってたらごめん。)

Androidで通知をタップしたかどうか検知する

Notification経由でActivityが起動されたか検知するというもの。 以前作っていたアプリではActivity.onNewIntent()でやっていた記憶があったが実装しただけでは通知されなかった。

ググったところ↓の記事を見つけた。onNewIntent()で受け取りたいActivityにandroid:launchMode="singleTop"を設定しろ。というもの。 stackoverflow.com

singleTopを設定しない場合、Activityスタックに同じActivityが複数残っていたので、NotificationのIntentがnewIntent扱いにならない?のかな。 この辺忘れやすいので覚えておきたいところ。

FirebaseのクラッシュレポートがCrashlyticsに移行するらしい

Firebaseのダッシュボードみてたらこんなメッセージが表示されていた。
「将来は、Crashlytics が Firebase のクラッシュ レポート機能になります。今すぐお試しください。FABRIC でインストール」 f:id:paraya3636:20170526124215p:plain

マジ?正直逆だと思ってた。FabricがGoogleに買収されていたのは知っていたので、将来的にはFirebaseに統合されるんだろうなと思っていたし動こうとしていた。 Firebaseクラッシュレポートが今すぐ廃止になるという話ではないようだけど…結構驚いた。

紹介ページにもその旨書かれていた。重大なバグがないならCrashlyticsに移行するのを推奨する的な感じかな。 f:id:paraya3636:20170526124234p:plain https://firebase.google.com/docs/crash/

今後もCrashlyticsを使っていこう。

GoogleI/O 2017でAndroidがKotlinを正式サポート声明出してたけど恐れるものではない

つい先日行われたGoogleI/O 2017で、AndroidがKotlinを公式にサポートする声明を出していた。 具体的にはAndroidStudio3.0から何もせず使えるということなので、3.0からKotlinプラグインが含まれる形で配布されると推測。

その関連でQiitaではKotlin入門の記事が急激にいいね付いてたり、TwitterではKotlinに対する不安をちらほら見かけた。 新しい言語をサポートするということで驚いているエンジニアが多い印象。 でもKotlinを使ってる身からするとそんなに身構えなくてもいいのになという感想を持ったので、少しKotlinがどんなものなのかを振り返ってみる。

KotlinはJava

Twitter上でKotlinが導入されたらJavaは使えなくなる?的なツイートを見たけど、そんなことはない。 KotlinとJavaは共存できるのでどちらか片方を選んだらもう片方は使えなくなるといったことはない。 むしろKotlinはビルド時にJavaのコードに変換される。 DroidKaigi2017でトクバイの八木さんが講演していたので参考までに。

speakerdeck.com

JavaでもKotlinと同等のコードは書ける。ただめんどい。

上記で説明したとおりKotlinはJavaに変換される。つまり逆の話をするとJavaでもKotlinのコードに相当するものを書ける。 でもコード量が多くなりがちで面倒。例えば以下のJavaUserクラスとKotlinUserクラスはビルド時も実行時も同じ挙動をするがコード量がだいぶ増減している。 概ねfinal宣言の簡略化とgetter/setterの自動生成、プライマリコンストラクタのお陰でKotlinはコード削減している。

public class JavaUser {
    private final String userId;

    public JavaUser(@NotNull String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }
}
class KotlinUser(val userId: String)

JavaっぽくKotlinを書いてもいい

Kotlinは言語なのでJavaと記法が違うところがある。特に上のコードを見てプライマリコンストラクタってなんだよ…って思う人も居ると思う。 初期の頃私も思ってたし、書き方合わないと思ってた。 そういう所はJavaっぽく書いても良いと思う。 例えばプライマリコンストラクタはセカンダリコンストラクタを用いることでJavaっぽく書ける。

class KotlinUser {

    val userId: String
    
    constructor(userId: String) {
        this.userId = userId
    }
}

コード量は増えるもののJavaに慣れてるなら上記コードでもいいと思う。 Kotlinの本質は、NullPointerExceptionの激減finalフィールドの書きやすさあたりだと思っているので本質のメリットさえ享受できていれば慣れるまでJavaぽく書いてもいいと思う。

Javaと共存

最初のほうでも書いたがKotlinはJavaなのでJavaと共存可能。 KotlinからJavaのコードを呼べるし、JavaからKotlinのコードを呼べる。 SwiftのようなBridging-Header.hなど設定ファイルは必要ない。

むしろJavaで書いてもいい

Kotlinの一部記法が良くわからず、一部Javaで書きたい人も居ると思う。 Java書いてもいいと思う。100%Kotlinにする必要はないと思う。

そして、Kotlinを勉強してみてもJavaがやっぱりいいと思う人は、Javaで書いてもいいと思う。 エンジニアにも好みがあるし、一番速く一番品質良く書ける言語で書くのが一番だと思う。

やっぱりKotlinをおすすめしたい

上でJavaで書いてもいいとしたが、でもKotlinで書けるならKotlinで書いたほうが良いとは思う。 最近仕事でJava100%で書かれたAndroidアプリを引き継いだのだが、NullPointerExceptionでのクラッシュレポートが多いので、Kotlin導入出来ていれば大部分は防げたんじゃないかという思いが強くある。 Kotlinは強くおすすめしたい。

AndroidStudioのWebpコンバータはとても良い

AndroidStudio2.3からwebpコンバータが搭載された。

画像を右クリック→ convert to WebP でコンバート可能。 早速つかってみた。

適用した箇所

写真のような画像は40%以上ファイルサイズが小さくなった。 逆にアイコン画像などは大きく変化しなかったり逆にファイルサイズが大きくなったりした。

75%品質で画像サイズが大きくなってしまう場合

品質を100にすると1〜2%ほどだが元画像から若干ファイルサイズを削ることができる。

Android5系でwebpが正しく表示されないことがある

画像内に透過があると画像の一部が壊れたように表示されることがあった。 透過画像でも一部の画像のみだったので、一旦pngに戻して対応した。

pngへのコンバートも出来る

png→wep→pngすると元の画像より大きくなってしまった。 pngに戻したいときは元画像に戻したほうが良い。

まとめ

少し癖はあるがアプリサイズを小さく出来るのでとても良いと思った。 特に今作ってるアプリはサーバレスでアプリサイズが肥大化してるので活用したい。

Android5系の一部端末でアニメーションがカクつくのを修正した

ARROWS NX/XperiaZ3/XperiaZ4辺りのAndroid5系端末でアニメーションがガクガクになっていたのを修正した。 Nexus5ではそこまでカクついたりはしていなかった。

問題箇所

問題箇所は以下が主な原因だった。

  • 余分なViewGroupなどレイアウトxmlの階層構造の深さ
  • android:clipChildren="false"
  • android:clipToPadding="false"

やっていたアニメーション

細かくは話せないがそこそこ複雑なViewで以下のようなアニメーションを同時に行っていた。

  • 背景の大きい画像をフェードアウト
  • CardViewをフェードしつつ45度回転しつつ画面外に移動させて見えなくする
  • CardView内の内容を更新
  • 背景の大きい画像を更新
  • CardViewをフェードしつつ45度回転しつつ画面内に登場させる
  • 背景の大きい画像をフェードイン

FPSを計測する

Taktを利用した。

github.com

FPSは通常30〜50 アニメーションする際に15まで落ちる感じ。 修正後は40〜50FPSで安定するようになった。

感想

  • 調査段階ではこの辺を読んで、アニメーションとViewの更新処理をより厳密に分けようとOnGlobalLayoutListenerを使ってみたりしたけどあまり効果はなかった。
  • 余分なViewGroupが多かったので、よりフラットな構造にしたら目に見えて改善したので驚いた。
  • clipChildren/clipToPaddingも変更しただけで目に見えて改善した。onLayoutなど描画イベントの波及を増やしてしまうんだろうか?マイナスマージンは避けようと思った。

DDDでの失敗談

近々同僚とLT大会をするので話すことをMarkdownで書いてみたので投稿。

DDDでの失敗談

DDDを1年半くらい実践してきて色々成功したこと失敗したことがあった。 この場では失敗談を共有してアンチパターンへの対処法をお伝えしたい。

ドメインしっかりと設計すれば変更少なくてすむだろう→そんなことはなかった

ドメインの設計見直しタイミングは以下のケースがあった。

  • 仕様を固めていく上で他の仕様も変わるケース
  • ユーザテストの意見反映で仕様が変わるケース
  • 実装を進めていてより良い設計を思いついたケース

意外とコロコロ変わる。 悩んでベスト設計を目指すのではなく、ベター設計で速度を優先したほうが良い。

ユビキタス言語決めたら変更はないだろう→変更入りまくり

  • 名前が学術名で難しいので分かりやすい名前に変えた
  • デザイン進めて行く上で変わった
  • 他アプリでの名称違うからそっちの反映
  • 監修担当から変更要望反映

ユビキタス言語は変わる。 変わらないように努めるべきだが変わる可能性は充分にあることを留意する。

通信も結局はデータ操作だからData層に入れられそう→Domain層でHttpステータスに応じて色々したい…

  • 通信処理もDB操作と同じくset/getのイメージで、returnもValue/nullで扱えそう。通信結果はData層内で隠蔽できそうだと思った。
  • でもHttpステータスに応じてアクション変えたいね。
  • やっぱりドメイン層で扱いたい。

通信結果もビジネスロジックとしてDomain層で扱いたい要望はあるので隠蔽しすぎないこと。 個人的にはCleanArchitectureの図のように、Data層/Web層は分離しとくと分かりやすくて良いと思う。

ビジネスロジックどこ書けばいいかわからん…とりあえず専用クラス作ってそこにメソッド書くか→Entityがただのデータの入れ物化

ビジネスロジックを書く際は既存のEntity/ValueObjectで担当できるか検討する。 担当出来ない場合、サービスクラスとして実装する。UseCaseには書かない。

まとめ

  • ドメインはアプリを作っていく過程で変わる可能性は充分にあるし、後日より良い設計を思いつく可能性が高い。設計に迷ったら時間を掛けすぎず一旦思いついた限りの内容で実装進める。
  • ユビキタス言語はプロジェクト初期に確定するのは難しい。変わらないように努力しつつ、後々変わる事も意識しておく。
  • ドメインは通信結果も意識する。Data層に押し込めすぎないようにする。
  • 振る舞いを考えるときは既存のEntitiy、ValueObjectで探すこと。安易にロジックをUseCaseなりに押し込めない。