Làm thế nào để phục hồi từ sự cố máy trạng thái hữu hạn?


13

Câu hỏi của tôi có vẻ rất khoa học nhưng tôi nghĩ đó là một vấn đề phổ biến và các nhà phát triển và lập trình viên dày dạn hy vọng sẽ có một số lời khuyên để tránh vấn đề tôi đề cập trong tiêu đề. Btw., Những gì tôi mô tả dưới đây là một vấn đề thực sự tôi đang cố gắng chủ động giải quyết trong dự án iOS của mình, tôi muốn tránh nó bằng mọi giá.

Theo máy trạng thái hữu hạn, ý tôi là> Tôi có một UI với một vài nút, một số trạng thái phiên có liên quan đến UI đó và UI này thể hiện điều gì, tôi có một số dữ liệu được hiển thị một phần trong UI, tôi nhận và xử lý một số kích hoạt bên ngoài (đại diện bởi các cuộc gọi lại từ các cảm biến). Tôi đã tạo các sơ đồ trạng thái để ánh xạ tốt hơn các kịch bản có liên quan mong muốn và có thể điều chỉnh được trong ứng dụng và giao diện người dùng đó. Khi tôi chậm triển khai mã, ứng dụng bắt đầu hoạt động ngày càng giống như vậy. Tuy nhiên, tôi không tự tin rằng nó đủ mạnh. Những nghi ngờ của tôi đến từ việc theo dõi quá trình thực hiện và suy nghĩ của chính tôi. Tôi đã tự tin rằng tôi có mọi thứ được bảo hiểm, nhưng nó đủ để thực hiện một vài thử nghiệm vũ phu trong UI và tôi nhanh chóng nhận ra rằng vẫn còn những lỗ hổng trong hành vi .. Tôi đã vá chúng. Tuy nhiên, vì mỗi thành phần phụ thuộc và hoạt động dựa trên đầu vào từ một số thành phần khác, một đầu vào nhất định từ người dùng hoặc một số nguồn bên ngoài tạo ra một chuỗi các sự kiện, thay đổi trạng thái..v.v. Tôi có một số thành phần và mỗi thành phần hoạt động như Trình kích hoạt này nhận được ở đầu vào -> trình kích hoạt và người gửi của nó đã phân tích -> xuất một cái gì đó (một thông báo, thay đổi trạng thái) dựa trên phân tích

Vấn đề là, điều này không hoàn toàn tự chủ và các thành phần của tôi (một mục cơ sở dữ liệu, trạng thái phiên, trạng thái của một số nút) ... COULD bị thay đổi, ảnh hưởng, xóa hoặc sửa đổi, ngoài phạm vi của chuỗi sự kiện hoặc kịch bản mong muốn. (điện thoại gặp sự cố, pin hết điện thoại đột ngột) Điều này sẽ đưa đến một tình huống không có giá trị vào hệ thống, từ đó hệ thống có khả năng KHÔNG THỂ phục hồi. Tôi thấy điều này (mặc dù mọi người không nhận ra đây là vấn đề) trong nhiều ứng dụng của đối thủ cạnh tranh của tôi trên cửa hàng apple, khách hàng viết những thứ như thế này> "Tôi đã thêm ba tài liệu và sau khi đến đó, tôi không thể mở chúng, ngay cả khi a nhìn thấy chúng. " hoặc "Tôi đã quay video hàng ngày, nhưng sau khi quay video quá nhật ký, tôi không thể bật phụ đề cho chúng .. và nút cho phụ đề không '

Đây chỉ là những ví dụ rút gọn, khách hàng thường mô tả nó chi tiết hơn..từ các mô tả và hành vi được mô tả trong đó, tôi cho rằng ứng dụng cụ thể có sự cố FSM.

Vì vậy, câu hỏi cuối cùng là làm thế nào tôi có thể tránh điều này, và làm thế nào để bảo vệ hệ thống khỏi bị chặn?

EDIT> Tôi đang nói về ngữ cảnh của một chế độ xem của bộ điều khiển trên điện thoại, ý tôi là một phần của ứng dụng. Tôi hiểu mô hình MVC, tôi có các mô-đun riêng biệt cho chức năng riêng biệt..tất cả mọi thứ tôi mô tả đều liên quan đến một khung vẽ trên UI.


2
Âm thanh như một trường hợp cho các bài kiểm tra đơn vị!
Michael K

Câu trả lời:


7

