簡単システムが秒で作れる時代に効率化が進まないと思うこと|GASでGmailを抽出してスプレッドシートに貼ってみた

こんにちは。「AIで勘違いしてなんでも作ってみる部」です。

この活動は、その名の通り、AIに対して「まあ、勘違いかもしれないけど、多分できるんじゃない?」って思いながら、とりあえず何かを作って解決してみよう、という試みです。すごくざっくりですが、そんなことをやっています。

今日は「簡単なシステムが秒で作れる時代に、効率化が進まないと思ってしまったこと」というテーマです。

目次

今回の取組|キャンプ場の問い合わせ業務効率化

今回の取組|キャンプ場の問い合わせ業務効率化

現在、あるキャンプ場の問い合わせ業務の効率化を進めています。
ここには主に2つの問題があります。

  1. 問い合わせの数が多いこと
  2. 対応方法が属人化していること:

まずは同じような問い合わせが多くて、毎回、対応するのが大変だ!という話です。これはキャンプ場でなくても顧客対応は特にtoC、toB関係なく、大変だと思います。

問合せ対応で業務が中断したり、問合せへの返信を忘れてクレームにつながったり、そんなことに悩む職場・人は多いのではないでしょうか?

また、個別に気付いた人が対応している場合も多いと思います。このキャンプ場も同じ悩みです。そこで「対応方法を標準化して、みんなが同じように一定レベルの回答ができるようにしよう」ということにも取り組んでいきたいと考えています。

現状整理:問い合わせデータの分析

この目標を実現するために、まずは「そもそもどんな問い合わせが多いのか」を把握する必要があります。流石にいきなりHPに〇〇を掲載しようだと芸がないので、まずは問い合わせ内容を抽出して、どんな問合せ内容がいつ多いのか?それを把握したいと思います。

口頭や電話の内容は追跡が難しいですが、Gmailから返信しているメールでの問い合わせなら記録が残っています。

そこで、以下の手順で進めることにしました。

  1. Gmailの送受信履歴を抽出する。
  2. どのような問い合わせが多いのかを分類して可視化する
  3. 件数が多く、解決しやすいもの、費用対効果が高い物等から優先順位をつけて解決していく。

生成AI(Claude)でGASコードを作成
GASでGmailを取得してスプレッドシートに抽出するコードが実現

生成AI(Claude)でGASコードを作成
GASでGmailを取得してスプレッドシートに抽出するコードが実現

私自身はエンジニア出身ではないので、正直コードもよく分からないですし、得意ではありません。更にエラー対応とか正直やりたくないです(笑)

しかし、今回、生成AIのClaudeを使ってみたところ、エラー修正も含めて1時間ほどでGoogle Apps Script(GAS)のコードが完成しました。

// Gmail抽出スクリプト
// スプレッドシートから期間と送信元アドレスを取得し、指定した条件でGmailの内容を抽出してスプレッドシートに転記します

// 文字列が日付形式かを判断する関数
function isDateString(str) {
  if (typeof str !== 'string') return false;
  
  // "Wed Jan 01 2025 00:00:00 GMT+0900 (Japan Standard Time)" の形式を検出
  return /\w{3}\s\w{3}\s\d{2}\s\d{4}/.test(str);
}

// 日付文字列からYYMM形式の文字列を取得する関数
function getYYMMFromDateString(dateStr) {
  try {
    const date = new Date(dateStr);
    if (isNaN(date.getTime())) {
      return null;
    }
    
    const year = date.getFullYear() % 100; // 西暦の下2桁
    const month = date.getMonth() + 1; // getMonthは0から始まるので+1
    return `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}`;
  } catch (e) {
    console.error(`日付文字列の変換に失敗しました: ${e.message}`);
    return null;
  }
}

// ログシートの作成・取得
function getLogSheet(ss) {
  let logSheet = ss.getSheetByName('実行ログ');
  if (!logSheet) {
    logSheet = ss.insertSheet('実行ログ');
    logSheet.getRange('A1:C1').setValues([['タイムスタンプ', 'ログレベル', 'メッセージ']]);
    logSheet.getRange('A1:C1').setBackground('#f3f3f3').setFontWeight('bold');
  }
  return logSheet;
}

