กรณีศึกษาที่เกิดขึ้นจริงเกี่ยวกับการเพิ่มประสิทธิภาพ SPA ของ React
ประสิทธิภาพของเว็บไซต์ไม่ได้ขึ้นอยู่กับเวลาในการโหลดเท่านั้น การมอบประสบการณ์การใช้งานที่รวดเร็วและตอบสนองอย่างรวดเร็วให้แก่ผู้ใช้ โดยเฉพาะสำหรับแอปเพิ่มประสิทธิภาพการทำงานบนเดสก์ท็อปที่ผู้คนใช้กันทุกวัน ทีมวิศวกรของ Recruit Technologies ได้ทำโครงการรีแฟคเตอร์เพื่อปรับปรุงเว็บแอปหนึ่งอย่าง AirSHIFT เพื่อประสิทธิภาพการป้อนข้อมูลของผู้ใช้ที่ดียิ่งขึ้น นี่คือวิธีการที่พวกเขาทำ
ตอบสนองช้า ประสิทธิภาพการทำงานลดลง
AirSHIFT เป็นเว็บแอปพลิเคชันบนเดสก์ท็อปที่ช่วยให้เจ้าของร้านค้า เช่น ร้านอาหารและคาเฟ่ สามารถจัดการงานแบบกะของพนักงาน แอปพลิเคชันแบบหน้าเดียวที่สร้างขึ้นด้วย React ประกอบไปด้วยฟีเจอร์มากมายสำหรับลูกค้า ซึ่งรวมถึงตารางตารางกริดของตารางเวลากะการทำงานที่แบ่งตามวัน สัปดาห์ เดือน และอื่นๆ
เมื่อทีมวิศวกรของ Recruit Technologies เพิ่มฟีเจอร์ใหม่ในแอป AirSHIFT พวกเขาก็เริ่มได้รับความคิดเห็นเพิ่มเติมเกี่ยวกับประสิทธิภาพที่ช้า Yosuke Furukawa ผู้จัดการฝ่ายวิศวกรรมของ AirSHIFT กล่าวว่า
ในการศึกษาวิจัยผู้ใช้ เราตกตะลึงเมื่อเจ้าของร้านค้ารายหนึ่งกล่าวว่าเธอจะออกจากที่นั่งไปชงกาแฟหลังจากที่คลิกปุ่มเพื่อจะได้ไม่ต้องรอให้ถึงคิวโหลด
หลังจากทำการวิจัยแล้ว ทีมวิศวกรก็พบว่าผู้ใช้จำนวนมากพยายามโหลดตาราง Shift ขนาดใหญ่ในคอมพิวเตอร์ที่มีสเปกต่ำ เช่น แล็ปท็อป 1 GHz Celeron M จากเมื่อ 10 ปีที่แล้ว
แอป AirSHIFT บล็อกเทรดหลักด้วยสคริปต์ราคาแพง แต่ทีมวิศวกรไม่รู้ว่าสคริปต์เหล่านั้นมีราคาแพงขนาดไหนเพราะสคริปต์เหล่านั้นกำลังพัฒนาและทดสอบคอมพิวเตอร์สเปคสูงขนาดใหญ่ที่มีการเชื่อมต่อ Wi-Fi ที่รวดเร็ว
หลังจากโปรไฟล์ประสิทธิภาพใน Chrome DevTools โดยใช้การควบคุม CPU และเครือข่าย เป็นที่แน่ชัดว่าจำเป็นต้องเพิ่มประสิทธิภาพ AirSHIFT จัดตั้งหน่วยปฏิบัติการเพื่อแก้ไขปัญหานี้ ต่อไปนี้คือ 5 สิ่งที่ทีมมุ่งเน้นเพื่อให้แอปตอบสนองต่อข้อมูลจากผู้ใช้ได้มากขึ้น
1. จำลองตารางขนาดใหญ่
การแสดงตาราง Shift ต้องใช้ขั้นตอนที่มีราคาสูงหลายขั้นตอน เช่น การสร้าง DOM เสมือนและแสดงผลบนหน้าจอตามสัดส่วนจำนวนเจ้าหน้าที่และช่วงเวลา เช่น หากร้านอาหารมีสมาชิกที่ทำงานอยู่ 50 คนและต้องการตรวจสอบกำหนดกะการทำงานรายเดือน ตารางดังกล่าวจะเป็นตารางที่มี 50 (สมาชิก) คูณด้วย 30 (วัน) ซึ่งจะทำให้เกิดคอมโพเนนต์เซลล์ 1,500 เซลล์ในการแสดงผล มีการดำเนินการที่มีราคาแพงมาก โดยเฉพาะสำหรับอุปกรณ์ที่มีสเปคต่ำ ในความเป็นจริง สิ่งต่างๆ แย่ลง จากการวิจัยพบว่า มีร้านค้าที่ต้องจัดการพนักงาน 200 คน ซึ่งต้องใช้ส่วนประกอบเซลล์ประมาณ 6,000 ชิ้นในตารางเดียวต่อเดือน
AirSHIFT ได้จัดตาราง Shift ให้อยู่ในรูปแบบเสมือนจริงเพื่อลดต้นทุนในการดำเนินการนี้ ตอนนี้แอปจะต่อเชื่อมเฉพาะคอมโพเนนต์ภายในวิวพอร์ตและยกเลิกการต่อเชื่อมคอมโพเนนต์ที่ออกนอกหน้าจอ
ในกรณีนี้ AirSHIFT ใช้ react-virtualized เนื่องจากมีข้อกำหนดในการเปิดใช้ตารางตารางกริด 2 มิติที่ซับซ้อน นอกจากนี้ ยังสำรวจวิธีเปลี่ยนรูปแบบการใช้งานดังกล่าวให้ใช้กรอบเวลารีแอ็กชันแบบเบาๆ ในอนาคตด้วย
ผลลัพธ์
การจำลองการทำงานของตารางเพียงอย่างเดียวช่วยลดเวลาในการเขียนสคริปต์ลง 6 วินาที (เมื่อใช้ทำให้ CPU ช้าลง 4 เท่า + สภาพแวดล้อม Macbook Pro ที่มีการควบคุม 3G แบบเร็ว) นี่เป็นการปรับปรุงประสิทธิภาพที่ได้ผลมากที่สุดในโปรเจ็กต์การเปลี่ยนโครงสร้างภายใน
2. ตรวจสอบด้วย User Timing API
ต่อมา ทีม AirSHIFT ได้เปลี่ยนโครงสร้างสคริปต์ที่ทำงานตามข้อมูลของผู้ใช้ แผนภูมิ Flame ของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ช่วยให้วิเคราะห์สิ่งที่เกิดขึ้นจริงในเทรดหลักได้ แต่ทีม AirSHIFT พบว่าการวิเคราะห์กิจกรรมแอปพลิเคชันตามวงจรของ React นั้นทำได้ง่ายขึ้น
React 16 จะแสดงการติดตามประสิทธิภาพผ่านทาง User Timing API ซึ่งคุณแสดงภาพได้จากส่วนการจับเวลาของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome AirSHIFT ใช้ส่วนการจับเวลาเพื่อหาตรรกะที่ไม่จำเป็นซึ่งทำงานอยู่ในเหตุการณ์วงจรของ React
ผลลัพธ์
ทีม AirSHIFT ได้ค้นพบว่าการกระทบยอดต้นไม้โดยไม่จำเป็นเกิดขึ้นก่อนการนำทางทุกเส้นทาง ซึ่งหมายความว่ารีแอ็กชันอัปเดตตาราง Shift โดยไม่จำเป็นก่อนการนำทาง การอัปเดตสถานะ Redux โดยไม่จำเป็นคือสาเหตุของปัญหานี้ การแก้ไขประหยัดเวลาในการเขียนสคริปต์ได้ประมาณ 750 มิลลิวินาที AirSHIFT ทำการเพิ่มประสิทธิภาพย่อยอื่นๆ ด้วยเช่นกัน ซึ่งส่งผลให้เวลาในการเขียนสคริปต์ลดลงทั้งหมด 1 วินาที
3. โหลดคอมโพเนนต์แบบ Lazy Loading และย้ายตรรกะราคาแพงไปให้ผู้ปฏิบัติงานที่ทำงานบนเว็บ
AirSHIFT มีแอปพลิเคชันสำหรับแชทในตัว เจ้าของร้านค้าหลายคนสื่อสารกับพนักงานของตนผ่านแชทและมองไปที่ตาราง Shift ซึ่งหมายความว่าผู้ใช้อาจกำลังพิมพ์ข้อความขณะกำลังโหลดตารางอยู่ หากเทรดหลักมีสคริปต์ที่แสดงผลตาราง อินพุตของผู้ใช้อาจมีคุณภาพต่ำ
เพื่อปรับปรุงประสบการณ์การใช้งานนี้ ตอนนี้ AirSHIFT ใช้ React.lazy และ Suspense เพื่อแสดงตัวยึดตำแหน่งสำหรับสารบัญพร้อมกับโหลดคอมโพเนนต์จริงแบบ Lazy Loading
นอกจากนี้ ทีม AirSHIFT ยังได้ย้ายข้อมูลตรรกะทางธุรกิจราคาแพงบางอย่าง ภายในคอมโพเนนต์ที่โหลดแบบ Lazy Loading ไปยังเว็บผู้ปฏิบัติงานด้วย วิธีนี้ช่วยแก้ปัญหาความยุ่งยากในการป้อนข้อมูลของผู้ใช้โดยเพิ่มพื้นที่ว่างในเทรดหลัก เพื่อให้มุ่งเน้นที่การตอบสนองต่อข้อมูลจากผู้ใช้ได้
โดยทั่วไปแล้ว นักพัฒนาซอฟต์แวร์ต้องเผชิญกับความซับซ้อนในการใช้งานผู้ปฏิบัติงาน แต่คราวนี้ Comlink ได้ช่วยแก้ปัญหาให้ ข้อมูลด้านล่างนี้เป็นรหัสจำลองที่ AirSHIFT ใช้ในการปฏิบัติงานปฏิบัติการที่มีราคาแพงที่สุดอย่างหนึ่ง ซึ่งก็คือการคำนวณต้นทุนแรงงานทั้งหมด
ใน App.js ให้ใช้ React.lazy และ Suspense เพื่อแสดงเนื้อหาสำรองขณะโหลด
/** App.js */
import React, { lazy, Suspense } from 'react'
// Lazily loading the Cost component with React.lazy
const Hello = lazy(() => import('./Cost'))
const Loading = () => (
<div>Some fallback content to show while loading</div>
)
// Showing the fallback content while loading the Cost component by Suspense
export default function App({ userInfo }) {
return (
<div>
<Suspense fallback={<Loading />}>
<Cost />
</Suspense>
</div>
)
}
ใช้comlink ในคอมโพเนนต์ต้นทุนเพื่อเรียกใช้ตรรกะ Calc
/** Cost.js */
import React from 'react';
import { proxy } from 'comlink';
// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default async function Cost({ userInfo }) {
// execute the calculation in the worker
const instance = await new WorkerlizedCostCalc();
const cost = await instance.calc(userInfo);
return <p>{cost}</p>;
}
ใช้ตรรกะการคำนวณที่ทำงานในผู้ปฏิบัติงานและเปิดเผยด้วย Comlink
// WorkerlizedCostCalc.js
import { expose } from 'comlink'
import { someExpensiveCalculation } from './CostCalc.js'
// Expose the new workerlized calc function with comlink
expose({
calc(userInfo) {
// run existing (expensive) function in the worker
return someExpensiveCalculation(userInfo);
}
}, self);
ผลลัพธ์
แม้จะมีจำนวนตรรกะที่ฝึกเป็นการทดลองได้ไม่มากนัก AirSHIFT ได้ย้าย JavaScript จากเทรดหลักไปยังเทรดของผู้ปฏิบัติงานประมาณ 100 มิลลิวินาที (จำลองด้วยการควบคุม CPU 4 เท่า)
ขณะนี้ AirSHIFT กำลังศึกษาว่าจะสามารถโหลดคอมโพเนนต์อื่นๆ แบบ Lazy Loading ได้ไหม และนำตรรกะออกไปใช้งาน Web Worker ได้มากขึ้นเพื่อลดการติดขัด
4. การตั้งงบประมาณด้านประสิทธิภาพ
เมื่อมีการนำการเพิ่มประสิทธิภาพเหล่านี้ไปใช้ ก็เป็นเรื่องสำคัญอย่างยิ่งที่จะดูแลให้แอปยังคงมีประสิทธิภาพต่อไปเมื่อเวลาผ่านไป ตอนนี้ AirSHIFT ใช้ bundlesize เพื่อไม่ให้เกินขนาดไฟล์ JavaScript และ CSS ปัจจุบัน นอกจากการตั้งงบประมาณพื้นฐานเหล่านี้แล้ว องค์กรยังสร้างแดชบอร์ดเพื่อแสดงเปอร์เซ็นต์ไทล์ต่างๆ ของเวลาที่ใช้ในการโหลดตาราง Shift เพื่อตรวจสอบว่าแอปพลิเคชันนั้นมีประสิทธิภาพแม้ในเงื่อนไขที่ไม่ดีที่สุดหรือไม่
- ตอนนี้ระบบจะวัดเวลาเสร็จสมบูรณ์ของสคริปต์สำหรับทุกเหตุการณ์ Redux แล้ว
- ระบบจะรวบรวมข้อมูลประสิทธิภาพไว้ใน Elasticsearch
- ประสิทธิภาพเปอร์เซ็นไทล์ที่ 10, 25, 50 และ 75 ของแต่ละเหตุการณ์จะแสดงด้วย Kibana
ตอนนี้ AirSHIFT กำลังตรวจสอบเหตุการณ์การโหลดตาราง Shift เพื่อให้แน่ใจว่าดำเนินการเสร็จสิ้นภายใน 3 วินาทีสำหรับผู้ใช้เปอร์เซ็นไทล์ที่ 75 งบประมาณนี้เป็นงบประมาณที่ไม่ได้บังคับใช้ในขณะนี้ แต่ทางบริษัทกำลังพิจารณาที่จะส่งการแจ้งเตือนอัตโนมัติผ่าน Elasticsearch เมื่อใช้จ่ายเกินงบประมาณ
ผลลัพธ์
จากกราฟด้านบน คุณจะบอกได้ว่าตอนนี้ AirSHIFT มีค่าใช้จ่ายถึงงบประมาณ 3 วินาทีเป็นส่วนใหญ่สำหรับผู้ใช้เปอร์เซ็นไทล์ที่ 75 และโหลดตาราง Shift ภายในวินาทีเดียวสำหรับผู้ใช้เปอร์เซ็นไทล์ที่ 25 การบันทึกข้อมูลประสิทธิภาพของ RUM จากเงื่อนไขและอุปกรณ์ที่หลากหลายทำให้ AirSHIFT สามารถตรวจสอบได้ว่าการเปิดตัวฟีเจอร์ใหม่ส่งผลต่อประสิทธิภาพของแอปพลิเคชันจริงหรือไม่
5. แฮ็กกาธอนด้านประสิทธิภาพ
แม้ว่าความพยายามในการเพิ่มประสิทธิภาพทั้งหมดนี้จะมีความสำคัญและสร้างผลลัพธ์ แต่การให้ทีมวิศวกรและทีมธุรกิจให้ความสำคัญกับการพัฒนาที่ไม่เกี่ยวข้องกับการทำงานก็ไม่ใช่เรื่องง่ายเสมอไป ความท้าทายส่วนหนึ่งก็คือเราไม่สามารถวางแผนการเพิ่มประสิทธิภาพบางอย่างได้ คำตอบเหล่านี้ต้องอาศัยการทดสอบและแนวคิดที่ลองผิดลองถูก
ตอนนี้ AirSHIFT ได้จัดแฮ็กกาธอนเกี่ยวกับประสิทธิภาพภายใน 1 วันเพื่อให้วิศวกรมุ่งเน้นเฉพาะงานที่เกี่ยวข้องกับประสิทธิภาพเท่านั้น ในแฮ็กกาธอนเหล่านี้ ทีมงานได้ลบข้อจำกัดทั้งหมดออกไปและเคารพความคิดสร้างสรรค์ของวิศวกร ซึ่งหมายความว่าการนำมาใช้งานใดๆ ที่ส่งผลต่อความรวดเร็วถือเป็นสิ่งที่ควรพิจารณาร่วมด้วย โดย AirSHIFT จะเร่งกระบวนการแฮ็กกาธอนให้แบ่งออกเป็นทีมเล็กๆ และแต่ละทีมจะแข่งขันกันเพื่อดูว่าใครจะได้รับคะแนนประสิทธิภาพของ Lighthouse เพิ่มขึ้นมากที่สุด ทุกทีมต่างแข่งขันกัน 🔥
ผลลัพธ์
วิธีแฮ็กกาธอนใช้ได้ผลกับองค์กรเหล่านี้เป็นอย่างดี
- คุณสามารถตรวจหาจุดคอขวดด้านประสิทธิภาพได้ง่ายโดยลองใช้หลายๆ วิธีในระหว่างแฮ็กกาธอน และวัดผลโดยใช้ Lighthouse
- หลังจบแฮ็กกาธอน การโน้มน้าวทีมว่าควรให้ความสำคัญกับการเพิ่มประสิทธิภาพใดสำหรับการเผยแพร่เวอร์ชันที่ใช้งานจริงนั้นก็ไม่ใช่เรื่องง่าย
- และยังเป็นวิธีที่มีประสิทธิภาพในการสนับสนุนความสำคัญของความเร็ว ผู้เข้าร่วมทุกคนสามารถเข้าใจความสัมพันธ์ระหว่างวิธีการเขียนโค้ดของคุณกับผลของประสิทธิภาพ
ผลข้างเคียงที่ดีคือทีมวิศวกรอื่นๆ มากมายภายใน Recruit สนใจแนวทางการลงมือปฏิบัตินี้ และทีม AirSHIFT ก็กำลังอำนวยความสะดวกให้กับแฮ็กกาธอนหลายความเร็วภายในบริษัท
สรุป
วิธีนี้ไม่ใช่เส้นทางที่ง่ายที่สุดในการที่ AirSHIFT ในการเพิ่มประสิทธิภาพเหล่านี้ แต่ก็ให้ผลตอบแทนที่คุ้มค่าอย่างแน่นอน ตอนนี้ AirSHIFT จะโหลดตาราง Shift ภายใน 1.5 วินาทีตามค่ามัธยฐาน ซึ่งนับว่ามีประสิทธิภาพมากขึ้น 6 เท่าจากช่วงก่อนดำเนินโปรเจ็กต์
หลังจากเปิดตัวการเพิ่มประสิทธิภาพ ผู้ใช้คนหนึ่งกล่าวว่า
ขอขอบคุณอย่างยิ่งที่ทำให้ Shift Table โหลดได้เร็ว การจัดการงานแบบกะจะมีประสิทธิภาพมากขึ้นมากในตอนนี้