SMARTCAMP Engineer Blog

スマートキャンプ株式会社(SMARTCAMP Co., Ltd.)のエンジニアブログです。業務で取り入れた新しい技術や試行錯誤を知見として共有していきます。

テクノロジーで社内の非効率を無くす

こんにちは、BOXIL開発に携わっている、新卒エンジニアの高砂と申します!

私はスマートキャンプにてこれまでインターンとして1年、新卒社員として1年ほど働いています。

皆さんは、普段の業務の中で「これって非効率だな」と感じた経験はありますか?

私はこれまで業務の中で非効率を見つけると、社内コミュニケーションツール「Slack」上で動くbotをGASで開発などして解決していました。

本記事では、開発した業務効率化botの内でお気に入りのものを3つほどご紹介し、その中でも特に注力した1つについて詳しくお話ししていきます!

業務効率化bot3選

来客対応サポートbot

スマートキャンプでは「RECEPTIONIST」という受付サービスを利用しています。

来客時にSlack通知する機能があり非常に便利なのですが、この通知には来客名しか表示されず、誰の来客か分からないという弱点があります。

なのでこれまでは、その日の受付担当者が来客名とマッチするGoogleカレンダー上の予定を目視で探し、来客先の社員に連絡するというフローで対応していました。

しかしそれが非効率だと思った私は、下記のように自動で対応する予定を探し、連絡してくれるbotを作りました。

詳しくはこちらの記事で説明しているので、良ければご覧ください。 tech.smartcamp.co.jp

質問精度向上bot

入社したての頃、新卒の私は「良い質問の仕方」を身につけるのに苦戦しました。

質問が曖昧だったり、過去に聞いた事があるのにまた質問してしまったりしていました。

かといってそれを質問する度に意識するのも非常に難しいです。

なので私が質問する度に、botが質問文かどうかを下記のようなロジックで判定した上で、質問文の場合は「良い質問の仕方」を意識させるような問いかけをするにしました。

var questionWords = ['ですか?', 'ますか?']
if (receivedMessage.indexOf(questionWord) !== -1) {
  postMessage(message)
}

これにより私は、質問の度に「良い質問の仕方」を毎回意識することができ、自然と良い質問ができるようになりました。

日報半自動生成bot

スマートキャンプには「毎日退勤時に日報を書く」という文化があります。

その文化自体はとても良いものだと思うのですが、「日報の作成作業」にも非効率が潜んでいました。

それを解決する為に下記のようなbotを作成しました。

詳しくは次のセクションでお話ししていこうと思います。

日報半自動生成botの詳細

背景

先述した通り、スマートキャンプには「毎日退勤時に日報を書く」という文化があります。

その目的は2つあり、1つは業務報告、1つはコミュニケーション活性化です。

日報には下記のように「本日のタスク」と「雑感(ひとことコメントのようなもの)」を記載するので、2つの目的を達成できるようになっています。

なので日報を書くこと自体は重要なのですが、日報の前半の「本日のタスク」については、各自がGoogleカレンダーを見ながら手打ちで入力するという作業が発生していました。

「その作業は効率化し、雑感に時間をかけるべき」だと考えた私は、Googleカレンダーから自動で「本日のタスク」を抽出できるのでは考えました。

要件定義

前述の課題を解決するにあたって、下記要件が必要と考えました。

  • Googleカレンダーから予定名を抽出して一覧化してくれる事
  • 一覧を日報の定形フォーマットに挿入してくれる事
  • 上記を特定の時間に共有してくれる事

これらを実現してくれるbotをGASで開発してみました。

実際の実装内容

実装は下記のように行いました。6つのセクションに分けて解説していきます。

①ーーーーーーーーーーーーーー
function main() {
  var sheetId     = PropertiesService.getScriptProperties().getProperties().sheetId
  var spreadsheet = SpreadsheetApp.openById(sheetId)
  
  var formSheet       = spreadsheet.getSheetByName('form')
  var formSheetValues = formSheet.getDataRange().getValues()
  
  var idTableSheet       = spreadsheet.getSheetByName('idTable')
  var idTableSheetValues = idTableSheet.getDataRange().getValues()

②ーーーーーーーーーーーーーー  
  formSheetValues.slice(1).forEach(function (formSheetRow) {
    var calendarId   = formSheetRow[1]
    var calendar     = CalendarApp.getCalendarById(calendarId)
    if (calendar !== null) {
      var events       = calendar.getEventsForDay(new Date())
      var eventMessage = ''

③ーーーーーーーーーーーーーー      
      events.forEach(function (event) {
        var title = event.getTitle()
        var status = event.getMyStatus()
        if (title !== '' && status != 'NO') {
          eventMessage += '・' + title + '\n'
        }
      })
      
      var mention = makeMention(calendarId, idTableSheetValues)
      var message = makeDailyReport(eventMessage, mention)
      postMessage(message)
    }
  })
}

