メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

iOS開発者が見たDroidKaigi 2025——AIが当たり前になった日

こんにちは。メドピアでモバイルアプリエンジニアをしている王です。

今年は同僚2人と一緒に「DroidKaigi 2025」に参加してきました。会場では、AIの存在感が一段と増し、開発の進め方やスマホの中で動く賢い仕組み(オンデバイスAI)、複数OSでのアプリ開発、テストのやり方まで、さまざまな領域が前に進んでいるのを実感しました。

ふだんはiOSを中心に開発している私ですが、Androidのこれからには大きな伸びしろがある——そんな手応えを強く感じるイベントでした。

具体的なセッションの紹介は、同僚の佐藤がこちらの記事に詳しくまとめています

https://tech.medpeer.co.jp/entry/2025/09/16/123000)。

よろしければ合わせてご覧ください。 本稿では、iOS開発者の視点から「AI」と「マルチプラットフォーム開発(KMP/CMP)」に焦点を当て、DroidKaigi 2025で得た学びを整理します。

まずはAIについて。 従来のChatGPT、GitHub Copilot、Geminiに加え、今年はClaude Codeを選ぶ場面が目に見えて増えました。さらに、Android向けの開発支援ツールであるKoogComposeFlowが登場し、モバイル特化の"使えるAIツール"が実務に入ってきた印象です。

また、オンデバイスAIの代表例であるGemini Nanoのように、端末内で完結して動く仕組みも存在感を増しています。通信に頼りにくい場面でも素早く応答でき、プライバシー面でも有利です。

一方で、Apple側ではXcode 26が2025年9月16日にリリースされ、Coding Assistantが搭載されました。現時点ではChatGPTやClaude codeとの連携が中心で、Apple独自のAI体験はこれからに期待——という受け止めです。良い道具は早く取り入れて回す、という姿勢が以前にも増して大切になってきたと感じます。

次に、複数OSでの開発について。 ここ数年で「どちらか一方に寄せる」か「完全に別々に作る」かという二者択一ではなく、現実的な折り合いの付け方が広がってきました。たとえばKotlin Multiplatform(KMP)は、iOSとAndroidのあいだで"アプリの土台となるロジックやデータ処理"を共通化するための技術です。

さらにCompose Multiplatform(CMP)を使えば、一部の画面を共通化することも可能になってきました。ただし見た目や操作感には各OSの文化があります。そこは無理に揃えず、それぞれに合わせて仕上げる——この"いいとこ取り"がいまの主流だと感じます。

弊社プロダクトClinPeerは、いまは iOS が Swift、Android は Kotlin のネイティブで開発しています。KMP/CMP を“使う”と決めたわけではありませんが、まずは API やキャッシュ、データモデルなどの「裏側の共通化」で小さく PoC を試し、数値で効果を見極めたいと考えています。手応えがあれば、一覧・詳細・ブックマークといったシンプルな画面から CMP の適用を段階的に検討し、必要に応じていつでも戻せるようにしておきます。いきなり全部は変えず、良い結果だけを丁寧に積み上げていきます。

最後に少し個人的な話を。 モバイル開発の面白さは、深い技術に向き合うことと、使い心地を磨くことの両方に関われる点にあります。アプリを出すとすぐに反応が返ってきて、ユーザーの声を聞きながら素早く改善できる。この"手触りのあるものづくり"は、AIやマルチプラットフォームの進化によって、これからさらに面白くなるはずです。

イベントで得た学びは、私たちの開発にもすぐ生かしていきます。オンデバイスとクラウドのAIを場面に応じて使い分け、iOSとAndroidの"賢い共同制作"を小さく始める。日々の使い勝手を静かに、でも確実に良くしていきます。

もし今回の内容にご興味があれば、ぜひお気軽に声をかけてください。情報交換や共同での検証など、ご一緒できたらうれしいです。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

DroidKaigi 2025に参加してきました!

はじめに

こんにちは!メドピアにてモバイルアプリエンジニアをしている佐藤です。
今年のDroidKaigiには総勢3名のモバイルアプリエンジニアがオフラインにて参加しました。
実際に足を運んだセッションの中でも特に印象に残ったセッションをご紹介します。

UIだけじゃないComposeの可能性 ━ 宣言的に奏でるメロディ

usuiatさんによるセッションです。

youtu.be

composeがUIを表示するまでの仕組みを体系的に学ぶことができ、runtimeの可能性を感じることが出来ました!
特に何気なく普段から活用しているComposable関数ですが、Composable関数を呼び出した際のReusableComposeNodeがどのように動作するのか知れてとても面白く、オーディオブロックダイアグラムをComposable関数で表現する件にはこんなアプローチがあるのかと「ほえ〜」と感嘆しました。
音声処理ライブラリの解説の中でところどころ流れる音声も良い感じでしたので、YouTubeの動画での視聴がおすすめです!
開発する中での手札が明確に増えたと思える非常に勉強になったセッションでした。

はじめてのMaterial3 Expressive

chukaさんによるセッションです。

youtu.be

Material3 ExpressiveのComponentを実際のコードを交え紹介していただき、今自分が関わってるアプリならこのComponentを採用したら良さそうだな🤔と頭の中で考えながら聞いていました。
普段使いするようなLoadingindicatorやButtonsはすぐにでも差し替えを検討したいと思えましたし、SearchAppBarやFABmenuなどは知っておくだけでもUIの表現手段の一つとして検討余地の高いものなので知ることが出来て良かったです。
新機能開発におけるデザイン検討時などに定期的に見返したくなる素晴らしいセッションでした。

デザイナーがAndroidエンジニアに挑戦してみた

Kanon Fujitaさんによるセッションです。

youtu.be

Figmaの設定値とComposable関数における設定の相性の良さや、OOUIとデータクラスの組み合わせのわかりやすさなどはデザイナー視点だとそう思えるのかと聞いてて新鮮でとても面白かったです。
弊社でもデザイナーの方とのコミュニケーションは頻繁に発生するので、「一緒により良く作る」のコミュニケーションは改めて意識していきたいと思えました。
何はともあれAndroid最高!!!!!!!!!

意外と知らない Android と Google Play の世界

Rikako Katayamaさんによるセッションです。

