blog

紫陽花

プロダクトの改善と意思決定について

プロダクト改善について

意思決定

長期で勝つためには数字に基づいた意思決定が絶対

  • 事業会社において組織の強さとは何か?
    • 強さは回せる仮説の量と質で決まる。
    • 仮説検証のサイクルが早く、精度の高い仮説の改善を積み重ねることができる組織が強い

最善の改善とは最善の意思決定である。

  • 意思決定の量と質は事業理解の深さで決まる。
    • 理解の深さによって打ち手の量が増える
    • 理解の深さによって打ち手の最善の意思決定ができる精度が決まる
    • 理解の深さによって打ち手の意思決定の速さが決まる

だから意思決定する人は事業を最も理解しなければいけない。

意思決定をする上で最低限理解するべきもの

  • 計画/目的/目標値/背景/前提条件/仮説
  • 現在の課題/施策
  • 将来的な課題/施策
  • 過去の課題/施策
  • 全体数字 (KPI/KGI)

意思決定をする上で考える視点

  • プロダクト視点
  • 収益・コスト視点
  • 組織視点

施策

  • 施策の定義

「仮説」「実践」「検証」を行いプロダクトをより良くすること。

  • 施策の基本は、「小さな施策で検証し、結果が出れば大きな施策として実行する。」

PDCAのサイクルに1ヶ月要します」は遅すぎる。 2週間以内で検証できるような粒度で検証を行う。

  • 施策で得られるKPIへの影響を明確にする

無駄を省くためKPIに影響しない施策は基本やらない。 必ず施策から想定される影響を数字に落とし込む「PVが1,000向上する見込み」「ユーザー数が100,000増加する見込み」 etc...

  • 施策実施後は必ず振り返りを行う

施策が良かったか、悪かったか。考察する 今後の仮説の精度を上げるために施策の振り返りはナレッジとして貯めていく。 振り返りから新たな仮説を生み出す

  • 施策を管理する施策シートを作成すると良い

シートはスプレッドシートなどで良い 施策名/内容サマリ/影響KPI/期待値/工数/予定日/実施結果 など一元管理すると良い

  • 施策の中での「最小工数で作る」とは?

最小工数で作るとは、その機能を最小工数で作ることではなく、施策の方向性がよくないのか判断するために、検証に足るクオリティのものを最小工数で作るっていうこと。そうしないと単純にやり方がよくない可能性が高くて検証しにくい。

マイルストーン構築

計画と行動を時系列で落とし込み、最終ゴールから逆算して作る。

  • 最終ゴールをイメージし、現在と比較して必要なものを全て洗い出す。
  • マイルストーンはマクロとミクロで作る
    • マクロは6ヶ月、1年で見たときの粒度で考える 抽象的でも良い
    • ミクロは1ヶ月、3ヶ月の期間で具体的なアクションを明確に明記する
  • アクションには必ず優先順位をつける

    • 優先順位は仮説と、過去の結果を参考に現在の状況を踏まえてつける
    • 優先順位をつけることで最短距離で目標に近づく
  • やることとやらないことを明確にする。

KPI

KPIが達成できるなら手段は選ばない。というスタンスで臨む ただし、KPIが未達で終わっても次に繋がる(将来の成果が約束される)ファクトがつかめればそれで良い

KPIは最終的な目標 (KGI)を達成するための、過程を計測するための中間指標

  • KPI達成とユーザーのベネフィット向上を天秤にかけた場合は必ずユーザーを取る

    • 事業はユーザーによって成り立っている。KPI達成は共有側の目標値であり、需要側には関係ない話。供給側の目標達成のために需要側に課題を生み出してはいけない。
  • KPI達成が難しいからといって簡単に下方修正してはいけない。

    • 変えることを許してしまうと徐々に基準が低くなり成長が遅くなる。事業として失敗する要因になる。
    • ゆでガエル現象
  • チーム全体が事業の数字を因数分解し、理解している状況を作る。

    • 表層的な数字(売上など)で振り回されない
    • 因数分解した先の数字を理解し、課題を見つける
    • 要素の課題は色々な課題の関係から生まれるものもある。
    • 理解することがまず大事。解決策、アクションは二の次で良い

