今だからこそ、行きたいお店をリストアップしようではないか。

こんにちは。
デザイナーのkazuです。
お酒大好きゲーマーです。最近はFortniteばかりやってます。

以前、フリーをやめてフリーに入社した話というブログを書いてから2回目のブログです。 定期的に書いていきたいと思ってるんですが、実務がいそがしくそれどころではないです。がんばります!

さて、コロナの影響で自粛生活が続いていますが遊びにもいけない、ショッピングも映画もいけない、大好きなお店で美味しいご飯やお酒も楽しめない。

そんな生活がつづいてけっこう精神的にきついと思います。
私は飲み会が大好きなので、入社した暁にはfreeeメンバーでいろんなところに飲みに行きたいと思っていたので、いきなり自粛になってしまい途方に暮れています。
そんなときだからこそお店に行けるようになったら絶対いくぞリストをつくってみました。
お!これは!?というお店がもしあれば行ってみてください!
今飲食店に限りませんが店舗は大変だと思います。
なのでいくリスト作っていけるようになったらどんどん行ってしまいたいとおもってます。

うなぎ かぶと

うなぎたち
とにかくおいしい
池袋にある名店。
今では予約もなかなかとれずいくのが大変になってしまいました。
もう10年くらい通っている大好きなお店なのですが、2代目になっても味は一品。
蒸さないタイプのうなぎの白焼き、蒲焼、くしなどを楽しめます。
チャンスあれば是非一度は行ってみて欲しいお店です。

tabelog.com

しんぽ

しんぽの料理
ほたるいか食べたい
西荻窪にある和食の名店。
ホタルイカがすごいおいしくてよくある黒いやつではなく透明なやつ。
いくらチャーハンもすごいおいしい!

tabelog.com

ほていちゃん

ほていちゃん
よきせんべろ
所謂せんべろ。
僕がよくいくのは吉祥寺店。他にも色々あるみたいです。
よくある安めの居酒屋で昼間っからやってるので最高ですね。
パクチーメンマがおすすめ!

tabelog.com

レフェルヴェソンス

レフェルヴェソンス
お酒もしらないものばかりでした。
西麻布にあるフレンチ。
初めてのフレンチだったけど、おいしかった。
流石の接客でした。 創作料理もおおくて目でも楽しめた。

tabelog.com

鏑屋

鏑屋の料理
コーンのかき揚げをつみながら酒をのむ!
東武東上線大山駅にある大衆居酒屋。
自宅からお店まで結構とおいですけど、それでもいきたくなるお店。
コーンのかき揚げと煮込みが絶品。からさ選べるんですが大辛がおすすめ!

tabelog.com

麺尊 RAGE

麺尊 RAGEのつけ麺
これはつけ麺。今すぐ食べたい。
西荻窪にあるラーメン。
何も言わずに食べに行って欲しい。
スープはいつの間にか完飲してしまうのでびっくりします。

tabelog.com

米心

米心のごはん
土鍋飯はマスト
渋谷にある隠れ家的和食居酒屋。
日本酒の種類がすごい豊富なので日本酒好きにはたまらないお店。
土鍋飯がおいしいのでいったら頼もう!

tabelog.com

中村 玄

中村 玄の料理
中村 玄は食べると体に良さそうな気がする
恵比寿にある隠れ家の中華(中華でいいのかな?)
なかでも、麻辣香鍋(汁なし火鍋)がとてもおいしい!
これを食べながら飲むハイボールが最高なんですよ。

tabelog.com

炭火焼肉ホルモン 三四郎

三四郎の肉
ハツ刺しがほんとおいしい!
西荻窪にある焼肉・ホルモンのお店。
ハツ刺しが新鮮でおいしいし、タンの盛り合わせも色々なタンを堪能できて最高。
煮込みで食べる白ごはんも最高なのでやばいです。

tabelog.com

ふぐ 牧野

牧野の料理
ふぐ料理ももちろん絶品
浅草の手前、稲荷町駅にあります。
店の前からはスカイツリーも見えるのでライトアップされた綺麗なスカイツリーもみれます。
ここはなんといっても毛蟹大根鍋。
これの大根が毛蟹の出汁を全部吸って最高の一品に仕上がってます。
シメで食べる雑炊やラーメンがさらに最高で全て最高。
チームの忘年会でいきたいNO1

tabelog.com

晩杯屋

最高のセンベロ。
大晦日も通っていたくらい一人でのサク飲みには最高でした。
黒ホッピーセットと新生姜。
ただ、よくいってた西荻窪店がなくなってしまったので悲しいですが、弊社の五反田にはあるのでいくぞ!

tabelog.com

