それがいいことの序章です

楽しいことならいっぱい夢見ることならめいっぱい

Kyashに入社して1年が経ったよ

あっという間に1年が経った、おちこんだりはしてなくて、私はげんきです。 前職は転籍だったので、しっかり環境が変わるのは初めてだったけど、それなりに馴染めたしとても楽しく開発ができてると思う。

最近はAndroidのリードの立ち回りもやっていて、それなりにバリューも出せてるんじゃあないだろうか。とはいえ、モバイルチームみんなそれぞれ優秀でオーナーシップがあるのでチームでモバイル開発をやってる感じがしてとっても良い。それぞれ個性があって、スキルマップみたいなのを作ったら塗られてる面積がでかいだろうなと思ってる。みんな同じとこが塗られるんじゃなくて、面積が多いほうがチームパワーが高くていいなと思っているのでとても好き。まだまだスタートアップなので、荒削りなところがありもするけど、トレードオフをおさえて進めている感覚がある。モバイルで見ると、最近の開発はだいたい宣言的UIでやってるしKMPもいわゆるViewModel相当のレイヤーまで責務を寄せているし、チャレンジングな部分もあるし、やっていきは高いんじゃないかな。ほほう、と思った人はラフに雑談しましょう。

入社するときに気になってたいわゆるFintechにおける開発って求められるものが違うんじゃないかという部分は、事前に聞いてた通りモバイル開発ではそんなに感じることはない。けど、業界という意味だと中にいないと知り得ない難しさや歯がゆさがめちゃくちゃあって、いやはやワクワクすっぞという感じ。不確実性が本当に高い。こうときこそ、開発組織としても腕の見せ所だと思うタイプなので、さあどうやってやりますかね(にっこり)という毎日である。エンジニアリングをやっているぞ。 めちゃくちゃ不確実性の高いドメイン領域を戦う上で、背中を預けられるビジネスサイドがいることも中に入って本当に感じる。あんまし業務上で深く関わることは多くないけど、リリースに必要な要件や法的な部分などをガシガシやってるのをSlackで見ると、One Teamを感じる。頼もしいのひとこと。

褒めてばっかぽいけど、自分がいろいろと楽しむタイプなのでまあよいでしょう。簡単に勝つより山王戦くらいの緊迫感があったほうがいいじゃない。うまくいってない部分はたくさんあるし変化も激しい、けどみんなとまだまだうまくできるんじゃないかという気がしてる、まだまだやっていくぞ!

楽しく開発しています!

KyashのKMMにおけるテストのこれまでとこれから

はじめに

これは Kyash Advent Calendar 2022 の12日目の記事です、こんにちは あるいは こんばんは。

10月にAndroidエンジニアとしてKyashに入社し2ヶ月が立ちました、@_rmakiyamaです。楽しく開発しています!

Kyashのモバイルアプリ開発ではKMM (Kotlin Multiplatform Mobile) を採用しています。Kyashの場合、ロジックの共通化と各OSがUIを最適化しUXを最大化することを方針とし、UI以外はすべてKMMで共通化する選択をとっています。
本記事では、KMMにおけるテストについて、「実装当時と前提である課題が変わったことで、方針を変えていこうとしている」という話をします。

これまで

まずはこれまでのKMMにおけるテストの方針について簡単に紹介します。

アーキテクチャ外観

アーキテクチャ外観

  • 各OSのUI層はSwiftUI/Jetpack Composeを採用
  • UIからはStateHolderとしてKMMで実装するMVIベースのReactorを利用

より詳しい背景などは Kyash Tech Talk #3 で発表されたMobileアプリのアーキテクチャ設計法をご覧ください。

テストの方針

おおきく下記の観点からReactorからApiClient層までの統合テストを行う選択をしていました。

  • 各OSでロジックが異なったことによるインシデントを避けたい
  • multi-thread問題を含むKotlin/Native起因のクラッシュを避けたい

統合テストでは、HttpClientにおけるレスポンスのみをMockする方法を取っています。KyashではHttpClientにKtorを採用しているため、Ktor ClientのMockEngineを活用しています。

これまでのテストの方針

これにより、expect/actualでの各プラットフォームにおけるコードの差異がある場合もワンソースでテストを行うことができ、Kotlin/Native起因のクラッシュにも気づきやすい状態を実現しています。

くわしい説明は割愛しますが、Kyashでは統合テストを実装しやすくするためのヘルパーメソッドを用意し、面倒なセットアップとレスポンスのMockを容易に書ける仕組みを整え、下記のように手軽に統合テストを記述することができます。

