asoview! TECH BLOG

アソビュー株式会社のテックブログ

データドリブンSEOへの挑戦

アソビュー Advent Calendar 2019 の8日目の記事です。

遊びのマーケットプレイス「アソビュー!」のSEOを担当している西本です。
本職はインハウスSEO担当ですが、最近はチーム内でデータアナリストとしての需要も増えており、チームで追いかけているKPIをモニタリングするダッシュボードの構築も担当しています。
僕は2019年5月にアソビュー株式会社に入社したのですが、入社してからまず取り組んだSEOダッシュボードについて書きます。

目的・背景

下記3点を目的に、入社してすぐにSEOダッシュボードの構築に着手しました。
・課題の特定
・計測指標の拡大
・モニタリング工数の削減

▼課題の特定

入社したばかりのため、現行サイトのどこにSEO観点での課題があるのか分からず、まずはそれを把握したいと考えました。また、課題の優先度もなるべく定量的に判断したかったため、分析に必要なデータを集めることを始めました。

▼計測指標の拡大

最近SEOは難しくなったと言われることが多く、直近8年SEOに取り組んでいる僕も同様に感じています。様々な要因はあるものの、その1つとして表示速度やユーザ行動等見るべき範囲が多岐に広がっている、という点が挙げられると思います。以前は順位・流入数・CV数の主要3指標を見ていれば概ね事足りていましたが、抑えるべき範囲の広がりに合わせて、見るべき指標も拡大する必要があると考えています。

▼モニタリング工数の削減

見るべき指標は拡大すべきですが、そのモニタリングにリソースが割かれると、本来必要な施策推進のための分析や要件策定にリソースをかけることが出来なくなり、事業成長に貢献出来なくなります。そのため、モニタリング指標を増やし、かつモニタリング工数は抑える必要がありました。

仕組み

前述の目的のために、クラウドとBIツールを活用し、各モニタリング指標が自動で更新されるSEOダッシュボードを構築しました。その仕組みは下記図の通りで、クラウドはGCP、BIツールはRedashを使用しています。 SEOダッシュボードの仕組み

指標定義

どの指標をモニタリングするかについて、詳細は後述しますが、下記SEO評価要因をベースに考えています。 SEO評価要因

上記枠組みに沿って、各評価要因を定量的に分析するには、どのデータソースをどう可視化すれば示唆が得られそうか検討のうえ、データの収集とグラフの作成を進めていきました。尚、モニタリングする指標としては上記枠組みを元にした「SEO評価指標」と、その評価を元に生み出された「SEO結果指標」の2つに分けて計測しています。

SEO評価指標

下記の通り、SEOの各評価要因毎にデータソースを定め、集計→可視化をしています。 SEO評価指標

SEO結果指標

下記は「SEO結果指標」として計測している各指標です。 SEO結果指標

僕が入社する以前から流入数・CV数はモニタリングしていましたが、サイト全体という粒度だったため、機能別に分解して可視化しています。また、Google Search Consoleのデータも加えることで、クエリ毎・ページ毎の傾向も解像度高く把握出来るようになりました。

構築によるメリット

▼モニタリングの進化

モニタリングの進化

元々の目的であった、計測指標を増やしたうえで運用工数を削減する、を実現出来ました。各指標は自動でデータが更新されるため、朝出社した後Redashのダッシュボード1画面を見るだけで、各指標の動きが確認出来るため快適です。

▼問題の早期検知

データは自動で更新されるため、各指標を毎日確認することが可能です。そのため、予期せぬ問題が発生した時も早期に検知、対応することが可能になります。 PageSpeed Insights

上記はPageSpeed Insightsのスコアですが、あるUI改善施策をリリースした後にスコアが大きく低下することがありました。その状況を早期に検知出来たため、すぐに対応を実施し、スコアを元に戻すことが出来ました。

▼データを元に意思決定

