AWSサポートの一歩進んだ使い方 ~問い合わせの極意編~

はじめに

はじめまして、オクトSREチームの@DanKadoiです。 github.com

普段は、

  • AWS上でのインフラ構築
  • Docker・Kubernetes環境整備
  • CI / CD サイクルの改善や効率化
  • プロダクト初期フェーズにおける様々な運用課題の解決支援
  • インフラやアプリケーションのモニタリングの仕組みを整備
  • OS、ボリューム、ネットワーク、AWSアカウントのセキュリティ対策

etc.. などの技術領域で、日々少しずつ会社貢献しています。

Terraformを用いたIaC(Infrastructure as Code)や、運用負荷の低減/耐障害性の強化などを目的としたインフラ構成の改善、サーバレスアーキテクチャ(過去記事参照)への移行、開発量・成果・費用対効果・処理効率などを可視化するためのメトリクス取得法の確立、より高度で高効率なKubernetesによるコンテナ運用、GitHub Actionなど、手につけたい技術は他にもまだまだたくさんあります。 tech.88oct.co.jp

知らない技術や新しい仕組みをインフラ(あるいはプロダクト)に導入して運用を軌道に乗せるには、苦難がつきものです。

雑多な差し込み業務を捌きながら、唐突に発生する障害の事象確認をしつつ、日々の業務に平行して新しい仕組みを導入するための検証・調査を実施するのは一定のハードルがあります。

しかし、障害 は嫌でも発生してしまいますし、説明を求められれば事実確認が必須となります。

なので私は、事象の詳しい確認・調査の難航が容易に見越せて、尚且つ、早急な解決を求められている場合は、AWSの技術的なサポートを積極的に利用させて頂いております。

今回は、私がAWSサポートへ技術的な問い合わせをする際に気をつけているポイントについて、事例紹介と併せて解説させて頂きたいと思います。

AWSサポートとは

f:id:d_hack0928:20200323121523p:plain AWS 使用料の月額のうち数%(サポートプランAWS使用料で変動)を支払って、AWS Trusted AdvisorAWS Personal Health Dashboardなどを含め、特別なサポートをAWSから受けられるサービスのことです。

aws.amazon.com

「技術的な問い合わせ」には、事象や問題をスムーズに確認・解決するために培われた コミュニケーションナレッジ があります。
それは、だれが,どこに,どのような 問い合わせをする場合においても、変わらず在ると、私は考えています。
分かる人がこの記事読めば そんなの当たり前だ と思うかもしれませんが、基本に立ち返る良い機会だ くらいに受け止めて閲覧頂けますと幸いです。

サポートプランに加入する方法

ご利用中のAWSアカウントにて、rootユーザでログインして頂き、以下のドキュメントに沿ってプラン変更の操作をしてください。 aws.amazon.com

スムーズに解決したAWSサポートへの問い合わせ事例

本番環境で起こったこと

2020/02/16 午後
ANDPADの社内環境にて、AWS CognitoでGoogle認証(過去記事参照)をかけているページをChromeで開こうとすると、ERR_TOO_MANY_REDIRECTSのエラーを出して認証ページに到達しない現象が発生し、環境利用者から問い合わせを受けました。 tech.88oct.co.jp

取り急ぎ、上長およびセキュリティチームから、「他のブラウザをからアクセスすれば発生しないので一旦それで回避してほしい」といった旨のアナウンスを社内向けに出してもらい、私の手元(macOS Catalina 10.15.3, Chrome80系)で事象の再現を確認し以下のように整理しました。

発生条件:
■(OS問わず) Chromeのバージョン80.xxx以上を利用している端末で発生する
■■ERR_TOO_MANY_REDIRECTSが出て、Cognito認証後のページに全くアクセスできず画像1のエラーがブラウザに表示されているケースがある
■■シークレットブラウザを使ったり、googleアカウントの再ログインなどを行ってアクセスを試みたりして、Cognito認証後のページに到達できるが、画像2のエラーが開発者モードで確認できるケースがある

発生しない条件:
■Chromeを使っていても、バージョン79.xx以下のままアップデートしていない環境では、発生しない
■Chrome以外のブラウザを利用すれば、Cognito認証(googleアカウントログイン)通過後のリダイレクトが正常に行える

f:id:d_hack0928:20200322200209p:plain f:id:d_hack0928:20200322200213p:plain

本件の場合、本番環境で発生したためALBの再作成といったサービスダウンタイムが発生する作業を実施しづらく、頻繁に利用される社内環境であったため、AWSサポートに技術的な問い合わせをして早急な解決を図りました。

f:id:d_hack0928:20200322205408p:plain

AWSサポートに問い合わせを送る際に私が気をつけたポイント

本番用のAWSアカウントにて本件に該当するリソースを確認し、以下のようなテンプレートでAWSサポートに問い合わせのメッセージを送信しました。

${いつもの冒頭挨拶}

発生事象:
${本番環境で起こったこと に記載の通り}