Rubyで小さなツールを作る時のtips

メインファイルの作成

main.rbを用意し処理を1ファイルにまとめます。 実行する同一処理の増加などによってはオブジェクト指向の考え方に則って構造化していきます。 走り出しから構造化を意識してコードを書くのではなく、とりあえず処理を実行できるところまで作ることを意識します。

別ファイルの読み込む

ファイル毎に処理を分けた場合には実行ファイルにファイルを読み込む必要がある 基本的はrequireで読み込む。 同一ディレクトリ階層の場合は、requireでカレントディレクトリを示すドットを打つ

optparseでパラメータ管理

CLIで実行する際にオプションを渡したい時あります。 そんな時は optparse を使うと便利です。 ARGVの機能を簡単に導入できます

require 'optparse'
opt = OptionParser.new
opt.on('-a') { |v| p v }
opt.on('-b') { |v| p v }

opt.parse!(ARGV)

ARGVはコマンドライン引数のこと argument vector (引数の配列)

手軽な構造体

OpenStruct

ruby-progressbarで進捗表示

実行時間が長い処理を行っている時進捗状況が目に見える形でわかると便利ですよね。 ruby-progressbarを使うことで進捗状況を可視化することができます。 利用方法は簡単です。下記を参考に使ってみましょう

インストール

gem install ruby-progressbar

実行処理

require 'ruby-progressbar'
pb = ProgressBar.create
10.times do
    pb.increment
    sleep 0.1
end
pb.finish   

SEO 学習 memo

SEO memo

SEO

「Search Engine Optimization」 検索エンジン最適化

検索結果でWebサイトがより多く露出されるために行う一連の取り組みのことを指す

Googleが掲げる10の事実

  • ユーザーに焦点を絞れば、他のものはみな後からついてくる。
  • 1つのことをとことん極めてうまくやるのが一番。
  • 遅いより速い方がいい。
  • ウェブでも民主主義は機能する。
  • 情報を探したくなるのはパソコンの前にいるときだけではない。
  • 悪事を働かなくてもお金は稼げる。
  • 世の中にはまだまだ情報があふれている。
  • 情報のニーズはすべての国境を越える。
  • スーツがなくても真剣に仕事はできる。
  • 「すばらしい」では足りない

SERP

SERP (Seach Engine Result Page) サープ Googleは1ページ目の情報でユーザーのニーズを全て満たそうと考えている なのでSERPには多様性を持たせようとしている

ゲームタイトルの検索結果では - 公式ページ - wiki - playstore - news - 公式youtube - twitter - 攻略サイト

など網羅的なページが表示される

ユーザーの満足度と数字

ユーザーの満足度を数字を通して見る際に見るべき指標

情報の細分化はユーザーの満足度に影響する

検索ボリューム

キーワードの検索回数 Adwordsで確認することができる 検索ボリュームの大きいキーワードは検索上位をとるのが難しい 単一キーワード、「モンスト」のほうがボリュームが大きい 複合キーワード、「モンスト アニメ 最新話」の方がボリュームが小さい

複合キーワードと単一キーワード

単一キーワード 「モンスト」

複合キーワード 「モンスト アニメ 最新話」

ロングテール

特定の狙ったキーワードだけでなく、関連する様々なキーワードで検索にヒットさせ、幅広く流入を増やすこと

検索順位とセッション

検索順位とセッションは相関性はないがニアイコールではある

コンテンツマーケティング

最終的に勝負を決めるのはコンテンツ

ドメインオーソリティ

mozが定めるサイトの評価スコア

ページオーソリティ

mozが定めるページの評価スコア

  • 被リンク
  • 信頼性
  • キーワード網羅性

パンダアップデート

「低品質なコンテンツが検索結果上位に表示されにくくするため」のGoogle検索アルゴリズムアップデートの総称

ペンギンアップデート

「スパム行為や、ウェブマスター向けガイドラインに著しく違反しているwebページ」の検索順位を下げる

Ginzametrics

検索順位をdayで追うことができる Ginzametrics

namaz

検索順位の変動を確認できる namaz

インフラ 学習 memo

インフラ で学んだことを雑にmemoしていく

サーバー

サーバーとは、「Linux」や「Windows Server」など、サーバー用のOSインストールしたコンピュータ

