Google Colaboratory で Qiita:Team の全投稿を取得して、可視化したり、人気ランキングを作ってみる

Kaizen Platform で Product Manager / Engineering Group Manager をしている @takus です。

Kaizen Platform では全社の情報共有ツールとして Qiita:Team を利用しています。Qiita:Team は API が公開されていて投稿した記事などを取得することができるため、Google Colaboratory で全記事を取得して投稿の傾向を可視化したり、人気ランキングを作ってみたりしたので、その話を紹介したいと思います。

TL;DR

  • Kaizen Platform は全社員が積極的に情報発信をしながら仕事をしている
    • 積極的な情報発信は良い面が多いが、情報過多になる悪い面もある
  • 情報の流通状況を可視化してみることでよりよい情報共有の仕組みに改善中
    • 計測できないものは改善できない
    • 全ては公開できないけど一部の内容を紹介
  • Google Colaboratory は情報収集と可視化を気軽にするために便利
    • 今なら無料で使えるし、複数人でコラボレーションもしやすくてオススメ

Kaizen Platform と Qiita:Team

オープンさ

オープンさ: 自らの仕事 (プロセス・成果) をオープンに。 情報は閉じ込めてはいけない。 どこにあるかわからない/誰も読んでないドキュメントには価値はない。

Kaizen Platform, Inc. エンジニア行動指針 – Kaizen Platform のモノ作り – Medium にも オープンさ が記されてるように、会社として新しい働き方を作るということに挑戦するにあたって、Kaizen Platform は情報共有・透明性を大事にしながら、 CEO からエンジニア、カスタマーサクセス、バックオフィスのメンバーなど、皆が積極的に情報発信をしながら仕事をしています。

Qiita:Team

f:id:kaizenplatform:20180425231517p:plain

その中でも、以前から情報共有ツールとして利用している Qiita:Team には様々な部署から様々な情報がもたらされ、毎日たくさんの人が情報発信をしています。これは、積極的な情報発信によって部署を超えたコラボレーションや議論が非同期で進められるメリットがある一方で、情報過多になって大切な情報を見落としたりするデメリットもあり、全てがうまくいってるわけではなく、情報の流通状況を可視化してみたりすることでよりよい情報共有の仕組みへの改善を進めています。

その取り組みの一貫として、Google Colaboratory で Qiita:Team の全記事を取得して投稿の傾向を可視化したり、人気ランキングを作ってみたりしたので、その方法について解説していきます。

Google Colaboratory の環境準備

f:id:kaizenplatform:20180426001351p:plain

Google Colaboratory は Google が機械学習の教育や研究用に提供している Full Managed な Jupyter Notebook 環境です。2018/04/25 時点では、リサーチプロジェクトということで無償で利用することができます。

使い始めるのは笑えるくらい簡単で Google Colaboratory にブラウザでアクセスするだけです。コードスニペットなども充実しているので、pip によるライブラリのインストール方法や、Google Drive との連携などを簡単に行えます。ここでは使い方の説明はしませんが、そのあたりが知りたい場合は Google Colaboratory事始め - Qiita などをご覧ください。

記事取得

Qiita API v2 の GET /api/v2/items で記事を取得した上で、1 行 1 投稿の JSON 形式でファイルに保存していきます。

team = 'YOUR_TEAMNAME'
access_token = 'YOUR_ACCESS_TOKEN'

start_date = '2018-01-01'
end_date = '2018-03-31'

import sys
import re
import json

import pandas as pd
import numpy as np

!pip install -q qiita_v2 retry
from qiita_v2.client import QiitaClient
from qiita_v2.exception import QiitaApiException
from retry import retry

c = QiitaClient(team=team, access_token=access_token)

@retry(delay=1, backoff=2, max_delay=8)
def list_items(yyyymm, page=1, per_page=100):
  print('fetching yyyymm:{} page:{}'.format(yyyymm, page), file=sys.stderr)
  r = c.list_items(
    params={
      'page': page,
      'per_page': per_page,
      'query': 'created:{}'.format(yyyymm),
    })
  return r
        
for dt in pd.date_range(start=start_date, end=end_date, freq='MS', tz='Asia/Tokyo'):
  yyyymm = dt.strftime('%Y-%m')
  filename = 'qiita-{}.json'.format(yyyymm)

  with open(filename, 'w', encoding='utf8') as f:
    posts = list_items(yyyymm, page=1)
    m = re.search(r"\?page=(\d+)", posts.link_last)
    if m:
      last_page = int(m.group(1)) + 1
    else:
      last_page = 2
    
    for page in range(1, last_page):
      posts = list_items(yyyymm, page=page)
      for post in posts.to_json():
        t = json.dumps(post, sort_keys=True, ensure_ascii=False) + "\n"
        f.write(t)