■該当するリソース
■■ALB ${ARN}
■■リスナー ${ARN}
■■リスナールール ${ARN}
■■インターネット経由でアクセスする際のURL ${エンドポイントのURL}
■■Cognito認証を以下の通り利用している
ユーザープール ID:  ${ARN}
( プール arn:  ${ARN} )
クライアント ID:  ${ID}
セッション Cookie:  ${Cookie種別}
セッションタイムアウト:  ${Time}
認証されていない場合:  ${アクション種別}
スコープ:  ${スコープ}
■■転送先
ターゲットグループ: ${ARN}
( ${ターゲットグループに紐付くリソースにデプロイされているアプリケーションの説明} )

発生条件:
${本番環境で起こったこと に記載の通り}

発生しない条件:
${本番環境で起こったこと に記載の通り}

問い合わせ:
本件を早急に解決したい と考えいて、解決手段を模索しております。
本件は、Chrome 80におけるSameSite Cookie仕様変更の影響で発生している と考えて良いでしょうか。
また、上述しております該当もしくは関連するawsインフラリソースにおいて、本件の原因となりうる問題が発生していないかご確認いただけますでしょうか。

気をつけたポイントは以下の通りです。

  • 何が、どのリソースで、どのような条件で発生し、何に困っているかを、正確に言語化する
  • 読み手の調査に手間や時間がかからないように、リソースのユニークIDはすべて記載する
  • 読み手が「何に回答して欲しいのか」に悩まないように、問う内容その補足情報を明確に区別する
  • 添付ファイルは、タイトルで中身が推察できるようにしつつ、文章内で参照できるようにする (画像1など) f:id:d_hack0928:20200322215316p:plain

実は、開発環境でも数日前に発生していた

本件に極めて類似する事象が、ANDPADの開発用のAWSアカウントでも、2020/02/13 午後 に確認されていました。

その際は、Cookie headerの文字数が4,096を超えているところまで確認し、最終的に関連するALBリソースを再作成することで事象の復旧を確認しました。

( ※開発用のAWSアカウントは、サポートプランに加入していなかったため、当時AWSへの問い合わせは断念していた)

開発用のAWSアカウントのその後...

開発部の執行役員と交渉して、開発用のAWSアカウントもサポートプランに加入して頂く運びとなりました。
加入の意図としては、以下のような説明をしました。

  • これまで運用してこなかったAWSのマネージドな仕組みや新しい技術をプロダクトで使おうと思った際に、稀に検証段階でテクニカルサポートが欲しいケースがある
    • 本番適用前なので、本番用のAWSアカウントにリソースがなく、テクニカルサポートを受けられない
    • 真新しい技術で日本語記事がインターネット上に少ない段階だと、調査が難航したりする
  • 複数のAWSアカウント間でリソースを共有して連携するようなケースが近年増えてきて、共有先のAWSアカウントでマネージドな機能を利用する際にIAM権限回りの問題が発生して調査が難航しやすい
    • アカウントをまたいでサポートに状況確認してほしい場合、共有先のアカウントがサポートプラン未加入の場合、対応してくれるかわからない
  • 開発用のAWSアカウントで数日前に発生した障害が、サポートプラン未加入のためAWSに問い合わせできず原因調査も難航したため、リソースを再作成することで強引に復旧させた。しかしその後、本番用のAWSアカウントでも同様の問題が発生してしまった(まさに本件のケース)

などを解決したい。(未然に防ぎたい)

これからステークホルダーに対してAWSサポートプランの加入交渉をしようと考えている運用チーム/SREチームの方は、加入によって増えるコスト加入したら享受できる恩恵 を天秤にかけた結果が、先方に伝わるように説明できれば良いと思います。
意思決定者と交渉するのもSREの仕事です、その参考になれば幸いです。

問い合わせ後のAWSサポートによる素早い対応

f:id:d_hack0928:20200322221217p:plain 先方の担当者の方に、問い合わせ内容のホスピタリティを褒めて頂けました。
回答を要約すると、以下のような内容でした。

  • 該当リソース(ALB)に対し、「Cross-Origin Resource Sharing (CORS) リクエストの際に SameSite 属性が必要となるブラウザのために、Application Load Balancer の認証機能において ‘SameSite=None’ を付与する変更」が加えられた
  • この変更によって、クライアントがバージョン 80 以降の Chromium ベースブラウザを使用する場合において、Load Balancer が Authentication Cookie にこの属性を含める形となった
  • これによって、Cookie のサイズが許可されるサイズよりも大きくなるという問題が見つかった(文字数が上限を超える)
  • 御社のALB に対して、この変更のロールバックを実施した
  • 現在、全ての Load Balancer に対してロールバックを実施している段階である

本事象に関連する情報:
https://forums.aws.amazon.com/ann.jspa?annID=7413
Chromium (web browser) - Wikipedia

まとめ

スムーズな事象解決を目指した問い合わせのナレッジとは

これまでの私の業務経験を元に、問い合わせの文章がどの程度の情報を持っていればその後のやり取りがスムーズになるか、箇条書きでまとめてみました。

今後、サーバやアプリケーションで発生した何らかの事象について問い合わせをしたい方は、問い合わせ先がどこであっても、以下に気をつけて頂ければ良いかと思います。もちろん、下記をすべからく満たしている必要はありません。

  • 自分の状態を具体的に説明する
    • どのような事象・問題が発生しているか
    • どのような環境で発生しているか
    • (AWSの)どのインフラ・リソースで発生しているか
    • 誰が・何に・どのように困っているか
    • (解決した場合)どのような状態であることが、正であるか
    • いつまでに、どうなっていたいか(希望・期待)
  • 自分で収集できた、関連し得る情報を共有する
    • 事前に確認することができた事実や調査結果
    • 関連が疑われる挙動・異常・操作
    • 関連するログファイルを添付
    • 事象を手元で再現したときの様子をgifやスクリーンショットなどで添付
  • 誰が読んでも概ね同じような解釈ができる文章を書く
    • 主語を省略しない
    • 技術やリソースの固有名詞は正確に記載する
    • 隠語・造語・略語・社内用語はなるべく使わない
    • あなたの問い合わせを受けとる人間は、あなたの親友でも家族でもないことを念頭に入れておく

おわりに

問い合わせの多くは、2~5個の質問をし返さないと、調査に着手することすら難しい程度の情報量 しか持っていません。この記事は、読んだすべての方の業務が、今までより少しでもスムーズに回ることを願って書きました。読んで振り返ったナレッジを、些細な質問からでも、是非実践してみてください。

engineer.88oct.co.jp

NuxtのSSRモードでメモリリーク?原因はaxios?

はじめに

最近金髪から黒髪に戻して更生しました藤井(フロントエンドエンジニア)でございます。久々にテックブログに貢献させて頂きます!

 

今はメインの施工管理機能の改修の傍ら、新機能開発にも携わっておりまして、フロント側はSSRモードのNuxtを採用しております。さて、そんな中SREチームから「フロントエンドがメモリリークしていませんか?」との通報が入りました。

 

いやいや、そんなハズは・・と思いながらもDatadogを見てみると見事にメモリ消費量が右肩上がりに増えていってます。なぜじゃ・・・。

f:id:yohei-fujii:20200314183203p:plain

調査開始

メモリリークになるような処理を入れた覚えはないぞ!と思いつつも調査開始です。ひとまずChromeのDevtoolでPerformanceやMemoryタブを見ながら確認しますが、これと言って原因が見つかりません。

f:id:yohei-fujii:20200314201317p:plain

 

おかしい・・。なんでだろう。

あれこれ試しましたが解決せず、ほぼ1日消化しました(やってしまった・・)

 

SSRのデバック

そして他の人にも相談しながらやはり気になったのはSSRモードということです。考えてるだけでは何も進まないので、ひとまず調査してみることに。以下の記事を参考にさせていただきました。

qiita.com

ターミナルで以下のコマンドを叩いてNuxtを立ち上げます。

node --inspect node_modules/.bin/nuxt-ts

次に、以下のページをブラウザで開きます。

chrome://inspect/#devices

 

このような画面が開きますので、Inspectを押してChrome Dev Toolsを起動させます

f:id:yohei-fujii:20200314184607p:plain


そして立ち上がったNuxtアプリケーションを確認します。最初にスナップショットを撮って置きます。あとは何度もページ再読み込みしたりなどしてアクセスをかけました。そしてもう一度スナップショットを取得(HEAP SNAPSHOTはChrome DevToolsのMemoryタブから取得できます)

 

カメラで撮影をしている人のイラスト

 

いよいよ取得したスナップショットを確認です。

さてさて、確かにSnapshot 1 から2にかけてメモリ消費量が増えてます。ひとまずShallow Size(オブジェクト自体の大きさを表す)の大きなものからパーッと目を通しました。

 

おぉー、いっぱいあるなぁ。どれどれ。

根気よく中身を確認していきます。

 

f:id:yohei-fujii:20200314185115p:plain

そうしているとArrayの中に気になる部分を見つけました! 

InterceptorManager?はて、こんなものがなぜ出てくるのか・・。

f:id:yohei-fujii:20200314185429p:plain

そしてそれはArrayだけではなく、system / Contextにも同じようなものが出ていることを確認できました。

 

InterceptorManagerと見て、真っ先に思いつくのはHTTPクライアントであるaxiosです。やはりSSRモードだと何か悪さしているのか?と気になりググってみると似たような記事がヒットしました。

 

techblog.timers-inc.com

 

これは、確かに気になるぞということで早速consoleなどを仕込んで確認します。

f:id:yohei-fujii:20200314190007p:plain

 

まず初回アクセス時点でのInterceptorsの中身を確認。

f:id:yohei-fujii:20200314190104p:plain

ターミナルの方でhandlersの中身が空であること、そしてブラウザの方でも初期値はまだセットされておらず空であることを確認できました。

f:id:yohei-fujii:20200314190215p:plain


それでは、何回かアクセスを繰り返してみて確認します。

すると・・

f:id:yohei-fujii:20200314190449p:plain

 

あら、増えている・・。

 

f:id:yohei-fujii:20200314190500p:plain

 

なぜだー!!!お前はなんだ!

どうやらpluginsはSSRモードだとリクエストの度に動くので、そのことが起因して、axiosインスタンスが肥大化して行っているようです。

 

後々気付いたのですが、公式ページにちょこっとだけ書いてありました。

私たちは isomorphic な HTTP リクエストを作るために axios を使っています。私たちはあなたの Nuxt プロジェクトに、私たちの axios module を使うことを強くオススメします。

node_modules 内の axios を直接使用しており、axios.interceptors を使用してデータを処理する場合、interceptors を追加する前にインスタンスを作成してください。そうしなければ、サーバレンダリングされたページをリフレッシュする際に、interceptor が複数追加され、データエラーが発生します。 

ja.nuxtjs.org

いよいよ対応処理

どうするかというと、Interceptorsのhandlerが存在する場合(=2回目以降のplugins呼び出しの場合)に登録実行させなければ、インスタンスの肥大化を防ぐことができるのではないかと考え、判定処理をいれました。

f:id:yohei-fujii:20200314191536p:plain

一度変数interceptorManagerに代入しanyを付与しているのは、型の問題があったからです。AxiosRequestConfigにはhandlersがないので、どうしようかとも考えましたが、ひとまずanyを使ってしのぎました。(どなたかより良い方法あったら教えてくださいませ)

f:id:yohei-fujii:20200314191617p:plain

idがすでに1以上であれば、つまりinterceptorsの登録が既にされていたらreturnするようにしました。

 

そして運命の確認!もう一度ブラウザを開き、何度もアクセスをして見てみました。

f:id:yohei-fujii:20200314191938p:plain

 よし!何度ページを読み直しても増えていません!

 

それでは、念の為今回の対応を取り込み、検証環境で確認してみます。再度Datadogを確認します。

 

f:id:yohei-fujii:20200314200259p:plain

見事メモリ消費量が安定しました!めでたしめでたし!

 

さいごに

思わぬSSRの罠にハマってしまった感があります。日頃から気をつけていても、今回はまさかお前か!みたいな感じでメモリリークを起こしてしまっていました。SSRモードの場合は、pluginsだけではありませんがライフサイクルにはかなり気をつけなければなりませんね。

 

さて、今回の作業のようにパフォーマンス改善調査というのは根気のいる作業ですが、品質を考える上では気をつけて対応していかなければならないところです。まだまだ課題も多いですが、一つ一つ解決していけたらなと思います。興味ある人、ぜひ一緒にやりましょう!

 

Railsでのバックグラウンド処理を考える

こんにちはCDOの山下です。

今回は、新規サービス開発にあたりRailsのバックグラウンド処理について考えることがあったので記事にしようと思います。

現状のRails環境下でのバックグラウンドジョブ

Railsでバックグラウンドジョブを扱うといえばresquesidekiqが有名で多くのサービスでも実運用で使われていると思います。弊社の主力であるANDPADでもサービス開始当初からsidekiqが使われてきましたが、Redisを仲介してジョブを処理するサーバーをアプリケーションサーバーとは別で運用する必要がありサービス規模が大きくなるにつれてインフラ管理コストが負担になってきました。

f:id:oct88:20200312210620p:plain

図1:sidekiqのインフラ構成

主な利用用途としては、以下に上げるようなもので、数10msecで終わるようなものから数時間単位で終わるものまで様々な処理がバックグラウンドジョブに放り込まれています。

主な用途

  • リアルタイム通信連携(10msec~1sec)
  • 外部連携(10msec~1sec)
  • 画像処理、加工(100msec~10sec)
  • インポート、エクスポート系処理(1min~6h)

また弊社では、新規で開発するサービスに関してはマイクロサービスとしてkubernetes(k8s)のクラスタ環境にアプリケーションをデプロイする機会が増えてきましたが、バックグラウンドジョブを今までのsidekiqサーバーに相乗りしていくと加速度的に負担が増えていく状態になるため別の方法を検討し始めました。 

SQS + Lambdaでバックグラウンドジョブを処理する

2018年6月よりAWS LambdaのイベントリソースがSQSに対応したことからSQSにenqueueしたイベントからLambdaを起動して処理をすることが可能になりました。Lambdaの実行時間も最大15分に拡大していることからインポート、エクスポート系の処理以外はLambdaに移行しても問題なさそうな雰囲気です。弊社では、新規サービスと既存サービスで切り出しやすそうなところから徐々にSQS + Lambdaの構成にバックグラウンドの処理を移行し始めています。serverless frameworkを採用することでLambda関数のデプロイを簡易に実行できるようになっています。

f:id:oct88:20200313094640p:plain

図2:SQS + Lambda構成

SQS + Lambda構成のメリット・デメリット

SQS + Lambda構成のメリットとデメリットを上げておきます。Railsエンジニアにとっては開発負担が増えるのでより良い方法はないかと色々模索しましたが、サーバー管理の必要のないスケーラブルな構成はとても魅力的だなと感じています。また、Lambdaの実行時間制限があるので既存のバックグラウンド処理の全てを網羅できなかったのが悩ましいところです。少し時間のかかる処理(インポート、エクスポート系の処理)は別の方式を模索中です。

メリット
  • スケーラブル
  • 従量課金になるのでコストが抑えられる
  • 言語の選択肢が広がる
デメリット
  • Railsでまるっと管理できなくなる
  • 簡易にアプリ側の資産を使えなくなる
  • Lambdaの実行時間制限(15分)があるので全てを解決できない

まとめ

Railsのバックグラウンド処理の作り方としては、世の中にsidekiqやresqueなどの定番的なものはあるもののインフラ的な側面ではコンテナ化やサーバーレスなどRailsの枠を超えた選択肢もありなかなか悩ましいなと思ってます。k8sクラスタの中にバックグラウンドを処理するコンテナを抱え込む方法も模索はしていましたが、管理コストが上がるので結局断念しました(より良い方法があるよって方は是非情報交換しましょう)。今回この方式を採用するデメリットとしては、今までRailsの中で書けていたバックグラウンドの処理をLambda実行用に別に記述しなければいけなくなったことがあります。ただ、言語の制限なく実行できるという面ではメリットにもなっています。Railsエンジニアとしては手間が増えることも事実ですが、SQSやLambdaをうまく使うことで関心が分離されスケーラブルな構成に少しずつできていければと思っています。

 

ピンポンゲームで学ぶ、アジャイルな「見積もりと計画づくり」

「見積もりと計画づくり」を学ぶ会を開催したよ

エンジニアのからまげです。

先日、アプリチームで、アジャイルな「見積もりと計画づくり」を学ぶため

ワークショップを開催しましたが、今回は「ピンポンゲーム」を行いました。

 

みんなでワイワイ楽しく盛り上がりましたので、その様子をリポートさせていただきます。

f:id:karamage88:20200219173950j:plain

 

ピンポンゲームとは

ピンポンゲーム(正式名称:Ball Point Game)は、アジャイルスクラム開発の体験の定番のワークショップのひとつです。 

 

ゲームの目的 

「ピンポンゲーム」の目的は、1分間で、できる限りたくさんのピンポン球を、チーム全員でパスし、触ることです。

 

ゲームのルールと進行方法について

ルール

  • 全員が大きなチームの一員となる(今回の参加者は6人で1チーム)
  • チームの全員が、ボールに触れなければならない
  • 全員が触ったピンポン球が「リリース可能なプロダクト」とする
  • ボールをパスする際、空中に浮いている時間がなければならない
  • 「リリース可能なプロダクト」を最大化するために「見積もりと計画づくり」を行う
  • 全部で3回のスプリントを行う

進行方向

  1. チームは、スプリントの最初に2分間「見積もりと計画づくり」として、チームのプロセス方法や作業計画を決める
  2. チームには、いくつの「リリース可能なプロダクト」を達成できるか、数を見積もる。
  3. 1分間のワークを行う。
  4. プロセスを改善する方法を議論するため、チームに1分間、「ふりかえり」の時間を与える。
  5. 3回のスプリントを繰り返す。

 

実際のゲームの様子

まず見積もりと計画を立てよう

「見積もりと計画づくり」を話し合うチームメンバーたちの様子です。全員、やったことないことに対して、どう見積もるか悩んでいます。結局、当てずっぽうで、「30個ぐらい」 と見積もりました。

f:id:karamage88:20200219173959j:plain

 

ワーク開始! 

実際に、1分間のワーク開始!

 

近くに集まって、小さな輪を作ってパスしていく作戦のようです。

でも、受け取りそこなってポロポロ落としています。

f:id:karamage88:20200219173943j:plain

 

 一度に受け渡す量を増やすと、ボールをこぼすリスクも高まります。

f:id:karamage88:20200219174010j:plain

 

ふりかえり! 

ワークを終え、2分間の「ふりかえり」の様子です。みんなでカイゼン案を話し合っています。ボールをこぼしすぎたので、「もっと近づいて受け渡す量を調整したほうが良い」といった意見がでました。

f:id:karamage88:20200219174021j:plain

 

結果発表 

以下は、3スプリント回した時の「実績値 /  見積もり  」です。

f:id:karamage88:20200219174031j:plain

 

  

ワークショップを終えて、学んだことまとめ

  • 初回見積もりは、当てずっぽうになるから、大きく外しやすい
  • やったことないことは見積もれない
  • スプリントを回すほど、見積もりが収束してくる
  • ふりかえりでカイゼンすることによって生産性があがる(下がることもある)
  • 継続的に同じやり方を繰り返すことによって、だんだん早くなる
  • やり方を変えるのは大きな不確実性があるが、抜本的なカイゼンを生むことがある
  • 見積もりは前回実績が最も頼りになる見積もりの根拠になる

 

以上が、今回の学びです。

 

みんなで盛り上がって楽しかったですね〜

 

皆さんも一度この「ピンポンゲーム」を試してみてはいかがでしょうか?

 

認証機能追加を、ユーザーストーリーマッピング的なもので整理してみた!

はじめに

初めまして!オクト デザインチームの小久保です。

普段は、グラフィックデザイン(パンフレットなど、主に紙の制作物)からUIデザインまで、幅広くデザインに携わっています。

 

その中でもUIデザインは、ユーザーがやりたいことを、ストレスなく達成できる画面をデザインしていく作業が主になります。

 

…が、UIはユーザーの使い勝手を左右する、超重要な部分。

日々、黙々と画面デザインをしてる訳ではなく、時には要件定義から関わり、ユーザーにとって理想のフローはどんなものかを、プロダクトチームや開発チームと一緒になって整理していきます。

 

今回は、そんな「要件定義」フェーズの前段階として、ストーリーマッピング的なもので要件洗い出しを行なった事例を紹介します。

 

ユーザーストーリーマッピングとは

詳しくはこちら↓↓を読んで頂けば概略が掴めると思います。

qiita.com

 

基本的には、考えられるユーザーストーリーを1つずつ 付箋に書き出し、
【横軸=時間】【縦軸=ストーリーの粒度】とした平面上に
その付箋をマッピングして、ユーザー体験を整理する手法です。

 

そして最後に、どのストーリーをリリースの範囲とするか、を決定します。

 

なぜ、ユーザーストーリーマッピングを利用したのか?

今回、対象となった案件は「認証機能の追加」でした。

 

当初、簡単だと思っていたこの案件は、要件を整理していくうち、実はストーリーが結構複雑なことに気が付きました。

 

理由は以下。 

  • ユーザーが使用する認証アプリには色々種類がある
  • アプリ版とWeb版で、少し要件が異なる
  • イレギュラーストーリーが多数考えれる

 

 そこで、一旦考えられる全てのストーリーを洗い出し整理し、どこまでをANDPADとして担保するのか?を整理することに。

 

その際、この複雑なストーリーを、わかりやすく整理出来る方法はないか?
と思っていたところ、たまたま社内の方がオススメしていた、ユーザーストーリーマッピングが向いているのでは?と直感し、トライしました!

 

(なお、今回はブレストツールのMiroを使用しました。)

 

実際マッピングしてみた

こんな感じになりました。

時系列にシナリオを並べつつ、右上に想定されるユーザーの軽いペルソナもお記載し、
誰がこの機能を使うか?を、整理していく時も常に意識出来るようにしました。

ストーリーマッピングしてみました

ストーリーマッピングしてみました

 

実施時のポイント

  • シナリオの文型は、「ユーザーが●●できる」とした。

    →「●●する」だと「ボタンを押す」など動作に注目がいきがちですが、
     「●●できる」だと動作の目的(例えば「設定できる」)に自然と視点がいき、要件を整理しやすかったです。

  • 一旦私が叩き台を作っておき、チームメンバーには、それを元にシナリオが合っているか確認していく形にした。

    →チームメンバー其々が書き出したシナリオをマッピングしていく形がメジャーですが、ストーリーマッピング自体、今回初めての試みだったので、文法合わせなどのお作法の認識合わせで時間がかかることが予想されました。
    ともすれば、本来の目的である「認証機能のシナリオを抜け漏れなく書き出す」ことが、時間内に達成できない可能性があったため、この形を取りました。

  • リリース範囲選定は、プライマリユーザーが必要な機能はどれか?に主眼を置いた。

    マッピングとは別に、想定ユーザー(プライマリ・セカンダリ)を記載しておき、そのユーザーにとって必要な機能か否か?を、ストーリーのリリース範囲の選定基準としました。

 

ユーザーストーリーマッピングして良かったこと

今回トライしてみての振り返りです。

良かった点が多く、今回の課題を解決するのにマッチした手法だったと思います。

  • 口頭や文章でやり取り時は、複雑に見えていた要件が、マッピングすることによってスッキリした。
  • ストーリーの中でも複雑なところ・単純なところが可視化されて、注力しなければならない点が見えてきた。
  • 視覚化されたので、イレギュラー時のストーリーや、派生したストーリーなど、抜け漏れに気づけた。
  • 整理していく中で、実はプライマリユーザーは別にいるのではないか?と気づくことができた。
  • 想定ユーザーのペルソナも併せて記載しておいたおかげで、「ユーザーAはこの動作はしないのでは?」的な、ユーザー目線での整理ができた。

ユーザーストーリーマッピング、ピンと来た方は、ぜひ活用してみてください!
あなたの課題を解決する一助になるかもしれません。

より詳しく知りたい方は、こちらの本がオススメです!

www.oreilly.co.jp

 

仲間募集中!

そんな、幅広いフェーズにコミット出来る、オクトのデザインチームは、
一緒に働く仲間を募集中です!

気になった方は、ぜひお気軽にエントリーお願いします!

hrmos.co

 

新機能開発ってどう進めてるの?

f:id:mikakato:20200225115358p:plain

はじめに

初めまして、12月にPdM(プロダクトマネージャー)として入社した加藤です。

 

現在ANDPADチームの一員として、新機能の開発に従事しています。

PdMとしてはせっかく作った機能があまり使って貰えない...という事態は避けたいものですし、かといって開発に無限の時間・リソースを割ける訳でもない...。
そんな中で、どうしたらスピード感を持ちつつ良い機能が作れるのかを日々チームメンバーと共に考えています。

 

建設業界未経験(IT業界出身)かつSaaSサービスのPdMとしてもまだまだ勉強中の身なのですが、実際にどんな感じで進めてるの?という部分を簡単にお伝えできたらと思います。

とりあえず作るの前に

ANDPADは建築・建設現場向けに特化したツールであるため、新しい機能を追加開発するにあたっても「業界で働く方々が、真に必要としているものを作るという意識」を手放さない事が大切です。

書くと当たり前な事に思えますが、意外と難しいなと感じます。特に私のような業界未経験の身だと機能的なアイデアが先行しがちです。

何となくで作ってしまう=失敗パターン...の轍を踏まないためにも、まずはリーンキャンバスを使い、作ろうとしているプロダクトのターゲット/課題/価値/ソリューションが一貫性を持っているかを整理しました。

  • ターゲットとなるセグメント(事業規模や拠点数はどのくらいか、新築なのかリフォームなのか、注文住宅なのか分譲住宅なのか...)はどこか?ユーザーはどのような人(現場監督、営業、設計士...)か?
  • その人は日々の業務で具体的にどのような課題(ペイン)を感じているのか?
  • 課題に対して、ANDPADとしてどのような価値を提案できるか?
  • 価値を実現するソリューション(機能)は何か?

リーンキャンバスについてはこちらで詳しく紹介されています。

media.bizmake.jp

設定した仮説はエンジニアを含むチームメンバー全員で確認し、認識をそろえることも大切な要素だと思います。

ユーザーの声をきく

ユーザーの解像度が低いままでは、どんなに良いプランを描いても顧客ニーズと開発するプロダクトが乖離しかねません。

そのため、リーンキャンバスで設定・整理した仮説が本当に合っているのか?を、実際のターゲット層となる方にプロダクトインタビューを重ねました。

インタビューをするにあたっては一旦仮説に基づいてプロトタイプ(UIイメージが伝わるワイヤーフレーム、モック)を作成し、極力具体的なイメージをお見せするようにしています。

実物を開発する前にユーザーのリアルな反応やフィードバックが得られますし、もしこの段階で仮説がズレていた場合は随時修正していきます。

 

プロダクトインタビューの手法や観点については、こちらの書籍を参考にしています。

www.nikkeibp.co.jp

 誰が見ても分かる言葉に翻訳する

 仮説設定についてもインタビュー内容についても同様ですが、情報を整理する際はとにかく誰が見ても分かる言葉や表現を選ぶことを意識しています。

PdMの性質上、社内外あらゆる役割・属性の方々から情報を集め・整理し・展開しなければなりません。情報源も展開先も多様です。

ただ小さいチームで動いていると、どうしても「共通の文脈をあらかじめ理解している」前提で話が進んでしまいがちです。

その後の認識のズレを正す手間も時間も積み重なると大きな負担になるので、地味かつ至極当たり前のことですが、PdMとして極力コミュニケーションコストを下げるためにできることを実践しています。

  • 書き手の独りよがりな表現を使わない
  • 極力、図で表す(言葉よりコミュニケーションのずれが少なくて済む)
  • ユーザーが読んでも営業マンが読んでもエンジニアが読んでも同じ意味にとれる表現を選択する
  • 曖昧な言葉はできるだけチーム内で意識を合わせる

 

おわりに

最後まで読んでいただきありがとうございます!
オクトでは一緒に働く方募集しております。よろしければこちらも是非ご覧ください。

engineer.88oct.co.jp

「コミッターと読み進めるRailsリーディング会 #1」を開催しました!~ Rails v1.0.0を読み進める! ~

はじめに

はじめまして!オクトのRailsエンジニアの @KanechikaAyumu です!

弊社では、日々色々な勉強会が開催されています。

先日は、ANDPADの技術顧問をして頂いている松田さんにRailsリーディング会の勉強会を開催して頂きました!

prtimes.jp

貴重なお話を聞ける機会なので、社内の勉強会に閉じるのがもったいないと思い、外部の方も参加できるような形式を取らせて頂きました。当日参加してくださった方、平日の日中のお忙しい中にご参加頂き、ありがとうございました!!

oct.connpass.com

Railsソースコードを読んだことない人や、どこから読み進めて良いのか分からずな方は、参考にして頂ければと思います!

  1. 当日の様子
  2. Rails v1.0.0
  3. コミッター紹介
  4. Active Record
  5. Action Pack
  6. alias_method
  7. 最後に

当日の様子

当日は社内のエンジニアに加えて、数名外部のエンジニアの方にご参加頂きました。ご参加ありがとうございます!

松田さんの画面操作を見ながら、参加者全員でリーディングを行いました。Railsだけではなく、ソースコードの読み方やコマンド操作などたくさん学ぶことができました!

f:id:ayumu-kanechika:20200216175542j:plain

f:id:ayumu-kanechika:20200216175608j:plain


Rails v1.0.0

松田さんのオススメのOSSの読み方は、「First Commitから読み進めていくこと」とのことです。作者の本当に実現したかった内容が、ノイズ等がなく、シンプルに書き下されている為です。今回の勉強会でもv1.0.0から読み進めて行くことになりました。
 
皆さんもお手元にチェックアウトしてみて下さい!
$ git clone git@github.com:rails/rails.git
$ cd rails
$ git checkout v1.0.0
 

Railsは、フルスタックのMVCフレームワークです。
Mのモデルレイヤーは、O/Rマッパーも兼ねて「Active Record」が担います。
Cのベースとしては「「Action Pack」があり、当時は「ActionController」や「ActionView」が担っておりました。MVCの糊付けとして、「Railtise」があります。

勉強会では、中核な処理の「Active Record」「Action Pack」を読み進めました。

コミッター紹介 

その前にコミッター紹介です。生産者の顔が一番大事とのことです!

 

