コネヒト開発者ブログ

コネヒト開発者ブログ

DroidKaigi 2023 Day2 参加レポート

こんにちは!Androidエンジニアの関根です。

2023/09/14から3日間、DroidKaigi 2023が開催されています。 弊社でもスポンサーをさせていただきオフライン参加しているので、僭越ながらレポートをします。

本日は、2日目にわたしが聴講したセッションを紹介します。後日アーカイブ動画公開後に更新していく予定です。 少しでもAndroid開発の盛り上がりに貢献できたら嬉しく思います。

ビジネス向けアプリを開発するときに知っておくべきAndroid Enterpriseの世界

最初は、Yusaku Tanakaさんによるモバイルデバイス管理(MDM)を利用した開発についてのセッションです。

MDMに関して、システム構成や配布方法、実装方法など始まりから終わりまでを理解できる内容になっていました。 相対的に事例を多く聞ける事例ではないので、初めての知見ばかりで、新鮮に聞かせていただきました。 すぐにでもMDMを利用して社内ツールの提供をすることもできそうに感じています。

speakerdeck.com

ビジネス向けアプリの開発を予定している方、社内用のアプリを作りたい方におすすめしたいです。

Flutterにおけるアプリ内課金実装 -Android/iOS 完全なる統一-

弊社の中島さんのFlutterを用いたアプリ内課金の定期購入についてのセッションです。 Androidの関数と対比しながら解説して頂き、Flutter未経験の方にも理解しやすい内容でした。 終始落ち着いて発表されていて、改めて一緒に働けることを心強く思いました。中島さん登壇お疲れ様でした!

speakerdeck.com

Flutterで定期購入機能の導入を検討中、あるいはアプリ内課金機能があるアプリのFlutterへのリプレイス を検討中の方におすすめしたいです。

Androidアプリの良いユニットテストを考える

Nozomi Takumaさんによる、Androidアプリ開発でのユニットテストに関するセッションです。

良いユニットテストの定義を提示して頂いた上で、テストの種類ごとにおける実行速度の対比や、 テストダブル利用時の考慮すべきトレードオフ、テスト実装時の手法など、網羅的でわかりやすい内容でした。テストコードはプロダクトコードとは違う知識や思考が必要だと思うので、解説いただいた内容をもとにチームでの議論もしやすくなると感じました。

speakerdeck.com

ユニットテストを書いていない、もしくは書いているがもう一歩踏み込んで取り組みたい方におすすめです。

レイヤードアーキテクチャーでの例外との向き合い方

Yukihiro MoriさんによるMVVMをベースにした例外の扱いに関する発表です

レイヤーごとの例外の対処方法や、ユーザーへの例外の伝え方のパターンと実装方法など、開発上の関心を総合的に解説した内容です。 実装方法とアーキテクチャ図を合わせて紹介していただき、理解しやすい内容で、実装内容を具体度高く聞けたので、弊社にも取り入れていきたいと思います。

speakerdeck.com

なんとなく例外を扱っている、例外の種類が多くハンドリングに困っているという方にお勧めしたいです

できる!アクセシビリティ向上

Ogura Yuriさんによるアプリのアクセシビリティに関するセッションです。

そもそものアクセシビリティの定義や、TalkBackとスイッチアクセスの機能を、実際のデバイスで操作するデモから始まり、知識がない状態でも安心して聞けました。 デモの後は施策立案〜リリースまでのプロセスと、明日にでもできる容易な改善手法を解説いただいたので、導入時に参考にできることを多く知れたと思います。

speakerdeck.com

アクセシビリティに対して見識がない方にお勧めしたいです。

まとめ

スピーカーの皆様、スタッフの皆様、2日目もお疲れ様でした!

今日は企業ブースもいくつか回らせていただき、久しぶりにオフラインでの情報交換ができ、楽しませてもらいました。 今回は、NISSANさんの企業ブースでモビリティアプリを触らせていただくなど、スマートフォン以外を扱う企業参加も増えている印象で、Androidコミュニティのさまざまな広がりを感じました。 明日もよろしくお願いします!

最後にコネヒトでは一緒に働く仲間を募集しています! 興味持っていただけた方は気軽にご連絡ください!

www.wantedly.com

CakePHP4.3から非推奨になったFixtureのテーブル定義の問題を解決しました

こんにちは。

今回はCakePHPのバージョン4.3から非推奨機能に追加されたTestFixture の対応をしたのでバックエンドエンジニアの共同制作でブログに書いてみました。

冒頭〜導入手順5までは高橋で、手順6以降は西中が書いております。

以前PHP8.1にアップデートした際にCakePHPのバージョンも4.2から4.3にアップデートしました。

その時のブログはこちら↓

https://tech.connehito.com/entry/2023/03/31/195819

この時からテストを実行する度に以下のような警告が出るようになりました。

Deprecated Error: You are using the listener based PHPUnit integration. This fixture system is deprecated, and we recommend you upgrade to the extension based PHPUnit integration. See https://book.cakephp.org/4/en/appendices/fixture-upgrade.html
/var/www/html/server/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php, line: 79

対象のリポジトリは元々CakePHP3系で作られていたので、テストに使うテーブル定義はFixtureクラスの中に定義されていました。 ですが、CakePHPのマイグレーションを利用しておらず、いわゆるマスタとなるようなテーブル定義は別のリポジトリで管理されています。

そのため、テーブル定義が二つの場所にある二重管理状態になっていました。

CakePHPの公式ドキュメントではCakePHPのマイグレーションを使った方法については詳細に記述されているのですが、DDLファイルを使った方法は簡潔に記述しかありません。ネットで探してもあまり見つからなかったので、同じように躓いた人の役に立てれたら嬉しいなと思っています。


目次


前提

対応方法をご紹介する前に前提条件をお伝えします。

  • PHP: 8.1
    • CakePHP: 4.3
    • PHPUnit: 9.6.5
  • AWS
    • ECS
    • Amazon Aurora MySQL v2(MySQL5.7)
  • DBのスキーマ管理はアプリケーションコードとは別リポジトリ
    • マイグレーションツールは Ridgepole
  • GitHub Actions

導入手順

mysqldumpによって取得したDDLファイルからテストのテーブル定義を使うように変更しました。

1. アプリケーションリポジトリにDDLファイルを/config/schema配下に置く

DDLファイルは以下のSQLコマンドで生成しました。

