分散コンピューティングで人工生命を演算する

こんにちは!SpeeeでiOS/Swiftエンジニアをしている id:Mitsuyoshi です。

私は趣味で人工生命をつくっていて、先日開催したSpeeeKaigiでもその発表をしたのでここで紹介します。

tech.speee.jp

f:id:Mitsuyoshi:20170907145713g:plain

人工生命とは

人工生命とは、生命のいち側面をシミュレートすることで、我々の知る生命の理解と、ありえたかもしれない生命の探求を行なう分野です。

アプローチにはさまざまな手法がありますが、以下のような研究が有名です。

コンウェイのライフゲーム
実装の容易さと表現の多彩さで様々な研究が行われています。
ライフゲーム - Wikipedia

阪大 四方先生の進化する人工生命
自己複製するRNAを使用した化学的手法の人工生命です。
“生命”を人工的につくる - RNA複製能力の向上と膜たんぱく質の進化に成功

なぜやるか

人工生命を創ろうとしている理由は、自分が影響を与えることができるけれども、完全にコントロールできないものが好きだからです。 私は趣味で、プレイヤーが操作しないタイプの箱庭ゲームや、動植物の飼育、あるいはロボットの制作などを行ってきましたが、それらは全て、「自分がセットアップするけれども、見たことのないふるまいを見せてくれる」という面白さがありました。 生命の進化というのはその最たるもので、環境を変化させ進化を促すことはできるけれども、それがどのような結果をもたらすかはやってみないとわからず、そこに発見と観察の楽しさがあります。

f:id:Mitsuyoshi:20171003193039g:plain

どうやるか

人工生命のアプローチには大きく分けてソフトウェア、ハードウェア、ウェットウェアの3つがあり、そのうち、最も手間のかからないソフトウェアでのアプローチを行なっています。 ただし、ソフトウェアはウェットウェアと比べて計算能力が圧倒的に低いという欠点があるので、今回のはその欠点を補うコードを書きました。

f:id:Mitsuyoshi:20171012150548g:plain

今回の試行

今回はSwarmChemistryという人工化学のモデルをSwiftで実装し、それを分散コンピューティングに載せて実行できるようにしました。

github.com

スクリーンセーバーのダウンロード

参考文献

おわりに

今回はスクリーンセーバーとして実装したのですがこれが思いのほか良く、面白いパターンが生まれた時にはずっと眺めていられます。
また、毎日使うので改良案なども定期的に思いついてモチベーションの維持にもつながりました。
真に"生命"と呼べるようなパターンは出てきていませんが、続けていって少しずつ改良していくつもりです。

Reactでパターンシーケンサを作った話

こんにちは、Speeeエンジニアの二社谷(nishaya)です。

先日開催されたSpeeeKaigi(詳細は以下の記事を参照)にて、Reactで使ったパターンシーケンサの発表を行いました。

tech.speee.jp

今回作ったもの

DEMO
ソースコード

  • ブラウザで動くマルチトラックのステップシーケンサです
  • 音楽の知識がなくても、なんとなく触っているだけでそれっぽい音が出ます
  • サンプラーもついてます

f:id:nishaya:20170904095922p:plain

使ったもの

  • React/Redux
  • FlowType
  • Web Audio API/MediaDevices

発表資料

speakerdeck.com

モチベーションと課題

前回のSpeeeKaigiではReactでシンセサイザーを作ったのですが、自分は楽器を弾けるわけではないので、ブラウザを使って音楽を楽しむところまでは到達できませんでした。
そこで、下記の3点を押さえたモノを作れば、楽器を弾けない自分でも音楽を楽しむことができるのでは?と考え、シーケンサを制作することにしました。

  • 指定したタイミング通りに音を鳴らす
  • 演奏パターンを生成する
  • 合成した音だけでなく、録音した音も鳴らせるようにする

課題1: 指定したタイミング通りに音を鳴らす

一定間隔で発音を制御しようとしたとき、最初に思いつくのが setTimeoutsetInterval を使う方法です。
ループが巡ってくる度に発音タイミングかどうかを調べ、発音タイミングなら OscillatorNode.start() で音を鳴らすことで、指定のタイミングに沿って音を鳴らすことができそうです。