// ログを記録する関数
function logMessage(ss, level, message) {
  // ssが定義されていない場合は取得する
  if (!ss) {
    try {
      ss = SpreadsheetApp.getActiveSpreadsheet();
    } catch (e) {
      console.log(`[${level}] ${message} (ログシートにアクセスできません: ${e.message})`);
      return;
    }
  }
  
  try {
    const logSheet = getLogSheet(ss);
    const timestamp = Utilities.formatDate(new Date(), 'GMT+9', 'yyyy/MM/dd HH:mm:ss');
    logSheet.appendRow([timestamp, level, message]);
    console.log(`[${level}] ${message}`);
  } catch (e) {
    console.log(`[${level}] ${message} (ログ記録中にエラー: ${e.message})`);
  }
}

// メインの実行関数
function extractGmailToSpreadsheet() {
  try {
    // 現在アクティブなスプレッドシートを取得
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    logMessage(ss, 'INFO', '処理を開始しました');
    
    // 期間とアドレス指定シートを取得
    const configSheet = ss.getSheetByName('期間とアドレス指定');
    if (!configSheet) {
      throw new Error('「期間とアドレス指定」シートが見つかりません');
    }
    
    // 設定を取得
    const startMonth = configSheet.getRange('B3').getValue(); // 抽出開始月
    const endMonth = configSheet.getRange('B4').getValue(); // 抽出終了月
    const senderEmail = configSheet.getRange('B6').getValue(); // 送信元メールアドレス
    
    logMessage(ss, 'INFO', `取得した設定値 - 開始月: [${startMonth}], 終了月: [${endMonth}], 送信元: [${senderEmail}]`);
    
    // 設定値の検証
    if (!startMonth || !endMonth) {
      const errorMsg = '抽出開始月と抽出終了月を入力してください';
      logMessage(ss, 'ERROR', errorMsg);
      throw new Error(errorMsg);
    }
    
    // 日付形式の確認と変換
    let startMonthStr = '';
    let endMonthStr = '';
    
    if (startMonth instanceof Date) {
      // Date型の場合
      const year = startMonth.getFullYear() % 100; // 西暦の下2桁
      const month = startMonth.getMonth() + 1; // 0始まりなので+1
      startMonthStr = `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}`;
      logMessage(ss, 'INFO', `開始日付をYYMM形式に変換しました: ${startMonth} -> ${startMonthStr}`);
    } else if (isDateString(String(startMonth))) {
      // 日付文字列の場合
      const date = new Date(String(startMonth));
      const year = date.getFullYear() % 100; // 西暦の下2桁
      const month = date.getMonth() + 1; // 0始まりなので+1
      startMonthStr = `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}`;
      logMessage(ss, 'INFO', `開始日付文字列をYYMM形式に変換しました: ${startMonth} -> ${startMonthStr}`);
    } else {
      // 通常の値の場合(YYMM形式を想定)
      startMonthStr = String(startMonth);
    }
    
    if (endMonth instanceof Date) {
      // Date型の場合
      const year = endMonth.getFullYear() % 100; // 西暦の下2桁
      const month = endMonth.getMonth() + 1; // 0始まりなので+1
      endMonthStr = `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}`;
      logMessage(ss, 'INFO', `終了日付をYYMM形式に変換しました: ${endMonth} -> ${endMonthStr}`);
    } else if (isDateString(String(endMonth))) {
      // 日付文字列の場合
      const date = new Date(String(endMonth));
      const year = date.getFullYear() % 100; // 西暦の下2桁
      const month = date.getMonth() + 1; // 0始まりなので+1
      endMonthStr = `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}`;
      logMessage(ss, 'INFO', `終了日付文字列をYYMM形式に変換しました: ${endMonth} -> ${endMonthStr}`);
    } else {
      // 通常の値の場合(YYMM形式を想定)
      endMonthStr = String(endMonth);
    }
    
    if (!startMonthStr || !endMonthStr) {
      const errorMsg = '日付形式の変換に失敗しました。YYMMの形式(例: 2501)で入力するか、有効な日付を入力してください。';
      logMessage(ss, 'ERROR', errorMsg);
      throw new Error(errorMsg);
    }
    
    logMessage(ss, 'INFO', `検証済み設定 - 期間: ${startMonthStr}~${endMonthStr}, 送信元: ${senderEmail}`);
    
    // 期間の計算
    const periods = calculatePeriods(startMonthStr, endMonthStr);
    
    // 各期間に対して処理を実行
    for (const period of periods) {
      try {
        processEmailsForPeriod(ss, period, senderEmail);
      } catch (periodError) {
        logMessage(ss, 'ERROR', `期間「${period}」の処理に失敗しましたが、次の期間の処理を続行します: ${periodError.message}`);
      }
    }
    
    logMessage(ss, 'INFO', '処理が完了しました');
    try {
      SpreadsheetApp.getUi().alert('Gmailからのデータ抽出が完了しました。「実行ログ」シートで詳細を確認できます。');
    } catch (uiError) {
      logMessage(ss, 'WARN', `UIでのアラート表示に失敗しました。これはスクリプトがバックグラウンドで実行されている可能性があります: ${uiError.message}`);
    }
  } catch (error) {
    const errorMsg = `実行中に致命的なエラーが発生しました: ${error.message}`;
    try {
      // ssが定義されている場合のみログシートに記録
      if (typeof ss !== 'undefined') {
        logMessage(ss, 'ERROR', errorMsg);
      } else {
        console.error(errorMsg);
      }
    } catch (logError) {
      console.error(errorMsg);
      console.error(`さらにログ記録中にもエラーが発生しました: ${logError.message}`);
    }
  }
}