mysqldump -u[ユーザー] -h[ホスト] -P[ポート] -p[パスワード] --no-data --skip-column-statistics --no-create-db [データベース名] > base_test.sql

FixtureやFactoryでレコードを追加する際に、AUTO_INCREMENTの値が1ではない場合主キーが重複してしまうため、awkコマンドを使って初期値を変換しました。

awk '{ gsub(/AUTO_INCREMENT=[0-9]+/, "AUTO_INCREMENT=1"); print }' "base_test.sql" > "test.sql"

2. phpunit.xmlを変更する

phpunit.xml から <listeners> ブロックを削除し、以下の内容を phpunit.xml に追加しました。

ref: https://book.cakephp.org/4/en/appendices/fixture-upgrade.html

<extensions>
    <extension class="\Cake**\T**estSuite\Fixture\PHPUnitExtension" />
</extensions>

3. tests/boostrap.phpに追記する

1で置いたDDLファイルを使用してテーブル定義を取得します。

ref: https://book.cakephp.org/4/ja/development/testing.html#creating-test-database-schema

$testSqlFile = dirname(__DIR__) . '/config/schema/test.sql';
(new SchemaLoader())->loadSqlFiles($testSqlFile, 'test');

4. Fixtureクラスからテーブル定義を削除する

実施したリポジトリは元々CakePHP3系で作られていたので、テストに使うテーブル定義はFixtureの中に定義されていました。 段階的なアップグレードを行っていたため、Fixtuer内にまだテーブル定義は残っている状態です。 そのため、まずは各Fixtureクラスからごっそりテーブル定義ブロックを削除していきます。

<?php
namespace App\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

/**
 * ArticlesFixture
 *
 */
class ArticlesFixture extends TestFixture
{
    /**
     * Table name
     *
     * @var string
     */
    public $table = 'articles';
    public $connection = 'test_hoge';

-    /**
-     * Fields
-     *
-     * @var array
-     */
-    // @codingStandardsIgnoreStart
-    public $fields = [
-        'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
-        'title' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => '', 'collate' => 'utf8mb4_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null],
-        'description' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => '', 'collate' => 'utf8mb4_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null],
-        'status' => ['type' => 'integer', 'length' => 3, 'unsigned' => false, 'null' => false, 'default' => '0', 'comment' => '', 'precision' => null, 'autoIncrement' => null],
-        'created' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null],
-        'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null],
-        '_indexes' => [
-            'index_status' => ['type' => 'index', 'columns' => ['status'], 'length' => []],
-        ],
-        '_constraints' => [
-            'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
-        ],
-        '_options' => [
-            'engine' => 'InnoDB',
-            'collation' => 'utf8_general_ci',
-        ],
-    ];

    /**
     * Records
     *
     * @var array
     */
    public $records = [
        ︙
    ];
}

また、$recordsの中に配列がある場合、今まで$fieldsのtype指定していたのでこのように独自でjson形式にしなければなりません。

$records = [
    [
        'id' => 1,
        'urls' => [
            0 => [
          'type' => 1,
        'url' => 'https://www.example1.co.jp',
      ],
      1 => [
          'type' => 2,
        'url' => 'https://www.example2.co.jp',
      ],
        ],
    ],
    [
        'id' => 2,
        'urls' => [
            0 => [
          'type' => 1,
        'url' => 'https://www.example1.co.jp',
      ],
      1 => [
          'type' => 2,
        'url' => 'https://www.example2.co.jp',
      ],
        ],
    ],
];
// テストで使用するのにjson形式に変換する
foreach ($records as $seq => $record) {
    if (is_array($record['urls'])) {
       $records[$seq]['urls'] = json_encode($record['urls']);
    }
}
$this->records = $records;

以下のように直接json形式にするでも大丈夫です。

$records = [
    [
        'id' => 1,
        'urls' => '[{"type": 1,"url": "https://www.example1.co.jp"},{"type": 2,"url": "https://www.example2.co.jp"}',
    ]
    [
        'id' => 2,
        'urls' => '[{"type": 1,"url": "https://www.example1.co.jp"},{"type": 2,"url": "https://www.example2.co.jp"}',
    ]
];

5. ユニットテストを回してみる

今回実施したリポジトリではDockerコンテナを利用しているので、コンテナの中に入ってPHPUnitを回すようにしていました。

元々、composer.json 内でPHPUnitを定義しているため、composer から呼び出せるようになっています。

    "scripts": {
        "post-install-cmd": [
            "App\\Console\\Installer::postInstall"
        ],
        "post-create-project-cmd": "App\\Console\\Installer::postInstall",
        ︙
        "test": "phpunit --colors=always"
    },

テストコードの件数が少ない場合は気にしなくて良いのですが、テスト件数が多くテスト実行後に結果を見ようとするとターミナル上で見切れてしまうことが多々あったので実行結果はテキストファイルに書き出すようにしていました。 その時、composerのタイムアウトが発生してしまうことがあるので予め環境変数を上書きしてタイムアウトが起きないように設定した上でテストを実行し、出力したファイルを見比べながらテストコードを実情にあった形で直していきます。

$ export COMPOSER_PROCESS_TIMEOUT=0
$ composer test > text.log

CakePHPのFixtureはどうやら主キーやユニークキーが重複してしまうFixtureのレコードも許してしまい、レコード重複エラーが発生してしまうという事象が頻発してしまいました。

このリポジトリではFixture Factoriesを利用しているので、重複が出ないようにテストケース内でFactoryクラスを使ってレコードを作成するように書き換えることで既存のテストに影響が出ないように修正を行いました。

ref: https://tech.connehito.com/entry/2022/07/22/100000

これで一応Fixtureの警告は消えましたが、これだとテーブル定義を変更した場合にアプリケーションリポジトリのDDLファイルを手動で更新しなくてはなりません。

テーブル定義を管理しているリポジトリに変更があった場合に自動でAWSのS3にDDLファイルをアップロードし、アプリケーションリポジトリでそのDDLファイルをダウンロードしてくるという仕組みを作ることになりました。

6. 自動化

6.1. DDLファイルをS3のバケットにアップロードする

テーブル定義変更の度にリポジトリ内のDDLファイルの変更を行わないといけないだけでなく、弊社の場合、複数のリポジトリで同じDBを参照しているということが多々あるため、スキーマ定義の変更の度に各リポジトリ内のDDLファイルを書き換えるのは手間だという問題もありました。

