วิธีการกู้คืนจากการแยกเครื่อง จำกัด ?


14

คำถามของฉันดูเหมือนจะเป็นเรื่องวิทยาศาสตร์ แต่ฉันคิดว่ามันเป็นปัญหาที่พบบ่อยและนักพัฒนาที่มีประสบการณ์และโปรแกรมเมอร์หวังว่าจะมีคำแนะนำเพื่อหลีกเลี่ยงปัญหาที่ฉันพูดถึงในชื่อ Btw. สิ่งที่ฉันอธิบายร้องเป็นปัญหาจริงฉันพยายามแก้ปัญหาเชิงรุกในโครงการ iOS ของฉันฉันต้องการหลีกเลี่ยงค่าใช้จ่ายทั้งหมด

โดยเครื่องสถานะ จำกัด ฉันหมายถึงสิ่งนี้> ฉันมี UI ที่มีปุ่มไม่กี่รัฐหลายเซสชันที่เกี่ยวข้องกับ UI นั้นและสิ่งที่ UI นี้แสดงถึงฉันมีข้อมูลบางอย่างที่แสดงค่าบางส่วนใน UI ฉันได้รับและจัดการทริกเกอร์ภายนอกบางอย่าง (แสดงโดยการเรียกกลับจากเซ็นเซอร์) ฉันทำแผนภาพสถานะเพื่อทำแผนที่สถานการณ์ที่เกี่ยวข้องให้ดีขึ้นและเป็นที่พึงปรารถนาใน UI และแอปพลิเคชันนั้น เมื่อฉันค่อยๆติดตั้งโค้ดแอปเริ่มทำงานมากขึ้นตามที่ควรจะเป็น อย่างไรก็ตามฉันไม่มั่นใจมากว่าจะแข็งแกร่งพอ ความสงสัยของฉันมาจากการเฝ้าดูกระบวนการคิดและการนำไปใช้ของฉันเอง ฉันมั่นใจว่าฉันมีทุกอย่างที่ครอบคลุม แต่ก็เพียงพอที่จะทำการทดสอบสัตว์เดรัจฉานใน UI และฉันก็รู้ได้อย่างรวดเร็วว่ายังมีช่องว่างในพฤติกรรม ... ฉันทำการปะแก้พวกเขา อย่างไรก็ตาม ในขณะที่แต่ละองค์ประกอบขึ้นอยู่กับพฤติกรรมจากการป้อนข้อมูลจากส่วนประกอบอื่น ๆ การป้อนข้อมูลบางอย่างจากผู้ใช้หรือแหล่งภายนอกทำให้เกิดห่วงโซ่ของเหตุการณ์เปลี่ยนแปลงสถานะ .. เป็นต้น ฉันมีองค์ประกอบหลายอย่างและแต่ละพฤติกรรมทำงานเช่นเดียวกับทริกเกอร์นี้ที่ได้รับเมื่อทริกเกอร์อินพุท -> และผู้ส่งวิเคราะห์ -> เอาท์พุทบางอย่าง (ข้อความการเปลี่ยนสถานะ) จากการวิเคราะห์

ปัญหาคือสิ่งนี้ไม่ได้มีการควบคุมตัวเองอย่างสมบูรณ์และส่วนประกอบของฉัน (รายการฐานข้อมูลสถานะเซสชันสถานะของปุ่มบางปุ่ม) ... สามารถเปลี่ยนแปลงอิทธิพลลบหรือแก้ไขนอกขอบเขตของเหตุการณ์หรือ สถานการณ์ที่พึงประสงค์ (โทรศัพท์ล่มแบตเตอรี่จะหมดทันทีเมื่อเปิดเครื่อง) สิ่งนี้จะแนะนำสถานการณ์ที่ไม่แน่นอนเข้าสู่ระบบซึ่งระบบอาจไม่สามารถกู้คืนได้ ฉันเห็นสิ่งนี้ (แม้ว่าคนจะไม่ตระหนักว่านี่เป็นปัญหา) ในแอปคู่แข่งของฉันหลายแห่งที่อยู่ในร้าน Apple ลูกค้าเขียนสิ่งนี้>> "ฉันเพิ่มเอกสารสามฉบับและหลังจากไปที่นั่นแล้วฉันไม่สามารถเปิดได้ แม้ว่าจะเห็นพวกเขา " หรือ "ฉันบันทึกวิดีโอทุกวัน แต่หลังจากบันทึกวิดีโอด้วยเช่นกันฉันไม่สามารถเปลี่ยนคำอธิบายภาพได้ .. และปุ่มสำหรับคำอธิบายภาพไม่ได้ '

