Videos Move fast while maintaining quality with black box testing

Description

สร้างระบบแบบรีบๆ เลยไม่ได้เขียนเทส พอไม่มีเทสโค้ดก็พันกันไปหมด พอโค้ดพันกันก็เขียนยูนิตเทสต์ยาก พออยากจะปรับปรุงโค้ดก็ไม่กล้าเพราะกลัวพังเพราะไม่มีเทส ในหัวข้อนี้เลยอยากแชร์แนวคิดและวิธีที่ผมกำลังทดลองใช้อยู่ เพื่อพยายามออกจากลูปนี้ (ไม่รู้จะออกได้ไหมนะ) Notes and references: https://dt.in.th/go/bbtt

Chapters

  • แนะนำตัวและหัวข้อการพูด 0:00
  • ปัญหาในการพัฒนาและทดสอบซอฟต์แวร์ 0:54
  • ความสำคัญของ Automated Testing 1:41
  • ความท้าทายในการทำ TDD และ unit testing 2:50
  • แนวทางการพัฒนาและทดสอบซอฟต์แวร์ที่ใช้อยู่ 5:57
  • การทำ black box testing แทน unit testing 7:02
  • การเพิ่ม testing tools เข้าไปในแอปพลิเคชัน 11:01
  • ตัวอย่างการแก้ไข bug ด้วย black box testing 12:45
  • ประโยชน์ของการออกแบบระบบแบบ multi-tenant 14:28
  • แนวคิดเรื่อง testing in production 15:35
  • ข้อควรระวังในการเขียน black box test 16:20
  • สรุปและข้อแนะนำสุดท้าย 16:50

Transcript

คำบรรยายต่อไปนี้อาจไม่ถูกต้องทั้งหมด หากคุณพบข้อผิดพลาดใดๆ คุณสามารถช่วยแก้ไขข้อผิดพลาดได้บน GitHub

แนะนำตัวและหัวข้อการพูด0:00

ก็เริ่มกันเลยดีกว่านะครับ สวัสดีครับผม ผมชื่อไทนะครับ ตอนนี้เป็น Software Engineer อยู่ที่ Eventpop ครับ อยู่ใต้ Opn นะครับ สำหรับวันนี้ผมอยากจะมาแชร์แนวคิด วิธีที่ผมกำลังลองใช้ อยู่กับโปรเจคต่างๆ นะครับ ทั้งโปรเจคส่วนตัวแล้วก็โปรเจคที่ทำงานนะครับ เพื่อที่จะทำให้ผมสามารถพัฒนา Software ได้อย่างรวดเร็ว โดยยังคงคุณภาพอยู่นะครับ

ก็หัวข้อนี้นะครับ เราจะ move fast ตามชื่อเลยนะครับ เพราะว่า สไลด์ผมเยอะนะครับ

ก่อนอื่นต้องขอบอกก่อนนะครับว่า เนื้อหาในหัวข้อนี้ ส่วนมากจะเป็นความคิดส่วนตัว จากประสบการณ์นะครับ อาจจะไม่ได้มี fact มา back แบบแน่นๆ นะครับ แล้วก็อาจจะมีช่องโหว่ เต็มไปหมดเลยนะครับ ฉะนั้นก็อย่าเพิ่งเชื่อ 100% นะครับ เพราะว่า opinion ของผมเนี่ย พอผมเรียนรู้ ผมก็เปลี่ยนความคิดตัวเองไป เรื่อยๆ นะครับ วันนี้ผมมองแบบนี้ เดือนหน้า ผมอาจจะมองอีกแบบนึงก็ได้นะครับ แต่ว่าอย่างน้อยก็หวังว่าจะได้มุมมองอะไรสักอย่าง กลับไปประยุกต์ใช้หรือ กลับไปคิดเล่นกันต่อนะครับ

ปัญหาในการพัฒนาและทดสอบซอฟต์แวร์0:54

ก็ ที่ผมอยากมาพูดหัวข้อนี้ เพราะว่ามันก็จะมีบางทีที่ ผมเข้าไปลองทำโปรเจคบางโปรเจคนะครับ แล้วก็พบว่า ผมไม่ค่อยกล้าแก้โค้ดเลยครับ ไม่ค่อยกล้าปรับปรุงโค้ดเลย แล้วความรู้สึกนั้นมันทำให้ ผมรู้สึกว่าผมทำงานได้ช้าครับ ซึ่งผมก็ไม่ค่อยชอบความรู้สึกนั้นเท่าไหร่นะ อย่างเคยมีรอบนึงครับ ที่มันมีระบบนึงที่อยู่ๆ มันทำงานช้าครับ