焼肉ヒロミヤ

ヒロミヤの肉
肉質最高
曙橋にあります。
お酒はその辺に置いてあるのを自分で作って飲むスタイル。
とにかく肉の量がすごいし肉質もよかったしで最高でした。

tabelog.com

鳥かど

鳥かどの焼き鳥
ストップを言わないと延々とでてくる
目黒にある焼き鳥の名門。
焼き鳥は庶民的なものだ。という意見もありますがこういう高級な焼き鳥もたまには食べたいものです。
鳥しきの姉妹店のこのお店は斬新なメニューもあるのでたのしかったです。

tabelog.com

みやこんじょ

みやこんじょの料理
画像でお酒が飲める
新宿は歌舞伎町にある宮崎の郷土料理のお店。
鳥のタタキとチキン南蛮はマスト。
お店の場所が若干わかりづらいですw

tabelog.com

麗郷

麗郷の料理
麗郷の料理ぜんぶおいしいよ!
渋谷にある台湾料理のお店。
しじみとビーフンは絶対に頼もう。
それだけで紹興酒を2瓶あけれるぞ!
お店結構ひろいから打ち上げとかで行きたい。

tabelog.com

二の鉄

二の鉄
クセのあるモツ食べたい
溝口にあるめっちゃやすいホルモン。
結構食べたつもりでもお会計全然いってなくて毎回びびってます。
雰囲気もいい雰囲気なのでいい空間でお酒を楽しめます。

tabelog.com

魚がし 福ちゃん 2号店

魚がし 福ちゃん 2号店の料理
何気にマカロニサラダもうまい
渋谷にある立ち飲みの店。
お皿に大量の刺身がのってでてきます。
これを知らないで頼み過ぎるとおそらく食べれないです。 いつも混んでるのでいくなら、開店直後がおすすめ!

tabelog.com

西尾さん

西尾さんの料理
久しぶりにいきたすぎる。
新宿にある居酒屋。
ご主人が一人できりもりしているので時間をたっぷりつかって美味しい料理とお酒を楽しみましょう。
ここで飲んだ出汁割りがアツい酒のなかに出汁のでそうなの色々入っていてでてくるスタイルでおいしかった。

tabelog.com

根津 釜竹

根津 釜竹の料理
このうどんを頬張りたい
うどんといえば丸香とか有名ですけど、こちらもおすすめ。
うどん以外にもおいしい肴があるのでそれをいただきつつお酒をのみ、シメにうどんをたべると幸せになります。

tabelog.com

長くなりすぎた....

おわりに

いきたいお店はもっともっとあるんですけど、今でも長過ぎるのでまた機会があれば.....

自粛でどこにも行けないで家で飲むしかないのでストレスもたまりますがそれを超えてから行くお店は最高だろうなぁとおもい待っています。
みなさんも今のうち行きつけのお店や行きたいお店のリスト作って楽しみにまつ!というのもやってみるといいかもしれませんよ! 

弊社、飲みが好きな方々いるんで一緒にハモニカ横丁とかいって適当に飲みたい....

勤怠打刻操作を意識しないAPI打刻をする

おはこんばんちは、ソフトウエアエンジニアの橋本 (@af12066) です。コロナウイルスによる自粛期間もあり4ヶ月ほど散髪していないので、そろそろ行きつけの美容室に行きたい気持ちです。

これまでにfreee Developers Blogでは、人事労務freee APIを使用したさまざまな勤怠打刻方法がいくつか提案されてきました。
2018年にはIFTTTおよびGoogleアシスタントを利用した音声操作による打刻やUnity+Oculusを活用したVR打刻、2019年にはAWS IoTエンタープライズボタンを利用した打刻が紹介されました。

developers.freee.co.jp developers.freee.co.jp developers.freee.co.jp

本記事では打刻シリーズ第4弾として、私が開発した「打刻を意識しない打刻方法」を紹介したいと思います。
なお、この記事は「勤怠を自動化する技術」LT Nightで紹介した内容の文字起こし*1、および紹介しきれなかった内容の補足説明となります。

モチベーション

打刻は勤怠実績を残す重要な動作であり、時刻の正確性が要求されます。打刻の正確さと手軽さを両立させるために、たとえば人事労務freeeのトップ画面に打刻ボタンが設置されていたり、iOSアプリでは通知センターからワンタップで打刻することもできます。 一方、私のケースでは打刻ボタンを押す習慣がつく前に忘れてしまう、打刻リマインダを設定してもあとまわしにした結果打刻しない、といったことがたびたび発生していました...。

そこで、いつもどおり仕事をするだけで勝手に打刻される方法はないか?と考えた結果、本記事の手法が生まれました。