// 期間の計算関数
function calculatePeriods(startMonth, endMonth) {
  try {
    // スプレッドシートの参照を取得
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    
    // 入力値を文字列に変換
    let startMonthStr = String(startMonth);
    let endMonthStr = String(endMonth);
    
    // ログに入力値の型と値を記録
    logMessage(ss, 'DEBUG', `calculatePeriods - 入力値: startMonth=${startMonthStr}(${typeof startMonth}), endMonth=${endMonthStr}(${typeof endMonth})`);

    // 手動で年と月を解析
    let startYear, startMonthNum, endYear, endMonthNum;
    
    if (startMonthStr.length === 4 && /^\d{4}$/.test(startMonthStr)) {
      // YYMMフォーマットの場合
      startYear = parseInt(startMonthStr.substring(0, 2), 10);
      startMonthNum = parseInt(startMonthStr.substring(2, 4), 10);
    } else {
      throw new Error(`開始月が不正な形式です: ${startMonthStr}。YYMMの形式(例: 2501)で入力してください。`);
    }
    
    if (endMonthStr.length === 4 && /^\d{4}$/.test(endMonthStr)) {
      // YYMMフォーマットの場合
      endYear = parseInt(endMonthStr.substring(0, 2), 10);
      endMonthNum = parseInt(endMonthStr.substring(2, 4), 10);
    } else {
      throw new Error(`終了月が不正な形式です: ${endMonthStr}。YYMMの形式(例: 2503)で入力してください。`);
    }
    
    logMessage(ss, 'DEBUG', `解析結果 - startYear=${startYear}, startMonth=${startMonthNum}, endYear=${endYear}, endMonth=${endMonthNum}`);
    
    // 解析結果の検証
    if (isNaN(startYear) || isNaN(startMonthNum) || isNaN(endYear) || isNaN(endMonthNum)) {
      throw new Error(`期間の解析に失敗しました。正しい形式(YYMM)で入力されているか確認してください。入力値: ${startMonthStr}, ${endMonthStr}`);
    }
    
    if (startMonthNum < 1 || startMonthNum > 12 || endMonthNum < 1 || endMonthNum > 12) {
      throw new Error(`月の値が不正です(1-12の範囲である必要があります): ${startMonthNum}, ${endMonthNum}`);
    }
    
    const periods = [];
    
    // 開始年月から終了年月までのすべての月を計算
    let currentYear = startYear;
    let currentMonth = startMonthNum;
    
    while (
      currentYear < endYear || 
      (currentYear === endYear && currentMonth <= endMonthNum)
    ) {
      const periodStr = `${currentYear.toString().padStart(2, '0')}${currentMonth.toString().padStart(2, '0')}`;
      periods.push(periodStr);
      
      // 月を増やす
      currentMonth++;
      if (currentMonth > 12) {
        currentMonth = 1;
        currentYear++;
      }
    }
    
    logMessage(ss, 'INFO', `計算された期間: ${periods.join(', ')}`);
    return periods;
  } catch (error) {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    logMessage(ss, 'ERROR', `期間計算エラー: ${error.message}`);
    throw error;
  }
}