คนที่เข้าเว็บผ่านมือถือ รู้สึกว่าโปรแกรมมันทำงานกระตุก ผมก็เลยเข้าไป optimize มัน ก็เป็น app React นะ ก็ optimize ให้มันทำงานเร็วขึ้น ซึ่งเวลา optimize บางทีผมต้อง รื้อโค้ดหลายส่วนครับ ผมก็ทำเสร็จแล้วแหละ แต่ว่าไม่กล้า merge ไม่กล้าปล่อยขึ้น production เพราะผมกลัวว่าจะไปทำอะไรพังนะ ก็ต้องเสียเวลามา test feature ต่างๆ นะครับ เพื่อให้เกิดความมั่นใจนะครับ ยิ่งถ้า project เริ่มใหญ่เนี่ย ก็จะยิ่งใช้เวลาในการ test นาน ถึงจะมั่นใจได้นะครับ

ความสำคัญของ Automated Testing1:41

ซึ่งสิ่งที่มันจะมาช่วยก็คือ automated testing ใช่ไหมครับ ทุกคนรู้ว่าควรเขียน automated test นะครับ บางครั้งผมก็คุยกับ dev คนอื่นๆ ดูนะครับ

ถามว่าเขียน test กันหรือเปล่า บางคนที่ทำงานใน startup นะครับ ก็บอกว่าไม่มีเวลามาเขียน unit test เลย เพราะว่าต้องรีบปั่นของให้เสร็จทันเวลาเนอะ แต่พอเขียน code แบบไม่มี unit test เนี่ย code มันก็มีโอกาสที่จะพันกันมั่วไปหมดใช่ไหม พอกลับมาเขียน unit test เนี่ย กลับมาเขียนเพิ่มทีหลังแทบ จะเขียนไม่ได้เลย ถ้าเราไม่รื้อโค้ดให้มันกลับมา test ได้ แต่พอจะรื้อโค้ดเราก็ไม่กล้ารื้อ เพราะไม่มี test ใช่ไหม นอกจากไม่มี unit test แล้วเนี่ย พวก test ระดับสูงกว่า พวก API test, UI test ก็อาจจะไม่ได้เขียนนะครับ แล้วเวลาจะปล่อยของขึ้น production ทีนี้ทำยังไงนะครับ ถ้าไม่ปล่อยๆ แบบ YOLO ไปเลยนะครับ ก็อาจจะต้องไล่ทดสอบแบบ manual หรือไม่ก็โยนให้อีกทีมหนึ่งทำนะครับ เช่นทีม QA นะครับ แล้วถ้าโชคดีหน่อยนะครับ ก็ทีม QA เนี่ย ก็จะเขียน automated test ให้นะครับ แต่บางที automate test เนี่ย มัน run ได้แค่บน environment QA เราเอามา run ใน localhost มันก็ run ไม่ได้นะครับ ฉะนั้นกว่าเราจะรู้ว่า

กว่าเราจะรู้ว่าที่เราแก้ไป มันทำอะไรพัง บางที feedback loop มันก็ช้าครับ ถ้าไม่มี automate test คอยช่วยนะครับ

ความท้าทายในการทำ TDD และ unit testing2:50

ซึ่งที่ผมเคยอ่านมาเนี่ย เขาบอกว่าทีมที่แบบ high performing high performing มากๆ เนี่ย feedback loop มันควรจะสั้น เขาบอกว่าทีมควรจะสามารถ เอา code ที่พัฒนาเสร็จ ขึ้น production ได้ ภายในเวลาประมาณ 15 นาทีนะครับ อันนี้ก็กลายเป็นคำพูดว่า 15 Minutes or Bust นะครับ ซึ่งผมก็ค่อยๆ หาทางที่จะไปใกล้จุดนั้น

มากขึ้นเรื่อยๆ นะครับ ถ้าเราอยู่ในทีมที่แบ่งมี mindset เกี่ยวกับ TDD ครับ ว่าแบบไม่ว่ายังไง ไม่ว่าการเขียน test มันจะเป็นยังไงเนี่ย ยังไงเราก็ต้องมี test เพื่ออนาคตที่ยั่งยืนนะ มันก็อาจจะไปถึงจุดนั้นง่ายหน่อยนะครับ แต่ว่าแค่การจะ TDD เนี่ย ผมว่ามันก็ต้องลงทุนหาศาลเลยครับ ตั้งแต่เรื่องการศึกษาเลย ตั้งแต่สมัยที่เรียนมหาวิทยาลัยเนี่ย เรื่อง test ผมก็ได้เรียนแค่ทฤษฎี แล้วก็ภาคปฏิบัติก็ได้ทำกับตัวอย่างเบสิคๆ ครับ