④ーーーーーーーーーーーーーー
function makeMention(calendarId, idTableSheetValues) {
  var SLACK_ID_COLUMN = 2
  var EMAIL_COLUMN    = 3
  var mention = ‘’
  
  idTableSheetValues.forEach(function (idRow) {
    if (idRow[EMAIL_COLUMN] === calendarId) {
      mention = ‘<@‘ + idRow[SLACK_ID_COLUMN] + ‘> ‘
    }
  })
  return mention
}

⑤ーーーーーーーーーーーーーー
function makeDailyReport(message, mention) {
  return ‘今日の日報フォーマットを持ってきたわん!\n\n’ + mention + ‘*【日報】’ + Moment.moment().format(‘YYYY年MM月DD日(dddd)’) + ‘*’ + ‘\n```本日のタスク```\n’ + message + ‘\n```雑感```}

⑥ーーーーーーーーーーーーーー
function postMessage(message) {
  (中略)
}

まず①では、スプレッドシートから利用者情報を抽出しています。

アンケートで集めた日報半自動生成botの利用希望者一覧が記載されているスプレッドシートから、それぞれのメールアドレスおよびSlackのメンバーIDを引っ張ってきています。

①ーーーーーーーーーーーーーー
function main() {
  var sheetId     = PropertiesService.getScriptProperties().getProperties().sheetId
  var spreadsheet = SpreadsheetApp.openById(sheetId)
  
  var formSheet       = spreadsheet.getSheetByName('form')
  var formSheetValues = formSheet.getDataRange().getValues()
  
  var idTableSheet       = spreadsheet.getSheetByName('idTable')
  var idTableSheetValues = idTableSheet.getDataRange().getValues()

次に②では、①のメールアドレスをもとに対応するGoogleカレンダー、およびそこに記載されている今日の全予定を取得しています。

②ーーーーーーーーーーーーーー  
  formSheetValues.slice(1).forEach(function (formSheetRow) {
    var calendarId   = formSheetRow[1]
    var calendar     = CalendarApp.getCalendarById(calendarId)
    if (calendar !== null) {
      var events       = calendar.getEventsForDay(new Date())
      var eventMessage = ‘’

そして③では、②の全予定の中で「不参加」以外の予定の予定名を取得し、変数に代入しています。

③ーーーーーーーーーーーーーー      
      events.forEach(function (event) {
        var title = event.getTitle()
        var status = event.getMyStatus()
        if (title !== '' && status != 'NO') {
          eventMessage += '・' + title + '\n'
        }
      })
      
      var mention = makeMention(calendarId, idTableSheetValues)
      var message = makeDailyReport(eventMessage, mention)
      postMessage(message)
    }
  })
}

④では、①のメンバーIDからSlackでのメンション文言を生成しています。

④ーーーーーーーーーーーーーー
function makeMention(calendarId, idTableSheetValues) {
  var SLACK_ID_COLUMN = 2
  var EMAIL_COLUMN    = 3
  var mention = ‘’
  
  idTableSheetValues.forEach(function (idRow) {
    if (idRow[EMAIL_COLUMN] === calendarId) {
      mention = ‘<@‘ + idRow[SLACK_ID_COLUMN] + ‘> ‘
    }
  })
  return mention
}

そして⑤では、③の予定名情報および④のメンション文言を用いて、botが実際に送るメッセージ内容を生成しています。

⑤ーーーーーーーーーーーーーー
function makeDailyReport(message, mention) {
  return ‘今日の日報フォーマットを持ってきたわん!\n\n’ + mention + ‘*【日報】’ + Moment.moment().format(‘YYYY年MM月DD日(dddd)’) + ‘*’ + ‘\n```本日のタスク```\n’ + message + ‘\n```雑感```}

最後に⑥では、⑤で生成したメッセージを実際に送信する処理を行っています(良くある処理なのでこちらは省略させて頂きました)。

⑥ーーーーーーーーーーーーーー
function postMessage(message) {
  (中略)
}

以上の6つのセクションによって、今回の日報半自動生成botを実装しました。

実際の利用状況

最初は自分の為に作り始めたbotでしたが、社内公開してからクチコミで色んな方に利用して頂き、今ではなんと30人以上が利用しています!(全正社員の4割ほどにあたります)

また、利用者から寄せられた声をもとに定期的にアップデートもしており、好評をいただいています。

まとめ

最近の業務ツールはAPI連携が盛んであり、特にGASでSlack用のbotを作るのは自由度が高いです。

業務ツールの移り変わりと共に非効率な作業も発生しがちなものなので、皆さんもそれをbotで解決してみてはいかがでしょうか?

スマートキャンプのミッションである「テクノロジーで社会の非効率を無くす」を、引き続き社内でも体現していこうと思います!