// 指定した期間のメールを処理する関数
function processEmailsForPeriod(ss, period, senderEmail) {
  try {
    logMessage(ss, 'INFO', `期間 ${period} のメールを処理中...`);
    
    // シートを作成または取得
    let sheet = ss.getSheetByName(period);
    if (!sheet) {
      logMessage(ss, 'INFO', `シート「${period}」が存在しないため、新規作成します`);
      sheet = ss.insertSheet(period);
      // ヘッダー行を設定
      sheet.getRange('A1').setValue('日時');
      sheet.getRange('B1').setValue('送信先アドレス(TO)');
      sheet.getRange('C1').setValue('送信先アドレス(CC)');
      sheet.getRange('D1').setValue('送信先アドレス(BCC)');
      sheet.getRange('E1').setValue('メールタイトル');
      sheet.getRange('F1').setValue('メール内容');
      sheet.getRange('G1').setValue('添付ファイルの有無');
      sheet.getRange('H1').setValue('ラベル');
      
      // ヘッダー行の書式設定
      sheet.getRange('A1:H1').setBackground('#f3f3f3').setFontWeight('bold');
    } else {
      logMessage(ss, 'INFO', `既存のシート「${period}」を使用します`);
    }
    
    // 期間の始めと終わりの日付を計算
    const year = 2000 + parseInt(period.substring(0, 2), 10);
    const month = parseInt(period.substring(2, 4), 10);
    const startDate = new Date(year, month - 1, 1); // 月は0から始まるため-1
    const endDate = new Date(year, month, 0); // 月末日
    
    // 検索クエリを作成
    const startDateStr = Utilities.formatDate(startDate, 'GMT+9', 'yyyy/MM/dd');
    const endDateStr = Utilities.formatDate(endDate, 'GMT+9', 'yyyy/MM/dd');
    
    // クエリの作成 - 期間内かつ指定した送信元からのメール
    let query;
    if (senderEmail) {
      query = `from:(${senderEmail}) after:${startDateStr} before:${endDateStr}`;
    } else {
      query = `after:${startDateStr} before:${endDateStr}`;
      logMessage(ss, 'WARN', `送信元メールアドレスが指定されていません。すべてのメールが対象になります。`);
    }
    
    logMessage(ss, 'INFO', `検索クエリ: "${query}"`);
    
    // Gmailを検索
    logMessage(ss, 'INFO', `Gmailの検索を開始します...`);
    const threads = GmailApp.search(query);
    logMessage(ss, 'INFO', `${threads.length} スレッドが見つかりました`);
    
    if (threads.length === 0) {
      logMessage(ss, 'WARN', `期間 ${period} には該当するメールはありませんでした`);
      return;
    }
    
    // データを格納する配列
    const data = [];
    
    // 各スレッドを処理
    let processedMessageCount = 0;
    for (let i = 0; i < threads.length; i++) {
      const thread = threads[i];
      logMessage(ss, 'DEBUG', `スレッド ${i+1}/${threads.length} を処理中...`);
      
      const messages = thread.getMessages();
      logMessage(ss, 'DEBUG', `スレッド内の ${messages.length} メッセージを処理します`);
      
      // 各メッセージを処理
      for (let j = 0; j < messages.length; j++) {
        const message = messages[j];
        
        try {
          // メッセージの送信日時
          const date = message.getDate();
          
          // 送信先(TO)
          const to = message.getTo() || '';
          
          // CC
          const cc = message.getCc() || '';
          
          // BCC(GASではBCCを直接取得できないため空文字を入れる)
          const bcc = '';
          
          // メールタイトル
          const subject = message.getSubject() || '';
          
          // メール内容
          const body = message.getPlainBody() || '';
          
          // 添付ファイルの確認
          const attachments = message.getAttachments();
          const hasAttachments = attachments.length > 0 ? 'あり' : 'なし';
          
          // ラベル
          const labels = thread.getLabels().map(label => label.getName()).join(', ');
          
          // データを配列に追加
          data.push([
            Utilities.formatDate(date, 'GMT+9', 'yyyy/MM/dd HH:mm:ss'),
            to,
            cc,
            bcc,
            subject,
            body,
            hasAttachments,
            labels
          ]);
          
          processedMessageCount++;
          
          // 25件ごとにログを出力
          if (processedMessageCount % 25 === 0) {
            logMessage(ss, 'INFO', `${processedMessageCount}件のメールを処理しました`);
          }
        } catch (messageError) {
          logMessage(ss, 'ERROR', `メッセージの処理中にエラーが発生しました: ${messageError.message}`);
        }
      }
    }
    
    // シートにデータを書き込む
    if (data.length > 0) {
      logMessage(ss, 'INFO', `${data.length}件のメールデータをシート「${period}」に書き込みます...`);
      sheet.getRange(2, 1, data.length, 8).setValues(data);
      logMessage(ss, 'INFO', `${data.length}件のメールデータをシート「${period}」に書き込みました`);
    } else {
      logMessage(ss, 'WARN', `処理されたスレッドはありましたが、書き込むデータがありませんでした`);
    }
  } catch (error) {
    logMessage(ss, 'ERROR', `期間「${period}」の処理中にエラーが発生しました: ${error.message}`);
    throw error;
  }
}

