ด้วย (ออก) แอปขัดข้องได้โปรด!
เผยแพร่แล้ว: 2020-02-12โปรแกรมเมอร์พยายามหลีกเลี่ยงปัญหาในโค้ดของตน หากมีคนใช้แอปพลิเคชันของตน ไม่ควรแตกหรือออกโดยไม่คาดคิด นี่เป็นหนึ่งในการวัดคุณภาพที่ง่ายที่สุด - หากแอปขัดข้องบ่อยครั้ง แสดงว่าอาจทำได้ไม่ดี
แอปขัดข้องเกิดขึ้นเมื่อโปรแกรมกำลังจะทำสิ่งที่ไม่ได้กำหนดไว้หรือไม่ดี เช่น หารค่าด้วยศูนย์หรือเข้าถึงทรัพยากรที่ถูกจำกัดบนเครื่อง โปรแกรมเมอร์ที่เขียนแอปพลิเคชันอาจทำได้อย่างชัดเจน “สิ่งนั้นจะไม่มีวันเกิดขึ้น ฉันจะข้ามมันไป” - เป็นเรื่องธรรมดาและไม่ใช่ความคิดที่ไร้เหตุผลโดยสิ้นเชิง มีบางกรณีที่ไม่สามารถเกิดขึ้นได้ ไม่เคยเลย จนกระทั่ง… มันเกิดขึ้น
ผิดสัญญา
กรณีที่พบบ่อยที่สุดกรณีหนึ่งที่เราทราบดีว่าบางสิ่งไม่สามารถเกิดขึ้นได้คือ API เราได้ตกลงกันระหว่างแบ็กเอนด์และฟรอนท์เอนด์ – นั่นคือการตอบกลับของเซิร์ฟเวอร์เดียวที่คุณจะได้รับสำหรับคำขอนี้ ผู้ดูแลห้องสมุดนี้ได้บันทึกพฤติกรรมของฟังก์ชันนี้ ฟังก์ชันนี้ไม่สามารถทำอะไรได้อีก วิธีคิดทั้งสองวิธีนั้นถูกต้อง แต่ทั้งสองวิธีอาจทำให้เกิดปัญหาได้
เมื่อคุณใช้ไลบรารี่ คุณสามารถพึ่งพาเครื่องมือภาษาเพื่อช่วยคุณจัดการกับกรณีที่เป็นไปได้ทั้งหมด หากภาษาที่คุณใช้ไม่มีรูปแบบการตรวจสอบประเภทหรือการวิเคราะห์แบบคงที่ คุณต้องจัดการเอง อย่างไรก็ตาม คุณสามารถตรวจสอบว่าก่อนที่จะส่งไปยังสภาพแวดล้อมการผลิต ดังนั้นจึงไม่ใช่เรื่องใหญ่ นั่นอาจเป็นเรื่องยาก แต่คุณอ่านบันทึกการเปลี่ยนแปลงก่อนที่จะอัปเดตการพึ่งพาและเขียนการทดสอบหน่วยใช่ไหม ไม่ว่าคุณจะใช้หรือทำให้ไลบรารี่การพิมพ์ที่เข้มงวดมากขึ้น คุณสามารถจัดเตรียมโค้ดและโปรแกรมเมอร์คนอื่นๆ ได้ดียิ่งขึ้น
การสื่อสารส่วนหลังส่วนหน้านั้นยากขึ้นเล็กน้อย มักประกอบกันหลวมๆ ดังนั้นการเปลี่ยนแปลงด้านหนึ่งจึงทำได้ง่ายดายโดยไม่ทราบว่าจะส่งผลต่ออีกด้านหนึ่งอย่างไร การเปลี่ยนแปลงในแบ็กเอนด์มักจะทำให้สมมติฐานของคุณเสียหายในส่วนหน้า และทั้งคู่มักถูกแจกจ่ายแยกกัน มันต้องจบลงอย่างเลวร้าย เราเป็นเพียงมนุษย์และบางครั้งเราก็ไม่เข้าใจอีกฝ่ายหรือลืมบอกพวกเขาถึงการเปลี่ยนแปลงเล็กๆ น้อยๆ นั้น อีกครั้ง นั่นไม่ใช่เรื่องใหญ่สำหรับการส่งเครือข่ายที่เหมาะสม – การตอบสนองการถอดรหัสจะล้มเหลว และเรารู้วิธีจัดการกับมัน แม้แต่โค้ดถอดรหัสที่ดีที่สุดก็อาจได้รับผลกระทบจากการออกแบบที่ไม่ดีเช่นกัน...
ฟังก์ชั่นบางส่วน การออกแบบที่ไม่ดี
“เราจะมีตัวแปรบูลีนสองตัวที่นี่: 'isActive' และ 'canTransfer' แน่นอนว่าคุณไม่สามารถถ่ายโอนเมื่อไม่ได้ใช้งาน แต่นั่นเป็นเพียงรายละเอียดเท่านั้น” เริ่มกันเลย การออกแบบที่ไม่ดีของเราซึ่งสามารถโจมตีได้อย่างหนัก ตอนนี้บางคนจะสร้างฟังก์ชันด้วยสองอาร์กิวเมนต์และประมวลผลข้อมูลบางส่วนตามนั้น วิธีแก้ปัญหาที่ง่ายที่สุดคือ… แค่เกิดความผิดพลาดในสถานะที่ไม่ถูกต้อง มันไม่ควรเกิดขึ้น ดังนั้นเราไม่ควรสนใจ เรายังใส่ใจในบางครั้งและแสดงความคิดเห็นเพื่อแก้ไขในภายหลังหรือเพื่อถามว่าควรเกิดอะไรขึ้น แต่ในที่สุดก็สามารถจัดส่งได้โดยไม่ต้องทำงานนั้นให้เสร็จ
// รหัสเทียม ฟังก์ชัน doTransfer (Bool isActive, Bool canTransfer) { ถ้า ( isActive และ canTransfer ) { // ทำบางอย่างเพื่อการโอนว่าง } else if ( ไม่ใช่ isActive และ canTransfer ) { // ทำบางอย่างเพื่อการโอนไม่พร้อมใช้งาน } else if ( isActive และ not canTransfer ) { // ทำบางอย่างเพื่อการโอนไม่พร้อมใช้งาน } else { // aka ( ไม่ใช่ isActive และ canTransfer ) // มีสี่สถานะที่เป็นไปได้ // สิ่งนี้ไม่ควรเกิดขึ้น การถ่ายโอนไม่ควรสามารถใช้ได้เมื่อไม่ได้ใช้งาน ชน() } }
ตัวอย่างนี้อาจดูงี่เง่า แต่บางครั้งคุณอาจติดกับดักประเภทนั้น ซึ่งยากต่อการตรวจพบและแก้ไขมากกว่านี้ คุณจะจบลงด้วยสิ่งที่เรียกว่าฟังก์ชันบางส่วน นี่คือฟังก์ชันที่กำหนดไว้สำหรับอินพุตที่เป็นไปได้บางส่วนเท่านั้น โดยไม่สนใจหรือหยุดทำงานร่วมกับผู้อื่น คุณควรหลีกเลี่ยงฟังก์ชันบางส่วนเสมอ (โปรดทราบว่าในภาษาที่พิมพ์แบบไดนามิก ฟังก์ชันส่วนใหญ่ถือเป็นบางส่วนได้) หากภาษาของคุณไม่สามารถรับประกันการทำงานที่เหมาะสมกับการตรวจสอบประเภทและการวิเคราะห์แบบคงที่ ภาษาของคุณอาจขัดข้องหลังจากผ่านไประยะหนึ่งในลักษณะที่ไม่คาดคิด โค้ดมีการพัฒนาอย่างต่อเนื่องและสมมติฐานเมื่อวานอาจใช้ไม่ได้ในวันนี้
ล้มเหลวอย่างรวดเร็ว ล้มบ่อย.
คุณจะป้องกันตัวเองได้อย่างไร? การป้องกันที่ดีที่สุดคือการรุก! มีคำกล่าวที่ดีว่า “ล้มเหลวอย่างรวดเร็ว พลาดบ่อย” แต่เราไม่เห็นด้วยหรือว่าเราควรหลีกเลี่ยงแอปขัดข้อง ฟังก์ชันบางส่วน และการออกแบบที่ไม่ดี Erlang OTP ให้โปรแกรมเมอร์ได้เปรียบในตำนานที่จะรักษาตัวเองหลังจากสถานะที่ไม่คาดคิดและอัปเดตขณะทำงาน พวกเขาสามารถจ่ายได้ แต่ไม่ใช่ทุกคนที่มีความหรูหราแบบนี้ เหตุใดเราจึงควรล้มเหลวอย่างรวดเร็วและบ่อยครั้ง?
ก่อนอื่น เพื่อ ค้นหาสถานะและพฤติกรรมที่ไม่คาดคิดเหล่านั้น หากคุณไม่ตรวจสอบว่าสถานะแอปของคุณถูกต้องหรือไม่ ผลลัพธ์อาจเลวร้ายยิ่งกว่าการหยุดทำงาน!
ประการที่สอง เพื่อ ช่วยให้โปรแกรมเมอร์คนอื่นๆ ทำงานร่วมกันบนฐานรหัสเดียวกัน หากคุณอยู่คนเดียวในโครงการในตอนนี้ อาจมีคนอื่นตามหลังคุณ คุณอาจลืมสมมติฐานและข้อกำหนดบางประการ เป็นเรื่องปกติที่จะไม่อ่านเอกสารที่ให้ไว้จนกว่าทุกอย่างจะทำงานหรือไม่ทำเอกสารวิธีการและประเภทภายในเลย ในสถานะนั้น มีคนเรียกใช้หนึ่งในฟังก์ชันที่พร้อมใช้งานด้วยค่าที่ไม่คาดคิดแต่ถูกต้อง ตัวอย่างเช่น สมมติว่าเรามีฟังก์ชัน 'รอ' ที่ใช้ค่าจำนวนเต็มใดๆ และรอเป็นจำนวนวินาทีนั้น เกิดอะไรขึ้นถ้ามีคนผ่าน '-17' ไปที่มัน หากไม่เกิดความผิดพลาดในทันทีหลังจากทำเช่นนั้น อาจส่งผลให้เกิดข้อผิดพลาดร้ายแรงและสถานะที่ไม่ถูกต้อง มันรอตลอดไปหรือไม่?