พอต้องมาทดสอบโค้ดจริงๆ ก็พบว่า component นึงเนี่ย render component ย่อยอีก 100 อันนะครับ ต้องเตรียม environment ให้ component มันสามารถ run ในตัว test environment เราได้ หรือไม่ก็ต้องไปจัดการแก้ให้ component แต่ละตัว สามารถ mock ส่วนประกอบย่อยๆ อีกได้เนี่ย เอาเป็นว่าไม่ว่าไปทางไหนมันก็เหนื่อยหมดเลยครับ ขนาดผมเขียน test เองยังเหนื่อยเลย จะชวนคนในทีมมาเขียนด้วยเนี่ย ก็น่าจะยากครับ แล้วมันก็ไม่ใช่ว่า เราเรียนแค่แบบชั่วโมง 2 ชั่วโมง จะเขียน test เป็นใช่ไหม ผมมองว่ามันเป็นศาสตร์และศิลป์ เลยครับเรื่องการทำ TDD เนี่ย ตอนที่ผมเริ่มทำนะ speed ผมตก แบบ drop มากๆ เลย เพราะต้องคอยคำนึงตลอดว่า ไอ้เนี่ยจะ test ยังไงดี แถมบางทีเนี่ยผมเขียน test ที่ไม่ดี มันกลับทำให้ผมช้าลง แทนที่จะเร็วขึ้นครับ เพราะนอกจากมันจับ bug อะไรไม่ได้เลยจริงๆ แล้วเนี่ย มันยังทำให้เวลาผม refactor เนี่ย จะแก้โค้ดนิดแก้โค้ดหน่อย มันก็ fail ก็ต้องมาแก้ test ตามอะไรแบบนี้ครับ กว่าจะมาอยู่ในจุดที่รู้สึกว่า เขียน test แล้วทำให้เร็วขึ้นเนี่ยก็ใช้เวลาเป็นปีครับ ซึ่งก็นั่นแหละครับ บางทีไม่มีทรัพยากรพอ ที่จะแบบมาลงทุนกับเรื่องพวกนี้ บางทีผมเองก็ไม่มีเวลา เขียน unit test เหมือนกัน โดยเฉพาะงานที่มันแบบรีบมากๆ นะครับ มันก็เลยเหมือนว่าเราต้องเลือกเอาอ่ะ ว่าถ้าไม่ยอมลงทุนเรื่อง testing, CI/CD ก็ต้องอยู่กันแบบช้าๆ กลัวๆ จะทำอะไรทีก็ต้องรอรีวิว รอ test รอ approve นะครับ

แต่ถึงแม้จะก้าวข้ามจุดนั้นมาได้ เราก็จะเมื่อเจอด่านต่อไปครับ คือ framework นะครับ บางทีถ้าเราเขียนโค้ดตาม ท่ามาตรฐานปกติของ framework นะ มันได้ code ที่ unit test ไม่ได้ครับ ก็ต้องเปลี่ยนไป integration test แทน เราก็ต้องมาสร้าง environment สำหรับการ test นะครับ หรือไม่ ก็ต้อง refactor code ให้มัน unit test ง่ายขึ้น เช่น เอา hexagonal architecture มาใช้นะครับ แต่พอเอามาใช้เนี่ย จากเดิม code ที่อ่านง่ายๆ ตรงไปตรงมานะ เดิมมีแค่ 2 class แล้วมี controller กับ model ก็แตกเป็น 5 class ครับ break ออกจาก pattern เดิมของ framework นั้นครับ คนอื่นเข้ามาอ่านเนี่ย ก็ไม่เข้าใจแล้ว ต้องกระโดดไปกระโดดมา 5 ไฟล์ แต่ว่าทุกอย่างเนี่ย unit test ได้หมดเลยนะ แต่คุ้มหรือเปล่า ไม่รู้นะครับ ก็เอาเป็นว่า trade-off มันเยอะมากครับ แล้วก็เกิดแนวคิดต่างๆ ที่มันขัดแย้งกันมากมายนะครับ

บ้างก็แนะนำ Testing Pyramid บ้างก็บอกว่า Pyramid มัน out ไปแล้ว แนะนำ Testing Trophy แทนนะครับ บ้างก็บอกว่าการทำ end-to-end test เนี่ย เป็นไอเดียที่ไม่ค่อยดีเท่าไหร่ ก็ให้ระวังนะครับ บ้างก็บอกว่า unit test เนี่ยมันไม่ค่อยมีประโยชน์ ก็เลยไม่ค่อยเขียน แต่อย่างน้อยก็จะดูเห็นด้วยกันหมดนะครับว่า การเขียน test มันเป็นเรื่องปวดหัวมากเลยครับ