Tôi chắc chắn bạn đã biết điều này nhưng chỉ trong trường hợp:

  1. Đảm bảo rằng mọi nút trong sơ đồ trạng thái có một vòng cung đi ra cho MỌI loại đầu vào hợp pháp (hoặc chia các đầu vào thành các lớp, với một cung ngoài cho mỗi lớp đầu vào).

    Mỗi ví dụ tôi đã thấy về một máy trạng thái chỉ sử dụng một cung ngoài cho BẤT K input đầu vào sai.

    Nếu không có câu trả lời chắc chắn về việc đầu vào sẽ làm gì mỗi lần, thì đó là một điều kiện lỗi hoặc có một đầu vào khác bị thiếu (điều đó sẽ dẫn đến một vòng cung cho đầu vào đi đến một nút mới).

    Nếu một nút không có vòng cung cho một loại đầu vào, thì đó là giả định đầu vào sẽ không bao giờ xảy ra trong cuộc sống thực (đây là một điều kiện lỗi tiềm ẩn sẽ không được xử lý bởi máy trạng thái).

  2. Đảm bảo rằng máy trạng thái chỉ có thể lấy hoặc chỉ theo MỘT cung để đáp ứng với đầu vào nhận được (không quá một cung).

    Nếu có các loại kịch bản lỗi khác nhau hoặc các loại đầu vào không thể xác định được tại thời điểm thiết kế máy trạng thái, các kịch bản lỗi và đầu vào không xác định sẽ chuyển sang trạng thái có đường dẫn hoàn toàn tách biệt với "cung tròn thông thường".

    IE nếu nhận được lỗi hoặc không xác định ở bất kỳ trạng thái "đã biết" nào, thì các cung theo sau là kết quả của việc xử lý lỗi / đầu vào không xác định sẽ không quay trở lại bất kỳ trạng thái nào mà máy sẽ ở nếu chỉ nhận được đầu vào đã biết.

  3. Khi bạn đạt đến trạng thái đầu cuối (cuối), bạn không thể chỉ quay lại trạng thái không đầu cuối về trạng thái bắt đầu (ban đầu).

  4. Đối với một máy trạng thái, không nên có nhiều hơn một trạng thái bắt đầu hoặc ban đầu (dựa trên các ví dụ tôi đã thấy).

  5. Dựa trên những gì tôi đã thấy, một máy trạng thái chỉ có thể biểu thị trạng thái của một vấn đề hoặc kịch bản.
    Không bao giờ nên có nhiều trạng thái có thể cùng một lúc trong một sơ đồ trạng thái.
    Nếu tôi thấy tiềm năng của nhiều trạng thái đồng thời, điều này cho tôi biết tôi cần chia sơ đồ trạng thái thành 2 hoặc nhiều máy trạng thái riêng biệt có tiềm năng mỗi trạng thái được sửa đổi độc lập.


9

Điểm của một máy trạng thái hữu hạn là nó có các quy tắc rõ ràng cho mọi thứ có thể xảy ra trong một trạng thái. Đó là lý do tại sao nó là hữu hạn .

Ví dụ:

if a:
  print a
elif b:
  print b

không hữu hạn, bởi vì chúng tôi có thể nhận được đầu vào c. Điều này:

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

là hữu hạn, bởi vì tất cả các đầu vào có thể được tính. Tài khoản này cho các đầu vào có thể đến một trạng thái , có thể tách biệt với kiểm tra lỗi. Hãy tưởng tượng một máy trạng thái với các trạng thái sau:

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

Trong các trạng thái được xác định, tất cả các đầu vào có thể được xử lý đối với tiền được chèn và soda được chọn. Mất điện nằm ngoài bộ máy trạng thái và "không tồn tại". Một máy trạng thái chỉ có thể xử lý các đầu vào cho các trạng thái mà nó có, vì vậy bạn có hai lựa chọn.

  1. Đảm bảo rằng mọi thứ hành động là nguyên tử. Máy có thể mất toàn bộ năng lượng và vẫn để mọi thứ ở trạng thái ổn định, chính xác.
  2. Mở rộng các trạng thái của bạn để bao gồm vấn đề không xác định và có lỗi đưa bạn đến trạng thái này, nơi các vấn đề được xử lý.

Để tham khảo, bài viết wiki về máy trạng thái là kỹ lưỡng. Tôi cũng đề nghị Code Complete , cho các chương về xây dựng phần mềm ổn định, đáng tin cậy.


"Chúng tôi có thể nhận được đầu vào c" - đây là lý do tại sao các ngôn ngữ an toàn rất quan trọng. Nếu loại đầu vào của bạn là một bool, bạn có thể nhận truefalse, nhưng không có gì khác. Ngay cả khi đó, điều quan trọng là phải hiểu các loại của bạn - ví dụ: các loại không thể, dấu phẩy động NaN, v.v.
MSalters