SEOの課題や優先順の検討には、経験を元にした定性判断は一定必要ですが、なるべく定量で判断したいと考えています。 流入数の内訳(機能別)

上記は機能別の流入数の内訳推移ですが、僕が入社するまではコンテンツSEOを強化することで順調に流入数を伸ばすことが出来ていました(※上記グラフの薄い青)。
ただ、記事での流入のためCVRが低く、流入が取れてもCV数増加につながり辛いという課題もあります。コンテンツSEOで大きく流入を伸ばすことは出来ているため、これからはCVにつながりやすいプロダクト側のSEOを強化すべく鋭意がんばっています。成果としてはまだまだこれから…ですが。

最後に

アソビューでは一緒に働く仲間を絶賛募集中です。
マーケターの採用もしておりますので、データ×マーケティングを推進すべく一緒に楽しく仕事が出来ればと思います。 www.wantedly.com

個人的には、データエンジニアの方が来ていただけると嬉しいです。
メタデータと分析用クエリの管理が出来る人がおらず困っています。助けてください。
そんなことを思いながらRedashにクエリを量産する今日この頃です。

CloudFormation の StackSets を利用した GuardDuty の有効化

アソビュー Advent Calendar 2019の6日目。

こんにちは。アソビューで SRE チームを担当している秋元です。

アソビューのシステムやサービス運用をする上での取り組みを紹介していきたいと思います。 今回は、CloudFormation の StackSets を利用した GuardDuty の有効化について書きたいと思います。

弊社ではインフラのプロビジョニングツールとして Terraform を使用することが多いですが、GuardDuty の場合、複数の AWS アカウント、リージョンで有効化する必要があり Terraform で作成すると面倒だったので、CloudFormation の StackSets を利用してみました。

GuardDuty

脅威の検出

GuardDuty は、CloudTrail、VPC フローログ、DNS ログなどを解析して悪意のある操作や不正な動作をモニタリングする脅威検出サービスです。

docs.aws.amazon.com

IAM ユーザーのアクセスキーが不正に利用されていないかや、EC2 上で起動しているプログラムが不正な通信を行なっていないかなども検知してくれます。
普段使用しているリージョン、アカウントはもちろんですが、普段使用していないリージョン、アカウントでも有効化することが推奨されています。

通知

脅威が検知されると、CloudWatch イベントが作成されます。
弊社では、検出されたイベントを Datadog に送り、通知するようにしています。

また、GuardDuty では、他のアカウントと関連づけることができます。

docs.aws.amazon.com

弊社では、特定のアカウントをマスターアカウント、その他をメンバーアカウントとし、発生した GuardDuty のイベントをマスターアカウントに集約、Datadog に送信しています。

f:id:akmtr:20191127160446p:plain

CloudFormation StackSets

非常に簡単にセキュリティの脅威を検知できる GuardDuty ですが、有効化を行うにあたりリージョンごとに設定する必要があります。
そのため、例えば Terraform で設定を管理しようとすると、(アカウント数)×(リージョン数)だけ provider を作成する必要があり面倒という問題があります。
そこで弊社では CloudFormation の StackSets という機能を使って設定を行なっています。

CloudFormation StackSets は、一つの CloudFormation のテンプレートを使って、複数の AWS アカウント、リージョンにスタックを作成できる機能です。
スタックの作成は StackSet を作成するアカウントでも別のアカウントでも行えます。 イメージとしてはこんな感じです。

f:id:akmtr:20191127160728p:plain

StackSets でスタックを作成するにあたり、事前に IAM ロールを作成する必要があります。

  • AdministrationRole
    • StackSets を作成するアカウントに作成
    • ExecutionRole に AssumeRole できる必要がある。
  • ExecutionRole
    • スタックを作成するアカウントに作成
    • スタックを作成するのに必要なポリシーが付与されている必要がある。
    • AdministrationRole から AssumeRole されることができる必要がある。