เหล่านี้เป็นเพียงตัวอย่างสั้น ๆ ลูกค้ามักจะอธิบายรายละเอียดเพิ่มเติม .. จากคำอธิบายและพฤติกรรมที่อธิบายไว้ในนั้นฉันคิดว่าแอปเฉพาะนั้นมีการแยก FSM

ดังนั้นคำถามสุดท้ายคือฉันจะหลีกเลี่ยงปัญหานี้ได้อย่างไรและจะป้องกันระบบจากการบล็อกได้อย่างไร

แก้ไข> ฉันกำลังพูดถึงในมุมมองของผู้ควบคุมวิวเวอร์หนึ่งคนในโทรศัพท์ฉันหมายถึงส่วนหนึ่งของแอปพลิเคชัน ฉันเข้าใจรูปแบบ MVC ฉันมีโมดูลแยกต่างหากสำหรับฟังก์ชั่นที่แตกต่างกัน .. ทุกอย่างที่ฉันอธิบายมีความเกี่ยวข้องกับผืนผ้าใบหนึ่งบน UI


2
ดูเหมือนจะเป็นกรณีสำหรับการทดสอบหน่วย!
Michael K

คำตอบ:


7

ฉันแน่ใจว่าคุณรู้แล้ว แต่ในกรณีนี้:

  1. ตรวจสอบให้แน่ใจว่าทุกโหนดในไดอะแกรมสถานะมีส่วนอาร์คออกสำหรับอินพุตทุกชนิดตามกฎหมาย (หรือแบ่งอินพุตเป็นคลาสด้วยอาร์คขาออกหนึ่งอันสำหรับแต่ละคลาสของอินพุต)

    ทุกตัวอย่างที่ฉันเห็นของเครื่องรัฐใช้อาร์คขาออกเพียงอันเดียวสำหรับอินพุตที่ผิดพลาดใด ๆ

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

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

  2. ตรวจสอบให้แน่ใจว่าเครื่องรัฐสามารถรับหรือติดตามเพียงหนึ่งอาร์คเพื่อตอบสนองต่ออินพุตที่ได้รับ (ไม่เกินหนึ่งอาร์ค)

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

    IE หากได้รับข้อผิดพลาดหรือไม่รู้จักในสถานะ "รู้จัก" จากนั้นส่วนโค้งตามด้วยผลลัพธ์ของการป้อนข้อมูลการจัดการข้อผิดพลาด / ไม่ทราบไม่ควรย้อนกลับไปยังสถานะใด ๆ

  3. เมื่อคุณไปถึงสถานะเทอร์มินัล (สิ้นสุด) คุณไม่ควรกลับไปที่เทอร์มินัลที่ไม่ใช่เพียงแค่สถานะเริ่มต้น (เริ่มต้น) เท่านั้น

  4. สำหรับเครื่องสถานะหนึ่งไม่ควรมีสถานะเริ่มต้นหรือสถานะเริ่มต้นมากกว่าหนึ่งรายการ (ตามตัวอย่างที่ฉันเคยเห็น)

  5. จากสิ่งที่ฉันได้เห็นเครื่องสถานะหนึ่งสามารถแสดงสถานะของปัญหาหรือสถานการณ์หนึ่งเท่านั้น
    ไม่ควรมีหลาย ๆ สถานะที่เป็นไปได้ในคราวเดียวในแผนภาพสถานะเดียว
    ถ้าฉันเห็นความเป็นไปได้สำหรับสถานะที่เกิดขึ้นพร้อมกันหลายสถานะสิ่งนี้จะบอกฉันว่าฉันต้องแยกแผนภาพสถานะออกเป็นเครื่องรัฐ 2 เครื่องขึ้นไปที่มีความเป็นไปได้ที่แต่ละรัฐจะต้องแก้ไขอย่างอิสระ