5

Biểu thức chính quy được thực hiện như các máy trạng thái hữu hạn. Bảng chuyển đổi được tạo bởi mã thư viện sẽ có trạng thái lỗi được tích hợp sẵn để xử lý những gì xảy ra nếu đầu vào không khớp với mẫu. Ít nhất có một sự chuyển đổi ngầm định sang trạng thái thất bại từ hầu hết các trạng thái khác.

Các ngữ pháp ngôn ngữ lập trình không phải là FSM, nhưng các trình tạo trình phân tích cú pháp (như Yacc hoặc bison) thường có cách đưa vào một hoặc nhiều trạng thái lỗi, để các đầu vào không mong muốn có thể khiến mã được tạo kết thúc ở trạng thái lỗi.

Âm thanh như FSM của bạn cần trạng thái lỗi hoặc trạng thái lỗi hoặc tương đương đạo đức, cùng với cả hai trường hợp rõ ràng (đối với trường hợp bạn dự đoán) và ẩn (đối với trường hợp bạn không lường trước được) chuyển sang một trong các trạng thái lỗi hoặc lỗi.


Hãy tha thứ cho tôi, nếu câu hỏi của tôi nghe có vẻ ngớ ngẩn, vì tôi không được giáo dục chính thức về CS, và tôi chỉ học lập trình trong vài tháng. Điều đó có nghĩa là, khi tôi nói một phương thức xử lý, đối với một sự kiện được ấn cho một nút và trong phương thức đó, tôi có một cấu trúc if-other-switch-điều hòa phức tạp vừa phải (20-30 dòng mã), Tôi nên luôn luôn xử lý đầu vào không mong muốn một cách rõ ràng? HOẶC bạn có nghĩa là nó ở cấp độ "toàn cầu"? Tôi có nên có một lớp riêng xem FSM này không, và khi sự cố xảy ra, nó sẽ đặt lại các giá trị và trạng thái?
Earl Grey

Giải thích các trình phân tích cú pháp được tạo bởi Yacc hoặc Bison nằm ngoài tôi, nhưng thông thường, bạn xử lý các trường hợp đã biết và sau đó có một khối mã nhỏ cho "mọi thứ khác đều chuyển sang trạng thái lỗi hoặc lỗi". Mã cho trạng thái lỗi / lỗi sẽ thực hiện tất cả việc đặt lại. Bạn có thể phải có một giá trị bổ sung cho biết lý do tại sao bạn đến trạng thái thất bại.
Bruce Ediger

FSM của bạn nên có ít nhất một trạng thái cho các lỗi hoặc nhiều trạng thái lỗi cho các loại lỗi khác nhau.
whatsisname

3

Cách tốt nhất để tránh điều này là Kiểm tra tự động .

Cách duy nhất để có sự tự tin thực sự về những gì mã của bạn làm dựa trên các đầu vào nhất định là kiểm tra chúng. Bạn có thể nhấp xung quanh trong ứng dụng của mình và cố gắng thực hiện mọi thứ không chính xác, nhưng điều đó không mở rộng tốt để đảm bảo bạn không có bất kỳ hồi quy nào. Thay vào đó, bạn có thể tạo một bài kiểm tra chuyển đầu vào xấu vào một thành phần của mã của bạn và đảm bảo rằng nó xử lý nó theo cách lành mạnh.

Điều này sẽ không thể chứng minh rằng máy trạng thái không bao giờ có thể bị hỏng, nhưng nó sẽ cho bạn biết rằng nhiều trường hợp phổ biến được xử lý chính xác và không phá vỡ những thứ khác.


2

những gì bạn đang tìm kiếm là xử lý ngoại lệ. Một triết lý thiết kế để tránh ở trong một trạng thái không nhất quán được ghi lại là the way of the samurai: trở về chiến thắng hoặc không trở lại. Nói cách khác: một thành phần nên kiểm tra tất cả các đầu vào của nó và đảm bảo rằng nó sẽ có thể xử lý chúng bình thường. Nó không phải là trường hợp, nó nên đưa ra một ngoại lệ có chứa thông tin hữu ích.

Khi một ngoại lệ được đưa ra, nó sẽ nổi bong bóng lên. Bạn nên xác định một lớp xử lý lỗi sẽ biết phải làm gì. Nếu một tệp người dùng bị hỏng, hãy giải thích cho khách hàng của bạn rằng dữ liệu bị mất và tạo lại một tệp trống sạch.

Phần quan trọng ở đây là để trở lại trạng thái làm việc và tránh lan truyền lỗi. Khi bạn hoàn thành việc này, bạn có thể làm việc trên các thành phần riêng lẻ để làm cho chúng mạnh mẽ hơn.