Terraform で記載すると下記のようになります。 (マスターアカウントのアカウント ID=012345678901

  • AdministrationRole
resource "aws_iam_role" "cloudformation_admin_role" {
  name = "StackSetAdministrationRole"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudformation.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}
EOF
}

resource "aws_iam_policy" "cloudformation_admin_policy" {
  name        = "cloudformation_admin_policy"
  description = "cloudformation_admin_policy"
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "1",
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::*:role/StackSetExecutionRole"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "cloudformation_admin_attach" {
  role       = "${aws_iam_role.cloudformation_admin_role.name}"
  policy_arn = "${aws_iam_policy.cloudformation_admin_policy.arn}"
}

resource "aws_iam_role" "cloudformation_execute_role" {
  name = "StackSetExecutionRole"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "012345678901"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "cloudformation_execute_attach" {
  role       = "${aws_iam_role.cloudformation_execute_role.name}"
  policy_arn = "[スタックを作成するのに必要な IAM ポリシーの ARN]"
}
  • ExecutionRole
resource "aws_iam_role" "cloudformation_execute_role" {
  name = "StackSetExecutionRole"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "012345678901"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "cloudformation_execute_attach" {
  role       = "${aws_iam_role.cloudformation_execute_role.name}"
  policy_arn = "[スタックを作成するのに必要な IAM ポリシーの ARN]"
}

少しわかりにくい点としては、マスターアカウントでも ExecutionRole でスタックを作成するので作成する必要があります。

ここで一点注意があります。 StackSets に対応していないリージョンもあるので、その場合は別途 GuardDuty の設定をする必要があります。

StackSets を利用した GuardDuty の有効化

マスターアカウント、メンバーアカウントのテンプレートは下記の通りです。

  • マスターアカウント
AWSTemplateFormatVersion: 2010-09-09
Description: Creates an AWS::GuardDuty::Detector resource and optionally an AWS::GuardDuty::Master resource in a set of accounts and regions.

Resources:
  Detector:
    Type: AWS::GuardDuty::Detector
    Properties:
      Enable: True

  MemberA:
    Type: AWS::GuardDuty::Member
    Properties:
      Status: Invited
      MemberId: 23456789012
      Email: xxxx@hoge.com
      DetectorId: !Ref Detector
      DisableEmailNotification: True

  MemberB:
    Type: AWS::GuardDuty::Member
    Properties:
      Status: Invited
      MemberId: 34567890123
      Email: yyyy@hoge.com
      DetectorId: !Ref Detector
      DisableEmailNotification: True
  • メンバーアカウント
AWSTemplateFormatVersion: 2010-09-09
Description: Creates an AWS::GuardDuty::Detector resource and optionally an AWS::GuardDuty::Master resource in a set of accounts and regions.

Resources:
  Detector:
    Type: AWS::GuardDuty::Detector
    Properties:
      Enable: True

  Master:
    Type: AWS::GuardDuty::Master
    Properties:
      DetectorId: !Ref Detector
      MasterId: "012345678901"

上記では、

  • マスターアカウントのアカウント ID: 012345678901
  • メンバーアカウントのアカウント ID: 23456789012, 34567890123

という構成です。

作成している内容は下記の通りです。

  • マスターアカウント
    • GuardDuty の有効化
    • メンバーアカウントを招待
  • メンバーアカウント
    • GuardDuty の有効化
    • マスターアカウントからの招待を承認

このテンプレートを使用して、全リージョン、全メンバーアカウントを指定してスタックを作成しています。

感想

やってみた感想は下記の通りです。

  • よかった点
    • Terraform で書くよりもすっきり書くことができた。
  • よくなかった点
    • StackSets に対応していないリージョンもあるので、その場合は別途 GuardDuty の設定をする必要があるのが面倒。
    • 実行する部分はマネージメントコンソールから実行するか、何かしらのスクリプトを書く必要がある。
    • Terraform など、CloudFormation 以外のプロビジョニングツールを使っている場合はメンテナンスコストが上がってしまう。

すでに Terraform など別のプロビジョニングツールを使用している場合、メンテナンスコストが上がってしまうのであまり好ましくないかもしれませんが、GuardDuty のアカウント連携の記載方法あたりが個人的にはわかりづらかったので参考になればと思います。

アソビュー!QAチームの紹介

アソビュー Advent Calendar 2019の5日目。

QAチームの青柳です。
今回はアソビュー!QAチームの紹介と今後の展望についてお話できればと思います。

アソビュー!QAチームとは?

QAチームは昨年発足したばかりで、まだまだこれからのチームです。
私が入社したときはメンバーの入れ替わり時期で、しばらく1人のときもあり寂しいな・・・と思うこともありましたが、現在は19新卒含む3名のチームとして、アソビュー!のプロダクト品質を磨きこんでいます。

アソビュー!QAチームでは「Shift Left」を掲げ、QA全体の時間軸を左に移し、後工程での影響度を最小限にする取り組みを行なっています。
f:id:msyn27:20191202114103p:plain (ウォーターフォールっぽく見えてしまいますが、概念を説明するためにこのような図になっています。)
QAチームは全体を俯瞰して見る存在となり、品質をプロセスで作り込み、仕様漏れ、バグを素早く検知することによって手戻りを防ぎ、みんながハッピーな世界を目指しています。

どんな仕事をしているの?

QAが各スクラムチームに所属し、ざっくりですが以下のフローで作業を行なっています。

  1. テスト計画作成
  2. テストケース作成
  3. テスト実施(機能テスト、シナリオテスト、回帰テスト)
  4. リリース判定会議
  5. リリース前テスト
  6. テスト報告書作成

良くある形のフローですが、アソビュー!らしいところでは、シナリオテストを作成するときにステークホルダーを巻き込んで一緒に作成しているところです。
今までは、シナリオテストの粒度=担当QAの知識量だったのですが、顧客に対して一番近いところで仕事をしている仲間たちから意見を吸い上げることで、気付かなかったシナリオに気付くことができるようになり、シナリオテストの精度がぐーんと増しました。
また、サポートとQAが連携して課題を特定するプロセスも確立されつつあるので、今後も連携強化を図り、幅広く活動していきたいと思っています。

見えてきた課題、今後の展望

アソビュー!で1年ほどQAとして活動して様々な課題がありました。

  • 重要機能の改修にQAがアサインされていない(リソース不足)
  • 品質基準がフワっとしているので、過剰なQAが行われている
  • リリースにあたり、QAがボトルネックになっている・・・etc

顧客の求める品質をモデル化した考え方として「狩野モデル」があります。
f:id:msyn27:20191202162601p:plain 詳細はこちらを参照ください。
https://www.juse.or.jp/departmental/point02/08.html
最初のうちは良かったのですが、「当たり前品質」の部分に力を入れすぎてしまい、顧客に新たな価値を届けるのが遅くなってしまうなどの問題点が徐々に露呈してきました。
品質基準をキチンと設けることの必要性、むやみやたらにテストを実施することは誰も幸せにしないことに気付かされたので、今後はテストフローの見直しも含め、自動テストの推進、ベトナムチームとの連携や、重要機能の定義など見えてきた課題を解決しながら、アソビュー!流のQAチームを作っていければと思います。

最後に

私自身、組織の立ち上げは初めてで手探りの部分も多くありますが、まずはやってみよう!という文化が根付いているため、目的・得られるものがハッキリしていればチャレンジさせてもらえる環境です。
つい先日、「チームとして生産性を向上させるため、メンバー同士の相互理解を深める」を目的に終日外部でチームビルディング を実施してきました。
チームビルディングを実施した前と後ではチームの雰囲気が変わり、良いチームとして再スタートを切れたのかな?と思っています。
今後もQAチームに関する情報を発信していきますので、お楽しみに!

アソビュー!では一緒に働く仲間を募集しています。 プロダクト品質を共に磨き込むQAメンバーも絶賛募集中です!カジュアルな面談からもできますので、お気軽にお問い合わせください。 www.wantedly.com

入社して2ヶ月。アソビューに転職した理由。

アソビュー Advent Calendar 20194日目
静電気がすごく、ドアノブに触れるのを毎回ビクビクしている相原です。

はじめに

私は10月にアソビューへ入社しました。
以前はインターネット広告代理店でデザイナー兼コーダー(?)として働いていました。

主にグラフィックデザインやWebサイトのコーディングをしていました。
広告を制作することで、多くの人の目に触れる喜びを感じました。
その後は人の喜ぶモノが作りたいと思い、社内用の業務効率化ツールの開発をしてきました。

転職を考えた理由

組織の問題に対して業務効率化ツールの開発をし、成果がでたり、喜んでもらうのがやりがいでした。
しかし社内用のツールでは限られた人しか使用しない為、だんだん物足りなさを感じ、
広告制作をしていた時のように多くの人に届けられるサービスが作りたくなりました。

そこで、自分は「好きなものづくりを通して1人でも多くの人に喜びや感動を届ける」と転職を決めました。

アソビューを選んだ理由

正直アソビューのことは知りませんでした。

転職するといってもどこがいいのかモヤモヤしていたところ
Wantedlyでアソビューを知り、詳細を見ていくと「なにこれ楽しそう...」

ワクワクを すべての人に

人が幸せに生きていくために必要なことは、「物の充足」と「心の充足」です。
モノに満たされた現代社会の中で、心を満たすことがますます求められています。

特にここに惹かれました。
私には、他の会社では感じなかった「ワクワク」がありました。

ただ便利で人を集めるモノではなく、
人の感情を動かせる、寄り添えるモノって絶対楽しいし、やりがいがあると思いました。
もしお金の為だけに働くなら実際この職業を選んでいないかもしれません。
でも 何をするか、「心の充足」を求めて好きなものづくりができるエンジニアに、アソビューに辿り着いたのかもしれません。

...

選考の面談では「何がやりたいか」についてじっくり話をしました。
会社としての欲しい人材を探すだけではなく、アソビューに入社してその人のプラスになるかも重視してくれました。
面談以外でもメールを通して採用担当の方が疑問や不安点を払拭してくださり、
初めての転職でしたが、不安や懸念点もなく入社がただただ楽しみでした。

良いモノを届けるには、つくる側も楽しめなければいけない と社員1人1人を大切にし、
全員で「ワクワクを、すべての人に。」を目標とするアソビューに私は入社を決めました。

さいごに

みんなとにかく仲がいいです。

ピアボーナス制度を導入していて、社員同士が積極的に「ありがとう」を言い合っています。
隔週で社長の山野さんから全社員に近況などの共有があり、社長と社員の距離も近いです。
新しい制度や仕組みも、まずは取り入れてみる というのも面白いところです。

「ワクワクを、すべての人に。」を届けようと同じ目標を持つメンバーと一緒に働けるのは楽しいです!
アソビューはまだまだ様々な職種でメンバーを募集しています。
Wantedlyをぜひご覧ください!
www.wantedly.com

いまさらすぎるけど Google Spreadsheet はやっぱり便利だった件

asoview! Advent Calendar 2019 の 3 日目の記事です。

サーバサイドエンジニア/開発マネージャのタケウチです。

最近はビジネスチームと連携する役割が増えてきたのですがデータのやりとりが必要なときは Google Spreadsheet を使っています。いつのまにかいろんなことができるようになっていて改めて便利だなーと思ったりします。 いまさらすぎて涙が出そうですが、よく使っている関数や機能(スクリプト除く)を書いていきたいと思います。

Google 翻訳

いつもお世話になっている GOOGLETRANSLATE 関数です。DETECTLANGUAGE 関数で言語識別もできます。

画像表示

IMAGE 関数でセルに画像を表示できます。

IMPORTRANGE 関数

IMPORTRANGE 関数は他のスプレッドシートの特定範囲をインポートします。スプレッドシートを他のチームと共有するとどんどんシートが増えていくのでこれをうまく使うとシートを増やさずに済むかもしれません。ただし、参照位置を文字列で指定するため行・列変更には弱いです。

他にも IMPORTXML, IMPORTHTML, IMPORTFEED, IMPORTDATA というものがあるのでもう大体のフォーマットのデータはスプレッドシートに取り込めそうです。

範囲の結合

={A1:B2;C1:C2} といったように複数の範囲を ; で区切って {} で囲うと範囲を結合できます。いろんなシートにデータが散らばっている場合などに使えます。範囲の代わりに IMPORTRANGE でも同様にできます。

QUERY 関数

QUERY はスプレッドシートの範囲を "Google Visualization API のクエリ言語" という SQL っぽい言語でデータを加工したりフィルタなどできます。 また、 group by や pivot で集計もできるので非常に便利です。

例えば以下の 2 シートがあったとします。

f:id:daicham:20191202203744p:plain
配送先東部シート
f:id:daicham:20191202203925p:plain
配送先中部シート

where でフィルタはこんな感じ。列指定もできます。

f:id:daicham:20191202204030p:plain

group by で集計はこんな感じ。 集合関数 が使えて label で列名を指定できます。

f:id:daicham:20191202204113p:plain

pivot はこんな感じ。列展開されます。

f:id:daicham:20191202204204p:plain

ドキュメントには他にもいろいろ書いてあります。

ARRAYFORMULA

ARRAYFORMULA 関数は配列(範囲)に対応していない関数で配列を使うことができます。

例えば、最高評価が S だったとき Legend と表示したい場合、 E2=ARRAYFORMULA(IF(D2:D13="S", "Legend", "")) と書くとその下の行も自動的に表示されます。

f:id:daicham:20191202204229p:plain

参考文献

既存ReactプロジェクトにTypeScriptを導入した話

アソビュー Advent Calendar 2019の2日目。

フロントエンドエンジニアの指田です。
今回はアソビューの既存ReactプロジェクトにTypeScriptを導入した内容についてお話します。

はじめに

Babelでコンパイルしている既存ReactプロジェクトにTypeScriptを導入した話です。
本記事ではTypeScript等の説明は致しません。

導入

  • 既存のビルド構成は変更しない。(@babel/preset-typescriptを利用。ts-loaderは使用しない)
  • 導入直後はコード変更もしない。
  • 完全にTypeScriptにするまでJavaScriptとTypeScriptは混在する。

インストール

JavaScript Standard Styleを利用しているため、Typescriptのconfigも追加してます。

# TypeScript
yarn add -D typescript 

# Babel
yarn add -D @babel/preset-typescript

# ESLint
yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-standard-with-typescript

設定

最初の設定は悩みました。
設定を厳しくしすぎると、開発が進まなくなるので必要そうな設定のみで導入しました。

TypeScript

初期はallowJs(JavaScriptもトランスパイルに含めるかどうか)は外して導入してます。

{
  "compilerOptions": {
    "skipLibCheck": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "strict": true,
    "noImplicitAny": false,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
  },
}

ESLint

overridesを使用してJavaScriptもTypeScriptも同じ様にlintが効くようにしてます。

{
  "env": {
    "browser": true,
    "jest": true
  },
  "extends": [
    "standard",
    "standard-with-typescript",
    "standard-jsx",
    "plugin:react/recommended",
    "plugin:css-modules/recommended"
  ],
  "plugins": [
    "react-hooks",
    "css-modules"
  ],
  "rules": {
    "react/prop-types": 0,
    "standard/computed-property-even-spacing": "off",
    "react-hooks/rules-of-hooks": "error"
  },
  "parser": "babel-eslint",
  "settings": {
    "react": {
      "version": "detect"
    },
    "node": {
      "tryExtensions": [".ts", ".tsx", ".js"]
    },
  },
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "plugins": [
        "@typescript-eslint",
        "react-hooks",
        "css-modules"
      ],
      "parser": "@typescript-eslint/parser",
      "parserOptions": {
        "sourceType": "module",
        "project": "./tsconfig.json"
      },
      "rules": {
        "@typescript-eslint/explicit-member-accessibility": "off",
        "@typescript-eslint/explicit-function-return-type": "off",
        "@typescript-eslint/promise-function-async": [
          "error",
          {
            "allowedPromiseNames": [],
            "checkArrowFunctions": false,
            "checkFunctionDeclarations": true,
            "checkFunctionExpressions": false,
            "checkMethodDeclarations": false
          }
        ]
      }
    }
  ]
}

