KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

テックブログを公開するまでにやったこと

こんにちは、LINE上で動くおくすり連絡帳 Pocket Musubiというサービスを開発している南光(@stnamco)です。テックブログを公開するにあたり足回りの整備や運用も主に自分がやっています。

この記事では、テックブログを公開するまでにどういう考えで作ってきたか、また公開するまでの過程でどういう取り組みをしてきたかをご紹介します。

なぜやろうと思ったのか

そもそもなぜテックブログ運用の主担当に自分が手を挙げたかということですが、カケハシの実像と対外的に見えているギャップを埋めたいという気持ちがありました。

正直な話、僕は転職活動をするまでカケハシのことを知りませんでした。そのため、選考を受けるまでは開発環境の開発の進め方もレガシーで、これまでの働き方とギャップの大きい会社なのではないかと思っていました。 しかし、選考の過程や実際に働いていく中で、月に一度すべてのエンジニアが集まりLT会を催していたり、技術要素についても前例のない環境には前例のないIT開発を 業界変革に適うカケハシの技術スタックを紹介のようなことを認識していく中で、レガシーな環境という認識は誤っていたなと思いました。

こういったギャップを埋めていくためにもまずは実像を発信していくことが大事だと考え、前職ではテックブログで開発チームの情報を積極的に発信し社外の人にも多く会社の実像を認知してもらえていたので、カケハシでも同様にテックブログで情報を発信していきたいと考えました。

テックブログの仕様検討

前述のような課題感を1on1でCTOの海老原にも共有し*1、テックブログを公開する許可が得られました。

テックブログを作っていくにあたり、まずは運用方針を考えました。 これまでの経験から、View数が多い記事を書くことに注力しすぎると、どんどんハードルが高くなり継続的に発信をしていくのが難しくなるという課題や、発信する技術の母集団によってそもそも興味を持っていただける読者の方の数が全然違うので*2、そういった技術要素に関心を持つ人たちに伝えられる情報を選択できなくなってしまう課題があると考えました。

そのため、カケハシのテックブログではView数を追いかけるのではなく、カケハシをより多面的に伝えていけるように、継続的に発信していくことが重要であると定義しました。 また運用的な目線では、継続的に書いていってもらうためにも、書き手がいかにストレスなく執筆できる環境を整えるかに注力しようと考えました。 そのため、業務の隙間時間に執筆の時間を確保するのは難しいので、業務時間内に時間を確保し執筆していい旨も明文化しています。

そして、そういった取り組みへの社内の理解度を上げていくために、前述のような内容を資料としてまとめて社内に展開し、エンジニアLT会で共有および期待値合わせを行いました。


スクリーンショット 2021-09-14 9 54 09

発信した際には、下記のように協力者も多く出てきてくれました。 組織で新しい取り組みをする際には、声を上げる人とその取り組みに相乗りしてくれる協力者がいることが大事だと考えているので、そういう方が自然に出てきてくれるのはありがたかったです。

スクリーンショット 2021-09-14 8 55 30


ブログの構築

前述の方針も勘案しながら、ブログを実装していくにあたっては以下のような方針で進めました。

  1. 執筆以外の手間を減らすため可能な限り自動化
  2. GitHubアカウントがない人でもレビューできる。

1) 執筆以外の手間を減らすため可能な限り自動化

ブログを投稿するまでには、おおまかに執筆/レビュー/入稿(ブログツールへのアップロード)のステップがあります。

執筆/レビューについては普段使わないツールを使う手間を増やさないために、コンテンツはすべてGitHub上に集約し、レビューもGitHub上で行われるようにしています。

入稿でははてなへ記事をあげる必要があるのですが、いちいち普段開かないはてなブログを開くのは手間なので、GitHub Actionsでblogsyncを利用し、執筆者はGitHub上の操作だけで完結するようにしています。 具体的には、記事の更新はPR作成で実行できるGitHub ActionsのイベントをフックしてAPIを実行し、記事の作成については、GitHub Actionsのworkflow_dispatchで各APIの実行とPRの作成を行っています。 また執筆者がGitHub上の操作だけで良くなったことで、はてなブログの権限管理についても不要な権限を排した仕組みを作ることができました。

スクリーンショット 2021-09-15 9 27 16

2) GitHubアカウントがない人でもレビューできる。

記事は内容によって開発メンバー以外のレビューも必要になりますが、法務や広報などReviewerになる人すべてがGitHubのアカウントを持っているわけではありません。 そのため社内のドキュメント管理ツールであるesaに記事のコピーを作るようにしました。具体的には前述のGitHub Actionsでイベントをフックし、esaについても作成および更新がされるようにしています。

新規投稿時のGithub Actions

name: post article to hatena

on: workflow_dispatch