記事取得における工夫

全記事を取得するにあたって 2 件ほど問題が起きたので下記のような対応をしています。ページングが 100 ページまでしか遡れない問題は悩みの種でしたが、query で絞り込みを入れることで検索結果を 10,000 件以内に絞り込むことで全取得が可能になります。別のドキュメント管理ツールにデータを移行するような必要がある場合は覚えておくとよいと思います。

  • API アクセスが一定確率でエラーになる
    • 一定間隔でリトライすることで解決
  • Qiita API v2 のページングが 100 ページまでしか遡れない
    • 記事が 10,000 件を超えると途中までしか遡れない
    • query で created:2017-01 など指定して月毎に取得することで解決

記事を Dataframe として読み込み

JSON 形式で保存されているファイルを、Jupyter Notebook 上で扱いやすい Dataframe 形式で読み込みます。

import glob
import pandas as pd
import numpy as np

# Load JSON as dataframe
list = []
for f in glob.glob('*.json'):
  list.append(pd.read_json(f, lines=True))
df = pd.concat(list)

# Drop unused columns
df = df.drop(['group', 'body', 'rendered_body', 'likes_count', 'page_views_count'], axis=1)

# Flatten user & tags
df = df.assign(user = df.apply(lambda x: x['user']['id'], axis=1))
df = df.assign(tags = df.apply(lambda x: ' '.join(map(lambda y: y['name'], x['tags'])), axis=1))

# Sort by created_at
df = df.sort_values(by="created_at")

df.tail()

df.tail() すると Dataframe の一部が確認できます。

f:id:kaizenplatform:20180425231803p:plain

記事の投稿状況を可視化

2016 年以降の月別の記事投稿数を集計して時系列の変化をみてみます。

df_by_month = df\
  .groupby([ df['created_at'].dt.year, df['created_at'].dt.month])\
  .agg({
    'url': {'items_count': np.count_nonzero},
    'user': {'users_count': lambda x:len(x.unique())},
    'reactions_count': {'reactions_count': np.sum},
    'comments_count': {'comments_count': np.sum},
  })
df_by_month.index.names = ['year', 'month']
df_by_month.columns = df_by_month.columns.droplevel(0)
df_by_month = df_by_month.reset_index()

df_by_month\
  .plot(kind='bar', x=['year','month'], y='items_count', color="red", alpha=0.6, figsize=(12,2))

今回は matplotlib で棒グラフを作成してみました。 2016 年は会社の状況があまりよくなかったと聞いていましたが、それを顕著に示すような結果になりました。

f:id:kaizenplatform:20180425231830p:plain

人気記事の月間ランキング作成

最後に記事毎のリアクション数を集計して月間人気記事ランキングを作成して、Qiita:Team にそのまま貼れる Markdown 形式で出力してみます。

yyyy = 2018 
mm = 1

monthly_ranking = df.where(
    (df['created_at'].dt.year == yyyy) & (df['created_at'].dt.month == mm)
  )\
  .sort_values(by=['reactions_count'], ascending=False)\
  .head(20)\
  .reset_index()

print("### {} 年 {} 月".format(yyyy, mm))
print("| Rank | Reactions | Title | Author |")
print("|:----:|:---------:|:------|:-------|")
for index, row in monthly_ranking.iterrows():
  print("| {} | {} | {} | @{} |".format(index + 1, row['reactions_count'], row['url'], row['user']))
print()

これを Qiita:Team に投稿することで下記のような月間ランキングを簡単に作成することができます。 年初なので CEO/CTO の年頭所感、新入社員の自己紹介などが人気だったみたいですね。

f:id:kaizenplatform:20180425232235p:plain

まとめ

他にも、

  • 曜日・時間帯でヒートマップを作成してどんな時間帯に投稿が多いか?
  • ユーザの部署情報を用意して部署毎の投稿状況や投稿者数に違いがあるか?
  • マネージャーとメンバーで投稿数にどのような違いが出るか?

など、色々と観察してみると見えてくることが多いので Google Colaboratory で簡単に分析をしてみて、継続的にみたいものは BI ツールの Chartio で可視化していきたいなと思っています。

福岡でチームビルディング合宿を開催し、Frontend Teamの開発行動指針をアップデートした