// メニューを追加
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('Gmail抽出')
      .addItem('Gmailデータを抽出', 'extractGmailToSpreadsheet')
      .addItem('ログシートをクリア', 'clearLogSheet')
      .addToUi();
}

// ログシートをクリアする関数
function clearLogSheet() {
  try {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const logSheet = ss.getSheetByName('実行ログ');
    
    if (logSheet) {
      // ヘッダー行を残して削除
      const lastRow = logSheet.getLastRow();
      if (lastRow > 1) {
        logSheet.getRange(2, 1, lastRow - 1, 3).clearContent();
      }
      SpreadsheetApp.getUi().alert('ログシートがクリアされました');
    } else {
      SpreadsheetApp.getUi().alert('ログシートが見つかりません');
    }
  } catch (error) {
    console.error(`ログシートのクリア中にエラーが発生しました: ${error.message}`);
    SpreadsheetApp.getUi().alert(`エラーが発生しました: ${error.message}`);
  }
}

このGASコードを使うことで、指定した期間(例えば3ヶ月や4ヶ月)に、指定したメールアドレスから送ったGmailの送信履歴を抽出できるようになったのです。

正確にはスプレッドシートの一番左端のシートに次の内容を入れて、指定しないといけません。入力するセルの位置だけ間違えないように注意してください。

1時間でGmailの抽出ができたことには正直驚きました。

簡単なのに、なぜ広がらないのか? 最初の壁

こんなに簡単に作れてしまうなら、もっと世の中に、この便利なものをそれぞれが自分の仕事で困っていること、大変なことを自動的にやれるようにするような文化やアクションが増えてもいいのでは?と思いました。

しかし、現実にはなかなか難しい面もあると感じています。
では、どこが難しいのか、どう乗り越えられるのかを考えてみました。

まず世の中に中々広がらないと思ったのは、「コードをAIで作れる」というのは皆さんも耳にしたことがあると思いますが、では「何」をシステムにやらせたいのかを言語化する難しさがある点です。

いわゆる、お仕事でいう「要件定義」のような部分が難しいのだろうな、と感じました。

参考:Google Apps Script(GAS)とは?

今回使ったGAS(Google Apps Script)は、Googleが提供しているクラウドベースの言語であり、開発プラットフォームです。

  • Google Workspace(スプレッドシート、Gmail、カレンダーなど)の自動化
  • Slack、Chatwork、LINEなど外部サービスとの連携

などが可能です。(私も詳しくは分かっていませんが、そう書いてありました)

具体的なAI活用プロセス