jobs:
  post-article:
    runs-on: ubuntu-latest
    steps:

    - name: Set up Go 1.13
      uses: actions/setup-go@v2
      with:
        go-version: 1.13
      id: go

    - name: Cache blogsync
      id: blogsync-cache
      uses: actions/cache@v2
      with:
        path: ~/go/bin/
        key: ${{ runner.os }}-go-blogsync-210920
        restore-keys: |
          ${{ runner.os }}-go-blogsync-

    - name: Check out code into the Go module directory
      uses: actions/checkout@v2

    - run: git fetch origin main

    - name: Setup blogsync
      env:
        BSY: ${{ secrets.BSY }}
      run: |
        if !(type ~/go/bin/blogsync > /dev/null 2>&1); then
          go get github.com/x-motemen/blogsync;
        fi
        echo -e ${BSY} > blogsync.yaml

    - name: Post article to hatena
      env:
        DOMAIN: ${{ secrets.DOMAIN }}
      run: |
        ~/go/bin/blogsync post --title=draft --draft ${DOMAIN} < draft.md

    - name: Create PR
      uses: peter-evans/create-pull-request@v3
      with:
        base: main
        branch-suffix: timestamp
        title: Article by ${{ github.actor }}
        body: |
            - [] [社内レビュー](https://github.com/kkhs/techblog#%E8%A8%98%E4%BA%8B%E3%82%92%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%97%E3%81%A6%E3%82%82%E3%82%89%E3%81%86)は通過しましたか?
            - generated by [create-pull-request](https://github.com/kkhs/techblog/actions/workflows/post.yml)

    - name: Cache pip
      id: pip-cache
      uses: actions/cache@v2
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
        restore-keys: |
          ${{ runner.os }}-pip-

    - name: Setup pip
      if: steps.pip-cache.outputs.cache-hit != 'true'
      run: pip install -r requirements.txt

    - name: Post article to esa
      env:
        DOMAIN: ${{ secrets.DOMAIN }}
        ESA_TOKEN: ${{ secrets.ESA_TOKEN }}
        ESA_TEAM_NAME: ${{ secrets.ESA_TEAM_NAME }}
      run: |
        git diff origin/main --name-only \
        | grep entries/${DOMAIN}/entry \
        | xargs -t -n1 python scripts/post_article.py ${ESA_TOKEN} ${ESA_TEAM_NAME}

記事更新時のGithub Actions

name: push article to hatena

on: 
  push:
    branches-ignore:
      - main
    paths:
      - 'entries/**'

jobs:
  push-article:
    runs-on: ubuntu-latest
    steps:

    - name: Set up Go 1.13
      uses: actions/setup-go@v2
      with:
        go-version: 1.13
      id: go

    - name: Cache blogsync
      id: blogsync-cache
      uses: actions/cache@v2
      with:
        path: ~/go/bin/
        key: ${{ runner.os }}-go-blogsync-210920
        restore-keys: |
          ${{ runner.os }}-go-blogsync-

    - name: Check out code into the Go module directory
      uses: actions/checkout@v2

    - run: git fetch origin main

    - name: Setup blogsync
      env:
        BSY: ${{ secrets.BSY }}
      run: |
        if !(type ~/go/bin/blogsync > /dev/null 2>&1); then
          go get github.com/x-motemen/blogsync;
        fi
        echo -e ${BSY} > blogsync.yaml

    - name: Push article to hatena
      env:
        DOMAIN: ${{ secrets.DOMAIN }}
      run: |
        git diff origin/main --name-only \
        | grep entries/${DOMAIN}/entry \
        | xargs -t -n1 ~/go/bin/blogsync push

    - name: Cache pip
      id: pip-cache
      uses: actions/cache@v2
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
        restore-keys: |
          ${{ runner.os }}-pip-

    - name: Setup pip
      if: steps.pip-cache.outputs.cache-hit != 'true'
      run: pip install -r requirements.txt

    - name: Push article to esa
      env:
        DOMAIN: ${{ secrets.DOMAIN }}
        ESA_TOKEN: ${{ secrets.ESA_TOKEN }}
        ESA_TEAM_NAME: ${{ secrets.ESA_TEAM_NAME }}
      run: |
        git diff origin/main --name-only \
        | grep entries/${DOMAIN}/entry \
        | xargs -t -n1 python scripts/push_article.py ${ESA_TOKEN} ${ESA_TEAM_NAME}

テックブログコンテンツの作成

継続的にテックブログを公開していくには、コンテンツ作りの仕組み化も考えていく必要があります。 継続的にコンテンツを作るための型としてローテーションで記事の執筆依頼をすることも考えましたが、義務的に執筆してもらうというより対外的に発信していくこともカルチャーとして作っていきたいという気持ちがあるので選択肢から外しました。

ではどうやっていくかについてですが、月に1度の技術LTに毎回5~6人は発表者が集まっているため、それらを記事化すると週に1回公開できるくらいはコンテンツ作れそうだなと考えました。そのため、LT後の資料はテックブログ化の依頼をするようにしています。 またLTは心理的なハードルがあり苦手な人もいるので、そういった公のアウトプットに至る前の段階からボトムアップ的にコンテンツを拾えるように、Slackのメッセージに対してスタンプを押すことでSlackのテックブログチャンネルに投稿されるように設定*3し面白そうな取り組みがあれば拾えるようにしました。

下記はスタンプ利用の実例です。こちらの投稿をしているのはCEOの中川で、そういったエンジニア以外の人も積極的に技術に関心を持ってくれているというのは尊いことだなと思いました。

スクリーンショット 2021-09-06 15 16 20

終わりに

このように始まったテックブログではありますが、まだまだ理想との乖離がある状態なので今後も理想に向けて継続的に改善を続けていきたいと思っています。 その過程であった発見などはこのテックブログで積極的に発信していけたらなと思っています。 

*1:CTOは1on1用にタイムスロットを確保してくれているので、自由に1on1の設定ができます

*2:他社のテックブログを見ても、特定の技術要素に絞った内容よりオンボーディングなどgeneralな内容の方が伸びがち

*3:Reacji Channeler