4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GPT-4にGASスクリプトのコードレビューとリファクタリングをやらせてみた結果

4
Last updated at Posted at 2023-03-24

概要

にわかに騒がれて久しいgptですが、やはりエンジニアの端くれとして「こいつにプログラミングやらせてみたらどうなるんだ?」という好奇心は尽きないものです。

今回は、その一端として「レビューとリファクタリング」をやらせてみた。という内容です。

やってみたこと

以前プライベートで公開したQiitaの記事の中でオープンにしているスクリプトに対して、レビューとリファクタリングをやってみました。

使用したスクリプトはこちら(2019年作成のものなのでかなり古めかしい…)

元のスクリプト

/** 
 * reply
 * ユーザからのアクションに返信する
 */
function reply(data) {
  // POST情報から必要データを抽出
  var lineUserId = data.events[0].source.userId;
  var postMsg    = data.events[0].message.text;
  var replyToken = data.events[0].replyToken;
  var action    = data.events[0].message.action;
  // 記録用に検索語とuserIdを記録
//  debug(postMsg, lineUserId);
  debug(action, lineUserId);

  // 検索語に対しての回答をSSから取得
  var answers = findResponseArray(postMsg);

  // 回答メッセージを作成
  var replyText = '' + postMsg + '」ですね。かしこまりました。以下、回答です。';
  // 回答の有無に応じて分岐
  if (answers.length === 0) {
    // 「類似の検索キーワード」がないかチェック
    var mayBeWord = findMaybe(postMsg);
    if (typeof mayBeWord === "undefined") {
      // 回答がない場合の定型文
      sendMessage(replyToken, '答えが見つかりませんでした。別のキーワードで質問してみてください。');        
    } else {
      sendMayBe(replyToken, mayBeWord);
    }
  } else {
    // 回答がある場合のメッセージ生成
    answers.forEach(function(answer) {
      replyText = replyText + "\n\n=============\n\nQ:" + answer.key + "\n\nA:" + answer.value;
    });

    // 1000文字を超える場合は途中で切る
    if (replyText.length > 1000) {
      replyText = replyText.slice(0,1000) + "……\n\n=============\n\n回答文字数オーバーです。詳細に検索キーワードを絞ってください。";
    }
    // メッセージAPI送信
    sendMessage(replyToken, replyText);
  }
}

#やってみた

とりあえずレビューを依頼

image.png
こんなお返事が返ってきました。
image.png
ほうなるほど、どれどれ。

1. コメントへの指摘

コメントの言語が英語と日本語が混在しているため、一貫性を保つために、すべてのコメントを同じ言語(英語または日本語)に統一することをお勧めします。

仰るとおりです、直します。

2. 関数定義の確認

GASスクリプトには、findResponseArray()、debug()、findMaybe()、およびsendMessage()関数が含まれていることが前提となっていますが、これらの関数が定義されていないため、その実装が適切であることを確認してください。

あーこれはですね、大丈夫です。このファイルの外に定義してありますので動作します。ありがとう。

3. 未使用の変数

以下の行に関して、action変数がdata.events[0].message.actionから取得されていますが、これはLINEのWebhookイベントオブジェクトから直接取得することはできません。action変数は使用されていないため、この行を削除しても問題ありません。

var action    = data.events[0].message.action;

仰るとおりです。消します。

4. 仕様へのコメント

コードの一部が、特定の文字数を超えた場合にメッセージを切り取るための処理が含まれています。ただし、LINEのメッセージには最大文字数が制限されているため、代わりに複数のメッセージに分割して送信することを検討してください。

確かに。これは仕様検討します。

総評

以上の点を修正することで、コードの品質と可読性が向上すると考えられます。全体的に、良いスクリプトであると言えますが、いくつかの改善点があります。

押忍、あざす。

次に早期returnする修正を指示

雑い感じに修正指示を投げてみました。
image.png
余裕です、と返事。
image.png

修正内容