前提および事前準備

動作環境

この記事ではmacOSの機能を利用した方法を説明するため、それ以外の環境は対象外となります(すみません)。同様のサービス管理方法があれば実現可能であると思われます。

また、事業所にてfreeeアプリストアからアプリケーションを作成し、Client ID, Client Secret, 認可コードを取得しておいてください。手順の詳細は、freee APIチュートリアルをご参照ください。

developer.freee.co.jp

勤怠の定義

今回は自動打刻の都合上、勤怠は会社支給のラップトップ上で作業した時間のみを対象とします。つまり、ラップトップを起動しログインしている間は勤務しているとみなすことにします。

自動打刻の概観

打刻に関するAPIドキュメント/create)によると、打刻には次の4種類が存在します。

  • 出勤
  • 休憩開始
  • 休憩終了
  • 退勤

一日あたり8時間労働とすると、上記4つすべての打刻を行なう必要があります*2

出勤は勤怠の定義そのままで、ログインに成功した段階で打刻を行ないます。休憩は昼ごろに1時間確保しますが*3、具体的な時間の規定はないため、適当な時間に確保することにします。退勤もまた、ログアウト完了までに打刻をする必要があります。

ざっくり状態遷移は次のようになります。ただしAPIの具体的な仕様の説明ではないため、正確でない場合があります。

勤怠の状態遷移。出勤から開始し、休憩開始および休憩終了を経て退勤となる。休憩開始および休憩終了はくりかえすことができ、または休憩を行なわずに出勤・退勤のみ打刻することもできる
勤怠の状態遷移

休憩開始の直後に退勤を打刻したり、退勤のあとに休憩終了しようとするとAPI側でエラーとなることから、上記の状態遷移となることが推定されます。

次のようなエラーがAPIのメッセージとして返ってくる:「休憩開始時刻の後に退勤時刻を指定することはできません、退勤時刻の後に休憩終了時刻を指定することはできません」
不適切なAPI打刻の例

自動打刻の実装

トークンの取得および機密情報の格納

Client ID, Client Secret, 認可コードが取得済みであるとして、これらを用いてリフレッシュトークンを取得する必要があります。また、アクセストークンの取得・更新のために、Client ID、Client Secret、リフレッシュトークンも合わせて保存する必要があります。

developer.freee.co.jp

トークンは任意のファイルに書き込んでから暗号化して保存したり環境変数に保存してもよいですが、Macにはキーチェーンアクセスという機密情報を保存するためのアプリケーションがあるため、これを活用してみます。

support.apple.com

シェルからキーチェーンアクセスを操作するために、securityコマンドがあります。使い方の詳細はman 1 securityを参照してください。

リフレッシュトークンの取得からキーチェーンアクセスへの登録までをまとめると、以下のようなスクリプトになります。リフレッシュトークンの更新は別途行なうため、以下のスクリプトを実行するのは初回のみとなります。

# 初回のリフレッシュトークンを取得するために必要な設定をおこなう

export FREEE_CLIENT_ID="<freee APIのClient ID>"
export FREEE_CLIENT_SECRET="<freee APIのClient Secret>"
export AUTHORIZATION_CODE="<freee APIの認可コード>"
#!/bin/bash