Tôi không phải là một chuyên gia khách quan, nhưng trang này phải là một điểm khởi đầu tốt:

http://developer.apple.com/l Library / ios /#documentation / cocoa / conconual / objectivec / Chap / ocExceptionHandling.html


1

Quên máy hữu hạn của bạn. Những gì bạn có ở đây là một tình huống đa luồng nghiêm trọng . Bất kỳ nút nào cũng có thể được nhấn bất cứ lúc nào và các kích hoạt bên ngoài của bạn có thể tắt bất cứ lúc nào. Các nút có thể là tất cả trên một luồng, nhưng một trình kích hoạt có thể tắt ngay lập tức cùng lúc với một trong các nút hoặc một, nhiều hoặc tất cả các trình kích hoạt khác.

Những gì bạn phải làm là xác định trạng thái của bạn tại thời điểm bạn quyết định hành động. Nhận tất cả các nút và trạng thái kích hoạt. Lưu chúng trong các biến cục bộ. Các giá trị ban đầu có thể thay đổi mỗi khi bạn nhìn vào chúng. Sau đó hành động theo tình huống như bạn có nó. Đây là một ảnh chụp nhanh về cách hệ thống nhìn vào một điểm. Một phần nghìn giây sau nó có thể trông rất khác, nhưng với đa luồng thì không có "hiện tại" thực sự mà bạn có thể bám vào, chỉ có một hình ảnh bạn đã lưu trong các biến cục bộ.

Sau đó, bạn phải đáp ứng với trạng thái đã lưu - lịch sử - của bạn. Mọi thứ đều cố định và bạn nên có một hành động cho tất cả các trạng thái có thể. Nó sẽ không tính đến các thay đổi được thực hiện giữa thời gian bạn chụp ảnh nhanh và thời gian bạn hiển thị kết quả của mình, nhưng đó là cuộc sống trong thế giới đa luồng. Và bạn có thể cần sử dụng đồng bộ hóa để giữ cho ảnh chụp nhanh không bị mờ. (Bạn không thể cập nhật, nhưng bạn có thể đến gần để có được toàn bộ trạng thái của mình từ một thời điểm cụ thể.)

Đọc lên trên đa luồng. Bạn có rất nhiều điều để học hỏi. Và vì những tác nhân đó, tôi không nghĩ rằng bạn có thể sử dụng nhiều thủ thuật thường được cung cấp để xử lý song song dễ dàng ("Chủ đề công nhân", v.v.). Bạn không làm "xử lý song song"; bạn không cố gắng sử dụng 75% của 8 lõi. Bạn đang sử dụng 1% toàn bộ CPU, nhưng bạn có các luồng tương tác cao, độc lập cao và sẽ cần rất nhiều suy nghĩ để đồng bộ hóa chúng và giữ cho việc đồng bộ hóa khỏi việc khóa hệ thống.

Thử nghiệm trên cả máy đơn lõi và đa lõi; Tôi thấy họ cư xử khá khác biệt với đa luồng. Các máy đơn lõi tạo ra ít lỗi đa luồng hơn, nhưng những lỗi đó kỳ lạ hơn nhiều. (Mặc dù các máy đa lõi sẽ làm rối loạn tâm trí của bạn cho đến khi bạn quen với chúng.)

Một suy nghĩ khó chịu cuối cùng: đây không phải là thứ dễ kiểm tra. Bạn sẽ cần phải tạo các kích hoạt ngẫu nhiên và nhấn nút và để hệ thống chạy thẳng ra một lúc để xem những gì bật lên. Mã đa luồng không xác định. Một cái gì đó có thể thất bại một lần trong một tỷ lần chạy, chỉ vì thời gian đã tắt trong một nano giây. Đưa vào các câu lệnh gỡ lỗi (với các câu lệnh if cẩn thận để tránh 999.999.999 tin nhắn không cần thiết) và bạn cần thực hiện một tỷ lượt chạy chỉ để nhận được một tin nhắn hữu ích. May mắn thay, máy móc là thực sự nhanh chóng những ngày này.

Xin lỗi để đổ tất cả điều này vào bạn sớm trong sự nghiệp của bạn. Hy vọng rằng ai đó sẽ đưa ra một câu trả lời khác bằng cách giải quyết tất cả những điều này (tôi nghĩ rằng có những thứ có thể chế ngự được các yếu tố kích hoạt, nhưng bạn vẫn có xung đột nút / kích hoạt). Nếu vậy, câu trả lời này ít nhất sẽ cho bạn biết những gì bạn đang thiếu. Chúc may mắn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.