class HogeReactorTest {
    @Test
    fun executeAction_hoge_then_piyp() = reactorSuspendTest(
        reactorFactory = ::HogeReactorFactory,
        // 必要なAPIレスポンスのMockを指定
        responses = {
            every { "/testing/api/path" } returns SUCCESS_RESPONSE_JSON
        }
    ) { reactor ->
        // implement your testing
    }
}

課題の変化

これまでの課題のひとつであるmulti-thread問題はNew memory managementに移行することで解決しました。さらに、expect/actualでの各プラットフォームの実装差異の課題について見たときに、expect/actualで実装された処理は少なく、課題感としては小さくなっていると判断できそうでした。

また、これまでの方針はうまく機能していましたが、KMM化が進むにつれて下記のような新たな課題も生まれてきました。

  • data層でのキャッシュの仕組みを導入したことでテストが複雑化する
  • APIのレスポンスが暗号化されていることがありレスポンスのMockコストが高い

これから

課題が変化すれば、解決策も変化していきます。

Kyashでも改めてテストの方針をチームで考え直しました。これまでの課題と新たな課題をもとに、下記の方針とすることにしました。

  • Reactorのユニットテストを必須とする
    • UseCase層からMockする
  • expect/actualでプラットフォーム間に差異のある実装は別途テストをする
  • 必要に応じてこれまでの統合テストも行っていく
    • 既存の仕組みを活かせる

これからのテストの方針