แนวทางการพัฒนาและทดสอบซอฟต์แวร์ที่ใช้อยู่5:57

สำหรับ session นี้นะครับ ผมก็จะมาพูดเกี่ยวกับ แนวทางในการ พัฒนาและทดสอบ software ที่ ผมใช้อยู่ตอนนี้นะ สำหรับผมเนี่ย มีด้วยกัน 2 ข้อ 1. คือทำ software ของเราให้มัน test ง่ายๆ ครับ เราลองสวมหมวก tester แล้ว ดูว่าตรงไหนเนี่ย ถ้าเรารู้สึกว่าตรงนั้น มัน test ยาก เราก็ไปแก้ software ของเราให้มัน test ตรงนั้นง่ายขึ้น พอทำแบบนั้นแล้วการเขียน test มันก็จะง่ายขึ้น แล้วพอเราไปถึงจุดที่ การเขียน test เนี่ย มันง่ายกว่าการทดสอบด้วยมือ ผมก็เชื่อว่าคนจะเริ่มเขียน test กันเองนะครับ อย่างที่ 2 คือถ้าเจอ bug เนี่ย ก่อนแก้ ให้เขียน test ครอบก่อนนะครับ คราวนี้สิ่งที่มันตอบโจทย์ ผมได้แบบมากๆ เลยเนี่ย มันกลับไม่ใช่การทำ unit test ครับ ผมพบว่ามันคือ black box testing นะครับ คืออะไรครับ ปกติโปรแกรมของเราเนี่ย ก็จะประกอบไปด้วยส่วนย่อยๆ ต่างๆ ใช่มั้ยครับ พวก controller components utility อะไรต่างๆ นะ การ test แบบ white box เนี่ย คือ เราเอาส่วนประกอบย่อยๆ มาแยก test กันแบบแยกๆ ชิ้นใช่มั้ยครับ แต่การ test แบบ black box คือ เราไม่สนใจเลยว่าข้างในมีอะไรนะครับ เรา test จากข้างนอกอย่างเดียวเลย ถามว่าแบบนี้ไม่ยากเหรอ ก็กลับไปที่ข้อ 1 ครับ ก็ทำให้มัน test ง่ายนะครับ เราไปดูที่ test pyramid กันก่อนนะครับ

การทำ black box testing แทน unit testing7:02

ซึ่งจริงๆ pyramid มันก็มีหลายเวอร์ชั่นมากครับ มาดูรูปนี้กันก่อน ส่วนมากเนี่ย black box test มัน จะคลุมด้านบนของ pyramid นะ คือพวก end-to-end test กับ integration test ครับ ส่วนด้านบนของ pyramid เนี่ย มักจะถูกมองในแง่ลบนะครับ เพราะว่ามันทั้งช้า ทั้งพังง่าย test flaky ง่าย แล้วเวลาพังทีเนี่ย

เราก็ไม่รู้ว่ามันพังที่จุดไหน เราก็ต้องไปคอยขุด code ไปคอย debug อีกทีอะ ก็เลยกลายเป็นคำแนะนำ ว่าให้เขียนกันน้อยๆ นะ แล้วก็ให้ไปทำ unit test เยอะๆ แทน แต่ว่าหลายครั้งเนี่ย ก็กลายเป็นว่า developer ก็ เขียนกันแต่ unit test แล้วไม่มี test ระดับ UI เลย หรือถ้ายิ่งไปกว่านั้นหน่อยเนี่ย มี unit test แล้ว test ผ่านหมดนะ แต่พอโปรแกรมพังบน production มันไม่มี log อะไรเลย เพราะว่าเชื่อ unit test กันจนเกินไปนะครับ อ่า ปัจจุบันเนี่ย เวลา ที่ผมเข้าไปใน codebase แล้วพบว่ามันไม่มี test เนี่ย เดี๋ยวนี้สิ่งที่ผมพยายามทำนะ ก็ไม่ได้เริ่มจากการเขียน unit test อีกต่อไปครับ เดี๋ยวนี้ผมจะลอง test จาก UI ลงไปก่อนนะครับ