より正確に、今回私が行った手順を説明します。

  1. 何を実現したいか」をChatGPTに相談しながら整理
  2. その内容をNotionにメモ
  3. Notionからメモした内容をダウンロード
  4. Claudeにその内容を貼り付け
  5. Claudeに「これを実現するGASを書いて」と丸投げw
  6. Claudeがコードを作成
  7. そのコードをGoogleスプレッドシートのGASエディタに貼り付け
  8. 発生したエラーを(Claudeに聞きながら)修正
  9. 完成

このような流れです。

8.のエラーの修正も実行して出てきたエラーをスクショしてClaudeに貼り付けて「対応して。」と依頼しただけです。エラーの箇所が細かく出るように5.で指定するとかちょっとしたコツはありますが、本当にコツだけです。専門的な知識ではないかな。

AIに「伝える」ことの重要性

ここでやはり大事だなと思ったのは1.の「何をどう実現(自動化)したいのか」をきちんとChatGPTと相談しながら言語化しからこそ、Claude(AI)も伝えた内容を実現するGASコードをスグに作れたのだと思います。

部活なので、ざっくりとですがこんな感じです。

生成AIを使ったGAS活用の壁:要件の具体化

ChatGPTに相談しながら「自分が何をしたいのか」を具体化したので、Claudeにお願いした時にそれを実現するコードができたと思った話は、ご紹介した通りです。

例えば、「Gmailの特定の件名のメールを集めてスプレッドシートに一覧化してほしい」と頼んだとします。
人間相手なら「大体このくらいの期間かな?」「よしなにやっておいて」で通じるかもしれません。

しかし、システムに指示する場合、

  • 期間は?(例:3年前まで遡る?)
  • スレッド形式の場合はどうする?
  • 特定のメールアドレスとは、どれ?
  • スプレッドシートのどこに(どのセル、どの列に)どう書き込む?

といった具体的あな指示があった方がエラーも少なく、後から修正する必要もなくなると思います。これらが曖昧だと、AIはコードを作れないか、作れてもエラーが起きやすくなると思います(ただ、できなくはないですし、最初はエラーが出て修正しながらでもいいと思います)

日常業務の「感覚」とシステムの「厳密さ」

これが、なかなかAIによる自動化が広がらないポイントだと感じています。

日々の業務で、私たちは「あのメールに対応したっけ?」「これ前に来たな」「このメール集めておいて」といった処理を感覚的に行っています。

「メールを集めて」と依頼されると、人間なら(おそらく不要であろう)3年前まで遡ったりはせず、文脈から必要な範囲を推測するでしょう。大体このメールの内容が欲しいんだろうな、という勘所をもって、なんとなく集めて報告・確認しながら仕事を進めることが多いはずです。

しかし、システムに落とし込む場合は、「どの期間の」「どのメールアドレスの」情報を「スプレッドシートのどこに」「どういう形式で」入れるのかを、具体的に指定してあげる必要があります。

この、日々の業務のやり方と、システムに落とし込む際の具体性(粒度)の違いが、大きな壁になっていると感じます。

それは、日々感覚でやっちゃっていることを言語化するのが難しいからだと思います。

今後の可能性:AIが「感覚」を理解する?

もちろん、これがもうちょっと時代が進むと、AIがもっと感覚的に「何をやりたいのか」を忖度して実現してくれるようになるかもしれません。

私たちが日頃、仕事を進めながら「なんとなくこういうことをやって、こうやっていったら上手くいくだろうな」と感覚的にやり方を学んでいくプロセスは、AI技術の一つであるディープラーニングに近いものがあると感じています。

ディープラーニングは、例えば猫の画像を大量に読み込ませると、機械が勝手に「この特徴の、こういう形状のものは、いわゆる猫なのである」ということを自分で学ぶ、といった技術です(ざっくりですが)。

なので、私たちが普段感覚的にやっている業務のやり方も、いずれAIが学習してくれるかもしれません。

しかし、現時点ではまだ、その手前の「言語化」のハードルが高いため、なかなか業務効率化が進みにくいのだろう、というのが私の考えです。

どうすればいいか?:「まずやってみる」ことの重要性

では、どうすればこの壁を乗り越えられるでしょうか?

私の答えはシンプルで、「まずやってみること」が一番早いと考えています。

簡単にツールを作れる時代だからこそ、小さくてもいいから試してみる。これがすごく重要なのではないでしょうか。