日本市場ならではのGoogle Playの仕様や機能、また日本で先行して改訂されたポリシーがグローバルに展開された事例など、Googleが日本市場において取り組んできた内容を知ることができました。
さらに、Play Consoleの権限設定まわりも日本からのフィードバックをきっかけに改修された部分があるとのことです。
Androidエンジニアにとって切っても切り離せないGoogle Playの舞台裏について話を聞ける、有意義なセッションでした。

Flutterからネイティブへの挑戦と学び - 評価1.6から4.0への道のり

Ryo Kitamuraさん、kentaro fujiiさんによるセッションです。

youtu.be

ネイティブアプリからFlutterなどのクロスプラットフォーム化というのは弊社でもたまに出る話ではあるのですが、Flutterからネイティブアプリにリプレイスというのはあまり聞かない話なので、ネイティブアプリへのリプレイスまでの背景を知れて貴重な知見を得られました。
また、チームビルディングの部分では特に心理的安全性を高める取り組みの部分が面白かったです。
心理的安全性の部分はチームへの新規参入される方などが特に感じやすい部分だと思うので、そうした方を対象にしたオフィスアワーなどは実践したら良さそうだなと考えていました。

レビュー周りの取り組みもエンジニアとして定期的に挙がる話題なので聞けて良かったです。
コードレビューは知恵比べや技術力を誇示したりクイズ大会をする場ではない、まさにその通りですね!コードレビューは共同作業であるという意識を改めて高めることが出来ました。

「どこから読む?」コードとカルチャーに最速で馴染むための実践ガイド〜新メンバーを活躍に導くオンボーディング戦略〜

richako (risako070310)さんによるセッションです。

youtu.be

弊社では複数サービスを展開しているということもあり携わるサービスが変わるというのはちょくちょくある話でもあるので、なるほどなーとなる頷きの多いセッションでした。
特に良いと思ったのはドキュメント更新を文化と仕組みにするという部分です。
一番ドキュメントを必要としていて真剣に読むユーザーがメンテナーとなり、そしてオンボーディングの最終タスクとしてオンボーディングドキュメントを組み込むことで継続的にドキュメントが成長していく仕組みとする。
新メンバーがメンテナーになる文化、素晴らしいと思いました!

スマホ新法って何?12月施行?アプリビジネスに影響あるの?

健太 鈴木さんによるセッションです。

youtu.be

公正取引委員会の方のセッションをエンジニアイベントで聞く機会があるとは思っていませんでした笑
2025年12月18日に施工されるスマホ新法に関わる話です。
事業者目線で言うとスマホ新法の規制対象になるにはまず月間平均利用者数が4000万人以上になる必要があるとのことでしたので、
「公正取引委員会恐ろしい!!!」
「スマホ新法鬱陶しい!!!」
と思う為にはまずはそこまで利用者数を増やす必要がありそうです笑
開発者目線だと新しいアプリストアの登場やOS機能の利用可能性の向上が見込まれる変化としてあるとのことでしたので、そうした変化におけるキャッチアップや対応が楽しみだなと思いました。

法律に関するお堅い内容と見せかけてスピーカーである健太 鈴木さんのユーモアがすごく、公正取引委員会のマスコットキャラクターのパーカーが税金ではなく自腹という件では会場が笑いに包まれていました笑
私が今年参加したセッションの中では一番参加者が多くDroidKaigi2025のYouTubeで最も再生されている(2025年9月16日の記事公開時点)人気セッションでしたので、楽しみながらスマホ新法に関する理解を深められる素晴らしいセッションです。

OAuthを正しく実装する:Androidアプリのためのセキュアな認証

Chrystian Vieyra Cortesさんによるセッションです。

youtu.be

Oauth2.0認証を用いてモバイルアプリにログイン機能を実装する際に外部ブラウザにするか?WebViewにするか?といったことや、トークンの保存における暗号化について触れられていました。
ログイン機能を実装する際、外部ブラウザにするかWebViewにするかについてはよく議論に上がる部分かと思うので検討の際の参考になると思います。

また、トークンを共有設定保存した場合、ルート化しない限りは読み取り抽出する方法はないので暗号化せずに共有設定に保存するの下りの部分は特に面白かったです。
最近ログイン回りを実装した際にはとりあえず思考停止で暗号化してdatastoreに保存するようにしていたので、そういった考え方もあるのかと非常に興味深い内容でした。
ただトークンの暗号化についてはChrystian Vieyra Cortesさんも議論の余地のある見解と仰られていた通り人によって考え方が違う部分だと思いますので、よく検討した上で実装していきたいですね。

Cache Me If You Can

RyuNen344さんによるセッションです。

youtu.be

個人的に今年のDroidKaigiで一番におすすめのセッションです。
AGPやGradleについては何となくの理解で、Gradle周りの記述も公式に実装方法や説明が記載されているなどAGPやGradleのライフサイクルを意識したことはなかったのですが、内部ではこんな風に動いていたのかと非常に勉強になりました。
ConfigurationCacheを有効にする際も、しっかりと仕組みを理解して実装するのとしないのではキャッシュによる恩恵の受け方が大きく変わると思います。
これだけまとめられて濃密な内容が40分程の動画で無料で視聴出来てしまうのには感謝しかありません。

EncryptedSharedPreferences が deprecated になっちゃった!どうしよう!

Yuki Anzaiさんによるセッションです。

youtu.be

ちょうど1年ぐらい前にトークン保存における暗号化の際EncryptedSharedPreferencesがdeprecatedになっており対応をどうしようと頭を悩ませていたのでとても共感出来る内容でした。
deprecatedになった原因のクラッシュも過去に経験して頭を悩ませたことのある問題で普通に実装してると発生してしまいがちの内容だと思いますので、暗号化して内部に保存する際の実装方法を検討する際には非常におすすめのセッションです。
ちなみにクラッシュが発生した際はこのセッションでも触れられているバックアップ設定と例外をキャッシュして対応するようにしました。

暗号化した内容の保存については前述したChrystian Vieyra Cortesさんのセッションでも触れられているので、合わせての視聴がおすすめです。
Chrystian Vieyra Cortesさんの見解然り、Yuki Anzaiさんも思想的転換の章でOSの保護を信じて余計な暗号化はしないとありましたので、暗号化周りについては考えさせられることが多いDroidKaigiでした。

ブース、懇親会

セッション以外にも、ブース巡りや懇親会を大いに楽しむことができました。
特に印象に残ったのは、pixivさんとメルカリさんの企画です。