ซึ่งบางคนเห็นผมทำแบบนี้ก็สงสัยว่าทำไมผมถึงเลือกไปทางนี้ คือแบบ unit test เนี่ย มันเร็วจริง มันเสถียรจริง มันละเอียดจริง แต่มันไม่ใช่สิ่งที่ผมต้องการตอนนั้นนะครับ ที่ผมต้องการคือไอ้นี่ครับ confidence คือเราต้องการมั่นใจว่าแก้ code ไปแล้ว มันไม่มีอะไรพังนะ เรามาดูตัวอย่าง code กันดีกว่านะครับ เราเริ่มจาก unit test ก่อนละกัน อันนี้เอามาจาก NestJS นะครับ คือเวลาเราจะเขียน unit test ให้ NestJS เนี่ย ก่อนอื่นเราต้องรู้จักพวก API testing เช่นพวก createTestingModule นะครับ ที่เป็นของที่เราต้องเรียนรู้เพิ่มนะ แล้วเราก็ต้องรู้ว่า controller ของเรา ไปเรียก service อะไรบ้าง เราจะได้ mock ได้ถูก method นะครับ ซึ่งอันนี้เรายังไม่พูดถึงข้อดีข้อเสียของมันละกัน มาเทียบกับ black box API test นะครับ

อันนี้ผมยิง status ยิง API เช็ค

status แล้วก็เช็ค response แล้วก็จบละครับ มันก็ดูง่ายกว่าเนอะ แต่ถ้าใครที่ช่างสังเกตหน่อยก็จะเกิดคำถามว่า อ้าว แบบนี้ตอนแรกเนี่ย database เราเป็น database เปล่า test ก็พังสิ หรือถ้าข้อมูลที่ใช้ใน test เนี่ย มันมีข้อมูลอื่นๆ อยู่ด้วยเนี่ย ก็พังสิ ใช่ไหมครับ ก็ใช่ครับ ก็ต้องแก้ วิธีที่ผมแก้คือผมเปิด API เพิ่มครับ เอาไว้เตรียมข้อมูลใน database พอเรายิง API เนี่ย database ก็จะมีข้อมูลที่พร้อม test นะครับ คราวนี้ถ้าใครช่างสังเกตอีกหน่อยเนี่ย ก็จะแย้งมาว่า อ้าว แบบนี้เวลาเรายิง API ทีเนี่ย ข้อมูลเก่าก็หายหมดเลยสิ

หรือถ้า API มันไม่เคลียร์ข้อมูล ข้อมูลต่างๆ มันก็ปนกันหมดเลยใช่ไหม ถ้ารันหลายๆ test พร้อมกันเนี่ย มันก็ชนกันพังเลย ซึ่งใช่ครับ ก็ต้องแก้เหมือนกัน ผมแก้โดยการทำให้ระบบของผมเนี่ย รองรับได้หลายๆ environment ใน instance เดียวนะครับ โดยแต่ละ environment เนี่ยก็จะมี มันก็จะแยกจากกันนะครับ

ก็คือระบบก็จะเป็น multi-tenant นะครับ ตอนที่เรายิง API เนี่ย ตัว API มันก็จะสร้าง environment ขึ้นมา แล้วก็เอา environment ID เนี่ย ไปใช้ใน test นะครับ ทีเนี่ย test ทุกข้อก็จะมี environment ของตัวเองนะครับ ทำให้ข้อมูลไม่ยุ่งกับข้อมูลอื่นๆ นะครับ นอกจากนี้มันก็จะทำให้ เราสามารถ run test หลายๆ test พร้อมกันได้ด้วย อ่า เนี่ยครับ ถ้าเราทำให้ app ของเรา test ง่ายนะ มันก็น่าจะเขียน test ได้ง่ายขึ้นนะครับ ผมมักจะได้ยินเขาพูดกันว่า

UI test หรือ end-to-end test เนี่ย เป็นอะไรที่เขียนยาก แล้วก็ ซึ่งมันก็ถูกครับ ถ้าเราไม่แก้ app ของเราให้มัน test ง่าย การ test ก็ย่อมเป็นเรื่องยาก ยิ่งถ้าคนเขียน app กับคนเขียน test เป็นคนละคน หรือว่าอยู่กันคนละทีม หรือว่าอยู่กันคนละบริษัท แล้วไม่ยอมมา sync กันดีๆ เนี่ย มันก็จะค่อนข้างยากนิดนึงนะครับ แต่ถ้าระหว่างที่เรา dev อยู่เนี่ย เราสวมหมวก tester ไปด้วย หรือทำงานใกล้ชิดกับคนที่ ทำพวก testing หรือ QA เนี่ย มันก็จะง่ายกันทั้งสองฝั่งนะครับ อย่างบางที่เนี่ย ผมเห็นว่า QA กับ dev เนี่ย นั่ง pair programming กันแบบเป็นเรื่องปกติ เลยนะครับ หรืออย่างในวงการอื่น นะครับ อย่างตู้เกมเนี่ย ถ้าเราเอากุญแจไปไขตรงที่หยอดเหรียญเนี่ย ข้างหลังมันก็จะมี ปุ่ม service นะครับ พอกดไปแล้วเราก็จะเจอพวก test menu ต่างๆ เนอะ ก็ทำให้ทดสอบอะไรต่างๆ ง่าย ไม่ต้องขนตู้กลับมาที่โรงงานแล้วมาแก้ใหม่เนอะ