皆さんも、最初にExcelやPowerPointを触り始めた時(大学生くらい? 高校生でも使うかな?)は戸惑ったはずです。今やプログラミングも学校で必修化されていますが、最初は誰でも手探りです。

でも、やっていくうちに、なんとなく勘所がわかってくるものですよね。

ビジネスサイドとエンジニアサイドの溝を埋める

この「やってみる」経験が、会社で何かを自動化・効率化したい時の大きなハードルである、ビジネスサイドとエンジニアサイドのギャップを埋める助けになります。

  • ビジネスサイド: 何をやりたいかは明確だが、技術的な制約(サーバー、API、言語の限界など)が分からない。
  • エンジニアサイド: 技術的な制約は分かるが、ビジネス要求の意図を完全に汲み取って実装するのが難しいことがある。

ここでビジネスサイドが「小さく試してみる」ことで、「あ、ここまで具体的にしないとダメなんだ」「こういうエラーが出るんだ」という感覚が掴めます。

コードを直接書かなくても、ClaudeのようなAIを介して「何かを作って自動化してみる」という経験をすると、「ここまで具体化したら実現できるんだな」「このエラーってこういう風に起こるのね」「これとこれを組み合わせられるんだ」といったイメージが湧いてきます。

このイメージがあると、社内で「何をどう自動化したいのか」「どうすれば楽になるのか」という話を、より建設的に進めやすくなるのではないでしょうか。

いますぐ試せること

今回使ったGASのコードもブログに貼っておくので、ぜひ試してみてください。(※ここにブログ記事へのリンク等を挿入してください)

Google Apps Scriptのエディタを開いて、コードを貼り付けて、自分のGmail履歴を抽出してみる。(データはどこにも送信されないので安心してください。手元のスプレッドシートで確認できます)

これだけでも、「あ、これって便利かも」という最初の体験は得られるはずです。

やり方が分からなくても、「なんかこういうことができるらしいんだけど、やり方教えて」とGPTに聞けば、教えてくれます。
万が一エラーが出ても、そのエラー画面をスクリーンショットして「こんなエラーが出たから直して」と言えば、直してくれます。

それくらい、今は楽にできるようになっています

最初から完璧にできる必要はありません。
特にエンジニアではない側が、まずAIを使ってコードに触れてみて、「コードってどういう風に動くのか」「どこに貼り付けると何ができるのか」を体験してみることが、業務効率化の第一歩として、すごく踏み出しやすくなるのではないかと思いました。

まとめ|まずは試してみよう

  • 生成AIを使えば、GASを始めとする簡単なシステムは、今や本当に手軽に作れる時代です。
  • しかし、それを活かすためには「何をどうしたいのか」を具体的に伝える力が必要です。
  • その力は、訓練で身につけることができるはずです。

まずは、今回のコードをブログからコピペして、Gmailを抽出してみる。やってみて、自分のなかで「これ自動化できたら楽だな」と思うことをピックアップして、AIに作らせてみる。

そんなことから始めてみてはいかがでしょうか。

便利なツールは、もう皆さんの手元にあります。あとは、私たちがそれをいかに楽しんで、やり始めてみるかだけだと思うんですよね。

今日の話が、同じようにDXや自動化に取り組む方々のヒントになれば嬉しいです。SNSでは、実際にやっている作業風景や効率化の流れを、失敗も含めて発信していますので、もしよかったら見てやってください。

それでは、今日はありがとうございました。

誤解しないでほしいこと:エンジニアの仕事はなくならない

ここで勘違いしてはいけないのは、これがプロフェッショナルなエンジニアの方々の仕事がなくなる、ということでは全くないなと思っています。

システムが大きくなって、関連するシステムが多くなったり、コード量が増えたりすればするほど、より多くのことを考慮し、経験がある人が作った方が、上手く進みますし、綺麗に動きますし、エラーも少なく、保守もしやすいです。餅は餅屋。その領域はプロに任せるべきだし、人が介在しないとまだまだできないんじゃないかなと思います。

ただ、そのプロに「何をしてほしいのか」を伝えるためにも、まずは小さなことから自分で始めてみて、勘所を掴んでおくことも大事だなという話でした。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次