pixivさんのブースでは「pixiv Q」というアプリをBitrise経由で実際にインストールでき、アプリ内でAndroid開発にまつわるクイズを楽しむことができました。時間帯によって出題されるクイズの内容が変わる仕組みになっており、さまざまな問題に挑戦できたのが面白かったです。

メルカリさんのブースでは「プロンプトゴルフ」という企画が行われており、できるだけ短いプロンプトで課題となる機能を実現することに挑戦できました。アンケートフォームからプロンプトを入力・送信すると、Claude Code GitHub Actionsが連携して実行され、その場で結果を確認できる仕組みです。
企画自体を楽しめたのはもちろんですが、メルカリさんとしても多くの参加者が入力したプロンプトを通じて知見を得られる点も羨ましいなーと思いました。

弊社では「AIファーストカンパニー」を掲げていることもあり、メルカリさんのAIエージェントを活用したこの企画にはとても刺激を受けました。

style.medpeer.co.jp

懇親会では食事や雑談もちろんのこと、Android開発にまつわる情報交換と様々な話題を楽しめました!
弊社からDroidKaigiに参戦したメンバーの都合がつかず、私一人での参加だったということもあり色々な席にお邪魔させていただいたのですが、その中でも特にドワンゴさんとLINEヤフーさんの方とはAI周りの活用事例や最近注目している技術などの話題で長時間に渡り交流をさせていただき、この場を借りて心から感謝申し上げます。

最後に

今年のDroidKaigiもセッション、ブース、懇親会と楽しみつつも学びの多い有意義な大会でした。
毎年ブース巡りをしているとノベルティ等で荷物が溢れて大変になるのですが、今年は最初に大きめのバッグをいただけたこともあり荷物が溢れることもなく、毎年イベントのクオリティがより良くなっていってることを感じます。
このような素敵な大会を提供してくださったDroidKaigi運営の方々・スピーカーの皆様・多くの企業・DroidKaigiに関わるすべての方々に感謝を申し上げます。
また来年も参加できることを楽しみにしております!


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

SREチームで「AIエージェント縛り」をやってみた

はじめに

こんにちは。SREチームの侘美です。
弊社ではLLM(大規模言語モデル)を活用したコーディング、特にDevinやClaude Codeのようなエージェント型ツールを積極活用する方針を打ち立て、各種ツールを利用できる環境を整備しています。 また、習熟やノウハウの獲得のため各チームで一定期間AIエージェント縛りで開発を行い、得られた知見や課題を共有する活動も進めています。

我々SREチームでも2週間にわたってAIエージェント縛りで開発する実証実験を行いました。 本記事では、この実証実験を通じて得られた、通常のプロダクト開発チームとは異なるSREチームならではの課題や知見を共有します。

前置き

弊社SREチームの特徴

  • 5人チーム
  • 5名で社内の全プロダクトを分担して担当
  • 主な業務:
    • AWS/GCP/Azureの構築・メンテナンス
    • GitHubや各種SaaSの管理
    • プロダクトのアラート対応やフォロー
    • データ分析基盤の構築
  • 使用する言語・ツール
    • HCL(Terraform)
    • JavaScript/TypeScript
    • Python
    • etc

利用したAIエージェントツール

  • Claude Code
  • Devin
  • Gemini CLI

AIエージェント縛りに関するルール

  • 手動でのコーディングは原則禁止
    • 障害対応や納期的に厳しいものは例外
  • 任意のAIエージェントツールを利用可能
  • コミットメッセージ、Git操作、PR作成等は人間が実施してOK
  • 週の終わりに振り返り会を実施する(2週で計2回)

AIエージェントの得意領域

メリットや有効に活用できた場面をメンバー内で共有した結果、いずれのメンバーもほぼ同じ結論となっていました。その中で意見が多かったものを以下に記載します。

1. シェルスクリプト生成

全メンバーが一致して評価したのは、シェルスクリプト生成の精度の高さです。

特に以下のような作業で威力を発揮しました。

  • AWS CLI一括処理: RDSメトリクス取得、複数アカウントの管理作業
  • データ分析スクリプト: CloudWatch metricsの統計処理、CDC スループット計算
  • コード生成用スクリプト: removed block一括生成、設定ファイル自動生成

Aurora MySQL から Confluent Cloud への CDC スループット分析という複雑な要件に対し、400行を超える高度なシェルスクリプトを一発で生成することもできました。(手動では2-3時間かかる作業が30分で完成)

2. ドキュメント・PR説明文の生成

文書作成系の作業でも有効に活用できました。

  • プルリクエスト説明文: コミット履歴から適切な説明を自動生成
  • 技術ドキュメント: 実装内容をもとにした分かりやすい手順書作成
  • コミットメッセージ: Conventional Commits準拠の体裁の良いメッセージ

以下のようにClaude Code用のカスタムコマンドを作成してPR説明文生成を自動化するとかなり捗ったと紹介しているメンバーもいました。

---
allowed-tools: Bash(git log:*), Bash(git diff:*), Bash(git fetch -a:*), Bash(cat:*), Bash(pbcopy:*), Read(*.md), Fetch(*)
description: "現在の作業ブランチからプルリクの説明文を作成します。"
---

* この作業ブランチに含まれるコミットとコミットメッセージをまとめて, プルリクエストに記載するdescriptionをmarkdownで作成してください。
  * 作業ブランチとorigin/masterもしくはorigin/mainブランチと比較することで, その作業ブランチに含まれるコミットとコミットメッセージを抽出します。
    * ローカルのorigin/masterもしくはorigin/mainブランチが古い可能性も考慮してgit fetch -aを事前に実行してください。
* descriptionの書式
  * Claude Codeで作成したことがわかりやすいように, description内にClaude Codeの署名を末尾に含めてください。
  * 可読性を上げるために以下の対応を行なってください。
    * またタイトル等で絵文字を多用してぱっと見で見やすい方にしてください。
    * 可能な限り箇条書きとして閲覧しやすくします。
    * 箇条書きにした項目の関連性によって, 適切な範囲で段落を下げてください。
  * 以下の情報は不要なので省略してください。
    * プルリクエストを見るとわかる, 変更ファイルの一覧や統計情報は冗長であるため不要です。
    * GitHub ActionsのCIによってチェックされる項目はdescriptionには不要です。