หรือพวกโทรศัพท์หลายๆ รุ่นเนี่ยมันก็จะมีเบอร์ลับอยู่ พอเรากดเบอร์นี้ไปเราก็จะเจอ test menu นะ ซึ่งเราก็ทำแบบเดียวกัน กับแอปเราได้นะครับ ก็คือเราสามารถใส่พวก developer tool หรือ testing tool เข้าไปในแอปของเรานะครับ mobile app ก็ทำได้เหมือนกันนะ แล้วก็ใส่พวก test page, test endpoint ต่างๆ เข้าไปนะครับ

การเพิ่ม testing tools เข้าไปในแอปพลิเคชัน11:01

แล้วก็อย่าลืมป้องกัน endpoint พวกนั้นดีๆ นะครับ อย่างในแอปที่ผม develop เนี่ย บางทีผมก็ใส่ test menu เข้าไป เป็นหน้าลับอยู่ในแอปนะครับ ทำให้ผมสามารถทดสอบ components ส่วนต่างๆ ได้โดยที่ไม่ต้องเปิด storybook แยกอีก process นึง

แล้วก็อย่างอันนี้ผมทำเป็นเกมนะ เกมผมก็ใส่เพิ่มอีกหน้านึงเข้าไป ที่พอกดเข้าไปแล้วเนี่ย มันจะขึ้นหน้า result ทันที แล้วก็ทำให้สามารถ develop หน้านั้นได้โดยไม่ต้องเล่นเกมเองใหม่ทุกรอบครับ ซึ่งหน้านี้มันก็ connect กับ backend จริงๆ นะ แต่ว่าก็จะเป็น test environment นะครับ นอกจากนี้ผมก็มี route ที่เอาไว้ รัน unit test ใส่เข้าไปในแอปด้วยครับ ก็ทำให้ผมสามารถรัน unit test ได้ โดยไม่ต้องรันอีก command เพิ่มนะครับ ก็ปัจจุบันผมก็ยังเขียน unit test อยู่นะครับ แต่ผมก็จะเขียนเฉพาะกับพวก ชิ้นส่วน ที่มันอยู่ได้ด้วยตัวของมันเอง และสามารถ test ได้ โดยที่ไม่ต้อง ไป mock ไป stub ชาวบ้านเขานะครับ ผมเลิกพยายามที่จะ unit test มันทุกอย่างแล้วนะครับ และอีกอย่างหนึ่งที่ผมอยากจะแนะนำมากๆ ก็คือ พยายามให้เครื่องมือการ test มันอยู่ใกล้ๆ มือเราเข้าไว้นะครับ เราจะได้เรียกใช้ง่ายๆ ซึ่งสิ่งที่ตอบโจทย์ผมมาก ๆ คือ Playwright นะครับ

เดี๋ยวผมโชว์ตัวอย่างให้ดูนะครับ ผมลง extension Playwright ไว้นะครับ ด้านขวาผมก็เขียนโค้ดตามปกติเลย ส่วนด้านซ้ายมันจะมีรายชื่อ test ต่างๆ

พอผมกด run test มันก็จะเปิด browser แล้วก็ run test ทุกข้อเลย แล้วก็ test มันก็ควรจะ run เร็ว ๆ นะครับ คราวนี้มันก็ค่อนข้างเร็วนะ แต่ว่า Playwright ถ้าเรากด show browser ออก แล้วกด run test อีกที Playwright มันจะ run test หลาย ๆ ข้อพร้อม ๆ กันนะครับ ก็จริงอยู่ที่การ test ระดับ UI มันช้ากว่า unit test นะ

แต่ว่าเราสามารถ scale มันได้ ถ้าระบบของเราอนุญาตให้ สามารถ test หลายๆ ข้อ พร้อมกันได้นะครับ แค่นี้ผมก็ไม่ต้องเปิด terminal หลายๆ อันแล้วนะครับ

