iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Modern Web

來自 GAS 的香氣~跟鳳黃酥一起享受 Google Apps Script 的午茶時光系列 第 8

Day 8 — 自動化回信機(5) 優化回信機

咦?我們都寫完了,為什麼還不進入下一個專題呢?

嘖嘖,這你就不懂了!身為一個工程師,能動,只是交件標準。但是你後續如果還要維護,那麼你寫的這份爛 code 會在未來搞死你!

真心不騙!

不說別的,其實我寫這個系列時,我已經用了這個東東大概有 2 個月了,但是當我回頭整理時,驚為天人!

這是哪個王八蛋寫的 Code 啦!

心中真是充滿了三字經…

所以我特別加了一個部分是要來「優化」你的程式碼。

一方面,你可以在後續更好維護;另一方面,你在之後如果要擴增東西,也比較好處理!

但是在優化之前,我們先來解決一個 Bug!

不知道大家有沒有發現,這支程式,有一個重大的 Bug 呢?

沒錯,就是勾選拿掉一樣也會寄信!

這樣就糟糕了!如果不小心把勾勾拿掉時,使用者不就會又收到重複信件,然後引發一連串你要「客服」的問題…

所以為了不要讓未來的我們難過,我們這邊必須要額外加上一個判斷式:

function onEditTrigger() {
  const e = {
    range: SpreadsheetApp.getActiveRange()
  };
  if (e.range.isChecked()) {
    const theSheet = e.range.getSheet();
    const theRowIndex = e.range.getRow();
    const theColIndex = e.range.getColumn();
    const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
    const theData = {};
    theData.email = thisRange.getCell(1, 2).getValue();
    theData.shoolId = thisRange.getCell(1,3).getValue();
    theData.class = thisRange.getCell(1,4).getValue();
    theData.name = thisRange.getCell(1,5).getValue();
    console.log(theData);
    MailApp.sendEmail({
      to: theData.email, // 這邊我們直接把取得的 email 帶入
      subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
      body: `親愛的同學 ${theData.name} 你好
      你的密碼已經修改為「我愛兔兔教」,
      請務必記好你的新密碼!
      `
    });
    console.log(`Email已經寄出至 ${theData.email}`);
  } else {
    console.log(`取消勾選`);
  }
}

我們藉由判斷該格是否已經被勾選成為 checked 狀態來決定我們是不是要發信。

弄完之後我們回頭去驗證一下:

我們把勾勾拿掉,然後去看結果:

恩!果然不會寄信了!

但是一定有人會突發奇想:如果是修改到其他欄位呢?

我們直接來實驗吧!

果然不用擔心,因為其他欄位不是 CheckBox ,所以不存在被勾選起來的問題,因此永遠都會是 false

這邊也附上 Docs 的部分讓你好查詢相關細節: Class Range


結束了 Debug ,我們來談談其他優化的部分。

優化其實不只是將程式碼結構、速度進行優化,同時也包含了使用介面、使用體驗等等。

介面,我們是不用想了啦,就是那個試算表,但是我們可以調整程式碼結構以及使用體驗的部分!

你會問:速度呢?
這個我們先不管…

首先是程式碼結構,我們把 MailApp.sendEmail() 直接寫在 onEditTrigger() 中其實看似沒問題,但是當我們要額外擴充功能時,例如:針對每一個系統要發不同內容的信件,就會出現問題。

因此我們要修改一下,把 MailApp.sendEmail() 這個功能提取出來另外用一個函式來包裝:

function onEditTrigger() {
  const e = {
    range: SpreadsheetApp.getActiveRange()
  };
  if (e.range.isChecked()) {
    const theSheet = e.range.getSheet();
    const theRowIndex = e.range.getRow();
    const theColIndex = e.range.getColumn();
    const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
    const theData = {};
    theData.email = thisRange.getCell(1, 2).getValue();
    theData.shoolId = thisRange.getCell(1,3).getValue();
    theData.class = thisRange.getCell(1,4).getValue();
    theData.name = thisRange.getCell(1,5).getValue();
    console.log(theData);
-    MailApp.sendEmail({
-      to: theData.email, // 這邊我們直接把取得的 email 帶入
-      subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
-      body: `親愛的同學 ${theData.name} 你好
-      你的密碼已經修改為「我愛兔兔教」,
-      請務必記好你的新密碼!
-      `
-    });
+    sendMail(theData.email, theData.name)
    console.log(`Email已經寄出至 ${theData.email}`);
  } else {
    console.log(`取消勾選`);
  }
}

+function sendMail(email, name) {
+  MailApp.sendEmail({
+    to: email,
+    subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
+    body: `親愛的同學 ${name} 你好
+    你的密碼已經修改為「我愛兔兔教」,
+    請務必記好你的新密碼!
+    `
+  });
+}