* 作成完了しましたら, クリップボードに格納してください。
  * 末尾にEOF等のdescriptionとは関係のない文字列が入らないようにしてください。

3. JSON・設定ファイルの編集

構造化データの編集作業においても手作業に比べてかなりの効率化が見られました。

  • Slack通知のJSONペイロード: 複雑な条件分岐やフォーマット調整
  • Lambda関数の軽微な修正: ESM形式への変更、パッケージ設定の調整

4. 小規模の修正を広範囲に実施するケース

大量のファイルに似た小さい修正を行うような作業でも効果的に感じました。

  • アカウント削除: 複数サービスからの特定ユーザー一括削除
  • 設定ファイル更新: 複数環境への同一設定適用
  • リソース名変更: 命名規則に合わせた一括リネーム

AIエージェントの苦手領域・課題

一方でうまく実装できない領域や課題も多く発見されました。 特にこの実証実験前から懸念していた、Terraformなどに代表される宣言的コードとの相性の悪さが浮き彫りになりました。

1. Terraformとの相性の問題

全メンバーが一致して指摘していました。

古いリソース・非推奨属性の提案

  • TerraformのProvider更新が頻繁なためか、AIの精度が低い
  • 推奨されない属性や廃止予定のリソースタイプを提案
  • 最新のベストプラクティスに従わないコード生成
  • MCPを利用してもそこまで改善されない

宣言的コードの特性による非効率性

Terraformなどの宣言的コードでInfrastructure as Codeを実現するケースにおいては、設計が完了すれば後はその設計をそのままコード化するだけなので実装上で悩むシーンはそこまで多くありません。

一方、Ruby等のプログラミング言語でバックエンドサービスを構築する場合、設計が完了した後もメソッドの分割の仕方や同じ処理系でも実装方法が無限にあるなど、詳細設計〜実装〜テストとまだまだ考慮すべき点が山程あります。この工程をAIに行わせることでかなりの生産性向上が見込めます。

そのため「自然言語で作業を指示する」というAIエージェントの利用方法とTerraformの相性の悪さを感じる結果となりました。

学習データ不足

Terraformのコードはそこまで複雑ではないのにもかかわらず、LLMによるコーディングの精度が悪いことは各所で言及されています。

一般的なプログラミング言語はOSSとして質の高いコードがいくつもWeb上で公開されています。 Terraformの場合もAWSが提供する公式モジュール等、良いコードがいくつも公開されています。 ですが私達サービスを構築するSREチームが参考にすべきような、『実際に運用されている大規模サービスのTerraformコード』が公開されている例は多くないと思います。

このように、実用に耐えうるレベルの質の高い学習のためのコード不足がそのまま他の言語と比べて精度が悪いといった結果を引き起こしているのでは?という考察もメンバー内で上がっていました。

2. 指示作成コストの高さ

複雑な要件の言語化が困難

  • 正確な実装を得るために、自然言語でterraformを記述することになる
  • プロンプト作成時間が実装時間を上回るケースが頻発
  • 大きい作業は1プロンプトより細かく小出しに指示した方が正確だが、これは結局、自然言語でコードを書いているようなもの

3. editorconfig・Linterルールの無視

設定ファイルの強制適用が困難

  • .editorconfigの設定をAIに従わせる効果的な方法がない
  • コード生成後に手動でフォーマット修正が必要
  • 自動修正(fix)ツールの不足

こちらはHooksの登場により、整備することである程度解消できる目処が見えてきましたね。 (実証実験中にHooksが発表されました)

一貫性のないコードスタイル

  • チームの規約に合わないインデントや改行
  • 命名規則の不統一
  • コメントスタイルの不一致

4. git操作の危険性と制御の困難さ

予期しない操作の実行

このあたりはAIエージェントあるあるで有名だと思いますが、実際に期間中にメンバーがいくつか遭遇していました。

  • rebase指示すると作業がループする
  • 追加実装したコードを消される
  • PRが勝手にクローズされる

(SREチームがコミットメッセージやコミットの粒度に厳しいメンバーが多く、より綺麗なコミットに修正しようとしたため遭遇率が高かった可能性もあります)

5. コストと経費処理の複雑さ

Claude Codeの支払いを会社側が行い、社員をメンバーとして利用させるようなチームプラン的なものが現状ありません。 そのため弊社では「AWS/GCPでClaudeを従量課金で動かして一人 100USD/月 を超えないように管理する」or「個人でProプランやMAXプランを契約して経費精算」という少々手間のかかる運用になっています。

その他知見

AWSコスト分析

AWS Cost Explorerから取得したデータを使い、アカウント別コスト比較や増減理由の分析を素早く行うことができました。

mise.toml活用

asdfからmiseに移行し、タスクランナー機能でvalidate, fmt, lint, trivyを統合実行できる環境を構築することで、指示やカスタムコマンドを簡略化できて効率的でした。

まとめ

2週間実装の全てをAIエージェントにすることで、得意不得意や有効的な活用方法が見えてきました。 特に現状の精度では、SRE領域のタスク全てを無理にAIエージェントに任せようとすると、かえって生産性が落ちる状況です。そのため、これらの知見をチームで共有できた点でも、かなり有用な実証実験だったと考えられます。

現状、ある程度の使い分けの方針は見えてきましたが、AIに関しては日進月歩で進化している領域なのでこれら苦手領域を克服してくる日も遠くないのでしょう。 随時エージェントの性能改善に関する情報をキャッチアップしつつ最も業務効率が上がる使い方を模索し続ける必要がありそうです。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

YAML + Rakeタスクで実現する「権限漏れゼロ」なBI運用

こんにちは、サーバーサイドエンジニアの長谷川(@hasehiro25)です。

今回の『ClinPeerアプリ開発の裏側』連載では、BIツール運用の実践的なTipsをご紹介します。 tech.medpeer.co.jp

BIツールの運用における課題として、「テーブルやカラムが追加された際のメンテナンスに手間がかかる」があります。

参照できるカラムをリストで管理する「許可リスト方式」では更新漏れが起きやすく、逆に参照できないカラムを管理する「拒否リスト方式」では、意図せず個人情報などのカラムが参照可能になってしまうリスクがあります。

そこでClinPeerでは、テーブルやカラムが変更された際にCIでチェックを行い、BIで参照できるデータを安全に更新する仕組みを導入しています。これにより、権限設定の抜け漏れを防いでいます。