しかし、その方法だと下記の2点の問題がありました

  • ループのインターバル未満のタイミングで発音できない
  • 同時発音数が多くなるとnodeの初期化などの負荷が高くなって発音タイミングがズレる

そこで、setTimeout() を適度なタイミング(今回は16分音符1つ分の1/3に設定)で回し、 向こう一定期間分の発音スケジュールを算出し、OscillatorNode.start() の引数として渡しています。

スケジュールしてから発音までには時間差があるので、その間にnodeの初期化などの処理が完了し、指定された時刻に一斉に音が鳴ります。
これによって、発音数が多くなってもズレることなく発音することができるようになりました。 また、シャッフルによってハネたリズムや、細かく刻んだリズムなど、微妙なタイミングでの発音も可能になりました。

f:id:nishaya:20170904100052p:plain

課題2: 演奏パターンを生成する

音符を置いてメロディを書いていくのは敷居が高いと思ったため、単純な音の羅列を幾重にも変化させてパターンを生成することを試みました。

パターンは fragment と呼ぶモジュールを通ると別のパターンになり、次のfragmentに渡され、それを繰り返して最終的に演奏されるパターンが生成されます。
各fragmentは、以下のようにパターンを変化させるfunctionをラップしていて、Reactのpropsを通じて次のfragmentにパターンを渡していきます。

transform(steps: Steps): Steps {
  const newList = steps.list.map((step) => {
    let note = step.note + this.state.transpose
    if (note > 127) {
      note = 127
    } else if (note < 0) { note = 0 }
    return { ...step, note }
  })
  return { ...steps, list: newList }
}

fragmentsの紹介

デモには下記のようなfragmentを実装しました。

f:id:nishaya:20170904100203p:plain

repeat

指定した回数分パターンを繰り返します。

stairs

指定した音程で階段状の変化を与えます。

transpose

指定した分だけ音を上げたり下げたりします。

scale

指定したスケールに音階を固定します。
適当に生成したパターン同士でもスケールを合わせるとなんとなく調和する(ように自分には聞こえる)ので気に入っています。

stretch

指定した倍率にパターンを引き延ばします。
これによって16分音符のn倍以外での発音が発生しますが、前述のタイミング制御により、そういった微妙なタイミングでの発音も問題なく吸収できています。

limit

上下に音階の制限を設けます。 制限を超えた音は制限値に丸められます。

課題3: 録音した音を鳴らせるようにする

スネアやシンバル、ストリングスといった音色は基本波形から合成するのが難しいため、サンプリングされた音源を使えるようにしました。

圧縮された音源ファイルは AudioContext.decodeAudioData() を用いてデコードすることで AudioBuffer が得られるのでこれを AudioBufferSourceNode にセットして再生します。

録音の実装

用意されたサンプリング音源を鳴らせるだけでは面白くないので、録音した音声データも使えるようにしました。

デバイスに内蔵(or接続)されたマイクにアクセスするには MediaDevices.getUserMedia() を用います。
このメソッドを呼び出すとブラウザではデバイスの使用許可を求めるダイアログが表示され、ユーザが許可をすると MediaStream が得られます。