「サーバーにどのようなミドルウェアをインストールするか」によってサーバーの用途が変わる。

サーバーに複数のミドルウェアをインストールすることも可能。 この場合「Webサーバー 兼 データベースサーバ」となる

ネットワーク

TCP/IP

IPアドレス

32ビットで構成 8ビットずつ10進数に変換したものをピリオドで区切って表現 例:「192.168.100.200」 「0」~ 「255」 「0.0.0.0」から「255.255.255.255」まで IPアドレスは、ネットワーク上で互いに重複しない唯一無二の番号で、いわゆる「住所」に相当 IPアドレスには「パブリックIPアドレス」と「プライベートIPアドレス」がある。

パブリックIPアドレス

IPアドレスは重複が許されないため勝手に設定できない、 インターネットで利用するIPアドレスは「ICANN」という団体が一括管理 インターネットに接続する際に用いるIPアドレスのことを「パブリックIPアドレス」もしくは、 「グローバルIPアドレス」と呼ぶ

プライベートIPアドレス

プライベートIPアドレスは誰にも申請することなく自由に使える

ポート番号

ポート番号の利用で1IPアドレスに対して複数のアプリケーションが通信可能になる 「web」「DNS」「SMTP」にはあらかじめポート番号が決まってたりする。それを「ウェルノウンポート」と呼ぶ

HTTP

webサーバーとwebブラウザでやりとりする通信規約

TCP/IPモデル

OSI参照モデル

ドメイン

DNSサーバー

ドメイン名」と「IPアドレス」を結びつける

ホスト

ホスト「host」とは、コンピュータやルーターなどのネットワーク機器など、 IPアドレスを持つ通信機器の総称

VPC

VPCを「パブリック」と「プライベート」に分けて利用

パブリックサブネット

Webサーバーなどを置く インターネットに接続し、「公開」されている。

プライベートサブネット

DBサーバなどを置く インターネットには直接接続していないため、「非公開」とされている。

NAT

Network Address Translation 内部だけで通用するアドレスを外部とも通信できるアドレスに変換する技術

サブネットマスク

サブネットマスク表記」

表記方法の違い

CIDR

「CIDR表記 (サイダー表記)」

表記方法の違い

ルーティング

ネットワークにデータを流すために必要な設定「ルーティング情報」 「ルーティングテーブル」や「ルートテーブル」と呼ばれる AWSでは「ルートテーブル」

インターネットゲートウェイ

インターネットに接続する間口 EC2からインターネットへ、インターネットからEC2へアクセスできるようにするためにアタッチする必要がある

ネットワーク関連コマンド

AWS

2004年11月からサービス開始

AWSの特徴 - 豊富なサービス - 柔軟なリソース - 従量課金

リージョン

世界中の地域に存在するデータセンター群 「オレゴンリージョン」「東京リージョン」「バージニアリージョン」

アベイラビリティゾーン

リージョンのさらに分割されたデータセンター群 大阪と東京的な

エッジロケーション

東京に2つ、大阪に1つある CDNサービスのcloudFrontやRoute53のDNSサーバなどで用いられている

Amazon VPC

Amazon Virtual Private Cloud」

AWS上に論理的な仮想ネットワークを構築するサービス 元々AWSパブリッククラウドサービス

Amazon EC2

Amazon Elastic Compute Cloud」 「EC2インスタンス」と呼ぶ インスタンスとは、仮想的なサーバーのこと

AMI (Amazon Machine Image)

Amazon Route53

WebベースのDNSサービス 権威DNSサーバー

  • Hosted Zone

Hosted ZoneはDNSレコード (Resource Record) の集合

  • Record Set Record Setは、各DNSレコード

  • Routing Policy Routing Poricyは、Route53がRecord Setに対してどのようにルーティングを行うのかを決定する

レコードタイプ

A (Address Record)

ホスト名とIPV4IPアドレスマッピングを行う ドメイン名とIPアドレスドメイン名:IPアドレス = 1:n

CNAME (Canonical Name Record)

他のDNS名の別名を設定する Aレコードで定義されているドメイン名と別名を定義する。 IPアドレス:ドメイン名 = 1:n を定義する

