はじめに こんにちは、フロントエンドエンジニアの中畑 ( @yn2011 ) です。 au Webポータル 無料ゲーム では様々なフロントエンドのパフォーマンス最適化に取り組んでいます。今回は、既に実施した最適化の中から 対応コストが小さく、効果が分かりやすかったもの を中心に、対応事例のご紹介をします。 なお、 au Webポータル 無料ゲーム は Jamstack 構成となっており、Next.js (SSG) と ヘッドレスCMS を利用しております。詳細な技術スタックについては ヘッドレス CMS 運用におけるデプロイと環境差分について に記載がありますので、ぜひこちらもご覧ください。 Lighthouse による測定結果 パフォーマンスの最適化を行う前の状態で、Lighthouse の測定結果は以下のようになっていました。 指標 指標の意味 結果 First Contentful Paint テキストまたは画像が初めてペイントされるまでにかかった時間 2.3 秒 Speed Index ページのコンテンツが取り込まれて表示される速さ 3.7 秒 Largest Contentful Paint 最も大きなテキストまたは画像が描画されるまでにかかった時間 9.1 秒 Time to Interactive ページが完全に操作可能になるのに要する時間 8.9 秒 Total Blocking Time タスクの処理時間が 50 ミリ秒を上回った場合の、コンテンツの初回描画から操作可能になるまでの合計時間 1,720 ミリ秒 Cumulative Layout Shift ビューポート内の視覚要素がどのくらい移動しているか 0 測定結果を見ると、Largest Contentful Paint、Total Blocking Time は特に改善の余地がありそうでした。今回は、この測定結果を元に、実装コストが小さく・既存の機能に対する影響も小さいと判断した以下の 3 つの最適化についてご紹介します。 ピックアップバナーの preload au Webポータル 無料ゲーム のトップページは以下のようになっており、画面の大部分をゲームタイトルのバナー(ピックアップバナー)が占めています。 トップページにアクセスした際に、ピックアップバナーの画像を優先的に読み込むことで Largest Contentful Paint の数値を改善しユーザが体験する画面表示までの速度を高めることができます。 実装としては、以下のような要素を HTML に追加するだけで実現可能です。 <link rel="preload" href="https://url-to-image" as="image" /> 外部ドメインに対するリクエストの preconnect au Webポータル 無料ゲーム では、広告の表示やデータ分析のために外部ドメインに対してリクエストを行います。 リクエスト先の外部ドメインが予め分かっている場合には、事前に DNS Lookup、Initial Connection、SSL を済ませておくことでリクエストが要求されてからレスポンスを得るまでの時間を短縮することができます。 実装としては、以下のような要素を追加するだけで実現可能です。 <link rel="preconnect" href="//other.domain.com" /> Chrome DevTools の Network タブを利用して確認すると、preconnect 指定前は以下であったのに対し preconnect 指定後に確認すると、各フェーズに使用される時間が短くなりました。 なお、preconnect の他に、dns-prefetch を属性値として指定する方法もあります。両者の特徴を比較すると、preconnect の方が多くの処理を事前に行うことができる反面、ブラウザのサポート範囲は dns-prefetch よりは狭いです。 dns-prefetch preconncet ブラウザサポート ○ △ DNS Lookup ○ ○ Initial Connection、SSL ☓ ○ 以下のようにフォールバックとして両方を指定することも可能なそうですが、 WebKit では動作しないという報告 がありました。 <link rel="dns-prefetch preconnect" href="//other.domain.com" /> preconnect は、あくまでパフォーマンス改善のための nice to have な対応であり一部ブラウザが対応していなくても動作自体に影響はないため preconncet のみを利用する判断をしました。 Google オプティマイズのスクリプトを常に読み込まない au Webポータル 無料ゲーム では、A/B テストを実施するために、Google オプティマイズを利用しています。そのため、Google オプティマイズのスクリプトを必ず読み込んでいました。 <script src="https://www.googleoptimize.com/optimize.js?id=OPT_CONTAINER_ID" /> しかし、A/B テストは常に実施しているわけではないため A/B テストを実施していない期間については不要なリソースの読み込みとスクリプトの実行が発生してしまっていました。 au Webポータル 無料ゲーム は、Next.js の SSG を利用しているので、 A/B テストを実施していなければビルド時に Google オプティマイズのスクリプトタグを含めないように変更しました。 A/B テストを実施しているかの判定は、利用しているヘッドレスCMS に特定のレコードが存在するかどうかで行っています。 実装としては以下のように、 _app.tsx の getInitialProps で 判定を行い Props にフラグを追加しました。 static async getInitialProps() { ... return { pageProps: {}, isOptimizeRunning: !!config.experiments && config.experiments.length > 0 } } この isOptimizeRunning を利用し、レンダー時にスクリプトタグを含めるかどうかを決定します。 {isOptimizeRunning && ( <script src="https://www.googleoptimize.com/optimize.js?id=%24%7BOPT_CONTAINER_ID" /> )} 改善の結果 以上の最適化を行い、Lighthouse を再実行すると測定結果は以下になりました。 指標 前 後 改善率(%) First Contentful Paint 2.3 秒 1.3 秒 43.48 Speed Index 3.7 秒 3.0 秒 18.92 Largest Contentful Paint 9.1 秒 6.2 秒 31.87 Time to Interactive 8.9 秒 8.6 秒 3.37 Total Blocking Time 1,720 ミリ秒 1,550 ミリ秒 9.88 Cumulative Layout Shift 0 0 0.00 画面描画に関する指標(First Contentful Paint、Speed Index、Largest Contentful Paint)を中心に大きく数値が改善しました。トータルのスコア自体も 38 → 44 と上昇しました。 おわりに au Webポータル 無料ゲーム で実施したフロントエンドパフォーマンスの最適化についてご紹介しました。 個人的には、パフォーマンスの最適化というと難しそう、調査や実装に多くの時間が必要になりそう、といった先入観がありましたが、意外と簡単に実装できて成果に繋げられるものもあるんだな、という学びがありました。 今回ご紹介したものは、 実際に取り組んだパフォーマンスの最適化の中の一部であり、実際にはもっと実装の変更が大きく、既存機能への影響を考慮しなけばならないものも多くありました。 それらについては、また別の機会にお伝えできればと思います。 最後までお読み頂きありがとうございました。
SrManager の尾野です。 2021/03/17(水)にKDDIグループ6社合同でテックカンファレンスを開催しました。 今回、コミュニティの立ち上げから運営まで携わりましたので、雑感と今後について触れたいと思います。 (このアイキャッチは コネヒト社 の方がデザインしてくださいました。) KGDC is 何 KGDCは「 K DDI G roup D eveloper C ommunity」の略です。 ”KDDI グループ企業各社の Developer が集い、「エンジニアが楽しめる」イベントを提供するコミュニティ” をコンセプトに立ち上がりました。 connpass グループページ connpass イベントページ(現在は終了しております) 弊社 お知らせ 弊社からは VPoE 新井:パネルディスカッション CTO準備室室長補佐 曽根:セッション カルロス(フロントエンドエンジニア): LT にも登壇していただきました。 なぜやることになったのか? 思いつき です。 個人的に繋がりのあった コネヒト社の CTO と Supership 社の CTO に「一緒にイベントやったら楽しそうじゃないですかね?」と雑にお声掛けさせてもらったのがきっかけです。 KDDIグループ、実は多彩なんです。 そんな事が多くの方に伝われば良いなと思って企てました。 どうやって進めていったのか? 招集 時間軸で言うと 2020年12月初頭です。 弊社社長の江幡にも協力を頂き、 共催企業 にお声掛けしました。 共催企業は弊社含め全 6 社、快く共催について賛同を頂きました。 運営準備 各社運営にご協力いただける方をアサイン頂き、実行に移ったのが年明けすぐ 2021年01月初頭でした。(運営メンバーは総勢20人程) 私自身もゼロイチでコミュニティを立ち上げる経験が無く、各社知見のある方と相談しながらTODOやロードマップを立てていきました。 ざっくりと以下の分担で各社割り振り、進めて行きました。 配信チーム オンライン配信におけるツールやコミュニケーションに意思決定を持つチーム コンテンツチーム コンテンツやタイムテーブルに意思決定を持つチーム プロモーションチーム 拡散/集客方法に意思決定を持つチーム 司会チーム 当日の司会進行など また、週次で集まり各チームのTODOや進捗/課題などを吸い上げて進行していきました。 主に scrapbox 上でログを残しながら、専用の Slack workspace 上で連携を取りながら進めていくスタイルを取りました。 当日に至るまで、開催日の変更や緊急事態宣言の延長など、大きな予定変更がありながらも運営メンバーの皆様が臨機応変に対応してくれました。 開催前日のお気持ち Slack 投稿です。 (共同司会の KDDI Web Communications 葛さんのなんと上手い事か。圧巻でした。) 当日 connpass 上での参加申し込み: 233 名 当日 Zoom 参加も常時 100 人以上のイベント規模となりました。 当日司会進行しながら聞いていて、非常にバラエティに富んだラインナップだったと実感しました。 KDDIグループ、実は多彩なんです。 全登壇者が時間超過する事なく進行出来たのは、登壇者の皆様がすごかった(語彙力)というのもありますが、裏でタイムキープをしてくれた 弊社 下地/五月女 のきめ細やかさのお陰というのもあります。 全量ではありませんが、当日セッション/LT資料は こちら に上がっております。 さいごに 執筆時点、次回開催に向けて検討を進めております。 次回は #1 として、もっと大々的に打ち出しながら開催していければと考えております。 KDDIグループで協力しながら、もっとグループ全体を盛り上げて行ければと思っております。 また、快く共催に賛同してくださり、運営に携わってくださったグループ企業の皆様には厚く御礼申し上げます。 共催企業(敬称略) iret https://www.iret.co.jp/ au コマース&ライフ https://www.au-cl.co.jp/ KDDI Web Communications https://www.kddi-webcommunications.co.jp/ コネヒト https://connehito.com/ Supership https://supership.jp/ KDDIグループ、実は多彩なんです。 その中でも ユーザー中心な “ものづくりCompany” を目指す mediba で一緒にものづくりしてくれるメンバーを随時募集しております。
こんにちは。下地と申します。 私のロールはエンジニアリングマネージャー(以下、EM)なのですが、EMと言っても組織によってコミットする領域や振る舞い等が違うと思います。そこでmedibaにおけるEMとしての業務内容をまとめ、どの領域にコミットしているのかを整理したいと思います。 ※他EMとやり方を同期しているわけではないのであくまで私がEMとして実施している範囲の解説になります。予めご了承下さい。 主な業務 medibaにおけるEMはピープルマネージメントを軸にしておりプロダクトに1人のEMを配置しチームを運営しています。主な業務としてピープルマネージメント、組織運営、プロダクト開発の3領域にわける事ができます。 ピープルマネージメント メンバー(ヒト)に向き合い、成長や育成にコミットすることで、組織の成果を最大化する事を目指します。ただ、成長や育成はあくまで個人に依存していると考えているので主に場を整えたり、作る事を意識し支援する事を重点に置いています。 1on1の実施 毎週30分メンバーと話しています。話す内容はメンバーによってバラバラで雑談や、趣味、業務のお困りごと、目標等についてお話します。リモートワーク中心の業務なのでメンタルチェックも兼ねて実施しています。 各メンバーの成長支援の創造 コンフリクトの解消や場を整備しパフォーマンスが出せる環境を提供するよう心がけ支援します。私の考える理想のEM像は部活動におけるマネージャーなので、雑務やパフォーマンスに影響がある箇所は1on1を通し情報収集を行い対応します。 組織運営 ミドルマネージャーの主な業務が詰まっている領域です。medibaのEMも例外ではありません。詳細は割愛しますが、評価は良いところにフォーカスし価値を高めていく事を意識しています。 評価 採用面接 組織KPIのコミット 広報活動 プロダクト開発 書籍、ティール組織にある”助言プロセス”を取り入れフォローしています。 助言プロセスとは 原則として、組織内のだれかがどんな決定も下してもかまわない。 ただしその前にすべての関係者とその問題の専門家に助言を求めなければならない。 決定を下そうという人には、一つ一つの助言をすべて取り入れる義務はない ※書籍"ティール組織 ― マネジメントの常識を覆す次世代型組織の出現"から抜粋 プロダクト、メンバーのボトルネックの解消 開発プロセスや、プロダクトの課題解決は助言プロセス主体で進めるものの、プロダクト全体のボトルネックや、他職能マネージャーとの調整やメンバー間のトラブル解消等は全体を俯瞰して見ているEMが対応します。このボトルネックの解消は、EMの多岐に渡る業務の中で1番優先度が高い業務としています。 意思決定が必要なMTGへの参加 施策出しやリリース等々のMTGはあまり参加しないものの意思決定が必要なMTGには積極的に参加しています。テキストで対応するより会話した方が意思も伝えやすいと考えています。 障害時の取りまとめ EMが指揮を取り影響範囲等を調査報告します。他マネージャーとの連携が必要なのと最終的にEMが報告するので積極的に対応します。 プロジェクトマネージャー業務 メンバーが実施する事もありますが他マネージャーや他部署との連携が必要な場合EMが対応します。 技術選定 組織としての技術選定の観点として売上/利益、今後の展望、成長のバランスを意識し事業内容でどこにBETするかを判断しています。売上/利益重視なら得意なスタック、今後の展望を重視するなら既存スタックにとらわれず最適なスタックを選定といった具合です。 まとめ medibaの主なEM業をまとめて見ましたが如何でしょうか?私自身はコードを書く業務には携われていないのでハードスキルが止まっているものの、1on1等で視座があがっていくメンバーや、仕事が楽しいと言ってくれるメンバー、業務の幅を広げ活躍できる領域を広げるメンバー等の成長を近くで実感できるのは非常に気持ちがよくEMのやりがいを感じます。 今回は組織運営パートの詳細は割愛していますが機会があれば言語化したいと思います。 最後になりますが、現在medibaでは EMを募集 をしています。 少しでも興味を持って頂けたら応募してもらえると幸いです。 余談 EMトライアングル とはEMの役割をグラフィックモデル化したものです。以下の図はEMトライアングルに主な作業領域に色をつけ可視化したものになります。medibaではTechnology - Team領域を主軸に活動している事もあり全領域を網羅する形となっています。こちらも参考にして頂けると幸いです
はじめに medibaの野崎です。 バックエンドエンジニアとしてバックエンドアプリケーションやインフラストラクチャーの運用を行っています。 また,兼務でテクノロジーセンターにてTechLeadチームにも所属しています。 昨年よりau Webポータルの運用チームに担当となりました。 au Webポータルの運用チームは、複数のシステムを運用しています。 大半のシステムが初期開発から数年経過しインフラストラクチャー(AWSリソース)を手動で変更するような業務となっており、後述するような課題が多く見受けられました。 本記事では、その改善のために行った 既存システムのインフラストラクチャーのコード化 - Infrastructure as Code(IaC)を進めたプロセスを紹介したい と思います。 インフラストラクチャーを手動で変更する場合の課題 所属するチームではこれまで以下のような業務の流れになっておりインフラストラクチャー(AWSリソース)を手動で変更していました。 ※弊社ではバックエンドエンジニアとインフラエンジニアにロールが分かれています。 変更内容をバックエンドエンジニアが作成し、インフラエンジニアに変更依頼を行う その変更内容を元にインフラエンジニアがAWSマネージメントコンソールを介して変更作業を行う このような業務の大きな課題として以下のような点が挙がっていました。 AWSリソースの管理がインフラエンジニアに属人的にとなる バックエンドエンジニアからの変更依頼が多い際には、変更作業にリードタイムが発生する 変更履歴が残らず、組織変更に柔軟に対応できない こういった課題の解決のため、 まず既存システムのインフラストラクチャーのコード化 - Infrastructure as Code(IaC) を検討しました。 バックエンドエンジニアもコードを介して、AWSリソースの変更管理を行って貰うためです。 どのように既存システムリソースをインフラコード化するか 弊社では新規開発時にInfrastructure as Code(IaC)ツールとしてTerraformを利用することが多いため、Terraform利用を前提にしました。 既存のリソースをTerraformのコード化するには、 terraform import コマンドを使うことになります。 しかし、このコマンドはAWSのリソースを1点ずつ指定する必要があります。 参考: https://www.terraform.io/docs/cli/import/index.html 今回の対象システムのリソース数は 数100 あり、この方法でコード化するのは現実的ではありませんでした。 そこで今回はTerraformerというツールを使い、既存システムのTeraformコードの生成を行いました。 以下では、その実施手順を記載します。 参考: https://github.com/GoogleCloudPlatform/terraformer Terraformerは、既存のシステムからTerraformコードとそのstateファイル(tfstate)を生成するCLIツールです。 Terrformerによる既存システムのコード化の実施 今回のシステムは以下のような前提として記載していきます。 システムの環境は、開発環境(dev環境)と商用環境(prd環境)に分かれている 各環境ごとに、AWSアカウントが1つずつある 東京リージョンを利用している ローカルPCとして、macOSを使う 1. コード化対象のシステムの確認 Terraformerの README.md にAWSに対応しているサービスが記載されています。これらから対象システムのうちコード化したいサービスについてリージョンごとにリスト化しておきます。 (例: 東京リージョンにてacm,alb,ec2_instanceなど) また、AWSのグローバルサービスについても同様にリスト化しておきます。 (例: iam,route53,wafなど) 2. Terrformerコマンド実行し、コードを生成する 以下のツールをローカルPCにインストールします tfenv Terraformのバージョンを管理するツール https://github.com/tfutils/tfenv 利用したバージョン: 2.0.0 Terraformer 既存システムからTerraformのコードとstateファイルを生成するツール * https://github.com/GoogleCloudPlatform/terraformer 利用したバージョン: 0.8.11 次に適当なディレクトリを作成し、以下のファイルを作成します。 init.tf .terraform-version ファイルには以下のように記載します。 $ echo 'provider "aws" {}' > init.tf $ echo '0.11.14' > .terraform-version 次に terraformer import コマンドでコードの生成を行います。 このコマンドのフラグはいくつかありますが、今回はシステムに合わせて以下のようにしました。 フラグ regions は、生成対象のサービスのリージョンを指定する。 今回は東京リージョンとグローバルサービスにそれぞれ分けて指定する。 フラグ resources には、「1. コード化対象のシステムの確認」で確認したサービスをリージョンごとに記載する。 フラグ path-pattern は、生成するコードの配置ディレクトリを指定する。 ※tfenvにて 0.11.14 としている理由 TerraformerのAWSプロバイダーの生成するコードが 0.11(HCL1)系のものになるためです。 README.md などを見ると_0.13 対応などの記述もありましたが、コードを確認したり実際にコマンドを実行しましたが、現在のところ 0.11系 でしか生成出来ないようでした。 #対象が東京リージョンにあるサービス $ terraformer import aws \ --resources=acm,alb,ec2_instance,eip,elasticache,igw,nat,nacl,rds,route_table,s3,sg,sns,sqs,subnet,waf_regional,vpc,vpc_peering \ --path-pattern aws-service/dev/ap-northeast-1 \ --regions=ap-northeast-1 #対象がグローバルサービス $ terraformer import aws \ --resources=cloudfront,route53,waf,iam \ --path-pattern aws-service/dev/global/ \ --regions=global このコマンドを実行すると、以下のようにtfファイルとtfstateファイルが生成されます。 ※スクリーンショットでは、フォルダを閉じていますが_globalディレクトリの配下にもtfファイルとtfstateファイルが作成されています。 3. コードの修正とapply 生成したコードをチーム開発で使えるようにコードの修正をいくつか行いました。以下に今回実施したことを簡単にリストします。 これらは開発チームの状況や対象システムによって異なるため、参考までに留めてください。 Teraformのバージョンアップ 前述したように、生成したコードは 0.11 のものとして作成されています 運用するバージョンに合わせて、Terraformの terraform 0.12upgrade コマンド等を使い、コード修正を行います 参考: https://www.terraform.io/upgrade-guides/0-12.html 管理不要なAWSリソースをTeraform管理外とする 例えば、defaultのvpcなどは運用上管理が不要なので、この時点で管理外としておきます tfstateをローカルからS3に移動 最後に生成・修正したコードを元に実際の環境に terraform apply を実行します。 一見差分が出ないように思われますが、今回実行した場合いくつか差分が出ました。 一例として、Route53があります。providerにて comment のdefault値が Managed by Terraform となっているため、これ以外の文字列が実リソースに設定されていれば、差分となります。 参考: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone#argument-reference このような差分は1点ずつ確認しながら、コードの修正(差分を ignore_changes に設定する)または apply を行い、 最終的にコードとの差分を無くします。 チーム開発を始める ここまでで既存システムをコード管理下に置くことが出来ました。 今回はさらにバックエンドエンジニアを対象に Terraformの使い方やAWSリソースそのものについて勉強会などを行い、IaCでの開発に必要な知識を理解して貰いました。 その上で簡単な変更作業を切り出しながら、Infrastructure as Code(IaC)での開発に慣れて貰っています。 最後に 弊社のようなシステムの安定性と変更容易性を高いレベルで両立しなければいけない組織では、Infrastructure as Code(IaC)は非常に大切なプロセスだと考えています。 今回の取り組みは改善の第一歩であり、 継続的に今回のプロセスを維持・改善しつつ、組織的にもスキルの向上を高めていけるように、今後も取り組みを続けていきたいと考えています。 medibaでは、システムを深く理解し関わる組織の理解も鑑みながら、よりよいサービス運用をともに検討していただけるようなエンジニアのご応募をお待ちしています。 以上になります。
こんにちは。武田( @tkdn )です。 納得度の高いプロダクト開発とは何だったのか 前編 では、プロダクト開発に際して直接的な関与ができていない原因は、自分の中の無知・無関心にあったというところで終えました。 後編ではプロダクトマネジメントを意識しながら、どうやってものを作ろうとしているかについて書いていきます。前編よりは実践的になっているはずです。取り組みのご参考にされてください。 プロダクトマネジメントを意識する 昨年 11 月にキリの良い大きなリリースがあったため 12 月から 3 つプロダクトを抱えたチームは二手に分かれ、私は au Web ポータル無料ゲームというプロダクトの担当となりました( ヘッドレス CMS による運用についてこのブログでも触れたプロダクトです )。 まず取り掛かったことはプロダクトオーナー(以降 PO)に張り付いた業務を剥がすことと、プロダクトマネジメントの理解でした。 PO はステークホルダーからは期限を迫られ、開発からはできるか分からんと言われ、事業部全体では数字が足りないと言われる。それだけならまだしも、ミーティングや調整が多く、肝心なプロダクトのことやプロダクトが提供するユーザー価値や収益バランスについて深く考える時間の余裕があまりなさそうでした。 同時にプロダクトマネジメントについて理解を深めることで、PO の負担を減らすだけでなく、プロダクトチームを正しいものづくりに持っていく必要があると考えたのです。前編でも一部引用したように プロダクトマネジメント は非常に強力な書籍となり、ここまでの活動を支えています。 PO やプロダクトマネージャーに委任することなく、現場で正しいと思ったことはすべて現場で取り組もうと考えたのです。 関心を持つための根幹を定義する プロダクトチームが施策の優先度や意思決定の場面で立ち戻るための指針を定義する PRD(プロダクト要求定義書)からまずは着手しました。これは太い指針がなければ必ず折れる、立ち戻る場所がなければ離散すると考えたからです。 プロダクトの目標 プロダクト立ち上がりの背景 ターゲットユーザー、ペルソナ なぜ作っているのか 何を作っているのか どういった機能を提供しているのか … 参考にしたリソースはいくつかありますが、 Tably 及川さんの資料 にある項目を一番参考にしています。 幸いにも 2020 年前半に UX 部門のメンバーを中心にプロダクトリブランディングのためのワーク(スクリーンショット下部の Miro)を行っており、ビジネス提供方針、NPS 調査結果などを踏まえたユーザーの根本的要求の定義やペルソナやターゲットセグメントなど多くの考察をすでに行っていました。 技術畑からするとむずがゆいような内容に触れなくてはいけない場面もありますが、ここを定義しないと納得感を得られる自信がなかったため歯を食いしばりました。現状「なぜ開発しているのか」に立ち戻る原点にはなっているかなと感じています。 最適なプロダクトのカタを見つける 開発に際してはモブプロを中心とした組織学習をベースにしており、ほとんど息を吸うように実践していましたが、ことプロダクトマネジメントとなると何から手を付ければ良いかわからない状態です。現状十分に回せているかと言われると怪しいところですし、プロダクトのカタをうまく回せる工夫を今も実践中といったところです(以下の画像は書籍、プロダクトマネジメントからのものです)。 1 では企業活動の戦略的意図を実現するため、プロダクトが扱う課題へブレイクダウンさせる必要があります。収益とプロダクトをつなげる接点となるので本来は PdM と強く持つべき接点ですがうまく実践できていないところです。 2 では 1 における共通目標達成のための現状把握です。3 はその共通目標に対するオプション目標(目標達成のためのエピックと言えるでしょう)を立て実行に移していきます。4 で結果を振り返り継続し最適化するか別のソリューションを考えるかなど実績ベースでカタを繰り返すことになります。 これらカタ実践の前に、 ソリューション先行による施策をやめるようにしています。具体的には共通目標に紐付かない・現状分析のない機能追加やツール導入の撤廃です。 プロダクトが目指す目標を意識したエピックを切り、数値ベースの試算をしたうえでリリース後の効果検証を繰り返しています。 幸運にも KR とした数値がプロダクトの達成度と成功を測るために最適なメトリクスであったため、基本的にはその数値を追い続けることになりました。これまで PO やアナリストに任せていたところにも関心を寄せ、構想と実行が分離しない形でなぜ我々は手を動かしているかの納得を得ようとしています。 ただしくツールを使う、たとえば JIRA プロダクトチームはスクラムを実践してきており、ワークフローの可視化や日々のイベントで JIRA を利用していましたが、JIRA にあるエピックはいつの間にか緩いカテゴリやラベリングといった使い方で本来の意味を失っていました。 カタでも触れたように共通目標のためのオプションはすべてエピックされるべきで、それぞれが何を達成するのか明文化しておく必要があります。JIRA のエピックを機能させるべく使い方も改めました。 エピックにはテンプレートを用意しなぜこれを推進するか明記する エピックはロードマップで可視化しリファインメントしやすくしておく (エピックを色分けせず色気が出てないのはご勘弁ください) プロダクトを世に放つのは開発者である これはポジショントークととらえられる可能性も多分にありそうですが、最終的にプロダクトを動かしリリースしているのはまごうことなく開発者です。 プロダクトマネジメントトライアングル にある、プロダクト・ソフトウェアを起点とした根源的要素として開発者、ユーザー、ビジネス(収益)の 3 点で構成されていることからもよく分かります。 コードをアップデートする人たちこそが唯一厳密に欠くことのできないチーム要員だ。開発者は会社のすべての責務を担うことができる(常に効果的にとは行かないが)。 どこまでの責務を追うか・プロダクトマネジメントにあたるような業務まで手を伸ばすかは開発者それぞれですが、介入していったほうが圧倒的に納得感が高いはずですし、コミットできる深さも違うはずだと今は感じます。 課題はないのか 模索しながらなのでまだつかみきれていない部分や課題もたくさんあります。 誰と何をどこまでやるべきかは整理しきれていないので、開発者が踏み込んでよいか微妙なラインで取り組んでいます。前編にもあるとおり私たちは職能のプロが集まってひとつの事業もしくはプロダクトを支えていくことになるわけですが、別の職能のプロに任せるべきことにまで手を伸ばしていないかは気を遣っています。判断を誤ると気持ちの良いチームワークが果たせません。 また開発者の担当するタスクがいわゆる「開発」だけではなく、ミーティングのアジェンダ作成やファシリテート、施策効果のざっくりした試算も行うようになった反面、開発タスクが薄くなりすぎていることも懸念のひとつです。私自身もコードを書かないスプリントが 2 回以上続いたら、ちょっと気が触れるでしょう。 先日発表されていた プロダクトマネジメントクライテリア ですが、自分たちではチェック項目がまったく埋められず旅の遠さに愕然としているところです。 まとめ 前編とは違って後編は取り組みを雑多に列挙していくような形になりました。 12 月から取り組んで結果どうなっているのかについて触れていませんでしたが、プロダクトの成果としての KR としていた数値目標は徐々に増加傾向にあり、始める前よりはまずまずの納得度を得られているんじゃないかなといったところです。 これまで実践してきたモブプロといった組織学習の中で得られた成功体験は間違いなく効いていて、重要なのは積み重ねられたチームでの学習の厚みであり、チームでの学習こそが不確実性を減らしていく のだとあらためて実感させられています。 前編後編と少し技術から離れたことを書きました。納得あるプロダクト開発を考えたい開発者にとって、少しでも役に立てられれば幸いです。後続のポストはがっつり技術的な投稿を期待して今日はここまでとしましょう。 最後まで読んでいただきありがとうございます。
こんにちは。武田( @tkdn )です。今日は「納得度の高いプロダクト開発とは何だったのか」というお題で開発チームが現場でどう変わろうとしているかという話をします。 簡潔に申し上げれば、技術的な取り組みを推進するものの直接事業目標にコミットできていなかった開発チームが、プロダクトマネージャー・プロダクトオーナーの役割を部分的に剥がして目標となる KR に対してコミットできる開発チームへと変わろうとしている話になります。 「納得度の高いプロダクト開発」という言葉自体かなり主語が大きく、人それぞれの主観でとらえ方が変わりそうですので、あくまで 我々の開発チームにとって 、という冠はつけさせてください。 また私個人が所属する開発チームにおける現時点の取り組みに至るまでの変遷ですので、mediba 全プロダクトチームに該当しない点はあらかじめお断りしておきます。 内容が膨れてきてしまったため前編と後編に分けています。この前編についてはだいぶ観念的な部分が多く実践を知りたいという人は後編だけ読まれるのをお勧めします。 前編は組織変遷と組織形態に対する一般的な解釈に並行し、分業・標準化について考え、今ある課題への取り組みについてお話します。そのあとに個人が勝手に抱えたチームの課題感について触れていきます。 後編は前編で明らかとなった開発チームの課題を解決するべく、今チームはどう取り組みどういった変化が起きているか、具体的な事例について話します。 ものづくり再解釈 弊社 VPoE 新井の記事 にもあるとおり、組織構造はここ数年で大きく変わりました。2018 年中期に機能別組織としての開発本部はなくなり縦割りの事業部制組織へ変更されたあと、2020 年にビジネス、テクノロジー、クリエイティブ部門レイヤとなる横串の組織体ができていわゆるマトリクス型組織に変化しています。 テクノロジー部門では、 定期の活動報告会が開催される(オンライン・ニ◯◯コ動◯風なコメント付きで) 、 数年眠っていた勉強会が再開される(クソゲーを大量に作って品評する) 、などマトリクス型となった開発横組織の活動の一部はこのブログでもお伝えしたとおりです。 先日の Agile Tech EXPO での報告にもある シニアマネージャー森實のセッションでも取り組みの一部が垣間見えるのでぜひ御覧ください。 組織体の変遷、一エンジニアからの雑感 ここ数年思いつきで組織が変わっているわけではありません(私の知る限りにおいては)。変遷の中でそれぞれの組織体で求められたこと、その変遷をざっくり振り返ってみます。 組織体種別/特徴 分業のスタイル アウトプット 標準化対象 機能別組織 直列的 統合的 スループットコントロール(プロセス) 事業部制組織 並列的 加算的 アウトプットコントロール 機能別組織 事業部制組織 技術基盤が固まった、機能別組織 機能別組織では各作業工程が直列でチェインしており、ビジネスや企画やディレクション、デザインそして開発から品質管理といった工程の分割が行われます。直列分業により前工程のアウトプットが次工程のインプットとなり、前工程に依存したコンテキストを持つ、リレー的協働が多くなるでしょう。全工程のアウトプットが最終的な成果として統合され、組織の経営成果となるのが特徴です。 機能別組織を成す目的は予測された目標をクリアするためです。 作るものがはっきりしている場合に有効で、最終的な成果統合のために、機能別組織であった開発本部でも予測可能な目標設定を持つことになります。 たとえば事業スキームの形成とそのシステム化が目的であった場合、予測されたゴールはシステムのリリースになるでしょう。リリース後一定の経済効果を生み出すために安定したシステムを提供することも、この組織体の目標になるかもしれません。 直列した工程の最終的なアウトプットであるシステムリリースや安定した運用を目標として、開発組織はものを作るためのプロセス、マニュアル、そしてインフラを整備し標準化してきました。具体的に言えば全社通してのインフラ AWS 移管、それらを利用するにあたっての知見集約やマニュアル化、技術的プラクティスの伝播などが標準化にあたるでしょう。これらは作業工程のプロセスコントロールであり、標準化の対象はスループットになります。 当時の CTO を中心に、機能別組織の中で技術的躍進や文化形成などに十分投資できたおかげで、AWS をはじめとしたクラウドを当然のように利用できているという現状があります。 作り物のゴールや成すべき作業目標が明確かつ予測可能である一方で、機能追加やリリースだけを前提としているため、作ったあとの価値提供や事業成長について考える観点がどうしても抜けてしまいます。ものを作ること自体・作る数を達成目標にするということは、プロダクトマネジメントでも「ビルドトラップ」として言及されていますね(機能別組織だから頻出するわけではありません、事業部制でも・だからこそ生じる問題ではあります)。 書籍: O'Reilly Japan - プロダクトマネジメント 参考: KPIが生むビルドトラップ|Aki|note 成長のための事業部制組織 予測可能な目標ではなく変化する市場やニーズをかんがみて、ユーザー体験・価値提供とビジネス価値のバランスに重点を置き、mediba は CXO を中心としてユーザー体験にフォーカスしていくと同時に事業部制組織へと組織体を変えていきます。 機能別組織と違い異なる職能がひとつのチームを形成し、その事業部ごとの複数のプロダクトチームは並列で開発しプロダクトを成長させます。 事業部制組織は複数チームがそれぞれ並行してアウトプットし、それらを加算したものが経営成果となります。分割された経営資源の合算が最終目的ですので、数値目標のようなアウトプットコントロールによる標準化が特徴で、プロセスをコントロールしない(できない)のが機能別組織との違いです。 事業部制組織の目的・狙いは絶え間なく変化する外的環境の不確実性へ立ち向かうため、事業・プロダクトチームはものを作る方法を委ねられたのだと理解しています。 それぞれの事業において、不確実性が高く例外となる事象が発生しやすいケースでは、専門性をもったチームでの組織学習によって得られた思考能力・応用力・判断力に任せて対応を進めるほうが効率的です。事業やビジネススキームに合う形でワークフローは整備され、求められるシステムもそれぞれの事業にあった形で成熟していくことになるでしょう。 事業部制組織がうまくいくケースでは、事業ごと組織内での市場的競争により健全な競争意識が醸成され、事業・プロダクトチームの達成感やエンゲージメントを高めるだけでなく組織と個人の成長を望めそうではあります。 書籍 から引用しますが、書けば書くほど甘美な組織体ですね。 “各チームを並列化、競争を生むことで組織内部の切磋琢磨を望むことができる” “アウトプット・コントロールはプロセス・コントロールよりも不確実性に対して頑健” “管理する側に負担がかからない” 課題に対する現状のマトリクス組織 しかしどの組織も一定の課題を抱えるように mediba の開発組織も例外ではありませんでした。 事業部制により、技術指針や設計レビュー、Ops を含んだシステム保守のあり方など、機能別組織の中で標準化されていた・されようとしていたことはプロダクト開発チームに閉じていくようになりました。いわゆるサイロ化というやつです。 サイロ化が悪いわけではありません。機能別組織が敷いた旧来の標準化されたプロセスにブロックされチャレンジできなかった領域へ取り組める、事業とのバランスを考え余剰を活かして新しい技術要素を広げていける、などのメリットもあります。 ただしその一方で、ほかの事業部の開発には無関心といった状況もないとは限りませんし、マネージャーからすればガバナンスの効力範囲が小さいうえ観察できることも散漫になるでしょう。 そういった課題解決にマトリクス型組織が求められるのは当然で、その一環として前段で申し上げた取り組みがあるというわけです。まだ始まったばかりの組織体ですのでテクノロジー部門では課題への取り組みを一層強化していくでしょう。 一エンジニアの課題感 事業部制になってからチームが持つ目標に対してダイレクトなコミットができない(と思い込んでいた)というのが自分の大きな課題となっていました。 機能別組織であれば開発組織自身が掲げる目標を意識しながら個人の技術的な取り組みや日々の活動のテーマを昇華させやすいと感じていましたが、 事業部制となると自分ができることは何なんだと立ち止まるようになったのです。 こう感じている開発者は私だけではなかったはずです。 プロダクトチームの開発者として取り組めることを苦悩しながらさまざまな実践をしてきました。 モブプログラミングの実践により属人化を排除する リリースの回数を増やしていく(ためのプロセスを構築する) 運用コストを下げるために X を導入する、Y からリプレイスする パフォーマンスを計測しメトリクスから異常値を検知する チームで合意しブレないものづくりに取り組む 以上はいずれも取り組みとしてポジティブに見えます。ただ事業部制といった組織軸においては取るに足らない改善業務のように感じてしまうことが多くなってきたのです。 もちろん実際には取るに足らない改善業務ではけっしてありません、技術組織が強くあるためには必要な取り組みです。 ※ 上記のような技術的な取り組みを評価すべくテクノロジー部門ではどういった評価が適切かといった議論や実評価も試験的に進んでおり、組織的な課題解決に取り組んでいる最中です。 開発者の中にある不確実性 より良いプロダクトチームの組成といった部分においては現マネージャーと協働しながら良いメンバーに恵まれチーム自身も成長しているものの、さてプロダクトに対してどうかと言われると自信がまったくありません。 チームのデータアナリストにはプロダクトが追うべき数値を可視化してもらっていましたが、伸び悩む数字をデイリーイベントで見ては無力感を日々感じ、事業に対してコミットできたかどうかの手応えのない状態がしばらく続きました。若干それに麻痺しかけていたことも危機感の 1 つです。 そうなると人間はどうしても環境や外部に要因を見出そうとして、市場やユーザー、プロダクトの特性に不確実性を探してしまいます。 しかし、不確実性は市場や外的環境の変わりやすさだけではなく、人間の推測する能力が低いことも影響します。それと同時に能力の低さの根本には、無知・無関心があるのではないでしょうか。 プロダクトについての理解不足からコミットできる領域を自分自身が狭くしている可能性について考える必要があるでしょう。 前編はここまでです。 開発者としてプロダクトへダイレクトに関与できなさというのは、自らの能力の低さと関心の無さにある起因するのではと思うにいたり、今どうやってプロダクト開発に取り組んでいるか・納得をえるためにどうしているかといったことを 後編 で書いていきます。
こんにちは。武田( @tkdn )です。 GraphQL を API として採用したサービスを今年序盤にリリースしています。具体的な内容は今年の夏サミ 2020 の公募枠でお話させていただいたのでよろしければ資料もご参考ください。 週一でリリースし続けるためのフロントエンドにおける不確実性との戦い方 / Developers Summit 2020 Summer C-4 - Speaker Deck 今日は GraphQL や Apollo Server についての振り返りと反省を中心に供養しておきます。GraphQL 採用に迷いがある開発者、Apollo Server を採用しようとしている開発者へ向けた知見になれば幸いです。 まとめてみたら GraphQL みが思いの外少なくなりましたが、 GraphQL Advent Calendar 2020 の 23 日目の記事です。 なぜ GraphQL を採用したか、リリース後どうだったか 最近話題になっていた Netflix の技術記事 で組織内の API アーキテクチャの変遷に名称を与えていました。記事にあるような Federated Gateway といったドメイン単位のグラフサービス群をいくつも持つ巨大化した構造では当然なく、我々の API は本当にミニマムな構成です。 我々の API は KDDI の認証システムや同 VPC 内で別サービスとして切り出したポイント参照・付与 API 通信をブリッジする役割を備えながら、Web フロントエンドでの利活用を目的とした、いわゆる Aggregated Gateway/BFF な立ち位置の GraphQL API です。 新規サービスとしてリリース後にどう転んでいくか、不確実なプロダクトの将来のために以下 2 つのことを考え GraphQL を採用しました。 価値検証のための変更をフロントエンドでハンドルしやすくする プロダクトの伸長を考慮し API 自身の変更容易性を持たせる これらの採用理由に妥当性があったのかを考え供養していきます。 1. 価値検証のための変更をフロントエンドでハンドルしやすくする 新規サービスは当初から価値検証のためフロントエンドのコード変更が多く見込まれていました。そのため UI に必要とされる情報に追加があるたびにスキーマを変更したり、API の開発が多く発生したりするとそれだけリリースのリードタイムは長くなってしまいます。自由なクエリによるレスポンスバリエーションを最大限に活かせるよう、クライアントからリクエストするクエリが多く変更されることを見越していました。 ただ残念ながらリリース後クライアントからリクエストされるクエリはほとんど変更されていません。 今後変更が求められることを望んでやみませんが、ある程度ユースケースが固まった状態からクエリが変更されるというようなことは我々の場合は頻繁に起こるものではなかったということでしょう。リリース後生じる変更のホットスポット見極めは今後の課題となりそうです。 2. プロダクトの伸長を考慮し API 自身の変更容易性を持たせる 今年は 2020年5月に au のポイントは Ponta ポイントと統合される 、ということもありました。ポイントを扱うサービスにとっては変更もやむなしでスピード感が求められたり、ステークホルダーのニーズに答えるべく当初予定していなかった機能変更などが発生したり、 クライアントからのクエリの変更こそありませんでしたが、API のコードは比較的多く変更されています。 DIP にのっとり責務を分割しレイヤ化したアーキテクチャを採用したおかげで、リリース時点でカバレッジ 90 を超えるテストコードを配置できています(カバレッジが高いからすばらしいというわけではありません)。網羅されたユニットテストはコードを触るうえでの安心感が違いますし、変更における影響範囲について不安がないというのはやはり開発者にとって重要だと感じます。ただレイヤが多重なので変更によっては触るコード範囲が大きいという苦言もなくはないです。 また同期をとるためのモブプロはコロナ禍になった状況でも行い、コミュニケーションにズレのないワークフローとチームのおかげで、認識齟齬を圧倒的に減らすことができています。 API の変更容易性を担保したコードベースとチーム力がプロダクトを支えているひとつの柱と言えそうです。 Apollo Server 運用におけるあれこれ GraphQL 採用理由と振り返りについて書きましたが、以下は採用した Apollo Server の性能からロギング、運用においてできていることやできていないことを中心に書いていきます。 Apollo Server の性能 我々のアプリケーションで利用している範囲ではほとんど性能の問題はありません。 弊社では負荷試験で以前から Gatling という Scala 製のストレスツール を利用しています。リリース前の局面以外では Go 製の Vegeta を利用することもありましたし、自身も試しに Node 製の autocannon や周辺の診断ツール を使ってみたこともあります。選択肢として Gatling に軍配が上がるのは、試験で生成されたレポーティング HTML(下記画像は今回のもの)が見やすいという点や時間経過によりリクエスト数を増やしていける点などです。 今回は以下の条件でリクエストを処理できており、CPU/メモリなどのサーバリソースにも何ら問題はありませんでした。 項目 詳細 Node.js v12 API Apollo Server v2.9 CPU コア 2 クラスタ内コンテナ数 2 リクエスト 100 req/sec * 600 秒 かなり控えめなリクエスト数で安心しきっているな? とお思いかもしれません。 ですが、新規サービスとして需要予測が控えめだったことに加えて、2018 年に弊社で初めて Node.js でフロントサーバと API サーバをプロダクションで利用した際、CDN を挟まない状況で負荷試験の惨憺たる結果に愕然とした記憶から今回肩透かしのような安堵を得ています。 当時と今を比較し Node.js が依存するエンジン V8 の性能向上やライブラリのバージョン差異による考察を深く行っていないので以下の条件を鵜呑みにはしないでほしいのですが、当時の苦い負荷試験での条件は下記になっています。 項目 詳細 Node.js v8 SSR Next.js v6 API graphql-yoga(リリース当時は Apollo Server v1 に依存) CPU コア 2 クラスタ内コンテナ数 8 リクエスト 100 req/sec * 600 秒 当時は知見が少なかったこともありますが、この条件下で実施された負荷試験では 30 req/sec も処理できませんでした。当時試験を担当した開発者は「コンテナがいくつ必要なんだ…」「今から作り変えるか…」など不安を募らせながら改善していったという経緯があります。今なら改善のアプローチや選択肢が思いつきそうですが、どこから手をつければよいやらと頭を抱えてしまっていたのは事実です。 こういった苦い結果を見ているからか今回の試験結果の良好さを信じきれず、安全をとってリリース直後はコンテナ 8 つで稼働させていましたが、コスト削減のためすぐコンテナ 2 つの稼働に切り替えました。この状態で 1 年近く安定して稼働しており、対向先システムへの疎通失敗に見舞われアラートが上がる以外は何の問題もありません。 アラートはコンテナで動作するアプリケーションのログを Datadog へパイプしモニタリング・検出して発報するのですが、Apollo Server ではログをどうしているかについての失敗、振り返りを以降で書いていきます。 ログとエラートラッキング Apollo Server はコンテナで稼働させているのは前述通りですが、FireLens を利用したログルーティングにより S3 保管と Datadog へ出力しています。アプリケーションからは LTSV のログフォーマットで標準出力させており、この部分についての成功・失敗について触れていきます。 ログ出力機構の配置失敗 Apollo Server 導入に際して必ず公式ドキュメントを読んだうえでプラクティスを実践し自分たちのプロダクトに合うようカスタマイズさせていったのですが、ロギングに関してはあまりうまくいかなかったことのひとつです。 今でこそしっかり ロギングの項目が公式ドキュメントに設けられています が、リリース前にはこのドキュメントがなく我々のリリース直前である、 2020 年 1 月中旬に追加 されています。 公式のロギングのプラクティスによれば、リクエストライフサイクルにフックできるプラガブルな機構があるので、そこに適切な出力を仕込めば 1 リクエストに対してコンテキストをかき集めながらログを出力することが可能そうです。 const loggerPlugin: ApolloServerPlugin = { requestDidStart(requestContext: GraphQLRequestContext) { console.log(`クエリ:${requestContext.request.query}`) return { // resolver オペレーション終えた didResolveOperation(_requestContext){/** ... */} // エラーが起こった didEncounterErrors(_requestContext){/** ... */} // 他にもバリデーションやクエリのパース処理にフックさせることが可能 } } } const server = new ApolloServer({ typeDefs, resolvers, plugins: [ loggerPlugin ] }) 設計・実装当時は公式ドキュメントにロギングについての記載がなかったとはいえ、我々の調査不足やフレームワークのコードリーディング不足もあり、 現状 resolver 毎にログを出力する構成になっています。 上記の図のようにリクエストは ① 一度 Apollo のコンテキストを通ってリクエスト受信のログ出力を行います。さらにクエリのバリエーションにもよりますが、上記ですと ② User resolver での正常終了をログに出力するだけでなく、③ Contents resolver でもログを出力します。そのため複数ユーザーのリクエストによって出力順は担保されず多段的になるため、一意のリクエストに対して ① ② ③ を束ねるということが難しいため、調査の際の懸念が生じました。いまのところトラブルシュートにおいて問題ありませんが、今後の改善を考慮したいところです。 Apollo でロギングを検討される方はぜひ公式ドキュメントどおり plugins を使ってみてください。 ここでは正常リクエストのロギングを取り上げましたが、例外が発生した場合はログだけでなく Sentry にエラーイベントを送信しています。例外発生時、ロギング・Sentry への送信・クライアントにエラー返却をどのように設計・実装しているか、次で説明します。 例外捕捉時のエラーイベントとロギング Apollo では例外が発生した場合、フレームワーク側がよしなに処理しクライアントにエラーのレスポンスを返却します。 我々のユースケースでは Apollo で例外をつかませる前にリクエスト情報の一部(ヘッダからセッション ID やログのためのメタ情報など)を例外へ取り付け throw するハンドラが resolver に実装されれば大方事足りそうでした。下記のソースコードではコンテキストを引数に受ける exceptionHandler といった例外用の関数です。 // 粗雑な resolver 実装例 export const foo: QueryResolvers["foo"] = async ( _root: unknown, _args: unknown, context: ApolloContext, ) => { /** * いろいろ割愛 */ const userFoo = await fooUsecase .getUserFoo(context.timestamp, context.user) // exceptionHandler がコンテキストをまぶして例外を送出する // ⇢ Apollo Server が捕まえてエラーレスポンスを作成する .catch(exceptionHandler(context)); return userFoo; }; exceptionHandler での例外送出で Apollo がよしなにエラーレスポンスを返してくれますが、エラー種別によってクライアントでメッセージを変更したり API のスタックトレースを渡さないようにしたり、レスポンスの加工が必要になります。Apollo では formatError オプション が需要を満たしてくれそうです。 設置した formatError 関数は、クライアントに返却するエラーレスポンスを加工しフレームワークがよしなにやる部分を書き換え、Sentry にエラーイベントを送ることも兼ねました。1:Error レベル以上のログ出力、2:Sentry 送信、3:クライアントにエラーを返すという手順の中でエラーオブジェクトを下記のように加工します。 処理わけ 1.Error レベル以上のログを出力する 2.Sentry にエラーイベントを送る 3.GraphQLError を返す スタックトレースは… 含める 含める 含めない 接続先のエンドポイントは… マスクしない マスクしない マスクする エラーコードの置き換えを… する する する ほかログの可読性を高めるための加工を… いろいろ やって こねこねする クライアントにエラー時のスタックトレースを渡したくない ため、最終的に 3 の手前で GraphQLError から省きます。 debug オプション を false にしてスタックトレースをそもそも入れないという選択肢ももちろんあります。 またエラー発生時に 特定の接続先のエンドポイントがクライアントへむき出しになっては困ります。 AWS のリソースもそうですが、対 KDDI との接続先ももちろんそうです。そのため文字列のマスク加工を 3 の手前で処理しています。便利なオプションはないので利用用途に応じて実装する必要はあるでしょう。 フロントエンドにおけるユーザーケアのために実施しているエラーコードの書き換えは 夏サミでもお話したとおりで 、 GRAPHQL_VALIDATION_FAILED 、 INTERNAL_SERVER_ERROR といった Apollo がもつ既存のエラーコードも自前のものに置き換えるなどしています。 で、結局置き換えや適切なエラーレスポンスへの整形やマスクをかけたら、上記のように一番コードベースで読みづらく割としんどい箇所になりました。しんどくはありますが、この formatError によって例外発生時のレスポンス整形や差し迫った対応に必要なログ出力から Datadog でのエラー検知を行い、Sentry へのイベント送信し Slack へ通知し、デプロイ時や稼働中のトラブルを検知できています。 Renovate と週次アップデート Apollo とはあまり関係ない話ですが、チームでは Renovate によるパッケージのアップデートを週次で行い毎週リリースに含めています。 人間がアップデートするのではなく自動化されたしくみ(Renovate) Renovate による PR をチームが判断しマージできる パッケージアップデートによるリリースが毎週行うという合意形成ができる 自動化や利便性から Renovate を導入しても 2, 3 が欠如していてはワークしません。2 では暗黙知の一般化とモブプロでの PR マージを、3 ではチームでの合意・協調を進める必要があります。 自動化だけが目的ではなく、健全性を保ち腐らないコードベースでリリースし続ける、までチームが合意できてこそと考えます。 ほころびは割れ窓から生まれる ただし定期的なアップデートもしかるべき手段で検証できていないと危険だなということも運用して半年くらいで経験しました。 とある日の Renovate PR はグリーンな状態だったので通常通りチームは PR をマージし検証のためステージング環境にデプロイしていました。運用してしばらく経っていたのでデプロイやコンテナの代替わりによる入れ替え、ログの注視はそこまで見なくなっていました。 デプロイ後しばらくしてからブラウザで画面を確認すると、クライアントアプリケーションの画面は正常に見れている ようだったので品質管理部門に正常性の確認を依頼して検証が正常に終わればリリースされる予定でした。 ただステージングの Datadog ⇢ Slack のアラート通知に見慣れないログが出ており、調査すると API サーバが正常に起動していなかったことがわかりました。よくよく調べると ECS で最初に起動したタスク定義(Renovate PR マージ後のイメージ)では正常起動できず、サーバリソースの異常により以前のタスク定義(正常起動した 1 世代前のタスク)に戻ったため画面は正常に見れていたのです。 前提としてアプリケーションは Yarn Workspace を利用した monorepo で管理し、API は依存をすべてバンドルしているのですが、直接的な原因はすぐわかりました。 Error: Cannot find module 'node-fetch' といったログとスタックトレースからバンドルされたファイルの以下の箇所に問題があったようです。 基本的にすべてバンドル想定なので上記のような CommonJS require で外部モジュールを読み出すことはないはずです。問題は何だったのでしょうか。 Renovate によりアップデートされた node-fetch に依存の中でバージョン差異が生まれたため 、monorepo ルートの下層パッケージにある api/node_modules/node-fetch へインストールしていました。 これだけなら問題ないはずですが、webpack.config 内の webpack-node-externals の設定にもともとミスがあり、バンドルされるパッケージ内の依存(今回生まれた api/node_modules/node-fetch )をバンドルしないという問題が発生していたのです。 技術的にいたらない部分があったことも悔しいですが、 アラートの通知が Slack に流れていたにもかかわらずすぐ気付けなかったことでさらに悔しさが増します。 間接的な要因も考えると、まず Slack におけるステージング環境のアラート検知を放置していたのはよくありません。 当時を思い返すともっと良くない部分もあり、ステージング環境の Slack アラート通知は頻繁でそれが当然ということが常態化していたため、重要な通知が埋もれていたのは完全に割れ窓が放置されたといってよいでしょう。 プロダクション環境のオンコールや検知に敏感なチームメンバーが多いことは救いで、実稼働のプロダクション環境については心配をしていませんが、ステージング環境であろうとこういった割れ窓を放置するのはよくありませんね。 まとめ 前半では GraphQL を採用してどうだったか、反省点はなんだったかについて触れてきました。技術的な取り組みとしてやはりフロントエンドフレンドリーなので楽しいという反面、不確実なプロダクト成長に対してはフロントエンドで GraphQL のメリットを存分に享受できたかという点ではマイナス、API の変更容易性やアーキテクチャとしてはまずまずといった感じです。 ロギングやエラートラッキングについてはこれまでチームや組織が培ってきた知見が大きいですが、一部 Apollo Server の具体的なオプションや実装について触れました。Apollo は公式ドキュメントが充実しているので、まずはカタどおりに組み込んでから考えてみるのをお勧めします。またエラーレスポンスには秘匿情報が入らないよう留意するポイントなども書きました。 最後は GraphQL や Apollo から大きく離れましたが、定期的なパッケージアップデートと運用についての反省を書きました。アップデートを順次リリースし続けること、割れ窓を放置しないことについて触れたつもりです。 類似したプロダクトをもう 1 つ最近リリースしてまして、反省や振り返りはまだまだ多いです。クライアントサイドでのローディング UI への取り組みを誤り CLS スコアが落ちたり Context API か Props かの選択で方針が混在したり、Jest を使ったコンポーネントテストのプラクティスなど失敗を含んだ反省文はいくらでも書けそうですが、本日は以上にしておきます。 今月不惑の年に突入した武田( @tkdn )が書きました。
こんにちは。テクノロジーセンター・SRE Unitのイ・グンジェです。 今回、AWS Access Keyを誤ってGithubにPushしてしまった事故(?)があり、 それに対する備忘録と再発防止対策についてお話したいと思います。 やらかしたこと AWS による漏洩通知と対応内容 AWS からの通知後にやったこと 再発防止策としてのgit-secrets導入 git-secrets 基本設定 git-secrets 高度な設定 git-secrets をテストする まとめ やらかしたこと medibaではサービスごとにAWS Accountを分けているため、 複数のAWS 環境が存在しています。 全てのAWS環境にあるEC2の情報を一目で把握したかった私は 全てのAWS環境からEC2の情報を取得するPython Scriptを書くことに決めました。 Boto3 SDKを利用して、EC2情報を取得するScriptを作成した私はテストのため、 テストScriptを作り、AWS Access Keyを書き込んで動作確認をしていました。 作業途中、もっと大きいモニターがあるPCで作業したくなって、 Githubにコードを上げて自由に作業環境を切り替えるのを考えました。 コードを上げるためにGitHub Repositoryを準備し、 .gitignoreファイルに用意してテストScriptは除外されるようにしてからGithubにコードをPushしました。 (テストで書いたScriptにはAWS Access Keyが書き込んでいるため) しかし、何と。。誤字が入ってしまい、 テストScriptもPushされてAWS Access Key公開されてしまいました。。。! AWSによる漏洩通知と対応内容 GithubにAccess Keyの情報を上げるバカなことのやったのは12/17 21:55頃。 その後、AWSからAccess Keyが外部に公開されたというメールが届いていました。 メールには不正アクセスによる課金などを防ぐために隔離ポリシーを対象Userに付与したという内容も書いてありました。 CloudTrailからも AWSCompromisedKeyQuarantine ポリシー付与のログが確認できて、 UserやRole、EC2インスタンを作成する権限が全部拒否されていました。 さらにこのポリシーは"iam:DetachUserPolicy"を持っているため、 付与されたUserが直接Detachするのもできない状態でした。 また、AWSのサポートチケットがOpenされたとのメールも届いていました。 AWSからの通知後にやったこと まずはAccess Keyが無効化されているのを確認して削除しました。 そして、公開されてから悪用の行為はなかったのかCloudTrailでログを確認してみました。 12/17 21:55頃Access Keyの公開が認識され、 AWSCompromisedKeyQuarantine ポリシーが Attacheされた以降、特にUserとかRoleが作成されてリソースが追加された履歴はありませんでした。 (12/18の履歴は私が挫折して彷徨した履歴です。) 悪用の履歴はなかったため、他のチームメンバーにお願いして AWSCompromisedKeyQuarantine ポリシーをDetachし、新しいAccess Keyを作成しました。 再発防止策としてのgit-secrets導入 この事故で迷惑をかけてしまった私は恥ずかしいと思いながら、 今後同じ事故を防ぐためにどのような対策があるか考えてみました。 言うまでもなく当たり前なことですが、コードに直接Access KeyとSecret Access Keyを 書き込まないとか.gitignoreでRepositoryに上げるファイルを制限する方法などがあると思いましたが、 今回の事故のように誤字を入力するなどの人災により.gitignoreの制限が無効化される場合があるため、 もっと確実な方法が必要だと思いました。 その時、優れたスキルを持っていつも色んな情報を共有してくれていたメンバーが git-secretsについて紹介してくれました。(ありがとうございました!) git-secretsはcommitやcommit messagesをScanして 正規式にMatchされるのパターンがあればcommitをrejectしてくれるツールです。 参考 : git-secrets また、Classmethodの記事にもgit-secretsを紹介していて、 導入した内容もあったので参考しながらgit-secretsを導入してみました。 git-secrets基本設定 git-secretsをインストール # brew install git-secrets git-secret messageをhookするためにgit hookをインストール # cd /path/to/my/repository # git secrets --install ✓ Installed commit-msg hook to .git/hooks/commit-msg ✓ Installed pre-commit hook to .git/hooks/pre-commit ✓ Installed prepare-commit-msg hook to .git/hooks/prepare-commit-msg gitの設定にgit-secretsパターンを追加 # git secrets --register-aws # view .git/config [secrets] ★以下のような設定が追加される providers = git secrets --aws-provider patterns = (A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16} patterns = (\"|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)(\"|')?\\s*(:|=>|=)\\s*(\"|')?[A-Za-z0-9/\\+=]{40}(\"|')? patterns = (\"|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?(\"|')?\\s*(:|=>|=)\\s*(\"|')?[0-9]{4}\\-?[0-9]{4}\\-?[0-9]{4}(\"|')? allowed = AKIAIOSFODNN7EXAMPLE allowed = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY git-secrets高度な設定 上記の設定方法はrepositoryがあるDirectoryのLocal設定を参照するため、 他のrepositoryはgit-secretsが効かないです。 全てのrepositoryにgit-secretsを適用したい場合は --global のOptionを付けてGlobal設定から参照できるようにする必要があります。 (これで既存のrepositoryはもちろん、今後新しくCloneするrepositoryも適用されます。) # git secrets --register-aws # view .git/config ↓ # git secrets --register-aws --global # view ~/.gitconfig また、git hookは以下のコマンドでglobal設定しておくと、 新しいrepositoryができたらtemplateDirからhookを持って来るので自動的にhookの設定もできます。 # git secrets --install ~/.git-templates/git-secrets # git config --global init.templateDir ~/.git-templates/git-secrets 最後に、git-secretsの正規式からフィルタリングされたくない文字列がある場合は 以下のようにallowedを追加することで、無視するのもできます。 # git secrets --add --allowed (文字列) git-secretsをテストする インストール及び設定が完了して、repository全体をScanしてみたら、 以下のようにパターン分析を通してAccess Keyを見つけてくれました。 commitしてPushしようとしても以下のようにErrorのメッセージが出力されて、 Commitが拒否されます。 また、Visual Studio Codeでも以下の画像の通りErrorメッセージのModalが出て Commitが拒否されます。 (Sourcetreeではgit-secretsがうまく動かないようなので、別途で対応する必要があります。) これで、Access Keyの情報が入っているファイルを誤ってGithubに上げようとしても git-secretsがちゃんとScanしてCommitを止めてくれることが確認できました。 これから、気づかずCommitしようとしてもgit-secretsがちゃんと止めてくれますよね。 まとめ これで、私がAWS Access Keyを誤って公開したことから、 再発防止のためにgit-secretsを導入したことまでのお話をまとめてみました。 何よりもこの事故で驚いたのはAWS側からAccess Keyが外部に公開されたのを すぐに検知してCustomerに通知しつつ、隔離ポリシーを対象Userに付与するまでの対応がとても早かったということです。 GithubにAccess Keyが上がってから1分内で全ての対応が完了されていて、 そのおかげで大きな情報漏れ事故に繋がらず、収束できたと思います。 git-secretsを経験することができたのも楽しかったです。 インストールも思ったより簡単ですし、設定もテンプレートで すぐに追加できるので、誰でもすぐに使えるツールだと思いました。 やはり、個人勉強以外にも障害や事故でも学ぶことがあると思いました。 以上です。 次回は楽しい内容で戻ります。
本稿は、 mediba Advent Calendar 2020 15日目担当の沼沢です。 以前、 VPoE の新井が説明していた 通り、弊社では2020年度からマトリクス型の組織構造を採用しており、この中の「テクノロジーセンター」というセンターがエンジニア組織となっています。 しかし、エンジニアが同じセンターに所属してはいるものの、通常はアサインされている各プロダクトの開発や保守運用業務を行っており、横の連携が少ないために相乗効果が生まれにくいという課題がありました。 また、この組織構造になったときに、弊社では既に 原則在宅勤務 体制に移行しており、ほとんどの業務がオンラインで行われるようになっていたことも、横の連携が少ない一因となっていると考えています。 そこで、テクノロジーセンターでは数ヶ月に1度の間隔で、以下を目的として「テクノロジーセンター活動報告会」なるものを開催するようにしています。 事業に対しての理解を深める エンジニア同士の理解を深める これまでに3回活動報告会を開催しており、2回目からは LT 大会も開催し、社内での評判も良いです。 ただ、オンラインではどうしても 発表者の方が反応のないモニターに向かって黙々と話す ということがやはり寂しくもあり辛くもあります。 そこで、双方向でコミュニケーションを取ることはできないか、一体感の醸成ができないか検討していたところ、 Comment Screen というツールを発見し、3回目の活動報告会で採用してみました。 前置きが長くなってしまいましたが、この Comment Screen が思いの外盛り上がったので、その知見を置いておこうと思います。 Comment Screen とは 参加者や視聴者が投稿したコメントが、画面の右から左に流れるというもので、簡単に言うと ニ◯◯コ動◯ のコメント機能です。 (◯コニ◯◯画 を知らない方はごめんなさい。) なお、Comment Screen は本来は無料のツールではなく、昨今の新型コロナウイルスの感染拡大を受け、現在は無料で提供中のようです。 本当にありがとうございます…!! 参考: オンライン会議アプリ「Comment Screen」の無料配信を決定 イベントやテレワークを支援、問い合わせ窓口も開設 なお、本稿の内容は全て2020年11月の段階で確認している情報であり、今後は更新されている可能性があります。ご注意ください。 Comment Screen の使い方 Comment Screen アカウント登録、Room 作成 この手順は、誰か1人がやれば大丈夫です。 https://commentscreen.com/ にアクセスし、サインアップ Private Room 作成 サインアップ時の情報でブラウザで Comment Screen にログイン 「+ New Room」 Title: 任意の文字列 Hashtag: 任意の文字列 ※Comment Screen 内で一意の必要あり Private Room: ✔ ※Public なイベントの場合は不要 Password: 任意の文字列 Comment Screen のインストール、起動 公式サイトのダウンロードよりインストール https://commentscreen.com/#download アプリケーションは、発表者全員がインストールする Comment Screen アプリケーション起動 Enter event で予め作成済みの event に JOIN Input your event name.: Private Room 作成時に指定した Hashtag の値 Input password: Private Room 作成時に指定した Password の値 JOIN 後、左下の「display enable」に ✔ を入れる QR コード or URL を参加者に共有 アプリケーション起動 → Room JOIN 後、以下のようなダイアログが表示されます。 ステップ1の「ウェブサイト」のリンク URL またはステップ2の「QR コード」と、Private Room 作成時に設定した Password を参加者に共有します。 これをブラウザで開き、Password を入力することで、参加者がコメント投稿可能な画面を表示できます。 Zoom や Teams などのツールで画面共有 ここまでで、Comment Screen が起動している PC の画面上に、投稿されたコメントが流れるようになりますが、これだけでは視聴者にコメントが流れる様子をお届けできません。 そこで、この状態で Zoom や Teams の画面共有で表示することで、視聴者にもコメントが見えるという仕組みです。 Zoom や Teams で、デスクトップ共有をすることで、スライドを表示しつつ投稿が流れる様子を映すことができます。 管理画面で投稿を確認 アカウント登録時の情報で、 https://commentscreen.com/ からログインすることで、この Room に投稿されたコメントの一覧を確認することができます。 使用実例 実際に前回の活動報告会での様子を抜粋しました。 この LT では、このスライドの前に大人気漫画「鬼滅の刃」の煉獄さんとかまぼこが踊っている MMD が映っていたので、それに関連したコメントが投稿されていました。 ニ◯動のように、ウケ狙いのコメントを投稿する方も多く、非常に盛り上がりました。 Comment Screen 利用時の注意事項 この注意事項は、あくまで弊社が利用してみて感じた事項です。Comment Screen の公式見解ではないので悪しからず。 社外秘情報は極力書き込まないよう注意する 公式に問い合わせをして Room 削除後の投稿コメントの取扱について確認したところ、物理削除されデータベース等には一切残らないと回答をいただきましたので、そちらの心配はありません。 しかし、Private Room といえど、Hashtag と Password がわかれば Room に入れるため、Room を削除する前に悪意のある第三者に入られてしまうと過去の投稿コメントも見えてしまいます。 そのため、社内で利用する際は 社外秘に該当しそうな情報 は書き込まないようにし、利用後は Room の投稿コメントをバックアップした上で、速やかに Room を削除することをおすすめします。 弾幕、絵文字の連打は控える 弾幕とは、画面が見えなくなるほど大量のコメントを投稿する行為で、とても盛り上がる部分で行われることが多い行為なのですが、Comment Screen の描画力は発表者の PC の性能に依存しているため、大量のコメント投稿や絵文字の連打を行うと、発表者の PC がめちゃくちゃ重たくなります。 それこそ発表中のスライドが次のページに進むのにラグが発生するほど重たくなりますので、控えましょう。 発表と関係のないアプリケーションは極力閉じる 前述の通り、Comment Screen の利用は発表者の PC の性能に依存します。 発表には使わないアプリケーションを極力閉じておくことで、PC に余裕を持たせておきましょう。 映ってはいけない資料などは事前に閉じておく Comment Screen では、ウィンドウの共有ではなくデスクトップ共有を使用します。 それ故に、 例え社内といえど見られてはいけない情報が載っているファイルなどは事前に閉じて おきましょう。 発表者メモは参照できない デスクトップ共有を利用するため、スライドのメモ書き部分等を見ることができません。 必要に応じてスマホでメモを表示するなり、温かみのある手書きメモを用意するなりの工夫が必要です。 まとめ 弊社で利用した際の使い方と注意点を書きましたが、いかがでしたでしょうか。 他にも、今回利用していない 参加者が質問を投稿する機能 や、 運営側がアンケートを取る機能 などがあり、まだまだ使い切れていないというのが正直なところです。 Twitter と連携する機能もあるので、オープンなイベントでは活用できるのではないでしょうか。 また、利用してみて思ったのですが、オンラインだけではなくオフラインの勉強会等でも利用したいと思えるツールでした。 本稿が、昨今のオンラインでの勉強会や報告会等で、反応のないモニターに向かって話すことが辛くなってきた方々の参考になれば幸いです。
こんにちは。武田( @tkdn )です。 MVP でスタートさせた au Webポータル 無料ゲーム というサービスを、手製のビルドスクリプトと手製のコンフィグで生成していた静的サイトから、Next.js SSG + ヘッドレス CMS へ 9 月にリニューアルしました。 リニューアルした理由に触れつつどうやってデプロイ・運用しているか、あたりを中心に今日は書いていきます。 なお、この記事は Jamstack Advent Calendar 2020 15 日目の記事です。 前提 Next.js Next.js は React を利用したフロントエンドフレームワークです。SSR/SSG などを実現できるほか、ディレクトリ構成による動的ルーティングや API ハンドラの取り付けなども可能で、要件次第ではありますが個人的には積極採用できるメリットが多いと考えています。 昨今のフロントエンド事情を汲み取ったうえで、最初から開発者のパフォーマンスを引き出せるだけではなく、Web パフォーマンス指標(最近の Web Core Vitals など)の取り組みにも力が入っており Next.js Conf での発表が記憶に新しいところです。 ヘッドレス CMS:microCMS microCMS は API ベースでテーブルを作成し多用なフィールドに対応したカラムを追加することで直感的に操作できるヘッドレス CMS です。Contentful、GraphCMS、Prismic など候補はあったのですが、日本語でわかりやすく運用メンバーでも容易に操作できるという点で microCMS を選択しました。 microCMS さんには紹介記事でも取り上げていただいています。 microCMS 導入事例 - 開発を介さなくてもコンテンツが更新できるように! リリースまでのリードタイムを短くしたい なぜリニューアルしたかについては、ソース管理のつらさ・それに伴うリリースの人依存を排除して、リリースまでのリードタイムを縮めたいという思いからでした。 MVP としてリリースした 2019 年春段階では 10 本ほどだったゲームタイトルも、今では 100 本以上になっています。リニューアル以前はゲームタイトルなどのデータを記述したファイルをマニュアルで更新し、ビルドスクリプトやテンプレートによって静的サイトを生成していました。これが運用において非常にしんどくなっていたのです。 さらにゲームタイトルがソース管理されているため、ビジネスサイドでゲームタイトルを追加したくても、開発者が別の作業で対応できない場合はスプリント中のリリースを諦める必要がありました。定期的なリリースによってユーザーに新しいゲームと届けられないというのは口惜しい限りです。 リニューアル後のデプロイ、環境差分チェック microCMS 導入によりリニューアル後の運用は想定よりもだいぶ楽になりました。デプロイ・リリースに関しても CMS webhook を介し自動化されており、作業コストはかなり低くなり気軽にリリースできる環境が整っています。 以下ではデプロイフローをどう工夫しているか、CMS の制約により本番環境とステージング環境のデータ差分チェックを自動化していることについて触れていきます。 デプロイフローの工夫 デプロイフローはチームメンバーが下記のように組んでくれています。 リリース作業者が CMS 上でリリース用レコードを追加します CMS 上に設定した webhook により AWS API Gateway + lambda へリクエストが送られます 通知を受けた lambda は webhook では不足している情報を取得するためさらに microCMS のリリース API へリクエストし情報を取得します 取得した情報からデプロイする環境をパラメータにセットし、ジョブをトリガする CircleCI API へリクエストします ジョブが起動すると Next.js が適切なパラメータを受け取り環境向けに SSG のビルドを始めます ビルドされた成果物を S3 に PUT してデプロイ完了です(Cloudfront を利用しているのでデプロイ後は Invalidation も挟みますが) microCMS webhook の注意点 前述の 2 と 3 の工程を見ていただくと分かるように、microCMS webhook のリクエストは以下のようにレコードに対する情報をすべて付帯していません(記事投稿時点)。 { "service": "awesome-game-app", "api": "release", "id": "5wig8fqa6", "type": "new" } id がユニークキーとなるので /release/5wig8fqa6 へ再度リクエストし情報を取得します。webhook だけでは CMS で管理する情報が得られないので注意が必要そうです。 不要にムダなリクエストを発生させない 我々は Standard プランで利用しているので( 料金参照 )、データ転送量は 200GB となっています。ゲーム用のサムネイルやバナーなどの画像を microCMS からアップロードしたホスト先のままにしては転送量のリミットを超えると判断して、画像も自前の S3 でホスティングしています。もちろんハンドルしやすさを自分たちの手元に寄せるという意味も含みます。 さらに転送量だけではなくビルド時もエコな考慮をしました。Next.js ビルド前(前述の工程では 5 の前)に画像をダウンロードするスクリプトを実行しているのですが、前回ビルド時のタイムスタンプを status.json のように S3 バケットに同梱しておき、ゲーム情報のレコードに追加・更新があった場合のみ画像をダウンロードするようにしています。スクリプトのサンプルも掲載しますが、リトライを 2 度目まで行うこと( vercel/async-retry を利用)、並列実行できることなどを実現しています。 スクリプト参考 CI でのダウンロード実行 制約による、ステージングと本番データの差分チェック ステージング環境と本番環境などを用意するのはどのプロジェクトでも当然ですが、microCMS で環境によるデータの棲み分けをひとつのプロジェクトで実現しようと考えた場合、データが公開状態か下書き状態(いくつか種類があります)かで判断する必要が出てきました。 開発当時 microCMS では単一のレコード取得で下書きを取得できたものの、リストでは下書きを取得できないという問題がありました( 現在では取得可能です )。またテーブルにカラムを追加したいなどの改修に対応しづらいということもあったので、プロジェクトは「商用向け」「ステージング向け」と 2 つに分けデータも二重で管理しています。 ただステージング環境では本番環境同等のデータを入れて QA の受け入れをクリアしなくてはいけません。そのため 二重管理というのはステージング環境のテストデータを作りやすいという反面、本番と同等のデータを作るために人間によるオペミスのリスクが 2 倍になります。 具体的にはステージングで入れたデータと同じだと思って入れた本番データに差分がありリリースしてから発覚するようなケースでしょうか。 そういったリスクのために複眼チェックを人間がやるのはかなり馬鹿らしかったので、CircleCI Cron Job でステージング環境と本番環境の差分チェックを自動化しています。毎日 10:00 ころに実施され結果は Slack に報告されます。 ヘッドレス CMS の運用 開発者フレンドリーに作られたヘッドレス CMS は有効な選択肢であると今回採用して感じました。かゆいところに手が届くという開発者の気持ちが汲まれているだけではなく、採用した microCMS はなんと言っても日本語で直感的に操作が可能という、開発者と運用するメンバーにとってバランスが取れた製品であることも大きなメリットだと感じています。 API が GraphQL であるとか REST であるなどは関係なく、何よりサポートの手厚さや問い合わせなどスムーズにコミュニケーションできるというのはヘッドレス CMS を実際にプロダクトで採用するにあたって一番重要だと考えます。microCMS さんはツイートしたり管理画面からのチャット問い合わせなどにめちゃくちゃ早く対応してくれますし、数ヵ月前のやりとりを実装後にフォローしていただく場面もありました。 質問と返答 機能実装後のケア 最終的に microCMS をべた褒めするような記事になってしまいましたが(笑)、本日は下記をお伝えしました。 ヘッドレス CMS webhook から CircleCI での Next.js ビルドのためのジョブ起動、そしてデプロイ ヘッドレス CMS で商用環境・ステージング環境のデータ差分をチェックするためのしくみ 以上、武田( @tkdn )でした。
mediba Advent Calendar 2020 10日目担当の尾野です。 入社から昨年度まで関わっていた au Webポータルから離れ、今期からゼロイチの経験をしたくて新規事業創出部門にいます。 ただ、何を隠そう我々の部門は お金がありません 。 今回はそんなお金の無い部門が安価に CMS を立てたと言う小ネタ中の小ネタなお話です。 こんな人が対象 初期構築/ランニング共に安価な構成で構築したい CMS は非エンジニアでも利用可能なものを構築したい React(Next.js) の利用経験がある サービス運営の中で静的なランディングページの提供を必要とするケースは決して稀ではないと思いますが、WordPress の様なパッケージ化された CMS の場合、システム構築や公開後の可用性維持に思わぬコストが発生する事があると思います。 そういったケースには有用かと思います。 Netlify CMS is 何? https://www.netlifycms.org/ Open source content management for your Git workflow (Git ワークフローのオープンソースコンテンツ管理) Use Netlify CMS with any static site generator for a faster and more flexible web project (Netlify CMSを静的サイトジェネレーターと一緒に使用して、より高速で柔軟なWeb プロジェクトを実現します) 公式ページの冒頭の通り、GitBucket や Github 等のリポジトリをハブとし、静的サイトジェネレータと組み合わせる事で高速で柔軟な Web プロジェクトを実現出来るとの事です。 料金形態については Netlify Pricing( https://www.netlify.com/pricing/ )をご参照ください。 Netlify CMS を使う方の多くは、Netlify Hosting サービスとセットで使う事が多いようですが、 無償プランの範疇ではアクセス制限を掛ける事が出来ないようです。 ほとんどの場合、Staging 環境などにおいてアクセス制限を掛ける事は必須かと思います。 それを富豪的に解決したくない程にはお金をケチりたいので自前で立てる事にしました。 構成 CMS : Netlify CMS -リポジトリ : Github Enterprise Cloud 静的サイトジェネレータ:Next.js(ver. 9.4) markdown parser: gray-matter markdown 表示: react-markdown Hosting:AWS S3 + CloudFront 以下の様な構成にしてます。 特筆点で言うと以下くらいです。 CMS は staging 向き合いのみにした Netlify CMS では push するブランチを config.yml で指定する事が出来るが、それを環境変数毎に動的に変更させる為には config.yml を止めて直接ソースコードに設定を書く必要があり止めた( https://www.netlifycms.org/docs/beta-features/#manual-initialization ) 運用も staging で入稿して、OKなら production で入稿しなおして〜 となると二重運用になってしまうので、staging で OK なら slack 経由で Github Actions をキックし、production に deploy する方式にした アカウント管理は社の Active Directory と連携しそちらに委ねた SSO 連携出来る Github Enterprise Cloud の恩恵を受けた 自前環境でNetlify CMSが使えるようになるまで 認証 自前で構築となると、認証サーバーも自前で構築する必要があります。 以下でいくつか紹介されています。 https://www.netlifycms.org/docs/external-oauth-clients/ 今回は以下を採用しました。 https://github.com/marksteele/netlify-serverless-oauth2-backend 構築手順は以下のブログの通りに進めていけば良さそうです。 https://www.control-alt-del.org/blog/serverless-blog-howto/ ただ1点だけ、Github の OAuth Client を OAuth Apps ではなく Github Apps に変更しました。 アカウント単位ではなくリポジトリ単位で認証したいという理由なだけです。 Github Apps 作成時の入力/設定は以下くらいでした。 General > User authorization callback URL:[sls deployコマンドの出力結果のoauth url] Repository permissions Actions:Read & Write Pull requests: Read & Write CMS設定 config.yml の 以下セクション周りを変更します path/to/public/config.yml backend: name: github branch: deployment/staging repo: [該当のリポジトリ名] base_url: [払い出されたAPI Gateway の URL] auth_endpoint: /prod/auth commit_messages: create: 'Create {{collection}} “{{slug}}”' update: 'Update {{collection}} “{{slug}}”' delete: 'Delete {{collection}} “{{slug}}”' uploadMedia: '[skip ci] Upload “{{path}}”' deleteMedia: '[skip ci] Delete “{{path}}”' locale: 'ja' local_backend: true publish_mode: editorial_workflow media_folder: public/images public_folder: /images media_folder や config.yml を public/ に置いているのは、SSG テンプレートとして利用している Next.js 9.1 でサポートされたpublicディレクトリサポートに乗っかる為です。 https://nextjs.org/blog/next-9-1#public-directory-support その他 Preview 画面がそのままだとあまり Preview 感が無いので、Preview Template をカスタムしてます。 https://www.netlifycms.org/docs/customization/ path/to/public/admin/index.html <!doctype html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Content Manager</title> <script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script> </head> <body> <!-- Include the script that builds the page and powers Netlify CMS --> <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script> <script>CMS.registerPreviewStyle("./markdown.css");</script> <script type="module"> import IndexPreview from "./preview-templates/index.js" CMS.registerPreviewTemplate("index", IndexPreview); </script> </body> </html> path/to/public/admin/preview-templates/index.js import htm from "https://unpkg.com/htm?module" const html = htm.bind(h) const IndexPreview = createClass({ render: function () { const entry = this.props.entry const largeImage = entry.getIn(["data", "largeImage"]) return html` <div class="content"> <div class="about-wrap"> <div class="header-wrap"> <div class="header"> <div class="header-left"> <img class="logo-image" src="/images/Frame.svg"></div> <div class="header-right"> <ul> : : 完成版 こんな感じで動きます (もうちょっとクオリティ上げれば良かったですね、アニgif) さいごに Netlify Hositng 環境じゃなくとも割と簡単に動かす事が出来ます。 安心安価に LP 作りやブログシステム構築するなら参考にしてみてください。
こんにちは、Habits チームでエンジニアをしている中畑 ( @yn2011 ) です。 tl;dr Google Apps Script (GAS) を利用し、広告掲載の実績値を集計する作業を自動化した 約半年間運用した結果、時々エラーは発生するものの概ね有効に動作している なぜやったか 背景 Habits チームのプロダクトである 無料ゲーム は、無料で様々なブラウザゲームを提供しているサービスです。ビジネスとしては、サービス内の広告掲載によってマネタイズを行っています。 プロダクトを継続する上で、広告掲載の実績値は重要なため、 チームの夕会では Google Data Studio のレポート機能を利用して各指標の動向を確認するようにしています。 集計業務 このレポートを作成するため、データアナリストが毎日手動で広告プラットフォームの管理画面からデータを取得し、スプレッドシート上に貼り付けて整形・集計する業務を行っていました。1回あたり15分程度で済む作業ではあるそうなのですが、定型的な作業で自動化しやすそうですし、節約した時間や労力をもっと付加価値の高い業務に転換できれば最高です。 どうやったか システム概要 以下の理由から、GAS を選択しました。 広告プラットフォームが提供する API を利用して現在と同等の情報を取得できる 現在の集計業務はスプレッドシート上で行われている GAS のトリガー機能を利用してスケジュール実行が可能 開発 GAS はブラウザ上で利用可能なエディタが提供されており、コーディングや実行をブラウザから行うことができます。また、 clasp という CLI ツールを利用することで、ローカル環境で TypeScript を利用してコーディングし、GAS のプロジェクトに push することもできます。 なお、 clasp は 2019 年 7 月の マイナーアップデート(2.3.0) を最後にバージョンが上がっていないため、あまり活発にメンテナンスされていない OSS の利用に抵抗があるという意見もあるかもしれません。clasp を使用しないとしても、 ts2gas を使用することでコードのトランスパイルは可能ですし、型定義 ( @types/google-apps-script ) は別のコミュニティよって開発されています。ローカル環境で開発できることで、コードのバージョン管理がしやすく、ブラウザ上のエディタ特有の問題(例えばフォントの問題で全角数値と半角数値の区別が付かない等)も回避できるので、clasp を使用しないとしてもローカル環境で GAS を開発をすることはおすすめです。 今回は clasp を使用して、ローカル環境で開発しました。普段使いのエディタやキーバインド(私は VSCode + Vim キーバインド派)を使えますし、型定義によって適切に補完が効くこともあってチームで快適に開発ができました。 運用してどうだったか 単純な自動化とはいえ、やはりシステムを運用すると様々な課題に直面します。約半年間の運用で出会った課題について書きます。 エラー検知 トリガーを利用した GAS の実行でエラーが発生した場合は、トリガーの作成者宛にメール通知されます。特定のメールアドレスを通知先に設定することはできないようです(出来たら是非教えて頂きたい!)社内の個人アカウントで作成している場合、メール通知だけではその作成者が休暇中であったり、受信トレイで見落とすなどして、エラーの発見が遅れる懸念があります。私のチームではまだ実装していませんが、導入時に GAS の実行結果をチームの Slack に通知する等の対応も行ったほうが良いかもしれません。 トリガーの二重起動 現在までに、2, 3回発生したことがあります。どういうわけかトリガーが同時刻に2重起動します。発生すると売上等の数値が2倍になるため、すぐに気付いて修正することはできていますが、注意が必要です。 セル数上限 現在、1つのスプレッドシートに作成可能なセル数は500万個です。(空のセルも含む)なかなか上限に到達することはないんじゃないかと思いますが、日々の積み重ねは恐ろしいもので、実際に発生しました。API から取得したデータを保持するシートは、必要な列数が限られているので不要な列を削除して空白セルの数を減らして対応しました。 原因不明のタイムアウト こちらも 2, 3回発生しました。GAS が途中で停止します。スプレッドシートかGAS に一時的な障害が発生していたのかもしれませんが、原因の特定には至っていません。発生時には手動でスクリプトを起動することで対応しています。 まとめ 運用上の課題はあり、エンジニアがリカバリーにあたる必要はありますが、その頻度はあまり多くないです。GAS を利用して、広告掲載の実績値を集計する作業の自動化しビジネスチームの支援を行うことができました。これからも自動化可能な業務を見つけてエンジニアから提案・導入していきます!
こんにちは。 SrManager の尾野です。 今回は mediba における技術学習の取り組みについて紹介します。 タイトルこそふざけてますが真面目な取り組みです。 何をしたのか? 「伝説のクソゲー大決戦」と題して、Unity(2D でも3D でも可)を使ってクソゲーを作り、誰が一番のクソゲーを作ったかを競う会を開催しました。 何のためにやったのか? 5G関連を中心に各 PJ で Unity を使いそうな機会が増えてきており、 技術知見の相互補完の為 取り組みを通じて mediba として対応出来る 技術範囲を広げて行きたい エンジニア同士の横断連携的な意味合いも兼ねて → Web以外のプラットフォームへのニーズが高まっていく中、組織として対応出来る様に 相互補完しながら組織の技術力を高めていきたい ◎未経験領域の技術に対し、 学習機会/動機の創出 と 知識の相互補完による組織の学習力向上 を狙いとしました。 どうやって進めたのか? 期間 10月下旬〜11月下旬の1ヶ月。最終回に品評会を実施 毎週 Developer’s community の1枠を利用し、進捗やお困りごとの共有をしながら 業務に支障のない範囲で進めてもらう 作品の公開方法 developer は 週次で WebGL build してもらい、生成物を repository に push GitHub Actions で対象の S3 に配布 audience は CloudFront 経由で配布物をブラウザで参照 上記の様な簡易的な環境を用意しました。 進め方 週次で情報共有だけではなく、参考文献を随時共有しながら進めていく方式を取りました。 作品紹介 作品を一部アニgifに変換したものですが紹介します。 品評スライド 審査員を務めてくれた方が作ってくれました。 (品評会の様子を撮り忘れた事が悔やまれます…) 参加してくれた方々からの感想(一部) ・和気あいあいと技術的な工作するのは楽しかったです。 ・前提初心者&クソゲーなので敷居が高くないもの良かったと思います。 ・短期的に期限を決めて作ったので高速にキャッチアップできた ・お題がテックぽくなかったためかいろんなひとが見てくれた ・みんなの作品面白くて、品評も含めてすごく楽しかったです! ・こういう発表会などの目標がある方が勉強もやる気になりますねー! ・開発以外の人も楽しめてよかった。 ・未経験だった自分が今では「何をどうすればこう動く」が分かった状態になれた。 ・unityの学習を始めるまで一人では躊躇していたが、皆で始めたことで初めの一歩が踏み出せたこと。 最後に みんなほぼ未経験から始めて1ヶ月、業務時間以外の所で形にする事が出来ました。 個人で未経験領域に立ち向かうのは気力が入ります。 組織として立ち向かうには、同じスタート地点にいるいわば「同士」と、作る為の「動機」が学習力を強く後押ししてくれるんだなと改めて感じました。 未経験領域に対して「やったことないから出来ません」と言わず、組織として楽しみながら立ち向かえる文化を醸成していきます。
こんにちは。テクノロジーセンターの森竹です。 バックエンド開発を担当しています。その他にはアジャイル開発の推進や BIT VALLEY -INSIDE- のコミュニティ運営に参画しています。 今回は私が担当しているプロダクトである au Webポータル のチームで取り組んでいる チームビルディングの取り組み について、記事にさせて頂きました。 前提 2020年3月より会社的にリモートワーク指示な状況となり、au Webポータルチームのメンバー全員がリモートワークに移行しました。また2020年4月に組織変更があり、au Webポータルチームのメンバー約半分が入れ替わる状況となりました。同タイミングで新たなプロジェクトが始まることもあり、チームビルディングに取り組む良いタイミングだと考えました。 なぜチームビルディングなのか チームビルディングの取り組みを通じて、チームの成長段階の概念である タックマンモデル の各段階を進みつつ、成果を出すまでの時間を早期に押し上げたいと考えました。 リモートワークな状況ではありますが、チームメンバーのお互いのことを知りながら信頼関係を築き、そこから混乱や意見の対立を乗り越えて、チームとして成果を出していけるよう成長出来ればと考えています。 チームビルディングの取り組みの内容 偏愛マップ 自分の好きなものを1枚に書き込んだものが偏愛マップです。自己紹介を通じてお互いを知り合ったり、共通点を見つけたりします。書き方は自由でマインドマップ形式でも手書きでも構いません。作成した偏愛マップをチーム内で共有して雑談することで、コミュニケーションの量や質を上げる取り組みです。 今回はお二人の偏愛マップを紹介します。 一人目はプロダクトオーナー(PO)の偏愛マップです。手書きの温かみを感じたのと、自分もクリームソーダ好きだなーと気付きがあったのが印象的でした。 二人目はフロントエンドエンジニア(FE)の偏愛マップです。マインドマップ形式であるのと、改めて海外旅行の偏愛っぷりが想像以上だったのが印象的でした。 ニコニコカレンダー チームメンバーのコンディションや気持ち、モチベーションを見える化します。出社/退社時の1日2回入力する方針で運用しています。ニコニコカレンダーを俯瞰することで、チームメンバー個人やチーム全体の状況が把握できます。 今回はGoogle スプレッドシートを使用して作成しましたが、入力しづらい、忘れてしまうという課題がありました。ある時チームメンバーのデータアナリスト(DA)が、入力をサポートするGoogle フォームを作成してくれ、入力のしづらさをカイゼンすることができました。更にSlackのリマインダー通知も設定することで、入力を忘れてしまう課題もカイゼンしました。このようなカイゼンがチームメンバーから生まれてくることに、チームの成長を感じました。 将来的にはポストモーテムなどでタイムラインによる振り返りを行う際に、ニコニコカレンダーのデータを活用した取り組みをしたいと考えています。 星取り表(スキルマップ) チームメンバーのスキルを見える化します。個人で作るのではなく、チーム全員で作り上げます。また一度作って終わりではなく、継続的にアップデートすることで、チームの成長度を測ります。 星取表(スキルマップ)を俯瞰したり、プロダクト開発に必要なスキルとの DIFF を取ることで、チームの強みや弱みが見えてきます。チームの弱みや足りない領域に関しては、チームで補完して行く取り組みを行います。 具体的にはau WebポータルのWebアプリケーションの一部で Node.js を採用しているのですが、星取表(スキルマップ)から Node.js のスキルがあるメンバーが少ないことが見えてきました。 Node.js アプリケーション部分の改修が頻繁であることを鑑みて、 Node.js に関する勉強会をチームで開催し、プロダクト開発に必要なスキルを身に付けて行く取り組みを始めました。 またバッチアプリケーションの一部に Go を採用しているのですが、バッチアプリケーションの改修が稀であることから、習得希望者が多い状況ではありましたが Node.js のスキルを身に付けることを優先しました。 ドラッカー風エクササイズ 期待マネジメントの取り組みで、チームにおける期待を見える化して、すり合わせます。下記1.〜4.の質問を付箋紙などに書きながら共有します。 ⾃分は何が得意なのか
⾃分はどうやって貢献するつもりか
⾃分が⼤切に思う価値は何か
チームメンバーは⾃分にどんな成果を
期待していると思うか
最後に自分以外のチームメンバーから5.の質問に対して、5段階でフィードバックをしてもらいます。 その期待は合っているか 完全に合っていない あまり合っていない ふつう だいたい合っている 完全に合っている 個人的には5.の質問に対するフィードバックからチームで対話することに価値があると感じました。またドラッカー風エクササイズを通じて目的を再確認することが出来たことが大きな収穫と感じました。 最後に au Webポータルチームにおけるチームビルディングの取り組みを紹介しました。このような取り組みを一緒に推進してくれたスクラムマスター(SM)、取り組みに参加してくれた au Webポータルチームのみんなに感謝しています。 いわゆるチームビルディング三種の神器である インセプションデッキ は今後実施予定となりますが、今回紹介した取り組みは一度やって終わりではなく、 継続的に実施する 必要があると考えています。 また 目的 はチームビルディングの取り組みをすることではなく、 チームで成果を上げること です。目的を見失わず、行動して行きたいと思っています。
こんにちは。medibaのテクノロジーセンター・SRE Unitのイ・グンジェと申します。 私はSREエンジニアとして2020年4月からmedibaに参画することになり、 「テクノロジー」のものづくり部隊に属するかつ横断的にはauポータルコンテンツの「Daily Habits」のチームに参加しております。 この記事では、Daily HabitsチームとそのチームでのSRE(Site Reliability Engineering)活動についてお話させていただきたいと思います。 [参考] 2020年度エンジニア組織について Daily Habitsチーム サービス auポータルではニュース、天気、無料ゲームなどの多様なコンテンツがあります。 その中で、Daily Habitsチームは以下のコンテンツを担当しております。 毎日ポイント 無料ゲーム 特に「毎日ポイント」という名前からも分かるように、Daily Habitsチームは ユーザの「習慣」にフォーカスしたサービスを担当するチームで、ユーザーが毎日使いたくなるサービスを提供するのを目指しております。 チーム構成 Daily Habitsチームはより良い品質のコンテンツを提供するために、 スクラム開発を採用しております。 スクラム開発はソフトウェア開発における反復的で漸進的なアジャイルソフトウェア開発手法の1つであり、以下のような特徴があります。 開発プロジェクトを数週間程度の短期間ごとに区切る その期間内に分析、設計、実装、テストの一連の活動を行う 一部分の機能を完成させるという作業を繰り返しながら、 段階的に動作可能なシステムを作り上げる スクラム開発における反復の単位を「スプリント」という 実際に私たちのチームは1週間単位でスプリントを運用しておりまして、 以下のように多様なメンバーが毎日集まってサービスの改善点や今後のサービス方向性などについて話し合っております。 また、集まった内容は毎週金曜日に次回スプリント計画会でスプリント課題に上げて、迅速に実際のサービスにもDeployできるようにしております。 [参考]ものづくりプロセスを導入・改善した結果どうなったの?ってお話 Daily HabitsチームのSRE 上記の内容で言及したように、Daily Habitsチームは多様なポジションのメンバーが集まり、1週間のスプリント単位でサービスを運用しております。 何よりも異なる領域のエンジニアとすぐに意思決定できる環境である為、SREの概念を展開するのができると思いました。 ただし、SREの概念は人、組織、会社により異なると思い、私たちのDaily Habitsチームは「Daily HabitsのSRE」を定義し、自主的なSRE活動を展開することにしました。 Daily Habits SREの定義 1. 概要 SREはGoogleが「サービス管理における伝統的なSysAdminのApproach」から離れて、 Googleの方式で新しく解析し、提示した「サービス管理におけるGoogleのSysAdminのApproach」です。 尚、SREの背景はDevOpsであり、DevOps具現のためのBest PracticeがGoogleのSREです。 DevOps is a set of practices, guidelines and culture designed to break down silos in IT, ops, networks, security, etc. Site Reliability Engineering is a set of practices we’ve found to work, some beliefs that animate those practices, and a job role. [参考]Google Nextの発表資料 結局、SREはGoogleがDevOpsを具現するために実装した新しい「SysAdminのApproach」ということで、 Daily HabitsもDaily HabitsなりのSREを定義してDevOps的なエンジニアリングの具現を実施します。 2. Daily Habits SREの定義 Daily HabitsのSREは Daily Habitsサービスの信頼性を高めるための行動を実施します。 信頼性は日本産業規格では以下のように定義されています。 一定の条件下で、安定して期待される役割を果たすことのできる能力 アイテムが与えられた条件で規定の期間中、要求された機能を果たすことができる性質 そこで、Daily Habitsサービスで以下の活動をすることでサービスの信頼性向上に務めます。 安定して期待される役割を果たすことのできる能力を高める システム変更が安定的に行われるための環境を作る Game Habitsのコンテンツを安定的に提供するための環境を作る より快適で安定した環境でDaily Habitsの価値提供ができるようにする 与えられた条件で規定の期間中、要求された機能を果たす能力を高める Point Habitsのシーズン期間中、安定的にPoint付与に成功するための環境を作る Habitsコンテンツの障害を把握し、迅速に対応できる環境を作る サービス提供水準を把握し、改善に務める 3. Daily Habits SREのガイドライン Daily Habitsサービスの信頼性を高めるためには Metric & Monitoring Daily Habitsシステムのモニタリング体制を構築する モニタリングデータを活用してサービス水準の指標を設定する 設定した指標の状態を把握し、サービス水準を洞察する モニタリングデータに基づいて改善を繰り返し、Daily Habitsのサービス信頼性を高める SLO / SLIを定義する。 Capacity Planning Daily Habitsシステムを運用することに必要なリソースを把握・確保する サービス特性上、急激なTrafficはないため、過度なリソース消費に注意 Resourceを把握し、Scaleを調整する(削減・増設) コストを節約した分、新しい領域に投資する 快適なシステム環境でサービスを提供して信頼性を高める 適切にコストを配置する Change Management Daily Habitsシステムの変更を管理する システムの変更フローで人間を除去し、自動化することで障害を減らす システム障害の70%は人間が関与したのが原因になるため CI/CDツールを用いて開発したソフトウェアのBuild/Deployを行う Toil作業を減らす システムの変更において反復的でつまらない手作業をなくし、自動化させる。 システムの変更を自動化することで所要時間を減らす 節約できた分、サービス品質向上に務める 障害・所要時間を減らして信頼性を高める システムの自動化に務める Emergency Response Daily Habits障害対応体制を構築する 障害対応のマニュアル(playbook)を作り、より迅速に対応できるようにする できるだけ、障害回復時間を早くする。 誰でもできるようにする 障害による被害を減らすことで信頼性を守る・高める 障害対応をマニュアル化し、メンバーが迷わず対応できるようにする 最後に ここまで、Daily HabitsチームとSREについてお話させていただきました。 現時点ではDaily Habit SREの行動指針を定義しただけど思っており、 SLO/SLI指標の設定、Capacity Planningなどについて具体的な基準値を定義するなどの 課題が残っています。 その課題を達成することで、お客様に提供しているDaily Habitsのサービスの品質が 数値で把握できるようになったらより素敵なDaily HabitsのSREになれると思います。 まだまだ道のりが遠いと思いますが、これから「ヒトにHAPPY」を伝えるように 頑張って行きたいと思います。 ありがとうございます。
こんにちは。2020年度よりVPoEを務める事になりました新井です。 期が始まり早3ヶ月ほど過ぎますが弊社、エンジニア組織の「これまで」と「これから」について簡単にお伝えします。 これまで(2019年度)の組織 武田 、 下地 のブログエントリーでもお伝えしておりました通り、 弊社は「ものづくりカンパニー」になることを掲げ、組織全体で大きな変革を遂げている最中です。 http://www.mediba.jp/news/20191001/ エンジニア組織の変遷としては 一昨年度上期(〜2018/09)までは、機能型組織としてエンジニアは1つの本部で固まっていました。 一昨年度下期(2018/10〜)からは、事業型組織として「auパートナー本部」「コミュニケーションデザイン本部」という2事業本部にそれぞれの役割に応じた形にてエンジニアが所属する形となっていました。 この変遷についてはエンジニアは 最適な技術手段を使い、事業を持続的に成長させていく役目 だと考えているので、事業中心に考えていく文化が出来る大きな機会だと捉えてました。 エンジニア組織については以下に詳しく記載しておりますので読んでみてください。 [参考] 2019年度 medibaのエンジニア組織 https://qiita.com/mdb-hijikata/items/21a09ae804232d3d1535 これから(2020年度)の組織 2020/04から、よりチーム一丸でユーザーの課題に向き合い、正しいモノを創れる環境へと全社の組織構造が事業型からマトリクス型へ変化しています。 ざっくりと以下の通りになります。 要約すると 大きく「ビジネス」「テクノロジー」「クリエイティブ」の3つのものづくり部隊、それを支えるコーポレートの構成 各プロダクトの事業最大化/成長を担うプロダクトマネージャーを主軸としたプロダクトチーム構成(縦ライン) そこに参画し、エンジニアのマネジメントを主務としたテクニカルマネージャー構成 CxO直下のプロダクト横断的な戦略を担う各Unit構成 人/組織に於けるマネジメントの責任を担うVPoX構成 となります。 これから目指していく姿 テクノロジーセンターとして、以下を掲げております。 ビジョン:「良いもの」を届け続ける 言葉にすると普通な感じや当たり前の様に感じるかもしれませんが、我々はテクノロジーを通じて 「良いもの」とは? 「届け続ける」ためには? に常に向き合っていかなければなりません。 時代の変遷やそれに伴う技術/人の進化、価値の多様性に追従していく為には、 変化に強い、フレキシブルな組織 になっていく必要があります。 そのためには共に働く仲間が事業を通じて成長出来るサイクルを作っていかなければならないと考えております。 VPoEとして、マネジメントラインに以下のミッション/バリューを掲げております。 ミッション 個人、チームの生産性が最大限発揮できる環境、機会の創出をすることでエンジニアが働きたい会社をつくる 事業成長を通して技術で課題を解決する機会を多く提供してあげたいと考えております。 バリュー(全員) まずは自分に与えられている責務を果たす 次は隣の人から信頼を得る 自分が責任を持てる範囲(T字、π字)を広げるを繰り返す 自分→チーム→プロダクト全体→テクノロジーセンター全体→会社全体→社会 個人ではなくプロダクト/ユニットチームの総和で生産性が最大化されることを目的としております。 現状における課題 とはいえまだまだ課題は山積みの状態で、 2017年にCTOが抜けてから、エンジニア組織として弱体化している事実があります。 大きな所で言うと 採用力の低下 専門体制を見据えた採用戦略の見直し 人材/技術の固定化 注力事業へのアロケーション/アウトソース活用 横断的な連携が薄い TechLead体制の立ち上げや活動報告などのアウトプット共有の仕組み化 これらはテクノロジーセンターのKPIとし、解決に向けて尽力していきたいと思っております。 最後に まだまだ走り始めたばかりで、これから何が起こるかわかりません。 しっかりと課題と向き合い、エンジニア組織をより良く出来る様努めていきます。 共に課題と向き合い解決してくれる仲間も募集しております。 以上、お読みいただきありがとうございました。
こんにちは。2020 年 5 月にエンジニアとして入社した中畑( @yn2011 )です。 毎日ポイント の開発チームで TypeScript や Go を書いています。 今回は、なぜ私が mediba に入社したか、実際に入社してみてどうだったか、また、原則在宅勤務体制下でのオンボーディングを経験してどうだったか、について書いていきます。 なぜ入社したか 別の企業からも内定を頂いていたため、どちらの内定を承諾するのが自分にとってベストなのか悩みましたが、最終的には、mediba と配属チームの文化が決め手になりました。 技術や開発プロセスに対する様々な取り組み モダンな技術や実験的な開発プロセスの導入を積極的に推進できる環境は、エンジニアにとって魅力的です。mediba では、過去に au Web ポータル の技術刷新 や、 「ものづくりプロセスの導入」 などの事例があり、こういった取り組みを社内で推進していく立場にある方々と一緒に働く機会を得られるのはとてもエキサイティングで、魅力に感じました。 私が現在所属しているチームにおいても TypeScript や GraphQL を利用した BFF (Backend for Frontend) 層の導入や Go 言語によるバックエンド開発など比較的モダンな技術スタックによるプロダクト開発が行われています。私が TypeScript や Go 言語が好きで、今後強みにしていきたいと考えていたことも、このチームで働きたいと思った理由の 1 つです。 個人とチームを強くする 私は、チームは個人の集まりであり、チームを強くするためには個人の成長や情熱、そしてメンバーそれぞれが良好な関係を築けていることが大切であると考えています。 一次面接の場でチームに関する考え方について話題になった際に、配属予定チームでは、個人とチームを強くすることを大切にしていて Scrapbox を活用した分報を全員が行う(Slack の #times Channel の簡易版) ビジネス職・デザイナー職・品質管理職の方も交えたスクラムイベントの実施 原則モブプログラミングによる開発の進行 等の具体的な施策を行っているというお話を伺うことができ、自身の価値観とチームの価値観がマッチしていそうだなと感じました。 また、私がプライベートで行っている開発、技術ブログや登壇資料等のアウトプットについて評価して頂いていたという点も、しっかりと個人と向き合う文化の現れなのかな、と感じて安心感がありました。そういった取り組みについて入社後も期待をしているというお話を頂き、少なくともこの部分については自分がチームに貢献していけそうだなという自信にも繫がりました。 入社してどうだったか 次に、実際に入社してどうだったかについて書きます。 新型コロナウィルスの影響により入社 2 日目から在宅勤務 mediba では新型コロナウィルスの感染拡大を受け、 2020 年 3 月から原則在宅勤務体制となりました。 私自身も入社 2 日目から在宅勤務が始まりました。5 月に入社してから約 1 ヶ月が経過していますが、6 月現在もこの体制は継続しています。 したがって、実はこれを書いている現在も、チームのほとんどの方(選考時にお会いした方々は除く)と直接の面識はない状態です。私としても大きな不安を抱えながらの入社となりましたが、チームの文化やモブプログラミングの取り組みが在宅勤務下で有効に働いていて、想像以上にスムーズに業務をキャッチアップできていると感じています。 チーム文化 チーム文化については入社前の想像とほとんどギャップを感じていません。課題をチームとして解決していこうという空気が強く、過度なセクショナリズムや局所最適化は見受けられません。Scrapbox を活用した分報上でのコミュニケーションも活発で、業務上の連絡、ちょっとした困りごと・提案から「あつまれ どうぶつの森」の話題まで様々なやり取りが行われています。モブプログラミングについても文化としてしっかりと根付き、日々実践されています。 モブプログラミング チームでは、設計や検証も含めた開発関連のタスクを全てモブ(複数人による共同作業)で行っています。結果的に、1 日のほとんどの時間をチームメンバーと共有することになります。私自身は、モブプログラミング未経験であったため、特にドライバー(実際にコードを書く等の操作を担当する役割)を担当する際には緊張や不安もありましたが、チームのメンバーに恵まれたこともあり、自然と慣れていくことができた印象です。誰かと一緒に作業をすること自体に抵抗がなければ、モブプログラミングが未経験の方でも円滑に業務を進められるはずです。 また、モブプログラミングはメンバーと腰を据えて技術的な会話ができる貴重な時間でもあります。開発対象のシステムについてはもちろんですが、開発に利用している言語の特徴・型システムやライブラリの設計思想、プログラミングスタイル等、言語化して誰かと話すことで思わぬ気付きや理解が得られることがありました。こういった気付きを得られることは、とても価値のあることです。 例えば、私の場合は Go 言語で開発を行っていますが、モブプログラミング中に型システムについて話していて、理解不足に気づいたので業務後に学習し、その内容を個人の技術ブログに記事として投稿、投稿した記事についてメンバーからコメントを頂いて更に理解を深める…といった具合に、業務を通じて良い学習ループを回せています。 1 週間スプリント・週 1 リリース チームでは、スクラム開発を採用しており、1 スプリント期間を 1 週間としています。各スプリントにはリリース日が設定されていて、スプリントの成果は次のスプリントですぐにリリースされます。1 週間という短い期間であるため、各スプリントのリリース内容が必ずしもユーザーの目に触れられるとは限りませんがソースコードレベルでは確実に変更の発生するような開発フローが定着しています。 もちろん、リリース頻度は一概に高ければ良いというものではないですが非常にフロー効率の良い、インクリメンタルな開発が実現されていると感じています。特に、スピード感を持ってプロダクトを良くしていきたい、という思いが強い方には向いている環境だと感じています。 フルリモートでオンボーディング 冒頭でも書きましたが、入社 2 日目から在宅勤務が始まりました。オンボーディングについてもモブ形式で行われ、各種アカウントやツールの設定、開発環境の構築も常時 Microsoft Teams で画面共有を行って進めて頂きました。モブで進めているため、すぐに相談・意思決定できるので、オンボーディング初日からリポジトリの README.md を修正してコミットしたり、入社 1 週間前後でプロダクションコードの軽微な修正をコミットをすることもできました。リモートによるオンボーディングの進行自体は、モブで進める前提であれば在宅勤務でも特に支障はない印象でした。(ただし、以前から顔を合わせて業務をしていない相手とは心理的な距離を縮めにくい等の在宅勤務する上で普遍的な課題はあります) モブプログラミングの利点として、オンボーディング時の有効性はよく挙げられるようですが、特に新しく入ったメンバーがドライバーを担当することで、作業中に発生した疑問・相談をリアルタイムに解消できたり実は既存メンバーの暗黙知となっていることに気づけたりするので、確かにとても有効であるという実感があります。また、新しく入ったばかりだと、メンバーのことをあまり知らない状態からスタートしますが、モブを通して各メンバーの仕事の進め方や考え方に触れることにもなるので、相互理解を深めることができています。 まとめると、オンボーディングについては意外に何とかなった(して頂いた)という感想です。 まとめ この記事では、私が mediba への入社を決めた理由、実際に入社して 1 ヶ月間の間に感じたことについて書きました。もちろん、入社してまだたった 1 ヶ月時点の感想ではありますし、チームには改善していかなくてはならない課題もありますが、アジャイル志向なエンジニアの方におすすめできるチームです。この記事を読んで、 mediba に興味を持たれた方は、こちらからお気軽にご連絡ください! 株式会社mediba 採用情報
こんにちは。ものづくり推進部下地と申します。 もう試されている方もいらっしゃるかと思いますが2020年1月29日に 毎日ポイント をリリース致しました。 5つのミッションをクリアし成果報酬としてau WALLETポイントがもらえるサービスとなっており、au キャリア外の方も auID は発行できますのでこれをきっかけに試して頂けると幸いです。 ※推奨環境は、Android:5.x以上(Chrome51以上)、iOS:10.0.x以上になります。 本稿ではこの”毎日ポイント”の開発の取り組みについて説明させて頂きます。 なお、毎日ポイントは “ものづくり” の為の開発プロセス試行 を踏襲しております。 チーム構成 初期メンバーはフロンエンド2名、バックエンド3名、インフラ1名、スクラムマスタの計8人でした。途中入れ替わりがあったものの最終的には以下の構成となりました。 正直な所、全体アーキテクチャ設計、システム設計からリリースまでをスクラムで回した知見がなかったのでチームに最適化した結果、開発メンバーのみで構成された変則的なスクラムチームとなりました。 ※品管、デザイナー、アナリスト、プロダクトオーナーはプロジェクトに参画していたものの、開発によった話が多かったので必要な場合のみスポットでスクラムイベントに出てもらっていました。 現在は品管、デザイナー、アナリスト、プロダクトオーナーをメンバーに加えスクラムを回しています。 課題 課題を個人の問題ではなくチームの問題にしたかったこともあり、課題をある程度明文化する事から始めました。 大小様々な課題があったものの、その中でもDeveloper eXperience (以下DX)が上がる課題を主に抽出しました。 ミーティングが多い ミーティングが多いと単純に開発時間が短くなりますよね。開発チームは開発に集中するのが理想です 属人化 スーパーマンになるのは気持ちいいものの組織として個への依存はできるだけ取り除きたい DXの向上 DXが向上すると、開発効率やベロシティが向上し、結果ユーザーにいち早く価値を届けることができるのではないかと考えています 改善方法とアクション 課題に対するアクションは図の通りです。 詳細は下記になります。 開発コアタイム 13:30 〜 16:30の3時間は開発以外のミーティングを禁止にしました ミーティングを入れられる時間が午前中のみになるので入れる側もより精査しメンバーを選定するようになりました ただしスクラムマスタはステークホルダーとの会話があるので特例としました モブプログラミング ものづくりプロセスからモブプログラミングを導入。フロントエンド2チーム、バックエンド1チーム、インフラ+スクラムマスタの系4チームで稼働しました 原則チームで動くので人からチームへの依存になり結果、属人化排除に成功 ユーザーストーリーによってバックエンドチームがフロンエンドチームに参画したりとシームレスに開発を行う事ができ良い体験ができました 設計フェーズを手厚く バックエンド、インフラメンバーを中心にアーキテクチャ設計からメンバー全員で行いました メンバー全員参加なのでコストは高いもののアーキテクチャを1から設計する機会は少ない + アーキテクチャ設計に腹落ちして開発に臨んで欲しいと思い決行。 設計の知見も伝搬でき学びがとても多かったです ユースケース、シーケンス設計に時間をかけた 約1ヶ月程設計していました。メンバー内からも設計にコストをかけ過ぎではないのか?と指摘を貰いましたが結果かけてよかったと強く思います タスクの完了定義を変更 今まで完了の定義が実装のみだったがUnitTestを追加。追加した事でUnitTestを書く文化が浸透しました メンバーで協議し書かなくていいと判断したものもあります 仕様の相互確認会の実施 成果物の乖離があってはいけないのである程度実装及び設計後ステークホルダーを呼びメンバー全員で仕様及びユースケースの確認を行いました 結果、プロジェクトにどう影響があったの? 結果は・・・。 スケジュール遅延0回 開発効率、体験向上の影響なのかリリース日はもちろんの事、これまであってないようなものだったコードフリーズ日も遅延なし。 品質が凄く良い 技術の習熟度等他にも要因はあったものの、これはモブプログラミング + 設計フェーズを手厚くした事による影響だと思っています。 性能試験では高負荷をかけても落ちないから面白くないというメンバーが出たり(私の事です)、 総合試験に関してはメンバー全員が試験項目書が間違っているのではと?逆に不安になる程バグが少なかったです。 実装期間が3ヶ月と短かったのですが不具合も少なく全体的に高品質だったと思います。 ※因みにバグ件数ですが、機能バグ0件、デザイン崩など軽微なバグが27件でした。 仕様の相互確認会で安心し開発に尽力できた 要所要所で行った事でステークホルダー、開発メンバー共に成果物への安心感が得られ想像以上に体験がよくとても好評でした。 良い事ばかり!?とは言え課題も・・・ 良い事ばかり記述していますが課題もあり、、 ものづくり推進部はmedibaにおけるものづくりのプロセスを醸成する組織です。 今回実施したものづくりプロセスを組織に伝搬したいものの方法等を見いだせていないのが現状です。 良い体験等をどのように伝搬、醸成していくのもミッションの1つなので 引き続き試行錯誤して行きたいと思っています。 まとめ 巷ではアジャイル開発では設計不要説等ありますが、設計は大切だと再認識できたり DX向上の為チームに寄り添いチームとして成長していく事で、一体感はもちろんの事 高揚感も得られとても良い成功体験を得ることができました。 今後は課題解決とチーム全体の体験向上をより一層改善したいと思っています。 余談 スクラムを回していると気になるバーンダウンチャート。 プロジェクト開始時はきれいなバーンダウンではなかったものの最終的にはキレイなバーンダウンを描くことができました。
この記事は 「セイチョウ・ジャーニー」「挫折論への招待」 Advent Calendar 2019 18日目の記事です。 mediba創造開発部 バックエンドエンジニアの五月女(そうとめ)です。 私が一冊の書籍と出会うきっかけや出会い後の経験などをまとめました。 私の初めてのブログとなります。宜しければお付き合いください。 プロセスデザインラボへの参加 ある日、 ファシリテーション の力でコミュニケーションを活発にしていこうという取り組みをしている プロセスデザインラボ という社内グループを知りました。 当時、自分が所属するプロダクトのミーティングでは、いつも特定の人だけが発言するという状態で 全員参加 のコミュニケーションに変えたいなと悩んでいたところでした。 プロセスデザインラボの方たちは私とまったく面識のない方たちでしたが快く私を迎えてくれました。 フォースフィールド分析 、 モアレス分析 (下部写真2枚目)といったファシリテーション手法を知り、学びを自分のプロダクトにフィードバック出来た コト の他、この有志の ヒト たちがテック、アジャイル、スクラム愛❤️に溢れていてたくさんの情報を共有できた コト は私にとって貴重な経験になりました。 そこで知った コト の一つが 技術書典 の存在です。 技術書典 情報が少ないまま、会場の池袋へ。 開場30分前に到着も既に凄い行列。 この凄まじいまでの行列はディズニーランド以上なのではと思える程。 (5人幅の行列が500m以上1km未満くらい?) 休日の午前中から技術書を求めてこんなにたくさんの ヒト がいるなんて! それだけでとても刺激になりました。 時間になり入場、人混みをかき分けた先で一つの書籍( モノ )と出会ったのです。 セイチョウ・ジャーニー プロセスデザインラボ の ヒト たちに教えてもらった カイゼン・ジャーニー と名前が似てるなと思いながら何となく購入しました。 (カイゼン・ジャーニー著者の 市谷さん 、 新井さん に許可をもらった上でこの名前にしたそうです。) 市谷さん、新井さんの弊社過去ブログはコチラ 2018/11/02 カイゼン・ジャーニー著者 市谷聡啓氏 による講演会を実施しました 2019/09/26 medibaカイゼン啓蒙家が実現 『カイゼン・ジャーニー』新井 剛氏を招いたイベントを社内で実施しました! セイチョウ・ジャーニーで学んだことの実践 Twitterの有効活用 Twitter連携でのテストくらいにしか使っておらず非公開にしていたアカウントを公開にしてアジャイル、スクラム界隈の ヒト たちをフォローしてみました。呟くことは少ないけど、日々の情報収集にて刺激をもらう状態が作れました。 この時期から勉強会や技術カンファレンスに少しづつ参加するようになりました。 行動のハードルを低くする。小さな変化行動。 長女が小学校卒業とともに4年間所属していた少女ソフトボールチームを卒業、私はコーチとしてチームに残る事にしました。 自分が指導者なんてと思う感情もありながらもセイチョウ・ジャーニーが背中を押してくれた上での決断だとも感じます。 迷っている自分に やらない理由をみつけていない? とセイチョウ・ジャーニが問いかけてくれました。 一冊の書籍が自分のやった事がない、 自信がない事にあえてチャレンジできるマインド になれた コト のきっかけのように感じます。 この少女ソフトボールチームでは、11月に六年生にとっての最後の大会がありました。彼女たちがソフトボールに向き合った四年間の成長を想うと自然と涙がこぼれます。 私の娘もそうだったようにソフトボールというスポーツを通して、人としても大きく 成長 していくという点、本当によい活動だと感じます。 また ヒト の 成長 って何モノにも代え難い喜びなのだと、その 成長 を一緒に分かち合えるのならば本当に最高だし、それはスポーツでもエンジニアリングでも共通していえる コト ではないでしょうか。 (11月秋季大会にて。試合前のシートノック。私は初めての経験で指導者の身でありながら私もまた日々成長の場を頂いております。) エンジニアリングマネージャーに 今年4月から EM をやらせて頂くことになりました。 当初はとても不安が大きかったと記憶していますが、そんな時に同じ組織のメンバーの一人から 「五月女さんに協力したい。一緒に組織を盛り上げたい。」 と言ってくれている ヒト がいました。 この言葉は、私の背中をとても強く押してくれましたし、 一人じゃない んだって気付かせてくれたし、どんな コト だって乗り越えられる、そんな気持ちにさせてくれる力のある言葉でした。 私は共にエンジニアリングする仲間になんて恵まれているのだろう! 私の過去を振り返った時、ソフトウェアを作る上で携わった方々の言葉に何度も支えられてきたなと強く感じます。 今回頂いた言葉は私がエンジニアリングやその組織運営に 前向き になれる、そんな言葉のひとつになったと。 そして開発を続けていれば、よくない状況で心が沈むなんてこともありますが、そんな時にこそ本当に救われます。もらった言葉たちに。 そしてこんな出来 ゴト があるからこそソフトウェアを作るって コト をやめられないと感じるし、これからも続けようと強く想うのです。 そんな言葉を身近な ヒト に伝えることができる、 そんなヒトに私もなりたい! EOF2019 セイチョウ・ジャーニー の共著者の一人、 ゆのんさん が EOF2019 に大きく関わっていた コト を知ったのはイベント開催直前でした。 もしかして、どこかで少しでも短い時間会話できたら、感謝を伝えたい。そんな風な想いを抱きMacBookAirと一緒に セイチョウ・ジャーニー をバッグの中に忍ばせて会場に向かいました。 そして偶然(?) 廊下 を歩いていたゆのんさんを見つける コト ができて 「今の私があるのはこの本のおかげです。」 ってセイチョウ・ジャーニー片手に伝えることができました。 オープニングセッションで、 技術カンファレンスは廊下でのインフォーマルな会話が重要 というような話題がありましたが、私にとってもその通りになりました。 また感謝の気持ちをオフラインで伝えるという貴重な経験ができました。 広報ブログで社員紹介される 私がmedibaでの経験をふりかえってみたのは、 社員紹介 で取り上げてもらうことがきっかけでした。 どんな コト を話そうかなと事前にmedibaに入社してからの記憶をめぐらせました。 ふりかえりの中で セイチョウ・ジャーニー が頭に浮かび話題にしたく、その許可を頂くために共著の一人である てぃーびーさん にDMできた コト 。 この行動もまた EOF2019 で学んだ、 空気を読まずにDMする という コト の実践でした。 (EOF2019「 Podcastという組織文化戦略 」にて) まとめ プロセスデザインラボ、技術書典、セイチョウ・ジャーニー、少女ソフトボール、エンジニアリングマネージャー、EOF2019、ゆのんさん、てぃーびーさん、その他このブログでは書ききれないプロダクトを通しての出会い、助け合い、衝突、失敗やトラブルも含めて全部、 私のマインドを育ててくれたヒト、モノ、コト だったんだ! これって セイチョウ・ジャーニー に書かれていた 計画的偶発性理論 だったのかな。 全てに感謝です!! ここまてお付き合い頂いた ヒト 、本当にありがとうございました! 皆さま良いお年を。
この記事は Node.js Advent Calendar 2019 、15 日目の記事です。 こんにちは。ものづくり推進部の武田( @tkdn )です。 先日 11/30, 12/1 に弊社がスポンサードさせていただいた JSConf.jp に参加してきました。当日参加したセッションの雑多なメモはパブリックに残し、社内のコンフルには整理したものを展開し知見を持ち帰って実務にいかそうと思います。 会場廊下では、お世話になった方、知り合いのエンジニア、発表された方と立ち話する機会もありまして、情報交換や普段オンラインでのみやりとりしている方ともオフラインでコミュニケーションできて非常に充実したカンファレンスでした。 初日にスポンサートークの枠で 5 分程度ですが、mediba での フロントエンド, JavaScript についてお話させていただきました。表面的なことばかりだったのでもう少し泥臭い話もすればよかったかなと感じています( こういうのとか 、 こういうのとか )。 日本での初開催に向けて尽力された運営の皆さま、本当にありがとうございます。 スポンサートーク: mediba におけるフロントエンド, JavaScript 当日参加セッションメモ: JSConf.jp 雑まとめ さて本題の記事ですが、今年度から Node.js でのサーバ運用をはじめてつまづきのあった、 ロードバランサーと Express そのタイムアウト、ランタイムバージョンアップ後の問題 、そして問題に対する課題感について書いています。 Node.js(Express) サーバ運用が始まる 2019 年 3 月に実施した au Webポータルのリニューアルには Next.js を利用していますが、もちろんそこには Express の存在も要るわけで、それに伴う新しい運用が始まるということでもあります。 正直なところ Node.js のサーバ運用経験があるメンバーが豊富にいたわけではないので、負荷試験・性能試験等で安全はもちろん担保の上で、運用に乗ってからいろいろ粗(というと言い方はよくないですが)は出るだろうなと思っていました。 ELB, Express のタイムアウトはきちんと確認しよう au Webポータルの現アーキテクチャは CDN, AWS を利用しておりリクエストを受ける前段は Akamai CDN -> ELB -> ECS クラスタ(Node.js コンテナ) という形なのですが、リリース後すぐに Datadog のアラートとログから、極稀に ELB が 504 を返すことがあるということが分かりました。全体の1パーセントに満たないログです。 504 だとユーザ面に影響があるのではというツッコミが入りそうですが、最前段にある Akamai でオリジンが 5xx のステータスコードを返却する場合には正常時の stale cache を返却する構成になっているため、ユーザ面への影響はありません。ありませんが、これはこれで問題です。 504 を返していた原因としては Express 側の keepAliveTimeout を ELB に合わせたものにしていなかったというのが原因になります。リリース前に気付くべきことなのかも知れませんが、この問題については性能試験においても検出はされておらず、運用に乗せてから検出されたケースになります。 解決方法としては、ELB のアイドルタイムアウトのデフォ値が 60 秒なので、express 側は 60 秒以上にしておくといいかもしれません。 const app = express(); const httpServer = app.listen(3000, () => console.log('Example app listening on port 3000!')); /** @note タイムアウトの設定 */ httpServer.keepAliveTimeout = 70000; 参考: HTTP | Node.js v12.13.1 Documentation (デフォルト値は 5000 となっています) Node.js v8.x -> v10.x バージョンアップ Node.js v8 の EOL は年内(2019-12-31)となっていますが、皆さんきちんとアップデートできていますか? 弊チームはギリギリでバタバタとやりたくなかったため、au Webポータルチームが抱えているプロジェクト群(一つではありません)で利用している Lambda の Node.js ランタイムを v10 へ移行するところから始めました。割と早い段階でランタイムアップデートを行うに至った経緯としては、 Lambda ランタイムの AMI が更新 というアナウンスがあったため、同時に確認し追ってかかる運用コストを減らそうという意図もありました。 アップデートによるパッケージの影響や動作確認などを終え、Lambda AMI 変更・ランタイムバージョンアップはいくつか課題があったものの解消し 7 月段階で全て v10 に切り替えを完了しています。 その後 8月に Express を運用しているコンテナ内のランタイムアップデートへと作業を進めたのですが、Node.js のバージョンアップはアプリが依存するパッケージも多く影響範囲の調査だけで相当時間がかかります。そのため、ローカル環境コンテナ内ランタイムバージョンアップ、ステージング環境へのデプロイなどで実動作から確認するのが一番手っ取り早く、動作確認とステージング環境からのアラートがないことを確認し、バージョンアップ後の担保としました。 JavaScript = Node.js はブラウザのランタイムとしてスタートしている言語であること、Chrome に搭載されている V8 をエンジンとしていること、などから後方互換性がある程度保ったままメジャーバージョンが上がっていきます。そして偶数バージョンが LTS のリリースラインにあり、奇数はすぐ EOL をむかえるリリースプロセスになっています。 バージョンアップリリース後にタイムアウト再発 実働しているコンテナのランタイムバージョンアップのリリース後、見覚えのあるアラートが上がるようになりました。 前述の ELB タイムアウト問題の再発です。 この時も数パーセントのかなり低い割合で現象が発生していました。おそらく同様の問題であるような気がしていたのですが、いろいろ調べたところ下記の記事にあたり大変助かりました。 Check Your server.keepAliveTimeout - Shuhei Kagawa Regression issue with keep alive connections · Issue #27363 · nodejs/node · GitHub 記事にある内容は前述のロードバランサーのタイムアウトと Exress のタイムアウト見直しと同じになりますが、末尾に重要な情報とリンクがあり、二つ目の issue に詳細が書かれています。 結果から言うと v10.15.2 以上の場合は server.headersTimeout の指定を上記の keepAliveTimeout で指定した数値より大きくする必要があります(指定がない場合、デフォルト値は 40000 です)。 const app = express(); const httpServer = app.listen(3000, () => console.log('Example app listening on port 3000!')); /** @note タイムアウトの設定 */ httpServer.keepAliveTimeout = 70000; httpServer.headersTimeout = 80000; 該当の issue で話されている内容ではありますが、Slowloris HTTP DoS 攻撃(不完全なヘッダーを送り続けてサーバのプロセスを圧迫するような攻撃です)に対する防止策のコミット 1a7302b から変更があるようです。 今回の件から見えてくる課題 運用の知見がなかったものは蓄積する他ありませんが、今回その中でも課題と感じることが出てきました。 バージョンアップの担保とは 環境差異による再現性の低さ ひとつめ、バージョンアップについてです。これは EOL がついてまわる言語を扱う以上向かい合わなくてはいけませんし、どこで安全性を担保するのか難しいところです。アップデートにより obsolute された API 等は調査で知り得るものの、既存で存在しユースケースの中で発生しえる現象については実働で確認するしかありません。 担保できる機能テストの自動化やステータスチェック等考えられることは多くありますが、何年も保持できる LTS バージョンはなく、比較的早いリリースサイクルに対してどう向き合うかは課題だと感じます。 ふたつめ、環境差異による再現性について。こちらについては、ステージング環境でタイムアウトの現象を検出できなかった点が課題と感じています。今段階でも再現せよというお題に明確な解答が出せていません。プロダクション環境で稀に出たアラートだったというところで片付けてもいいのかも知れませんがなんだかモヤります。 具体的な回避策については記述したとおりではあるものの、あまり決定的な解がなくもんやりしつつ、以上 ELB のアイドルタイムアウトと Express(Node.js)サーバのタイムアウトについて武田が書きました。 mediba ではエンジニアだけでなく一緒にプロダクトを良くしていくメンバーを募集中です。 特に TypeScript でサーバサイドを書ける方や React に取り組みたい方がいらっしゃるとわたしが一方的に嬉しいのでぜひよろしくお願いいたします。