TECH PLAY

株式会社mediba

株式会社mediba の技術ブログ

167

こんにちは。武田( @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 に取り組みたい方がいらっしゃるとわたしが一方的に嬉しいのでぜひよろしくお願いいたします。
アバター
はじめに SRE 推進部インフラストラクチャーグループの間山です. 弊社では大量の EC2 インスタンスを起動しており, コスト削減できないかという課題から一部のシステムにスポットインスタンスを導入しました. しかし,導入したシステムのスポットインスタンスが AWS 側により全台 Terminate されシステムに遅延が生じました. スポットインスタンスのみの Auto Scaling Groups を使用していたため, EC2 インスタンスが Terminate された数分後には新しい EC2 インスタンスが起動されましたが, 再度全台 Terminate される状況でした. そこで,Terminate されないオンデマンドインスタンスとスポットインスタンスを組み合わせることができる EC2 Auto Scaling Gourps という機能を使用したことにより可用性の担保を実施いたしました. EC2 インスタンスの購入方法 EC2 の購入方法は以下の 4 つの購入方法が存在します. 購入方法は異なりますが作成されたインスタンスの性能は同じですので適切な選択をしましょう. オンデマンドインスタンス EC2 インスタンスの定価の購入方法 使用した時間のみ課金されていく スポットインスタンス オンデマンドインスタンスの単位時間あたりの価格より割引される AZ (アベイラビリティゾーン)にて EC2 のキャパシティがない場合は Terminate される RI (リザーブドインスタンス) EC2 インスタンスを長期間使用する場合に割引が実施される 購入したインスタンスタイプを起動した際にオンデマンドではなく RI として適用される Savings Plans 1 年もしくは 3 年の期間において,コミットメント値を指定する コミットメント値は,1 時間あたりに使用する料金である コミットした値に対して割引が発生する スポットインスタンスについて 概要 同一のインスタンスタイプ内にて起動できるインスタンス数の枠(スポットインスタンスプール)が空いている場合, AWS 側は オンデマンドインスタンスより割引をされたインスタンスを提供をします. スポットインスタンスの価格は,スポットインスタンスプールの空き状況によって変動します. 空きが無い場合にはスポットインスタンスの価格が上昇し,逆に空きが多い場合には価格が下降いたします. スポットインスタンスを起動する場合には予め上限価格を設定しておき, それよりも現在の価格が上回った場合にはインスタンスが Terminate されてしまいます. なお,上限価格のデフォルト設定はオンデマンド価格になっております. 以下のコンソール画面より,スポットインスタンスの価格の変動について調べることも可能です. EC2 ダッシュボード内の,インスタンス -> スポットリクエスト -> 価格設定履歴より確認できます. デメリット スポットインスタンスは,オンデマンドよりも価格が低くよりコスト削減に向いております. しかし,以下の条件に達するとインスタンスは中断の後,Terminate されます. スポットインスタンスの料金が設定した上限価格より上回る スポットインスタンスプールの空き容量が無くなった 中断通知を受け取った後は,2分間与えられるため,その間にインスタンス内の Draining 処理が必要になります. ここでは詳しく説明は致しませんが,スポットフリートを使用することで中断テストが可能なので事前に試すことも可能です. よって,スポットインスタンスを使用する際には,データを特定のインスタンスに持たせないアプリケーション設計が必須です. EC2 Auto Scaling Gourps と起動設定,起動テンプレートについて スポットインスタンス単体での起動も可能ですが,Terminate されてしまいインスタンスが存在しない状態になります. また,システムの柔軟性に欠けてしまいスケーリング,オートヒーリングをしたい場合には向いておりません. そこで,EC2 Auto Scaling Gourps という機能を使用することで, 起動したいインスタンスタイプの組み合わせや常に起動したいインスタンスの台数, スケーリングする条件を設定できます. EC2 Auto Scaling Gourps では,AMI,キーペアなどの インスタンスの起動に関する設定が必要となり以下の機能を使用しなければなりません. 起動設定(Launch Configuration) 起動テンプレート(Launch Template) 我々が最初に使用したのは起動設定であったため, オンデマンドインスタンスとスポットインスタンスの組み合わせを使用することが出来ませんでした. 一方,起動テンプレートは多くの設定項目が存在し,なおかつテンプレートのバージョン管理も できるので間違ってデプロイした際にはロールバックもできます. よって EC2 Auto Scaling Gourps との組み合わせには, 起動テンプレートを使用することで柔軟に変更しやすいと考えられます. 検証実験 起動テンプレート と EC2 Auto Scaling Groups には多くの組み合わせ設定があるため, 各パラメータの変更することで,起動される EC2 インスタンスについて検証を実施します. 今回は特にスポットインスタンスとオンデマンドインスタンスの起動配分について焦点を当てていきます. 設定内容 環境 インスタンスタイプ: m5.large インスタンス数: 20 台 起動テンプレート EC2 ダッシュボード内の,インスタンス -> 起動テンプレート -> 起動テンプレートの作成 へ移動します. 基本的な起動テンプレートの設定については起動設定(Launch Configuration)と同じになりますが, インスタンスタイプを EC2 Auto Scaling Groups にて変更できるようにするため, 起動テンプレートには含めない を選択いたします. 下へスクロールすると,高度な詳細を設定できるようになり以下の部分を編集しました. 購入のオプション: チェックボックスに マークしない IAM インスタンスプロフィール: セッションマネージャーを使用するために適切なプロフィールを選択 EC2 Auto Scaling Groups EC2 ダッシュボード内の,Auto Scaling -> Auto Scaling グループ へ移動します. Auto Scaling グループの作成画面では,起動テンプレートにチェックを入れ, 先程作成した起動テンプレート名を選択します. フリートの構築にて, 購入オプションとインスタンスを組み合わせる に チェックを入れることで詳細な設定が可能になります. インスタンスタイプは2つのインスタンスタイプが推奨されておりますが, 検証目的のために,m5.large のみを使用しております. 商用で使用する際は他のスポットインスタンスプールへのリクエストが 通りやすくするために,複数のインスタンスタイプを指定するのが良いでしょう. インスタタイプの分散 のチェックを外すことでインスタンスの配置方法を詳細に設定できます. 今回は以下のパラメータを操作した場合に,オンデマンドとスポットの配分を検証します. オプションのオンデマンドベース ベースを超えるオンデマンド割合 Auto Scaling Groups の設定後も,操作 -> 編集 より インスタンス数やスポットとオンデマンドの配分を変更できます. 結果 20 台のインスタンスを起動した場合のスポットとオンデマンドの配分結果は以下の表になります. 結果については, オンデマンドインスタンスの起動台数 : スポットインスタンスの起動台数 です. オプションのオンデマンドベースのインスタンスが起動したのち, 残りのインスタンスについては割合で計算されるようです. コスト戦略 上の表から,1 ヶ月間(30 日間)起動していた場合の価格を計算します. m5.large のオンデマンド価格は, $0.124/時間 とします. スポットインスタンスの価格は,スポットインスタンスの概要に貼り付けた以下の価格とします. 時間ごとの価格の変化については考慮しておりません. ap-northeast-1a: $0.0350/時間 ap-northeast-1c: $0.0350/時間 なお,検証ではインスタンスは,アベイラビリティゾーンに均等に配置されておりましたので, 各 AZ のスポットインスタンスの価格も均等にいたします. 以下の表は各インスタンスの配分のコストを計算した結果になります. 1 ヶ月の料金が$1000 以下にしたい場合には,20%:80%の割合が良さそうです. まとめ スポットインスタンス導入時の失敗から,いかに可用性を高めコスト削減できるかという課題を解決するために, 起動テンプレートと Auto Scaling Groups 利用し, スポットインスタンス,オンデマンドインスタンスを起動しました. 今回は EC2 インスタンスのみに焦点を置きましたが,ECS のインスタンスや EKS のクラスタにも応用が可能です. インスタンス性能は変化せず,コストが削減できるのはとても有意義であり, 他のサービスリソースへ投資する余裕が出てきます. ぜひとも積極的にスポットインスタンスと Auto Scaling Groups を活用していきましょう. 最後に mediba では,より良い環境を作っていきたいエンジニアを随時募集中です. 採用ページは こちら
アバター
こんにちは、インフラストラクチャーグループの沼沢です。 今回は、タイトルの通り 公開日時の指定が可能 な静的コンテンツ配信用のシステムを、サーバレスで作ってみました。 なお、リージョンは全て東京リージョンとします。 構成図 まずは構成図です。 公開日時が指定可能な仕組み S3 には、時間で公開状態へ移行するような設定や仕組みがありません。 これを実現するために、S3 オブジェクトのキーをもとに、Lambda を利用して、あたかも公開日時を指定しているかのような動きを実装します。 なお、本稿では分まで指定できる設定としていますが、要件によってカスタマイズすることも可能です。 S3 「非公開 S3 バケット」と「公開用 S3 バケット」を用意 「非公開 S3 バケット」のバケット直下には、プレフィックスに 公開したい年月日時分を示す yyyymmddHHMM 形式のディレクトリ を作成 2020年1月1日0時0分に公開したい場合は 202001010000 作成した公開予定ディレクトリの配下に、公開予定のファイルをアップロード 余談ですが、バケットポリシーを駆使すれば非公開と公開でバケットを分けなくても実現は可能なのですが、今回は分けています。 というのも、バケットポリシーは設定を誤ると root 以外操作できない状態になったり、非公開のつもりのディレクトリが公開状態になっていて公開前情報が流出しまったり… とにかく、2つ用意したからってコストに差がでるわけでもありませんので、なるべく設定をシンプルにするためにバケットを2つ用意することにしました。 CloudFront 「公開用 S3 バケット」をオリジンとして、CloudFront を経由してコンテンツを配信します。 今回用意する仕組みでは 公開済みファイルの上書きも可能 となっていて、分毎にコンテンツが上書きされる可能性があるため、CloudFront の Default TTL を60秒としておくのが良いでしょう。 また、S3 への直アクセスを防ぎ、必ず CloudFront を経由するようにするため、Origin Access Identity を設定することをおすすめします。 Lambda 「非公開 S3 バケット」から「公開用 S3 バケット」にファイルをコピーする処理を行う公開用 Lambda を用意します。(ソースコードは後述) この Lambda では、ざっくりと以下の処理をしています。 起動した年月日時分に該当するディレクトリが「非公開 S3 バケット」直下に存在するか確認 存在すればその配下のファイルを全て公開用バケットにコピー コピーする際は、プレフィックスの yyyymmddHHMM は除いたキーでコピー ディレクトリ構成も全てそのままコピーする 例えば、 202001010000 ディレクトリが存在する場合のコピーは以下の様なイメージ。 s3://非公開S3バケット/202001010000/aaa.html s3://非公開S3バケット/202001010000/hoge/bbb.html s3://非公開S3バケット/202001010000/hoge/fuga/ccc.html ↓ s3://公開用S3バケット/aaa.html s3://公開用S3バケット/hoge/bbb.html s3://公開用S3バケット/hoge/fuga/ccc.html その他、この Lambda には以下のような設定をしておきます。 IAM ロールには AWSLambdaBasicExecutionRole と AmazonS3FullAccess のマネージドルールをアタッチ ただし、 AmazonS3FullAccess は強力なので、本番利用の際は適切に権限を絞ったカスタムポリシーの用意を推奨 タイムアウト値は、コピーするファイルの量にもよるので、要件に合わせた設定を推奨 CloudWatch Events 公開用 Lambda を毎分キックするように CloudWatch Events を設定 Cron 式で * * * * ? * を指定 Cron 式の詳細は こちら を参照 Lambda Function のソースコード 今回は Python 3.7 用のソースコードを用意しました。 やっていることは単純なので、得意な言語に書き換えても良いと思います。 unpublish_bucket と publish_bucket の値だけ変更すれば動くと思います。 import json import boto3 from datetime import datetime, timedelta, timezone JST = timezone(timedelta(hours=+9), 'JST') s3 = boto3.client('s3') unpublish_bucket = 'unpublish_bucket' # 非公開 S3 バケット publish_bucket = 'publish_bucket' # 公開用 S3 バケット def lambda_handler(event, context): now = "{0:%Y%m%d%H%M}".format(datetime.now(JST)) # 現在日時(分まで) now_format = "{0:%Y/%m/%d %H:%M}".format(datetime.now(JST)) # 現在日時(分まで) unpublished_list = s3.list_objects( Bucket=unpublish_bucket, Prefix=now + '/' ) if not 'Contents' in unpublished_list: print(f'[INFO] {now_format} に公開予定のファイルはありません。') return flag = False for obj in unpublished_list['Contents']: unpublished_path = obj['Key'] if unpublished_path.endswith('/'): continue publish_path = unpublished_path.replace(now + '/', '') copy_result_etag = publish_file(publish_path, unpublished_path) get_result_etag = publish_file_check(publish_path) if copy_result_etag == get_result_etag: print(f'[SUCCESS] s3://{unpublish_bucket}/{unpublished_path} -> s3://{publish_bucket}/{publish_path} にコピーしました。') flag = True else print(f'[FAILED] s3://{preview_bucket}/{unpublished_path} -> s3://{publish_bucket}/{publish_path} のコピーに失敗しました。') if flag == False: print(f'[INFO] {now_format} 用のディレクトリ(s3://{unpublish_bucket}/{now}/)はありましたが、ファイルがありませんでした。') def publish_file(publish_path, unpublished_path): result = s3.copy_object( Bucket=publish_bucket, Key=publish_path, CopySource={ 'Bucket': unpublish_bucket, 'Key': unpublished_path } ) if 'CopyObjectResult' in result: return result['CopyObjectResult']['ETag'] else: return None def publish_file_check(publish_path): result = s3.get_object( Bucket=publish_bucket, Key=publish_path ) if 'ETag' in result: return result['ETag'] else: return None 注意事項 前述の通り、Lambda 用の IAM ロールに付与する権限には注意してください CloudWatch Events は 分 が最小単位です 正確にその分の0秒に Lambda が起動するわけではありません よって、秒まで指定した公開日時を指定することは本稿の内容では実現できません コストについて 大抵の Lambda 実行は空振りになってしまってコストがもったいないと思うかもしれませんが、Lambda は無料利用枠の恩恵が大きく、この仕組だけでクラウド破産のようなことにはならないかと思いますので、そこはご安心を。 EC2 等、時間単位で課金されるものを利用していないため、トラフィックによる従量課金を除いた場合に発生する主要なコストとしては以下のものぐらいかと思います。 Lambda の無料利用枠を超えた分 CloudWatch Logs(Lambda のログ) への転送量と保存容量 S3 の保存容量 Lambda のコードをチューニングしたり、「非公開 S3 バケット」を低頻度アクセスストレージにしたりすると、更にコストを抑えられます。 その他 分毎ではなく時間毎など他の間隔にする 例えば時間毎で公開設定をしたい場合は、本稿の仕組みを以下のように修正すれば実現可能です。 アップロード時のプレフィックスを 公開したい年月日時を示す yyyymmddHH 形式のディレクトリ を作成する CloudWatch Events の Cron 式に 0 * * * ? * を指定 Lambda のコードの現在時刻を取るフォーマットを時間までのものにする ついでに CloudFront のキャッシュ時間も、公開間隔に合わせて調整することでキャッシュ効率も上がります。 非公開日時の指定をできるようにする 本稿の仕組では、非公開(「公開用 S3 バケット」からのファイル削除)日時の指定までは行っていません。 そこで、CloudWatch Events と Lambda の組み合わせをもう一組作るのも良いと思います。 Lambda でのエラー発生時のリカバリ策を仕込む 本稿では、Lambda でエラーが発生した際のリカバリを考慮していません。 コピー失敗などが発生すると、公開されるべきコンテンツが公開されず、エンドユーザやビジネスへの影響が出る事故になりかねません。 Lambda のコードでは、 print で CloudWatch Logs に [SUCCESS] や [FAILED] を出力するようにしてあるので、その文字列を CloudWatch などで監視して、検知をトリガーにリカバリ用の仕組みがキックされるようにしておくと、事故の発生率を下げることができます。 簡単に思いつくリカバリの方法としては、もう一度 Lambda をキックするなどしょうか。 もしくは Twilio 等の電話通知を行い、それに気付いた運用者が、「非公開 S3 バケット」から「公開用 S3 バケット」へ、手動でコンテンツをコピーする形でも良いかもしれませんね。 あとがき 今回は、公開日時指定可能な静的コンテンツ配信システムをサーバレスで作成しました。 AWS を利用する場合、安易に EC2 でごにょごにょしようとせず、「可能な限りサーバ管理を AWS に任せる」という発想のもと、マネージドサービスを活用した設計を心がけてみましょう。 そうすることで、実際のインフラコストだけではなく、構築時や運用開始後の人的コストが劇的に下がり、エンジニアが より価値を生み出す生産的な活動に時間を割けるようになる ので、ぜひ検討してみてください。 ちなみに、この仕組みは3時間程度でできました。 本稿の執筆にかかった時間の方が長いです。 お後がよろしいようで。
アバター
こんにちは。ものづくり推進部の武田です。 ブログを書くたびに触れている所属の「ものづくり推進部」ですが、 プロダクトを作るヒトたちをなんとなく応援する 部署では ありませんし 、 職場で居場所がない社内ニートのためのサルベージ 部署でも ありません 。また、社内で実際に誤解を受けた部分でもあるのですが、 社内の選定技術を一方的に強いてマサカリを投げてくる といった部署でも ありません 。 そして突然ですが、弊社では 10 月 1 日より人事制度が改定されています。 mediba、「ものづくりカンパニー」として成長戦略の加速を目指し、人事制度を抜本的改定へ | 株式会社mediba ニュースリリース内では「 ものづくりカンパニー 」というキーワードが印象付けられる内容となっています。 ユーザー中心の「ものづくりカンパニー」として中長期的な成長戦略を掲げ、実現へ向けた組織体制を確立する 弊部は期初より上記の実現のため、PO, UI デザイナー, UX リサーチャー, データアナリスト, エンジニアの職能が集まりより良いワークフローを模索・試行し、 「ものづくりプロセス」を創生・伝播させていくための部隊 という位置づけです。なお、すべてのプロダクトに関わっているわけではなく、あくまで一部のプロダクト群にのみ寄り添った活動から始めていることはご承知おきください。 前置きが長くなりましたが、その中でも開発プロセスを中心にしたエンジニアの取り組みに対して本年度前半どういったアプローチをして結果どうだったか振り返りを行ったので、今回はそのサマリーをブログで紹介させてください。 開発チーム構成 上記は私が所属するものづくり推進部のアーキテクトチーム(図一番右)と、直接・間接的に関わり合う開発チーム A, B です。図は cybozu さんで開催した モブプログラミング Meetup での発表資料より抜粋しています。 ものづくりにおける新しい開発プロセスの創出は、私が所属するアーキテクトチームが中心となり、プロダクトを持ったサービスグロースチーム A, B の開発者たちと関わりながらプロセス自体の見直しや、学習とその定着に根ざした開発フロー、その伝播が主なミッションとなります。 各チームの大まかな担当プロダクトと役割については下記のようになっています。 Growth Team A 相互に関連性が高いいくつかのプロダクトを持ち、多くのステークホルダーと調整を行いながら開発に臨む Growth Team B MVP (Minimum Viable Product:実用最小限の製品) をリリースしより速度が重視されるリリースサイクルで開発に臨む Architect Team 技術的な負債の定期的な返却、開発ワークフローの改善、開発者のための学べる土壌づくり、新規プロダクトのアーキテクチャや設計・実装も含んだ、より良い開発サイクルの醸成に臨む モブワーク・共有を当然にした開発フロー 我々アーキテクトチームの A,B チームへの関わり方はそこまで大きくはなく、 以前記事にも上げたとおり 合同でモブプログラミングを行い試行の中でフィードバック・改善を繰り返したのち、各チーム内でそれぞれの自立を促しながらチーム開発に持ち帰ってもらいました。 その後 A, B チーム、そして我々アーキテクトチームは自分たちの各 1 週間スプリントの中に、モブワークを予定として登録し今も継続してモブプロでの開発を行っています。 モブを実践し続けていると下記のようなメリットが挙げられそうです(個人的主観を含みますが、モブプロを実践されている社外の方と話し感覚はそれほど食い違いはなさそうと最近感じてます)。 属人化の排除 ヒト対課題による issue ドリブンな開発スタイル 効率化と品質向上 オフラインでのコミュニケーション向上 また scrapbox を導入し共有を当然のように行っています。日毎のページを作成し日々のログを残す(分報, #times_ チャンネルを全員でやってる感覚に近いです)場所にしているので休暇から復帰後の同期が容易であったり、困りごとの早期発見に役立っていたり、モブ中の設計資料下書きで共同編集する用途であったりと様々なシーンで役に立っています。 Wiki やマークダウンと比べて、 書くぞ! という気概に対するハードルが低い Slack でリアルタイムでチャンネルに晒されるという危険性がなく、 心へのが負担が小さい (と書くと心理的安全性警察が来そうですが) これらを踏まえると、誰がいつでも何を書いても誰かが拾ってくれそうという善意が大きく働いているような気がします。 開発プロセスにおける目標値 開発者にとっては DX を高めることがより良いプロセスの一部であることには間違いないのですが、プロダクト内の施策実施数やビジネス観点での目標値への寄与を示すような、定量的に図れる数値目標というのは導き出しづらいものがあります。 負債返却のための改善ができるプロセスの土壌、スピード感を求められたリリースサイクルに寄与できる安全性の高いデプロイ、これらを実現に導くためものづくり推進部アーキテクトチームはデプロイ指数を目標値として定めました(参考: エンジニアリング組織論の招待 著者である広木大地さんの Tweet )。 定めた経緯としてはものづくりプロセスにおける開発が示せる正義であり、施策数を意識しより良いサイクルを回している健全な指標として適切と考えこの数値目標を設定しています。 期初時点ではもちろん滑り出しということも考えられますが、健全と言われている 0.1 には程遠いものでした。模索しながらであるため、他のサイクルもうまく回りだしていなかったということも起因しそうですが、期初の 5 月時点では 0.016 とかなり悲惨です。 要件や施策のサイクルがうまく回りだすと定期的なリリースサイクルが生まれ、デプロイの改善や技術負債の返却も平行するようになってからは数値が上がっていくのがよくわかります。ただある程度までいくと、人数・環境(試験環境)・QA などの制限事項により一定値でとどまる印象です。 とはいえ、達成すべき・コミットできる目標値があるというのは開発者にとって日々の張り合いになりました。デプロイのような関与しやすい数値目標は重要です。 前半振り返ってどうだったか 2019 年度上期を終え開発チーム A, B そしてアーキテクトチームで合同の振り返り LT 大会をしました。 各 3 チームに振り返りのネタを持ってきてもらい、上記のように scrapbox 内で質問を投げあって行われています。GIF アニではないのが悔やまれますが、カーソルが十数人動いて質問を書きあっている様はちょっと圧巻です。 主にモブの効能が大きいのですが 誰が休んでもベロシティが下がることがなかった モブで属人化を排除したので誰でもリリースできる モブでやるので手戻りが少なくスピード感を意識して週一でリリースを継続できた 新しくジョインしたメンバーも違和感なくモブに参入可能だった 上記のような言葉が上がっており、モブは文化としてほぼ根付いたなという印象です。 ただ今のメンバーで、という前提条件が大きいので再現性はまだまだ低いように感じています。 チームによっては他職能とのモブワークや機能提案の場が設けられている反面、一方のチームでは別案件で開発メンバーが一時的に減ったり、業務の偏りが整理できず落ち着いて取り組みたい場面に差し込みが多くなったり、技術的にチャレンジできることが少なかったりと、下期に取り組むべき課題はまだまだ残っていることも明らかになりました。 また、直接的に関与できなくともデイリーイベントでアナリストや PO と数値を共有・数値目標を開発者とともに数値を意識付けできていたプロダクトチームもあれば、一方で数値目標がチームで共有しきれておらず課題が顕在化したチームもありました。次期以降チームの視線やベクトル合わせがより重要な課題だとも感じています。 上がってきた課題について蓋をせずに話せる場面も多く、課題が多く残るものの振り返りの場において各チームメンバーが対人リスクを堂々と取れていること自体を称賛したい気持ちが強く、課題の吸い上げ等にはあまり心配していないのが正直なところです。 まとめ 長くなりましたが、mediba は中長期的にものづくりカンパニーとして成長を目指しており、私の所属するものづくり推進部のアーキテクトチームは引き続き下期も以下のようなことに取り組み続けます。 モブプロ・モブワークを中心とした開発スタイルの追求・伝播 他職能とのモブまで範囲を広げ柔軟なものづくりプロセスへの寄与 共同作業を通した学習と定着を繰り返し、個人へ技術的成長のポーティング 開発者がコミットしやすい数値目標、もしくはプロダクトが持つべき目標値の共有と認識合わせ 開発者が体験を損わずにものづくりにコミットできるプロセスづくり 少しエモみも多くなりましたが、本日は以上です。
アバター
こんにちは、auサービス開発部ポイント開発Gの佐藤です。 2019年4月に新卒で入社し、早いもので4ヶ月が経過しました。 実は皆6月頭には配属されておりすでに個々の業務に携わっています。 入社式の記憶もまだ新しいですが… (その時の様子は こちら です) この記事では同時に新卒で入社した計3人のエンジニアの紹介をします。ぜひご覧ください! 1人目 1人目はこの方、川北さん 学校では何を学んできたのか?  公立はこだて未来大学という大学に通っていました。大学の講義では技術面で言うとProcessing、Python、Swith、Scalaですかね、がっつりやっていた訳でもないのでもう忘れたものがほとんどですが笑。 研修でやったこと  PHPのYiiフレームワークでのTODOリストや、MySQLによるDB設計を作成しました。PHPに関しては、ほぼ触ったことがない言語で、Yiiというフレームワークも読み方すら知らない言語でした笑。やったことのない言語から、多少の不安はありましたが、メンターさんに毎回聞くことで、たくさんの学びを得ることができました。  この研修において驚いたことはメンターが3人もついてくれたことです。最初に聞いた時は威圧感があって怖そう…と思っていましたが、いざ始まるとみなさん優しく、いつでも対応して下さったので感謝しています。  できたところ・悩んでる事・分からない事を共有できる場を設けてもらったのは本当に良かったです。 そこから学んだこと  「調べても分からないことは聞く」という単純なものです。「調べる」ことはみなさんやると思うのですが、「聞く」ことに関しては、"メンターさんの仕事が忙しそう"、"自分から話しにいくのが苦手"、"こんな簡単なやつ分からないとか言ったらバカにされそう…“等から聞かないでそのままにしてしまうケースが多くあり、その間ずっと自分で「調べる」ことをしていました。しかし、そんなこと言ってられません笑。新人の内は、どんなに忙しい先輩方でもある程度許容してくれます(100%とは言えません笑)。  決してバカになんかされません(100%とは言えません笑)。誰に対しても、頼るか聞くかしないと、数年後の未来や成長を見た時に悲惨なことになると思い、自分も必然的に「聞く」ようになりました。  ”聞くこと” も、新人1年目の仕事だと感じました。 キャリアビジョン  自分は視野の広いエンジニアになりたいと思っています。1つのことを極めるというのも悪くないのですが、その分野一筋でいくことに怖さがあるからです。なぜかと言うとその分野がもしなくなってしまった時また一からになってしまう可能性があるからです。その可能性がなく幅広い知識量を持つことで、いろんなエンジニアとのコミュニケーションもできると考え、視野の広いエンジニアになりたいと考えています。  上記を前提に、自分のキャリアビジョンは2つあります。 プロダクトマネジメント・スクラムマスター  エンジニアと総合職の方の橋渡し的なポジションになりたいと思っています。どちらかと言うと自分は表現することが得意だと思うので、エンジニアのお話や言いたいことを噛み砕き双方のコミュニケーションを円滑にしていきたいのが一番考えていることです。 アプリエンジニア(iOS・Android)  このキャリアビジョンは、学生時代のPBL時にiOSメンバーとしてアプリ開発していたことがきっかけです。しかしiOSネイティブ以外にも、Androidネイティブだったり、クロスプラットフォーム開発にも興味があります。 2人目 2人目はこの方、山口さん 学校では何を学んできたのか?  大学では、工業系の大学で情報工学を専攻していて、サーバ関連や、や、IaaSサービスに関する研究などを行なっていました。プログラミング言語は、Java、C、Ruby、Pythonとかを経験しました。  ちゃんと勉強していた風ですが、研究室に全然行かず先生に怒られたり、就職活動の報告をしなかったせいで「きちんと報告もできない奴の研究の面倒なんか見ないぞ?」と言われたりと褒められるような大学生ではなかったです(笑)。研究室の先輩も先生があんなに怒ってるの初めて見たというくらいでした。 研修でやったこと  入社直後の研修は、ビジネス職の同期と同様の研修をしていました。その研修内容の一環でUXに関するコンテンツがありました。サービスを作って、グロースさせていくことの重要性を感じることができる内容でした。  エンジニアとしてのスキルは業務を通じたり個人で頑張れば良い話なので、このような研修を新卒のうちに受けることができたのは新卒研修ならではなんじゃないかと思っています。 そこから学んだこと  アジャイルやUXの浸透でユーザーの課題をより速く、適切に解決することが求められているのを改めて感じています。  インフラのコード化やマイクロサービスの影響もあり、これからはサービスに関わる一人一人の自発性がより求められていくなと…。頑張っていきます。 キャリアビジョン  中期的な目標としては、マイクロサービスのアーキテクチャ設計とコンテナベースのアプリケーション開発能力を身に付けたいと思っています。  今、グループ内でマイクロサービス化プロジェクトが動いています。kubernetesやgRPC、Goなどを採用しており、モダン開発を経験できる環境なので、この環境を生かしてスキルを上げていきたいです。 3人目 3人目はこの方、佐藤さん 学校では何を学んできたのか?  学校ではWeb学科という所で学んでいました。Webサイトの作り方をコーディングから基礎的なサーバの知識まで幅広く教わりました。 研修でやったこと  PHPという言語を学校で学んでいたのですが、応用的な利用をしたことがなかったため研修ではフレームワークを中心に学習していました。業務ではLaravelというPHPフレームワークを利用するとのことで、研修の間はLaravelのコーディングを反復し基礎的な知識を身に着けることができました。 そこから学んだこと  フレームワークという名前は聞いたことがあったものの、触れたことがなかったために触ることを躊躇してきていた自分がいました。実際触ってみるととても楽にWebサイトを作ることができたり、データベースとの連携が取れたりして作業の効率化を図れそうです。しかし便利な部分があるその反面、仕様をしっかりと理解していないとバグを生みかねないと感じたので完璧になるまで習得していきます。 キャリアビジョン  いつか将来は自分の手で新規のWebサービスを育て上げたいと思っています。そのためにはWeb開発の手法だけではなく維持や運営周りの技術も習得する必要があるため今は広い視野をもって学習していきます。 最後に 以上、パソコン好きで構成された新卒エンジニアを軽く紹介させていただきました。 まだまだま学ぶことがたくさんあり、同時に学生気分が抜けきっていませんが、一人前の "プロ"グラマーを目指すために精進してまいります! medibaでは、より良い環境にしていきたいエンジニアを随時募集中です。 採用ページは こちら
アバター
こんにちは。ものづくり推進部、フロントエンドエンジニアの武田です。 今日は Datadog, Lighthouse を使ったクライアントパフォーマンス計測に取り組んでいる、というお話です。 mediba では webpagetest を使った定期実行と計測を以前から行っています。 DataStudioとGASでWebPagetestの計測結果をグラフ化する uknmr/gas-webpagetest 紹介記事: gas-webpagetestでWebPagetestのパフォーマンス計測を自動化、可視化する 1 での取り組みをベースにし、 clasp で GAS のソースコード管理・デプロイを実現するための仕組みや webpagetest Lighthouse test と連携したメトリクスの取得まで網羅したものが 2 になります。 今回は少し webpagetest とは趣向を変えて Lighthouse による定期実行とパフォーマンス値取得 Datadog API を利用したカスタムメトリクスへの POST Datadog による可視化 についてご紹介します。 実施に必要なもの Datadog (Pro Plan or Enterprise Plan での契約) Node.js v10.13 以上(現時点)、Chrome がインストールされている実行環境 Lighthouse 定期実行する仕組み 超簡単な説明ですが Datadog とは? -> システム監視のための SaaS Lighthouse とは? -> クライアントパフォーマンスのスコアリングツール です。 Lighthouse による定期実行とパフォーマンス値取得 webpagetest ではなくなぜ Lighthouse なのか webpagetest を利用する場合、自前のプライベートインスタンスとして立てることも可能ですが、コストとの兼ね合いでパブリックインスタンスとして存在するリージョンを利用するというシーンがどうしてもあります。今回はプロダクション環境とパブリックに閲覧が不可能であるステージング環境の2環境を施策に合わせて比較をする必要があるため、どうしてもその制限をクリアできません。 ステージング環境を正常に閲覧できる(=リクエストを受け付けられる) Lighthouse 実行のために必要な Node.js v10 以上が動作する Lighthouse 実行のために Chrome が動作する これらを定期的に実行する 以上を実現することが必要そうです。 どこで Lighthouse 定期的に動かすか ランタイムを Node.js v10.x にした lambda もしくは CodeBuild でスクリプトを実行、定期スケジューリングを CloudWatch Events にするということも可能そうです。一度 CodeBuild 想定でコストを計算してみます。CodeBuild の OS image は Chrome も素で入っていますし 、割となんでも入り感があります。 料金 - AWS CodeBuild | AWS 毎月かかりそうな試算の条件 デイリーで24回実行想定 ビルドにかかる時間 5 分 インスタンスタイプに一番高いクラス 1分単位で 0.02 USD 24回/day * 30day * 5 分 * 0.02 USD = 72 USD 現時点レートで 7,827 円、自分が毎月もらっているお小遣いから出せるかと言われると出せない金額なので今回は AWS 環境での実行を諦めます。 いろいろ考えた結果、ほぼゼロコストで仕上げるため選択したのは Travis CI でした。といっても弊社では Travis CI Enterprise を AWS 環境上で動作させており、そこで実行させる想定です(なので詳細を詰められるとゼロコストではないのですが)。 ただ残念ながら定期実行を叶える Travis Cron Jobs はリポジトリのブランチ毎にマニュアルで指定する必要があるのでそこは残念な感じになります、人間がポチポチ GUI から指定して定期実行を実現することにします。 Lighthouse スクリプト フロントエンドエンジニアの方ですと Chrome Devtools -> audit や Lighthouse を CLI から利用することは一度はやってみたことがあると思うのですが、今回はよく見るスコアがほしいわけではなく特定のパフォーマンスメトリクスを取得したいという意図です。個人的にも絶対的なスコアリングが全てだと思っていません、 計測し比較し向上しているかが一番重要であると思っています 。 プログラマブルに Ligththouse を操作していきますが、 実はほとんどドキュメントにあったりするので 、参考に取得してパフォーマンス値をかき集めてみます。 const lighthouse = require('lighthouse'); const log = require('lighthouse-logger'); const chromeLauncher = require('chrome-launcher'); const opts = { chromeFlags: ["--headless", "--disable-gpu"], logLevel: "info" }; log.setLevel(opts.logLevel); launchChromeAndRunLighthouse("https://stg.example.com", opts).then(results => { // 一旦標準出力に表示 console.table(results); }); function launchChromeAndRunLighthouse(url, opts, config = null) { return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => { opts.port = chrome.port; return lighthouse(url, opts, config).then(results => { // results.lhr はよく見るスコアリングの元データ // https://github.com/GoogleChrome/lighthouse/blob/master/types/lhr.d.ts const { "time-to-first-byte": ttfb, "first-contentful-paint": fcp, "first-meaningful-paint": fmp, "speed-index": speedindex, interactive, metrics, } = results.lhr.audits; return chrome.kill().then(() =>({ TTFB: Math.round(ttfb.numericValue), FIRST_PAINT: metrics.details.items[0].observedFirstPaint, FMP: Math.round(fmp.numericValue), FCP: Math.round(fcp.numericValue), SPEED_INDEX: Math.round(speedindex.numericValue), TTI: Math.round(interactive.numericValue), })); }); }); } Lighthouse 実行時の Promise.resolve で返却される results は型定義もあり 、昨今のエディタ補完の恩恵を受けると大変 DX が良いのですが、必要な数値は正直どこに格納されているか探すほかないので、CLI で一度 JSON ファイルを成果物として実行してから探すのが一番手っ取り早いです。切り取られたスクリーンショットの情報が Base64 でエンコードされ格納されている ので違った工夫もできそうではあります。 ここまでで Lighthouse 側の準備は整ったので次に Datadog 側を準備します。 Datadog API を利用したカスタムメトリクスへの POST そもそもなぜ Datadog を選ぶのか 担当するプロダクトのシステムモニタリングとして現在利用しており(他のプロジェクトでの利用実績もあります)、インテグレーションや API 連携について学びたいというのと、値のプロットと可視化を Datadog 一括にしちゃえば便利だし見るところ少なくていいんじゃね? というのが大きなモチベーションです。 私が活動するメインフィールドはフロントエンドなのですが、チームでは属人化を避けるため監視やアラート対応・調査を含め、モブを通して暗黙知をなくそうという取り組みをしている点も Datadog を候補にした理由です。 Datadog API とカスタムメトリクスの利用 次はDatadog API を使ってカスタムメトリクスを作り POST しますが、まずは API key, APP key が必要になってきます。 ナビゲーションから Intergrations -> APIs API key, APP key 取得 実際にリクエストを送る際は node-dogapi というのがあるのでこちらを利用してみます。 初期化 const datadog = require("dogapi"); // 環境変数に Datadog API key, Datadog App key がセットされている想定 datadog.initialize({ api_key: process.env.DATADOG_API_KEY, app_key: process.env.DATADOG_APP_KEY, }); カスタムメトリクスへの送信 任意の文字列をカスタムメトリクス名として、収集した値をプロットしていきます。なお以下のコードは先ほど出力に結果を表示したブロックで利用する想定です。タグ名に関しては特定の要素に紐づけ絞り込みを目的として利用を推奨しているようで、公式にもある通りプロダクション環境やステージング環境の種別としてタギングします。タグのルールとしては <KEY>:<VALUE> というルールになります。 参照 const { TTFB, FIRST_PAINT, FMP, FCP, SPEED_INDEX, TTI, } = results; const tags = "env:staging"; datadog.metric.send_all([ { metric: "webperf.measure.ttfb", points: TTFB, tags, }, { metric: "webperf.measure.first_paint", points: FIRST_PAINT, tags, }, { metric: "webperf.measure.fmp", points: FMP, tags, }, { metric: "webperf.measure.fcp", points: FCP, tags, }, { metric: "webperf.measure.speed_index", points: SPEED_INDEX, tags, }, { metric: "webperf.measure.tti", points: TTI, tags, }, ], (err, results) => { if (err) { console.log(`Error: ${JSON.stringify()}`); process.exit(1); } console.log(`Results: ${JSON.stringify(results, null, 4)}`); }); ここまでのもの実行できれば Datadog のカスタムメトリクスに値がプロットされ可視化するデータは出来たことになります。 Datadog による可視化 ダッシュボードを作成 新しいダッシュボードを作成しグラフを作る準備をします。 Timeborad: 時系列にイベントグラフを閲覧しレイアウトが自動 Screenboard: ステータスやグラフなどデータとして混合されたもの向けでレイアウトがフレキシブル 2つから選べますがお好きな方を選んで調整してください。 ダッシュボードにウィジェットを追加 グラフで可視化する場合は Timeseries というウィジェットを使用します。 ウィジェットでハマるとしたらタグでの絞り込みな気がします。もしタグがサジェストされないなどうまくいかないようでしたら </> アイコンを押下して raw text での変更に切り替えると avg:webperf.measure.ttfb{key:value} のような入力が可能になるので試してみると良いかもしれません。 最近よく聞くようなパフォーマンスバジェットを閾値として定めて、閾値よりオーバーしたら Warning 表示にする、なおかつ閾値を超えた際にモニタリングによって Slack に通知するといったことも可能です。 Google Developers Japan: パフォーマンスバジェットのご紹介 - ウェブパフォーマンスのための予算管理 ダッシュボードは今のところシンプルですがこんな感じになっています。 日々プロットしたグラフを可視化し追いかけたい数値と、重要視したい値・バジェットを定めてデカデカと表示する、見栄えはよくありませんが実務に事足りるものになっています。 まとめ Lighthouse から特定の値を取得、Datadog API を使ったカスタムメトリクスへの POST、Datadog 内での可視化について書かせていただきました。 Datadog のカスタムメトリクス利用は Pro/Enterprise プランのみ 手早く低コストで定期実行したいなら CI のサービス利用を検討 Lighthouse の実行結果からはパフォーマンス値やその他(スクショなど)も取得できる Datadog API の利用は簡単(各種言語のライブラリ等も揃っており充実) ダッシュボードも気軽で簡単に可視化できる 今回は Datadog のプラン次第というところもありますが、まずは低コストでパフォーマンス定期計測やパフォーマンスバジェットの設定などに取り組んでみてはいかがでしょうか。
アバター
こんにちは。創造開発部 兼 ものづくり推進部の森竹です。 Scrum Inc. 認定スクラムマスター(LSM)です。 前回の 読書会はじめました に引き続き、記事を書かせて頂きます。 今回は2019/6/14(木)〜15(金)に Scrum Inc. 認定資格スクラムプロダクトオーナー(LSPO)研修 を受講した内容について、記事にしました。 Scrum Inc. 認定資格スクラムプロダクトオーナー(LSPO)研修とは Scrum Inc. Japan の 公式ページ に記載がありますが、簡単にまとめると下記のことを学ぶことが出来る研修です。 スクラムの基本や役割についての正しい知識 プロダクトのビジョンステートメントやペルソナなどを用いて、ユーザーストーリーの作成方法 ビジネス価値によるバックログの優先順位の付け方 わかりやすいユーザーストーリーの書き方 なぜエンジニアがプロダクトオーナー(PO)研修を受講するのか 社内読書会などを通じてアジャイルを推進するような活動をしていますが、プロダクトオーナー(PO)の役割を理解する必要があると考えました。 開発チームやスクラムマスター(SM)は経験があるので、どんな行動をすべきか分かるのですが、プロダクトオーナー(PO)は経験がないため、どのように振る舞えば良いのか分からず、課題に感じていました。 この研修を通じて、その課題を解決したいと思いました。 研修内容 講義とワークショップ、質疑応答が主な内容となります。 研修内容で、自分なりに気になったところは下記でした。 ユーザーや顧客の価値は変わる ユーザーや顧客からのフィードバックを開発チームへ伝える Howを指示してはいけない WhyとWhatを伝える。開発チームの独創的なアイディアに驚かされるはず 80%の価値は20%のフィーチャーによる 全ての機能を作らなくても優先度の高い機能があれば、そこでリリースすることができる スプリントレビュー ワクワクするようなスプリントレビューを開催する ユーザーストーリーは7次元でスライスする 機能的/非機能的な観点で定義する ワークショップ リーンキャンバス ペルソナ ビジョンステートメント ユーザーストーリーマッピング PO研修の感想 研修を通じて、POがすべき行動や振る舞い方を理解することが出来ました。開発チームやスクラムマスターとして、POマインドを持って行動してく必要があると感じました。ユーザーや顧客に使われるものを作りたい、価値のあるものを作りたいというマインドがあれば良いアイディアに気付けるかもしれませんし、POをよりサポートすることができると思います。 最後に Scrum Inc. 認定資格スクラムプロダクトオーナー(LSPO)研修 について、紹介させて頂きました。 今後はPO研修で学んだことを開発チームやスクラムマスターとして活かして行くのと、POを満足させるような行動をして行きたいと思います。
アバター