10

จุดสำคัญของเครื่องจักรสถานะ จำกัด คือมีกฎที่ชัดเจนสำหรับทุกสิ่งที่สามารถเกิดขึ้นได้ในรัฐ นั่นเป็นเหตุผลที่มันเป็นสิ่งที่แน่นอน

ตัวอย่างเช่น

if a:
  print a
elif b:
  print b

คือไม่cแน่นอนเพราะเราจะได้รับการป้อนข้อมูล นี้:

if a:
  print a
elif b:
  print b
else:
  print error

มีขอบเขตเนื่องจากอินพุตที่เป็นไปได้ทั้งหมดจะถูกนำมาใช้ บัญชีนี้เป็นไปได้ปัจจัยการผลิตไปยังรัฐซึ่งอาจจะแยกออกจากการตรวจสอบข้อผิดพลาด ลองนึกภาพเครื่องรัฐด้วยสถานะดังต่อไปนี้:

No money state. 
Not enough money state.
Pick soda state.

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

  1. รับรองได้ว่าทุกอย่างคือการกระทำของอะตอม เครื่องสามารถสูญเสียพลังงานโดยรวมและยังคงอยู่ในสถานะที่ถูกต้องและมั่นคง
  2. ขยายสถานะของคุณเพื่อรวมถึงปัญหาที่ไม่รู้จักและมีข้อผิดพลาดจะนำคุณเข้าสู่สถานะนี้ซึ่งมีการจัดการปัญหา

สำหรับการอ้างอิงบทความ wiki เกี่ยวกับเครื่องจักรของรัฐนั้นละเอียดถี่ถ้วน ฉันยังแนะนำCode Completeสำหรับบทที่เกี่ยวกับการสร้างซอฟต์แวร์ที่เสถียรและเชื่อถือได้


"เราสามารถรับอินพุต c" - นี่คือเหตุผลว่าทำไมภาษา typesafe จึงสำคัญ หากประเภทอินพุตของคุณเป็นบูลคุณจะได้รับtrueและfalseไม่มีอะไรอื่นอีก ถึงอย่างนั้นก็เป็นสิ่งสำคัญที่จะเข้าใจประเภทของคุณ - เช่นประเภท nullable, floating-point NaN, ฯลฯ
MSalters

5

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

การเขียนโปรแกรมไวยากรณ์ภาษาไม่ใช่ FSMs แต่โดยทั่วไปแล้วตัวแยกวิเคราะห์ (เช่น Yacc หรือ bison) มีวิธีการใส่สถานะข้อผิดพลาดตั้งแต่หนึ่งสถานะขึ้นไปดังนั้นอินพุตที่ไม่คาดคิดอาจทำให้รหัสที่สร้างขึ้นสิ้นสุดลงในสถานะข้อผิดพลาด

ดูเหมือนว่า FSM ของคุณต้องการสถานะข้อผิดพลาดหรือสถานะความล้มเหลวหรือเทียบเท่าทางศีลธรรมพร้อมทั้งชัดเจน (สำหรับกรณีที่คุณคาดหวัง) และโดยนัย (สำหรับกรณีที่คุณไม่คาดหวัง) การเปลี่ยนเป็นสถานะความล้มเหลวหรือข้อผิดพลาดอย่างใดอย่างหนึ่ง