ส่วนที่สำคัญที่สุดของความผิดพลาดโดยเจตนาคือการ ทำอย่างสง่างาม หากแอปพลิเคชันของคุณขัดข้อง คุณต้องให้ข้อมูลบางอย่างเพื่อให้สามารถวินิจฉัยได้ มันค่อนข้างง่ายเมื่อคุณใช้ดีบักเกอร์ แต่คุณควรมีวิธีในการรายงานแอพล่มโดยที่ไม่มีมัน คุณสามารถใช้ระบบการบันทึกเพื่อยืนยันข้อมูลนั้นระหว่างการเปิดใช้แอปพลิเคชันหรือดูจากภายนอก
ส่วนที่สำคัญที่สุดอันดับสองของการหยุดทำงานโดยเจตนาคือการหลีกเลี่ยงสิ่งนั้นในสภาพแวดล้อมการผลิต...
อย่าล้มเหลว เคย.
คุณจะจัดส่งรหัสของคุณในที่สุด คุณไม่สามารถทำให้มันสมบูรณ์แบบได้ มันมักจะแพงเกินไปที่จะคิดเกี่ยวกับการรับประกันความถูกต้อง อย่างไรก็ตาม คุณควรตรวจสอบให้แน่ใจว่าอุปกรณ์จะไม่ทำงานผิดปกติหรือขัดข้อง คุณจะบรรลุสิ่งนั้นได้อย่างไรเนื่องจากเราตัดสินใจผิดพลาดอย่างรวดเร็วและบ่อยครั้ง?
ส่วนสำคัญของการหยุดทำงานโดยเจตนาคือ การดำเนินการในสภาพแวดล้อม ที่ไม่ใช่การผลิตเท่านั้น คุณควรใช้คำยืนยันที่ถูกตัดออกไปในเวอร์ชันที่ใช้งานจริงของแอปพลิเคชันของคุณ สิ่งนี้จะช่วยในระหว่างการพัฒนาและช่วยให้สามารถระบุปัญหาได้ในขณะที่ไม่ส่งผลกระทบต่อผู้ใช้ปลายทาง อย่างไรก็ตาม ความผิดพลาดในบางครั้งก็ยังดีกว่าเพื่อหลีกเลี่ยงสถานะแอปพลิเคชันที่ไม่ถูกต้อง เราจะบรรลุสิ่งนั้นได้อย่างไรหากเราได้ทำหน้าที่บางส่วนแล้ว?
ทำให้สถานะที่ไม่ได้กำหนดและไม่ถูกต้องเป็นไปไม่ได้ที่จะเป็นตัวแทนและใช้ทางเลือกอื่นที่ถูกต้อง อาจฟังดูง่าย แต่ต้องใช้ความคิดและการทำงานเป็นอย่างมาก ไม่ว่าจะค้นหาจุดบกพร่อง ทำการแก้ไขชั่วคราว และ... ผู้ใช้ที่น่ารำคาญเสมอ จะทำให้ฟังก์ชันบางส่วนมีโอกาสเกิดขึ้นน้อยลงโดยอัตโนมัติ
// รหัสเทียม ฟังก์ชั่น doTransfer (สถานะสถานะ) { สวิตช์ (สถานะ) { กรณี State.canTransfer { // ทำบางอย่างให้พร้อมโอน } กรณี State.cannotTransfer { // ทำบางอย่างเพื่อการโอนไม่พร้อมใช้งาน } กรณี State.notActiv { // ทำบางอย่างเพื่อการโอนไม่พร้อมใช้งาน } // มันเป็นไปไม่ได้ที่จะเป็นตัวแทนของการถ่ายโอนที่มีอยู่โดยไม่ได้เปิดใช้งาน // มีเพียงสามสถานะที่เป็นไปได้ } }
คุณจะทำให้สถานะที่ไม่ถูกต้องเป็นไปไม่ได้ได้อย่างไร? ลองเลือกสองตัวอย่างก่อนหน้านี้ ในกรณีของตัวแปรบูลีนสองตัวของเรา 'isActive' และ 'canTransfer' เราสามารถเปลี่ยนสองตัวนี้เป็นการแจงนับเดียวได้ มันจะแสดงถึงสถานะที่เป็นไปได้และถูกต้องทั้งหมดอย่างละเอียดถี่ถ้วน แม้กระทั่งบางคนก็สามารถส่งตัวแปรที่ไม่ได้กำหนดได้ แต่นั่นจะง่ายกว่ามากในการจัดการ มันจะเป็นค่าที่ไม่ถูกต้องซึ่งจะไม่ถูกนำเข้าไปยังโปรแกรมของเราแทนที่จะเป็นสถานะที่ไม่ถูกต้องที่ถูกส่งผ่านไปภายในทำให้ทุกอย่างยากขึ้น
ฟังก์ชันการรอของเรายังสามารถปรับปรุงให้ดีขึ้นได้อย่างดีในภาษาที่พิมพ์อย่างชัดเจน เราสามารถทำให้มันใช้เฉพาะจำนวนเต็มที่ไม่ได้ลงนามในการป้อนข้อมูล เพียงอย่างเดียวจะแก้ไขปัญหาทั้งหมดของเราเนื่องจากคอมไพเลอร์จะแยกอาร์กิวเมนต์ที่ไม่ถูกต้องออก แต่ถ้าภาษาของคุณไม่มีประเภทล่ะ? เรามีวิธีแก้ปัญหาที่เป็นไปได้ อย่างแรก เกิดความผิดพลาด ฟังก์ชันนี้ไม่ได้กำหนดไว้สำหรับตัวเลขติดลบ และเราจะไม่ทำสิ่งที่ไม่ถูกต้องหรือไม่ได้กำหนดไว้ เราจะต้องหาการใช้งานที่ไม่ถูกต้องในระหว่างการทดสอบ การทดสอบหน่วย (ซึ่งเราควรทำอยู่แล้ว) จะมีความสำคัญมากที่นี่ ประการที่สอง – อาจมีความเสี่ยง แต่ขึ้นอยู่กับบริบทอาจเป็นประโยชน์ เราสามารถย้อนกลับไปใช้ค่าที่ถูกต้องซึ่งคงการยืนยันไว้ในบิลด์ที่ไม่ใช่การผลิตเพื่อแก้ไขสถานะที่ไม่ถูกต้องเมื่อเป็นไปได้ อาจไม่ใช่วิธีแก้ปัญหาที่ดีสำหรับฟังก์ชันเช่นนี้ แต่ถ้าเราทำค่าสัมบูรณ์ของจำนวนเต็มแทน เราจะหลีกเลี่ยงไม่ให้แอปขัดข้อง ทั้งนี้ขึ้นอยู่กับภาษาที่เป็นรูปธรรม อาจเป็นความคิดที่ดีที่จะโยน/เพิ่มข้อผิดพลาด/ข้อยกเว้นแทน มันอาจจะคุ้มค่าที่จะใช้ทางเลือกสำรองถ้าเป็นไปได้ แม้ว่าผู้ใช้จะเห็นข้อผิดพลาด แต่ก็เป็นประสบการณ์ที่ดีกว่าการหยุดทำงาน
ลองมาอีกตัวอย่างหนึ่งที่นี่ หากสถานะของข้อมูลผู้ใช้ในแอปพลิเคชันส่วนหน้าของคุณกำลังจะใช้งานไม่ได้ในบางกรณี อาจเป็นการดีกว่าที่จะบังคับให้ออกจากระบบและรับข้อมูลที่ถูกต้องอีกครั้งจากเซิร์ฟเวอร์แทนที่จะหยุดทำงาน ผู้ใช้อาจถูกบังคับให้ทำเช่นนั้นอยู่แล้วหรืออาจติดอยู่ในลูปการขัดข้องที่ไม่มีที่สิ้นสุด อีกครั้ง – เราควรยืนยันและล้มเหลวในสถานการณ์ดังกล่าวในสภาพแวดล้อมที่ไม่ใช่การผลิต แต่อย่าให้ผู้ใช้ของคุณเป็นผู้ทดสอบภายนอก
สรุป
ไม่มีใครชอบแอปพลิเคชั่นที่หยุดทำงานและไม่เสถียร เราไม่ชอบทำหรือใช้มัน ความล้มเหลวอย่างรวดเร็วด้วยการยืนยันที่ให้การวินิจฉัยที่เป็นประโยชน์ในระหว่างการพัฒนาและการทดสอบจะพบปัญหามากมายในช่วงต้น ทางเลือกในสถานะที่ถูกต้องในการผลิตจะทำให้แอปของคุณมีเสถียรภาพมากขึ้น การทำให้สถานะที่ไม่ถูกต้องไม่สามารถเป็นตัวแทนได้จะขจัดปัญหาทั้งชั้น ให้เวลากับตัวเองมากขึ้นในการคิดก่อนที่จะพัฒนาเกี่ยวกับวิธีแยกแยะและทางเลือกในสถานะที่ไม่ถูกต้อง และอีกเล็กน้อยระหว่างการเขียนเพื่อรวมการยืนยัน คุณสามารถเริ่มทำให้แอปพลิเคชันของคุณดีขึ้นได้ตั้งแต่วันนี้!
อ่านเพิ่มเติม:
- ออกแบบตามสัญญา
- ชนิดข้อมูลพีชคณิต