prettier

{
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "options": {
        "parser": "typescript"
      }
    }
  ]
}

npm script

JavaScriptも含めたチェックできるtscコマンドも用意しました。

{
  "scripts": {
    "ts-compile-check": "tsc -p tsconfig.json --noEmit",
    "ts-compile-check-in-js": "tsc -p tsconfig.json --noEmit --allowJs",
  },
}

型について

導入直後はanyまたは未指定で進めました。
型を定義していない状態は意味があるのか?とは思いますが、
引数の誤り、不要なPropsがなくなるのでコードがきれいになるメリットがあります。

まとめ

  • 既存コードがある場合、初期の導入範囲はなるべく小さくすることをおすすめします。
  • Babelを使用しているのであれば、@babel/preset-typescriptを利用する方が早めに導入できると思います。
  • ESLint等の設定はoverridesを利用し、混在しても問題ないようにするのがいいと思います。

最後に

アソビューではTypeScriptを導入したプロジェクトはまだ少数なので全てのReactプロジェクトへ導入を検討して行きたいです。

Aurora のカスタムエンドポイントを使ったサービス可用性の改善

こんにちは。アソビューで SRE チームを担当している秋元です。

アソビューのシステムやサービス運用をする上での取り組みを紹介していきたいと思います。
今回は、Aurora のカスタムエンドポイントを使ってサービス可用性を改善している話を書きたいと思います。