AレコードとCNAMEレコードの違い

Aレコードはドメイン名とIPアドレスの関係性を定義、CNAMEはそれの別名を定義する

DNSフェイルオーバー

利用の前提としてヘルスチェックを設定する必要がある

Amazon S3 (Simple Storage Service)

シンプルでとても使い易いインターネットストレージサービス

CloudFront

CloudFrontはAWSが提供するCDNサービス CDNサービス (Content Delivery Network) 画像などの性的コンテンツをS3から配信している時に、S3の前段にCloudFrontを挟むことで静的コンテンツをエッジサーバーがキャッシュし、速度を早くすることができる

S3とCloudFrontを連携して用いる

サーバー移設

road_workerのファイルを変更しmasterブランチへマージ circleciが変更を確認しAWSのRoute53の設定を変更 変更が反映されたタイミングでDNSサーバーからのレスポンスに応じて飛び先を変える DNSフェイルオーバーをサーバーの向き先変更には利用しない 重み付けはサーバーで失敗した時のリスクを最小限に抑えたい場合などで利用する レイテンシーは大規模サービスで主に利用する

アプリケーション管理ツール

  • ElasticBeanstalk
  • Opsworks
  • CloudFormation

unicorn-worker-killerを導入

Railsのプロダクトでサーバーのメモリが足りなくなる問題が頻発しました。

構成はnginx + unicorn

unicornのワーカープロセスは、起動後ユーザーからのリクエストを処理し、再起動されることがありません。 長期間の運用を続けるとメモリが徐々に食いつぶされ次第に枯渇していきます。 結果、リクエストが集中していない時間帯でもdatadogのアラートな鳴りまくる事態に陥っていました。

この状況を「unicorn-worker-killer」を導入し、解決しました。

f:id:Yamakichi:20170710225857p:plain

下記ブログを参考にさせていただきました。

Unicorn-worker-killerが便利だった件

unicorn-worker-killerを使うことで、ワーカプロセスが以下の条件の場合に、自動的に再起動してくれます。 - ワーカプロセスが指定回数のリクエストを処理した場合 - ワーカプロセスが指定量のメモリを使用している場合

Gemの導入

gem 'unicorn-worker-killer'

config.ruに設定を記述 [参考]

unless ENV['RAILS_ENV'] == 'development'
  require 'unicorn/worker_killer'
  CHECK_CYCLE = 16
  use Unicorn::WorkerKiller::Oom, (400*(1024**2)), (500*(1024**2)), CHECK_CYCLE
end
  • graceful restartとは?

graceful restart (緩やかな再起動)

グレースフル・リスタート

Apacheのrestartやgraceful、stopなどの違い

AmazonCloudFrontでRailsのAssets周りにある静的ファイルをCDN配信する

AmazonCloudFrontでRailsのAssets周りにある静的ファイルをCDN配信する

RailsでアプリのassetsをCloudFront経由で配信した時の話

問題と解決

Railsのアクションキャッシュ導入時、Webサーバ内からassetsの配信を行っていた。 その場合、Deploy時にassets precompileを実行しmanifestの更新を行うと、 キャッシュしていたviewのCSSがmanifest更新に伴って参照できなくなり、表示が崩れてしまうという問題が発生した。 この問題を解決するために、Deploy時にassets以下のファイルをS3に置いてCloudFront経由で配信する形式に変更することにした。

CDN

CDN (コンテンツデリバリーネットワーク) Akamaiが1990年代に提唱したコンテンツを配信するネットワーク

参考: 第1回 CDN の 仕組み (CDNはどんな技術で何が出来るのか)

Amazon CloudFront

AWSが提供するCDNサービス 今回はCloudFrontを使いました

CloundFront

Amazon S3

SimpleStrageService Sが3つでS3 「超便利ファイル置き場」

今回は静的ファイルをS3に置いてCloudFrontが参照する

S3

CDNを導入すると何が良いの?

パフォーマンスが良くなる。(高速化) 世界中のどこからアクセスされてもある程度一定のレスポンス速度を担保できる。

やること

  • S3バケットを用意
  • CloudFront側の設定
  • Rails側の設定
  • sprocketsのmanifestファイル
  • S3でクロスオリジンの設定