実装としては、愚直に依存するクラスを抽象化し、具象に依存しない作りにすることでMockに置き換えられるようにしています。
Reactorの場合はUseCaseに依存するため、UseCaseをインタフェースで実装し、テストのときはMockに差し替えるようにしています。(※ 擬似コード

interface GetPiyoUseCase {
    suspend operator fun invoke(): Piyo
}

class GetPiyo(...) : GetPiyoUseCase {
    override suspend operator fun invoke(): Piyo {
        return ...
    }
}

class GetPiyoMock : GetPiyoUseCase {
    lateinit var mock: () -> Piyo
    override suspend fun invoke(): Piyo = mock()
}

これを使い、Reactorのテストは下記のようにシンプルなユニットテストとして実装します。HasTestRulesについてはKMMのテストのtips / KMM testing tipsを参考にさせていただいています。

class HogeReactorTest : HasTestRules {
    // BeforeTest/AfterTestを隠蔽
    override val testRules: TestRules = TestRules(MainDispatcherRule())

    // 依存するUseCase群
    private lateinit var getPiyo: GetPiyoUseCase

    private fun createReactor(): HogeReactor {
        return HogeReactor(getPiyo = getPiyo)
    }

    @BeforeTest
    fun setup() {
        // default mocks
        getPiyo = GetPiyoMock().apply { mock = { Piyo.mock() } }
    }

    @Test
    fun executeAction_hoge_then_piyp() = runTest {
        // override mock instance
        getPiyo = GetPiyoMock().apply { mock = { Piyo.mock2() } }
        val reactor = createReactor()
        // implement yout testing
    }
}

この方針にすることで、下記の効果が得られることを期待しています。

  • Reactor単体のテストに集中できる
    • data層のキャッシュの実装に引っ張られること無くテスト可能
  • Reactorが抽象に依存するようになりテスタブルな実装になる
  • 一般に言われるテストピラミッドに沿ってテストが増える

もちろん統合テストが悪いということではありません。テストの範囲を意識してどのようなテストをするかについて、チームで改めて認識を合わせる良い機会になりました。

さらにこれから

あくまでも新たな方針は、現時点での方針に過ぎません。すでにKyashでは下記のようなトピックも上がっています。

  • モックのクラスの実装/管理が大変になる未来が見えるのでライブラリも検討できそう
  • Kotlin/Nativeの問題が少ないなかiosTestを常に回す必要はないのではないか

もっとよくできる部分は引き続きブラッシュアップしていくぞ!という気持ちで引き続きチームで取り組んでいく予定です。

おわりに

アーキテクチャは一度決めて終わりではなく、イテレーティブに改善していく必要のあるものです。今回のように「"なぜ"その決定を下したかが明らかである」ことは、その"なぜ"が変わったタイミングで次の改善を推進しやすくすることにつながります。

まだKMMもベータになったばかりです。KMMやそれを取り巻くエコシステムもどんどん進化していくことでしょう。我々のプロダクトも、KyashのValueである"動いて風を知る"にもあるように、イテレーティブにどんどん進化させていきます!

そんなKyashではAndroidチームをはじめ、様々な職種で仲間を募集しております。一緒にKyashを育てていきましょう!
Kyashをもっと知りたい、すでに応募したい!という方々はこちらから!

セルフワーキングアグリーメントを育てたい

こちらのPodcastを聴いたことがきっかけで、セルフワーキングアグリーメントについて考えてみた。 ワーキングアグリーメントの話以外にも、非常におもしろい話なのでぜひ聴いてみて欲しい。
anchor.fm

ワーキングアグリーメントについての説明には割愛するが、セルフワーキングアグリーメントはざっくりと「仕事をする上で自分が意識したいこと、大事にしたいこと」のようなニュアンスとして自分は捉えている。
意味合いの正確さはさておき、「仕事をする上で自分が意識したいこと、大事にしたいこと」を整理して言語化しておくことは自分にあっていそう。意識しようとしても忘れてしまっていたり、忙しさやその時の感情によっておろそかにしてしまうことがある。

頭にシュッと浮かんだ段階で走り書きしてみたものだとこんな感じになった。

  • たのしく開発をしよう
    • 原点を忘れない。モノづくりは楽しい。
  • 笑顔でいよう
    • 笑顔はいいことの序章です。
  • 素直でいよう
    • 自分自身に正直であろう。
  • 常にあいての新しい側面を見つけよう
    • 決めつけると新しい側面を見せてもらえない
    • 自分の停滞も始まる
  • ルーズボールは全力で拾いに行こう
    • 人生にアウトオブバウンズはないよ
  • だれに、なにを、どのように、を意識する
    • コミュニケーションも、設計も、なんでも
  • 分からないこと、知らないことは、積極的に聞こう
    • お互いの成長機会につながる
  • 適度な自信と充分な謙虚さを持とう
    • どちらも大事
  • 期待値のすり合わせをしよう
    • もやもや・不満はここが原因のことが多い
  • 良いループが回ることを意識しよう
    • やっておわりではない、フィードバックを得よう
  • 健康第一
    • 無理しない
  • 最後は人柄
    • なにはともあれ自分の思う良い人たれ

言葉として整ってなかったり粒度がバラバラだったりとまだまだ稚拙だけど、シュッと浮かんだものはそれなりに自分の中で意識していることでもあると思うので大事にしたいと思ったし、育てていきたいなと思う。いつか振り返られるように、種の状態として残しておこうついでにブログにしてみた。

最後に、元ネタがあるものを簡単にいくつか紹介したい。

笑顔でいよう

僕はMr.Childrenが大好き。これはPADDLEという曲の歌詞が好きでいつも意識している。 ちなみにブログのタイトルもこの歌詞から取っていたりする。いい曲。

常にあいての新しい側面を見つけよう

これは僕のバイブル的な小説、金城一紀さん作品の『映画篇』という小説から参考にしている。 この小説の中のセリフで、以下のようなものがある。

「まぁ、人であれ映画であれなんであれ、知った気になって接した瞬間に相手は新しい顔を見せてくれなくなるし、君の停滞も始まるもんだよ。(中略)」

出典: 金城一紀『映画篇』

これがめちゃくちゃ好きで、人生レベルで意識していることでもあるが、仕事であれ組織であれ技術であれ大事だなと思っている。

ルーズボールは全力で拾いに行こう

これは完全に部活でバスケをやっていた影響である。ルーズボールを拾わないとそれはそれは怒られるのである。
仕事では、誰がボールを持っているかわからない状態のものが意外と結構あったりする。仕事もバスケも、自分ができないことをできるメンバーがたくさんいる。積極的に拾ってシュートを打つもよし、パスをするもよし、試合を前にどんどん進めていくスタンスを常に持っていたいと思う。

最後は人柄

これはなにかのブログで見たワードなんだけど、今となっては見つけられなくなってしまった… 1回この言葉を見つけてから、すごく自分の中に残っていて、今では座右の銘を書くとき言うときはこれを言うようになっている。捉え方によってはあまり良くない印象を与えるかもしれないけど、自分の中ではかなりしっくり来ている。ここももっと言語化をしていきたい。

おわりに

みんなも大なり小なりセルフワーキングアグリーメントにあたる意識している、あるいは意識したいことがあるかもしれない。 ぜひとも聞かせて欲しいし、良いものは積極的に取り入れたい✌🏻

ポジティブでありたい話

とくにこれといったきっかけはないけど、過去に妻と話したPodcastを聞き直してみた。

podcasts.google.com

ストレングスファインダーの1位が「ポジティブ」だった僕が、ポジティブについてあーだこーだ話しているんだけど、自分で話しているので当然といえば当然だが、めちゃめちゃ頷きながら聞いた。

ここで話している「仕事でもスポーツでも、楽しんでいるほうが実力が出る」という持論(自分に当てはまるだけで万人がそうとは思っていない)は、いろんなタイミングで話すことがあって、それだけ自分の中では、無意識に様々なことを楽しむ方向に倒しているんだなと改めて感じる。これは自覚していることでもあるので、意識的にやっていることでもあって、大抵のSNSのプロフィールには「楽しく開発しています」なんて書いていたりする。

少し違う角度で「楽しい」について考えていることを言語化すると、自分の中での「楽しい」は、「楽をする」や「好きなことだけをする」といったこととは少し違いそう。
自分の中の「楽しい」は、スラムダンクの湘北vs豊玉で、南が言う「勝ったほうが100倍楽しいもんな」に近いんだと思う。すべてが勝ち負けではなくって、何かを達成するために、成果が出るために、誰かを喜ばせるために、そういう類いのことのために、ときには大変なことをするというのもまた、良いものじゃあないかとボカァ思うわけである。

「ポジティブは意思」の話は、自分でしておきながら忘れていたが、やはり良い話だった。
ここで言う「ポジティブ」は「なにごとも前向きに考えよう」といったことではなく、悲観的に捉えなくても良いよねくらいのニュアンスなんだけど、うまく言語化ができていない。言語化したい〜。語弊が生まれそうではあるがやはり「楽観的」のほうに近いのかもしれない。

小さいところからで良い、意識して意思を持ちたいものである。
Podcast内でも自分で言っているが、意識的にポジティブであろうとするのは、案外きついものでもあったりする。それでも僕は、ポジティブな自分でありたいし、周りもポジティブになればなお良いと思う。正のループを回していこうな。
よく話に頷いたり、よく笑ったり、言葉に出して褒めたり、そんなんでよい。ポジティブは細部に宿る。(言いたいだけ)

流川の「今日もあれやりましょーよ、オレたちはってやつ」ってセリフを思い出す。ポジティブなチームは強い。

「ポジティブは意思」の話をしようと思ったキッカケの投稿はこちら。↓

youtrust.jp

 

 

いやはや、スラムダンクの映画が楽しみで仕方ない。

書くことに対するハードルを下げる話

スタイルは確立できてないけどラフに書く練習をする。スマホでポチポチ書いてるので今風(?)である。

15分以上時間をかけないぞ、と決めたのでトライアタックで挑む。

 

なんでブログを書くハードルが自分の中で高いんだろうと考えてみると、真っ先に「書くネタがないな…」という理由が浮かんでくる。たぶんこれは建前で、本音は「誰かが読みたいであろう内容をカッコつけて書けるほど煮詰まったネタがないな」なんだなと思う。恥ずかしながら…。

ここを取っ払うとガツンとハードルは下がりそう。

 

もともと書き物をすると、文字数が多くなりがちなタイプなので、書くことはどちらかと言えばと言わずに好きなタイプだと思う。ただ、インターネット上でのみ自分を知っている人からすると、書いた内容によって少なからず自分の人柄などを脳内で補完されると考えると、やはりカッコつけたくなるものである。

 

大義名分があれば意外とこういうのを乗り越えられるタイプだと自己分析しているので、自分ハックは可能そう。自分ハック大事だよね。

今日、たまたま仕事の実装で同僚に壁打ちを頼んで話してると、話しながら自分で自己解決する部分があり、話すのって大事だなと再認識するとともに、「思考するには脳みそは狭すぎるな?」という気持ちになった。そしてこの「思考するには脳みそは狭すぎる」という考え、めっちゃ自分ハックとしては刺さるのであった。

 

きっとここの感覚は人それぞれな気がするが、ブログを壁打ち相手のように使い、脳内の思考を整理するのをやるのは合ってそう。やっていくぞ!

カッコつけたくなる、というのだけは、頭をきっとよぎるけど、整理したいことはたくさんあるので気にせずにやっていきたい。もちろんあわよくば、なにかしらフィードバックが返ってくると最高そうだがそれは考えないようにする。

 

書いてから15分は過ぎててスタートからアレだがこういうのも気にしないのである。書いてるからエライのである。

 

最後に言語化したい脳内で溜まってる話を置いておき、次回以降に繋げる。

  • scrapboxが自分の脳内整理に合ってる話
  • 私の中の、やるべきこと、やりたいこと、できること、の捉え方
  • チームで価値を出すということの私の感じ方
  • モデリングとイラストが似てるって感じた話
  • なぜと課題とドキュメント
  • だれに、なにを、どのように、は使える
  • 雑談レベルで話す新卒に読んで欲しい3冊

 

実はお風呂で書いていて、のぼせてしまいそうなので、以上、はてなブログスマホアプリの書き心地が良くてビックリしている私からでした。