function reply(data) {
  var lineUserId = data.events[0].source.userId;
  var postMsg    = data.events[0].message.text;
  var replyToken = data.events[0].replyToken;
  // 記録用に検索語とuserIdを記録
  debug(lineUserId, postMsg);

  var answers = findResponseArray(postMsg);

  if (answers.length === 0) {
    var mayBeWord = findMaybe(postMsg);
    if (typeof mayBeWord === "undefined") {
      sendMessage(replyToken, '答えが見つかりませんでした。別のキーワードで質問してみてください。');
      return;
    } else {
      sendMayBe(replyToken, mayBeWord);
      return;
    }
  }

  var replyText = '' + postMsg + '」ですね。かしこまりました。以下、回答です。';
  answers.forEach(function(answer) {
    replyText = replyText + "\n\n=============\n\nQ:" + answer.key + "\n\nA:" + answer.value;
  });

  if (replyText.length > 1000) {
    replyText = replyText.slice(0,1000) + "……\n\n=============\n\n回答文字数オーバーです。詳細に検索キーワードを絞ってください。";
  }
  sendMessage(replyToken, replyText);
}

おおお、たしかに処理を修正するタイミングが見極められている。素晴らしい。

関数に切り出させてみた

さらに雑い感じで整理を依頼しました。果たして適切な関数に切り出しができるか。
image.png
やりよった
image.png

修正後のスクリプト

function reply(data) {
  var lineUserId = data.events[0].source.userId;
  var postMsg    = data.events[0].message.text;
  var replyToken = data.events[0].replyToken;
  
  // 記録用に検索語とuserIdを記録
  debug(lineUserId, postMsg);

  var answers = findResponseArray(postMsg);

  sendResponse(replyToken, postMsg, answers);
}

function sendResponse(replyToken, postMsg, answers) {
  if (answers.length === 0) {
    var mayBeWord = findMaybe(postMsg);
    if (typeof mayBeWord === "undefined") {
      sendMessage(replyToken, '答えが見つかりませんでした。別のキーワードで質問してみてください。');
    } else {
      sendMayBe(replyToken, mayBeWord);
    }
    return;
  }

  var replyText = buildReplyText(postMsg, answers);
  sendMessage(replyToken, replyText);
}

function buildReplyText(postMsg, answers) {
  var replyText = '' + postMsg + '」ですね。かしこまりました。以下、回答です。';
  
  answers.forEach(function(answer) {
    replyText = replyText + "\n\n=============\n\nQ:" + answer.key + "\n\nA:" + answer.value;
  });

  if (replyText.length > 1000) {
    replyText = replyText.slice(0,1000) + "……\n\n=============\n\n回答文字数オーバーです。詳細に検索キーワードを絞ってください。";
  }
  
  return replyText;
}

image.png

やりよる…命名も悪くない(気がする)。

終わりに。

ソースコド丸投げは多分業務上しばらくできない気もしますが、普段貰わない人からレビューを受けている間隔でとても新鮮でした。ご参考までに。

おまけ

Class作らせてみたりもしましたが、これは如何に(まだ未判断)

class ReplyHandler {
  constructor(data) {
    this.lineUserId = data.events[0].source.userId;
    this.userMessage = data.events[0].message.text;
    this.replyToken = data.events[0].replyToken;
  }

  processReply() {
    // 記録用に検索語とuserIdを記録
    debug(this.lineUserId, this.userMessage);

    const answers = findResponseArray(this.userMessage);

    this.sendResponse(this.userMessage, answers);
  }

  sendResponse(userMessage, answers) {
    if (answers.length === 0) {
      const mayBeWord = findMaybe(userMessage);
      if (typeof mayBeWord === "undefined") {
        sendMessage(this.replyToken, '答えが見つかりませんでした。別のキーワードで質問してみてください。');
      } else {
        sendMayBe(this.replyToken, mayBeWord);
      }
      return;
    }

    const replyText = this.buildReplyText(userMessage, answers);
    sendMessage(this.replyToken, replyText);
  }

  buildReplyText(userMessage, answers) {
    let replyText = '' + userMessage + '」ですね。かしこまりました。以下、回答です。';
    
    answers.forEach(function(answer) {
      replyText = replyText + "\n\n=============\n\nQ:" + answer.key + "\n\nA:" + answer.value;
    });

    if (replyText.length > 1000) {
      replyText = replyText.slice(0,1000) + "……\n\n=============\n\n回答文字数オーバーです。詳細に検索キーワードを絞ってください。";
    }
    
    return replyText;
  }
}

function reply(data) {
  const replyHandler = new ReplyHandler(data);
  replyHandler.processReply();
}

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?