น่าจะเป็น blog ที่สั้นมาก ๆ ¯\_(ツ)_/¯
IPv9 มันเป็น April Fool’s Day ของ IETF ตั้งแต่ปี 1994 แล้ว
IETF April Fool’s Day joke ดูได้จาก RFC1606 และ RFC1607RFC 1606 – A Historical Perspective On The Usage Of IP Version 9 (PDF)
Human knowledge belongs to the world!
ได้รับแผ่น AKB48 Team SH – Type B มาช่วงเต้นเดือนที่ผ่านมา แผ่นนี้ใช้เวลาสั่งค่อนข้างนานมาก เพราะฝากเพจใน facebook หิ้วจากจีนมาให้ โดยราคาขายในจีนอยู่ที่ 248 หยวน หรือประมาณ 1,200 บาท แต่พอรวมค่าหิวและส่ง ก็โดนไปเกือบๆ 1,700 บาทเลยทีเดียว
เรามาดูกันว่าตัวแผ่นทีได้มามีอะไรกันบ้าง โดยเริ่มจากเพลงที่ให้มา มี 3 เพลง Shonichi, Love Trip และ Heavy Rotation
ส่วนใน DVD MV จะเป็น MV Love Trip มาให้
คือเอาจริง ๆ ก็งง ๆ เพราะ Debut ด้วย Digital Single เพลง Love Trip แต่พอเอามาทำแผ่นขาย ดันออกมาเป็น Shonichi มาเป็นเพลงหลัก แล้วในความเป็นจริง ควรทำ MV Shonichi มาใส่เป็นเพลงแรกและ Love Trip เป็นเพลงรองมากกว่าในฐานนะโปรโมทหลักของแผ่นนี้
เรามาดูว่าในตัวกล่อง Single แบบ Type B จะมี
ในส่วนของรูปสุ่ม 1 ใบ เป็นรูปสุ่ม 21 เมมเบอร์ โดยจะได้จะได้คนละแอคกับ Type A ทำให้ถ้าอยากได้โคลสอัพก็ต้องไปซื้อเพิ่มเอาอีกทีนึง ตัวรูปห่อเป็นพลาสติกมาให้ แล้วมีสติ๊กเกอร์ 3D พร้อมหมายเลขลำดับ ส่วนกระดาษ ก็กระดาษอันรูปธรรมดา ไม่มีสกรีนด้านหลังรูปอะไรเพิ่มเติม
ในส่วนของบัตร Handshake Coupon เป็นรูปรวม มีติ๊กเกอร์ 3D พร้อมหมายเลขลำดับ ตัว QR Code ด้านบน เป็นรหัสที่สุ่มเอาไว้ลงทะเบียนจับมือ บัตรจับมือใน Type B จะไม่เหมือน Type A เพราะ Type B จะเป็นบัตรจับมือรวม ส่วน Type A เป็นแบบเดี่ยว
ของที่ให้มาแตกต่างจาก Type A คือ Hand-painted Greeting card 1 ใบ ที่สุ่มแบบทั้ง 21 แบบ จาก 21 เมมเบอร์
ส่วนสุดท้ายคือ Lyrics book และ Photo book โดยทั้งสองเล่ม ก็คล้าย ๆ กันนะ ตัว Lyrics book จะเป็นรูปเมมเบอร์ในชุดเซมบัตสึ Shonichi สลับกับตัวเนื้อร้อง ทั้งแบบเดี่ยวและรูปหมู่ไปเรื่อย ๆ หลายสิบหน้า และในส่วนของ Photo book จะเป็นรูปเมมเบอร์ในชุดสบาย ๆ ของแต่ละเมมเบอร์ โดยแต่ละเมมเบอร์จะมีรูปคนละ 4-5 รูปไปตลอดทั้งเล่ม คุณภาพเนื้อกระดาษโอเคดีมาก ส่วนภาพที่ถ่ายโดยรวมดูดีนะ เป็น 2 เล่มที่ควรมีเก็บสะสมไว้เลย
เวลาใช้ application gateway (พวก load balancer หรือ reverse proxy) ตัว error ที่พบได้บ่อย ๆ จะมี 3 ตัวหลัก ๆ (โน๊ตไว้สำหรับอธิบายในอนาคต)
1. HTTP 502 Bad Gateway
คือ request ที่เข้ามาไม่สามารถส่งต่อไปยัง back-end ได้
โดยมักจะเกิดจาก
– service ที่ handle port listening นั้นดับไป
– IP ผิด
– DNS ที่ resolve IP มาไม่ได้ IP ที่ถูกต้อง
– โดน firewall block
2. HTTP 503 Service Unavailable
คือ request ที่เข้ามาส่งต่อไปยัง back-end แล้วได้รับการตอบกลับมาเป็น Error Code ที่ถูกตั้งค่าว่าไม่ปรกติ (มักจะเป็นพวกที่ไม่ใช่ HTTP 200 OK หรือพวก HTTP 301/302 Redirect) โดยทั่วไปเกิดจากแอปส่งผลตอบกลับเป็น HTTP 500 Internal Server Error (หาก config เพิ่มเติม เราสามารถใช้การส่ง error ตัวนี้ในการปกปิด Error Code หรือ Exception Message ที่มีความเสี่ยงออกไปยัง user ได้)
3. HTTP 504 Gateway Timeout
คือ request ที่เข้ามาแล้วส่งต่อไปยัง back-end แล้ว application gateway รอการตอบกลับมานานเกินกว่าค่า timeout ที่ตั้งไว้ (ปรกติจะตั้งไว้ 30-60 วินาที) ซึ่งมักเกิดจากตัวแอปด้านหลังประมวลผลนานเกิน โดยปัญหาเกิดจากเข้าใช้งานเยอะจนตัวแอปตอบสนองต่อการใช้งานไม่ทัน (แอปอาจจะ query ข้อมูลอย่างหนัก และฐานข้อมูลก็ทำงานตอบสนองต่อตัวแอปไม่ทันอีกต่อหนึ่ง)
ปล. back-end อาจจะเป็น Web Server หรือ Application Server ก็ได้
Ref: List of HTTP status codes
เปรียบเทียบรูปโปสเตอร์เลือกตั้งที่เป็นรูปแถมจากซีดีเธียร์เตอร์ AKB48 52nd Single「Teacher Teacher」และรูปที่ปริ๊นต์จากร้านอัดรูป “Kamera no Kitamura” ที่ญี่ปุ่น ที่ได้รับลิขสิทธิ์เพื่อปริ๊นต์ ภาพอย่างถูกต้องจาก AKS
ความละเอียดของภาพไม่หนีกันเลย โดยดูจากตรงเส้นผมที่จะมาเป็นเส้นที่ชัดมากทั้งสองแบบ
โทนสว่างและมืดของภาพ ภาพจากซีดีจะมืดกว่านิด ๆ ภาพที่ปริ๊นต์เองจะสว่างกว่าเล็กน้อย (ไม่จับผิดนี่มองไม่ออก)
ด้านล่างของรูปจากซีดีจะใส่ที่มาว่ามาจากซีดี AKB48 Teacher Teacher ซึ่งมีขนาดใหญ่กว่าจากการปริ้นต์ที่จะบอกแค่บริษัทที่ถือลิขสิทธิ์ ทำให้พื้นที่ในการวางรูปโปสเตอร์ของรูปแถมจากซีดีเล็กกว่าเล็กน้อย
ด้านหลังรูป ในส่วนรูปแถม จะมีลายน้ำ AKB48 Teacher Teacher ส่วนรูปปริ้นต์จะเป็นกระดาษอัดรูปที่เราคุ้นเคยกัน คือบอกยี่ห้อกระดาษ แต่มีลายน้ำระบุชื่อไฟล์รูป และหมายเลขลำดับรูปที่สั่งปริ้นต์ออกมาแต่ละรูปจะมีลำดับเลขรันไปเรื่อยๆ
ก่อนอ่านผมอยากทำความเข้าใจก่อนว่าผมเป็นเพียงหนึ่งในทีมงาน Music We Choose You กว่าหลายสิบชีวิตเท่านั้น มีทีมงานส่วนอื่น ๆ ที่ต้องอ่านบัตรโหวต และกรอกด้วยมือโหวตลงไปบนเว็บเองอีกหลายพันโหวต ที่ไม่ได้เกิดจากกระบวนการนี้ และใน blog นี้ อาจไม่ได้กล่าวถึงชื่อทีมงานหลังบ้านเป็นรายคนได้ เพราะเพิ่งได้เจอหน้ากันก็ตอนวันลุ้นผลคะแนนเสียงเลือกตั้ง และบางคนที่เป็นทีมงานฝั่งญี่ปุ่นก็ยังไม่เจอหน้ากันจนวันนี้ แต่ทุกคนทำงานอย่างหนัก เพื่อให้ได้ซึ่งรหัสโหวตเลือกตั้งมาเข้ากระบวนการ และสุดท้ายคือผู้สนับสนุนเงินที่ร่วมกันโดเนทเข้าโครงการเพื่อให้มีเงินจำนวนมากในการจัดหารซีดี และรหัสโหวตเลือกตั้งมา นั้นหมายความว่า 18,502 คะแนน เกิดจากความร่วมแรงร่วมใจกันของทีมงาน และผู้สนับสนุนทุกคน ผมไม่ขอรับเครเดิตเหล่านี้ไว้เพียงคนเดียว ถ้ามีรายชื่อที่แน่ชัด เดี่ยวจะนำลงมาใส่ให้อีกครั้ง
ในส่วนของกระบวนการนี้ไม่ได้เป็นสิ่งใหม่อะไร แต่เป็นการสังเกต และมีต้นแบบจากคลิปจากแฟนคลับฝั่งญี่ปุ่นที่ได้ลงแนวทางปฏิบัติไว้ เรานำมาปรับปรุงและเปลี่ยนแปลงในหลาย ๆ ส่วนเพื่อให้สอดคล้องกับการทำงานในทีมอีกรอบ (ใน blog นี้บางขั้นตอนเรามี source code เปิดเผยให้ลองนำไปศึกษาต่อด้วย)
ฉะนั้นการเล่าเรื่องของกระบวนการในส่วนนี้จึงเป็นเหมือนบันทึกความทรงจำ เป็นข้อมูลอ้างอิงในอนาคตสำหรับนำไปปรับปรุงกระบวนการ และสำหรับบุคคลที่สนใจ
ตัวอย่างกระบวนการ และสิ่งที่ผมนำเป็นต้นแบบจากฝั่งญี่ปุ่น
การเขียนใน blog นี้จะมี 2 ช่วง คือช่วงก่อนประกาศผลด่วน กับช่วงหลังประกาศผลด่วน ซึ่งผมพยายามแทรกช่วงก่อนประกาศผลด่วนเพื่อให้รู้ว่าก่อนประกาศผลด่วน เราทำอะไร และนำมาปรับปรุงให้ดีขึ้นอย่างไรหลังจากประกาศผลด่วนเพื่อให้ส่งรหัสโหวตให้ได้ทัน เพราะทีมงานก็เสียดายคะแนนอีกหลายร้อยคะแนนที่ส่งขึ้นไปช่วงผลด่วนไม่ทัน เนื่องจากเรายังประสานงานระหว่างทีมกันไม่ดี ตัวชุดโปรแกรมที่ทำงานในช่วงนั้นยังเจอปัญหาติดขัด และรวมไปถึงเว็บรับรหัสโหวต AKB48 ล่มช่วงประมาณตี 2-5 ในช่วงก่อนปิดรับผลด่วน จนทำให้เราโหวตช่วงผลด่วนไปได้ไม่ตามเป้าที่วางไว้
การติดต่อประสานงานระหว่างทีมงานหลัก ๆ คือใช้ LINE และ Discord สำหรับ LINE จะใช้เพื่อสื่อสารแบบเร่งด่วน และสื่อสารกับทีมฝั่งญี่ปุ่น ส่วน Discord จะใช้ประสานงานช่วงส่งรหัสโหวต และพูดคุยแก้ไขรหัสโหวตในช่วงกลางคืนตั้งแต่ประมาณ 3 ทุ่มถึงตี 2 (มีบางวันตี 3) เหตุผลที่เราใช้เพราะการสื่อสารด้วยเสียงมันไม่ต้องพิมพ์ เพราะมือพิมพ์รหัสโหวต หรือแก้ไขข้อมูลกันอยู่ การพิพม์ LINE ทำให้งานส่วนแก้ไขรหัสโหวตหยุดชะงักได้ แล้วคุณภาพเสียงของ Discord ค่อนข้างดีไม่ค่อยเจอดีเลย์อีกด้วย
เริ่มด้วยการแสกนบัตรโหวตด้วย Fujitsu ScanSnap iX500 ซึ่งเป็น Sheet Fed Scanner ยอดนิยมมากสำหรับงานแบบนี้ โดยเราแสกนออกมาเป็น JPEG ไฟล์ โดยเหตุผลที่เราไม่แสกนออกมาเป็น PDF เพราะ ไฟล์รูปภาพบริหารจัดการง่ายกว่า หรือนำไปเปิดไฟล์เพื่ออ่านกับอุปกรณ์หลากหลาย
เมื่อได้ไฟล์รูปภาพ ทีมงานฝั่งญี่ปุ่น-ไทยตกลงกันว่าจะอัพโหลดรูปภาพผ่าน Google Drive จากญี่ปุ่นมาไทยโดยการแชร์ Folder กลางตัวหนึ่ง เพื่อใช้สำหรับการส่งไฟล์รูปภาพบัตรโหวต และเอาไว้ค้นหาสำหรับกรอกทบทวน-แก้ไขรหัสโหวตในกรณีที่นำไฟล์รูปดังกล่าวไป OCR (Optical character recognition – การแปลงไฟล์ภาพเอกสารที่เป็นรูปภาพ ให้เป็นไฟล์ข้อความตัวอักษรโดยอัตโนมัติ) แล้วไม่ได้รหัสโหวตออกมาอย่างถูกต้อง โดยเราจัดแบ่ง Folder ตามรอบที่ส่งมาจากฝั่งญี่ปุ่น โดยคนที่กำหนดชื่อเป็นฝั่งญี่ปุ่น เพราะต้องให้ทางนั้นกำหนดรหัสอ้างอิงที่เข้าใจง่ายสำหรับคนทำงานฝั่งต้นทางที่มีจำนวนแผ่น และต้องดูแลจัดการบัตรโหวตจำนวนมาก เพราะจำนวนคนฝั่งญี่ปุ่นน้อยกว่าฝั่งไทยมาก เราต้องคิดถึงการจัดการหน้างานฝั่งนั้นเป็นหลัก
ในโครงการนี้ในส่วนของการโหวต เรามีทีมงาน 2 ส่วน คือทีมกรอกมือ และกดโหวต แล้วนำรหัสโหวตที่โหวตเสร็จแล้วมาใส่ใน Google Sheets ส่วนอีกทีมคือทีมที่ผมลงมาช่วยเป็นส่วนหนึ่งของทีมงาน ซึ่งทำผ่าน OCR โดยจุดรวมของรหัสโหวตทั้ง 2 ทีมนี้ คือใช้ Google Sheets ตัวหนึ่ง เพื่อใช้สำหรับทำงานร่วมกันเพื่อแชร์ข้อมูลรหัสโหวต และการแก้ไขข้อมูล โดยทั้ง 2 ทีมมีคนกว่า 10 คนช่วยกันดู ช่วยกันแก้ไขรหัสโหวต เราเก็บรหัสโหวตต่างๆ พร้อมกับชื่อไฟล์รูปจากใน Google Drive เพื่อช่วยอ้างอิงย้อนกลับไปยังรูปต้นฉบับที่รหัสโหวตนั้นถูกกรอกมา เพราะหากรหัสโหวตนั้นใช้ไม่ได้ด้วยเหตุผลใด ๆ เราสามารถกลับไปค้นหาได้ง่าย
ในรอบส่งรหัสโหวตก่อนประกาศผลด่วนเมื่อเราได้รับการยืนยันรูปที่จะทำ OCR ได้แล้ว เราเอารูปเหล่านั้นไปเข้า OCR ทันที แล้วพบว่าความเร็วและข้อผิดพลาดมีเยอะพอสมควร ในระดับความผิดพลาด ~35% และความเร็วควรจะเร็วได้มากกว่านี้
แต่หลังจากรอบผลด่วนเราปรับปรุงกระบวนการเพิ่มด้วยการใช้โปรแกรมที่ชื่อ XnView เข้ามาเพื่อทำ resize/crop แบบ batch (GitHub – Source Code) ในส่วนของรูปก่อนส่งเข้า OCR เพื่อให้ตัว OCR มันอ่านเฉพาะจุดที่จำเป็นต้องอ่าน และได้ผลตอบกลับที่เร็วขึ้น โดยรูปหมื่นกว่ารูปผ่านกระบวนการ batch นี้ เพื่อช่วยเรื่องลดความผิดพลาดจาก OCR ให้ได้มากที่สุด และยังลดจำนวนข้อมูลที่จะต้องส่งขึ้นระบบของ Google Cloud Vision API ได้ด้วย เราเคยจับเวลา รูปบัตรโหวตกว่า 2,000 รูป เราใช้เวลาไม่ถึง 15 นาที โดยนับเวลาตั้งแต่ resize/crop รูปบัตรโหวตจำนวนดังกล่าว มาจนได้ตัวเนื้อ Text กลับออกมาจาก Google Cloud Vision API กว่า 1,800 รายการ ซึ่งเกือบทั้งหมดที่สามารถนำไปส่งรหัสโหวตเข้าระบบได้ทันที ระดับความผิดพลาดลดต่ำลงเหลือ ~20% นั้นทำให้เราได้ประโยชน์จากการใช้ไฟล์รูปภาพแทน PDF เพราะเราสามารถหาชุดโปรแกรมที่สามารถทำการ resize/crop ได้ง่ายกว่า
รูปภาพต้นฉบับ
จะได้รูปภาพที่โดน resize/crop แบบด้านล่าง
สำหรับ OCR ที่เราใช้คือ Google Cloud Vision API ด้วยเหตุผลตั้งต้นดังนี้
แต่สุดท้ายในเหตุผลข้อที่ 2 ไม่ได้ถูกนำไปใช้หลังจากวันประกาศผลด่วน แม้จุดประสงค์คือส่งรหัสโหวตขึ้น Google Sheets ให้ทีมงานคนอื่นเห็นรหัสโหวตชุดนั้นร่วมกันได้ทันที แต่เจอปัญหาใหญ่คือติด rate limit API และทำเรื่องของ request จากทีม support ของ Google แล้วการตอบสนองไม่ทันต่อการใช้งาน (รอตอบกลับ 3 วัน) ผมจึงตัดสินใจย้ายไปใช้ฐานข้อมูลอย่าง MariaDB บน Cloud แทน แล้วเอารหัสโหวตที่ได้จาก OCR ใส่ย้อนหลับไปบน Google Sheets ด้วยมือ (Google Sheets API – Usage Limits = 500 requests per 100 seconds per project, and 100 requests per 100 seconds per user.)
ในขั้นตอน OCR จนได้รหัสโหวตมานี้ ช่วยลดจำนวนงานหลังบ้านที่จะต้องกรอกรหัสโหวตลงใน Google Sheets ได้เยอะมาก โดยเราเหลือกำลังคนไว้แก้รหัสโหวตที่ผิดพลาดประมาณ 15-20% ที่เหลือแทนได้
ในส่วนของ Script ที่เราใช้ส่งรูปขึ้น Google Cloud Vision API นั้น เราใช้ PHP ที่เขียนแบบ CLI เพื่อส่งไฟล์รูปข้างต้นขึ้น Google Cloud Vision API เพื่อให้ได้ Text ออกมา แล้วใช้ Regular expression กรองรหัสโหวตตาม pattern ที่กำหนดออกมา เป็นไฟล์แบบ CSV ไฟล์ (GitHub – Source Code)
เหตุผลที่เราใช้ CSV เพราะมันสามารถ import เข้าฐานข้อมูลผ่าน HeidiSQL เครื่องมือจัดการฐานข้อมูล MariaDB (ใช้งานกับ MySQL หรือ SQL Server ก็ได้) ได้ทันที และยังสามารถเปิดแก้ไขบน Spreadsheet อย่าง Microsoft Excel หรือ Google Sheets ได้ด้วย
โดยตัว HeidiSQL สามารถ export ตัวข้อมูลย้อนกลับมาเป็น CSV เพื่อนำไปทำงานบน Google Sheets ได้ทันที ทำให้เราไม่จำเป็นต้องใช้ Script อีกตัววิ่งส่งข้อมูลไปอัพเดทผ่าน Google Sheets API ตลอดเวลา และจุดสำคัญ การได้ CSV ไฟล์ดังกล่าว สามารถเอาไฟล์ CSV นั้นไปใช้กับโปรแกรมส่งรหัสโหวตอัตโนมัติที่เราเตรียมไว้ได้ด้วย
บางคนอาจจะคิดว่าทำไมไม่ใช้ฐานข้อมูลกลางเชื่อมต่อกันไปเลย ทำไมใช้ CSV โยนให้โปรแกรมส่งรหัสโหวตอัตโนมัติ?
– เหตุผลคือเรื่องกระจายเครื่องไปหลาย ๆ เครื่องเพื่อส่งรหัสโหวต ตัวโปรแกรมดังกล่าวติดตั้งง่ายไม่ซับซ้อนมาก และคัดลอกตัว Project และ CSV ของรหัสโหวต ปรับค่านิดหน่อย ก็เริ่มต้นทำงานได้แล้ว การเชื่อมฐานข้อมูลกลางอาจจะต้องทำ whitelist IP ฯลฯ อีกหลายตัวเพื่อป้องกันโดน hack อีกชั้น ซึ่งยุ่งยากเกินไป
สำหรับตัวโปรแกรมที่ใช้ในการส่งรหัสโหวตแบบอัตโนมัตินั้น ที่ชื่อ Katalon Studio พระเอกของงานนี้ ซึ่งเป็นเครื่องมือ automation testing solution ของนักพัฒนาซอฟต์แวร์ที่ โดยอ่านข้อมูลรหัสโหวตจากไฟล์ CSV ไปส่งลงฟอร์มของเว็บ AKB48
ตัว script ภายในเขียนด้วย groovy (GitHub – Source Code) ดักจับผลการส่งรหัสโหวตมี 4 สถานะดังนี้
รูปแบบหน้าทั้ง 4 หน้าที่จะเจอเมื่อเราส่งผลโหวต
จากการใช้ Katalon Studio เราจะเก็บผลการทำงานทั้ง HTML ไฟล์ และ Screenshot ของหน้าผลการโหวตเป็น JPEG ด้วย เพื่อใช้ในการตรวจสอบต่อไปหลังจบรอบโหวต
ในช่วงก่อนประกาศผลด่วนเราไม่ได้ตรวจสอบเคสในข้อที่ 3. และ 4. แยกออกจากกัน ทำให้เราพลาดคะแนนบางส่วนไปเพราะเว็บรับรหัสโหวต AKB48 ไม่ได้เสถียรตลอดเวลา จะมีการส่ง “An error occurred.” ออกมาอยู่เรื่อยๆ แม้แต่ช่วงวันท้าย ๆ ก็ยังไม่ได้แก้ไขให้ดีขึ้น มีอยู่หลายช่วงที่เราส่งรหัสโหวตไปกว่า 1,000 รายการ แล้วโดนตีตกด้วย An error occurred. อยู่เกือบ 600 รายการ และสุดท้ายทั้งหมดที่โดนตีตกเป็นรหัสโหวตที่ใช้งานได้ทุกตัว ทำให้เราต้องคัดแยกเพื่อให้ทีมหลังบ้านที่อ่านรหัสโหวตผิดพลาดไม่ต้องไปอ่านข้อมูลที่เกิดจากตัวเว็บ AKB48 แจ้งความผิดพลาดทั้ง ๆ ที่รหัสโหวตไม่ผิดอีก เพื่อลดงานฝั่งคนแก้ไขรหัสโหวตลง
เมื่อรหัสโหวตทุกส่วนส่งครบหมดจะเหลือเฉพาะรหัสโหวตที่โหวตได้ และรหัสโหวตที่โหวตไม่ได้ เราจะเอา log ของการส่งรหัสโหวตครั้งนั้นมาอ่านด้วย PHP ที่เป็น script ตัวอ่าน log แล้วเข้าไป flag สถานะในฐานข้อมูลตามแต่ละรหัสโหวตที่มี เพื่อบอกว่าโหวตสำเร็จหรือไม่ แล้วทำการสรุปรหัสโหวตที่โหวตได้ และรหัสโหวตที่โหวตไม่ได้ แยก Worksheet บน Google Sheets ออกจากกัน โดยในส่วนของ Worksheet ที่ใส่รหัสโหวตที่ส่งแล้วผิดพลาด จะมีทีมงานอีกส่วนเข้ามาช่วยกันอ่านไฟล์รูปบัตรโหวตและกรอกรหัสโหวตที่ถูกต้องลงไปแทน แล้วเมื่อจบการแก้ไขในแต่ละ Worksheet จะรวบรวมแล้วใช้โปรแกรมอัตโนมัติส่งเข้าเว็บโหวตอีกรอบ และในส่วนรหัสโหวตที่โหวตเรียบร้อย จะมีรอบสำหรับทบทวนวัน-เวลาที่โหวตเพื่อยืนยันรหัสโหวตว่าเมื่อโหวตเข้าไปแล้ว
โดยในขั้นตอนทบทวนวัน-เวลา เราจะใช้ script ส่งรหัสโหวตชุดเดิมส่งรหัสโหวตที่ต้องการวัน-เวลาส่งเข้าไปที่เว็บ AKB48 จนได้สถานะตามข้อที่ 2 แล้วใช้ script อีกชุดเข้าไปอ่านวัน-เวลาในไฟล์ HTML ที่บันทึกไว้ เพื่อนำไปอัพเดทลงฐานข้อมูลเมื่ออัพเดทเสร็จครบทั้งสถานะและวัน-เวลาโหวต เราจะเอาผลทั้งหมดกลับขึ้นไปที่ Google Sheets เพื่อสรุปผลการโหวตในแต่ละรอบเพื่อปิดงานรอบนั้น (ในขั้นตอนทบทวนวัน-เวลานี้เราเอารหัสโหวตที่กรอกด้วยมือไปก่อนหน้านี้ของอีกทีมหนึ่ง มาเข้ากระบวนการนี้ด้วยเช่นกัน)
นั้นหมายความว่า ทุก ๆ รหัสโหวตเราส่งเข้าเว็บ AKB48 เราจำเป็นต้องส่งรหัสโหวตเข้าเว็บโหวตอย่างน้อย 2 ครั้ง แต่ผลดีคือ มันช่วยทำให้เราสรุปยอดในแต่ละวันว่าเราส่งรหัสโหวตเข้าไปได้เท่าไหร่ และช่วยให้เราเก็บคะแนนที่ตกหล่นกลับมาโหวตได้อีกพอสมควร
ตัวอย่างการทำงานในการส่งรหัสโหวตด้วย Katalon Studio
สำหรับหน้ารายงานรหัสโหวต และจำนวนโหวตที่ Actual Vote ช่วงแรกเราใช้ Firebase Realtime Database ซึ่งทำการ Sync ข้อมูลกับ Google Sheetes อีกที ช่วงแรกข้อมูล Realtime มาก กดอัพเดทจำนวนคะแนนฝั่งหน้าเว็บรายงานขึ้นคะแนนใหม่ทันที แต่ด้วยความที่เราไม่ได้ optimize อะไรเลย (คือไม่มีเวลาทำ) สุดท้ายมันก็ไม่ได้ Realtime ตลอด เจออาการ Push ไม่ทำงาน เพราะเราไม่ได้ Index ข้อมูล มันเลยหยุด Push เพราะด้วยจำนวนของ node (รหัสโหวต) เริ่มเยอะขึ้น แถมเราเจอ charge ค่า B/W ของ Firebase เยอะตามไปด้วย เลยเปลี่ยนแผนใหม่เป็นการใช้ไฟล์ JSON data แบบอัพมือแทน โดยก็แค่ Sync จาก Google Sheets ไป export เป็นไฟล์ JSON data เดี่ยว ๆ แล้วฝั่งทีมเว็บส่วนรายงานผลแค่เอาไฟล์ไปวางที่เดิมก็จบงาน ลดค่าใช้จ่ายไปได้เยอะมาก แต่ก็มาหนักฝั่ง client ซึ่งก็เป็นเรื่องที่ช่วยไม่ได้ เพราะเอาเร็วเข้าว่า แล้วช่วง 2-3 วันสุดท้ายเราไม่ได้รายงานคะแนนสุดท้าย เพราะคิดว่ารอสรุปยอดทีเดียวหลังปิดโหวตดีกว่า เพื่อให้ทีมงานทุกส่วนได้โฟกัสกับการหาบัตรโหวต และส่งรหัสโหวตเข้าระบบ AKB48 ให้ได้จนหมดโดยไม่ตกหล่น และยืนยันผลให้พร้อมทุกอย่าง เพราะเราพลาดแบบรอบผลด่วนอีกไม่ได้แล้ว
ในส่วนของเครื่องคอมฯ ที่ส่งรหัสโหวตนั้น เราใช้ทั้งหมด 3 ตัวทำงานสลับกัน มี 1 ตัวทำงานตลอด 24 ชั่วโมง 5 วันติดต่อกันเพื่อโหวตเข้าระบบ และทบทวนผลการโหวตออกมาเป็นวัน-เวลาที่โหวตเพื่อให้แน่ใจว่าคะแนนทุกคะแนนที่ถืออยู่จะเข้าระบบจริง ๆ ซึ่งหากจำนวนคะแนนในมือเยอะกว่านี้ อาจส่งไม่ทัน เพราะจากที่ลองทดสอบค่าเฉลี่ยนในการส่งโหวต สามารถทำความเร็วได้ที่ 600-800 รหัสโหวตต่อชั่วโมง (อย่าลืมว่าเราต้องเก็บตกจากเหตุการณ์เจอหน้าเว็บ Error และทวนวัน-เวลาโหวตอีก) แต่เราก็ได้เตรียมแผนรองรับไว้แล้ว ด้วยการเตรียมเช่า Cloud VPS ที่อยู่ญี่ปุ่นเพิ่มเติมสำหรับส่งรหัสโหวตเพิ่มเติมได้ทันที (คิดว่าภายใน 4-6 ชั่วโมงน่าจะสร้างเครื่อง และพร้อมส่งรหัสโหวตได้อย่างน้อย 4 ตัว หรือเพิ่มความเร็วเป็น 2,000-3,000 โหวตต่อชั่วโมง)
สรุปว่าโครงการนี้เน้นถึกเยอะมาก script อะไรต่าง ๆ บางส่วนก็เผา และ workaround กันแบบสุด ๆ เนื่องจากรีบ และไม่มีเวลามาคิดเรื่อง seamless มากนักในบางขั้นตอน (เพราะงานประจำก็ต้องทำ คะแนนที่ต้องส่งก็เยอะขึ้นกว่าที่คาดหวังไว้ด้วย ต้องเผื่อเวลาตกหล่นไว้อย่างน้อย 1-2 วัน) ตามตารางกราฟด้านล่าง
ช่วงวันประกาศผลเลือกตั้ง ค่อนข้างลุ้นมาก เพราะตอนที่ประกาศแล้วผ่านคะแนนของโครงการไปแล้ว แล้วน้องยังไม่ได้ประกาศชื่อ โดนแซวว่า “พี่ฟอร์ดทำโปรแกรมโหวตผิดคนป่าวพี่” ทีมงานก็ใจคอไม่ดี ผมก็ใจคอไม่ดี เพราะลุ้นมาก แล้วเราทบทวนรหัสโหวตและคะแนนกันเยอะมาก
แล้วสุดท้ายก็เป็นแบบวิดีโอข้างล่างเนี่ยแหละครับ
สำหรับวินาทีประกาศผลนั้น? #ยิ่งกว่าเชียร์บอล #BNK48 #MusicBNK48 #NoMusicNoLife #MusicWeChooseYou @Music48Project pic.twitter.com/KpzhUR30su
— SmartLT ยังสามคามิอยู่โว้ย (@SmartLT) June 16, 2018
หากมีอะไรอัพเดทหรือตกหล่น เดี่ยวค่อย ๆ อัพเดทใน blog ตอนนี้เพิ่มเติมอีกที เพราะตอนนี้นึกออกมาได้ประมาณนี้
ทิ้งท้าย ด้านล่างคือสรุป Workflow การทำงานในช่วง 7 วันสุดท้ายของการโหวต