readonly REFRESH_TOKEN=$(curl -X POST \
  -H "Content-Type:application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=${FREEE_CLIENT_ID}" \
  -d "client_secret=${FREEE_CLIENT_SECRET}" \
  -d "code=${AUTHORIZATION_CODE}" \
  -d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" 'https://accounts.secure.freee.co.jp/public_api/token' \
  | jq -r '.refresh_token')

readonly KEYCHAIN_SERVICE_NAME='freee-kintai'

security add-generic-password -a client-id -w "${FREEE_CLIENT_ID}" -s "${KEYCHAIN_SERVICE_NAME}"
security add-generic-password -a client-secret -w "${FREEE_CLIENT_SECRET}" -s "${KEYCHAIN_SERVICE_NAME}"
security add-generic-password -a refresh-token -w "${REFRESH_TOKEN}" -s "${KEYCHAIN_SERVICE_NAME}"

キーチェーンアクセスを開き、パスワードと同様の扱いでClient ID, Client Secret, リフレッシュトークンが保存されていることを確認します。

キーチェーンアクセスでclient-idの詳細を確認しているスクリーンショット
キーチェーンアクセスでclient-idの詳細を確認(パスワードの表示にはMacのログインパスワードの入力が必要)

打刻の汎用スクリプト

人事労務freee APIを操作するための、打刻用のスクリプト (Bash) を書いていきます。出勤・休憩・退勤はすべて同じエンドポイントであるため、単一のスクリプトにまとめて引数で打刻種別を変えるようにしてみます。一回の打刻におけるAPIリクエストの流れは次のようになります。

  1. さきほど登録したClient ID、Client Secret、リフレッシュトークンを使用して認証をおこなう。このとき、アクセストークンおよびリフレッシュトークンが払い出され、リフレッシュトークンはキーチェーンに上書き保存し、アクセストークンは以降のAPIリクエストに使用する
  2. アクセストークンを使用して、事業所IDおよび従業員IDを取得する
  3. アクセストークン、および2.で得られた事業所ID、従業員IDに加えて打刻種別を指定し、打刻APIにPOSTする
Client ID、Client Secret、リフレッシュトークンを使用してアクセストークンを取得する

さきほどキーチェーンに登録したClient ID、Client Secret、リフレッシュトークンを取得し、アクセストークンを取得するエンドポイントにPOSTします。
security find-generic-passwordコマンドでキーチェーンの内容を取得できます。-wオプションを与えることで、標準出力にその登録内容だけを流すことができます。

#!/bin/bash

readonly CLIENT_ID=$(security find-generic-password -a client-id -w -s freee-kintai)
readonly CLIENT_SECRET=$(security find-generic-password -a client-secret -w -s freee-kintai)
readonly TOKEN=$(security find-generic-password -a refresh-token -w -s freee-kintai)

readonly AUTH_RESP=$(curl -X POST \
  -H "Content-Type:application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=${CLIENT_ID}" \
  -d "client_secret=${CLIENT_SECRET}" \
  -d "refresh_token=${TOKEN}" \
  'https://accounts.secure.freee.co.jp/public_api/token' 2>/dev/null)
readonly ACCESS_TOKEN=$(echo ${AUTH_RESP} | jq -r '.access_token')
readonly REFRESH_TOKEN=$(echo ${AUTH_RESP} | jq -r '.refresh_token')

# add-generic-password -Uでキーチェーンに上書き保存する
security add-generic-password -a refresh-token -w "${REFRESH_TOKEN}" -s freee-kintai -U
事業所IDおよび従業員IDの取得

2020年現在、/api/v1/users/meで取得できます。

人事労務APIリファレンス | freee Developers Community

スクリプトは次のようになります。事業所名は自身の事業所名に置換してください。

#!/bin/bash

readonly COMPANY_RESPONSE=$(curl -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  https://api.freee.co.jp/hr/api/v1/users/me 2>/dev/null)
readonly COMPANY_ID=$(echo ${COMPANY_RESPONSE} | jq -r '.companies[] | select(.name | test("事業所名")) | .id')
readonly EMPROYEE_ID=$(echo ${COMPANY_RESPONSE} | jq -r '.companies[] | select(.name | test("事業所名")) | .employee_id')
打刻APIにPOSTする

2020年現在、/api/v1/employees/${EMPROYEE_ID}/time_clocksにPOSTすることで打刻できます。

人事労務APIリファレンス | freee Developers Community

#!/bin/bash

readonly time_clocks_type=$1

readonly ISO8601DATE=$(date "+%Y-%m-%d")

curl -X POST -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type:application/json" \
  -d "{\"company_id\":${COMPANY_ID},\"type\":\"${time_clocks_type}\",\"base_date\":\"${ISO8601DATE}\"}" \
  https://api.freee.co.jp/hr/api/v1/employees/${EMPROYEE_ID}/time_clocks 2>/dev/null)

time_clocks_type=$1で引数を得ることで、アクセストークンの取得から打刻までを単一のスクリプトをまとめてdakoku.shとして実行権限つきで保存したとき、/path/to/dakoku.sh clock_inのように実行することで出勤打刻を行なうことができます。

打刻スクリプトの実行

作成したスクリプトdakoku.shを、勤怠種別ごとに実行させていきます。

出勤

システム環境設定の「ユーザとグループ」内、「ログイン項目」にて、ログイン直後に開きたいアプリケーションを指定します。ただし、実行権限を与えたシェルスクリプトを直接指定することはできないようです。
そこで、シェルスクリプトをラップしたAutomatorアプリケーションを作成し、それをログイン項目に指定することにします。

support.apple.com

# Automatorアプリケーションのシェルに以下を記述して保存する

export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin

/path/to/dakoku.sh clock_in
launchctl unload -w ~/Library/LaunchAgents/freee-kintai-taikin.plist # 後述

初期状態では環境変数PATHには/usr/bin:/bin:/usr/sbin:/sbinしか含まれないため、スクリプトで使用するコマンドに応じてPATHを追加してください。
また、初回実行時にはキーチェーンアクセスへのアクセス許可を求められます。

securityコマンドがfreee-kintaiキーチェーンへのアクセスを求める表示があらわれる
securityコマンドからのアクセスを求められるので、つねに許可する

Automatorの設定画面。シェルに/bin/bashを指定し、前述のスクリプトを記述する
Automatorの設定画面

システム環境設定のスクリーンショット
システム環境設定のログイン項目に、Automatorアプリケーションを指定する

休憩開始および終了

厳密な休憩時刻は定められていないため、かりに12時から13時まで休憩することにします。

macOSでは、cronに相当する機能としてlaunchdが提供されています*4。launchdの概観を知るには、"A launchd Tutorial" がわかりやすいので、時間があれば眺めてみてください。

12時に休憩開始を打刻するplistは次のようになります。~/Library/LaunchAgents/freee-kintai-put-break-time.plist といった名称で保存しておきます(~/Library/LaunchAgents/以下であればファイル名はなんでもよい)。
StartCalendarIntervalを使用して平日の12時に打刻する設定となっており、Weekdayは日曜日が0、月曜日が1、...という指定となります。休憩終了も同様に作成します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>freee-kintai-put-break-time</string>
    <key>ProgramArguments</key>
    <array>
      <!-- 絶対パスでスクリプトを指定する -->
      <string>/Users/your-login-name/path/to/dakoku.sh</string>
      <string>break_begin</string>
    </array>
    <!-- スクリプトの内容に合わせてPATHを更新する -->
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>StartCalendarInterval</key>
    <array>
      <dict>
        <key>Weekday</key>
        <integer>1</integer>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>2</integer>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>3</integer>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>4</integer>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
      <dict>
        <key>Weekday</key>
        <integer>5</integer>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>0</integer>
      </dict>
    </array>
    <key>ExitTimeout</key>
    <integer>30</integer>
    <key>RunAtLoad</key>
    <false/>
  </dict>
</plist>

launchctl loadコマンドにより、plistをlaunchdに登録します。

$ launchctl load -w ~/Library/LaunchAgents/freee-kintai-put-break-time.plist # 休憩開始
$ launchctl load -w ~/Library/LaunchAgents/freee-kintai-put-break-time-end.plist # 休憩終了
$ launchctl list | grep freee # launchdに登録したplistを確認。grepにヒットすればOK
-   0  freee-kintai-put-break-time
-   0  freee-kintai-put-break-time-end
退勤

出勤は「ログイン項目」にて指定できたものの、退勤に相当する「ログアウト項目」は存在しません。

ここで、freeeの退勤打刻を上書きできる仕様*5を活用します。具体的には、

  1. 19:00に退勤を打刻(WebまたはAPI経由で)
  2. 19:01に退勤をAPIで打刻
  3. 19:02に退勤をAPIで打刻

といった操作を順番に行ったとき、結果はすべて成功となり、最終的な退勤時刻は19:02となります(手順1.および2.は上書きされる)。つまり、休憩終了後からログアウトするまで退勤打刻をくりかえすことで、ログアウト時刻を退勤時刻とみなすことができます。

退勤をくりかえすplist (~/Library/LaunchAgents/freee-kintai-taikin.plist) は次のようになります。以下の例ではStartIntervalを使用して2分ごとに退勤操作をくりかえしています。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>freee-kintai-taikin</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Users/your-login-name/path/to/dakoku.sh</string>
      <string>clock_out</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <!-- 120秒ごとに退勤打刻をおこなう -->
    <key>StartInterval</key>
    <integer>120</integer>
    <!-- ねんのためstdout/stderrを残しておく -->
    <key>StandardOutPath</key>
    <string>/Users/your-login-name/path/to/taikin.out</string>
    <key>StandardErrorPath</key>
    <string>/Users/your-login-name/path/to/taikin.err</string>
    <key>ExitTimeout</key>
    <integer>30</integer>
    <!-- launchctl loadを実行した際にも退勤打刻をする -->
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>

ここで、出勤時に~/Library/LaunchAgents/freee-kintai-taikin.plistをunload(launchdから登録解除)していましたが、これは休憩開始前に退勤打刻されるのを防ぐためです。
休憩終了後に再度loadする必要があるため、そのためのplistを休憩打刻と同様に以下のように作成します。休憩終了は13:00としたので、ひとまず14:30から退勤打刻を開始すれば問題ないでしょう。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>freee-kintai-trigger-taikin</string>
    <key>ProgramArguments</key>
    <array>
      <string>launchctl</string>
      <string>load</string>
      <string>-w</string>
      <string>/Users/your-login-name/Library/LaunchAgents/freee-kintai-taikin.plist</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>StartCalendarInterval</key>
    <array>
      <dict>
        <key>Weekday</key>
        <integer>1</integer>
        <key>Hour</key>
        <integer>14</integer>
        <key>Minute</key>
        <integer>30</integer>
      </dict>
      <!-- ...省略 -->
    </array>
    <key>ExitTimeout</key>
    <integer>30</integer>
    <key>RunAtLoad</key>
    <false/>
  </dict>
</plist>

再度launchctl listを確認します。退勤をunload|loadしているため、時間帯によって結果が異なる場合があります。

$ launchctl list | grep freee
-   0  freee-kintai-trigger-taikin
-   0  freee-kintai-put-break-time
-   0  freee-kintai-put-break-time-end

あとは数日間運用しつつ人事労務freeeのタイムレコーダーを確認し、正常に打刻されていることが確認できればOKです。

人事労務フリーのタイムレコーダーのスクリーンショット。出勤・休憩開始・休憩終了・退勤がすべて記録されている
人事労務freeeのタイムレコーダー

打刻の信頼性を向上させる

これまで紹介した実装に加えて、以下の実装を追加で行っています。

  • APIサーバへの簡単な疎通確認を行ない、サーバに到達できないケース、認証に失敗したケース、状態遷移が正しくないケースのハンドリングやリトライ処理を行なう
  • stdout/stderrを即座に確認しづらいため、たとえばosascript -e 'display notification "人事労務freeeで打刻しました" with title "出勤"'を実行することで打刻の成功・失敗に関するフィードバックを通知させる
    • Mac標準の通知機能をAppleScript経由で利用

打刻漏れをしてしまうことがまずいため、それを早期に検知できること、対処方法がわかること(スクリプトやネットワークがまずいのか、打刻種別がよくないのか、あきらめて手動打刻しなければならないのか、など)が重要であると考えます。

まとめ

この記事では、能動的に打刻操作をしない自動打刻方法を紹介しました。別の環境や打刻以外の場面で活用できるかもしれないので、機会があれば参考にしてみてください。

Enjoy!

*1:書こうと思いつつ機会を逃していたら1年経過していたので、復習も兼ねる

*2:労働時間・休憩・休日関係|厚生労働省によると、労働基準法第34条にて、8時間を超える勤務の場合は少なくとも1時間の休憩が定められている

*3:実際には1時間以上確保したり複数回休憩することも可能だが、例外とみなす

*4:スケジューラ以外にもサービス管理などの機能があるが、ここでは紹介しない

*5:仕様であることを確認済み

Google Optimizeを使ったサイト改善

こんにちは。freeeプラットフォーム部でマーケティングを担当しているあおい( @BlueS3124 )です。

今回は、Google Optimizeを使ったWebサイトの改善について記述します。

freeeアプリストアのWebサイト改善の目的

APIの利活用を推進しているプラットフォーム部では、多くのユーザーにfreeeアプリストアを活用していただくことを目標にマーケティング活動を行っています。アプリストアのWebサイト改善もその一環として実施しています。

freeeアプリストアは、2019年1月にリリースされた、拡張機能や外部サービス連携をfreeeに追加できるアプリケーションとユーザーを繋ぐプラットフォームです。 freeeユーザーはアプリストアに訪問することで、課題を解決できるアプリがあるかを簡単に調べて、連携開始することができます。

app.secure.freee.co.jp

アプリストアに訪問するユーザーは、通常 ①TOPページ> ②検索一覧 > ③アプリ詳細ページ > ④連携ボタンのクリックと進んでいきます。出来るだけ次のステップに進むユーザーの比率を高めることがWebサイト改善の目的になります。

利用したツール

Webサイトの改善のため、コンテンツの変更を簡単に実装できるGoogle Optimize を利用してみました。

Google Optimizeは、特定のWebページのコンテンツを上書きして、ABテストを行うことができます。ユーザーの行動や参照元、属性などを元にコンテンツの内容を出し分ける「カスタマイズ(パーソナライゼーション)」といった機能もあります。

エンジニアやデザイナーの工数を取らずに、自分で簡単にWebページのコンテンツを上書きすることができるため、改善やテストをスピーディに回すことができるのが最も大きな利点だと思います。

具体的な改善事例

どんなサイト改善を行ったのか、実際の例を元にご紹介します。

おすすめアプリ行の設置

「新着アプリ」の上に「おすすめアプリ」が表示されている
おすすめアプリ行の設置

概要
  • 連携数を増やしたいアプリ
  • ③アプリ詳細ページ→④連携ボタンのクリックに至る率の高いアプリ

を選別して、意図的に①TOPページの上部に表示するテストを実施しました。

結果

おすすめアプリ行の設置は①TOPページから③アプリ詳細ページ至る訪問の増加、④連携ボタンをクリックする率の増加に繋がりました。 アプリ別で見ると、おすすめ行に掲載すると③アプリ詳細ページへの訪問が1.2~1.5倍、④連携ボタンのクリック数も1.2倍程度になることなども分かりました。

ポップアップバナーの設置

コンテンツにオーバーレイする形でキャンペーンを告知するバナーを表示している
ポップアップバナーの設置

概要

新規のアプリ連携を促進するキャンペーンに合わせて、ポップアップバナーを①TOPページに掲載しました。 新規連携を対象としたキャンペーンなので、初めてアプリストアに訪問したユーザーのみターゲティングするカスタマイズを行いました。

結果

キャンペーンは法人限定でしたが、法人と個人事業主のユーザーを識別して出し分けることができなかったため、バナー自体のクリック率は低めでした。アプリストア全体の④連携ボタンのクリックはキャンペーン期間中増加する結果に繋がりました。

おまけ:新型コロナウィルス関連のお知らせバナーの設置

ページ最上部に「COVID-19の最新情報」バナーが表示されている
新型コロナ関連のお知らせバナーの設置

概要

Google Optimizeでは、新型コロナウィルスへの対応に追われる事業者のために、営業時間やサービス内容などの変更に関するお知らせバナーをWebサイトに簡単に掲載できる機能が追加されました。バナーテンプレートが用意されているため、HTMLやCSSの知識がなくても簡単にWebサイトのヘッダーに表示することができます。

こういったバナー設置などのカスタマイズを同時に実施できる上限は本来最大 10 件ですが、新型コロナウイルスへの対応期間中は必要なだけサイトを更新できるように、制限が一時的に解除されています(詳細はこちら)。

まとめ

Webサイトの改善は、仮説に対して良い結果が得られないこともあります。けれども、筋が悪いことを含め答えを得られることに価値があるので、日々地道にテストを繰り返していくことが重要だと思います。

Google Optimizeは、HTMLとCSSで表現できることはだいたい実装可能で、本当に便利です。スピーディーなWebサイト改善や状況に合わせた情報更新を必要とされる方は、Google Optimizeの活用を検討してみてはいかがでしょうか。

freeeのデザイナーがお互いの成長に貢献できる状況を作るためのワークショップを実施してみた

OGP : freeeのデザイナーがお互いの成長に貢献できる状況を作るためのワークショップ こんにちはfreeeのプロダクトデザイナーのはるたんです。

最近はリモート生活も長引き、コーヒーを淹れるだけでは飽きてきたので、ラテアートに挑戦してみました。

本当はラテアートやコーヒーについてのブログを書きたいところですが、 今日はタイトルの通り「freeeのデザイナーがお互いの成長に貢献できる状況を作るためのワークショップ」を実施したので、その背景と振り返りについての記事を書こうと思います。

はじめに

今回のワークショップを実施した背景を説明するために、まずfreeeのデザイン組織について説明をします。 1年以上前は1つのデザインチームしかありませんでしたが、ここ数年で大きくなってきており、今では以下の3つのチームに分かれております。

  • デザインシステムチーム
  • プロダクトデザインチーム
  • デザインリサーチチーム

僕が所属するプロダクトデザインチームでは、担当するプロダクトの「情報設計」「UI設計」「デザイン品質向上」をメインで担当しており、プロダクト・事業部を跨るユーザー体験の方針を決定します。

チームが発足してから1年の間に、いろんなバックグラウンドを持ったデザイナーが増えてきました。強いメンバーが増えたのは嬉しいことですが、以下のような課題も生じつつありました。

  • freeeのデザイナーとして伸ばして欲しいスキルはある一方、個人が伸ばしていきたいと思っていることがわからないのでお互いに協力しづらい
  • めちゃくちゃスキルを持ったデザイナー集まってるはずなのに、誰がどういうスキルを持っているかわかりづらく、特定の誰かに相談が集中している

そんな時に、Cookpadの宇野さんが書いていた記事を発見しました。

note.com

継続的な1on1では自分の得意に伸ばしたい部分をより深くサポートができるようになりましたし、これを全社に公開することで他職種から「こういうことをお願いできないか」という機会も生まれてきています。

これは面白そうだなと軽い気持ちでこのnoteを共有したところ、興味ありそうなメンバーが何人かいたので、実際にワークショップを企画してみることにしました。

ワークショップをやる意義

企画するとは言ったものの、多忙なメンバーの時間を拘束してワークショップをするため、改めてやる意義を整理してみました。

個人で伸ばす分野、組織でのサポートはできつつあるので、メンバー間でサポートしあえると良いよねってことを示している
ワークショップの目的を整理した図

各セルの定義が抽象的な部分はありつつも、要はfreeeのプロダクトデザインチームでは、「個人で自発的に頑張る」「組織としてのサポート」はできつつあったり、まさに今取り組んでいるので、「メンバー間のサポート」が増えれば、結果的にプロダクトデザインチーム全体のスキルが向上し、最終的には個人がfreeeでやりたいと思うことの実現に集中できると考えました。

お互いがサポートしあうための手段として、まずは自分が持っているスキルのスキ・キライ・得意・苦手を可視化することは有効ではないか?と思い、ワークショップを実施することにしました。

事前準備

ワークショップで作ってもらうスライドのテンプレート

参加するメンバーには事前準備として、上記のマップを埋めてもらうようにしました。マップの作り方は、冒頭で紹介した宇野さんの記事に書いてある通り、以下の4象限で自分のスキルを可視化してもらいました。

・得意 × スキ
・得意 × キライ
・苦手 × スキ
・苦手 × キライ

元の記事で述べられている通り、あくまで「自分の意思表示」としてマップを活用してもらいたかったので、主観でスキキライを書いてもらうことにしました。

タイムスケジュール

タイムテーブルを書いたスライド

当日のタイムスケジュールは以下のようにしました。

  • アイスブレイク : 5分
  • 目的の説明 : 5分
  • 発表&質疑応答 : 5分 x 13人
  • リフレクション : 10分

20卒入社・中途のメンバーも合わせると合計13人が参加したので、発表時間は1人5分ほどに設定しましたが、終了後のアンケートでもポジティブな声が多かったので時間配分は問題なかったようです。

ワーク中の様子

ワーク中のメンバーの様子

ファシリテーターの僕が画面を共有しながら、一人一人発表してもらいました。発表方法にルールは決めず、自由に話してもらいましたが、時折雑談も入り終始賑やかな雰囲気でワークショップが実施されました(と筆者は思っております)。

筆者の発表スライド

Googleスライドのコメント機能を活用し、各セルにポジティブなコメントを残したり、質問が入ったりすることでワークはさらに盛り上がりました。

(このマップは僕のですが、冒頭で説明した通りコーヒーにどハマりしているので、右上に置いてます)

振り返り

終了後、参加メンバーにアンケートを取ったので、回答を元にワークショップを振り返りたいと思います。

良かった点

  • 対面で会う機会がなかったので、これを機に相談するハードルが下がったり、お互いを知るきっかけになった。(入社してから在宅勤務のメンバー)
  • 新卒として入社したこともあり、これまでふんわりとしか分かっていなかった先輩方の強みや役割を知ることができた。(20卒のメンバー)
  • 意外と「自分の中の認識と他の人から見た自分の姿」が違うのは面白かった。(在籍2年以内のメンバー)
  • お互いの好きなことやパーソナリティを知れてチームビルディングとして有意義だった。(在籍1年以内のメンバー)
  • フランクな相談や壁打ちを今後は気軽に行えると思う。(在籍1年以内のメンバー)

改善点

  • 表記揺れも多く他の人と比較して誰がどう言うスキルをもっているかを一覧して使うのは難しそう。(在籍3年以上のメンバー)
  • 予め共通の要素は用意しておき、それをマップのどこに配置するかを考えても良さそう。(在籍3年以上のメンバー)
  • 個性を出したい部分は、プラスアルファで自由に書いてもらったら良さそう。(在籍3年以上のメンバー)
  • 業務で必要なスキルと直接関係なさそうなスキルをどうやって切り分けるか。(在籍3年以上のメンバー)
  • 発表が一方的になりすぎたので、もう少し対話的にできると良さそう。(在籍1年以内のメンバー)

アンケートの結果を振り返ると特に新卒で入社したメンバーや中途で最近入ってきたメンバーにとっては、お互いを知る機会になったり相談するきっかけとして今回のワークショップが有意義だったようです。

一方、古くからいるメンバーにとっては、ワークショップの試みとしては面白かったようですが、既にメンバーのことを知っていることも多く、普段交流しているだけでは引き出せない当人の魅力が伝わる仕掛けを用意してあげれば良かったかなと思っております。

また、今回のワークショップの性質上、新メンバーほどお互いを知る良い機会になるので、今後新しいメンバーが増えた時、どう活用していくかはこれから考えていきたいと思います。

いかがでしたでしょうか。今回のワークショップは、在宅勤務中にお互いを知る良い機会になったと思います。興味を持った方はぜひ挑戦してみてください!