Implementing (Those Tricky) End-to-End Tests (การ Implement End-to-End Test ที่แสนยุ่งยาก)
ใน ระบบ microservice ความสามารถที่เราเปิดเผยผ่าน user interface ของเราถูกส่งมอบโดย microservices จำนวนมาก จุดประสงค์ของ end-to-end test ตามที่ระบุไว้ใน pyramid ของ Mike Cohn คือการขับเคลื่อนฟังก์ชันการทำงานผ่าน user interface เหล่านี้ กับทุกอย่างที่อยู่ข้างใต้ เพื่อให้ feedback เกี่ยวกับคุณภาพของระบบโดยรวม
ดังนั้น เพื่อ implement end-to-end test เราต้อง deploy microservices หลายตัวพร้อมกัน แล้วรันเทสต์กับทั้งหมด แน่นอนว่าเทสต์นี้มีขอบเขตใหญ่กว่ามาก ทำให้เรามั่นใจมากขึ้นว่าระบบของเราทำงานได้! ในทางกลับกัน เทสต์เหล่านี้มักจะช้ากว่าและยากขึ้นในการวินิจฉัยความล้มเหลว ลองมาเจาะลึกกันอีกหน่อย โดยใช้ตัวอย่างก่อนหน้านี้ของเรา เพื่อดูว่าเทสต์เหล่านี้จะเข้ากันได้อย่างไร
ลองนึกภาพว่าเราต้องการผลัก Customer microservice เวอร์ชันใหม่ออกไป เราต้องการ deploy การเปลี่ยนแปลงของเราเข้าสู่ production ให้เร็วที่สุด แต่ก็กังวลว่าเราอาจนำการเปลี่ยนแปลงที่ทำให้ helpdesk หรือ web shop พังเข้ามา ไม่มีปัญหา ลองมา deploy service ทั้งหมดของเราพร้อมกัน แล้วรันเทสต์กับ helpdesk และ web shop เพื่อดูว่าเรานำบั๊กเข้ามาหรือเปล่า ทีนี้ แนวทางที่ไร้เดียงสาคงเป็นการเพิ่มเทสต์เหล่านี้ไว้ที่ท้าย pipeline ของ customer service ของเราเฉยๆ ดังใน Figure 9-7
Figure 9-7. การเพิ่ม stage ของ end-to-end test ของเรา: เป็นแนวทางที่ถูกต้องหรือไม่
จนถึงตอนนี้ก็ดูดี แต่คำถามแรกที่เราต้องถามตัวเองคือ เราควรใช้ microservice อื่นๆ เวอร์ชันไหน เราควรรันเทสต์กับ helpdesk และ web shop เวอร์ชันที่อยู่ใน production หรือเปล่า มันเป็นข้อสมมติฐานที่สมเหตุสมผล แต่จะเป็นอย่างไรถ้า helpdesk หรือ web shop เวอร์ชันใหม่กำลังต่อคิวเพื่อขึ้น live เราควรทำอย่างไรในกรณีนั้น
นี่คือปัญหาอีกอย่างหนึ่ง: ถ้าเรามีชุด end-to-end test ของ Customer ที่ deploy microservices จำนวนมากและรันเทสต์กับพวกมัน แล้ว end-to-end test ที่ microservices อื่นๆ รันล่ะ ถ้าพวกมันกำลังทดสอบสิ่งเดียวกัน เราอาจพบว่าตัวเองครอบคลุมพื้นที่เดียวกันซ้ำๆ และอาจทำงานซ้ำซ้อนกันมากในการ deploy microservices ทั้งหมดเหล่านั้นตั้งแต่แรก
เราสามารถจัดการทั้งสองปัญหานี้ได้อย่างชาญฉลาด ด้วยการให้หลาย pipeline "fan-in" เข้ามาที่ end-to-end test stage เดียว ในกรณีนี้ เมื่อ build หนึ่งในหลายๆ build ถูก trigger ก็อาจส่งผลให้ shared build step ถูก trigger ตามไปด้วย ตัวอย่างเช่น ใน Figure 9-8 build ที่สำเร็จของ microservice ใดๆ ในสี่ตัวจะจบลงด้วยการ trigger shared end-to-end test stage CI tool บางตัวที่รองรับ build pipeline ได้ดีกว่าจะเปิดใช้งาน fan-in model แบบนี้ได้ทันทีโดยไม่ต้องตั้งค่าเพิ่ม
Figure 9-8. วิธีมาตรฐานในการจัดการ end-to-end test ข้าม service
ดังนั้นเมื่อไรก็ตามที่ service ใดตัวหนึ่งของเราเปลี่ยนแปลง เราจะรันเทสต์ที่เป็น local ของ service นั้น ถ้าเทสต์เหล่านั้นผ่าน เราก็จะ trigger integration test ของเรา เยี่ยมใช่ไหม อย่างไรก็ตาม น่าเสียดายที่ end-to-end testing มีข้อเสียอยู่มากมาย
Flaky and Brittle Tests (เทสต์ที่ไม่เสถียรและเปราะบาง)
เมื่อ ขอบเขตของเทสต์เพิ่มขึ้น จำนวนชิ้นส่วนที่เคลื่อนไหวก็เพิ่มขึ้นด้วย ชิ้นส่วนที่เคลื่อนไหวเหล่านี้อาจทำให้เกิดความล้มเหลวของเทสต์ที่ไม่ได้แสดงว่าฟังก์ชันที่ถูกทดสอบพัง แต่บ่งชี้ว่ามีปัญหาอื่นเกิดขึ้น ตัวอย่างเช่น ถ้าเรามีเทสต์เพื่อยืนยันว่าเราสามารถสั่งซื้อซีดีแผ่นเดียวได้ และเรากำลังรันเทสต์นั้นกับ microservices สี่หรือห้าตัว ถ้าตัวใดตัวหนึ่งล่ม เราอาจได้รับความล้มเหลวที่ไม่เกี่ยวข้องอะไรเลยกับธรรมชาติของเทสต์เอง ในทำนองเดียวกัน ปัญหาเครือข่ายชั่วคราวอาจทำให้เทสต์ล้มเหลวโดยไม่บ่งบอกอะไรเกี่ยวกับฟังก์ชันที่ถูกทดสอบเลย
ยิ่งมีชิ้นส่วนที่เคลื่อนไหวมากเท่าไร เทสต์ของเราก็อาจยิ่งเปราะบางมากขึ้นและมีความแน่นอนน้อยลงเท่านั้น ถ้าคุณมีเทสต์ที่ บางครั้ง ล้มเหลว แต่ทุกคนก็แค่รันมันใหม่เพราะมันอาจจะผ่านในภายหลัง นั่นแปลว่าคุณมี flaky test และเทสต์ที่ครอบคลุมกระบวนการต่างๆ จำนวนมากไม่ใช่ตัวการเดียว เทสต์ที่ครอบคลุมฟังก์ชันที่ทำงานบนหลาย thread (และข้ามหลาย process) ก็มักจะเป็นปัญหาเช่นกัน ความล้มเหลวอาจหมายถึง race condition หรือ time-out หรือฟังก์ชันนั้นพังจริงๆ flaky test คือศัตรู เมื่อมันล้มเหลว มันไม่ได้บอกอะไรเรามากนัก เรารัน CI build ของเราใหม่ด้วยความหวังว่ามันจะผ่านในภายหลัง แต่กลับเห็น check-in กองพะเนินขึ้นเรื่อยๆ และจู่ๆ เราก็พบว่าตัวเองมีฟังก์ชันที่พังจำนวนมาก
เมื่อเราตรวจพบ flaky test สิ่งสำคัญคือเราต้องพยายามอย่างเต็มที่เพื่อกำจัดมันออกไป ไม่เช่นนั้นเราจะเริ่มสูญเสียความเชื่อมั่นใน test suite ที่ "ล้มเหลวแบบนั้นเป็นประจำ" test suite ที่มี flaky test อาจกลายเป็นเหยื่อของสิ่งที่ Diane Vaughan เรียกว่า normalization of deviance นั่นคือแนวคิดที่ว่าเมื่อเวลาผ่านไป เราอาจคุ้นชินกับสิ่งที่ผิดพลาดจนเริ่มยอมรับว่ามันเป็นเรื่องปกติและไม่ใช่ปัญหา 5 แนวโน้มตามธรรมชาติของมนุษย์แบบนี้หมายความว่าเราต้องหาและกำจัด flaky test เหล่านี้ให้เร็วที่สุดเท่าที่จะทำได้ ก่อนที่เราจะเริ่มสันนิษฐานว่าเทสต์ที่ล้มเหลวเป็นเรื่องปกติ
ใน "Eradicating Non-Determinism in Tests," 6 Martin Fowler สนับสนุนแนวทางที่ว่า ถ้าคุณมี flaky test คุณควรตามหามันให้เจอ และถ้าคุณไม่สามารถแก้ไขได้ทันที ก็ให้เอามันออกจาก suite เพื่อที่คุณจะได้จัดการกับมันได้ ลองดูว่าคุณสามารถเขียนมันใหม่เพื่อหลีกเลี่ยงการทดสอบโค้ดที่รันบนหลาย thread ได้หรือไม่ ลองดูว่าคุณสามารถทำให้ environment เบื้องหลังมีความเสถียรมากขึ้นได้หรือไม่ หรือดีกว่านั้น ลองดูว่าคุณสามารถแทนที่ flaky test ด้วยเทสต์ขอบเขตเล็กกว่าที่มีโอกาสแสดงปัญหาน้อยกว่าได้หรือไม่ ในบางกรณี การเปลี่ยนซอฟต์แวร์ที่ถูกทดสอบให้ทดสอบง่ายขึ้นก็อาจเป็นทางออกที่ถูกต้องเช่นกัน
Who Writes These End-to-End Tests? (ใครเป็นคนเขียน End-to-End Test เหล่านี้)
สำหรับเทสต์ที่รันเป็นส่วนหนึ่งของ pipeline ของ microservice หนึ่งๆ จุดเริ่มต้นที่สมเหตุสมผลคือให้ทีมที่เป็นเจ้าของ service นั้นเขียนเทสต์เหล่านั้น (เราจะพูดถึง service ownership เพิ่มเติมใน Chapter 15 ) แต่ถ้าเราพิจารณาว่าอาจมีหลายทีมเข้ามาเกี่ยวข้อง และขั้นตอน end-to-end test ตอนนี้ถูกแชร์กันระหว่างทีมอย่างมีประสิทธิภาพแล้ว ใครกันที่จะเขียนและดูแลเทสต์เหล่านี้
ผมเคยเห็นปัญหาหลายอย่างที่เกิดขึ้นจากตรงนี้ เทสต์เหล่านี้กลายเป็นพื้นที่เสรีที่ทุกทีมได้รับสิทธิ์เพิ่มเทสต์ โดยไม่มีความเข้าใจ เกี่ยวกับสุขภาพของ suite ทั้งหมด สิ่งนี้มักส่งผลให้ test case ระเบิดขึ้นมาจำนวนมาก บางครั้งก็ จบลง ที่ test snow cone ที่เราคุยกันไปก่อนหน้านี้ ผมยังเคยเห็นสถานการณ์ที่ เพราะไม่มี ownership ที่ชัดเจนจริงๆ ของเทสต์เหล่านี้ ผลลัพธ์ของมันจึงถูกละเลย เมื่อมันพัง ทุกคนต่างสันนิษฐานว่าเป็นปัญหาของคนอื่น ดังนั้นพวกเขาจึงไม่สนใจว่าเทสต์จะผ่านหรือไม่
ทางแก้ปัญหาหนึ่งที่ผมเคยเห็นคือการกำหนดให้ end-to-end test บางตัวเป็นความรับผิดชอบของทีมใดทีมหนึ่งโดยเฉพาะ แม้ว่ามันอาจตัดผ่าน microservices ที่หลายทีมต่างกันกำลังทำงานอยู่ก็ตาม ผมเรียนรู้แนวทางนี้ครั้งแรกจาก Emily Bache 7 แนวคิดคือ แม้ว่าเราจะใช้ "fan in" stage ใน pipeline ของเรา พวกเขาก็จะแบ่ง end-to-end test suite ออกเป็นกลุ่มของฟังก์ชันการทำงานที่เป็นของแต่ละทีม ดังที่เราจะเห็นใน Figure 9-9
Figure 9-9. วิธีมาตรฐานในการจัดการ end-to-end test ข้าม service
ในตัวอย่างนี้โดยเฉพาะ การเปลี่ยนแปลงใน Web Shop ที่ผ่าน service test stage จะ trigger end-to-end test ที่เกี่ยวข้อง โดย suite นั้นเป็นของทีมเดียวกับที่เป็นเจ้าของ Web Shop ในทำนองเดียวกัน การเปลี่ยนแปลงใน Helpdesk เท่านั้นจะ trigger end-to-end test ที่เกี่ยวข้อง แต่การเปลี่ยนแปลงใน Customer หรือ Loyalty trigger ทั้งสอง ชุด สิ่งนี้อาจนำเราไปสู่สถานการณ์ที่การเปลี่ยนแปลงใน Loyalty microservice อาจทำให้ end-to-end test ทั้งสองชุดพัง ซึ่งอาจต้องให้ทีมที่เป็นเจ้าของ test suite ทั้งสองนี้ไล่ตามเจ้าของ Loyalty microservice เพื่อขอให้แก้ไข แม้ว่าโมเดลนี้จะช่วยได้ในกรณีของ Emily แต่อย่างที่เราเห็น มันก็ยังมี ความท้าทาย ของตัวเองอยู่ โดยพื้นฐานแล้ว มันเป็นปัญหาที่ทีมหนึ่งจะเป็นเจ้าของความรับผิดชอบของเทสต์ ในขณะที่คนจากทีมอื่นสามารถทำให้เทสต์เหล่านี้พังได้
บางครั้งองค์กรก็ตอบสนองด้วยการมีทีมเฉพาะทางเขียนเทสต์เหล่านี้ นี่อาจเป็นหายนะได้ ทีมที่พัฒนาซอฟต์แวร์จะห่างเหินจากเทสต์ของโค้ดของตัวเองมากขึ้นเรื่อยๆ cycle time เพิ่มขึ้น เพราะ service owner ต้องรอทีมเทสต์เขียน end-to-end test สำหรับฟังก์ชันที่พวกเขาเพิ่งเขียนเสร็จ เพราะมีอีกทีมเขียนเทสต์เหล่านี้ ทีมที่เขียน service นั้นก็จะมีส่วนร่วมน้อยลง และด้วยเหตุนี้จึงมีแนวโน้มที่จะรู้น้อยลงว่าจะรันและแก้ไขเทสต์เหล่านี้อย่างไร แม้ว่าน่าเสียดายที่มันยังคงเป็น pattern ขององค์กรที่พบได้ทั่วไป แต่ผมเห็นความเสียหายที่สำคัญเกิดขึ้นทุกครั้งที่ทีมหนึ่งถูกทำให้ห่างไกลจากการเขียนเทสต์ของโค้ดที่พวกเขาเขียนขึ้นเองตั้งแต่แรก
การทำเรื่องนี้ให้ถูกต้องนั้นยากมากจริงๆ เราไม่ต้องการทำงานซ้ำซ้อน และเราก็ไม่ต้องการรวมศูนย์เรื่องนี้จนถึงขนาดที่ทีมที่สร้าง service ห่างไกลจากมันมากเกินไป ถ้าคุณสามารถหาวิธีที่สะอาดในการมอบหมาย end-to-end test ให้กับทีมใดทีมหนึ่งได้ ก็ทำเลย ถ้าทำไม่ได้ และถ้าคุณไม่สามารถหาวิธีเอา end-to-end test ออกไปและแทนที่ด้วยสิ่งอื่นได้ คุณก็คงต้องปฏิบัติต่อ end-to-end test suite เหมือนเป็น codebase ที่แชร์กัน แต่มี ownership ร่วมกัน ทีมต่างๆ มีอิสระที่จะ check in เข้าไปใน suite นี้ แต่ ownership ของสุขภาพของ suite ต้องถูกแชร์กันระหว่างทีมที่พัฒนา service เอง ถ้าคุณต้องการใช้ end-to-end test อย่างกว้างขวางกับหลายทีม ผมคิดว่าแนวทางนี้จำเป็นอย่างยิ่ง แต่ผมก็เห็นมันถูกทำได้ไม่บ่อยนัก และไม่เคยเห็นที่ทำโดยไม่มีปัญหาเลย ท้ายที่สุดแล้ว ผมเชื่อมั่นว่าเมื่อองค์กรมีสเกลถึงระดับหนึ่ง คุณจำเป็นต้องเลิกใช้ end-to-end test ข้ามทีมด้วยเหตุผลนี้
How Long Should End-to-End Tests Run? (End-to-End Test ควรใช้เวลานานแค่ไหน)
end-to-end test เหล่านี้อาจใช้เวลานานพอสมควร ผมเคยเห็นมันใช้เวลานานถึงหนึ่งวันในการรัน ถ้าไม่นานกว่านั้น และในโปรเจกต์หนึ่งที่ผมเคยทำ regression suite แบบเต็มรูปแบบใช้เวลาถึงหกสัปดาห์! ผมแทบไม่เคยเห็นทีมที่คัดสรร end-to-end test suite ของพวกเขาจริงๆ เพื่อลดความซ้ำซ้อนของ test coverage หรือใช้เวลามากพอในการทำให้มันเร็วขึ้น
ความช้านี้ ผนวกกับความจริงที่ว่าเทสต์เหล่านี้มักจะไม่เสถียร อาจกลายเป็นปัญหาใหญ่ได้ test suite ที่ใช้เวลาทั้งวันและมักจะพังโดยไม่เกี่ยวข้องอะไรกับฟังก์ชันที่พังจริงๆ นั้นเป็นหายนะ แม้ว่าฟังก์ชันของคุณจะ พัง จริงๆ คุณก็อาจต้องใช้เวลาหลายชั่วโมงกว่าจะรู้ ซึ่ง ณ จุดนั้นคุณคงย้ายไปทำกิจกรรมอื่นแล้ว และการ context switch เพื่อดึงสมองของคุณกลับมาแก้ปัญหาก็คงเจ็บปวดไม่น้อย
เราสามารถบรรเทาปัญหานี้ได้บ้างด้วยการรันเทสต์แบบขนาน ตัวอย่างเช่น การใช้เครื่องมืออย่าง Selenium Grid อย่างไรก็ตาม แนวทางนี้ไม่ใช่สิ่งทดแทนการเข้าใจอย่างแท้จริงว่าอะไรที่ต้องทดสอบ และการ เอาออก เทสต์ที่ไม่จำเป็นแล้วอย่างจริงจัง
การเอาเทสต์ออกบางครั้งก็เป็นเรื่องที่ยุ่งยากใจ และผมสงสัยว่าคนที่พยายามทำแบบนี้มีอะไรคล้ายกับคนที่อยากยกเลิกมาตรการรักษาความปลอดภัยสนามบินบางอย่าง ไม่ว่ามาตรการรักษาความปลอดภัยนั้นจะไร้ประสิทธิภาพแค่ไหน การพูดคุยใดๆ เกี่ยวกับการเอามันออกมักถูกโต้แย้งด้วยปฏิกิริยาแบบสัญชาตญาณเกี่ยวกับการไม่สนใจความปลอดภัยของคน หรือต้องการให้ผู้ก่อการร้ายชนะ มันยากที่จะมีการพูดคุยอย่างสมดุลเกี่ยวกับคุณค่าที่สิ่งหนึ่งเพิ่มเข้ามา เทียบกับภาระที่มันนำมาด้วย มันยังอาจเป็นการแลกเปลี่ยนความเสี่ยง/ผลตอบแทนที่ยากอีกด้วย คุณจะได้รับคำขอบคุณไหมถ้าคุณเอาเทสต์ออก บางทีก็ได้ แต่คุณจะแน่นอนโดนตำหนิถ้าเทสต์ที่คุณเอาออกทำให้บั๊กหลุดผ่านไป อย่างไรก็ตาม เมื่อพูดถึง test suite ที่มีขอบเขตใหญ่กว่า นี่คือสิ่งที่เราจำเป็นต้องทำได้จริงๆ ถ้าฟีเจอร์เดียวกันถูกครอบคลุมในเทสต์ที่แตกต่างกัน 20 ตัว บางทีเราอาจกำจัดครึ่งหนึ่งของมันได้ เพราะเทสต์ 20 ตัวนั้นใช้เวลารันถึง 10 นาที! สิ่งที่จำเป็นสำหรับเรื่องนี้คือความเข้าใจที่ดีขึ้นเกี่ยวกับความเสี่ยง ซึ่งเป็นสิ่งที่มนุษย์ขึ้นชื่อว่าแย่มาก ผลก็คือ การคัดสรรและจัดการเทสต์ขอบเขตใหญ่ที่มีภาระสูงอย่างชาญฉลาดแบบนี้ เกิดขึ้น ไม่บ่อยนักอย่างน่าประหลาดใจ การหวังให้คนทำแบบนี้มากขึ้นไม่เหมือนกับการทำให้มันเกิดขึ้นจริง
The Great Pile-Up (การกองพะเนินครั้งใหญ่)
feedback cycle ที่ยาวนานซึ่งเกี่ยวข้องกับ end-to-end test ไม่ใช่แค่ปัญหาด้าน productivity ของนักพัฒนาเท่านั้น เมื่อ test suite ยาว การพังใดๆ ก็ต้องใช้เวลานานกว่าจะแก้ ซึ่งลดระยะเวลาที่เราจะคาดหวังได้ว่า end-to-end test จะผ่าน ถ้าเรา deploy เฉพาะซอฟต์แวร์ที่ผ่านเทสต์ทั้งหมดของเราสำเร็จ (ซึ่งเราควรทำ!) มันหมายความว่า service ของเราจำนวนน้อยลงที่จะไปถึงจุดที่พร้อม deploy เข้าสู่ production
สิ่งนี้อาจนำไปสู่การกองพะเนิน ในขณะที่ integration test stage ที่พังอยู่กำลังถูกแก้ไข การเปลี่ยนแปลงเพิ่มเติมจากทีม upstream ก็สามารถกองเข้ามาได้ นอกเหนือจากความจริงที่ว่าสิ่งนี้อาจทำให้การแก้ build ยากขึ้น มันยังหมายความว่าขอบเขตของการเปลี่ยนแปลงที่จะ deploy เพิ่มขึ้นด้วย วิธีที่เหมาะสมในการจัดการเรื่องนี้คือไม่ให้คน check in ถ้า end-to-end test กำลังล้มเหลว แต่เมื่อพิจารณาเวลาของ test suite ที่ยาวนาน สิ่งนี้มักจะทำไม่ได้จริง ลองพูดดูสิว่า "นักพัฒนา 30 คนของคุณ: ห้าม check in จนกว่าเราจะแก้ build ที่ใช้เวลาเจ็ดชั่วโมงนี้ได้!" อย่างไรก็ตาม การอนุญาตให้ check in บน end-to-end test suite ที่พังนั้น แท้จริงแล้วเป็นการแก้ปัญหาผิดจุด ถ้าคุณอนุญาตให้ check in บน build ที่พัง build อาจพังอยู่นานขึ้น บั่นทอนประสิทธิภาพของมันในฐานะวิธีให้ feedback ที่รวดเร็วเกี่ยวกับคุณภาพของโค้ด คำตอบที่ถูกต้องคือการทำให้ test suite เร็วขึ้น
ยิ่งขอบเขตของการ deploy ใหญ่ขึ้นและความเสี่ยงของการ release สูงขึ้นเท่าไร เรายิ่งมีแนวโน้มที่จะทำอะไรพังมากขึ้นเท่านั้น ดังนั้นเราต้องการมั่นใจว่าเราสามารถ release การเปลี่ยนแปลงเล็กๆ ที่ผ่านการทดสอบมาอย่างดีได้บ่อยๆ เมื่อ end-to-end test ทำให้ความสามารถของเราในการ release การเปลี่ยนแปลงเล็กๆ ช้าลง มันอาจจบลงด้วยการสร้างความเสียหายมากกว่าประโยชน์ที่ได้
The Metaversion (Metaversion)
ด้วยขั้นตอน end-to-end test มันง่ายที่จะเริ่มคิดว่า ผมรู้ว่า service เหล่านี้ทั้งหมดในเวอร์ชันนี้ทำงานร่วมกันได้ ทำไมไม่ deploy พวกมันทั้งหมดพร้อมกันล่ะ ความคิดนี้จะกลายเป็นบทสนทนาแนวว่า แล้วทำไมไม่ใช้เลขเวอร์ชันสำหรับทั้งระบบล่ะ อย่างรวดเร็วมาก ยกคำพูดของ Brandon Byars ที่ว่า “ตอนนี้คุณมีปัญหา 2.1.0 แล้ว”
ด้วยการ version การเปลี่ยนแปลงที่ทำกับ service หลายตัวรวมกัน เราก็ยอมรับแนวคิดที่ว่าการเปลี่ยนแปลงและ deploy service หลายตัวพร้อมกันนั้นเป็นที่ยอมรับได้อย่างมีประสิทธิภาพ มันกลายเป็นเรื่องปกติ มันกลายเป็นเรื่องโอเค เมื่อทำแบบนั้น เราก็เสียข้อได้เปรียบหลักอย่างหนึ่งของสถาปัตยกรรมแบบ microservice ไป นั่นคือความสามารถในการ deploy service หนึ่งตัวด้วยตัวมันเอง แยกจาก service อื่นอย่างอิสระ
บ่อยครั้งเกินไปที่แนวทางการยอมรับให้ service หลายตัวถูก deploy พร้อมกันจะเลื่อนไหลไปสู่สถานการณ์ที่ service กลายเป็น coupled กัน ไม่นานนัก service ที่แยกกันอย่างสวยงามก็จะพันกันมากขึ้นเรื่อยๆ กับตัวอื่น และคุณจะไม่มีวันสังเกตเห็น เพราะคุณไม่เคยพยายาม deploy พวกมันด้วยตัวมันเองเลย คุณจะจบลงด้วยความยุ่งเหยิงที่พันกัน ที่คุณต้อง orchestrate การ deploy ของ service หลายตัวพร้อมกัน และอย่างที่เราคุยกันไปก่อนหน้านี้ coupling แบบนี้อาจทำให้เราอยู่ในสถานะที่แย่กว่าการมี monolithic application เดียว
นี่คือเรื่องแย่
Lack of Independent Testability (การขาดความสามารถในการทดสอบอย่างอิสระ)
เรา กลับมาที่หัวข้อของ independent deployability บ่อยครั้ง ในฐานะคุณสมบัติสำคัญที่ช่วยให้ทีมทำงานได้อย่างอิสระมากขึ้น ทำให้ซอฟต์แวร์ถูกส่งมอบได้มีประสิทธิภาพมากขึ้น ถ้าทีมของคุณทำงานอย่างอิสระ ก็เป็นเรื่องธรรมดาที่พวกเขาควรทดสอบอย่างอิสระได้ด้วย อย่างที่เราเห็น end-to-end test สามารถลดความเป็นอิสระของทีมได้ และอาจบังคับให้ต้องมีการประสานงานในระดับที่สูงขึ้น พร้อมกับความท้าทายที่เกี่ยวข้องที่มันนำมาด้วย
แรงผลักดันสู่ความสามารถในการทดสอบอย่างอิสระขยายไปถึงการใช้ infrastructure ที่เกี่ยวข้องกับการทดสอบของเราด้วย บ่อยครั้งที่ผมเห็นคนต้องใช้ shared testing environment ที่เทสต์จากหลายทีมถูกรันร่วมกัน environment แบบนี้มักถูกจำกัดอย่างมาก และปัญหาใดๆ ก็สามารถก่อให้เกิดปัญหาสำคัญได้ โดยหลักการแล้ว ถ้าคุณต้องการให้ทีมของคุณสามารถพัฒนาและทดสอบได้อย่างอิสระ พวกเขาก็ควรมี test environment ของตัวเองด้วย
งานวิจัย ที่สรุปไว้ใน Accelerate พบว่าทีมที่มีประสิทธิภาพสูงมีแนวโน้มมากกว่าที่จะ "ทำการทดสอบส่วนใหญ่แบบ on demand โดยไม่ต้องพึ่งพา integrated test environment" 8