こんにちは、Kaizen Platform で Frontend developer やってます tatsuroro です。
先日、弊社Frontend Teamで初のチームビルディング合宿(以下、合宿)を福岡で開催しましたので、そのレポートをお伝えしたいと思います。

TL;DR

  • 「TECH DEEP SYNC: アプリ設計のベストプラクティス2018年春」と題し、福岡に集合して技術トピックについてディスカッション
  • 普段はリモートで働いているメンバーが一箇所に集まって集中議論することで日頃の開発知見を共有
  • 合宿のアウトプットとして、フロントエンド開発時の各メンバーの行動指針となる「チーム憲章」(後述) をアップデート
  • 福岡のごはんはとても美味しいです

なぜ「Frontend Team」合宿をやるに至ったのか

弊社の Frontend Team はメンバー4人のうち1人は大阪、もう1人は福岡でフルリモート勤務しているのですが、各人がそれぞれ別個のプロジェクトを担当していたりしてなかなか経験を共有する機会がなく、課題感を持っていました。 オンラインで Tech Sync やコードレビュー会を実施したりもしていましたが、皆日々忙しいのでなかなか時間を確保しづらかったり、オンライン開催だと議論の熱が失われがちだったりしていました。

そこで、合宿という形で集まって集中 Tech Sync をやろう、ホワイトボードを前に日頃の気づきや疑問、ベストプラクティスをぶつけあってみよう、どうせやるなら完全に業務を離れて地方開催だ!ということで Frontend Teamの合宿 in Fukuoka を開催する運びとなりました。

f:id:kaizenplatform:20180413145944j:plain 福岡オフィスとしてもお世話になっている The Company 福岡パルコ店にて開催

TECH DEEP SYNC: アプリ設計のベストプラクティス2018年春

朝の10時に集合し、ディスカッションテーマの確認から始めます。

今回は「TECH DEEP SYNC: アプリ設計のベストプラクティス2018年春」というお題のもと、各々気になるトピックを洗い出し、順にディスカッションしていくという形で実施しました。

f:id:kaizenplatform:20180413150034j:plain

SPAのルーティングやURL設計、認証などの構造的な話から GraphQL の活用スタイルまで、日頃溜め込んでいる知見や悩みがどんどんオープンに。
色んな視点・観点が重なり、議論は白熱してゆきます。

f:id:kaizenplatform:20180413150048j:plain

ランチ

ランチは会場近くの一風堂本店へ。

f:id:kaizenplatform:20180413163046j:plain 一風堂 大名本店

f:id:kaizenplatform:20180413163057j:plain ここ大名本店にしかない「元祖白丸・赤丸」は、味に深みがあってとても美味しかったです

f:id:kaizenplatform:20180413163108j:plain 九州人のソウルフード、ブラックモンブランを紹介してくれる laco 氏

午後:アイデア出し & ディスカッション

ランチの後もまだまだ話は尽きず。

「素の CSS 書くのやめて CSS in JS に一本化しません?」という提案に始まり、CustomElements の使いどころ、デザインチームとの協業の話、Google の Cloud Firestore を使って RealtimeDB をコンポーネントにバインドし、クライアントサイドの状態管理を無くすアイデアなど、話題は広がりおおいに盛り上がりました。

まとめ:チーム憲章をアップデート

1日の最後に、フロントエンド開発時の各メンバーの行動指針となる「チーム憲章」をアップデートして、今回の合宿のまとめとしました。

f:id:kaizenplatform:20180413163226j:plain 議論の内容をもとに、サービス設計・開発方針が更新されてゆきます

アップデート後のチーム憲章(一部)がこちら。

技術スタックについて

動作環境

  • 動作環境の保証ラインを設ける
    • プロダクトごとに変わってくるので、ちゃんと定めてメンテする
    • 基準を設けて機械的に判断する (e.g. 5%未満は切る)
      • リアルユーザー内での比率で見る
    • 後から切るほうが大変。マーケットに応じて広げることを検討する。

言語

  • 特別な理由がない限りTypeScriptを採用する

パッケージ管理

  • 特別な理由がない限りnpmを使う

フレームワークライブラリ

  • 基本的に自由

その他のライブラリ選定

  • 基本的に自由

コミュニケーションについて

with バックエンドチーム

  • FE / BE どちらか一方の都合を優先せず、相互に尊重する。スキーマに関するコンセンサスを最初に取る。

with デザインチーム

  • プロジェクト内での責務の分担を決めておく (UX設計 => UI設計 => UI実装)

