विचार करें कि मेरे पास gen_fsm के साथ लागू एक एफएसएम है। कुछ राज्य नाम में कुछ ईवेंट के लिए मुझे डेटाबेस में डेटा लिखना चाहिए और परिणामस्वरूप उपयोगकर्ता को जवाब देना चाहिए। तो निम्नलिखित StateName एक समारोह का प्रतिनिधित्व करती है:ओटीपी के सिद्धांत। अभ्यास में कार्यात्मक और गैर-कार्यात्मक कोड कैसे अलग करें?
statename(Event, _From, StateData) when Event=save_data->
case my_db_module:write(StateData#state.data) of
ok -> {stop, normal, ok, StateData};
_ -> {reply, database_error, statename, StateData)
end.
जहां my_db_module: लिखने गैर कार्यात्मक कोड वास्तविक डेटाबेस लिखने को लागू करने का एक हिस्सा है।
मुझे इस कोड के साथ दो प्रमुख समस्याएं दिखाई देती हैं: पहला, एफएसएम की एक शुद्ध कार्यात्मक अवधारणा गैर-कार्यात्मक कोड के हिस्से से मिश्रित होती है, यह एफएसएम की इकाई परीक्षण को असंभव बनाता है। दूसरा, एफएसएम को लागू करने वाला एक मॉड्यूल my_db_module के विशेष कार्यान्वयन पर निर्भरता है।
मेरी राय में, दो समाधान संभव हो रहे हैं:
लागू my_db_module: कुछ प्रक्रिया से निपटने के डेटाबेस के लिए एक अतुल्यकालिक संदेश भेजने के रूप में write_async, statename में जवाब न दें, StateData में से बचाने के लिए, wait_for_db_answer करने के लिए स्विच और एक हैंडल_इनोफ़ो में एक संदेश के रूप में डीबी प्रबंधन प्रक्रिया से परिणाम का इंतजार करें।
statename(Event, From, StateData) when Event=save_data-> my_db_module:write_async(StateData#state.data), NewStateData=StateData#state{from=From}, {next_state,wait_for_db_answer,NewStateData} handle_info({db, Result}, wait_for_db_answer, StateData) -> case Result of ok -> gen_fsm:reply(State#state.from, ok), {stop, normal, ok, State}; _ -> gen_fsm:reply(State#state.from, database_error), {reply, database_error, statename, StateData) end.
ऐसे कार्यान्वयन के लाभ वास्तविक डेटाबेस को छूए बिना यूनिट मॉड्यूल से मनमाना संदेश भेजने की संभावना है। समाधान संभावित दौड़ स्थितियों से पीड़ित है, अगर डीबी पहले जवाब देता है, कि एफएसएम राज्य या अन्य प्रक्रिया बदलता है तो एफएसएम को save_data भेजता है।
दौरान एक कॉलबैक फ़ंक्शन, लिखा प्रयोग करें init/1 StateData में:
init([Callback]) -> {ok, statename, #state{callback=Callback}}. statename(Event, _From, StateData) when Event=save_data-> case StateData#state.callback(StateData#state.data) of ok -> {stop, normal, ok, StateData}; _ -> {reply, database_error, statename, StateData) end.
यह समाधान दौड़ की स्थिति से ग्रस्त नहीं है, लेकिन अगर FSM कई कॉलबैक का उपयोग करता है यह वास्तव में कोड अभिभूत। यद्यपि वास्तविक फ़ंक्शन कॉलबैक में बदलना यूनिट परीक्षण संभव बनाता है, यह कार्यात्मक कोड अलगाव की समस्या को हल नहीं करता है।
मैं इस समाधान के सभी के साथ सहज नहीं हूँ। क्या इस समस्या को शुद्ध ओटीपी/एरलांग तरीके से संभालने के लिए कुछ नुस्खा है? ओटीपी और यूनिट के सिद्धांतों को कम करने की मेरी समस्या हो सकती है।