navigator.mediaDevices.getUserMedia({ audio: true, video: false })
  .then((stream: MediaStream) => // do something. )

f:id:nishaya:20170904100239p:plain

今回はこのstreamを MediaRecorder でキャプチャし、得られたblobを AudioContext.decodeAudioData() でAudioBufferにデコードしてから、音源としてアサインできるようにしています。

サンプルの編集機能

  • 録音したままだと前後に余分な音が入るのでカットしたい
  • 長く伸ばして発音させるためにループさせたい
  • 録音したそのままの音でなく、高く/低く再生できるよう調整したい

録音機能を実装したところ、上記のような不満を感じたので、さらにサンプルの編集機能を実装しました。

f:id:nishaya:20170904100425p:plain

UIによって編集されたサンプルデータは、以下の形式で管理されています(Flowtypeのアノテーション)。
録音された音声データそのもの(AudioBuffer)と再生に必要な情報(ループ区間や音程などのメタデータ)をまとめてあるので、これをシンセサイザーのプリセットやドラムの音に割り当てることで、どこで使う場合にも編集したとおりに鳴らせるようにしています。

export type Sample = {
  buffer: AudioBuffer,
  id: string,
  name: string,
  offset: number,
  loop: boolean,
  loopStart: number,
  loopEnd: number,
  transpose: number,
}

サンプルデータは、Reduxのstateを通じてサンプルを扱うコンポーネントに同期され、ドラムや楽器のソースとして選択できるようになっています。

所感

  • 今回作ったfragmentのチェインのように、内部データのフローとその可視化を同期させたい場合コンポーネントという概念がしっくりくる
  • パターンや発音情報、サンプリングデータなど、特定の形式のデータを扱う上でFlowtypeが役に立った
  • 通常はブラウザでやらないようなことをブラウザでやってみると、Web Audio APIやMediaDevicesなど、普段の開発で触れることのないAPIを知るきっかけになる。

非エンジニアの私が「Rails Girls Tokyo 8th」に参加してきました!

はじめまして!田中です!
普段はヌリカエというサービスで、主に経理関係を中心としたバックオフィス業務をしております。

そんな非エンジニアの私ですが、この度10/6-10/7にクックパッド社で開催された
Rails Girls Tokyo 8th」に参加させていただきました!
(朝日新聞様が書かれたRails Girlsレポート記事はこちら☆

f:id:shiro03kuma:20171009224555j:plain

※右が私です  

参加したきっかけ

  • エンジニアさんの仕事って凄いなあ
  • 請求システムの開発などでお世話になっているエンジニアさんの仕事をちょっとでも理解したい
  • エンジニアさんがよく開いているPCの黒い画面で何が起こっているのか知りたい
  • エンジニアさんのイベント(SpeeeKaigiなど)が盛り上がっていて楽しそう
    • 弊社では、社内外のエンジニアさんが交流するイベントが活発で、みんなでプレゼンして盛り上がるようなイベントが沢山あります

などの想いがあり、参加を応募しました!
 

Rails Girlsって?

Rails Girls Tokyo, 8th October 2017

より多くの女性がプログラミングを学びやすいように 。
そして何より「プログラミングって楽しい!」を多くの方とシェアすることを目的に作られたイベントだそうです。
現役のエンジニアさんからコーチを受けながら、Ruby on Railsを使ってWebアプリを作成して、実際にWeb上で公開するところまでを、二日間かけて学ばせて頂くイベントでした。  

1日目

 インストール・ ディ

業務時間が終わってすぐ会社を出て、クックパッド社にお邪魔しました!!
ハロウィンの飾り付けがとっても素敵でした♪
 
 f:id:shiro03kuma:20171009224551j:plain

おしゃれ〜〜〜♪

f:id:shiro03kuma:20171009230836j:plain 受付はこちら!

初日は自分のPCにRuby と Ruby on Railsのインストールを行いました。
プログラミングの為に、色々インストールするものがあって、驚きました!(;´▽`A``
ターミナルという黒い画面を引っ張りだして、用意して下さったマニュアル通りに色々インストール。
隣にコーチの方がついて下さって、分からなくなったら直に教えて下さりました~(^◇^)/ 
ありがたや・・・!!

Ruby でWebアプリケーションを作りやすくする為のフレームワークが、Railsだそうです!
 >「インストールしただけでも、大きな仕事を成し遂げた感じがします!」 とメンバーの1人が言ってましたが、ちょっと気持ち分かります。 f:id:shiro03kuma:20171023092630p:plain   ⇑Railsのインストールが終わったらこんな可愛い画面が表示されました! うちのチームは可愛いので皆でスクリーンショットを撮りました♡

f:id:shiro03kuma:20171009224609j:plain チームでぱしゃり!  

当日は8名前後(コーチ含む)の人数でチーム分けをされており、私は「さいばし班」でした。
他にも「おたま班」「しゃもじ班」などお料理にちなんだ班名がありました!

2日目

開会〜♪

オーガナイザーさんから「とにかく楽しみましょう!」というメッセージとともに開会!
スケジュールはこちら!
f:id:shiro03kuma:20171009224604j:plain

手作りな感じで可愛い☆
その後チームで自己紹介をして、早速アプリ作りスタート!

何をつくるの?

公開されている教材を確認しながら、大きく3つのステップを学びました。

  1. 「自分のideaを投稿できる」Railsアプリケーションを作る ⇛教材資料
  2. 書いたコードをGitHubに投稿する ⇛教材資料
  3. Web上に自分のアプリケーションを公開する ⇛教材資料

f:id:shiro03kuma:20171009224552j:plain

教材の内容を一つ一つコーチと確認しながら、進めていきました。

  • 今何をやっているのか?
  • なぜそれが必要なのか?
  • このコードの意味は?  

など、手元のホワイトボードを使って懇切丁寧に教えて頂きました。
 

カタカナや英語の専門用語が沢山出てきて困惑しましたが、
「ギットハブ」、「デプロイ」など社内で一度は聞いたことがある言葉もチラホラ出てきて、エンジニアさんが普段使っている言葉の意味が少し分かりました。
「デプロイ」みたいな言葉を初めて耳にするメンバーも多く、日頃からエンジニアさんと近いところで仕事ができるSpeeeの環境は結構珍しいのかな?という発見もありました。
 

ランチ♪

豪華なお弁当をいただきました!!!!

f:id:shiro03kuma:20171009224601j:plain

GitHubにコードを登録!

GitHubというエンジニアさん達のSNS?があり、私も僭越ながら今回作ったコードを登録しました!
驚いたことは、Web上で展開されている他者が作ったコードは、作者の許可なく使用できるという点です。「著作権とかないんですか?」と思わず質問してしまいました。
 技術を公開しあって、お互い高めあう文化はとても新鮮で素敵だと思いました。
ちなみに、他者の技術について愛あるアドバイスをすることを「マサカリを投げる」というらしいです。
斬新な表現!!!   

ノベルティ♪

会場にはスポンサーの皆様からのノベルティが沢山置かれていました!
みて下さい!!この可愛らしいクッキー♡

f:id:shiro03kuma:20171009224605j:plain

  今回のイベントロゴのシールも!なんて贅沢なノベルティ! f:id:shiro03kuma:20171009224603j:plain

このシールの猫ちゃんは「オクトキャット」といってGitHubのキャラクターなのだそうです。

アフターパーティ

一通りの学びを終えて、懇親会!
いろいろな会社のエンジニアさんや参加者の皆様と交流ができました。

f:id:shiro03kuma:20171009230838j:plain

同日開催のスウェーデンRailsgirlsメンバーに向けての写真を撮りました⇑
 

スポンサーやコーチからのLT

  LTとは「ライトニングトーク」の略で「光の早さで伝えたいことをプレゼンする!(3分くらいで)」という意味らしいです。
アフターパーティやランチの合間に、スポンサーやコーチの方々が「会社の紹介」「Rails Girlsを終えたら、どんなことしていくといいか」などについてLTを披露してくださいました。
特に「エンジニアは女性の働き方にあっている」 という話が印象的でした。
リモートワークを使って、子育てをしながらエンジニアとして活躍されている女性の方もいらっしゃるらしいです。  

今日からあなたもRuby Communityの一員です!

会場にはRubyコミッターの松田さんもいらっしゃっており、松田さんのLTで印象的だったのは「何か特定のコミュニティに所属していなくても、エンジニアでなくても Rubyを使っている人は皆Ruby Communityの一員」というお話でした。
今まで技術とは程遠い世界で生きてきましたが、こうやってアットホームでウェルカムな風土があると初心者にはとてもありがたいな、と思いました。

最後に

今回このイベントに参加したきっかけは、Speeeの社内Slackでmrknさんがイベントのご紹介をして下さって、直感で「ぴぴ!」っときて申し込みさせていただきました!!
日頃はバックオフィス系を担当しており、エンジニアの皆さんが作ったシステムを使わせて頂いたり、要望を出させて頂いている立場です。
どんなシステムを作るか、ディレクターやエンジニアの方と要件を考える場に何度か関わらせて頂きましたが 作る側と依頼する側にはコミュニケーションのむずかしさがあると感じる場合もありました。

依頼側としては「ちょこっと変えるだけだから簡単だろう」という想定で依頼をして
エンジニアさんやディレクターさんに難しい顔をさせてしまった時も。

ちょっとでも理解になればと本も読んだことがありましたが、実際やったことのない仕事を理解するのは難しいと感じていました。 今回のイベントに参加させて頂いて、「めっちゃ細かくて、難しい」ということを体感しましたし、改めてエンジニアさんたちを尊敬いたしました。

f:id:shiro03kuma:20171009224557j:plain
フライデーハグ♪
   

こうやってエンジニアリングを気軽に学べる機会を作って頂いて大変感謝しています。
沢山のスポンサー、運営、コーチのみなさま、素晴らしいイベントを有難うございました!!

f:id:shiro03kuma:20171009230839j:plain  

おまけ

ルビーを題材にした子供向けの本も出ているそうです!

f:id:shiro03kuma:20171009224600j:plain

これからの時代は、子供や女性も気軽にエンジニアリングを学べるようになっていくんだなと実感しました。

CloudFormationの管理を楽にする

娘にぞっこんアラサーエンジニアのpataijiです。

アラサーという言葉を初めて自分に使ったのでドキドキしています。

先日開催されたSpeeeKaigi#3 でCloudFormationのテンプレート管理をなんとかする、「Cloudruler」を紹介しました。

↓ SpeeeKaigi#3 についてはこちら tech.speee.jp

当日のスライド

speakerdeck.com

CloudFormationを使用している方にはそれなりに共感いただけると思うのですが、テンプレートファイルの管理ってかなり大変じゃないですか?

最近では、SAMのおかげで簡単にサーバーレスアプリケーションを作ることが出来るようになりましたが、VPC、EC2、RDS等をCloudFormationで管理する大変さは変わりません。

テンプレートをYAMLで書けるようになり、JSONしか対応していなかった頃と比べるととても良くなったなぁとは思うものの、どうしても冗長な記述が生まれがちですし、何より記述量が多い。

さらに初見殺しなのは、ドキュメントをしっかり読み込まないとRDS一つ用意するのにも苦労する繊細なリソース群。

公式のテンプレートスニペットやWeb上に公開されているテンプレート達を見ては感じるベストプラクティスはどれですか感。

そんな迷えるCloudFormation使い(私)を救うべく、Cloudrulerを作りました。

Cloudrulerが提供する機能はざっくり以下の2つです。

  • Rulerというスニペット機能
  • Pluginによるスニペットの配布と利用

Rulerというスニペット機能

RulerとはChefでいうCookbookのようなものです。

Rulerとしてスニペットを定義しておくとTemplateから簡単に呼び出すことが出来ます。

以下にサンプルを示します。

$ tree
.
├── Gemfile
├── rulers
│   ├── subnet.yml.erb
│   └── vpc.yml.erb
└── templates
    └── sample.rb
rulers/vpc.yml.erb
# vpc: VPC
---
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: <%= @cidr %>
      EnableDnsSupport: true
      EnableDnsHostnames: true
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  RouteTablePublic:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref VPC
  RoutePublic:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref RouteTablePublic
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
rulers/subnet.yml.erb
# subnet: Subnet
---
Resources:
  Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref <%= @vpc %>
      AvailabilityZone: <%= @availability_zone %>
      CidrBlock: <%= @cidr %>
      MapPublicIpOnLaunch: true
templates/sample.rb
description 'This is a sample template.'

vpc = ruler :vpc do
  @cidr = '10.0.0.0/16'
end

ruler :subnet, resource_name_suffix: 'PublicA' do
  @vpc = vpc.resources.vpc
  @availability_zone = 'ap-northeast-1a'
  @cidr = '10.0.1.0/24'
end

ruler :subnet, resource_name_suffix: 'PublicC' do
  @vpc = vpc.resources.vpc
  @availability_zone = 'ap-northeast-1c'
  @cidr = '10.0.2.0/24'
end
実行

上記のようなファイルを用意した後、コマンドを実行するとCloudFormationのテンプレートファイルに展開します。

$ cloudruler dump templates/sample.rb
---
AWSTemplateFormatVersion: '2010-09-09'
Description: This is a sample template.
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: VPC
      InternetGatewayId: InternetGateway
  RouteTablePublic:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: VPC
  RoutePublic:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: RouteTablePublic
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: InternetGateway
  SubnetPublicA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
  SubnetPublicC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: VPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: true

Rulerの良いところは、冗長な記述を排除できるところにあります。

例えば上記の例ですと2つのSubnetを用意していますが、Rulerとして定義してあるので、設定の異なる部分のみをDSLとして記述するだけで事足ります。

また、よく使うリソースの組み合わせをRulerとして定義することで、複雑なAWSのリソース群を構造化出来ます。

上記の例では、VPCとInternetGatewayの設定をRulerとして定義しています。

新たにチームに加わったメンバーは簡単なDSLを記述するだけで標準的なVPCを構築できますし、いざとなればRulerとして構造化されたリソースを紐解くことも可能です。

Rulerを適切に使用することで、DRYにテンプレートを実装可能となり、さらに学習コストを下げることが出来るようになります。

Pluginによるスニペットの配布と利用

ItamaeのRecipeのように、作成したRulerをPluginとして簡単に配布することができます。

社内の他チームに提供することはもちろん、公開されたPluginを再利用することで車輪の再発明を防ぐことが可能になります。

と、自信をもって書くことが出来ればよかったんですが、例によって時間が足りずPluginに関しては現在未実装です。。。

この辺りは私が開発を担当しているプロダクトでドッグフーディングを続けながら、せこせこ改善していこうと思います。

ということで、Cloudrulerの人柱になりIssueを切ってくれる、そんな方に会える日に向け日々是精進。

非エンジニアが社内wikiにヒートマップを実装してみた話

こんにちは、Speeeトレーディングデスク事業の長山(cho3)と申します。 広告運用者として、GoogleAdWordsやFacebook広告をはじめとする運用型広告の運用を行っています。

非エンジニアです。

先日開催したSpeeeKaigiで、社内wikiにヒートマップを導入する話をしました。

※SpeeeKaigiについては下記のエントリをご覧ください。

社内技術プレゼン大会SpeeeKaigi#3 開催レポート - Speee DEVELOPER BLOG

http://tech.speee.jp/entry/2017/09/01/102341

今回はその内容について書かせて頂きます。

そもそもヒートマップって...?

ヒートマップとは...

サイト訪問者の目線の動きやマウスの動き、サイトの熟読時間などの情報ををひと目で理解できるよう可視化したものです。 数値ではなく、サーモグラフィーのような色のグラデーションで表示されます。

引用:ヒートマップとは? ヒートマップツールを最大限活用するための基礎知識 | ユーザ視点をもっと間近に - ポップインサイト公式ブログ https://popinsight.jp/blog/?p=2841

簡単に言うと良くテレビで見かける"サーモグラフィー"のWeb版というイメージです。 クリックした位置が赤く色づけされます。

f:id:numabe:20170904213322p:plain

開発モチベーション

  • 社内wikiでも気軽にヒートマップで分析したい
  • 出来ることなら無料で使いたい

という想いがありました。

実装対象

弊社トレーディングデスクでは、社内のノウハウを蓄積し共有するためのwikiがあります。 WordPressで作っています。

※ほぼモザイクですみません...

f:id:numabe:20170905103209p:plain

弊社社内wikiが抱える問題点

社内wikiは直近アクセスが減ってきてしまっており、 改修を考えているところでした。

f:id:numabe:20170904213544p:plain

wiki内のユーザー行動をヒートマップで分析出来る環境を整え、 改修に向けて歩みだそう、というのが今回の話です。

このように実装しました

  1. Googleタグマネージャーでクリック位置など情報を取得し
  2. Firebaseに蓄積
  3. GoogleAppsScriptでFirebaseに蓄積した情報を呼び出し
  4. heatmap.jsに渡す
  5. GoogleAppsScriptにてHTMLを表示し完成

f:id:numabe:20170904213613p:plain

汎用性を高めるため、基本的にはGoogleのツールを使用し、 ヒートマップ表示部分には、以下"heatmap.js"を使用させて頂きました。

heatmap.js : Dynamic Heatmaps for the Web

https://www.patrick-wied.at/static/heatmapjs/

ちなみに:Firebaseとは

Googleが提供するツールです。

firebase.google.com

今回は

  • Realtime Database
  • Cloud Functions

を使用しました。

Realtime Database >>

クラウドでホスティングされる noSQL データベースを使用して、リアルタイムにデータを保存し、 ユーザーと端末の間で同期します。データの更新は接続された端末間で数ミリ秒で同期され、 アプリがオフラインになるとデータが利用可能になり、 ネットワーク接続にかかわらず優れたサービスを提供できます。

引用:https://firebase.google.com/products/


Cloud Functions >>

専用サーバーの管理や拡張を行うことなく、 カスタムのバックエンド コードでアプリを拡張します。 Functions は、webhook を使用して Firebase 製品、Google Cloud サービス、 サードパーティによって出力されるイベントによってトリガーできます。

引用:https://firebase.google.com/products/

ちなみに:GoogleTagManagerとは

Googleが提供するタグ一括管理ツールです。

www.google.com

何を」「いつ」「どこで」実行するか、詳細に指定出来ます。

通常業務では、広告配信に必要な情報を取得するためのjsを埋め込んだり、GoogleAnalyticsのタグを埋め込んだりするのによく使っています。

実装してみた結果

このようにヒートマップを表示することが出来ました。 今回はTOPページ(奥)と詳細ページ(手前)の2ページでトライしてみました。

f:id:numabe:20170904213644p:plain

結果を見て気づいたコト(TOPページ編)

グロナビのログインボタンが使われていない話

かつて要望が出て実装したログインボタンも、 WordPress純正のログインボタン(左上)の登場によって 使用されなくなってしまっているようです。

f:id:numabe:20170904213728p:plain

右側のアクセスランキングは全く使われていない話

かつて良かれと思って実装した週間アクセスランキング部分は、 全くクリックデータがありませんでした。悲しいですね...

f:id:numabe:20170904213755p:plain

TOPページからは検索しかしない話

結局TOPページのクリックは、右上の検索窓に集中しており、 TOPページに記事の一覧を載せているものの、 検索ニーズが一番高い事がわかりました。

f:id:numabe:20170904213824p:plain

気づいたコト(詳細ページ編)

TOPページに戻るリンクはロゴである話

万国共通のルールがここにもありました。

f:id:numabe:20170904213848p:plain

フォルダパスは3クリックで全選択している人が多い話

フォルダパスを載せている部分は、局所的に赤くなっていました。 3クリックで全選択しているのでしょう。 コピーボタンでも設置しておけば、UX向上になるかもしれません。

f:id:numabe:20170904213859p:plain

引き続き使われないアクセスランキング

悲しいですね...

f:id:numabe:20170904213915p:plain

Slack投稿への執念

弊社では社内コミュニケーションツールとしてSlackを使用しており、 以前こちらのようなエントリを書かせて頂きました。 (こちらも便利なので是非ご覧になって下さい!!)

SlackStatus とGoogleCalendarの同期をしてみた - Speee DEVELOPER BLOG

http://tech.speee.jp/entry/2017/04/24/114000

私がSlack連携やらずに誰がやるんだ」 という謎の執念が湧き上がってしまい、、 ヒートマップをSlackに投稿して本作品の締めとしたいと思います。

SpreadsheetとGoogleDriveへの拡張

以下のように、Spreadsheetにヒートマップを表示させ、 GoogleDriveにpdf化したヒートマップをアップロードし、 SlackにGoogleDriveのリンクを投稿する案で強引に進めます。

f:id:numabe:20170904214119p:plain

Spreadsheetにヒートマップを表示する

GoogleAppsScriptで、Firebaseから取得したクリック数を、 セルに表示させ、半透明のページキャプチャを重ねます。 それだけだと色がつかないため、Spreadsheetのお家芸"条件付き書式"で色を表示させます。

f:id:numabe:20170904214203p:plain

Spreadsheetに表示したヒートマップをpdf化する

GoogleAppsScriptで定期的にpdf化を実行し、 GoogleDriveにアップロードするように設定しておきます。

f:id:numabe:20170904214231p:plain

無事Slackへの連携が完了

無事投稿出来ました。これで安心して眠れます。

f:id:numabe:20170904214252p:plain

結局何が便利だったの...?

色々書いたので、何が便利なのか整理します。

  • GoogleTagManagerを使用していることから、汎用性が高いといえる。
  • 社内wikiにて実装が出来たため、その他社内サービスに横展開が出来る(改善欲はあるものの外部ツール入れる程でもない、というレベルの改善)
  • Slackにクリックが投稿されるため、日々Slackでヒートマップライフが送れる

まとめ

今回非エンジニアとしてエンジニアの社内イベントに参戦しましたが、学びは大きかったです。 自分のアウトプットを、普段とは違うものさしで評価される経験は貴重ですね。 こういった経験を今後も積み重ねていきたいと思います。

ありがとうございました。