今回のアップデートに際し、コミュニケーションについての項目が追加されたことはとても意義深かったです。
憲章には一言でまとめていますが、Production チームとしての成果を向上させるために積極的に他のチームと連携を取っていこう、スムーズな開発ができるよう尽力しよう、チームにとって必要であればデザイン作業も(得意不得意はあれど)担当するぞ、という各人の意志がここに結晶したのは大きな成果でした。

閉会〜打ち上げ

丸一日集中してディスカッションするのは大変ではありましたが、ともあれ初のFrontend Team合宿は充実した内容で終えることができました。 閉会後は、福岡の食を堪能しよう!ということで黒毛和牛もつのおいしいお店へ。

f:id:kaizenplatform:20180413163258j:plain 締めのちゃんぽんがこれまた美味かったです

f:id:kaizenplatform:20180413163311j:plain 中洲の屋台街へ。屋台のラーメンもまた乙な味です

おわりに

今回は知見を共有することが目的だったので、まずはやってみよう、発散も飛躍も大歓迎、行きすぎたら都度戻るというスタンスで議論していたのですが、やはり同じ空間で会話するメリットは大きく、終始多様なアイデアやアドバイスが飛び交っていました。 普段リモートで働いていて顔を合わせづらい分、業務を離れて1日でやりきるという意識のもと、集中して実施できたことも良い結果につながったのだと思います。

今後も、チームコミュニケーションの量と質の向上へ向けたイベントを継続し、より良いチーム作りを目指してゆきたいと思います。

Kaizen Platformで行っているOnboardingプロセス

Kaizen PlatformでSRE Group Managerをしている前田 (@glidenote)です。4月ということで転職や部署異動など新しい環境で働いている人が多そうなので、今回はKaizen PlatformのEngineering GroupとSRE Groupが行っているOnboardingプロセスを紹介したいと思います。

TL;DR

  • Kaizen Platformに入社してくれた人に最速でPerformanceを出してもらうためにOnboardingプロセスを策定し、運用、日々改善している
  • 入社してくれた人が自身のOnboarding Planを自分で作成し、CTO、メンターとで定期的に期待値の調整、振り返りを実施し、齟齬が発生しないようにする
  • ランチスケジュールを組み毎日別々の人と、別々の場所にランチに行き、一緒に働く人たちとオフィス周辺の情報を知ってもらう
  • 入社した人に「自分を知ってもらう努力」をしてもらう

背景

Kaizen Platformは創業時(2013年頃)から決まったOnboardingプロセスが特に存在せず、新しく入社した人がパフォーマンスを発揮するようになるまでに時間がかかっていたため、1年前(2017年前半)からEngineering GroupとSRE GroupではOnboardingプロセスを策定し、運用、改善している。

Onboardingとは

オンボーディングとは、組織やサービスに新たに加入した人に手ほどきを行い、慣れさせること。

Onboardingプロセスの流れ

  • 下記は入社前から入社3ヶ月後までのOnboardingプロセスの流れです。
  • 期待値の調整、振り返り、コミュニケーションの機会を増やし、誤解が発生せず、気持ちよく働ける状態に持って行くことが狙いです
  • 下記の共有のもの以外に、メンターの裁量でdailyやbi-weeklyなどの1on1などが設定されています
時期 やること 担当 備考
offer時 期待値の設定&すり合わせ CTO
入社前 メンターの決定 CTO
入社前 メンターとの期待値共有 CTO & メンター
入社前後 各種MTGへの招待 メンター
入社前後 歓迎会の設定 メンター
入社後1週間以内 CTOと1on1の設定 入社した人 会社のことをより知ってもらうため
入社後1週間以内 Product責任者と1on1の設定 入社した人 Productのことをより知ってもらうため
入社後1週間以内 自己紹介の記入 入社した人
入社後2週間以内 Onboarding Plan(3ヶ月)の策定 入社した人 Qiita:Teamに書く & メンターはサポートする
入社後1ヶ月経過後 1ヶ月のOnboarding Report(途中経過) メンター CTOにメールで提出
入社後1ヶ月経過後 CTOとの「1ヶ月面談」の設定 入社した人 1ヶ月の振り返り
入社後2ヶ月経過後 CTOとの「2ヶ月面談」の設定 入社した人 2ヶ月の振り返り
入社後3ヶ月経過後 3ヶ月のOnboarding Report メンター CTOにメールで提出
入社後3ヶ月経過後 CTOとの「3ヶ月面談」の設定 入社した人 3ヶ月の振り返り