アソビューではデータベースに AWS の Aurora を使用しているんですが、Aurora のカスタムエンドポイントという機能を使って一部のサービスレベルの高いアプリケーションが他のアプリケーションの影響を受けないようにしています。

Aurora のカスタムエンドポイントはそれほど新しいネタではありませんが、アソビュー内の取り組みの紹介ということでご容赦いただければと思います。

前提

他のスタートアップのサービスでもよくあるケースかとは思いますが、アソビューのシステムでは複数のアプリケーションから参照されている Aurora クラスターがあり、そこの負荷が高まると参照している全てのアプリケーションのレスポンスに影響が出てしまう、という問題がありました。
またこの Aurora クラスターへは、アプリケーションからのアクセス以外にも、集計、分析用の重い SQL が実行されているなど、様々な用途に使用されていました。
そのため、集計、分析用の SQL やサービスレベルのそれほど高くないアプリケーションによる負荷の増加が、サービスレベルの高いアプリケーションに影響を与えてしまうという状況でした。
本来であれば、少なくともスキーマなどの単位でアプリケーションごとデータが分割されているのがいいかと思いますが、テーブルレベルで共有されているものもあり、データ移行してクラスターを分割、というのも難しい状況でした。

改善の対応

この状況を改善するために、Aurora のカスタムエンドポイントを利用し、ロールごとにアクセスするリードインスタンスを分割しました。
これにより、サービスレベルの高いアプリケーションが他のアプリケーションの影響を受けないようにしたり、データ集計などの重い SQL の実行がアプリケーションに影響を与えないようにすることができました。