ยกโทษให้ฉันถ้าคำถามของฉันดูโง่เพราะฉันไม่มีการศึกษาอย่างเป็นทางการใน CS และฉันแค่เรียนรู้การเขียนโปรแกรมสำหรับสองสามเดือน หมายความว่าเมื่อฉันให้วิธีการจัดการสำหรับเหตุการณ์ที่ผลักสำหรับปุ่มและในวิธีนั้นฉันมีความซับซ้อนในระดับปานกลางถ้าโครงสร้างอื่น - สวิตช์ - ปรับอากาศ (รหัส 20-30 บรรทัด) ที่ ฉันควรจัดการกับปัจจัยการผลิตที่ไม่พึงประสงค์เสมออย่างชัดเจน? หรือคุณหมายถึงระดับ "ทั่วโลก" ฉันควรจะมีชั้นเรียนแยกต่างหากดู FSM นี้และเมื่อเกิดปัญหาขึ้นมันจะรีเซ็ตค่าและสถานะ?
Earl Grey

การอธิบายตัวแยกวิเคราะห์ที่สร้างจาก Yacc หรือ Bison นั้นเกินกว่าฉัน แต่โดยปกติแล้วคุณจัดการกับกรณีที่ทราบแล้วมีบล็อคโค้ดขนาดเล็กสำหรับ "ทุกอย่างอื่นเกิดข้อผิดพลาดหรือสถานะล้มเหลว" รหัสสำหรับสถานะข้อผิดพลาด / ความล้มเหลวจะทำการรีเซ็ตทั้งหมด คุณอาจต้องมีค่าเพิ่มเติมที่บอกว่าทำไมคุณถึงสถานะความล้มเหลว
Bruce Ediger

FSM ของคุณควรมีสถานะอย่างน้อยหนึ่งสถานะสำหรับข้อผิดพลาดหรือสถานะข้อผิดพลาดหลายสถานะสำหรับข้อผิดพลาดประเภทต่างๆ
whatsisname

3

วิธีที่ดีที่สุดที่จะหลีกเลี่ยงปัญหานี้คือการทดสอบแบบอัตโนมัติ

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

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


2

สิ่งที่คุณกำลังมองหาคือการจัดการข้อยกเว้น ปรัชญาการออกแบบเพื่อหลีกเลี่ยงการอยู่ในสถานะที่ไม่สอดคล้องกันนั้นได้รับการบันทึกไว้ว่าthe way of the samurai: คืนชัยชนะหรือไม่ส่งคืน กล่าวอีกนัยหนึ่ง: ส่วนประกอบควรตรวจสอบอินพุตทั้งหมดและตรวจสอบให้แน่ใจว่าสามารถประมวลผลได้ตามปกติ ไม่ใช่ในกรณีนี้ควรเพิ่มข้อยกเว้นที่มีข้อมูลที่เป็นประโยชน์

เมื่อมีการยกข้อยกเว้นมันจะเพิ่มสแต็กขึ้น คุณควรกำหนดเลเยอร์การจัดการข้อผิดพลาดซึ่งจะรู้ว่าต้องทำอย่างไร หากไฟล์ผู้ใช้เสียหายให้อธิบายกับลูกค้าของคุณว่าข้อมูลสูญหายและสร้างไฟล์เปล่าใหม่ทั้งหมด

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

ฉันไม่ใช่ผู้เชี่ยวชาญด้านวัตถุประสงค์ แต่หน้านี้ควรเป็นจุดเริ่มต้นที่ดี:

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocExceptionHandling.html


1

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

สิ่งที่คุณต้องทำคือกำหนดรัฐของคุณในขณะที่คุณตัดสินใจที่จะทำ รับปุ่มทั้งหมดและสถานะทริกเกอร์ บันทึกไว้ในตัวแปรท้องถิ่น ค่าดั้งเดิมอาจเปลี่ยนแปลงทุกครั้งที่คุณดู จากนั้นทำตามสถานการณ์ที่คุณมี มันเป็นภาพรวมของการที่ระบบมองถึงจุดหนึ่ง มิลลิวินาทีในภายหลังมันอาจดูแตกต่างกันมาก แต่ด้วยมัลติเธรดไม่มีกระแส "จริง" ในปัจจุบันที่คุณสามารถแขวนได้เฉพาะภาพที่คุณบันทึกไว้ในตัวแปรท้องถิ่น