S3バケットを用意

assetsファイルはS3バケットに置くので、バケットを用意します

ドメイン

assets.service-domain.com

CloudFrontの設定

CIでprecompileを行いS3にファイルを置く

DeployフローでCIを通す前提の話です。普段はCircleCIを利用しています

  • 1.テスト実行
  • 2.テスト成功
  • 3.assets precompile を実行
  • 4.compileファイルをs3にupload
  • 5.デプロイ
machine:
  environments:
  timezone:
    Japan
  ruby:
    version: 2.2.3
  services:
    - redis

deployment:
  production:
    branch: master
    commands:
     - ./deploy/circleci/upload_assets.sh
     - ./deploy/circleci/deployment.sh
#!/bin/sh
EXPIRE=`ruby -e "puts (Time.now + (60*60*24*30)).strftime('%Y-%m-%d')"`

bundle exec rake assets:precompile RAILS_ENV=production
mv ./public/assets/.sprockets-manifest-* ./public/assets/.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json
aws s3 sync ./public/assets s3://assets.service-domain.com/assets --region ap-northeast-1 --expires $EXPIRE

shellファイルの先頭に #!/bin/sh (シバン))を記述することはマナー (一応記述がなくても動く)

EXPIREでS3内のファイル有効期限を指定 (今回は30日間にセット)

mv コマンドで生成したmanifestの32文字の乱数部分を同一のものに変更 (今回は決めの値を記述しましたが、32文字であれば何でも大丈夫)

Rails側の設定

Rails側でassetsの配信設定を行います

config/environments/production.rb

config.action_controller.asset_host = ""

デフォルトではコメントアウトになっています、asset_hostに配信のURLを指定します。

config.acrion_controller.asset_host = "https://assets.service-domain.com"

precompile後のファイルはS3に置きますが、manifestファイルはWebサーバーのpublic/assets以下に置かなければうまく参照できず正しく表示されません。 Deployのタスク内でmanifestファイルのみをs3から取ってくる処理を書きます。

execute "aws s3 cp assets manifest" do
  cwd release_path
  command "aws s3 cp s3://assets.service-domain.com/assets/.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json ./public/assets/"
  environment "RAILS_ENV" => rails_env
end

今回はaws s3 cpコマンドで設置方法

sprocketsのmanifestファイル

  1. そもそもmanifestファイルってなんのために存在するの?
  2. manifestファイルではコンパイルされたassetsファイルのルートを指示する
.sprockets-manifest-8jednoecyllbeucnvekdwhbqlkjwhhdq.json

S3でクロスオリジンの設定

RailsでFontawsomeなどを利用している場合、上記の手順でDeployし表示できるが、Fontawsomeのアイコンが豆腐になってしまう問題が発生する。 この問題はクロスオリジンの設定をすることで解決できる。

うまく設定できるまで幾つか地雷を踏みましたがうまく設定できました。

Rails Routing Constraints

Constraintsとは

  • Railsのroutingに存在する機能
  • routingに制限を設けることができる
  • デフォルトで定義されている
  • カスタムで制約を作成することも可能

セグメントの制限

get "books/:id" => "photos#show", constraints: { id: /[A-Z]\d{5} }

上記はconstraintsでidに制約を追加している。 /books/A12345 のようなパスにはマッチするが、 /books/12345にはマッチしない。

リクエストに応じた制限

get "books", constraints: { subdomain: "admin" }

サブドメインadminが含まれていることを制限している。

ブロックでも表現できる。

namespace :admin do
  constraints subdomain: 'admin' do
    resources :photos
  end
end

カスタムconstraints

制約用のクラスを設けて対応する lib/constraint以下にクラスを置く self.matches?メソッド内に制約を定義する 下記ではrequestを引数で取り、その中に、admin が含まれているかどうかを判定する

module Constraint::Subdomain
  class Admin
    def self.matches?(request)
      request.subdomains.include?("admin")
    end
  end
end

ルーティング側には下記のように定義することで制約を加える

Rails.application.routes.draw do
  constraints Constraint::Subdomain::Admin do
    get "dashboard" => "homes#dashboard"
  end
end

dashboardへのリクエストパスのサブドメインにadminが含まれているかを判定する