本格的な分析用BIツールと、エラー調査用の簡易BIツールとしてBlazerをClinPeerでは導入しており、今回は後者のBlazerをメインにご紹介します。なお、両ツールとも共通でBI用スキーマファイルを使用しています。

github.com

specによるschemaチェック

ClinPeerでは、schema_for_bi.ymlというファイルで、Blazerから参照できるスキーマ情報を管理しています。

ファイルの中身は以下のようなイメージです。

articles:
  - id
  - created_at
  - updated_at
  - title
  - body

users:
  - id
  - created_at
  - updated_at
  - nick_name
  # - email

YAMLファイルの構造は、articles:のようにまずテーブル名を記述し、その配下にカラムをリスト形式で記述するシンプルなものです。

ここで重要なのが、リストの中でも#でコメントアウトされているカラムの扱いです。これらは意図的に参照を許可しないカラムとして扱われます。

コメントアウトを用いる目的は、カラムの存在を把握しつつ、「これは意図的に許可してないよ」という状態を誰が見ても分かるようにするためです。 もし「許可リスト方式」の場合、それが意図的に書いてないのか、単なる追加忘れなのかを区別できません。コメントアウトによって、その曖昧さをなくしています。

このYAMLファイルがデータベースの現状と一致していることを担保するために、CIで以下のようなspecを実行しています。

it "テーブル定義順がABC順であること" do
  tables = YAML.load_file("db/schema_for_bi.yml").keys
  expect(tables).to eq(tables.sort)
end

it "全てのスキーマ情報が記載されていること", aggregate_failures: false do
  expect_tokens = []
  ActiveRecord::Base.connection.tables.sort_by(&:itself).each do |table|
    expect_tokens << table
    columns = ActiveRecord::Base.connection.columns(table).map(&:name)
    columns.each { |column| expect_tokens << column }
  end

  yml_lines = File.readlines("db/schema_for_bi.yml")
  yml_lines.fill("", yml_lines.size..expect_tokens.size - 1).zip(expect_tokens).each do |actual_line, expect_token|
    expect(actual_line).to include(expect_token)
  end
end

内容はシンプルで、ActiveRecord::Base.connection.tables でテーブルとカラムの情報を全て取得し、File.readlinesで読み込んだYAMLファイルの内容と一致するかを一行ずつ確認します。(コメントアウト部分含む)

このspecがパスすれば、YAMLファイルがデータベースの現状を正しく反映していることが保証され、安全にBlazerの権限設定に進めます。

Rakeタスクによる権限更新

specのチェックを通過したYAMLファイルを使い、実際に権限を更新するためのRakeタスクがこちらです。

namespace :bi do
  task initialize_user: :environment do
    exec = ->(sql) { ActiveRecord::Base.connection.execute(sql) }
    exec["DROP USER IF EXISTS #{Setting::Blazer.db_user_name};"] # 権限リセット
    exec["CREATE USER #{Setting::Blazer.db_user_name} IDENTIFIED BY '#{Setting::Blazer.db_user_password}';"]
    exec["GRANT SHOW VIEW ON * TO #{Setting::Blazer.db_user_name};"]
  end

  task grant_select_columns: :initialize_user do
    YAML.load_file("db/schema_for_bi.yml").each do |table, columns|
      # 「read」など、MySQLの予約語に定義されたカラム名を、テーブル登録するカラム名として認識されるように、バッククォートで囲う
      columns = columns.map { |s| "`#{s}`" }.join(",")
      ActiveRecord::Base.connection.execute("GRANT SELECT (#{columns}) ON #{table} TO #{Setting::Blazer.db_user_name};")
    end
  end
end

initialize_userで古い権限設定を無効化して、新たな権限を適用する初期化処理を実行します。

そのあとgrant_select_columnsではYAML.load_file を使ってYAMLファイルを読み込み、それぞれのテーブルとカラムに対して権限設定を行なっています。コメントアウト部分は無視されるため、結果として参照を許可したいカラムにのみ SELECT 権限を付与する GRANT 文が実行される仕組みになっています。

grant_select_columnsの実行タイミングですが、他のデプロイ用タスクと合わせて追加しており、デプロイ時に自動で実行されるように設定しています。

namespace :deploy do
  task pre_hook: %i[setting:validate db:create db:migrate db:seed bi:grant_select_columns]
end

まとめ

BIツールの権限設定は後回しにされがちで、「いざデータを見たい!」という時に参照できない、といったことが起こりがちです。

今回ご紹介したように、テーブル構造の変更と同時に権限設定もチェックする仕組みをCIに組み込むことで、最新かつ安全な状態でデータを参照できる環境を維持できます。

「いつかやろう」と溜まりがちな作業は、CIを活用して日々コツコツと対応していくことで、少しずつ快適な開発環境に繋がっていくと思いますので、ぜひ参考にしてみてください。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

Notion のタスクのメモはどこに書く?コメント機能よりも「ページ下部」がオススメな理由と実践方法

こんにちは。メドピア内 Slack チャンネル 「#club_notion」 部長の佐藤太一(@teach_kaiju)です。

今回の「ClinPeerアプリ開発の裏側連載記事」では Notion を用いたタスク管理におけるメモの取り方を紹介します。

tech.medpeer.co.jp

目次

はじめに

Notion はその自由度の高さから、様々な情報を集約できる万能ツールとして扱うことができます。特にタスク管理においては、詳細情報だけでなく、関連するメモやアイデア、Slack でのやりとりのリンクなどを一緒に残しておきたい場面も多いのではないでしょうか。

そんなとき、「タスクに関するメモ、どこに書いていますか?」

よく使われるのは Notion の画面上部のコメントだと思います。

コメント(画面上部)

手軽に書ける反面、他タスク管理ツールとの挙動の違いで戸惑った経験はありませんか?

今回は ClinPeer チームの開発タスクで実際に行われている、メモはコメント機能ではなく「タスクページの下部」に書くという文化を紹介したいと思います!

コメント機能のよくある課題点

手軽に使えるコメント機能ですが、タスクのメモを残す場所としては、いくつかの課題があります。 情報は2025年5月時点のものです。

課題1: コメントのリンクを取得することができない

コメントのスレッドのリンクは取得できますが、2つめ以降のコメントはリンクが取得できません。