จากนั้นคุณต้องตอบสนองต่อการบันทึกของคุณ - ประวัติศาสตร์ - รัฐ ทุกอย่างได้รับการแก้ไขและคุณควรมีการดำเนินการสำหรับทุกรัฐที่เป็นไปได้ จะไม่คำนึงถึงการเปลี่ยนแปลงที่เกิดขึ้นระหว่างเวลาที่คุณถ่ายภาพสแนปชอตและเวลาที่คุณแสดงผลลัพธ์ แต่นั่นคือชีวิตในโลกที่มีเธรดหลากหลาย และคุณอาจต้องใช้การซิงโครไนซ์เพื่อป้องกันไม่ให้ภาพเบลอของคุณเกินไป (คุณไม่ทันสมัย ​​แต่คุณสามารถเข้าใกล้เพื่อรับสถานะทั้งหมดของคุณจากช่วงเวลาหนึ่งทันที)

อ่านหลายเธรด คุณมีอะไรมากมายให้เรียนรู้ และเนื่องจากทริกเกอร์เหล่านั้นฉันไม่คิดว่าคุณสามารถใช้กลอุบายจำนวนมากที่มีให้เพื่อให้การประมวลผลแบบขนานง่าย ("Worker Threads" และอื่น ๆ ) คุณไม่ได้ทำ "การประมวลผลแบบขนาน"; คุณไม่ได้พยายามใช้ 75% ของ 8 คอร์ คุณใช้ 1% ของ CPU ทั้งหมด แต่คุณมีเธรดที่มีความเป็นอิสระสูงและมีการโต้ตอบสูงและต้องใช้ความคิดจำนวนมากในการซิงโครไนซ์พวกเขาและทำให้การซิงโครไนซ์ไม่ให้ล็อคระบบ

ทดสอบทั้งเครื่องแกนเดี่ยวและเครื่องมัลติคอร์ ฉันพบว่ามันทำงานค่อนข้างแตกต่างกับมัลติเธรด เครื่องที่เป็นแกนเดียวจะทำให้เกิดข้อบกพร่องหลายเธรดน้อยลง แต่ข้อผิดพลาดเหล่านั้นแปลกกว่ามาก (แม้ว่าเครื่องที่ใช้มัลติคอร์จะทำให้จิตใจของคุณสับสนจนกว่าคุณจะชินกับมัน)

ความคิดที่ไม่พึงประสงค์สุดท้าย: นี่ไม่ใช่เรื่องง่ายที่จะทดสอบ คุณจะต้องสร้างทริกเกอร์แบบสุ่มและการกดปุ่มและปล่อยให้ระบบหมดเวลาสักครู่เพื่อดูว่าเกิดอะไรขึ้น รหัสแบบมัลติเธรดไม่ได้กำหนดไว้ บางสิ่งอาจล้มเหลวเพียงครั้งเดียวในการวิ่งหนึ่งพันล้านครั้งเพียงเพราะเวลานั้นถูกปิดเป็นนาโนวินาที ใส่คำสั่ง debug (อย่างระมัดระวัง if-statements เพื่อหลีกเลี่ยงข้อความที่ไม่จำเป็น 999,999,999 ข้อความ) และคุณต้องสร้างหนึ่งพันล้านข้อความเพื่อรับข้อความที่มีประโยชน์เพียงข้อความเดียว โชคดีที่เครื่องจักรมีความรวดเร็วในทุกวันนี้

ขอโทษที่ทิ้งสิ่งนี้กับคุณตั้งแต่ต้นในอาชีพการงานของคุณ หวังว่าใครบางคนจะได้คำตอบอื่นพร้อมกับวิธีแก้ปัญหาทั้งหมดนี้ (ฉันคิดว่ามีสิ่งต่าง ๆ อยู่ที่นั่นซึ่งอาจทำให้เชื่องต้นเหตุได้ ถ้าเป็นเช่นนั้นคำตอบนี้จะทำให้คุณรู้ว่าคุณพลาดอะไรไปบ้าง โชคดี.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.