ตัวอย่างการแก้ไข bug ด้วย black box testing12:45

คราวนี้มาดูตัวอย่างจาก project จริงๆ ดีกว่านะครับ อันนี้มีคนส่ง bug report มาครับ บอกว่ามีหน้าเว็บหนึ่งที่พอกดเข้าไปแล้วเข้าไม่ได้ ผมกดเข้าไป ตู้ม พังจริงด้วย ก็มาข้อ 2 นะครับ ถ้าเจอ bug ให้เขียน test ครอบก่อนแล้วค่อยแก้ ผมลองไป debug ดูนะ ผมก็พบว่า service worker ผมมันมี bug แล้วทีนี้ผมก็ไม่รู้เหมือนกันว่า ถ้าผมจะเขียน test ครอบ service worker จะทำยังไง จะ import มายังไง แล้วจะ test behavior มันยังไง แต่ถ้าให้ผมเขียน test แบบ Playwright นะ ผมเขียนได้ทันทีเลยครับ 1. ไปที่หน้าแรก 2. รอจนกว่า service worker มันจะ activate 3. ไปหน้าที่มีปัญหา 4. เช็คว่าหน้านั้นต้อง load ขึ้น อันนี้ผมก็ลอง run test ดูนะครับ ก่อนแก้มันควรจะ fail อันนี้ครับ คือ test fail นะครับ ขึ้นสีแดงเลย ส่วนหลังจากที่ผมแก้ ผมก็กด run ดูอีกที นี่ครับ test ผ่านแล้ว ฉะนั้น เวลาเราเจอ bug แล้วถ้าเราสามารถเขียน test ครอบได้เกือบทุกครั้ง ผมถือว่าเราอยู่ในจุดที่ดีมาก ๆ เลย โดยที่แทบไม่ต้องสนเรื่อง code coverage ด้วยซ้ำ ยิ่งถ้าเรามองว่า feature ที่เรายังไม่มีเนี่ย เป็น bug นะ ทุกครั้งที่เรา implement feature ใหม่ เราก็จะมี test มาครอบอย่างน้อย 1 อันนะครับ ซึ่งสิ่งที่มันช่วยให้ผมทำได้นะ ก็คือ มันทำให้ผมมีความมั่นใจมากขึ้น

แล้วทำให้ผมสามารถปรับปรุงซอฟต์แวร์ ได้อย่างไม่ยั้งมือเลยครับ อันนี้ตัวอย่างนะครับ ผม- PR เนี่ย ผมย้ายโปรเจค

จาก Nuxt.js ไปเป็น Next.js นะครับ โปรแกรม UI เหมือนกันเลยครับ ต่างกันแค่นิดเดียว เดิม components ทั้งหมดเขียนด้วย Vue ตอนนี้เขียนด้วย React ส่วนที่ผมทำแบบนี้ได้เนี่ย เพราะว่าผมมี UI test ทั้งนั้นเลย ส่วนพวก test ระดับ components เนี่ย ถ้าไม่โยนทิ้งก็ต้องเขียนใหม่หมดใช่ไหม เพราะมันเปลี่ยน framework น่ะครับ

ประโยชน์ของการออกแบบระบบแบบ multi-tenant14:28

อีกเรื่องหนึ่งที่ผมคิดว่าทำให้ระบบมัน test ได้ง่ายนะครับ คือการออกแบบให้ service ของเราเป็น multi-tenant เนาะ นอกจากทำให้มัน test ง่ายแล้วเนี่ย มันยังช่วยลดปัญหาเวลาเราต้อง test ข้าม service ด้วย เพราะว่าถ้ามันไม่เป็น multi-tenant เนี่ย เวลาเราจะ ทดสอบที เราก็ต้อง deploy ทั้ง cluster ทุกๆ service เข้าไปบน environment นึงถึงจะ test ด้วยกันได้ แต่พอ service เราเป็น tenant แยก environment กันได้แล้วเนี่ย เราสามารถมองว่า staging ของแต่ละ service

ถือว่าเป็น private คนอื่นห้ามมายุ่ง ถ้าจะ test เนี่ย ไป test กับ staging environment ของ service ที่รันอยู่บน production แทนนะครับ แล้วก็- คือผม- อีกอย่างหนึ่งเนี่ย ถ้าไม่มี multi-tenant นะ การที่จะ run test พร้อมๆ กันได้เป็นเรื่องยาก เพราะผมเห็นบ่อยมากในหลายๆ project นะ เวลาจะ run test แต่ละข้อ เราต้อง clear database ก่อน แล้วมันเลยทำให้เรา run test หลายๆ อันพร้อมกันไม่ได้ครับ แต่ถ้าระบบเราเป็น multi-tenant นะ เราสามารถให้ test แต่ละข้อเนี่ย