不知道有沒有人注意到,之前寫過的 sendMail() 函式這邊可以拿出來用 ???
如果你還沒刪掉,那就拿出來用一用吧!

甚至,我們直接要求傳遞進 sendMail() 函式參數為 Object 型態,再用解構賦值 (註一) 的方式得到需要的內容。

這樣的好處是我們需要什麼內容,都不用再去更動到 onEditTrigger() 中的程式碼,只要去修改 sendMail() 中的參數就可以把功能進行修整了!

當然啦,這有沒有符合 Function Programming 的原則,那就是另外一回事了!
如果你想了解更多,你可以參考 註二

總之,藉由這樣的方式我們把 MailApp.sendMail() 這件事情拆出來,在後續的程式碼維護上會更佳的容易!


接下來來到了體驗的優化。

就請你想想看,如果今天你申請了三種不同的系統,但是你都收到同一種信件,這樣合理嗎?

當然不合理啊!

所以我們必須要在寄信時,順便判斷他究竟是哪一個系統,來決定我需要寄出哪一封信。

這邊,我決定跟著上面的步伐,將這個「選擇寄出信件內容」的功能額外拆分出來,獨立成一個 Function:

function selectMailContent(name, system) {
  return `親愛的同學 ${name} 你好
  你申請了 ${system} 的密碼重設,
  系統管理員已經將您的密碼重新設為 「${system === "A 系統" 
   ? "我愛兔兔教"
   : system === "B 系統" ? "兔兔叫好聽"
   : "這是兔兔教你知道的"
  }」
  請務必記好你的新密碼!
  `;
}

這邊我使用了「三元運算子」(註三) 來決定我要發出去什麼內容

接著將我的程式碼替換進去:

function onEditTrigger() {
  const e = {
    range: SpreadsheetApp.getActiveRange()
  };
  if (e.range.isChecked()) {
    const theSheet = e.range.getSheet();
    const theRowIndex = e.range.getRow();
    const theColIndex = e.range.getColumn();
    const thisRange = theSheet.getRange(theRowIndex, 1, 1, theColIndex);
    const theData = {};
    theData.email = thisRange.getCell(1, 2).getValue();
    theData.shoolId = thisRange.getCell(1,3).getValue();
    theData.class = thisRange.getCell(1,4).getValue();
    theData.name = thisRange.getCell(1,5).getValue();
+    theData.name = thisRange.getCell(1,6).getValue();
    console.log(theData);
    sendMail(theData)
    console.log(`Email已經寄出至 ${theData.email}`);
  } else {
    console.log(`取消勾選`);
  }
}

-function sendMail({email, name}) {
+function sendMail({email, name, system}){
  MailApp.sendEmail({
    to: email,
    subject: "【系統信件 請勿回復】就是愛兔兔教,兔兔教是唯一真神!",
-    body: `親愛的同學 ${name} 你好
-    你的密碼已經修改為「我愛兔兔教」,
-    請務必記好你的新密碼!
-    `
+    body: selectMailContent(name, system)
  });
}

function selectMailContent(name, system) {
  return `親愛的同學 ${name} 你好
  你申請了 ${system} 的密碼重設,
  系統管理員已經將您的密碼重新設為 「${system === "A 系統" 
   ? "我愛兔兔教"
   : system === "B 系統" ? "兔兔叫好聽"
   : "這是兔兔教你知道的"
  }」
  請務必記好你的新密碼!
  `;
}

接下來去試驗一下:

成功~


今天的教學就到這裡囉~

我們成功地完成了一個簡單的勾選寄信系統!明天就要來寫新的專題啦!

有沒有興奮啊?(終於脫離這個奇妙的輪迴了…)

今日作業:

請試著想想看還有沒有可以優化的部分呢?

我知道大家可能前面的作業都還沒做,今天先出個延伸題請大家去想一想喔~

明天見囉,掰掰!


關於兔兔們:


學生:話說回來,我們不是工程師,可不可以原本那樣寫就好?
我:只要解決問題的人,就都是工程師!所以當然還是得好好優化一下自己的程式碼啊?
學生:但是…能動就好不是嗎?這樣很麻煩耶!
我:說的也是啦…話說這次的成績,「能補考就好」對吧?加減給個 59 分好了…
學生:老師,我覺得優化是非常重要的,我馬上去進行!(溜走)

註一:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

註二:
[Javascript] Functional Programming 一文到底全紀錄

註三:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Expressions_and_Operators#%E6%A2%9D%E4%BB%B6%EF%BC%88%E4%B8%89%E5%85%83%EF%BC%89%E9%81%8B%E7%AE%97%E5%AD%90


上一篇
Day 7— 自動化回信機(4) 勾選後寄出通知信
下一篇
Day 9— 物品借用紀錄系統 (1) 基礎建構
系列文
來自 GAS 的香氣~跟鳳黃酥一起享受 Google Apps Script 的午茶時光23

尚未有邦友留言

立即登入留言