今回の本題であるスキーマ定義のDDLファイルをダウンロードする仕組みは、正にこの問題を解決する手段として考えたものでした。

弊社では前述の通り、 Ridgepole を使ってスキーマ定義を管理しているのでスキーマ定義の変更が発生したタイミングでDDLファイルを作成し、S3のバケットにアップロードする仕組みを作成しました。

簡単に流れを説明するとこのようになっています。

  1. 開発者がテーブル定義を変更し、スキーマ定義管理用のリポジトリに push します。
  2. スキーマ定義管理用のリポジトリに設定されているGitHub ActionsがDDL反映処理の実行のためのECSを起動します。 この一連の処理については過去にブログで投稿しているので、そちらを参考にしてください。 refs: https://tech.connehito.com/entry/2019/10/08/165500
  3. 前述のDDL反映を行います。
  4. ECS内でmysqldumpコマンドを実行します。
  5. 各スキーマのDDLファイルを取得し、ローカルに保存します。 この記事の冒頭で紹介させていただいたawkコマンドを使ってDDLファイルの一部を書き換える処理も行っています。
  6. S3にファイルをアップロードします。

S3へのアップロードフロー

6.2. S3のバケットからDDLファイルをダウンロードする

「S3のバケットからDDLファイルをダウンロードする」ということは決まったのですが、「じゃあどのタイミングでDDLファイルをダウンロードするのが適切なんだろう?」という課題が出てきました。

そこで考えたのがこの3つのタイミングでした。

  • テスト実行時にDDLファイルをダウンロードする
  • DockerビルドのタイミングでDDLファイルをダウンロードする
  • Dockerコンテナを立ち上げたタイミングでDDLファイルをダウンロードする

テスト実行時にDDLファイルをダウンロードする

最初に思いついたのはこの方法です。 毎回テストの度に最新のDDLファイルをダウンロードすれば最新のスキーマ定義でテストが実行できるというメリットはあります。

ですが、

  • 通信エラーでS3のバケットからDDLファイルをダウンロードできなかった場合にテストが動かなくなってしまう
  • スキーマ定義の変更は頻繁に行われるわけではないので、毎回DDLファイルをダウンロードするのは無駄

という問題があったため、却下となりました。

DockerビルドのタイミングでDDLファイルをダウンロードする

Dockerコンテナをビルドするのはそんなに頻繁ではないので一見良さそうに思えます。

ですが、

  • テストコードは本番環境には不要なため、不要なファイルがDockerイメージに含まれてしまう
  • DDLファイルを含める分、Dockerイメージが大きくなってしまう
  • 本番環境には不要なファイルをダウンロードするために、DockerイメージをビルドするためのCIの設定にAWSのキーを設定しないといけない

という問題があったため、こちらも却下となりました。

Dockerコンテナを立ち上げたタイミングでDDLファイルをダウンロードする

ローカルでDockerコンテナを立ち上げる際に必ず実行するシェルファイルがあるため、そちらにDDLファイルをダウンロードする処理を追加しました。

ローカルのDockerコンテナは何かライブラリの更新・変更のような大きな変更があったらビルドし直すということもあり、いまの開発スタイルではこのタイミングが適切だろうということになり、このタイミングでDDLファイルをダウンロードすることになりました。

また、「なんかスキーマ定義合ってないかも?」となった時でも「まず最初にDockerコンテナを立ち上げ直してみよう」という手段が取れるので、問題解決の第一歩の負担が重くないことも良さそうだねという話になりました。

実際のシェルの処理とは異なりますが、以下のように aws-cli の aws s3 cp コマンドでS3のバケットからダウンロードし、 tests/bootstrap.php で読み込めるようにしました。

# copy table schema files from s3
aws s3 cp s3://[DDLファイルのあるバケット]/メインで使うDB.sql /tmp/ && \
aws s3 cp s3://[DDLファイルのあるバケット]/連携して使うDB1.sql /tmp/ && \
aws s3 cp s3://[DDLファイルのあるバケット]/連携して使うDB2.sql /tmp/ && \
aws s3 cp s3://[DDLファイルのあるバケット]/連携して使うDB3.sql /tmp/