コメントへのリンクがない

課題2: Enter で送信

誤って書き途中のまま送信してしまいがち。
(Enter は改行という挙動に切り替えられるようになってほしい)

課題3: 場所が画面上部で折り畳まれるデザイン

画面上部のコメントは数が多いと折り畳まれます。中身を確認するために開く必要があり、これが手間です。

コメントの折りたたみ

ページ下部へのメモの仕方

ページ下部にメモをとることで、上記の課題を解決できる他、ブロックを用いた見やすいデザインを作ることができる等のメリットも得られます。

その具体的な方法がこちらです。

ページ下部にメモ

  1. 「Memo」という見出しを作る
  2. 日付を書く
  3. 誰が書いたのかを示すために自身の絵文字のアイコンを出す(省略することはよくあります)
  4. 内容を記述

主なメモの内容

  • タスクの進捗
  • 関連するやりとりへのリンク
  • 思ったこと・気づき
  • 課題
  • 簡易的な議事録

特にタスクに関連するやりとりへのリンク(Slack等)はメモっておくと後から見返す時に非常に助かります。

タスクに関するMTGを行う場合は、最近出た AI ミーティングノートをタスクページに作るのも良さそうです。

Q & A

Q. 他のメンバーへの通知はどうする ?
A. 画面上部のコメント使います。内容が多い時は Memo のリンクをコメントに貼ります。ページ内メンションは使っていません。

Q. ページがどんどん長くなって見づらくならないか?
A. 画像を大量に貼ったりすると長くなりますが、トグルで折り畳めば気になりません。

まとめ

今回はタスクのメモをページ下部にとる具体的なやり方を紹介しました。

タスクにメモをとっておくと、タスクページそのものがドキュメントの役割を果たしたりすることが可能になります。情報を追いやすくなるためとてもオススメです。

また、本手法はチームでのタスク管理だけではなく、個人でのタスク管理でも使えます。
ぜひ試して見てください!


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

SwiftUIにおけるEnvironmentの活用法

こんにちは!メドピアにてモバイルアプリエンジニアをしている王です。 今回の「ClinPeerアプリ開発の裏側連載記事」では、SwiftUIのEnvironmentについてお話しできればと思います。 tech.medpeer.co.jp

SwiftUIのEnvironmentは、ビュー間でデータを共有するための強力な依存性注入(DI)の仕組みです。多くのSwiftUIプロジェクトで活用されており、ビュー間のデータ伝達を簡素化し、アプリ設計の柔軟性を高めます。ClinPeerでは、ほぼすべての画面をSwiftUIで構築しており、Environmentの活用について考察しています。

SwiftUIにおけるUI専用の依存性注入

依存性注入(Dependency Injection、DI)は、モダンなソフトウェア開発において重要な技術であり、以下の利点があります。

  • 疎結合:コンポーネント間の依存関係を最小限に抑えることで、モジュールの再利用性と保守性が向上します。
  • 保守性:依存関係が明示的になることで、コードの理解と修正が容易になります。
  • テスト容易性:依存関係を差し替えることで、ユニットテストが容易になります。

SwiftUIのEnvironmentは、ビューがロードされた後にのみ値を取得できるという特徴があります。この設計は、SwiftUIが宣言型UIフレームワークであることを反映しており、ビューの構築と更新がデータや環境と一貫性を保つようになっています。

値型以外の活用

Environmentは、単なる値型の注入にとどまらず、関数、ファクトリーメソッド、プロトコル制約など、さまざまな形式の依存性を注入できます。実際、SwiftUIの標準Environment値には、editModedismissmanagedObjectContextなど、非値型の例も含まれています。

開発者は、Environmentの活用を値型に限定せず、SwiftUIの特性を活かして、より柔軟で疎結合なコンポーネントを構築することが重要です。

Observationフレームワークの活用

EnvironmentObjectを使用する際、依存性の注入を忘れるとアプリがクラッシュするリスクがあります。一方、Environmentはデフォルト値を要求するため、より安全で信頼性の高い設計が可能です。iOS 17以降、Observationフレームワークの導入により、可観測オブジェクトの注入がさらに容易になりました。

extension EnvironmentValues {
    @Entry var article: Article = .init()
}

@Observable
class Article {
    // プロパティやメソッドを定義
}

struct ContentView: View {
    @Environment(\.article) var article
    var body: some View {
        // ビューの構築
    }
}

この方法では、クラッシュのリスクを回避し、同じ型の可観測インスタンスを複数使い分ける柔軟性も得られます。

extension EnvironmentValues {
    @Entry var article: Article = .init()
    @Entry var article1: Article = .init()
    @Entry var article2: Article = .init()
}

Environmentの最適化

Environmentを使用してアプリの状態を管理する際、ビューの更新効率がユーザー体験に影響を与えることがあります。以下の最適化戦略を採用することで、不要なビューの再描画を抑えることができます。

精密な注入

複数のサブ状態を含む複合値型に対して、特定のプロパティのみを注入することで、不要な更新を回避できます。ビューが実際に必要とする部分の状態だけを購読することで、より効率的なリアクティブUIを構築できます。

struct UserState {
    var height = 175 // 単位: cm
    var weight = 75  // 単位: kg
}

extension EnvironmentValues {
    @Entry var userState = UserState()
}

struct HeightView: View {
    // heightのみが更新対象
    @Environment(\.userState.height) var height
    var body: some View {
        Text("身長: \(height) cm")
    }
}

struct WeightView: View {
    // weightのみが更新対象
    @Environment(\.userState.weight) var weight
    var body: some View {
        Text("体重: \(weight) kg")
    }
}

struct BMIView: View {
    @Environment(\.userState) var userState
    var body: some View {
        let heightInMeters = Double(userState.height) / 100.0
        let bmi = Double(userState.weight) / (heightInMeters * heightInMeters)
        return Text(String(format: "BMI: %.2f", bmi))
    }
}

struct RootView: View {
    @State var userState = UserState()
    var body: some View {
        List {
            Button("身長を変更") {
                userState.height = Int.random(in: 130...220)
            }
            Button("体重を変更") {
                userState.weight = Int.random(in: 35...120)
            }
            HeightView()
            WeightView()
            BMIView()
        }
        .environment(\.userState, userState)
    }
}

条件付きの更新