Aurora カスタムエンドポイント

具体的にどういった対応をしているかをお話しする前に、Aurora カスタムエンドポイントとはどういったものかをご説明します。

Aurora にはデフォルトで writer と reader のエンドポイントがあり、writer のエンドポイントに接続すると、Aurora クラスターのマスターインスタンスへ、reader のエンドポイントに接続するとリードインスタンスのどれかへアクセスします。
このデフォルトのエンドポイントに加えカスタムエンドポイントを設定することができ、接続するリードインスタンスを柔軟に設定することができます。

接続する先のインスタンスは、ブラックリストかホワイトリストで指定できます。 AWS CLI で作成する場合、ブラックリストは --excluded-members オプションで、ホワイトリストは --static-members オプションで指定できます。

docs.aws.amazon.com

カスタムエンドポイントには

  • READER
  • ANY

の 2 種類があります。
READER のエンドポイントはマスターインスタンスが接続先の対象から除かれますが、ANY の場合は除かれません。

どのように使用しているか?

現在 3 つのカスタムエンドポイントを作成して使用しています。

  • アプリケーション用(サービスレベル高い)
  • アプリケーション用(その他)
  • 集計、分析用

f:id:akmtr:20191105143427j:plain
Aurora カスタムエンドポイントの構成

カスタムエンドポイントの設定