cp /tmp/*.sql /var/www/html/config/schema/

弊社のリポジトリはローカルのディレクトリを /var/www/html ディレクトリにマウントする形にしているので、マウントの対象外の /tmp ディレクトリにDDLファイルをダウンロードし、実際に読み込むファイルはマウント後のディレクトリにコピーしたものを利用する形にしています。

// Load one or more SQL files.
$ddlFiles = [
    'test' => 'メインで使うDB.sql',
    'test_sub1' => '連携して使うDB1.sql',
    'test_sub2' => '連携して使うDB2.sql',
    'test_sub3' => '連携して使うDB3.sql',
];

$schemaLoader = new \Cake\TestSuite\Fixture\SchemaLoader();
foreach ($ddlFiles as $schema => $file) {
$fullPath = dirname(__DIR__) . '/config/schema/' . $file;
    if (!file_exists($fullPath)) {
        // ファイルが存在しない場合は /tmp ディレクトリからコピーしてくる
        copy('/tmp/' . $file, $fullPath);
    }
    $schemaLoader->loadSqlFiles($fullPath, $schema);
}

まとめ

スキーマ定義をダウンロードできる仕組みを入れ、単体テストで利用できるようにしました。

これにより、最新のスキーマ定義でテストを実行できるようになり、テストコードとデータベース構造の整合性を維持できるようになりました。また、スキーマ定義の変更に柔軟に対応できるため、開発のスピードアップにもつながっていくことが期待できます。

他のリポジトリでも同じDBを参照しているため、横展開していくことで開発効率・開発者体験の向上が見込めそうです!

コネヒトでは一緒に働く仲間を募集しています!

そして興味持っていただけた方は気軽にご連絡ください!

https://www.wantedly.com/companies/connehito/projects

DroidKaigi 2023 Day1 参加レポート

こんにちは!Androidエンジニアの関根です。

2023/09/14から3日間、DroidKaigi 2023が開催されています。 弊社でもスポンサーをさせていただきオフライン参加しているので、末筆ながらレポートをします。

1日目に、わたしが聴講したセッションを紹介し、後日アーカイブ動画が公開されたら、リンクを貼りたいと考えています。 少しでも、Android開発の盛り上がりに貢献できたら嬉しく思います。

これで安心! Compose時代のDon't keep activities対応

最初はuponさんによるComposeの実装と絡めたActivity破棄に対処方法をまとめた発表です。

Activity破棄が起こる要因や対処方法が、わかりやすくまとめられおり、サービスの特性によってどこまで対応するかなど、判断軸も話されていて、あまり社外の事例は知れないため、参考になりました。

2023.droidkaigi.jp

Compose導入にあたりActivity破棄の対処方法を見直したい方に、おすすめしたいと思います。

Unleashing the Power of Android Studio

mhidakaさんによる、直近のAndroid Studioの追加機能をまとめた発表です。

直近数回のAndroid StudioのアップデートをUI Tool、Build System、Inspectの区切りで解説いただきました。 アップデートをまとめていただいたことで、現状と今後の方向性がよくわかる内容になっています。 特に、Network Inspectorで通信内容をインタセプトし改変できるようになったのは革命だと思いました。

speakerdeck.com

最近Android Studioのアップデートを追えてなかったなという方におすすめです。

iOSとAndroidで定期購入の意図しない解約を防ぐ

Ryo YamazakiさんとYuta Satoさんによる定期購読の解約に関する発表です。 定期購読中のクレジットカードの決済エラーなどによる、非自発的解約をAndroidとiOSそれぞれの機能と実装を詳細に解説した内容です。 弊社のママリアプリでも定期購読の機能を提供しているため、改めて見直したいと感じました。

2023.droidkaigi.jp

定期購読を導入している方、これから導入を検討している方におすすめしたいと思います。

YouTubeのLive配信をリリースするまで

yurihondaさんによるYouTubeのLive配信についての発表です。

事前準備からリリースまでを網羅的に解説されいて、サンプルアプリのコードを元にした解説が、わかりやすかったです。 躓きやすいところも共有していただき、実装にこの発表を見ておくと安心して取り組めそうです。

speakerdeck.com

Live配信は、昨今新しいコンテンツやビジネスとして盛り上がっているため、 実装機会も増えてくると思うので、現時点で予定がない方に、ぜひおすすめしたいです。

Master of Nested Scroll

すいみーさんによるネストスクロールに関する発表です。

JetpackComposeとAndroidViewでのそれぞれの解説に加え、併用する際の実装方法も解説いただきました。 ネストスクロール問題は、AndroidViewから悩みの種でCompose時代の解決策を知れたので、これから導入する場合の考慮すべきことが明確になりました。

speakerdeck.com

Composeへの移行検討中で、ネストスクロール問題を整理したい方お勧めしたいと思います。

まとめ

スピーカーの皆様、スタッフの皆様、1日目お疲れ様でした!

今回参加してJetpackComposeを当たり前に利用している事例が増えていることを実感しました。 弊社でも、そろそろJetpackCompose導入に向けて、計画を立て始めたところなので、よりモチベーションが高まりました。 1日目は、発表を聞く機会が多かったので、2日目は企業ブースにもお邪魔したいと思います。

明日は7月に弊社に参画した中島さんも発表されるので、応援も兼ねて2倍楽しみたいと思います。

2023.droidkaigi.jp

最後にコネヒトでは一緒に働く仲間を募集しています! 興味持っていただけた方は気軽にご連絡ください!

www.wantedly.com

第2回 リーン開発の現場輪読会 プロセス改善や WIP についてワイワイ編

こんにちは!コネヒトのプラットフォームグループでインフラエンジニアをしている @sasashuuu です。最近は VIVANT というドラマにハマっており、クラマックスに向けて目が離せず、日曜が待ち遠しい今日この頃です。

本日は、社内で実施中のリーン開発の現場という本の輪読会の様子についての記事の第2段です!(前回記事: 第1回 リーン開発の現場輪読会 技術課題についてワイワイ編

中盤から終盤へ差し掛かり、輪読会もヒートアップしてきましたので得られたことを本記事でお伝えしていければと思っております。

ちなみに前回の記事でも説明しましたが、現在リーン開発の現場という本を輪読しています。アジャイルソフトウェア開発手法のひとつであるリーンソフトウェア開発手法を、スウェーデンの警察機関のシステム開発で事例をもとに解説した本で、カンバンシステムを中心に書かれています。

リーン開発の現場 カンバンによる大規模プロジェクトの運営 | Henrik Kniberg, 角谷 信太郎, 市谷 聡啓, 藤原 大 |本 | 通販 | Amazon

今回の輪読会では、9 ~ 16章までが対象でした。進め方は前回同様に参加者は事前に各章の内容を読み、「思ったこと」「あるある」「やってみたい」の3つの観点で付箋を miro に書いてくるようにし、当日はそれらをもとにワイワイ話し合うというワークを実施しました。

輪読会でワイワイと話したこと

今回も書き出された付箋から、いくつか「特に話したいこと」をピックアップし、ワイワイと話しました。

今回は以下のようなラインナップのテーマがフォーカスされました。

外部ファシリテータの話

これは「第10章 継続的プロセス改善」で触れられている内容の、チームのでふりかえりの際(スプリント等)に、外部からファシリテーターを連れてきてファシリテートをしてもらうというやり方に着目した際の議論です。 チームにとっても外部ファシリテーターにとっても新たな気づきがあるという点や、チームリーダーがファシリテートを行わないことでじっくりと参加することができるメリットなどが本書では解説されていました。

以下、議論をした際のコメントを抜粋しておきます。

  • チーム外のファシリをすることでお互いのチームに良さそう
  • 自分のチームはファシリテーターは毎回違うが同じようなやり方になっているので、他のチームメンバーがファリシテーターをすることで他の課題の解決の仕方の視点が取り込めそう
  • チームのフェーズも関係しそう。 成熟しているチームは、やり方が固まっているところを見つめ直せるかもしれない。外部ファシリテーターでコンサル的な効果が見込めそうに思う
  • 純粋に他のチームのやり方を知りたい
  • 他のチームの雰囲気を知るのは良さそうだ

WIPとバッファを区別する話

これは「第11章 WIP をマネジメントする」で触れられている内容の、WIP(仕掛かり作業)とバッファを区別するというものに着目した際の議論です。本書ではカンバンボード上のバッファは待ち状態を意味するため、無駄だと解説されており(ただし、開発とテストの間のバッファなど、必要である小さなバッファは例外)、それらを区別しておくことが重要だとされていました。

以下、議論をした際のコメントを抜粋しておきます。

  • WIPとバッファなど時間の使い方や仕事の積み方を意識して使えると今後にとって良くなりそう
  • 職種が分かれていることで、WIPが増えるという状況はあると思う。(ネイティブとバックエンドの開発)
  • 一旦スタブを作って、ネイティブアプリとの連携部分を先に進めるということはやっている(ネイティブとバックエンドの開発)

サイクルタイム計測の話

これは「第12章 プロセスメトリクス」で触れられている内容の、ある作業が完了するまでにかかった時間を計測するサイクルタイムに着目した際の議論です。本書では、ほとんどの人は機能の開発にどれくらいの時間がかかって気がついておらず、実際に開発に費やした時間を知ると恐怖に近い感覚を覚えると書かれていました。また、サイクルタイムを可視化することで WIP 制限のテクニックを行うことで、サイクルタイムの短縮が見込めると解説されていました。

以下、議論をした際のコメントを抜粋しておきます。

  • 定めたポイントをもとに開発タスクの消化量を計測することはやっている
  • ベロシティの計算はやっている
  • サイクルタイムはフロー効率を可視化する意図がありそうに思った 。優先順位が高いものをリリースできているかどうかということの指標になりそう
  • WIPの制限とセットでこの指標を取ると良さそう
  • 作業日数/経過日数で出せると良さそう。実際サイクルタイムはどう取ると良いのだろう?
  • 本書では着手日と終了日を付箋に記入していたようだ、アナログでやっても良いかも
  • Notionだとプロパティで計算できそうだが、みんな使っていない?
  • Zenhubにはreport機能でそういうものがあったかもしれない

テスターからのFBの話

これは「第9章 バグをさばく」で触れられている内容の、バグの対応の際に機能開発チームに存在するテスターと開発者が毎日一緒に働いている様子に着目した際の議論です。

以下、議論をした際のコメントを抜粋しておきます。

  • QAエンジニアの人がいると良さそうに思っている。仕様にFBをもらえたりQAツールに 詳しかったり、テストの行程からFBをもらえると良さそうだ
  • QAエンジニアの採用は計画していないが、最近はMagicPodの導入は検討している

記入された付箋の数々

議論にはあがらなかったものの、それぞれの章で挙がった付箋も紹介しておきます。

第9章 バグをさばく

第10章 継続的プロセス改善

第11章 WIP をマネジメントする

第12章 プロセスメトリクス

第13章 スプリントとリリースの計画

第14章 バージョン管理の方法

第15章 アナログなカンバンボードを使う理由

第16章 僕たちが学んだこと

輪読会実施後の組織の変化

先述した外部ファシリテーターの件は、社内の MTG でも取り入れようというムーブが...!?

最後に

今回は、第2部 9~ 16章の内容を輪読会の様子を発信しました!次回はラストパートの第3部 17~ 21章です!お楽しみに!

本輪読会の本が気になった方はぜひ手に取ってみてください。

リーン開発の現場 カンバンによる大規模プロジェクトの運営 | Henrik Kniberg, 角谷 信太郎, 市谷 聡啓, 藤原 大 |本 | 通販 | Amazon

LLMを用いた機能を "見せること" にこだわり実装する中で工夫したこと

みなさんこんにちは。 MLエンジニアのたかぱいです。

本日は、LLMを用いた機能をリリースするにあたり、どのように実装を進めていったのかをお話したいと思います。
完璧でなくとも実際に動くものを見せることで「触ってもらう→フィードバックをもらう→改善する」といったループを素早く回しながら実装していったよ、という内容になっています。

プロジェクト推進の話に関しては先日公開したブログに書いているので、興味がある方はこちらも見てみてください!

tech.connehito.com


目次


今回実装した機能

一言で言うと「自動で文章の要約を作成してタイトルとして挿入できる」という機能です(以降、タイトル生成と呼びます)

先日のブログ記事でも紹介しましたが、実際にユーザーさんからも反応があり、今後も改善しながらより良いものを作っていきたいと思っています💪

自動で要約を作成して挿入できる、って… ママリ機能すごい✨ たしかにめちゃくちゃ長文で、途中で読むの断念することよくあるから 助かる😂

要約機能が面白くて遊んでしまう!

ママリの要約を挿入するを使ってみました!

AI搭載なんかな??今すごいよね。

以降、バックエンド(ML側の処理)とアプリケーション(iOS側の処理)に分けて、実装プロセスの裏側を紹介していこうと思います。

ML

タイトル生成の裏側の処理には、Open AI APIとLangChainを利用しました。

概要図

プロンプト周りの検証

今回はどのようなプロンプトを作成するか?が肝になってきます。

そこで、まずは過去ママリに投稿されている文章を使い、様々なプロンプトを検証していきました。

ある程度良いプロンプトができたタイミングで、検証用アプリを社内メンバーに配布して、実際にスマホから触ってもらいフィードバックをもらいつつ、プロンプトの微修正を行っていきました。

社内メンバーに協力を仰いでいる図

今回はiOS端末限定で検証していたこともあり、検証用アプリがインストールできない人も何人かいたため、Redash上で同じ機能が触れるようにすることで、なるべく多くの人に使ってもらう工夫もしました。

以下のようなPythonコードをRedashで記述することにより、特定のエンドポイントからのリクエストを取得し、Redashで扱える形式で表示することができます。

import json
import requests

url = 'URL'
payload = {
    'user_id': 9999999,
    'content': "{{content}}"
}

headers = {
    'Content-Type': 'application/json',
    'User-Agent': 'sample-UA'
}

    
response = requests.post(url, json=payload, headers=headers, timeout=(10.0, 17.5))
title = json.loads(response.text)['title']

result = {}
add_result_row(result, {'title': title, 'content': "{{content}}"})
add_result_column(result, 'title', '', 'string')
add_result_column(result, 'content', '', 'string')

redashで検証した時の図

LangChainを用いた実装

LangChain とはGPT-3のようなLLMを利用したサービス開発を支援してくれるライブラリです。

複数のモジュールを組み合わせることで、複雑なLLMアプリケーションを作成するプロセスを簡易化してくれます。

今回は以下のような要約クラスを作成し、ユーザーがママリ上で入力したテキストを要約しています。

import openai
from dotenv import load_dotenv
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

load_dotenv()
openai.api_key = os.environ["OPENAI_API_KEY"]

class OpenAISummarizer:
    def __init__(self, human_message: str) -> None:
        self.llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.2)
        self.delimiter = "####"
        self.system_template = """
            ここにプロンプトを挿入
                      以下のように記述することで、どこからどこまでがユーザー入力文(質問文)かを明確にしている
            The questions are separated by {delimiter} characters.
        """
        self.human_message = human_message

    def _create_prompt_template(self) -> ChatPromptTemplate:

        # systemメッセージプロンプトテンプレートの準備
        system_message_prompt = SystemMessagePromptTemplate.from_template(self.system_template)

        # humanメッセージプロンプトテンプレートの準備
        human_template = """{delimiter}\{human_message}\{delimiter}"""
        human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

        # chatプロンプトテンプレートの準備
        prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

        return prompt

    def run(self):
        # プロンプトの定義
        chat_prompt = self._create_prompt_template()

        # LLMチェーンの準備
        summary_chain = LLMChain(llm=self.llm, prompt=chat_prompt)
        result = summary_chain.run(delimiter=self.delimiter, human_message=self.human_message)

        return result

# 〜リクエストを受け取る部分は省略〜

# 要約の実行
summarizer = OpenAISummarizer(human_message=text)
response = summarizer.run()

LangChainの具体的な使い方などは以下のブログにも書いているので、興味のある方は見てみてください。

tech.connehito.com

以降のiOSパートはiOSエンジニアのゆりこにバトンタッチしてご紹介していきます。

iOS

タイトル生成機能のiOSアプリ実装を担当したゆりこです。

実装の進め方で工夫した点を挙げたいと思います。

全体スケジュール

施策具体化された6月1週目の打ち合わせでPdMより3週間後の4週目のリリースを目標にすることが伝えられました。この段階では仕様・デザインのFixがまだできていない状態。Miroでワイヤーを作りながらディスカッションを行なっていたので大まかな仕様とざっくりデザインはありました。

Miroに書かれた大まかな仕様とざっくりデザイン

アプリ実装担当として、まずは仮実装のものが開発環境で動かせる状態を早く作りたいと思いました。

理由は以下の通りです。

  • 3週間後にリリースするイメージをチームで共有したい
  • 仕様・デザインのFixで時間がかからないようにしたい

( ※ コネヒトではFirebaseのAppDistributionを使いリリース前のバージョンを検証端末として登録しているデバイスに配布することができるようになっています)

実際のところ、3週間後にMiroの大まかな仕様とざっくりとしたデザインが形になりユーザーが使っている状態をチームとしてはまだ想像しきれていなかったと思います。

また、デザイナーもこれまで打ち合わせには参加していないため、デザイン相談するにしてもキャッチアップに時間がかかりそうでした。

このあたりの課題を早い段階に仮実装アプリを配布することで一部解決できるのではと考えました。

当然、機能として動かすにはML側のAPIとの接続も必要でしたが、仮実装ではスピード重視でモックを使いAPI接続なしで動かしました。

最初に配布した仮実装は粗々なものでしたが、PdM・デザイナーに手元のデバイスで動かしてもらったことにより、仕様やデザイン観点ですぐにフィードバックがもらえ、最終的な「良さそう!」がもらえるまでスピード感を持ちながら進めることができました。

結果的に目標通りの期日に機能リリースできた点を踏まえると、粗々なものでも早い段階で仮実装を配布する動き方は施策をスピード感持って進める上で効果的であったと思います。

また開発環境への仮実装配布はチーム外の人も触れる状態になるので、この施策が閉じた環境で動いてないことをアピールする形にもなったと感じます。

この経験を他の施策にも活かしてアプリの機能改善をスピード感持ちながら進めていきたいです!

最後に

コネヒトでは一緒に働く仲間を募集しています! そして興味持っていただけた方は気軽にご連絡ください!

www.wantedly.com

第1回 リーン開発の現場輪読会 技術課題についてワイワイ編

こんにちは。Androidエンジニアのkatsutomuです。 前回に引き続き、狩野英孝さんのマイクラ配信にハマっています。 #12の家の地下が怪しいぞ!の巻のスポナーのくだりには驚愕しました!

さて本日は、社内で実施している輪読会の様子を、紹介したいと思います。 リーン開発の現場を3回に分けて輪読会を実施していく予定です。

コネヒトでは輪読会をはじめとして、共に学び合うカルチャーがあるので、少しでも社内の雰囲気を感じて貰えば嬉しいです。

輪読会の進め方

今回はリーン開発の現場という本を輪読しています。アジャイルソフトウェア開発手法のひとつであるリーンソフトウェア開発手法を、スウェーデンの警察機関のシステム開発で事例をもとに解説した本で、カンバンシステムを中心に書かれています。

リーン開発の現場 カンバンによる大規模プロジェクトの運営 | Henrik Kniberg, 角谷 信太郎, 市谷 聡啓, 藤原 大 |本 | 通販 | Amazon

コネヒトでもGithub ProjectsやZenhubで、カンバンを活用して開発を進めているので、業務のヒントを見つけるべく、有志を募って輪読会の開催に至りました。

そこそこボリュームのある本なのでそれぞれが個別で読み、事前に付箋を書く方法ですすめています。初回は第1章から第8章までが対象として、「思ったこと」「あるある」「やってみたい」の3つの観点で事前に付箋を書いてくるようにしました。

参加メンバーのお声

最初に、参加メンバーから感想を紹介します。

ささしゅう

技術課題の話で盛り上がる場面があったが、自身が所属しているプラットフォームグループのミッションとしても知りたい内容だったのでよかった。また、技術課題とは別の内容に比重をおいて本書を読み解くメンバーもいて、色々な視点を養えてよかった。

ほみちゃん

YuyaAboの話を聞いて捉え方が変わった。技術課題を解決することで、事業にどのような影響があるかは考えられていなかったので、いいきっかけになった。

otukutun

編成が違うプロジェクトのチームの事例が色々知れたので、今後の引き出しになると思った。 今のチームにどれぐらい当てはめられるかは、状況も違うのでしっかりと考えたい。

YuyaAbo

ボトルネックが可視化される一つの物理看板がすごい良いと思って読んでいた。 技術課題もボトルネックを解消するための一つの要素として扱うなど新鮮だった。今後も楽しみ。

それぞれ、何かしら学びを得られたと思いますし、今後の期待についてのコメントもあり、嬉しい限りです。この感想だけで満足せず、開発フローの改善もトライしていきたいと思います。

輪読会でワイワイと話したこと

当日は上げられた付箋から、いくつか「特に話したいこと」をピックアップし、社内の課題と合わせて1時間程度ワイワイと話しました。

今回は「第8章 技術課題をさばく」の内容が多くふれられ、

  • 技術課題をどう可視化するか
  • チームや組織で、どう管理するか
  • そもそも、どのように技術課題は捉えているか

というようなことが主題になりました。

この本には、技術課題の取捨選択のエピソードとして、開発フローのボトルネックになっている課題や、管理不能なクラスのリファクタリングの必要性を示すために、クラス全体を紙にプリントアウトした長さを元に、技術課題として対処すべきことを決める様子が書かれています。

それらエピソードから、開発のリードタイムを下げるなど事業的な価値と関連づけることが重要なのではないかという話に落ち着きました。

記入された付箋の数々

せっかくなので、今回の輪読会で上がった付箋を紹介します。

第1章 プロジェクトについて

第2章 チーム編成

第3章 デイリーカクテルパーティに参加しよう

第4章 プロジェクトボード

第5章 看板ボードをスケールさせる

第6章 プロジェクトのゴールを追え!

第7章 準備OKを定義する

第8章 技術課題を捌く

個人的な推し付箋は以下の2つです。

それぞれ4章プロジェクトボードと、8章技術課題を捌くで上げられた付箋です。 この2つを推している理由は、、今回、筆者が輪読会を開催した理由の一つに、開発フローのブロッキング要素可視化や技術課題の扱い方の事例を学び、チーム改善の種にしたいというモチベーションがあり、それが叶ったと感じた為です。

最後に

今回は、開発フローの改善のきっかけとして輪読会を実施した様子をお伝えしました。 今後は輪読会をきっかけに、どんな変化が起きたかもお伝えする機会を作れればと考えています。まずは、第2部 9~ 16章の内容を輪読会する予定です!

カンバンの運用に課題感を感じている方がいたら、ぜひ一度お手に取っていただくと良いかと思います。

リーン開発の現場 カンバンによる大規模プロジェクトの運営 | Henrik Kniberg, 角谷 信太郎, 市谷 聡啓, 藤原 大 |本 | 通販 | Amazon

そして、コネヒトでは一緒に働く仲間を募集しています! 興味持っていただけた方は気軽にご連絡ください!

www.wantedly.com

開発体験向上のためのプラットフォームエンジニアリング事例 - カナリアリリースをアプリケーションエンジニアだけで完結できるように改善した話

こんにちは。コネヒトの開発部プラットフォームグループでインフラエンジニアをしている @sasashuuu です。本日は私の所属するチームが最近興味・関心を持って取り組んでいるプラットフォームエンジニアリングの話題について取り上げたいと思います。弊社で行っていたカナリアリリースの運用改善の話になります。

はじめに

はじめに本記事の中心となるプラットフォームエンジニアリングとカナリアリリースの概要について簡単に触れておきます。

プラットフォームエンジニアリングとは、誤解を恐れずに端的に言えばアプリケーション開発者のためのプラットフォームの開発と提供を行うアプローチのことで、Gartner 社の プラットフォーム・エンジニアリングとは何か? の記事では下記のように解説されています。

「プラットフォーム・エンジニアリング」とは、アプリケーションのデリバリとビジネス価値の創出を加速させるための、テクノロジに対する新しいアプローチです。

  • プラットフォーム・エンジニアリングは、再利用可能なツールとセルフサービス機能を実装し、インフラストラクチャ・オペレーションを自動化することで、開発者のエクスペリエンスと生産性を向上させる
  • 新たなテクノロジのアプローチであるプラットフォーム・エンジニアリングは、アプリケーションの再利用可能で構成可能なコンポーネントとサービスを活用する
  • ユーザーにとっては、標準化されたツールとコンポーネント、そして自動化されたプロセスを利用できるというメリットがある

カナリアリリースとは、アプリケーションをユーザー全体に公開するのではなく、配信対象者を一部に絞った形で公開する手法の1つです。

なぜ今プラットフォームエンジニアリングなのか

弊社では会社設立とサービスの公開から10周年の節目を迎え、プロダクトの成長を考える上でも重要な局面を迎えています。 そのような中、プロダクト開発の前線で働く社内のエンジニアのボトルネックになっている部分を解消し、開発体験を上げることで、開発力の向上を図りたいと考え、この領域に力を入れていきたいと考えています。その取り組みの一環として、開発体験を下げる要因の1つであった弊社のカナリアリリースの運用課題に向き合いました。

前提となる環境

今回の事例では主に下記の技術スタックなどから構成される内容がメインとなっております。

  • インフラ環境
    • AWS
    • Docker
  • アプリケーション環境
    • PHP
    • CakePHP
  • CI/CD
    • GitHub Actions

改善の全体像

ざっくりと改善内容のイメージを掴んでいただくために、改善前の状態と改善後の状態を図で表したものを紹介します。詳細は追って解説していきます。

背景・課題感

弊社でもランタイムやフレームワークのバージョンアップ作業など、アプリケーションにおいて影響度の大きいリリースに関しては、カナリアリリースを用いてリリース作業を行なっています。しかし、運用面で抱える課題感がありました。

元々行なっていたカナリアリリースの流れは下記のようなものです。

上記のフローにはそれぞれ課題感がありました。

チームを跨いだ調整コストや反映漏れのリスク

最初にアプリケーションエンジニアからインフラエンジニアへカナリアリリースの対応依頼が来ます。互いにスケジュールなどを調整し、リリースの日時などを決めていましたが、チームを跨いだ調整コストなどがかかっていました。

さらに、アプリケーションエンジニアからコードフリーズ の確認や連絡を受けてからインフラエンジニアが手動で ECR 用の Docker イメージを build し、 push していたので、調整コストの発生や反映漏れ発生のリスクなどがありました。

作業時の人的リソースやコミュニケーションコスト

リリース当日は、基本的に上記のような作業をインフラエンジニアが行い、アプリケーションエンジニアがアプリケーションの状況を監視しつつトラフィック割合の変更に関する意思決定を行い、インフラエンジニアがトラフィック割合を調整していくというような連携を取っていました。リリース作業ではアプリケーションエンジニアとインフラエンジニア数名が同期的に集まり作業を行なっていましたが、作業内容に対する人的リソースやコミュニケーションコストが少なくない印象でした。またリリース作業自体のオペレーションに関しては、高度なインフラ技術が求められるものではなく、権限さえあれば手順に沿ってインフラエンジニア以外も行えるような内容でした。

改善によりもたらされた効果

改善後は下記のようになりました。改善前のフローも再度併せて並べておきます。

before

after

上記のような運用に改善したことで抱えていた課題感などが解消されました。

手動作業の自動化を図り作業をインフラエンジニアから手離れ

GitHub Actions のワークフローを実行するとカナリアリリース用 Docker イメージの ECR への push から ECS のタスク定義およびサービスの更新を一貫して行なってくれるため、カナリア環境の立ち上げにインフラエンジニアが干渉することなく、アプリケーションエンジニアに独力でやってもらえるようになりました。 Manually running a workflow に記載のように、ブランチ指定をしワークフローを手動実行できるようにしたことで、アプリケーションエンジニアの任意のタイミングでカナリア環境を立ち上げられるようにしました。 ワークフローでは ECR 用のイメージの build ~ push を自動化した他、デプロイツールに kayac/ecspresso を使用することで、カナリア環境へのデプロイを簡素化しました。

また、GNU Make とシェルスクリプトで実装したタスクランナーを導入しました。 カナリア環境へのトラフィックを ALB の加重ルーティングで調整するツールとなっており、実装内容は AWS CLI のコマンドを make コマンドのインターフェースで実行するというものです。

こちらはイメージがつきにくいかもしれないので、サンプルコードの一部を載せておきます。

Makefile

.PHONY: {カナリアリリース対象のプロダクト名}_modify_weighted_routing
{カナリアリリース対象のプロダクト名}_modify_weighted_routing:
    bash utils/modify_weighted_routing.sh {カナリアリリース対象のプロダクト名}

modify_weighted_routing.sh

#!/bin/bash

set -eu

# カナリアリリース対象のプロダクト名
TARGET_PRODUCT_NAME=$1
# カナリア・本番環境の加重ルーティング割合(%)
CANARY_PERCENTAGE=1
PRD_PERCENTAGE=99
# HTTP・HTTPSのリスナーのarn
HTTP_LISTNER_ARN=
HTTPS_LISTNER_ARN=
# カナリア・本番環境のターゲットグループのarn
CANARY_TARGET_GROUP_ARN=
PRD_TARGET_GROUP_ARN=

# メイン関数
function main () {
    echo "${TARGET_PRODUCT_NAME}の加重ルーティング割合変更開始。"
        # 対象プロダクト固有の設定情報読み込み
    source ./env/${TARGET_PRODUCT_NAME}
        # 加重ルーティング割合のセット
    set_weight_percentage
        # リスナーのデフォルトアクション変更
    modify_default_actions $HTTP_LISTNER_ARN $HTTPS_LISTNER_ARN
    echo "加重ルーティング変更完了。"
    ./utils/describe_weighted_routing.sh $TARGET_PRODUCT_NAME
}

# 加重ルーティング割合(%)のセット
function set_weight_percentage () {
    read -p "カナリア環境へdeployする割合(%)を入力してください: " P
    if [[ ! $P =~ ^([0-9]|1[0-9]|2[0-9]|30)$ ]]; then
        echo "半角数字0から30の間で設定してください。"
        set_weight_percentage
    fi
    TMP_PERCENTAGE=$P
    read -p "${TMP_PERCENTAGE}%で投入します。よろしいですか?(y/N): " YN
    if [[ $YN = y ]]; then
        CANARY_PERCENTAGE=$TMP_PERCENTAGE
        PRD_PERCENTAGE=$(( 100 - $CANARY_PERCENTAGE))
    else
        set_weight_percentage
    fi
}

# リスナーのデフォルトアクション変更
function modify_default_actions () {
    # 引数(リスナー)の数だけ変更をかける
    for i in $@
    do
# aws cli利用時の--cli-input-json指定のためのパラメータを別ファイルで作成
cat << EOF > utils/parameter.json
{
"DefaultActions": [
    {
        "Type": "forward",
        "ForwardConfig": {
            "TargetGroups": [
                {
                    "TargetGroupArn": "${PRD_TARGET_GROUP_ARN}",
                    "Weight": ${PRD_PERCENTAGE}
                },
                {
                    "TargetGroupArn": "${CANARY_TARGET_GROUP_ARN}",
                    "Weight": ${CANARY_PERCENTAGE}
                }
            ]
        }
    }
]
}
EOF
    aws elbv2 modify-listener --listener-arn $i --cli-input-json file://utils/parameter.json
    trap "rm utils/parameter.json" 0 1 2 3 15
    done
}

# 全体処理の実行
main

コマンド実行例

% make {カナリアリリース対象のプロダクト名}_modify_weighted_routing
bash utils/modify_weighted_routing.sh {カナリアリリース対象のプロダクト名}
{カナリアリリース対象のプロダクト名}の加重ルーティング変更開始。
カナリア環境へdeployする割合(%)を入力してください:

かつてインフラエンジニアが AWS コンソールから手動で調整していたカナリアリリースの割合を調整する作業をタスクランナーに落とし込みました。これにより、カナリア環境へのトラフィックの調整作業がアプリケーションエンジニアで手軽にできるようになりました。

作業時の人的リソースやコミュニケーションコスト削減

リリース作業時にアプリケーションエンジニアとインフラエンジニアが同期的に集まって行なっていたやり方を改善することができ、アプリケーションエンジニア主導のもとカナリアリリースの加重調整の判断と調整作業を一貫して行えるようになりました。これにより、作業にかかる人的リソースやコミュニケーションコストを削減することができました。アプリケーションエンジニア主導で作業を進めてもらいつつ、何か問題があった際にインフラエンジニアがフォローに入るという効率的な運用を行える体制をつくることができました。

開発体験の向上

先述していた改善効果により、チームを跨いだ調整コストや人的リソースを削減し、アプリケーションエンジニアがカナリアリリースを行うハードルを下げることで開発体験の向上をもたらせたと感じています。

おわりに

コネヒトでは現在、プラットフォームグループと呼ばれるプラットフォームエンジニアリング促進しようとするインフラエンジニアのチームが存在しており、アプリケーションの安定稼働や障害対応はもちろんのこと、プラットフォームエンジニアリングにも注力していこうという動きが盛んです。社内のエンジニアの開発体験を向上すべく日々奮闘中ですので、ご興味のある方は今後の私たちの動きなどにもぜひ注目してもらえると嬉しいです。