transformEnvironmentを使用すると、特定の条件を満たす場合にのみ環境値を更新できます。これにより、更新頻度を減らし、アプリの応答性と滑らかさを向上させることができます。

struct RootView: View {
    @State var userState = UserState()
    @State var height = 175
    var body: some View {
        List {
            Button("身長を変更") {
                height = Int.random(in: 130...220)
            }
            HeightView()
        }
        .transformEnvironment(\.userState) { state in
            guard height > 150 else {
                print("無視: \(height)")
                return
            }
            state.height = height // height > 150 の場合のみ更新
        }
    }
}

Environmentとサードパーティ製DIフレームワークの併用

SwiftUIのEnvironmentは優れた機能を提供しますが、ビューのライフサイクルに厳密に制限されます。ビジネスロジックをViewModel層に分離したり、ユニットテストを行う場合、サードパーティ製のDIフレームワークの使用が有効です。ClinPeerでは、FactoryというSDKを使用しています。

@Observable
class UserState {
    var height: Int = 175
    var weight: Int = 75
}

extension Container {
    var userState: Factory<UserState> {
        Factory(self) { UserState() }
            .scope(.shared)
    }
}

// 使用例
@Injected(\.userState) private var userState

ハイブリッドアーキテクチャの利点

Environmentとサードパーティ製DIツールを併用することで、以下の利点が得られます。

  • 柔軟なアーキテクチャ:ビュー層ではSwiftUIのEnvironmentを使用し、ビジネスロジック層ではFactoryなどのDIツールを活用できます。
  • テストの容易性:ビジネスロジックをUIから完全に切り離すことで、ユニットテストやモック化が簡単になります。
  • 保守性の向上:特定のUIフレームワークへの依存を最小限に抑え、コードベースの長期的な安定性と再利用性を高めます。

まとめ

SwiftUIのEnvironmentは、依存性注入とビューのライフサイクルを一体化した設計であり、視覚的なUIコンポーネントの境界を明確にしながら、ビュー階層におけるデータの効率的かつ制御可能な伝達を実現します。

また、精密な注入や選択的な変更によって、不要なビュー更新を避けることでアプリ全体の効率を高めることができます。 さらに、SwiftUIのエコシステムにおいては、柔軟にサードパーティ製のDIフレームワークを取り入れることで、より複雑なユースケースにも対応可能です。

Environmentの設計に対する深い理解は、拡張性が高く品質の高いSwiftUIアプリを構築するための確かな基盤となります。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。
ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

環境ごとの設定管理が可能な ClinPeer のフィーチャーフラグの紹介

こんにちは。サーバーサイドエンジニアの佐藤太一(@teach_kaiju)です。

今回の「ClinPeerアプリ開発の裏側連載記事」ではサーバーサイドにおける、フィーチャーフラグの実装方法を紹介します。

tech.medpeer.co.jp

目次

フィーチャーフラグとは

フィーチャーフラグ(機能フラグ、別名フィーチャートグル)は、機能のオン・オフを制御する仕組みです。
ClinPeer ではフィーチャーフラグを用いることで、開発中の機能の細かいリリースや、社内IPのみ機能を有効にするなどの柔軟な制御を実現しています。

フィーチャーフラグに関する詳細は以下の記事に書かれています。こちらもぜひご覧ください。

tech.medpeer.co.jp

機能の有効化 Feature#enabled?

ClinPeer では Flipper gem をラップした Feature クラスを用いています。

基本的な使い方

特定の機能(例:allow_access_to_new_sugoi_feature)が有効かどうかを調べるには、以下のように記述します。

if Feature::ALLOW_ACCESS_TO_NEW_SUGOI_FEATURE.enabled?

特定の条件で有効化

enabled? メソッドには、オプションで引数を渡すことができます。この引数を使うことで、「特定のユーザーだけに機能を有効にする」「特定のIPアドレスからアクセスされた場合のみ機能を有効にする」といった、より細かい制御が可能になります。

例えば、特定のIPアドレスからのアクセスに対してのみ機能を有効にしたい場合は、そのIPアドレス文字列を渡します。

if Feature::ALLOW_ACCESS_TO_NEW_SUGOI_FEATURE.enabled?(request.remote_ip)

許可するIPアドレスは、Flipper UI で設定します。

flipper_ui_allow_ip

フラグの運用

フィーチャーフラグの定義や操作は、主に config/features.yml ファイルと Flipper UI を通じて行います。

features.yml

フィーチャーフラグの設定は、config/features.yml ファイルで一元管理されます。このファイルには、各フラグの識別子 (kind)、説明 (description)、そして環境ごとの設定を記述します。

# config/features.yml の例
- kind: allow_access_to_new_sugoi_feature
  description: 新しいスゴイ機能へのアクセスを許可する
  development: flipper
  test: true
  staging: flipper
  production: flipper

各項目の意味は以下の通りです。

  • kind: フラグの一意な識別子です。コード中では Feature::KIND_NAME のようにして参照できます。
  • description: フラグの説明です。この内容は Flipper UI のダッシュボードにも表示されます。
  • 環境名 (development, test, staging, production など):
    • flipper: Flipper UI でフラグの有効/無効を制御する場合に指定します。(デフォルト: 無効)
    • true: その環境では常にフラグを有効にします。
    • false: その環境では常にフラグを無効にします。

ClinPeer ではデプロイ時にseed を実行し、その中で features.yml の内容をもとに差分を更新します。

# app/models/feature.rb の抜粋

class Feature < ActiveYaml::Base
  include ActiveHash::Enum

  # 略
  
  set_root_path Rails.root.join("config")

  enum_accessor :kind

  scope :flipper_controllable, -> { where(Rails.env => FLIPPER_VALUE) }

  FLIPPER_VALUE = "flipper"
  private_constant :FLIPPER_VALUE

  # 略
end
# seed の処理

features = Feature.flipper_controllable.pluck(:kind) # ymlからFlipper制御対象のkindを取得
current_features = Flipper.features.map(&:name) # 現在Flipperに登録されている機能名を取得

# ymlにあってFlipperにないものを追加
(features - current_features).each { |f| Flipper.add(f) }
# Flipperにあってymlにないものを削除 (ymlから削除されたフラグ)
(current_features - features).each { |f| Flipper.remove(f) }

フラグの新規追加

config/features.yml に新しいフラグの定義を追加します。 デプロイ時に seed で features.yml の内容をもとに差分を更新します。

