Hi there 👋🏻
Ryo Makiyama
Mobile Software Engineer. Having a blast in engineering! :)
Recent Posts
TypeSafe AI の Jev と遊んだメモ
Jevがもりもりと盛り上がっていたので、波には乗っておけということで触ってみた。 typesafe.ai Jevについての説明や導入方法はここでは割愛。わかりやすい記事がすでにたくさん書かれているのでそちらに任せる。 作ったのはこれ。 github.com ブックマークサービスを Raindrop.io にした矢先だったので、ちょうどよかった。 だいたいこういうのは、あとで読もうと溜めておくんだけど、読まずに眠りがち。 Jevを使って、今読むと良さそうな記事を出してもらうぞ!というのがきっかけ。 Jev basics 最低限の前提として簡単に、Jevへのインプットの話。 state: 判断の材料 questions: 判断したいこと stateのスキーマは自由。テキストでもJsonでも。 questionsは質問形式で。質問の型は3種類だけ。 Type What it answers Returns Choice Which of these options? choice, probabilities, confidence Score Which level? score, legend, probabilities, confidence Noul Is this true? noul (0 to 1) つまり、stateで判断の材料を渡し、questionsに回答をして貰う形。 判断基準の責任は人間が持つ Jevは判断に特化しているモデルということで話題になっていた。正直最初はイメージついてなかった。 触ってみてわかったのは、questionsによって判断基準を明確にできるところが強みでもあり難しいところでもあるなと感じた。 Jevでは「よしなに」ではあまり判断が機能しない。 作った raincheck での試行錯誤を紹介する。 { "relevant": { "type": "noul", // article は recent_work に記述されたプロジェクト・技術・問題に関係しているか? "instructions": "Does `article` bear on the projects, technologies, or problems described in `recent_work`?", "criteria": { // 記事は最近の作業に現れる技術・ツール・設計上の問題・領域を扱っている。 // 本人が「これは自分がやっていることについてだ」と認識するもの。 "true": "The article is about a technology, tool, design problem, or domain that appears in the recent work — the person would recognise it as \"this is about what I am doing\".", // 記事は最近の作業のどれとも無関係、あるいはキーワードを共有するだけで同じことを扱ってはいない。 "false": "The article is off-topic for everything in the recent work, or only shares a keyword without being about the same thing." } } } これだとNoulが0.8 ~ 0.5の間に、良さそうな記事と違うな〜という記事が混ざっていた。 Jevはただこの数値だけを返すので、じゃあしきい値をどこに設定するかなあという「判断」をする必要があった。 あれ、判断いるじゃあないか、って思ったよね。 Noulでの2値で、さらにtrueの説明を『本人が「これは自分がやっていることについてだ」と認識するもの。』と定義していた。 大事だったのは、questionsの設計。questionsが書けないのは、自分がその判断を言語化できていないから。と理解した。 改善としてNoulをやめて、Scoreにしてみた。 軸1: 記事の主題と、最近の作業が近いか 軸2: 記事を読んで、最近の作業に変化があるか { "distance": { "type": "score", // article の主題は、recent_work に示される本人が現在取り組んでいること・考えていることにどれだけ近いか? "instructions": "How close is the main subject of `article` to what the person is currently working on or thinking through, as shown in `recent_work`?", "criteria": [ // 接点なし:記事の主題は、本人が取り組んでいること・考えていることと無関係。せいぜい単語を共有するだけ。 "No contact: the article's subject has nothing to do with what the person is working on or thinking through; at most they share a word.", // 触れている:記事の主題は別のもので、本人が取り組んでいることには触れるだけ。 // あるいは同種の問いを、異なる対象やアプローチで扱っている。 "Touches it: the article's main subject is something else and only touches on what the person is working on; or it treats the same kind of question with a different object or approach.", // 主題そのもの:記事の主題は、本人が取り組んでいること・考えていることそのもの。 // それが技術であれ、仕事の進め方であれ、設計やプロダクトに関する問いであれ。 "The subject itself: the article's main subject is the very thing the person is working on or thinking through, whether that is a technology, a way of working, or a question about a design or a product." ] }, "effect": { "type": "score", // article を読んだ後、recent_work に示される本人が現在していることはどう変わるか? "instructions": "After reading `article`, how would what the person is currently doing, as shown in `recent_work`, change?", "criteria": [ // 変わらない:本人がすでにしていることを確認するだけ。一般的な背景知識・意見・ニュース。 // あるいは本人が直面している選択に関わらない概説やプラクティス一覧。 "Not at all: it confirms what the person already does; it is general background, opinion, or news; or it is an overview or a list of practices that does not bear on a choice the person is facing.", // 選択の材料になる:本人が今直面している選択——何を使うか、どう作るか、どう進めるか、 // 何を作るか——にまさに関わる選択肢・落とし穴・比較を与える。 "A choice is informed: it gives options, pitfalls, or a comparison that bear specifically on a choice the person is facing now — what to use, how to build something, how to proceed, what to make.", // そのまま適用できる:本人が今していることに直接適用できる、具体的な方法・決定・手順を与える。 "Applied as is: it gives a concrete method, decision, or procedure the person can apply directly to what they are doing now." ] } } Scoreの各項目についても、より具体的に書いている。 Jevの判断がいまいちだなと思ったときは、その判断基準がいまいちということ。 判断できる状態の材料の用意する 判断基準のquestionsに触れたが、stateも大事。 いらない材料があってもブレるし、材料が足りなくても判断できない。 raincheckでは、state を { recent_work, article }の構成にしている。 最初はrecent_workを雑にマークダウンテキストにしていた。 { "recent_work": "# What I have been working on (Claude Code sessions, last 7 days)\n\n## ...", "article": { "title": "...", "summary": "...", "domain": "..." } } TypeSafe のドキュメントを見ると、「state はネストした JSON にし、パスで参照する」というようなことが書いてあった。 recent_work.projects[1]のように参照できるから。 { "recent_work": { "days": 7, "projects": [ { "name": "rmakiyama/raincheck", "branches": ["main"], "sessions": 3, "titles": ["Judge bookmarks with Jev"], "prompts": ["Raindrop のブックマークを…", "閾値を…"] }, { "name": "org/other", "branches": [], "sessions": 1, "titles": [], "prompts": ["..."] } ] }, "article": { "title": "...", "summary": "...", "domain": "..." } } これに合わせて、questionsも動的に生成し、プロジェクト単位で質問するように変えてみたりもした。 正直 raincheck については、stateがかなり雑。そもそも最近の作業をローカルのセッションを切り詰めて持ってくるとしているので、あんまし精度も望めないんだよね。 適用する対象への理解度が出力を左右する 対象の状態をstateに、判断基準をquestionsに、それを適切に定義できるだけの理解度が求められている。 あたりまえだけど、改めてここ認識できたのは良かった気がする。 Jevが進化しても、他のモデルに似た概念が取り込まれても、判断基準を人間が持つことはしばらく変わらないことだろう。たぶんね。
AIと開発をした半年のメモ
AI、特にAI Agentと呼ばれるモノと本格的に開発をはじめてだいたい半年が経った。Androidエンジニアとしてこれまで、Android Studioが出てきたり、Kotlinが正式言語になったり、Jetpack Composeが出たり、AIだとGitHub Copilotが出たり、振り返ると多くの変化があったけど、その中でも群を抜いてインパクトがデカい。パラダイムシフトの中にある。 なかなか…
Agent Skillsと歩むAndroidのUI実装
こんにちは あるいは こんばんは。これは Kyash Advent Calendar 2025 の20日目の記事です。 Androidエンジニアをしている 牧山(@_rmakiyama)です。 最近はもっぱらClaude CodeやCodexといったAIエージェントと戯れる日々を過ごしています。いい時代ですね。Kyashの開発チーム全体としても、こうしたAIツールを開発フローにどう組み込んでいくか、日々模索が続いています。 しかし、モバイルアプリのUI実装の領域においては、なかなか思ったようなアウトプットが出ず、活用が思うようにできていない状態でした。 そこで、どうするとうまく付き合えるのか試行錯誤している途中経過を紹介します。 前提として Android開発におけるUI実装での試行錯誤になります。デザインにはFigmaを使っており、これをClaude CodeからFigma Dev Mode MCPを利用してデザインデータを取得しています。 ただFigma Dev Mode MCPを利用しても、なかなかどうして活用が進みませんでした。 思うようなアウトプットではないとは? 試行錯誤をするにあたり、AIが生成するUI実装のコレジャナイ感について考えてみると、大きく2つの課題がありました。 構造化の欠如 1つの巨大なComposable関数に全てベタ書きされる デザインの意図が構造に現れていない UI実装におけるコンテキストの欠如 Color(0xFF...)やsp直書きなどのマジックナンバー・ハードコードの多用 デザインシステムのコンポーネントの定義の未使用 これらは場合によって周辺のコードを読んで、よしなに適用してくれることもありますが、LLMの非決定性に左右されるためうまく制御できているとは言えません。 最初に試したこと 思ったようなアウトプットを出すには、LLMの決定性を高めることが重要だと感じました。そこでまずは2つのアプローチを試してみました。 UI の構造を先に人間が設計する FigmaのトークンとJetpack ComposeのTheme実装のマッピングをドキュメント化する 1. UI の構造を先に人間が設計する 思ったようなアウトプットに感じないときの原因のひとつの、「構造化の欠如」の検証として、自分で構造だけを先に定義してから残りを実装してもらう実験をしてみました。 未リリースの機能開発をしながらトライをしているので、ここではAIに内容を塗り替えてもらって紹介します。 @Composable fun RecipeDetailSections(...) { Column(...) { RecipeHeader(....) SectionDivider() CookingInfoSummary(...) SectionDivider() IngredientsSection(...) SectionDivider() CookingStepsSection(...) } } @Composable private fun RecipeHeader( recipeName: String, modifier: Modifier = Modifier, ) { TODO() } ... あとは各セクションの中身を実装していくだけなので、かなりお膳立てしている状態ではあります。 プロンプトとしては、なにができないかも見る意味で、詳細な指示は一切せずに投げています。マスクしていますが実際に下記のように依頼しています。 Figmaで選択している画面の実装をしたいです。 今回のスコープは、XXXと部分と、YYYからZZZまでのUIです。実装してください。 結果のスクリーンショットは割愛しますが、いい精度のアウトプットが出てきました。粗はありますが、繰り返しになるスタイリングを避けるために、コンポーネントを作ってくれていたのには感心しましたね。これは周辺のコードをうまく参考にしたようです。 Figmaトークンと実装のマッピングをしていませんでしたが、8割くらいはうまく合わせてくれていました。 想定通りではあるものの、FigmaトークンとマッピングしづらいTheme実装や、定義済みのデザインコンポーネントの利用がされていないなどは見受けられたので、これをやるだけでも人間の修正はだいぶ少なく済みそうです。 2. FigmaトークンとTheme実装のマッピングをドキュメント化する 次に、もうひとつの課題であった「UI実装におけるコンテキストの欠如」の検証として、Figmaトークンと実装のマッピングを行いました。 KyashではColorやTypographyなどをKIG (Kyash Interface Guidelines) としてFigmaトークンで用意しており、Androidではこれを実装に落とし込んでいます。詳細は割愛しますが、興味があればこちらもご参照ください。 マッピングをマークダウンファイルとして用意し、プロンプトでファイル参照することで解決を試みました。 実際のドキュメントの一部を抜粋して紹介します。 # KIGテーマシステムリファレンス ## 概要 KIG (Kyash Interface Guidelines) デザイントークンの実装リファレンス。 **アクセス方法:** - Colors: `KyashTheme.colors.primary` - Typography: `KyashTheme.typography.body` - Spacing: `KyashTheme.spacing.m` - Shapes: `KyashTheme.shapes.medium` ## Colors ### Material 系 | Figmaトークン | 実装プロパティ | 値 | |--------------|---------------|-----| | Color/Fill/Primary-Blue | `KyashTheme.colors.primary` | #209FFF | | Color/Fill/Primary-Blue (Light) | `KyashTheme.colors.primaryLight` | #DBF0FF | | Color/Fill/Success-Green | `KyashTheme.colors.secondary` | #00BF9D | ... ... ## Spacing | Figmaトークン | 実装プロパティ | 値 | |--------------|---------------|-----| | SpacingXXXS | `KyashTheme.spacing.xxxs` | 2.dp | | SpacingXXS | `KyashTheme.spacing.xxs` | 4.dp | | SpacingXS | `KyashTheme.spacing.xs` | 8.dp | ... ## Typography | 実装プロパティ | サイズ | 行高 | |---------------|--------|------| | `KyashTheme.typography.largeTitle` | 40sp | 1.5em | | `KyashTheme.typography.title1` | 36sp | 1.5em | | `KyashTheme.typography.title2` | 24sp | 1.5em | ... 今回も同様に、プロンプトは、詳細な指示をせずに投げています。実際のプロンプトは下記のように依頼しています。 @feature/ooo/src/main/java/co/kyash/xxx/yyy/XxxScreen.ktの実装をしてください。 対象の画面デザインは下記です。 https://www.figma.com/design/1234567-xxx @docs/kig_design_token_reference.md を見てThemeを参照するようにしてください。 UIの詳細はSectionsファイルを作り、Sections関数を定義して詳細はそちらに実装してください。 こちらもスクリーンショットを割愛しますが、値をベタ書きすることはなくなり、すべてKIGのTheme実装を使ってくれるという結果になりました。目論見が達成できて嬉しい。今回はTheme実装とのマッピングのみをしましたが、コンポーネント実装の情報も与えると精度向上が期待できそうです。 学び ここまでの試行錯誤を通して、知識やノウハウ、コンテキストを適切に与えると、わりと精度の高いアウトプットが得られることがわかってきました。 しかし、UIの構造を考える部分を委譲できていなかったり、コンテキストが断片的になっていてUI実装自体が体系化されていなかったりと、あまりスケールしない状態でした。 次に、チームでうまくワークさせるには、という観点からトライをしてみました。 Agent Skills というアプローチ 最初はClaude CodeのSubagentsを活用することを考えていました。しかし、UIの構造を考えるうえでのノウハウや参考の実装、FigmaトークンとTheme実装のマッピング表などのコンテキストをすべて含めていくと、わりと大きめのSubagentになりそうという感覚がありました。 ちょうどこのころAnthropicがSkillsを発表し、下記の観点からUI実装にも使えそうという判断をしました。 段階的な情報開示による効率的なコンテキスト消費 UI実装というワークフローを専門知識としてパッケージングできる 汎用性をもたせ複数のSubagentsからも利用可能 Agent Skillsの説明については割愛します。これらの記事がとても参考になりました! Agent Skills Equipping agents for the real world with Agent Skills UI実装フローの整理 Skillsを作っていくにあたり、まずは自分がいつもどのようにUI実装をしているかを整理しました。 ざっくりこんな感じのフローです。 ここで、自身が開発するときに1番気を使っているのが「セクションの構造を実装」するフェーズです。「思うようなアウトプットではない」と感じるときも、ここのギャップが1番大きいと感じていました。 フローを整理していくと、UI実装には各フェーズにおいてさまざまな知識やノウハウが詰まっていることに気づきます。どうりでただ「Figmaをもとに実装して。〇〇を参考にして。」くらいのラフなプロンプトでうまくいくほうが珍しい。Skillsを作っていく前にここを自分の中でも洗い出していきました。 知識の言語化の一例 AndroidのUI実装では、Jetpack Composeが使われます。Composeではこう書くよな、よく間違えるよな、学びたてのときはよく悩んだな、というポイントを補足していきます。 たとえば、クリック可能な要素にはModifier#clickableをよく使いますが、これはModifierのチェーンの順序で見た目の結果が変わります。一例ですが下記のような違いがあります。 // paddingを含めた範囲全体がクリック可能 Modifier .fillMaxWidth() .clickable { } .padding(16.dp) // paddingの内側だけがクリック可能 Modifier .fillMaxWidth() .padding(16.dp) .clickable { } そのほかにも、よく知られた知識はいくつもあります。自分はよくAPI Guidelines for @Composable components in Jetpack Composeを参照するのでこれもうまく取り込むことを考えました。 ノウハウの言語化の一例 UI実装を行うとき、どういうことを考えて実装しているかを考えてみました。フローにも示していますが、Figmaを見て、UIの構造を把握して、構造を実装しています。ここの暗黙知を与えてあげると、気になっていた「構造化の欠如」が解決するのではと考えました。 自分が考えていることを整理してみると、大きく5つのポイントを意識していることがわかりました。 デザインの4大原則を適用する 視覚的なまとまりを捉える 責任の分離を意識する(Single Responsibility) 複雑度のバランスを整える 抽象度を揃える(SLAP: Single Level of Abstraction Principle) ただFigmaの見た目だけを表現できるコードを書くのではなく、開発者がコードからUIの構造を把握しやすく、デザインの意図を汲んだ構造にすることで、保守性や変更容易性を高めることを意識しています。 画面のトップレベルの例としては、下記のようなイメージです。 // good Column(...) { ProfileAvatarSection() PersonalInfoCard() SectionDivider() LinkedAccountsSection() SectionDivider() DangerZone() } // good Column(...) { UserIdentitySection() SectionDivider() AccountSettingsSection() } // not good: 上からすべて読まないと理解できない Column(...) { Box(...) { Image(...) Icon(...) } Card(...) { // ... } // ... } // not good: 細かすぎる分割 Column { ProfileImage() EditBadge() UserNameText() NameField() EmailField() PhoneField() GoogleAccountRow() AppleAccountRow() AddAccountButton() LogoutButton() DeleteAccountLink() } Agent Skills 全体の構成 これらをベースに詳細を言語化し、Claude Codeが同じようなフローができるようにステップを組み、それぞれのタイミングで適切な知識を追加できるようなSkillsを目指しました。 スキルのファイル構成はこのようになっています。 figma-to-compose ├── examples │ ├── screen-structure.md │ └── section-grouping.md ├── references │ ├── android-resources.md │ ├── compose-best-practices.md │ ├── kig-components.md │ └── kig-theme-system.md └── SKILL.md 自身のUI実装フローを整理してできたステップごとに、Kyashならではのコンテキストや自身の知識やノウハウ、参考実装などを references や examples として配置しています。これらはオンデマンドでロードされる点がSkillsの良いところですね。 FigmaトークンとTheme実装のマッピングはkig-theme-system.mdとして references に配置しています。セクションわけのノウハウはsection-grouping.mdとしてサンプルコードとともに examples に配置しています。 SKILL.mdは、Claudeの作業に合わせて下記のようなステップに分けています。 ステップごとに、適宜必要な references や examples への参照を示し、適切なタイミングで知識・ノウハウをロードしてもらう構成となります。 試行錯誤ポイントとしては、Claude Codeに依存してしまいますがAskUserQuestionを使うように指示をして、HITL(Human-in-the-Loop)を挟むようにしています。 Skillsのアウトプット 実際に既存の画面の実装を手元で削除して、Skillsを使って作り直してもらいました。 FigmaとJetpack ComposeのPreviewで比較してみます。 Figma アウトプット Preview そこまで複雑ではない画面ですが、かなり精度が高いと言って良さそうです。 この実装中に、セクションのグルーピング提案のフェーズで実際に Claude Code が提案した内容をそのまま紹介します。 LoanTopScreenのセクショングルーピングとして、以下のどちらが適切ですか? **オプション1: 細かめのセクション分割** \```kotlin @Composable fun LoanTopSections( state: LoanTopReactor.State, onApplyClick: () -> Unit, onUsageHistoryClick: () -> Unit, onNextRepaymentDetailClick: () -> Unit, onEarlyRepaymentInfoClick: () -> Unit, onEarlyRepaymentClick: () -> Unit, modifier: Modifier = Modifier, ) { Column(modifier = modifier) { // 上部: 入金可能額 + ボタン BorrowableAmountSection( borrowableAmount = state.displayBorrowableAmount, applyEnabled = state.applyEnabled, onApplyClick = onApplyClick, ) // カード: 利用額 + 次回支払い UsageAndRepaymentCard( borrowingAmount = state.displayBorrowingAmount, nextRepaymentInfo = state.nextRepaymentInfo, onUsageHistoryClick = onUsageHistoryClick, onNextRepaymentDetailClick = onNextRepaymentDetailClick, ) // カード: 繰り上げ返済 if (state.shouldShowEarlyRepayment) { EarlyRepaymentCard( onInfoClick = onEarlyRepaymentInfoClick, onClick = onEarlyRepaymentClick, ) } } } \``` **オプション2: よりシンプルな分割** \```kotlin @Composable fun LoanTopSections( state: LoanTopReactor.State, onApplyClick: () -> Unit, onUsageHistoryClick: () -> Unit, onNextRepaymentDetailClick: () -> Unit, onEarlyRepaymentInfoClick: () -> Unit, onEarlyRepaymentClick: () -> Unit, modifier: Modifier = Modifier, ) { Column(modifier = modifier) { // 上部パート UpperSection( borrowableAmount = state.displayBorrowableAmount, applyEnabled = state.applyEnabled, onApplyClick = onApplyClick, ) // 下部パート(カード群) LowerSection( borrowingAmount = state.displayBorrowingAmount, nextRepaymentInfo = state.nextRepaymentInfo, shouldShowEarlyRepayment = state.shouldShowEarlyRepayment, onUsageHistoryClick = onUsageHistoryClick, onNextRepaymentDetailClick = onNextRepaymentDetailClick, onEarlyRepaymentInfoClick = onEarlyRepaymentInfoClick, onEarlyRepaymentClick = onEarlyRepaymentClick, ) } } \``` このSkillsを使ってみると、HITLがいい味を出していて、コードの構造を先にチェックできるのがとても良い。UpperSectionなど命名としてもうちょっと考慮必要だな、というような改善は見えますが、ここはのびしろですね。 コンポーネント単位で修正ができる体験がとても良かったです。 これから 現時点では個人の試行錯誤に目処をつけ、チームに共有をして使っていこう!というフェーズです。 悪くないアウトプットは出ていますが、まだまだのびしろはあると考えています。 Skillsのブラッシュアップ 知識・ノウハウの補填 適切な自由度があるか 適切なガードレールがあるか デザイナーとの連携 Claude Codeに依存しすぎない設計 Skillsの粒度の検討 今回は一気通貫型でトライ スキルとして切り出して汎用性を高めることも検討 LLMに委譲するラインを見極める 完璧なUIを実装させることを目指さない (今はまだ)人間がやったほうがうまくいく作業もある すべてをAIに任せるんだ!ではなく、どううまく業務に溶け込ませられるかを探っていきたいです。 仲間を募集しています! Kyashでは一緒に最高のプロダクト、最高の組織にしていくぞ!という仲間を募集しています 🙌🏻 求人一覧はこちらから 🙋🏻♂️
抽象化とイラスト
ソフトウェア開発は現実のモノゴトを抽象化する作業だなと思っている。 たとえばユーザーというモノをソフトウェアで表すとき、それぞれのソフトウェアで必要なプロパティしか定義しない。すべてのソフトウェアで血液型が必要とは限らないし、脳のシワの数なんてきっとほぼどんなソフトウェアでも不要なはず。(絶対なんて言えない) だからこそ対象領域の理解が必要になる。扱うモノゴトがどういう概念か理解しないことには抽象…
梨を買った
同僚が梨を農園で買ったという話を聞いて、くだものをスーパー以外で買うという選択肢を初めて自分の中で得た。翌日である。 好きなクリエイターの個展に行くとか、好きなイラストレーターの原画を買うとか、コース料理にアルコールペアリングを頼むとか、なんだか大人になったなと自分で感じられることをするのって、なんだか大人っぽいじゃないですか。 農園でくだものを買う、大人っぽい。 今回は梨園が近くにあったので、さ…
娘、3ヶ月
はやいことで8/5で娘が3ヶ月になる。こんなだったな〜と思い出せるようにラフにつらつらる。 だいたいのタイムスケジュールは新生児のころと変わっていない。沐浴を卒業して、夫婦日替わりで一緒にお風呂してるくらいかな。 ただ、娘、乳児の成長のはやいことはやいこと。タイミングしだいでミルクは200mlも飲んじゃう。退院してきたときは50mlくらいを小さな哺乳瓶であげてたのに、あれよあれよと4倍か。いまでは…
娘
5/5に第一子が産まれた。かわいいかわいい娘が産まれた。 3ヶ月の育休をもらっているんだけど、もう2ヶ月が経った、一瞬である。覚えていることは記録しておかねばなるまい。 出産の日には希望通り立ち合いができた。調べると、立ち合いについては色んなエピソードが世の中転がっているけど、千差万別。とにかく妻を支えるのみという気持ちだけ持っていくことにしていた。当日は猫の毛が少しついていた。 実際に病院に呼ば…
UI State設計とテスト方針

EM1年生の振り返り
これは Kyash Advent Calendar 2024 の17日目の記事です、こんにちは あるいは こんばんは。KyashでEngineering Managerをしている 牧山(@_rmakiyama)です。 2024年1月からEMのロールとなり、気づけばまるっと1年が経とうとしています。キャリアの中でEMを担うのは初めてです。 RPGのように、ロールが変わるとステータスに変化があるような世界ではありません。 唯一の正解のないEMというロールに対し、とあるEMのセーブデータを覗いてもらえるよう、徒然なるままに振り返りを残しておこうと思います。 どういう経緯でEMに? 私は2022年の10月に、AndroidエンジニアとしてKyashにジョインしました。 前任のEMの卒業を機に、一時的にEMが不在の時期がありました。その当時モバイルメンバーは6名(iOS、 Androidともに3名)かつ、それぞれが自律して動けることもあり、個人的にもそこまで大きな課題感はなかったように思っています。 実際にVPoEのこにふぁーさんが用意してくれたdocsの一部 ドキュメントではさらに、『なぜmakiyama=sanにお願いしたいか』『何をお願いしたいか』など、明確な期待をセットで伝えていただけました。これは【前編】評価、1on1だけやってていいの? こにふぁーさん、あらたまさんに聞く EMが担うべき役割とは #EMの役割や役割をお願いする時に伝えていることでも触れられているとおりですね。実際、受ける側としてとてもありがたかったです。 エスの回答をしました。 まずなにをやったのか なにはともあれ、自分が何をやっていくのかということを整理しました。 エンジニアリングマネージャーのしごと』をガッと一読して全体像を掴み、『エンジニアリングマネージャ/プロダクトマネージャのための知識体系と読書ガイド』で少し具体な項目のインデックスを増やし、いろんな記事や登壇資料を読み漁りました。知らないことだらけの扉が開いてしまったという感じでしたね。最近はEMというロールも認知度が高まり、コミュニティの熱量も高いので、たくさん知見がインターネット上にあって良いですね。 EMのアウトプットについて『エンジニアリングマネージャーのしごと』では、下記のように定義しています。(あなた = マネージャー自身) マネージャーのアウトプット = あなたのチームのアウトプット + あなたが影響を与えた他のチームのアウトプット そこで私のミッションとしては、マネジメントするチームのアウトプットの最大化としました。ここでのチームはモバイルです。 さてミッションは決まれどこれはだいぶ抽象的です。よし具体を考えるぞ、という中で、私がEMを担うタイミングでモバイルチームに大きな課題は認識していませんでした。(もちろん小さな課題や、やりたいことなどはある)とはいえこれはあくまで自分がメンバーという視点での話になります。 1on1 自分がメンバーとしての1on1はやっていましたが、マネージャーの立場として1on1をするのは初めてです。そこでまずは、教科書の『エンジニアリングマネージャーのしごと』に記載があるコントラクティングを素直にそのままやってみることに決め、最初の1on1のアジェンダとして下記の準備をしました。 当時は特に問いのスキルも低くてうまくいった感覚は正直ありませんが、期待値のすり合わせという意味では、やってよかったなという感覚があります。期待値のすり合わせは自分がメンバーとして1on1をするうえでも大事にしているところなので丁寧にやることを意識しました。 そこからは定期的な1on1ですね。1on1を通して課題を見極めるぞ、というスタンスでいましたが、実際にはメンバーそれぞれが自身で課題あるいはモヤりを見つけてくれているので、どちらかというと壁打ち相手になることがメインになっているなと感じています。私がひとりで見極めをしなければということはなかったわけです。ここは発見でもあり、メンバーにはいつも感謝しているところです。 実行してもらううえで大事にしているのは、メンバーに気持ちよくファーストペンギンになってもらうこと、自分はセカンドペンギンとしてファーストフォロワーになることです。 プレイングとの割合 私もいわゆるプレイングマネージャーです。よくプレイングとマネジメントの割合や向き合い方についての話を目にするので私の考えと実態についても振り返ってみます。前提として、プレイングの割合についても決定を委譲されていました。 EMを担うタイミングで、私のチームはAndroid 1名(私)/ iOS 1名のチームでした。その後チームが統合され、Android / iOS 2名ずつのチームになりました。チームとして取り組む内容としても、私は1人のプレイヤーとしての動きも期待されていました。 この1年を振り返ると、70%くらいはプレイングに割いていたように思います(今さらだけど割合で表すの難しい)。それも下記のような背景からでした。 今は、EMに専念しないと解決できない課題がない 1on1で出てきた課題に応じて柔軟に変えたらいい 具体の実行は頼れるメンバーがいる 立ち返るとミッションはマネジメントするチームのアウトプットの最大化です。これを実現するために、どういう振る舞いをすればよいか、なので、どういう割合にすべきという答えはありません。割合で考える必要がないんじゃないかなとも思っています。 1年経った今は、改めて目線を中長期まで向けたうえで取り組むべき課題はないかを考える時期になってきたように思います。採用もやっていきますからね。やっていくぞ! マネジメント範囲の変化 7月から組織変更があり事業部制が取られるようになりました。 toC領域の事業部のエンジニアに変化しています。内訳としては、モバイルが3名、バックエンド+QAが3名となり、自身の職能であるモバイル以外のエンジニアもマネジメントすることになりました。 職能チームのマネージャーから、フィーチャーチームのマネージャーになったわけですが、どちらも良し悪しあるな〜という所感です。 職能チームのマネージャーは、スキルセットがかなり活きてくるので、技術課題の場合は解像度も高めやすく、壁打ちもラクです。もちろん評価という側面でもやりやすい。とはいえ、私の場合はメンバーのスキルも高く、技術的な側面で支援することはあまりありませんでした。どちらかというと、自身(メンバー)のチームやプロジェクトの進め方についての相談が多く、私が所属しないチームの細かい課題のニュアンスを汲み取るのは難しくて、少しもどかしさを感じていたりしました。それでもことが前に進んだのは、オーナーシップを持って実行を進めてくれるメンバーだったからだなと感謝しています。 フィーチャーチームのマネージャーは、私とメンバーが同じ事業部として持つ目標が同じなので、そこの目線が揃っている部分はとてもやりやすいなと感じています。この変化の前は、自分の専門じゃない技術領域のメンバーのマネジメントに多少なりとも不安はありましたが、モバイルチーム同様、技術的な話よりもチームやプロジェクトの進め方についてよく話しています。ここはファーストフォロワーにもなりやすいですね。 1年の間にこの変化があったのは良い経験でした。どちらにせよ、どこを頼り、どこをサポートするかの違いだなと今は思っています。 振り返ってどうだった? いろいろと振り返ってみましたが、正直、EMとしてうまくいったという実感はありません。そもそもEMとしてうまくいくとはどういうことか、という解像度がまだ低いのかも知れません。 それでも、モバイルチームとしては1年前より成熟してきたように感じますし、事業部としてもこの半年で多くのトライをやってきて、こちらも成熟してきていると感じています。ここは救いですね、メンバーには本当に感謝です。 最初に戻りますが、EMというロールになったからといって突然ステータスに変化があるわけではありません。これは2年目も然りです。別の見方をすると、その後もしロールが変わったとしても、この経験値は必ず活きてくるという感覚もあります。ロールが変わってもレベル1に戻らないわけです。今は愚直にEMとしての経験値をためていきたいと思います。レベルアップしていくぞ! さてさてKyashでは一緒に最高のプロダクト、最高の組織にしていくぞ!という仲間を募集しています 🙌🏻ちょっとでも興味がある、そんな人は、面識あるなしにかかわらずせび気軽にお話しましょう! 求人一覧はこちらから 🙋🏻♂️ herp.careers
リリーストレインの軌跡
これは Kyash Advent Calendar 2024 の2日目の記事です、こんにちは あるいは こんばんは。Kyashでエンジニアリングマネージャーをしている 牧山(@_rmakiyama)です。 さて、昨年に続きですが、私は3つあるKyashのValue(行動指針)の中でも『動いて風を知る』がとても好きです。社内でもよく会話やSlackのemojiで飛び交うValueでもあり、自然とみんなの行動や意思決定に表れているなと感じています。 プロダクト開発チームでも、このValueを体現するように、初夏からリリーストレインを導入しました。少しずつですが開発にリズムが出てきたように感じています。 今回は、リリーストレインを導入するに至った背景と現在地について紹介します。 課題 2024年の始め、プロダクト開発チームは3つのチーム(現在は2つ)に分かれていました。チームによって責務とする領域やそれぞれの施策内容、開発の進め方が異なっており、それぞれのタイミングでリリーススケジュールを組んでいました。 これにより、下記のような課題を抱えていました。 リリースタイミングが被りそうなときのスケジュール調整が頻繁 QAのテスト設計から実施までのアサインが大変 次にリリースされるものを開発チーム全体で把握しにくい 特にスケジュールの調整コストは高く、リリースに向けたブランチ戦略 / QA / リリース作業も煩雑化していました。 また、QAチームのリソースは限られており、ある機能を優先させるために他の機能のテスト設計が遅れることもあり、複数のチームで並列して開発を進めていても、デリバリーが直列に近い状態となる時期もありました。 リリーストレインという選択肢 これらの課題を解決するための1つの選択肢として、リリーストレインの導入を進めました。 リリーストレイン自体の概要や目的などはここでは割愛します。捉え方は一つではないですが、特にSAFe(Scaled Agile Framework)のアジャイルリリーストレインの考えを参考にしています。 Kyashとしてのリリーストレインの目的は下記の2点に定めました。 複数チーム間のリリース前の調整 / コミュニケーションコストを減らす アジリティ高くプロダクトの価値をデリバリーしフィードバックサイクルを早める 導入にあたって大事にしたことは、『リリーストレインを忠実に守ること』が目的にならないようにすることです。ここが抜けてしまうと、「トレインに乗りそびれたら2週間後(次のトレイン)になることで価値提供が遅れてしまうのではないか」という逆行した感覚に陥ってしまう懸念があったため、それ自体が目的にならないことを強く意識していました。 ここの認識がずれないよう、エンジニアだけでことを始めるのではなく、PdMやQAチームと今の課題やリリーストレインの目的の認識合わせも行っています。 これにより、いくつかの懸念は出てきたものの、「うし、やってみっか」という温度感に揃えてからのスタートを切ることが出来ました、懸念についても、実際にトライしてみないと実態がわからないよねというものも多く、ここが事前にすり合ったのも良かった点です。 最初に行ったトレインの設計 リリースサイクルを2週間と定め、下記のプロセスで実施を開始しました。 1週目 月曜: POがトレイン乗車判断をする 水曜: QA用アプリ配布 木曜: 機能テスト開始 2週目 火曜: 機能テスト完了 水曜: リグレッションテスト開始 金曜: リグレッションテスト完了 / サブミット 翌週月曜日にリリース 🚀 POが次のトレインのリリース判断(1週目に戻る) 簡単な概略としては図のようなイメージです。 Kyashは事業の性質上、機能によっては仕様承認やリリース承認といった、いくつかのプロセスが用意されています。トレインとしてもリリースプロセス全体に合わせて設計することも考えましたが、まずはシンプルな形でスタートして、必要に応じてプロセスを追加することにしました。 探索と適応 やってみなければうまくいくかわからないという不確実性を許容してスタートしたリリーストレインですが、やっていくなかでいくつかの課題を見つけることが出来ました。 そこでチーム間で話し合い、下記のような決定をしました。 現在のトレインの設計 今では下記のようなプロセスとなっています。 1週目 各事業部開発 事業部ごとに機能テストを開始 2週目 水曜まで: 機能テスト完了 木曜: リグレッションテスト開始 金曜: リグレッションテスト完了 / サブミット 翌週月曜日にリリース 🚀 (1週目に戻る) 最初とさほど変わっていないようにも見えますが、各チームがより自律して動けるように余白を増やすことで、スケジュールによる価値提供の損失を防ぎやすくなりました。 リリーストレインで得たもの だいたい半年ほど変化を加えながら運用してきましたが、動いて風を知るという意味でもよいスタートが切れたのではないかと感じています。チームとしても下記のような効果を実感しています。 定期的・継続的にユーザーに価値を届けられている 時間以外の観点のトレードオフが議論されやすくなった 開発にリズムが生まれる リリーストレインから得たものではありませんが、少しずつリリーストレインに対する改善も職種問わず起きるようになっています。 直近だと、リリースのたびにSlackで作成しているリリースチャンネルに、Zapierを使って最初にすべきことを自動で投稿するようPdMがシュッと作ってくれて、確認漏れを防ぐことに一役買っています。 最初の課題感にあった、コミュニケーションコストですが、リグレッションテストの開始タイミングのすり合わせなどは引き続きあるものの、開始以前よりは認知不可含めだいぶ改善されています。 おわりに リリーストレインも走り始めたばかりで、まだまだ伸びしろがあると感じています。なんとなく効果を感じているものの、数値的な効果検証などは取れていないため、せっかくだし取りたいよねという話も出ていたりします。 ストレインはすべてのチーム・すべてのフェーズに適合するような手段ではありません。今のKyashの開発チームには、一定の効果が得られていますが、組織やフェーズが変わったときに同じように効果が出るとは限りません。 ストレイン自体ではなく、プロダクトの価値をユーザーに早く届けることであるという視点で、引き続き改善を続けていこうと思っています。 今回はリリーストレインの取り組みについて簡単に紹介しました。この他にも、ユーザーに爆速で価値提供できるようにまだまだトライしていきたいことばかりです! ストレインなどの取り組みについてもっと聞きたい、他にどんな課題を持っているのか聞きたい、ちょっとでも興味がある、そんな人は、面識あるなしにかかわらずせび気軽にお話しましょう!記事の内容にかかわらず、モバイルチームの話も大歓迎です! Kyashで一緒に、新しいお金の文化を創りましょう🙌🏻