それぞれの設定は下記の通りです。

エンドポイント インスタンスの指定 エンドポイントのタイプ
アプリケーション用(サービスレベル高い) static-members ANY
アプリケーション用(その他) excluded-members READER
集計、分析用 static-members READER

設定の意図は下記の通りです。

  • 「アプリケーション用(その他)」のインスタンスをスケールアウトさせるケースが多いので、インスタンスの指定を excluded-members で行なっています。
  • 「アプリケーション用(サービスレベル高い)」のインスタンスがマスターインスタンスになってもアクセスできるように、エンドポイントのタイプは ANY で指定しています。
  • 「集計、分析用」のアクセスがマスターインスタンスに影響を与えないよう、エンドポイントのタイプは READER に指定しています。

フェールオーバーの設定

Aurora クラスターのインスタンスは、フェールオーバーが発生した際にどれがマスターインスタンスになるかの優先度を設定することができます。
カスタムエンドポイントを利用してロールごとにアクセスするインスタンスを設定している場合、優先度を適切に設定しておかないとマスターインスタンスへの昇格で、本来負荷をあまりかけたくないインスタンスに意図せず負荷がかかってしまいます。

弊社では優先度を下記のように設定しています。

  • 「アプリケーション用(その他)」のインスタンスの優先度を小さく、「アプリケーション用(サービスレベル高い)」のインスタンスの優先度を大きくし、「アプリケーション用(その他)」のインスタンスに基本的にフェールオーバーするように設定しています。 (優先度の設定値が小さい方が優先的にマスターインスタンスに昇格します。)
  • 「アプリケーション用(その他)」のエンドポイントのタイプは READER にし、フェールオーバーが発生してもマスターインスタンスに余計な負荷がかからないようにしています。

まとめ

今回は、Aurora のカスタムエンドポイントの機能を利用して、アクセスするインスタンスを分散させる対応をご紹介しました。

  • Aurora のカスタムエンドポイントの機能を利用することで、アクセスするインスタンスを分散することができます。
  • 複数のアプリケーション間でテーブルレベルでデータが共有されている場合でも、低コストで分散することが可能です。
  • カスタムエンドポイントの設定やインスタンスのフェールオーバーの設定を適切に行わないと、運用を進めるうちに意図しない構成になってしまうので注意が必要です。

こちらは Aurora のシングルマスターのクラスターを想定して記載しています。
書き込みの負荷を分散させたい場合は、 Aurora のマルチマスター、Aurora クラスター間のレプリケーションなど、別途対応を検討する必要がありますので、ご注意ください。