入社した人が自身のOnboarding Planを作成する

  • 入社した人は下記フォーマットを利用して、自身のOnboarding Planを書いて、全社員が見える場所(Qiita:Team)に投稿する
  • Onboarding Planは1ヶ月おきに振り返り(Onboarding Report)を実施し、目標に対してどれくらい達成出来ているか、または出来ていないのかを可視化。
  • 目標に対して、どのような登り方をするかなども考えないといけないので思考の訓練にもなります。
## Kaizen Platform で私が目指したいこと

xxxx を実現する。

## 3ヶ月後の目標

1. xxxx できるようにする
2. xxxx できるようにする
3. xxxx できるようにする

目標設定の背景は xxx。

## 3ヶ月後の目標達成に向けての施策

### 1. について

- 具体的に何をやるか

### 2. について

- 具体的に何をやるか

### 3. について

- 具体的に何をやるか


# 振り返り

## Month 1

TBE

## Month 2

TBE

## Month 3

TBE

毎日違う人、違うお店へランチに行く

  • メンターが毎日違う人(以下ランチゲスト)とランチに行くように日程を調整
  • ランチゲストの人は、オススメの店にチョイスする。なるべくお店は被らないようにチョイスして貰う
  • メンターはランチゲストと行ったお店をまとめてQiita:Teamで管理する
  • 追記 休憩時間なので、ランチ同行は強制ではなく任意で行っています

下記は実際のまとめ投稿のスクリーンショットです。

f:id:kaizenplatform:20180409143956p:plain

入社した人に「自分を知ってもらう努力」をしてもらう

  • 入社した人に「自分を知ってもらう努力」を積極的にしてもらう
  • 入社時の自己紹介だけでなく、社内勉強会やMTG、全社合宿などで人前で話す機会を増やし、アピールする場を設ける
  • 「自分を知ってもらう努力」とは、筆者の以前の同僚である宮下剛輔さんのインタビューから拝借している金言です

宮下氏は一貫して、「自分を知ってもらえば、周りから来るようになる」というスタンスを取っている。だからこそ、自分を知ってもらう努力を誰よりも大切にしているのだ。

「テクノロジーの話に限らないんですよ。例えば、僕はドクターペッパー大好きっていい続けてきたんです。そうしたら最近、会う人がドクターペッパーを手土産に持ってきてくれるようになってきた。スピーカーとして話すときも、普通は壇上に水が置いてあるところを、ドクターペッパーが置いてあったり。ほかにも、ゲームではメタルギアソリッドシリーズが大好きで、そのことをいい続けていたら、どこどこに等身大の人形があったよとか、サントラが出てるよ、とか。それが自分のブランディングにもなるし、情報も集まってくる」

「当たり前のようですけど、自分の好きなことや、やっていることを生かせる場を、周りが用意してくれるようになるんです。コミュニティじゃなくても、職場の中でもそうですよね。直接、一緒に仕事をしている人しか、自分のしていることって分からないと思うんです。でも、もっと広くアピールしていくと、職場の中でも自分に最適なポジションが来ると思うんですよ」

全員でサポートし、良いチーム作り、良いプロダクトへ

上記のようなOnboradingプロセスは基本的にメンターが中心になって実施していますが、メンター以外のメンバーもOnboardingに積極的に参加し、より良いチーム作りをし、良いプロダクトを生み出すことを目指しています。

AWS 上で利用している SSL/TLS 証明書を一括管理するツール aws-cert-utils を作った話

はじめまして、Kaizen Platform SRE の @tkuchiki です。

本記事では AWS 上で利用している SSL/TLS 証明書(以下、証明書)を一括管理するツールを作成したので紹介いたします。

TL;DR

  • aws-cert-utils を作成して AWS 上で利用している証明書を一括管理できるようにした
  • 証明書の一覧表示、証明書を利用している ALB / CLB / CloudFront の一覧表示も可能
  • aws-cert-utilsを利用し証明書を管理することで、更新・確認作業においてミスが発生しにくくなった
続きを読む

Rails Developers Meetup 2018 で「正しく失敗しつつ進むプロダクト開発」という話をしてきました

Application Engineer の ryopeko です。 3/24 と 25 に開催された Rails Developers Meetup 2018 で登壇してきました。 自分のセッションは 3/25 14:50~ の回で、「正しく失敗しつつ進むプロダクト開発」というテーマでお話ししました。 当日は2トラックのセッションだったにも関わらずたくさんの方に見に来てもらえました。ありがとうございました。

続きを読む