フラグの有効・無効の切り替え

config/features.ymlflipper と設定されているフラグの有効/無効は、Flipper UI (社内用管理画面) 上で操作します。

flipper_ui_on_off

フラグの削除

不要になったフィーチャーフラグを削除する際は、以下の手順で行います。

  1. フラグの参照箇所をコード上から削除
  2. 上記対応をリリース
  3. config/features.yml から該当フラグの定義を削除

ポイント
「フラグ参照箇所の削除」と「ymlからのフラグ定義の削除」を同一のリリースに含めないようにしています。

  • Flipper は、存在しないフラグを参照した場合、無効 (false) として扱われます。
  • ymlの変更(フラグ定義の削除)を反映するデプロイタスクは、アプリケーションコードの反映よりも先に実行される場合があります。

もし同一リリースに含めてしまうと、ymlからフラグが削除された後、まだ古いコードがそのフラグを参照しているわずかな時間帯に、意図せず機能が無効化されてしまう可能性があります。

条件付き有効化の実装

Flipper には対象をflipper_idで識別し、一致した場合のみ機能を有効化するという機能があります。 具体的には以下の2つを比較し、一致した場合機能を有効化します。

箇所
enabled? の第二引数 puts some_obj.flipper_id # 127.0.0.1
Flipper.enabled?("allow_access_to_new_sugoi_feature", some_obj)
Flipper UI で設定した actor
flipper_ui_allow_ip

(actor は flipper_id という識別子を持ったオブジェクト。この識別子を比較することで actor が同一であるかどうかを判断しています。そして、actor が同一であれば機能を有効化します。)

https://www.flippercloud.io/docs/features/actors

ClinPeerでは StringFlipperActor クラスを導入することで、任意の文字列を直接Actorの識別子として扱えるように拡張しています。

# app/models/feature.rb の抜粋

class Feature < ActiveYaml::Base

# 略

  class StringFlipperActor
    attr_reader :value

    def initialize(value)
      @value = value
    end

    alias flipper_id value
  end

# 略

  def enabled?(obj = nil)
    case value
    when FLIPPER_VALUE
      obj = StringFlipperActor.new(obj) if obj.is_a?(String)
      Flipper.enabled?(kind, obj)
    else
      !!value
    end
  end

  private

  def value
    public_send(Rails.env)
  end
end

これにより、Feature#enabled? メソッドに文字列を渡すと、その文字列がそのまま flipper_id として扱われます。

Feature::ALLOW_ACCESS_TO_NEW_SUGOI_FEATURE.enabled?("127.0.0.1") # "127.0.0.1" がflipper_idとなる

この仕組みを利用することで、IPアドレスや特定の識別文字列など、モデルオブジェクトが存在しないようなケースでも柔軟にActorベースのフラグ制御を行うことができます。

生成AIを活用したフラグ削除

フィーチャーフラグは、機能のリリースサイクルを柔軟にする強力なツールですが、役目を終えたフラグは適切に削除していく必要があります。フラグが増えすぎると、コードの複雑性が増し、管理コストも増大するためです。

従来、フラグの参照箇所の削除は以下の手順で行っていました。

  1. コードベース全体から、削除対象フラグの参照箇所を検索する。
  2. 特定された参照箇所を一つ一つ手動で修正・削除する。

このプロセスは、特に view 等の分岐が複雑な場合、時間と手間がかかり、見落としのリスクも伴いました。

そこで、現在はフラグの参照箇所の削除に生成AIを使用しています。プロンプトの例を以下に示します。

Feature::{フラグ名}は常に{true or false}なフラグとなりました。
上記を参照しているすべての条件分岐を削除してください。
features.ymlから対象のフラグの削除はしないでください。
features.ymlの該当のフラグに「TODO: 参照箇所削除済み、削除予定」というコメントを追加してください。
参考:
 - kind: allow_access_to_new_sugoi_feature # TODO: 参照箇所削除済み、削除予定
 
その後 features.ymlをコミットしてください
コミットメッセージ: Git履歴を残すために削除予定のコメント追加

AIを活用すると、手動と比較して、以下のようなメリットが見込めます。

  • 参照箇所の自動特定: AIがコードを解析し、削除対象のフィーチャーフラグが使用されている箇所を迅速に特定します。
  • 修正コードの提案: 特定された箇所に対して、AIが適切な修正案(フラグ参照の削除や、条件分岐の恒久化など)を提案してくれる場合があります。
  • 作業時間の短縮とミスの削減: 手作業による検索や修正と比較して、作業時間を大幅に短縮し、ヒューマンエラーによる見落としや修正ミスを減らすことができます。

最終的なコードの確認とテストは開発者自身が行う必要がありますが、AIツールを補助として利用することで、フィーチャーフラグのライフサイクル管理をよりスムーズかつ安全に行えるようになると考えています。

おわりに

本記事では、ClinPeerにおけるフィーチャーフラグの実装と運用方法について紹介しました。 Flipperという強力な基盤ライブラリを利用しつつ、Feature というActiveHashモデルでラップすることにより、アプリケーション固有の事情や、より使いやすいインターフェースを開発チームに提供しています。

このように、フィーチャーフラグシステムを適切に抽象化(ラップ)することには、多くのメリットがあります。

  • 管理の容易化: フラグの定義を一元化 (features.yml) し、環境ごとの挙動を明確にすることで、管理コストを低減します。
  • 利用の簡便化: Feature::KIND_NAME.enabled? のような直感的で統一されたインターフェースを提供することで、開発者が迷うことなくフラグを利用できます。
  • 将来的な拡張性: 例えば、将来的に別のフィーチャーフラグ管理システムに移行する場合でも、Feature クラス内部の実装を変更するだけで済み、アプリケーションコードへの影響を最小限に抑えることができます。
  • 独自のロジックの追加: StringFlipperActor のように、特定のニーズに合わせた独自のロジックを組み込みやすくなります。

フィーチャーフラグは、アジャイルな開発、安全な機能リリース、そしてA/Bテストなど、現代的なソフトウェア開発において非常に有効なプラクティスです。 ClinPeerでは、このような仕組みを活用し、ユーザーにより良い価値を迅速に届けられるよう、日々改善を続けています。

この記事が、フィーチャーフラグの導入や運用を検討されている方の一助となれば幸いです。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp