selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

Terraform / aws-cdk を比較してみた(個人の所感です)

プライベートにて、経験の浅いチームから aws-cdk と terraformどちらが良いのですか?と聞かれたのでまとめてみました。間違いがあればご指摘いただければ幸いです。

前提

  • 利用する人間はIaCの初心者である
  • 当然 CloudFormation等に関する基本的な知識がないものとする

結論

  • 初学者にとっては、IaCのツールとしてはTerraformを採用するのが良さそう
  • その理由として最も大きなものは、「学習コストが少ない」こと
  • 「学習コストが少ない」についてブレークダウンすると下記のようになる
    • NewRelic や Sentry、その他SaaSとの連携もIaC化をする場合、Terraformなら1つで対応できる
    • aws-cdk は CloudFormation、aws-cdk、TypeScript、AWSの各種リソース等理解しなければ十分に活用できない
      • 欲を言えば、プログラミングの設計スキルも必要となる
    • TerraformはTerraformとAWSの各種リソースに対する理解の2点のみで良い
      • Terraform自体のキャッチアップを1とするなら、TypeScriptは4~5くらいの規模感
    • aws-cdk は原則として、インフラリソースの手作業による更新が許容されない
      • そのため、consoleを動かして挙動確認しながら理解を深めることができない

背景

2020年現在、AWSのインフラリソースを定義するメジャーな方法は3つあります。AWS CloudFormation、aws-cdk、Terraformです。まずはそれらの立ち位置について簡単に説明していきましょう。

AWS CloudFormation

AWS CloudFormationAWSが公式で提供しているIaCのためのツールです。公式で提供しているということもあり、ほぼすべてのAWSインフラリソースをこれで定義することができます。一般的によく利用されるようなインフラ設定については、サンプルコードがAWS公式によって提供されています。そのため利用者は、大抵のシステムを公式が提供してくれるテンプレートに少し手を加えるだけで構築することができます。また CloudFormationを拡張し、Serverless Application開発を容易にした SAM(Serverless Application Model)という機能も存在します。SAM Localを利用すればコードを手元で動作確認しながら、サーバレスアプリケーションの開発ができます。

良い事の多い CloudFormationですが、実際にコードを見てみましょう。下記にRailsアプリケーションを作る際のCloudFormationの一部を示します。これをサクサク読み書きできるようになるには、相当な修練が必要であることは想像に難くないでしょう。

// https://s3.us-west-2.amazonaws.com/cloudformation-templates-us-west-2/Rails_Single_Instance.template
"Properties": {
  "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
                      { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
  "InstanceType"   : { "Ref" : "InstanceType" },
  "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ],
  "KeyName"        : { "Ref" : "KeyName" },
  "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
    "#!/bin/bash -xe\n",
    "yum update -y aws-cfn-bootstrap\n",
    "/opt/aws/bin/cfn-init -v ",
    "         --stack ", { "Ref" : "AWS::StackId" },
    "         --resource WebServer ",
    "         --configsets full_install ",
    "         --region ", { "Ref" : "AWS::Region" }, "\n",

    "/opt/aws/bin/cfn-signal -e $? ",
    "         --stack ", { "Ref" : "AWS::StackId" },
    "         --resource WebServer ",
    "         --region ", { "Ref" : "AWS::Region" }, "\n"
    ]]}}        
 },
 "CreationPolicy" : {
  "ResourceSignal" : {
    "Timeout" : "PT30M"
  }
}

SAMを用いて小さいServerless Applicationを作るのであれば良いですが、ある程度の規模のシステムになると Cloud Formationについて深い理解をしていなければ、すべてを管理することはとてもむずかしいと思えます。ここで詳細は述べませんが、CloudFomartion自体はIaCの原理原則を守り、リソース間の依存関係の確実な管理をしてくれて、安全な更新が可能な良いものです。ですが、少し専門家向け過ぎるツールであると言えます。

aws-cdk

CloudFormationの辛さについては上述しました。AWSもその問題点を理解しており、CloudFormation Designer などのツールを公開し、GUI上の設定によってCloudFormationが自動生成されるような仕組みを用意していました。しかし、結局の所生成されるのは Cloud Formationです。Cloud Formation自体が読み難いという根本的な問題は解決していません。

その課題に対処するために作られたのが aws-cdk です。端的に言うと、VueやReactからHTMLを生成するように、TypeScriptで作ったプログラムからCloudFormationを生成できるツールです。下記の図のようにcdk がコンパイラとなってCloud Formationを生成します。

f:id:selmertsx:20210507095951p:plain

aws-cdk の登場によって、AWSはCloudFormationを assembly language というポジションにしました。これから先、主にユーザーが利用するのは aws-cdkであり、専門性高いエンジニアがツールを構築したり、cdkのOSSにコミットしたり、デバッグ等で利用するときに Cloud Formationの理解が必要になる。というのが AWS の考えだと思います。

実際に利用している aws-cdk のプログラムを下記に示します。TypeScriptに関する知識があることは前提になりますが、CloudFormationよりも格段に読みやすくなったのではないでしょうか。TypeScriptであるため IDEの補完機能による恩恵も受けやすく、明らかに間違った設定をすればコンパイルすることもできなくなります。

export class ApiGatewayStack extends Stack {
  public readonly api: Resource;
  public readonly authorizer: TokenAuthorizer;

  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const stage = tryGetStage(this.node);
    const cmsRestApi = new RestApi(this, `${stage}-rest-api`, this.getCmsRestApiProps(stage));
    this.authorizer = createAuthorizer(this, stage, cmsRestApi);
    this.api = RestApi.root.addResource("api");
  }

  private getRestApiProps(stage: string): RestApiProps {
    return {
      restApiName: `${stage}-rest-api`,
      deployOptions: {
        loggingLevel: MethodLoggingLevel.INFO,
        dataTraceEnabled: true
      },
      minimumCompressionSize: 1024,
      endpointConfiguration: {
        types: [EndpointType.REGIONAL]
      }
    };
  }
}

さらに、aws-cdk から CloudFormationを生成することができるため、CloudFormationで利用可能な各種ツールをそのまま利用できます。例えば生成したCloudFormation を CloudFormation Designerに取り入れれば、awsのインフラ図を生成することもできます。また、SAM Localと連携してローカル環境で動作させることもできます。最近ではAWS公式から serverless pattern というリポジトリが作られました。頻出する数多くのインフラパターンを詰めたコードのサンプル集です。これを参考にすれば、新しいシステムを作る際に、インフラのベストプラクティスを踏襲して安全なシステムを作りつつも、工数を大幅に削減することができます。

さて、ここまで良いところばかりを述べてきましたが、aws-cdkにもデメリットは数多くあります。まず最も大きなものとしては、「学習コストの大きさ」 です。少なくとも現状では、 CloudFormation、aws-cdk、TypeScriptの3点の知識が必要になります。さらに長期間に渡ってメンテナンス可能なIaCを実現しようとすれば、オブジェクト指向の理解・実践も必要となります。何より大きい課題は、「公式による力強い明確なベストプラクティスやコーディング規約の不在」 です。aws-cdkを取り入れるチームは、自ら設計指針を考え、適切なコーディング規約を作り、チーム内で合意する必要があります。そうしなければ、これまでの数多くのソフトウェアと同じように、負債を多く抱えたシステムになってしまうでしょう。Cloud Formationは、Stack間依存の取り扱いを非常に厳密に行っており、その厳密さがシステムに安定性を与える反面、理解せずに利用すると返却の難しい負債を作り出してしまいます。

これまでの内容をまとめると、「aws-cdk をチームで効果的に利用し続けるためには、CloudFormationやTypeScript、IaCの原則について一定以上の理解をしたエンジニアが集まり、0から設計指針やコーディング規約を作る能力・余地がある」というのがaws-cdkを採用する際の条件になります。

個人的には、大きな開発組織のSREや、フルスタックエンジニア個人による利用では力を発揮するツールという印象を持ちました。

Terraform

Terraform とは Hashcorp社により提供される IaCのツールです。最も大きな特徴としては特定のベンダーに閉じずに、様々なサービスの設定をこれでIaC化できることです。AWSGCP、Azureはもちろん、Auth0NewRelicなど、その他多種多様なSaaSに対応しています。さらに、Go言語に詳しければ自ら作ることもできます。

Terraformの記述方法は次のようになります。Terraformは設定をDSLで記述するため、aws-cdk ほど自由度はありませんが、CloudFormationよりはだいぶ楽に記述することができます。

resource "aws_iam_role_policy" "iam_policy_for_iot" {
  name = replace("${var.system_name_prefix}_iot_rule_to_kinesis_firehose_policy", "-", "_")
  role = aws_iam_role.iot_to_firehose.id

  policy = jsonencode(
    {
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Effect" : "Allow",
          "Action" : [
            "firehose:PutRecord",
            "firehose:PutRecordBatch"
          ],
          "Resource" : var.iot_data_firehose_arn
        }
      ]
    }
  )
}

また、Terraformは設計における数多くのベストプラクティスを公式で提供しています。そのため、公式のドキュメントをしっかり読み込めば、開発における大部分のユースケースには対応可能になっています。

ツールの比較

aws-cdkの背景からお話したように、これから先 CloudFormation を素のまま利用しないことを想定していると思われます。そのため、CloudFormationについては比較対象から除外します。よって、以降では aws-cdk と terraformについての比較を行っていきます。

比較表と結論

Terraform aws-cdk
学習容易性 ×
製造容易性
インフラの修正容易性 ×
コードの修正容易性

Terraformとaws-cdkの比較を行った表が上記になります。結果をざっくり一言で言えば、「分かってる人が使うならcdkの方が良いけど、そこまで分かってる人多分市場を探してもそうそういないよね」という言葉になります。以降、比較軸の内容について詳細に記述していきます。

学習容易性 Terraform◎ aws-cdk ×

学習容易性としては、Terraformを優勢としています。理由としては下記の通りです。

  • aws-cdkが必要とする知識は下記の通り
    • 土台としている CloudFormation に関する知識
      • 遠い将来はいらなくなる可能性が高いとはいえ、現状では必須
    • aws-cdk のフレームワーク自体の知識
    • TypeScriptの言語に関する知識
    • オブジェクト指向を用いた設計方法に関する知識
  • Terraform が必要とする知識は Terraformの使い方についてのみ
  • aws-cdkは公式でベストプラクティスを提供していないため自ら考え、構築しなければならない
  • Terraformは公式がベストプラクティスを提供しているため、それを守ればそれなりのものが作れる
  • 良い書籍が出ており、これを読んでおけばある程度の成果物の品質を担保しやすい
  • NewRelic、Sentry等のSaaSもIaC化を検討しており、結局は Terraformを学習しなければならない

製造容易性 Terraform △ aws-cdk ◎

  • aws-cdkの terraform に対する優位性は下記の通り
    • TypeScriptで記述するため型推論による恩恵を受けられる
      • 必要な設定はIDEが教えてくれるし、間違った設定は実行前にコンパイルエラーになる
    • オブジェクト指向によるコードの整理が可能である

手動によるインフラ修正容易性 Terraform ◎ aws-cdk ×

この項目はAWS Console上から手動で行った変更を IaCツールで取り込む際の難しさを示すものです。

コードの修正容易性

  • terraformではmoduleレベルでのリファクタリングの難易度が非常に高い
    • 一つ一つのリソースを terraform state mv していく必要がある
  • aws-cdkは同一の成果物(CloudFormation)が生成されれば良いので、コード自体は柔軟に変更が可能
    • スタック自体を移動するのは難しい

結論

以上、Terraformとaws-cdkの比較を行いました。 経験の浅いチームがプロダクションで利用する状況においては、学習資料が整っているという観点から terraformを使うのが良いのではないでしょうか。 aws-cdkは非常に便利な道具であるものの、深く理解して慎重に使わなければ返済の難しい負債を作り出します。 なので、趣味アプリ等でなれてから本番運用に持っていくと良いのではないかなと思います。

課題を整理・分類し、対処できるように解像度を高めていく

モチベーション

  • 日々、未加工の生肉のような課題っぽいものが飛んでくる
  • 課題っぽいものの中で、今の状態で実施すべき打ち手を把握したい
  • 課題をうまく整理・仕分けし、上記を実施していきたい

課題の図

そもそも課題とは何でしょうか。本書は課題を理想と現状のギャップと捉えます。 裏を返せば、理想がなければ課題もありません。つまり課題がない、という現象が起こってしまう原因の一つは「理想がない」からです。 ~馬田隆明 未来を実装する P.143~

f:id:selmertsx:20210328001046p:plain

  • 馬場隆明さんの「未来を実装する」という書籍では課題を上記のように定義している
  • 僕はこれに加えてもう一つ「知識」が重要な要素だと思っている
  • 理想があっても、知識がなければ課題に形を与えられない
    • 知識は、文献から得られるものだけでなく、自分たちのチームが実験、検証によって得た体験的な知識も含める
  • 形が与えられない課題は、適切な認識がされずに解決されない
    • 漠然とした不安をチームに与えるだけである
  • 様々な知識をもとに、課題を解決可能な状態に落とし込むための順番を整理したい
  • 理想 / 現状 / 課題の図は、個人、チーム、組織と、スケールは違えども大枠や対応方針はだいたい一緒である

課題の種類整理

既知の既知がある。我々が知っているものがあり、そのことを我々が知っていることだ。 既知の未知がある。我々が知らないものがあり、そのことを我々が知っていることだ。 それから、未知の未知がある。我々が知らないものがあり、そのことについても我々が知らないことだ。 ~ アリステアクロール Lean Analytics P.13~

f:id:selmertsx:20210328002628p:plain

  • 理想 / 目標 があれば課題が生まれる
  • 僕は、課題を上記のフォーマットで整理する
  • 既知の既知は、実行あるのみである
  • 既知の未知は、調査 / 学習 / 検証をして、既知の既知にする
  • 未知の未知は、課題分析 / 調査 / 仮説検証を行い、既知の未知にする
  • 未知の既知は、標準化 / マニュアル化を行い、既知の既知にする
  • 今見えている課題は、上記のどこに分類される課題なのかを整理する
  • 課題を対処する上で最も重要なのは、いかに迅速に「既知の既知」まで課題を落とし込むか

課題整理 (詳細)

why what how 状況例 実施内容
why what how が分かったので、あとはやるだけ 実装 / 実行
開発効率を向上させるために、デプロイ頻度を増加させたい。要素技術は分かったが、我々のプロダクトにマッチするか分からない 検証
開発効率を向上させるために、デプロイ頻度を増加させたい。そのための要素技術が分からない 技術調査 / 技術書の読書会 / 技術的な研修
開発効率を向上させるために、デプロイ頻度を増加させれば良さそうだが確証がない 課題仮説の検証
開発効率を向上させるために、何をすれば良いか分からない 調査 / 課題分析 / 仮説立案
  • 課題の状況と、それに対する打ち手を整理したものを上の表に示す
  • 上の図においては、「開発効率を向上させる」というミッションを持った開発チームを例にした
    • チームに落とすのであれば、もう2〜3段階解像度を上げたほうが良い
    • 例えば 「LeanとDevOpsの科学」にあるハイパフォーマーを目指すなど
  • ここで大切なのは、 課題に対する打ち手は、一足飛びにしないこと
  • 何をすれば良いかも分からないのに、技術調査をしても意味がない
    • 意味があったとしても非効率
    • 目をつぶってバットを振るようなもの
  • 検証もしていないのに、本実装に入るのはリスクが高い
  • チームで課題に向き合うときは、今見えている課題はどこのフェーズにあるのかを整理することが重要である
  • そして フェーズごとに適切なゴール設計と対処 が必要である
  • チームにて責任を持つ人の仕事は、下記の通り
    • 着手可能な課題を提供すること
      • そもそもWHYが固まっていないのに、実行部隊にタスクを投げない
    • 課題の詳細を適切にチームに伝えること
    • 課題の終了条件をチームに伝えること
    • チームが一足飛びに課題を解決しようとしたら、会話して気づいて貰うこと
    • 知識の不足により課題を適切に把握できていない場合は、教育の機会を設けること

最後に

  • 課題の解像度を高めるために、取れるアクションの回数には限りがある
    • なんでもかんでも 「やってみなきゃ分からない 」 は許されない
    • 「作ってみてユーザーに当てる」は制限回数が存在するビジネスがある
      • 未完成のものを当てすぎると顧客との信頼関係を失いうる
      • 開発チームの練度、実績、顧客との信頼関係、プロジェクトの期間、競合の状況などにより実際に作れる回数は自ずと決まってくる
        • 庵野監督も、実績がなければあれだけ延期することはできない
      • 自分たちの中で判断する分には、どれだけ雑でも良いだろうし、何度でもやれば良い
  • その限られた回数をどのように使うか、真剣に向き合うことが重要

アジャイルとリーン・スタートアップを組み合わせた開発プロセス ( 施策立案編 )

突然ですが最近転職しました。転職先は三菱重工業です。 業務内容については、概ねこちらの記事に書いてある感じです。 多くの人が意外に思うかも知れませんが、AWSをゴリゴリ使って毎日楽しくシステムを作ってます。

findy-code.io

製造業の世界に飛び込んだので、最近は製造業の世界に自分が経験してきたソフトウェア開発プロセスの良いところをどのように取り入れていくのか、といったことを考えることが趣味になっていたりします。 取り入れるべき開発プロセスを明確にイメージできるようにするために、一旦自分がこれまで学んだり、経験してきたソフトウェア開発のプロセスを一旦棚卸ししてみようと思い、記事にしてみました。

前提

Lean Startupについて

この開発プロセスは、Lean Startup の思想に基づいて構成されています。 Lean Startupについて間違いを恐れずに一言で言うならば、 「スタートアップにおいて、ムダなくサービス開発を継続し続けるためのマネジメント論」です。 Lean Startupの源流はトヨタ生産方式です。 そのため、このムダという言葉は、トヨタ生産方式におけるムダから来ており、 「付加価値を高めない各種現象や結果」 と定義されています。

重厚長大な市場調査と企画書を用意するよりも、 価値が伝わるミニマムな製品を作成しユーザーに直接ぶつけてみるほうが時間・金額的コストが安く、学びが多いこともあります。 逆によく考えずに手当り次第に機能を開発し、それが使われなかったとしたらムダが発生します。 それらの失敗から何かを学び、次に活かせるような学習のプロセスがなければ、ムダを生産し続ける組織になってします。 Lean Startupはそれらのムダを最小化するためのマネジメント方法です。 ただし、Lean Startup自体には、厳密なプロセスが規定されていません。 そのため私は、再現性高く改善できるプロセスが構築できるように、 Lean AnalyticsやDesign Sprint、ユーザーストーリーマッピングなどのフレームワークを組み合わせています。 この記事では、全体像をより具体的に把握することを優先し、Lean Startupの本質などに関する説明ではなく、それらを組み合わせたプロセスについて説明します。

この開発プロセスは1-10での利用を想定している

この開発プロセスは0-1ではなく、1-10での利用を想定しています。 すでに企画として立ち上がったサービスであり、PSFitは済ませており、 これからはユーザーの定着を目指していくところでの利用です。 それ以外のユースケースでは有効かどうかを確認できていません。

ソフトウェア自体の開発にはアジャイルを採用している

この開発プロセスはすでに決まったものを時間掛けて作るのではなく、ユーザーの反応を見ながら作るものを決めます。 そのため、短い期間で適宜軌道修正をすることができるアジャイルを採用しています。 アジャイル開発においては、職種をまたがってチームで開発するプロセスを提供してくれるスクラムと、 ソフトウェアエンジニアに向けてより良い規範を提供してくれるXPを組み合わせています。 ただし、スクラムやXPの部分については、それだけで膨大になってしまうため今回は説明しません。 もし、詳細を知りたいという方がいましたら、ブックマーク上でコメントいただけますと!

開発プロセスの全体像

開発プロセスの全体像はこちらになります。 なお、この開発プロセスは市谷先生の「正しいものを正しくつくる」という書籍をベースにしています。

f:id:selmertsx:20200705214843p:plain
開発プロセスの全体像

この開発プロセスの左側をざっくり3行で説明すると、こんな感じになります。

  • リーンスタートアップで事業計画を作成し
  • リーンアナリティクスで事業計画に対して数字的な裏付けを行い
  • Design Sprint でアイデアを作るプロセスと、それを実際に決定する合意プロセスを提供します

この章では全体の開発プロセスについて概要を軽く記載します。 それぞれのプロセスの詳細については、次の章にてまとめます。

最初のステップ:事業計画

事業計画フェーズでは、サービスの性質とKGI/KPIの設計、ステークホルダーとのコミュニケーション設計を行います。

リーンキャンバスと、インセプションデッキを作成し、誰のためのどのようなサービスを作るのか。我々のサービスの競合優位性は何なのか。 サービス開発を進めていく上でのステークホルダーと、ステークホルダーの人たちのコミュニケーション方法を簡潔にまとめます。 そして、Lean Analyticsをベースに現在のサービスのステージを特定し、そのステージに適したKGI/KPIを設定します。 基本的にすべてのKPIを追うことは出来ません。そのため追うべきKPIの優先度も決めておく必要があります。

これらの資料は何度も作り直すことになるでしょう。それはサービスを開発していくなかで、ユーザーや市場の解像度が上がるからです。 資料を修正する必要性が生まれるということは、チームが学習をしているということです。 それをポジティブに受け止めて、チームで話し合いながら更新していきましょう。

2つめのステップ:仮説立案

仮説立案フェーズでは、事業計画フェーズで定めたKGI/KPIに対して、有効と思われる機能の仮説を出します。

仮説の立案は Design Sprintを利用して行います。 Design Sprintでは、KPIから逆算して達成すべき課題を定義します。 例えば、定着フェーズのECサービスを例に考えます。 KGIが 「90日以内に戻ってくる購入者の割合」として、 KGIに紐づくKPIの1つを「ユーザーが目的の商品を見つけることができた割合」としたとします。 このようにKPIを決めたとき、解くべき課題は2点に集約されると思われます。 1点目は「ユーザーが求める商品を用意することができる」であり、2点目は「ユーザーが目的とする商品に到達できる」になります。 Design Sprintでは、KPIにヒットしうるビジネス上の課題を予め建ててから、その課題に関連するユーザーの動きをインタービューを通して整理します。 整理する上でカスタマージャーニーマップのようなものを作ることもあります。

その後、チーム全体で課題を解決しうる機能の案を出し合い、簡単なモックを作って有効性を検証します。 詳細は追って説明しますが、Design Sprintはまず最初に、解くべきビジネス上の課題を明確にします。 また、開発物を決めるまでのプロセスも厳密に定められているため、迅速な意思決定が可能になります。

3つめのステップ:検証計画の作成

検証計画の作成は著書 Running Lean の8.5章にて説明されている「1ページの実験計画書」を用いて行います。

Design Sprintにより提案された案を、実験計画書に落とし込んでいきます。 実験計画書においては、開発する内容、求める成果、成果が得られると思われる根拠、成果の計測方法、実験の期間を記載します。 このとき、もし会社にデータ分析チームがいるのであれば、根拠の部分に関して定量的な裏付けを行うと良いでしょう。 また、世の中にはすでに同じ様な実験が行われている可能性もあります。 そういった実験結果が論文などで公開されていることもあるため、一度探してみても良いでしょう。

4つめのステップ:MVPの特定

「1ページの実験計画書」で計画した実験を達成するために必要な最小限の機能を洗い出します。

この作業は「ユーザーストーリーマッピング」という手法を用いて行います。 ユーザーストーリーマッピングの「ユーザーストーリー」はスクラムで用いられる「ユーザーストーリー」と同じもので、 ユーザーがサービス上で目的を達成する上で発生するシーンと、それに対応した「ユーザーストーリー」をマッピングしたものになります。 全体を俯瞰することで、ユーザーに価値を提供するために必要な機能の一覧を把握できるようになり、目的を達成するための最小限の機能を認識できるようになります。

なお、MVPを特定する上では、セキュリティや法律の知識も必要になります。 例えば契約書を交わす上で必要な手順などを適切に把握していなければ、法律に違反するサービスを作ってしまうこともあります。 法律は機能単体で評価されるわけではなく、サービスの機能全体、そして実態で評価されます。 そのため、他のサービスの機能をそのまま自分たちのサービスに持ってきたからといって、法律上問題ないとは限りません。 また、法律を把握していれば、競合他者のサービスよりも、より良い機能を提案できることもあります。 そしてセキュリティについても意識する必要があります。MVPであるからといってセキュリティを疎かにすることはできないからです。

MVPの特定まで終わってしまえば、あとはスクラムのプロセスに乗せて開発を行えます。 そして出来たものを評価し、学習によって得られた結果をもとに、次の開発物を考案していくという流れになります。

以降、それぞれの開発プロセスについてより詳しく記載していきます。

事業計画

サービスを開発する上で、最初にあるべきなのは事業計画です。 事業計画がなければ、その事業に投資すべきか否かを判断することができません。 事業計画は企業毎にフォーマットがあると思いますので、承認者に見せる資料はそのフォーマットに従ったものを作ることになります。 しかし、一般的な企業における事業計画書では、開発に携わるすべてのメンバーが理解することには難しい場合がほとんどです。 そのため、チームの内外で共通認識を作るための別のフォーマットも必要になります。 そのフォーマットとしてよく使われるのが、リーンキャンバスとインセプションデッキです。

リーンキャンバスを作る

リーンキャンバスは、「Running Lean」の著者で知られるアッシュ・マウリャ氏が提唱するフレームワークで、 ビジネスモデルの9つの要素を1枚の紙にまとめたものです。

f:id:selmertsx:20200705215314p:plain
Lean Canvas( leanstackの公式ページより引用 )

その9つの要素とは、 解決すべき課題、ソリューション、既存の代替品、主要指標、独自の価値提案、 競合優位性、ハイレベルコンセプト、顧客セグメント、アーリーアダプター、コスト構造、収益の流れ、になります。 ビジネスはこの9つの要素の集合です。 どれだけ売上があったとしても、コスト構造が将来的にも掛かる見込みがある事業は継続することができません。 また、短期的に見てそれなりに利益が出たとしても、狙った顧客セグメントに利用して貰えなければ将来的に十分な成長を見込めない可能性もあります。 サービス開発当初は、この9つの要素はあくまでも仮説になります。 そのため、定期的にこのキャンパスを見直し、軌道修正をし続ける必要があります。

なお、リーンキャンバスについては上記9つの項目について検証すべき順番を定めており、その結果によって打ち手は変わります。 このあたりの詳細を知りたい場合は、こちらの書籍を参照してください。

リーンアナリティクスを利用してKPIを設計する

リーンキャンバスの主要指標は、Lean Analytics の手法を利用して決定します。 Lean Analyticsについて一言で説明すると「サービスにおいて最も注力すべき1つの指標をビジネスモデルと現在のステージから導き出すためのフレームワーク」です。 Lean Analyticsは Lean Startupのマネジメント手法に対して、より厳密なデータ駆動の意思決定プロセスを追加します。 Lean Analyticsのフレームワークにおいて、スタートアップは「共感」、「定着」、「拡散」、「収益」、「拡大」の5つのステージで成長する としています。 共感ステージでは、顧客インタビューやソリューションインタビューを繰り返し、解決に値する課題と、ビジネスとして成立しうるソリューションの発見を行います。 定着ステージでは、顧客にとって必要不可欠である、定期的に正しく利用される機能を作ります。 拡散ステージでは、ユーザー獲得や成長にフォーカスします。 収益ステージでは、収益構造について見直して利益の最大化を行います。 拡大ステージでは、市場におけるシェアを拡大するために、競合他社を見て戦略を考えていきます。 それぞれのビジネスモデル・ステージ毎に最も重要視すべきとされている指標は下記のようになります。

Lean Startup/ Analytics では、この最重要視する指標をOMTM(One Metric That Matters) と呼びます。 厳密に言えば違うかも知れませんが、私はこれをKGIとして扱っています。

KGIが決まったならば、それを扱える粒度まで分解していきましょう。 操作や計測が不可能なKPIは使うことができません。 その後、分割したKPIに対して、中期的に追うものの優先度を決めていきます。 KPIの定め方については書籍に説明を譲りますが、 僕としては 顧客に提供する価値をKPIにして、必ず1つ以上組み込むこと を強くお勧めします。

顧客視点を忘れたサービスでも、順調に成長しているときは問題が顕在化しません。 しかし、サービスの成長が鈍化してきたり苦しい局面になると、 そのようなサービスでは多くのチームメンバーのモチベーションが低下し離職につながります。

情熱を持ってサービスのビジョンを語れるプロダクトマネージャーは数多くいます。 しかし、本当に大切なのはそれを実際の施策にまで落とし込んで形にしていくことです。 そういった意味でも、顧客に提供する価値をKPIに置いて、チーム全体で追っていきましょう。

仮説立案

もうひとつ大きな問題は、意思決定のプロセスです。通常、おもしろいアイデアが出てきたら、それをある段階で役員レベルで評価します。筆者も何度かそういう状況を見てきました。そこで何が起こるかというと、既存事業はともかく、新規事業を評価する目のない人たちにより、適切でない評価が下されることが多くなります。たとえ評価が適切であったとしても、既存の市場がなかったとしたらリスクの高いアイデアということになりますから、そのリスクを取る主体が必要になります。すると、必ず反対者が出ます。そして、残念ながら、アイデアは実行に移されないことになります。なぜならば、役員の合議制では誰も、「リスクのあるアイデアを採用した結果に対する責任」を取りたくないからです。 エンジニアのためのデザイン思考入門 1.3.2 章より引用

この本にはこんなこと書いてますが、役員に限らず新規事業を評価する目を持っている人なんてほとんどいないというのが僕の持論です。 低リスクな施策を行い続けじりじりとサービスの状況が悪くなり、首が回らなくなったら一発逆転を狙ってハイリスクな施策に全力投球してしまう。 そんなリスクの取り方をしている企業、サービスは外から見たら分かりやすいかも知れませんが、内部からでは中々気づかないこともあるでしょう。

普通の人がリスクを取るには、根拠の裏付けができるものやプロセスというものが必要になります。Design Sprintは、そのための様々なプロセスを提供してくれます。

Design Sprint は Google Venturesにて考案された開発プロセスです。 Design Sprint が提供してくれるプロセスは大きく2点あります。デザイン思考に基づいたアイデアの作成プロセスと、そのアイデアを実行に移すための合意形成プロセスです。 Google Venturesが考案した開発プロセスだから、さぞかし理知的なんだろうなと思って読んでみると、意外と下記のような文章が多いことに驚きます。

スプリントをやるのはいいが、まる一週間は参加できないと決定者にいわれたら、要所要所で参加してもらおう。月曜日に問題についての考えを話してもらい... (中略)こうしたカメオ出演しかできない場合は、常時参加できる代理人を正式に立てて貰う(中略)あるスプリントでは、CEOがデザインディレクターにこんなメールを送った。「本プロジェクトのすべての意思決定権限を、貴殿に付与します」ばかばかしい?たしかに。効果はある?もちろんだ。 SPRINT 最速仕事術 P61より抜粋

このようにDesign Sprintでは、ある種ばかばかしいけれども実際に組織の中でよく起こる問題に対しても真剣に向き合っており、その上で合意形成が迅速に行われるような方法を提供してくれます。 Design Sprint では、開発に入る前に解決すべき課題をチームの中で明確にし、1週間という限られた期間の中で課題に対して有効と思われるプロトタイプの作成とテストまで行います。 今回の開発プロセスにおいては、解決すべき課題はリーンスタートアップ/ Analyticsによって提示されます。 説明の詳細は書籍に譲るとして、ここでは Design Sprintを行う際の注意点を記載します。

Design Sprintを行う際の注意点は下記3点になります。

  • 事前にサービスのライフサイクルの全体像及び数値を書き出しておく
  • 事前に、一部のメンバーだけでも解決すべき課題について 5 whysをやっておくと、アイデアの有効性を検討する際に役に立つ
  • プロトタイプを提示するときは、使われる際の状態をできる限り定量的に想定しておく

ユーザーヒアリングで顧客から聞いたことを鵜呑みにして施策立案をすることは良い方法ではありません。 顧客からの情報はボトムアップ的な情報として価値はありますが、サービス開発者としてもトップダウンで課題を捉えておく必要があります。 そのために、事前にサービスのライフサイクルの全体像を書き出しておいて 、その上で課題を抽出し 5 whysで分析しておくことをお勧めします。 課題をマッピングしておくことによって、Design Sprintにて提案されたアイデアがどこの課題にアプローチするものなのか整理することができるようになります。 ものによっては、複数の課題を連鎖的に解決してくれるアイデアを適切に拾うこともできるでしょう。 このように適切な事前準備をしておくことによって、すぐれたアイデアを拾える下地を作っておくことが Design Sprintの効果を最大化する上で重要となります。

もう一つ行っておきたい準備としては、機能が使われる上での状況を可能な限り定量的にイメージした上でアイデアを出すことです。 例えばチャットアプリにおいては、メッセージの流量、チャンネルの数によって適切なUIは異なります。 それを想定した上でプロトタイプを作って実験しなければ、間違った評価を得ることになってしまいます。

最後に

この章の冒頭で、初期に我々が救われ、思い違いをさせられた2つのフレーズについて取り上げた。「トイ・ストーリー」後、 「物語が一番偉い」と「プロセスを信じよ」の指針に従えば、集中と前進が約束されたかのように思っていた。 ( 中略 ) 同じように、「プロセスを信じた」が、「トイ・ストーリー2」はプロセスによっても救われなかった。 「プロセスを信じよ」が「何もしなくてもプロセスがまちがいを直してくれる」に変わってしまっていた。そのときに欲しかった安堵は得られたが、同時に、ガードも低くなり、最終的には受け身になってしまった。 もっと悪いことに、いい加減になってしまった。 ( 中略 ) 「プロセスによって自分が作られる部分もあれば、壊される部分もある」(中略) プロセスを「信じる」よりも「促す」ほうがイメージに近いと話してくれた。 プロセスのどがもたついているのかを確認して、尻を叩く。この場合も、プロセス自体ではなく個人が積極的な役割を果たす。 ピクサー流 創造するちから 第一部4章 ピクサーらしさ より抜粋

ここまで開発プロセスについて長々と書いてきました。 ですが、私個人としては、開発プロセスを守ることが最も大切なことだとは思っていません。 その開発プロセスを適用することで、どのような開発チームにしたいのかを考えることが最も重要だと思っています。 なので、目標とする開発チームのイメージが明確になければ、どのような開発プロセスも意味がありません。

Google は SRE、Design Sprint、OKRと、様々な開発プロセスを提案しています。 これらの開発プロセスを見ていて感じることは、人間の強さと弱さに向き合って、強さを最大化し弱さを最小化する仕組みを考えているように感じます。 開発プロセスは、エンジニアとして見れば、Railsのようなフレームワークです。 Railsを使って、どのような価値を人々に届けたいかを決めるのは、開発者自身だと思う次第です。

Azitで学んだことの棚卸し(たぶんずっとWIP)

2019年7月から参加したAzitを、2020年6月30日をもって退職することになりました。

AzitにはSREとして参加しましたが、開発プロセスを設計したり、開発物を考えたり、データを分析してみたり、 振り返ればSRE的な仕事はほとんどしておらず、色んなことに手を出した一年でした。 「サービス開発」という物事に対して、ソフトウェアエンジニアとしてだけではなく、 様々な観点から考える機会を貰えたことに今はとても感謝しています。

んで、今は有給消化期間になりましたので、とりあえず頭の中に溜まってた諸々の学びを外に出していこうと思います。 やってきたことがとても幅広いので、どのように見せるのが適切なのかウンウン唸っていたのですが、 うなり続けても全然見つからないので、一旦思いつく範囲で具体的に書き下してみました。 とりあえずは読みやすさを完全に無視して、やったことや学びとなったことを箇条書きで、粒度も揃えずに書き出します。 そのうちこの記事に書いた内容を追記・修正して再編集していこうと思います。

ここに書いた内容について、詳細を知りたいという奇特な方がいましたら、ブコメとかでコメントください。 そこだけ切り出してブログにまとめられそうなら、やってみようかなと思いますー。

Azitでやったこと一覧

ソフトウェア開発

  • CREWサービスのRailsアプリケーションリファクタリング
  • CREWサービスのインフラを再構築
  • 新規サービスのバックエンド開発
  • SendGrid, Sentry等の各種SaaS導入

開発プロセスの設計

新規サービスの開発

  • リーンアナリティクスにおける共感フェーズ達成のための目標設計など

学びまとめ

開発プロセスについて

  • 開発プロセスで重要なのは目的と思想であり、漠然と手法を守ることではない
  • 理想とする開発組織の状態を考え、その状態にするために使える開発プロセスを採用する
  • 開発プロセスの「守破離」はもちろん大切
  • それ以上に、理想とする開発組織の状態とそこに至るための過程を考えることが重要
  • KPTはチームを目標とする状態に軌道修正するための場であり、目標とするべきチームの状態と、チームの現状を適切に把握する手段がなければ機能しない
  • 開発プロセスの改善においては、チームメンバーで同じ本を読み、共通認識を持つことができると難易度がぐっと下がる

読書会について

  • 開発プロセスの改善にあたって、共通認識となる知識の土台が欲しかったので、めちゃくちゃ読書会をやった
  • 全盛期は週5で毎朝やっていた
  • 「正しいものを正しく作る」「ユーザーストーリーマッピング」「図解リーンスタートアップ」「リーンアナリティクス」「SPRINT 最速仕事術」などをチームで読んだ
  • 結果として、チームの中で普通にリーンスタートアップ/リーンアナリティクスの用語が普及し、開発プロセスの改善に大きく役立った
  • 普通に仕事をしている中で、あるべき開発の姿について、定期的に腰を据えて話し合うことができるチームは少ない
  • 読書会をし、チーム全体で議論をすることによって、あるべき形はどうなのか。我々は何ができてて、何が足りないのかを定期的に考える機会が生まれた
    • これによりKPTの質も上がった
  • 書籍に書かれている情報をもとに各々の経験を持ち寄って話し合うなど、ハンガーフライト的な役割も果たしてくれた

Azitでやったことについて

ソフトウェア開発

基本的にはあんまり目新しいことは出来ていない。箇条書きにするとこんな感じ。

  • AWS上のインフラリソースをterraformやaws-cdkを使って大体コード化した。
    • 基本的にはTerraformを利用する
    • Lambdaに関連するリソースはテストやデプロイの容易さという観点からaws-cdkを利用して管理する
  • Datadog等の監視用SaaSもTerraformで管理して、監視基準の設定を変更するときはPR上で意図を残すようにした
    • 監視設定については、SRE WorkbookとDatadogのmonitoring 101 を参考にした
  • AWSアカウントをAWS Organizationを利用して、staging/production/管理用と3つのアカウントに分割した
  • G Suite + AWS ALBの組み込み認証の導入
  • メール送信を自前のメールサーバーからSendGridに移行した
  • 新規サービスを Rails & React(redux)を利用して構築した

Rails & Reactを利用する上で書いたブログ記事はこちら。

selmertsx.hatenablog.com

もっと沢山書いておけばよかったですね。CDK周りについてはもうだいぶ忘れている。 SendGrid周りについては、まだ知識が新しいのでブログに書こう。

開発プロセスの設計

開発プロセスは、リーンスタートアップアジャイル・デザインスプリントの3つを軸として設計しました。 具体的にはこんな感じ。

リーンスタートアップで解くべき課題を選定する

selmertsx.hatenablog.com

selmertsx.hatenablog.com

selmertsx.hatenablog.com

上記に、リーンスタートアップで機能を開発するときに考えた諸々をブログでまとめています。 ここで私が学んだこととしては、10~15人くらいのチームであれば 目標を一つに絞って職種の垣根なく協力することが、最も良い結果を生むということです。 全員で一つの目標を追うことはコミュニケーションコストも掛かりますし、マネジメントコストもかさむでしょう。 だからと言って安直に職種ごとに目標を設定すれば、結局は局所最適化が発生します。 局所最適化による組織的な負債は、把握が非常に困難です。 見えないボトルネックほど怖いものはないので、ここはマネジメントする人間の踏ん張りどころだと思います。

この他にも具体的に開発物を考えていく上で学びになったことがたくさんあるんですけど、力尽きたので一旦ここまで。

Design Sprintで課題を解決するのに有効な機能を見つけ出す

www.axismag.jp

  • デザイン思考について様々な意見があることは知ってる
  • ただ、デザインスプリントはチーム開発において、再現性高く課題解決が可能な開発プロセスであると思っている
  • デザインスプリントにおいては「権限」を持つ人が参加し、適切に権限を行使することが求められる
  • 「達成する責任はあるけど、決める権限はない」という人間が多く存在する現場は少なくない
  • 現場においては権威がない人間の素晴らしいアイデアよりも、権威がある人間の的を外したアイデアの方が採用されうる
  • 意思決定プロセスを明確にし、不健全な責任と権限のバランスによる機能不全を防ぎ
  • イデアと発案者を明確に分離し、評価することができるという点において、デザインスプリントはよく練られた開発プロセスだと思う
  • デザイン思考に対する批判の中に、答えはユーザーの中にないというものがある
  • それはそのとおりだが、サービスによって成し遂げたい世界観とユーザーの間には「課題」が必ずあるはず
  • その「課題」を見つけ出し、課題に適切な「解決手段」を見つけ出す上でデザインスプリントは効果的
  • また、仕事の9割は卓越したイノベーションにより解決されるのではなく、現場の課題の泥臭い改善であり
  • その改善の速度と精度が競合優位性を作るのだと思う
  • 大抵の失敗は、ユーザーを理解したつもりになっていることによって起きている
  • 課題はサービスを作る人間が頭の中だけで考えるよりも、現場にいって直接目で見ることが大切
  • この点はリーンと非常に親しい開発の思想な気がする。徹底した現場主義
  • このあたりはもうちょっと本を読んで比較・整理してみる

アジャイルで作る開発チームを考える

  • 基本的にはアジャイルで作ることにした
  • アジャイルを推進していくにあたっては、最初に最終的なチームの成長目標を描いた
  • そして目標状態に至るためのフェーズを書き出した
    • Phase 1. アジャイル開発のインストール
    • Phase 2. ユーザーストーリーマップの導入とQCDのハンドリング
    • Phase 3. 仮説検証型の開発への移行
    • Phase 4. リードタイムの短縮
  • Phase3の方がPhase2よりも大切だが、いきなりチーム全体で行うことは難しい
  • 先に限られたメンバーでPhase3をある程度形にする
  • Phase3を少人数で実施できたら、チームメンバー全体でやる
  • 自分たちのフェーズを認識し、そのフェーズの目標を達成できているか振り返る
  • スクラムマスターは、振り返りに必要な定量・定性的情報を常に整理する
  • スクラムマスターはチームの補助輪であることを認識し、自らが積極的にファシリテートしなくても回るチームを作るのが理想

開発チームの目標とする状態

  • 自分たちが作るべきサービスについて、その存在意義、届けるべきユーザー、届けるべき価値について正しく理解している
  • 自分たちが作るものに対して、開発チームが主体となってQCDをコントロールして開発ができている
  • チームの全てのメンバーが、無駄なく目的とするサービスを作れている
  • 自分たちが届けたい価値について、どのような方法で届けるのか精度が高い仮説を出せる
  • 自分たちが作った機能について、事前に建てた仮説が正しかったのか検証することができる
  • 上述した取り組みについて、新しい知識を積極的に取り込み、改善し続けることができる

Phase1の目標状態

  • アジャイルに対する体系的な理解とその実践ができてる状態を目指す
  • プロジェクト管理をする上で必須となるスキルの習得
    • プロダクトオーナーから開発チームに齟齬なく要求を伝えられるようにする
    • 完了の定義を明確にし、届けるべき価値について認識に相違ないようにする
    • タスクを細分化し、それらを相互確認することによって無駄な仕事をしないようにする
    • タスクを見積もり、いつまでにどのような価値を届けるのか、ステークホルダーと合意を取りながら進めることができる

Phase2の目標状態

  • 開発チームが作るべき機能について、その仕様を自分たちで決めることができる
  • そして、開発チーム外のステークホルダーと協力して開発できる状態を目指す
  • 取り込むべき知識は下記2点

Phase3の目標状態

  • アジャイルリーンスタートアップを結合し、効果的に運用できている状態を目指す
  • リーンアナリティクスにおけるOMTMや、課題・仮説キャンパスを設定し、そこから開発物を考案できる状態にする

Phase 4の目標状態

  • DevOps的な概念を導入して、諸々自動化し、リードタイムが短縮される状態を目指す
  • まだ解像度は高くないが、チームとして目標とする状態の順番を示すための書いた
  • もちろん開発効率の向上はどのフェーズでやっても良いが、全体をみる人はこの優先度で頭を使った方が良いと思っている

最後に

他にも色々ありましたが、一旦疲れたのでここまで。 また記事を書いていくなかで、追記していこうと思います。

react-railsを利用したRailsアプリケーションにてCSRFの対策を行う

はじめに

最近久しぶりに Rails で Web アプリケーションを開発しました。その中で React でフォームを作ることになったため、CSRF に関する対策について調べました。そのとき調べた内容を記載します。

なお、React の利用は SPA などではなく、react-rails を利用してページごとに React Component を読み込ませています。

CSRF について

CSRF (Cross Site Request Forgeries) とは、悪意のあるユーザーが、任意の Web アプリケーションを利用しているユーザーの認証情報を用いて、任意の Web アプリケーション上の機密情報を盗む、または意図しないコードの実行をしようとする試みのことです。

具体的な攻撃方法について、Rails ガイドに記載されている例を元に説明します。

<img
  src="http://www.webapp.com/project/1/destroy"
  width="0"
  heigth="0"
  border="0"
/>

上記のような img tag が含まれたページをブラウザが表示するとき、ブラウザは http://www.webapp.com/project/1/destroy に対して GET リクエストを実行します。

もし攻撃を受けた側のユーザーが www.webapp.com のサービスを利用しており、 web.webapp.comの認証情報がセッションや Cookies に残っていた場合、その認証情報を利用して GET http://www.webapp.com/project/1/destroyAPI を実行することができます。

JavaScript を利用すれば、POST リクエストも行うことができます。次のように作られたリンクをクリックすると、POST http://www.example.com/account/destroy が実行されてしまいます。

<a
  href="http://www.harmless.com/"
  onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;"
  >To the harmless survey</a
>

Rails における基本的な CSRF 対策について

Rails における CSRF の対策は、基本的には authenticity_token というパラメータを form 毎に埋め込み、POST リクエストの中でその token を検証するというものです。次のような形で、form に authenticity_token というパラメータを埋め込みます。そして、これと同じトークンをセッションにも保存します。

<form action="/login" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="xxxxx==" />>
  <input type="email" name="sessions[email]" id="sessions_email" />
  ...
  <input type="submit" name="commit" value="OK" data-disable-with="OK" />
</form>

token の検証方法について、rails のドキュメントでは下記のように記載されています。

Returns true or false if a request is verified. Checks:

・Is it a GET or HEAD request? GETs should be safe and idempotent
・Does the form_authenticity_token match the given token value from the params?
・Does the X-CSRF-Token header match the form_authenticity_token?

実際の Rails のコードと合わせると、下記のような条件を満たしたとき token の検証は問題ないと判断されます。

  • request が get/ head である
  • CSRF の保護が有効になっており、かつ下記の条件を満たしている
    • request の origin が nil である。もしくは、同一 origin からのリクエストである
    • 下記パラメータのいずれかが、セッション内に格納されている authenticity_token と一致している
      • authenticity_token パラメータ
      • request.x_csrf_token

CSRF の保護は test 環境以外ではデフォルトで有効になっています。そのため、通常の Web アプリケーションの利用においては、GET リクエストでリソースの更新等をしていない限り、別段意識せずとも Rails 側が対応してくれることになります。

action/method毎に トークンの設定をする

ただし、CSP(Content Security Policy) を利用しているサービスにおいては追加で対応が必要となります。下記のような HTML が渡されたとき、後者の /innocuous にリクエストをする form 要素は無視され、前者の /user/change_password の方が優先されると報告されています。これにより、ユーザーのパスワードを変更するなどの攻撃が可能となります。

<form method="post" action="/user/change_password">
  <!-- xss -->
  <form method="post" action="/innocuous">
    <input type="hidden" name="authenticity_token" value="thetoken" />
  </form>
</form>

この問題は、この Pull Request において言及され、対策が取り込まれました。対策内容はaction/method ごとに authenticity_token を作成するというものです。これにより、上述の form hijacking により生成された POST リクエストは無効となります。

今回の対処方法

今回 CSRF 対策をする上で行ったことは下記2点です。

  • config/application.rb にて per_form_csrf_tokensを true とする (参考)
  • React Component の引数に action, method を指定した authenticity_token を渡す

authenticity_tokenの渡し方については下記のようになります。

# app/views/sessions/new.html.erb
<%= react_component("LoginForm", {
  loginUrl: admin_password_reset_url,
  token: form_authenticity_token(form_options: { action: session_path, method: "post" }),
}) %>

最後に

今回 SPAではないReactを利用したRailsアプリケーションで、CSRFの対策を行う方法についてまとめました。 この方法の問題点や、もっと良い実装方法がありましたら、コメント等をもらえると嬉しいです!

アジャイルとリーン・スタートアップを組み合わせた開発プロセス ~第3回 ライフサイクルとOMTM~

前回の記事では「事業計画とのすり合わせ」のステップについて記載しました。

selmertsx.hatenablog.com

今回の記事も、引き続き「事業計画とのすり合わせ」のステップについて説明しています。

TL;DR

  • 顧客のライフサイクルを書き出し、課題の解像度を上げましょう
  • サービスの最重要指標 ( One Metric That Matters ) を定めましょう
  • ( Lean StartupにおけるOMTMとKGIの関連付け等について、まだまだ理解が整理できていないので詳しい人教えて欲しい )

ライフサイクル

改善する前に現在のサービスの見える化をしましょう。 見える化をする上で、Lean Analyticsにはいくつかの方法を提供してくれています。 今回は、よくありそうなECサイトを例に見てみます。

f:id:selmertsx:20200206005604p:plain

上記の図の各ステップごとに、必要な数値をすべて出していきましょう。 まずはユーザー全体でデータを出してみましょう。 その後、もし分析可能なリソースがあれば、ユーザーをセグメントごとに分けて、 セグメントごとに上記のデータを出してみることをおすすめします。 ユーザーセグメントは、インセプションデッキに記載されたペルソナを元に下記のように4つに分割すると良いかと思います。

  1. ターゲットユーザーかつ、LTV > CAC を満たすユーザー
  2. ターゲットユーザーかつ、LTV > CAC を満たさないユーザー
  3. ターゲットユーザーではなく、LTV > CAC を満たすユーザー
  4. ターゲットユーザーではなく、LTV > CAC を満たさないユーザー

インセプションデッキを元にターゲットユーザーを設定するのは、誤った最適化を防ぐためです。 誤った最適化について説明をするために、またフリマアプリを例にします。 フリマアプリにおいて、最も購入してくれるユーザーの中には、おそらく「転売」を目的にしている人もいるでしょう。 もし、ここでターゲットユーザーをインセプションデッキから決めずに、 トラクション最適で進めてしまった場合、「転売」最適のサービスに誘導されるリスクがあります。 その結果、サービスは誤った方向に進んで行ってしまい、貴重な時間を無駄にしてしまいます。 出品者ユーザーのニーズを満たすために、一時的に「転売」ユーザーの力を借りるという選択をすることもあるでしょう。 ただし、 そういった成長は不健全なものであることは認識しておく必要があります。

ライフサイクルを書き出すと、どのセグメントのユーザーが、どこでチャーンしているのかを整理することができます。 これにより、プロダクトの課題を可視化することができるようになるでしょう。 プロダクトづくりは1,2番のセグメントのユーザーに対して注力します。 3番のセグメントのユーザーについては、そのセグメントのユーザーが1,2番のセグメントにいるユーザーに悪い影響を与えない限りにおいて、静観することになるでしょう。 ただし、ターゲットユーザーに悪い影響を与える場合は、排除するという選択肢を取る可能性もあります。

最重要指標 ( OMTM: One Metric That Matters )

スタートアップの成功の鍵は、本当の意味でフォーカスすること、それを持続させるための規律を持つこと。
フォーカスしていないのに成功したとすれば、それは単なる偶然にすぎない。
あてもなくさまよい、膨大な時間をムダにして、苦痛や徒労を経験した末の成功だ。
スタートアップの成功に秘訣があるとすれば、それは「フォーカス」である。
「Lean Analytics 6章 最重要指標の規律」

私はこれまで、プロダクトを成長させるために数多くのKPIを設定する企業を見てきました。 PMFitを達成し、十分に大きくなった企業においては、数多くのKPIを設定することもあるでしょう。 しかしながら、1=>10, 10 => 100 フェーズの企業においては、 多くのKPIを設定することは能力の分散や局所最適化に繋がり、デメリットが大きいと考えています。 例えば下記資料においては、CPAに責任を持つ人と、LTVに責任を持つ人が異なったため、 エロバナーが量産されたという失敗が記載されています。

www.slideshare.net

似たような失敗は枚挙に暇がありません。 例えば、営業は目標達成のために質の悪い顧客を大量に獲得してしまい、CSの対応コストが増加。 そして売上は上がらずにコストだけがかさみ、プロダクトの利益を奪ってしまう。 または、マーケターがCPAを下げるために本来のターゲット層とは全く異なる層に対してアプローチをする広告を出し、 全く異なる層のユーザーがプロダクトに広がり、既存の優良ユーザーがチャーンしてしまう。 KPIを個別に設定した結果、個別のKPI自体は上昇していても全体としては大きな損失を出してしまうという失敗はよくあることです。

このような問題を避けるために、チーム全体で最重要指標 (OMTM) を定めることが重要です。 OMTMは、現在のステージや投資家からの期待で定まります。下記資料のP87にサービスの性質と、ステージに合わせて見るべきOMTMの例が記載されています。

例えば、ECサービスにおいて現在のステージを「定着」とした場合、OMTMは「CV数」と「ロイヤリティ: 90日以内に戻ってくる購入者の割合」の2つのどちらかになります。 もちろん、プロダクトの状況によってはこれらの指標が適切でないケースがあります。 もしも適切な指標が見当たらなければ、自分たちで設計しましょう。 定着フェーズのゴールは、「顧客にとって必要不可欠である、定期的に正しく利用される機能の提供」です。 自分たちで指標を用意する場合、そのゴールを計測することができる指標であるかを注意しましょう。

さて、漠然と「このOMTMを追う」と決まったとしても、具体的なアクションはまだ浮かんで来ないでしょう。 次の記事では、OMTMを関係各所と協力しながらアクションに落とし込む方法について、記載させていただきます。

まとめ

  • 前回の記事において、投資家の期待、現在のフェーズに関する定量的な裏付けをしました
  • 今回の記事において、プロダクトのライフサイクル把握と、OMTMを定めました
  • 次回は現在のライフサイクルとOMTMを元に、アクションに落とし込むための方法について記載していきます。
  • 次回で「事業計画とのすり合わせ」ステップが終了です.... 長かった....

アジャイルとリーン・スタートアップを組み合わせた開発プロセス ~第2回 数値目標の認識合わせ~

先日書いたこちらの文章における、「事業計画とのすり合わせ」のプロセスについてのお話です。

selmertsx.hatenablog.com

一口にスクラムマスターと言っても、事業計画に関わる深さは人によって異なります。 会社の文化や、その他様々な要素によって変わるでしょう。 ただしどんな会社においても、数値目標をたてて、それを開発チームに共有するというステップは踏むはずです。

それら数値目標の作成に関して、あなたがどれくらい関与できるかは分かりません。 あなた自身が作るかも知れないし、ビジネスオーナーが中心となって決定し、あなたは共有されるだけかも知れません。 どのような形で共有されるにせよ、あなたが開発チームについて責任を持つ人のひとりであれば、 それらの数値目標を開発チームに渡す前に、適切に理解・検証し、ときにはステークホルダーと調整する必要があります

この記事では、そのために必要な知識や方法について記載していきます。 なお、この記事は ビジネスオーナーが立てた事業計画を受け取る側の、サービスに最近ジョインしたスクラムマスターの観点から書かれています。

TL; DR

  • Lean Analyticsのフレームワークを用いて、現在のサービスのステージについて認識合わせをしましょう
  • 投資家・経営陣の意思決定の指標とその理由を正しく把握しましょう
  • 現在のステージについてデータを元に裏付けをし、ステークホルダーと合意をとりましょう

ビジネスオーナーと認識をすり合わせるためのステップ

ビジネスオーナーから共有される数値目標を開発チームのものとする前に、下記のステップで認識のすり合わせをしていきます。

  • プロダクトのステージに関するビジネスオーナーの現状認識
  • プロダクト継続可否のチェックポイント
  • 主要KPIの分析

以下、それぞれのステップで行うことについて説明をします。

プロダクトのステージに関するビジネスオーナーの認識

私は事業のデータを見る上で、Lean Analyticsのフレームワークを活用しています。

理由としては、スタートアップの成長ステージに合わせて見るべき指標と、その解釈方法について具体的に示しているフレームワークだからです。 Lean Analyticsのフレームワークにおいて、スタートアップは「共感」、「定着」、「拡散」、「収益」、「拡大」の5つのステージで成長する としています。 それぞれのステージの詳細な説明は書籍に譲りますが、簡単に説明すると下記のようになります。

共感ステージでは、顧客インタビューやソリューションインタビューを繰り返し、解決に値する課題と、ビジネスとして成立しうるソリューションの発見を行います。 定着ステージでは、顧客にとって必要不可欠である、定期的に正しく利用される機能を作ります。 拡散ステージでは、ユーザー獲得や成長にフォーカスします。 収益ステージでは、収益構造について見直して利益の最大化を行います。 拡大ステージでは、市場におけるシェアを拡大するために、競合他社を見て戦略を考えていきます。

このフレームワークに基づいて、自分たちがどこのステージにいるとビジネスオーナーは判断しているのか確認します。 ビジネスオーナーがそのように判断するに至った定量・定性的なデータもあれば合わせて確認します。

プロダクト継続可否のチェックポイント

どのようなプロダクトにおいても、継続可否の判断をするためのチェックポイントというものが存在します。 審査をするのは、スタートアップにおいては投資家であり、企業においては自社の経営陣になります。

このチェックポイントに関して、その時期と観点、基準値とその理由をビジネスオーナーに確認します。 ここが擦り合っていないと、後々の数値目標の温度感について共通認識をつくることが出来ません。 ステークホルダー間でのMTGの議事録や、各種文書があれば確認しておきます。

投資家や経営陣の判断軸において、Lean Analyticsのステージと紐付けられていることはあまりありません。 投資観点では、そのサービスがどれくらいの規模になりうるのかがとても大切です。 TAM (Total Addressable Market)、SAM (Serviceable Available Market)、SOM (Serviceable Obtainable Market) の観点で、数字を作る必要がでてきます。 TAM/SAM/SOM については、下記の記事がとてもわかり易く説明されているので、こちらを参照してください。

medium.com

投資家の観点で、どのような数字が見られるかというと、例えば○○Pay系のサービスにおいては、決済単価も見られる指標の一つになりうると思います。 実際の決済単価のn%を収益とする〇〇Pay系のサービスにおいて、少額決済のみに利用されているのか、それとも高額な決済にも利用されているのかはSOMが大きく変化しうる要素です。 このように投資家の観点と、Lean Analyticsのステージは必ずしも完全に一致しないものの、ある程度リンクさせて考えないと健全でないサービスの成長をしかねません。

主要KPIの分析

これまでのステップで、ビジネスオーナーの現状認識と、投資家(自社の経営陣含む)からの期待値について把握しました。 このステップでは、現状を定量的に捉えることによって、目標とのギャップを正しく認識していきます。

Lean Analyticsではステージごとに分析するべき指標について、いくつか例を出してくれています。 例えば、定着フェーズにおいてはユーザーがサービスに費やした時間やチャーンレートに復帰率など、 拡散フェーズにおいてはバイラル係数などを見ることを推奨しています。

ここではビジネスオーナーの認識が拡散フェーズであるとして、データを確認していきましょう。

データの見方について

最初に、自分たちが認識している前のフェーズについて、本当に完了させることが出来たのか確認していきましょう。 例として、自分たちが定着フェーズを本当に終わらせることができたのかを確認します。 このとき、ユーザーの登録日時でコホート分析することをおすすめします。

ユーザー傾向変化を掴むためのコホート分析その1

例えば、メルカリのようなフリマアプリを例にデータを見ていきます。 例のためにユーザーの継続率を示す表を作りました。 横軸がユーザーの登録月、縦軸が分析対象月を示しています。

201807 201808 201809 201810 201811 201812
201807 1.0 NaN NaN NaN NaN NaN
201808 0.8 1 NaN NaN NaN NaN
201809 0.7 0.7 1 NaN NaN NaN
201810 0.6 0.5 0.6 1 NaN NaN
201811 0.6 0.4 0.4 0.5 1 NaN
201812 0.6 0.4 0.3 0.3 0.5 1

このような形で確認すれば、サービスが良い方向に向かっているのか、それとも悪い方向に向かっているのかを確認することができます。 この表でみると、ユーザーの継続率は徐々に減少していると言えるため、定着フェーズは終了できていないと見ることができます。 ユーザーのnヶ月目継続率を表現しており、そのような数値は大半の方が見ていると思います。 この表はわかりやすいので、次はもう少し複雑なデータを見てみましょう。

ユーザー傾向変化を掴むためのコホート分析その2

こちらも横軸がユーザーの登録月、縦軸が分析対象月を示しているデータです。

201807 201808 201809 201810 201811 201812
201807 1.0 NaN NaN NaN NaN NaN
201808 0.9 1 NaN NaN NaN NaN
201809 0.8 0.9 1 NaN NaN NaN
201810 0.8 0.8 0.9 1 NaN NaN
201811 0.8 0.8 0.8 0.9 1 NaN
201812 0.8 0.8 0.8 0.8 0.9 1

上の表を見ると、半年後チャーンレートが2割になっています。この結果を見ると定着フェーズは終わっているので、次に進みたくなりますね。 その誘惑をぐっとこらえて、次は一人あたりの平均売上という観点でコホート分析をしてみましょう。

201807 201808 201809 201810 201811 201812
201807 25000 NaN NaN NaN NaN NaN
201808 32000 30000 NaN NaN NaN NaN
201809 28000 25000 20000 NaN NaN NaN
201810 29000 23000 19000 15000 NaN NaN
201811 30000 20000 18000 13000 11000 NaN
201812 31000 18000 15000 11000 9000 9000

一人あたりのユーザーがサービスに使ってくれるお金は徐々に下がっていることがわかります。 次は、購入者が販売者から商品を買うまでに必要なやりとりの平均値についても見ていきましょう。

201807 201808 201809 201810 201811 201812
201807 3.1 NaN NaN NaN NaN NaN
201808 28 2.1 NaN NaN NaN NaN
201809 2.1 2.8 6.2 NaN NaN NaN
201810 2.8 2.7 6 7.2 NaN NaN
201811 2.4 2.6 5.8 7.3 8 NaN
201812 2.3 2.4 5 7.6 8.1 9.1

購入者が商品を購入するまでに、販売者とやりとりをする回数が劇的に増加していることが見て取れます。 フリマアプリにおいて、購買者の大多数が何度も値切り交渉を販売者に行い、かつ購入後にも何らかの連絡をして、 いかに品物を安く購入するか考え続ける人であったとします。 そのような購入者が大半を占める場合、販売者は少しくらい安く売れてしまったとしても、 違うフリマアプリに流れてしまうことが考えられます。

四半期もあれば、ユーザーの傾向は十分に変わりえます。 次のフェーズに進むには、今いるユーザーが当初予定していたペルソナと一致するのか、 ビジネスとして成立しうる優良なユーザーなのかを慎重に確認する必要があります。 可能であれば、 ユニットエコノミクス の観点でもデータを見ておくことをおすすめします。

どれだけユーザーが定着していたとしても、そのユーザーがサービスにとって望ましいユーザーでない場合はサービスを次のフェーズに進ませることは正しくありません。 ここを理解せずに次のフェーズに進んでしまっても、お金や時間をムダにするだけでなく、当初のターゲットとしていた優良ユーザーは離れ、優良でないユーザーのみが残ってしまい、元に戻ることができなくなる可能性があります。 (ただし、SNSなどは、ユーザー数がクリティカルマスに到達しなければ適切に価値を提供できません。そのため、定着・拡散フェーズの移行の判断は、より難しくなると思われます。)

データの分析方法について

もしあなたが小さいスタートアップに所属している場合は、データ分析者がいなかったり、いたとしても他の重要な案件にかかりきりで、これらのデータ分析に工数を割くことができない可能性があります。 その場合は、あなた自身がこれらのデータを出すことも検討しましょう。私としては、Pythonで簡単なデータ分析ができるようになることをおすすめします。 Python公式のチュートリアルと、「Python実践データ分析100本ノック」という書籍を一通りやれば、必要最小限のデータは見れるようになっているかと思います。 ちゃんとやれば一月程度で十分学習可能なので、時間を見つけては学習しておきましょう。

私がPythonをおすすめする理由としては、スタートアップにおいては十分にデータがクレンジングされていないし、データが様々な場所に散らばっていることが珍しくないからです。 たとえば、アプリ側のデータはFirebaseを利用してBigQueryに格納されていて、サーバー側のデータはAWSのRDSに格納されており、それらを統合して見る環境が整えられていないなどの状況がありえます。 Pythonであれば、BigQueryとRDSのデータをコード上でジョインしたり、複雑な条件でデータをクレンジングすることも難しくありません。 そのため、SQLについて学習することももちろん必須ですが、Pythonとそのデータ分析用ライブラリであるpandasについても、データ分析者ほどの専門性は不要だとは思いますが、身につけておくと良いでしょう。 ちなみにSQLについて学ぶのであれば、こちらの書籍がおすすめです。 私はSQLを実行してBigQueryとRDSからざっくりと必要なデータを取得し、その後Pythonでクレンジングや加工、グラフ作成などを行っています。

分析の際においては、極端に悪いユーザーのデータだけでなく、極端に良いユーザーのデータも除外することを意識しましょう。 無意識に都合の良いデータだけを見てしまうのは、分析の際によくあります。  ここは強い意思を持って、信頼区間内のデータだけを分析対象としてください。

さて、ここで現在のステージの再確認が終わったら、次は再確認したデータを元に目標値とのギャップを正しく認識します。 そのギャップの大きさを把握できたら、どのようなコスト・リスク・体制で戦っていくのか、ビジネスオーナーと共通認識を作ります。 その具体的なプロセスについて、次の記事に記載します。

まとめ

プロダクトの目標について期日と具体的な数値・理由について把握して、プロダクトの現状について正しい共通認識を作って、それで初めてプロダクトの開発方針を定めることができるようになります。 最初のプロセスで失敗するとあとでリカバリーができないので、このプロセスは慎重、かつ迅速にすすめていきます。