Railsは、DHHのファーストコミットで、大枠は出来上がっていました。
Action Mailer、Action Pack、Active Record、RailtiseなどMVCの中核の部分はだいたい全部入っていました。2004年にBase Camp(当時、37signals)のWebApplicationから切り出した為です。(とある1つ企業のフレームワークの切り出しで、この設計力の高さは驚愕です!!)
 
その最初のコミットがこちら
Initial
綺麗なコミットが積まれているのは、DHHがそういう性格の人だそうです。
 他にもコミットやRails Contributors をなどを見ながら、名前の挙がった方をつらつらと記載します!
$ git shortlog -sn db045dbbf6..v1.0.0
 
1771 David Heinemeier Hansson
278 Jeremy Kemper
205 Jamis Buck
79 Nicholas Seckar
77 Leon Breedt
70 Marcel Molina
42 Sam Stephenson
14 Thomas Fuchs
13 Tobias Lütke
12 Scott Barron
9 Florian Weber
8 Michael Koziarski
  1. DHH(David Heinemeier Hansson
    ファーストオーサー 37 signals CTO
    当時では珍しいRubyを使って、プロダクトを作り始めた。
    当時25歳。コードが書けて、設計できて、イケメン!!

  2. Jeremy Kemper
    No.2の重要人物
    Base Campにあとからジョインした。
    20世紀の頃からRubyを触っていた。
    Railsを影から支えるNo.2
    今の名前は、Jeremey Daer。
    結婚して、夫婦の名字を足して2で割ったらしい

  3. Jamis Buck
    Base campに後からジョイン
    代表作は、Switch Tower(?)。Rubyでピッとデプロイができる代物。
    商標などの兼ね合いで、のちにCapistranoに変わる。

  4. Nicholas Seckar
    主にActiveRecordを開発

  5. Marcel Molina
    当時は最年少。シンボルにProcを導入!

  6. SamStephenson
    まだ尚、社員
    JS系を色々と作っている。
    Asset Pipelineを作った人。Sprocketsも。

  7. Tobias
    社外の方。MySQLに強い。カナダ人。ActiveRecord
    Shopifyを起業をして、「CTO」ではなく「CEO」をやっている。

  8. Michael Koziarski
    ニュージーランドRailsコミッター。セキュリティ周り

  9. Eric Hodel
    シアトルRubyの親玉

  10. JoshPeek
    Railsコミッター。Rack。
    サンフランシスコの小さい企業Githubを立ち上げた。
    Rails魔改造をし続けて、Githubが2系を使い続けていた。

  11. Chat Fowler
     Rubyconf

  12. Shugo Maeda
    Railsのv1.0.0で唯一コミットが取り込まれた日本人

 

Active Record

当時のv1.0.0では「activerecord/lib/active_record/base.rb」の約1800行にコアの処理が全て書かれていました。他はおまけとのこと!
 
Railsも当時は新出のフレームワークだったので、ソースコードのコメントもかなり丁寧に書かれているので、キャッチアップしやすいです。
 
findメソッドにinteger渡すとプライマリキーとして検索されるなど、既に今と同じ形式でした。 機能としては、大枠できており、最先端という感じでした。最近の開発では、DSLが増えているという感じ。
 当時はfindしか使っておらず、relationとかなかったので、即SQL発行がされていました。
 
#find が面白いので、読み進めていきます!
def find(*args)
  ...
  case args.first
    when :first
      find(:all, options.merge(options[:include] ? { } : { :limit => 1 })).first
    when :all
      records = options[:include] ? find_with_associations(options) : find_by_sql(construct_finder_sql(options))
      ...
    else
      ...
      conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
 
引数にfirst、all、それ以外の何を渡しても最終的に「find_by_sql」に「construct_finder_sql」が呼び出されています。
 
#construct_finder_sql はストレートに処理が書かれています!
def construct_finder_sql(options)
  sql = "SELECT #{options[:select] || '*'} FROM #{table_name} "
  add_joins!(sql, options)
  add_conditions!(sql, options[:conditions])
  sql << " GROUP BY #{options[:group]} " if options[:group]
  sql << " ORDER BY #{options[:order]} " if options[:order]
  add_limit!(sql, options)
  sql
end
 
#find_by_sql は今でも残る重要なAPIとのことです!
def find_by_sql(sql)
  connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
end
 
次に、#save を読み進めていきます。
def save
  raise ActiveRecord::ReadOnlyRecord if readonly?
  create_or_update
end
 
中では、#create#update を呼び出すことになり、そちらも愚直にSQLを構築しています!
def create
  if self.id.nil? and connection.prefetch_primary_key?(self.class.table_name)
    self.id = connection.next_sequence_value(self.class.sequence_name)
  end
  self.id = connection.insert(
    "INSERT INTO #{self.class.table_name} " +
    "(#{quoted_column_names.join(', ')}) " +
    "VALUES(#{attributes_with_quotes.values.join(', ')})",
    "#{self.class.name} Create",
    self.class.primary_key, self.id, self.class.sequence_name
  )
  @new_record = false
end
 本当にRailsのコアの処理はv1.0.0に詰まっています!
 
他に大事なのはなどがあるのですが、時間が足りずなので、次回以降のお楽しみになりました!
続きを読む