มี environment ของตัวเองนะครับ แล้วก็เอา test แต่ละตัวเนี่ย ให้มัน run พร้อมๆ กัน แล้วเราค่อยไป clear test data ทิ้งจาก database ตอนท้ายสุดนะครับ

แนวคิดเรื่อง testing in production15:35

ซึ่งขั้นถัดไปนะครับ ก็คือ เราอาจจะเอา test ที่เราเขียนเนี่ย ไป run บน production ได้ด้วย คือสิ่งที่มันน่ากลัวกว่า It works on my machine นะครับ คือ It works on staging นะครับ แล้วไปพังบน Production นะครับ คือ คุณ Michael Bryzek นะครับ พูด ในหัวข้อ Testing in Production ว่ามี- บริษัทที่เขาทำอยู่เนี่ย เขาเลิกใช้ staging ไปแล้ว เพราะเขาพบว่ามันสิ้นเปลืองมาก ก็เลยไป test บน production แทนนะครับ เขาก็ยกตัวอย่างว่า ตลอดทั้งวันเนี่ย จะมี bot คอยไปซื้อสินค้า จากร้านค้าจริงๆ เลย เสร็จแล้วเขาก็ใส่โค้ดเพิ่มเข้าไป 3 บรรทัดเท่านั้น ว่า ถ้าคนที่ซื้อเป็น test user อีเมลลงท้ายด้วยเนี่ย ก็ถือว่าเป็น test user นะ แล้วก็ให้ cancel order ทิ้ง อันนี้ก็เป็นตัวอย่างหนึ่งของการ Test in Production แบบมีระบบนะครับ

ข้อควรระวังในการเขียน black box test16:20

สำหรับคนที่อยากจะลองเขียนพวก black box test เนี่ย ผมก็อยากจะฝากไว้อย่างหนึ่งว่า อย่าใช้พวก waitForTimeout หรือ sleep หรือ delay นะครับ เพราะว่า ข้อยกเว้นเนี่ยมันน้อยมาก

คือไม่ว่าเราจะสั่งให้มันรอกี่วินาทีเนี่ย ตัวเลขนั้น ถ้ามันไม่น้อยไป มันก็เยอะไปเสมอ เยอะไปเราก็รอฟรี น้อยไป test เราก็พังเนอะ ให้เปลี่ยนมาใช้วิธี เช็คซ้ำๆ ว่า test ของเรา พร้อมรันต่อหรือยังนะครับ แล้วก็ถ้ามันไม่มีตัวให้เช็คนะ ก็ ข้อหนึ่งฮะ เรากลับไปแก้แอปของเรา ให้มันเช็คได้นะครับ

สรุปและข้อแนะนำสุดท้าย16:50

ก็โอเค ผมหมดเวลาแล้วก็อยากจะฝากไว้ว่า

ปัจจุบันเนี่ย เครื่องมือในการทำ black box testing เดี๋ยวนี้มันก็ดีขึ้นมากๆ ครับ แล้วก็การ debug UI test เนี่ย ในหลายๆ case มันไม่ยากเท่าเมื่อก่อนแล้ว แล้วถ้าเรา run test แบบ black box แล้วมัน debug ยากเนี่ย ผมก็มองว่า มันก็เป็นปัญหาของแอปเรานะ แอปเราควรจะ debug ง่ายๆ ด้วย เราก็กลับไปแก้แอปเรา ฉะนั้นผมก็ฝากไว้แล้วกันนะครับ ข้อหนึ่งนะครับ ทำ software ให้มัน test ได้ง่ายๆ โดยเฉพาะอย่างยิ่งถ้างานของเรามีหลาย service ก็อยากจะแนะนำว่าให้แต่ละ service เนี่ย สามารถ test ได้โดยไม่ต้องเชื่อมกับ service อื่นนะครับ อันนี้ผมเลยใช้คำว่า black box testing นะ ไม่ได้ใช้คำว่า end-to-end นะครับ แล้วก็อย่างที่สองเนี่ย ถ้าเจอ bug

ก็ให้ครอบด้วย test ก่อนที่จะซ่อมนะครับ

ก็หวังว่าเนื้อหาในวันนี้นะครับ หวังว่าจะมีไอเดียอะไรที่น่าสนใจ แล้วเราลองไปคิดเล่นกันต่อนะครับ สำหรับวันนี้ก็ขอบคุณมากครับ