एकल जिम्मेदारी सिद्धांत, वह एकल जिम्मेदारी का सिद्धांत है,
वह एक समान परिवर्तनशीलता का सिद्धांत है - एक प्रोग्रामर के साक्षात्कार में समझने के लिए एक बहुत ही फिसलन भरा आदमी और ऐसा नर्वस प्रश्न।
इस सिद्धांत के साथ पहला गंभीर परिचय मेरे लिए पहले वर्ष की शुरुआत में हुआ, जब हमें युवा और हरे से जंगल से बाहर निकाला गया ताकि लार्वा से वास्तविक छात्रों को बनाया जा सके।
जंगल में, हम प्रत्येक में 8-9 लोगों के समूह में विभाजित थे और एक प्रतियोगिता का आयोजन किया - कौन सा समूह तेजी से वोदका की एक बोतल पीएगा, बशर्ते कि समूह का पहला व्यक्ति एक गिलास में वोदका डालता है, दूसरा पीता है, और तीसरा एक काट लेता है। अपना ऑपरेशन पूरा करने के बाद, यूनिट समूह कतार के अंत में खड़ी हो जाती है।
मामला जब कतार का आकार तीन का एक बहु था, और एसआरपी का अच्छा कार्यान्वयन था।
परिभाषा 1. एकल जिम्मेदारी।
एकल जिम्मेदारी (एसआरपी) के सिद्धांत की आधिकारिक परिभाषा बताती है कि प्रत्येक वस्तु की अपनी जिम्मेदारी और अस्तित्व की वजह है, और यह जिम्मेदारी केवल एक है।
टिपलर ऑब्जेक्ट पर विचार करें।
एसआरपी सिद्धांत को पूरा करने के लिए, हम जिम्मेदारियों को तीन में विभाजित करते हैं:
- एक डाल ( पौष्टिकता )
- एक पेय ( DrinkUpOperation )
- एक स्नैक ( टेकबाइटपरेशन )
प्रक्रिया में प्रत्येक भागीदार प्रक्रिया के एक घटक के लिए जिम्मेदार है, अर्थात्, इसकी एक परमाणु जिम्मेदारी है - पीने, डालने या काटने के लिए।
बदले में, इन ऑपरेशनों का मोहरा है:
lass Tippler { //... void Act(){ _pourOperation.Do() // _drinkUpOperation.Do() // _takeBiteOperation.Do() // } }
क्यों?
मानव प्रोग्रामर बंदर आदमी के लिए कोड लिखता है, और बंदर आदमी असावधान, मूर्ख और हमेशा जल्दी में कहीं भी होता है। वह एक बार में 3 से 7 शब्दों को पकड़ और समझ सकता है।
बू के मामले में, ये शब्द तीन हैं। हालांकि, यदि हम एक शीट के साथ कोड लिखते हैं, तो इसमें राजनीति के बारे में हाथ, चश्मा, नरसंहार और अंतहीन बहस दिखाई देगी। और यह सब एक विधि के शरीर में होगा। मुझे यकीन है कि आपने अपने व्यवहार में ऐसा कोड देखा है। मानस के लिए सबसे मानवीय परीक्षण नहीं है।
दूसरी ओर, बंदर आदमी वास्तविक दुनिया की वस्तुओं को अपने सिर में बांधने के लिए कैद है। अपनी कल्पना में, वह उन्हें एक साथ धकेल सकता है, उनसे नई वस्तुएं एकत्र कर सकता है और उन्हें उसी तरह अलग कर सकता है। एक पुराने कार मॉडल की कल्पना करें। आप अपनी कल्पना में दरवाजा खोल सकते हैं, दरवाजा ट्रिम को अनसुना कर सकते हैं और वहां खिड़की लिफ्टर तंत्र देख सकते हैं, जिसके अंदर गियर होंगे। लेकिन आप एक ही समय में मशीन के सभी घटकों को एक "लिस्टिंग" में नहीं देख सकते हैं। कम से कम "बंदर आदमी" नहीं कर सकते।
इसलिए, मानव प्रोग्रामर जटिल तंत्र को कम जटिल और काम करने वाले तत्वों के एक समूह में विघटित करते हैं। हालांकि, डीकंपोज़िंग अलग-अलग तरीकों से किया जा सकता है: कई पुरानी कारों में - डक्ट दरवाजा बाहर जाता है, और आधुनिक लोगों में - लॉक इलेक्ट्रॉनिक्स की विफलता इंजन को शुरू करने से रोकती है, जो मरम्मत के दौरान बचाता है।
इसलिए, एसआरपी एक सिद्धांत है जो एचओडब्ल्यू को विघटित करने के लिए समझाता है, अर्थात जहां अलगाव रेखा खींचना है ।
उनका कहना है कि अपघटन "जिम्मेदारी" के पृथक्करण के सिद्धांत पर आधारित होना चाहिए, अर्थात् विभिन्न वस्तुओं के कार्यों के अनुसार।
आइए वापस जाने के लिए और एक बंदर व्यक्ति को डिकम्पोजिंग के बाद मिलने वाले फायदे:
- कोड हर स्तर पर बेहद स्पष्ट हो गया है।
- कई प्रोग्रामर एक साथ कोड लिख सकते हैं (प्रत्येक एक अलग तत्व लिखता है)
- स्वचालित परीक्षण सरल है - तत्व जितना सरल है, परीक्षण करना उतना ही आसान है
- इन तीन ऑपरेशनों में से, भविष्य में, आप एक ग्लूटन (केवल टेकबिटेरेशन का उपयोग करके), एक शराबी (बोतल से सीधे ड्रिंकपॉपरेशन का उपयोग करके) जोड़ सकते हैं और कई अन्य व्यावसायिक आवश्यकताओं को पूरा कर सकते हैं।
और, बेशक, विपक्ष:
- और प्रकार बनाने होंगे।
- एक शराब पीने वाला पहली बार एक दो घंटे बाद पीएगा जितना वह कर सकता था
परिभाषा 2. एकीकृत परिवर्तनशीलता।
सज्जनों को अनुमति दें! पीने का वर्ग भी एक जिम्मेदारी पूरी करता है - यह पीता है! और सामान्य तौर पर, शब्द "जिम्मेदारी" एक अत्यंत अस्पष्ट अवधारणा है। कोई मानव जाति के भाग्य के लिए जिम्मेदार है, और कोई पोल पर उलझे पेंगुइन को उठाने के लिए जिम्मेदार है।
दो बिंगो कार्यान्वयन पर विचार करें। ऊपर उल्लेखित पहला, तीन वर्गों में शामिल है - डालना, पीना और एक काटने।
दूसरा एक फॉरवर्ड एंड ओनली फॉरवर्ड कार्यप्रणाली के माध्यम से लिखा गया है और इसमें एक्ट विधि में सभी तर्क शामिल हैं:
// . lass BrutTippler { //... void Act(){ // if(!_hand.TryDischarge(from:_bottle, to:_glass, size:_glass.Capacity)) throw new OverdrunkException(); // if(!_hand.TryDrink(from: _glass, size: _glass.Capacity)) throw new OverdrunkException(); // for(int i = 0; i< 3; i++){ var food = _foodStore.TakeOrDefault(); if(food==null) throw new FoodIsOverException(); _hand.TryEat(food); } } }
ये दोनों वर्ग, बाहर के पर्यवेक्षक के दृष्टिकोण से, बिल्कुल समान दिखते हैं और "पीने" की एकल जिम्मेदारी को पूरा करते हैं।
भ्रम की स्थिति!
फिर हम इंटरनेट पर सर्फ करते हैं और एसआरपी की एक और परिभाषा का पता लगाते हैं - समान परिवर्तनशीलता का सिद्धांत।
यह परिभाषा बताती है कि " मॉड्यूल में परिवर्तन का एक और केवल एक कारण है ।" यही है, "जिम्मेदारी परिवर्तन के लिए एक अवसर है।"
अब सब कुछ जगह-जगह गिर गया। अलग-अलग, आप डालना, पीना और काटने की प्रक्रियाओं को बदल सकते हैं, और खुद को केवल हम संचालन के अनुक्रम और संरचना को बदल सकते हैं, उदाहरण के लिए, पीने से पहले स्नैक को स्थानांतरित करना या टोस्ट रीडिंग जोड़ना।
फॉरवर्ड एंड ओनली फॉरवर्ड अप्रोच में, जो कुछ भी बदला जा सकता है, केवल एक्ट मेथड में बदला जा सकता है। यह उस मामले में पठनीय और प्रभावी हो सकता है जब थोड़ा तर्क होता है और यह शायद ही कभी बदलता है, लेकिन अक्सर यह 500 रेखाओं के भयानक तरीकों के साथ समाप्त होता है, रूस में नाटो में प्रवेश के लिए आवश्यकता से अधिक संख्याओं के साथ।
परिभाषा 3. परिवर्तनों का स्थानीयकरण।
पीने वाले अक्सर यह नहीं समझ पाते हैं कि वे किसी और के अपार्टमेंट में, या जहां उनका मोबाइल है, क्यों जाग गए। यह विस्तृत लॉगिंग को जोड़ने का समय है।
आइए डालना प्रक्रिया के साथ लॉगिंग शुरू करें:
class PourOperation: IOperation{ PourOperation(ILogger log /*....*/){/*...*/} //... void Do(){ _log.Log($"Before pour with {_hand} and {_bottle}"); //Pour business logic ... _log.Log($"After pour with {_hand} and {_bottle}"); } }
PourOperation में इसे एनकैप्सुलेट करते हुए , हमने जिम्मेदारी और इनकैप्सुलेशन के मामले में समझदारी से काम लिया, लेकिन अब परिवर्तनशीलता के सिद्धांत के साथ, हम अब शर्मिंदा हैं। ऑपरेशन के अलावा, जो बदल सकता है, लॉगिंग स्वयं ही परिवर्तनशील हो जाता है। हमें अलग करना होगा और डालने का कार्य के लिए एक विशेष लकड़हारा बनाना होगा:
interface IPourLogger{ void LogBefore(IHand, IBottle){} void LogAfter(IHand, IBottle){} void OnError(IHand, IBottle, Exception){} } class PourOperation: IOperation{ PourOperation(IPourLogger log /*....*/){/*...*/} //... void Do(){ _log.LogBefore(_hand, _bottle); try{ //... business logic _log.LogAfter(_hand, _bottle"); } catch(exception e){ _log.OnError(_hand, _bottle, e) } } }
एक सावधानीपूर्वक पाठक ध्यान देगा कि LogAfter , LogBefore और OnError को भी व्यक्तिगत रूप से बदला जा सकता है, और पिछले चरणों के साथ सादृश्य द्वारा, यह तीन कक्षाएं बनाएगा: PourLoggerBefore , PourLoggerAfter, और PourErrorLogger ।
और यह याद रखना कि द्वि घातुमान के लिए तीन ऑपरेशन हैं - हमें लॉगिंग के नौ वर्ग मिलते हैं। नतीजतन, पूरे बूज़ में 14 (!!!) वर्ग होते हैं।
अतिशयोक्ति? शायद ही! एक अपघटन ग्रेनेड के साथ एक बंदर आदमी एक "कंकर" को एक कंटर, एक गिलास, संचालक, एक पानी की आपूर्ति सेवा, अणुओं के टकराव के एक भौतिक मॉडल में कुचल देगा, और अगली तिमाही वैश्विक चर के बिना निर्भरता को उजागर करने की कोशिश करेगा। और मेरा विश्वास करो - वह नहीं रुकेगा।
यह इस बिंदु पर है कि कई लोग इस निष्कर्ष पर आते हैं कि एसआरपी गुलाबी राज्यों से किस्से हैं, और नूडल को मोड़ने के लिए छोड़ देते हैं ...
... Srp की तीसरी परिभाषा के अस्तित्व के बारे में कभी नहीं पता:
" चीजें जो परिवर्तन के समान हैं उन्हें एक ही स्थान पर संग्रहीत किया जाना चाहिए ।" या " जो एक साथ बदलता है उसे एक स्थान पर रखा जाना चाहिए "
यही है, अगर हम ऑपरेशन लॉगिंग को बदलते हैं, तो हमें इसे एक जगह बदलना होगा।
यह एक बहुत ही महत्वपूर्ण बिंदु है - चूंकि एसआरपी के सभी स्पष्टीकरण जो ऊपर कहा गया था कि विभाजित होने के दौरान प्रकारों को विभाजित किया जाना चाहिए, अर्थात, वस्तु के आकार पर "शीर्ष सीमा" लगाई जाती है, और अब हम एक "कम सीमा" के बारे में बात कर रहे हैं। । दूसरे शब्दों में, एसआरपी को न केवल "कुचलने के दौरान कुचलने" की आवश्यकता होती है, बल्कि यह भी अति नहीं है - "चीजों को कुचलने न दें । " अनावश्यक रूप से उलझें नहीं। यह बंदर आदमी के साथ ओकाम के उस्तरा की महान लड़ाई है!
अब बू आसान हो जाना चाहिए। IPourLogger लकड़हारे को तीन वर्गों में विभाजित नहीं करने के अलावा, हम सभी लकड़हारे को एक प्रकार से भी जोड़ सकते हैं:
class OperationLogger{ public OperationLogger(string operationName){/*..*/} public void LogBefore(object[] args){/*...*/} public void LogAfter(object[] args){/*..*/} public void LogError(object[] args, exception e){/*..*/} }
और अगर चौथे प्रकार के ऑपरेशन को हमारे साथ जोड़ा जाता है, तो इसके लिए लॉगिंग तैयार है। और संचालन का कोड स्वयं स्वच्छ और बुनियादी ढाँचे के शोर से मुक्त है।
नतीजतन, पीने की समस्या को हल करने के लिए हमारे पास 5 कक्षाएं हैं:
- ऑपरेशन का काम
- ऑपरेशन पी लो
- जाम संचालन
- Logirovschik
- बूलर्स का मुखौटा
उनमें से प्रत्येक एक कार्यक्षमता के लिए सख्ती से जिम्मेदार है, परिवर्तन का एक कारण है। परिवर्तन के समान सभी नियम पास में स्थित हैं।
वास्तविक जीवन के उदाहरण
सीरियलाइज़ेशन और डिसेरिएलाइज़ेशनडेटा ट्रांसफर प्रोटोकॉल के विकास के एक भाग के रूप में, किसी प्रकार के "उपयोगकर्ता" को एक स्ट्रिंग में क्रमबद्ध करना और अस्वाभाविक बनाना आवश्यक है।
User{ String Name; Int Age; }
आप सोच सकते हैं कि अलग-अलग वर्गों में क्रमांकन और विचलन की आवश्यकता है:
UserDeserializer{ String deserialize(User){...} } UserSerializer{ User serialize(String){...} }
चूंकि उनमें से प्रत्येक की अपनी जिम्मेदारी है और परिवर्तन का एक कारण है।
लेकिन उनके पास परिवर्तन का एक सामान्य कारण है - "डेटा क्रमांकन के प्रारूप को बदलना।"
और जब इस प्रारूप को बदलते हैं, तो क्रमबद्धता और विचलन हमेशा बदलते रहेंगे।
स्थानीयकरण परिवर्तनों के सिद्धांत के अनुसार, हमें उन्हें एक वर्ग में जोड़ना होगा:
UserSerializer{ String deserialize(User){...} User serialize(String){...} }
यह हमें अनावश्यक जटिलता से बचाता है, और यह याद रखने की आवश्यकता है कि हर बार जब आप धारावाहिक को बदलते हैं, तो आपको deserializer के बारे में याद रखना होगा।
गिनती और बचाओआपको कंपनी के वार्षिक राजस्व की गणना करने और इसे C: \ results.txt फ़ाइल में सहेजने की आवश्यकता है।
हम जल्दी से इसे एक विधि से हल करते हैं:
void SaveGain(Company company){ // // }
पहले से ही कार्य की परिभाषा से यह स्पष्ट है कि दो उपप्रकार हैं - "राजस्व की गणना करें" और "राजस्व सहेजें"। उनमें से प्रत्येक में परिवर्तन का एक कारण है - "गणना पद्धति में बदलाव" और "बचत प्रारूप में बदलाव"। ये परिवर्तन ओवरलैप नहीं होते हैं। इसके अलावा, हम इस सवाल का जवाब नहीं दे सकते हैं - "सेवगैन विधि क्या करती है?"। यह और विधि राजस्व की गणना करती है और परिणामों को बचाती है।
इसलिए, आपको इस विधि को दो में विभाजित करने की आवश्यकता है:
Gain CalcGain(Company company){..} void SaveGain(Gain gain){..}
पेशेवरों:
- अलग से CalcGain का परीक्षण किया जा सकता है
- बग्स को स्थानीय बनाना और परिवर्तन करना आसान है
- कोड पठनीयता में वृद्धि हुई
- प्रत्येक विधि में त्रुटि का जोखिम उनके सरलीकरण के कारण कम हो जाता है
परिष्कृत व्यापार तर्कएक बार हमने b2b क्लाइंट के स्वचालित पंजीकरण के लिए एक सेवा लिखी। और समान सामग्री की 200 लाइनों के साथ एक GOD विधि थी:
- 1 सी पर जाएं और एक खाता प्राप्त करें
- इस खाते के साथ, भुगतान मॉड्यूल पर जाएं और वहां इसे प्राप्त करें
- जांचें कि मुख्य सर्वर में ऐसे खाते वाला खाता नहीं बनाया गया है
- एक नया खाता बनाएँ
- भुगतान मॉड्यूल में पंजीकरण परिणाम और नंबर 1 सी पंजीकरण परिणाम सेवा में जोड़ते हैं
- इस तालिका में खाता जानकारी जोड़ें
- बिंदु सेवा में इस ग्राहक के लिए एक बिंदु संख्या बनाएं। यह सेवा खाता संख्या 1s दें।
इस सूची में भयानक कनेक्टिविटी के साथ लगभग 10 और व्यवसाय संचालन थे। खाता वस्तु की आवश्यकता लगभग सभी को थी। आधी कॉल में प्वाइंट आईडी और क्लाइंट नाम की जरूरत थी।
रिफैक्टरिंग के एक घंटे के बाद, हम इंफ्रास्ट्रक्चर कोड और खाते के साथ काम करने की कुछ बारीकियों को अलग-अलग तरीकों / कक्षाओं में अलग करने में सक्षम थे। ईश्वर विधि आसान हो गई, लेकिन कोड की 100 लाइनें शेष थीं जो कि अप्रकाशित नहीं होना चाहती थीं।
कुछ दिनों बाद ही समझ में आया कि इस "राहत मिली" विधि का सार व्यवसाय एल्गोरिथ्म है। और यह कि टीके का प्रारंभिक विवरण जटिल था। और यह इस विधि को टुकड़ों में तोड़ने का प्रयास है जो एसआरपी का उल्लंघन होगा, न कि इसके विपरीत।
यह हमारे लिए अकेले छोड़ने का समय है। आँसू पोंछो - हम निश्चित रूप से किसी तरह इसे वापस कर देंगे। अब हम इस लेख से ज्ञान को औपचारिक रूप देते हैं।
- तत्वों को अलग करें ताकि उनमें से प्रत्येक एक चीज के लिए जिम्मेदार हो।
- जिम्मेदारी "परिवर्तन के कारण" के लिए है। यही है, प्रत्येक तत्व में व्यावसायिक तर्क के संदर्भ में परिवर्तन का केवल एक कारण है।
- संभावित व्यावसायिक तर्क बदल जाते हैं। स्थानीय होना चाहिए। आइटम जो एक साथ उत्परिवर्ती हैं, पास होना चाहिए।
मुझे एसआरपी के कार्यान्वयन के लिए पर्याप्त मानदंड नहीं मिले हैं। लेकिन आवश्यक शर्तें हैं:
1) अपने आप से एक प्रश्न पूछें - यह वर्ग / विधि / मॉड्यूल / सेवा क्या करता है। आपको इसका उत्तर एक साधारण परिभाषा के साथ देना चाहिए। ( ब्राइटोरी को धन्यवाद)
स्पष्टीकरणहालाँकि, कभी-कभी एक साधारण परिभाषा को खोजना बहुत मुश्किल होता है
2) बग को ठीक करना या एक नई सुविधा जोड़ना फ़ाइलों / वर्गों की न्यूनतम संख्या को प्रभावित करता है। आदर्श रूप से, एक।
स्पष्टीकरणचूंकि जिम्मेदारी (एक सुविधा या बग के लिए) किसी एकल फ़ाइल / वर्ग में एनकैप्सुलेटेड है, तो आप जानते हैं कि वास्तव में कहां देखना है और क्या संपादित करना है। उदाहरण के लिए: ऑपरेशन लॉगिंग के आउटपुट को बदलने की सुविधा के लिए केवल लकड़हारे को बदलने की आवश्यकता होगी। बाकी कोड के आसपास चलने की आवश्यकता नहीं है।
एक और उदाहरण पिछले वाले के समान नए यूआई नियंत्रण के अतिरिक्त है। यदि यह आपको 10 अलग-अलग संस्थाओं और 15 अलग-अलग कन्वर्टर्स को जोड़ने के लिए मजबूर करता है - तो ऐसा लगता है कि आप "टूट गए" हैं।
3) यदि कई डेवलपर्स आपकी परियोजना की विभिन्न विशेषताओं पर काम कर रहे हैं, तो मर्ज संघर्ष की संभावना, यानी, यह संभावना कि कई डेवलपर्स एक ही समय में एक ही फ़ाइल / वर्ग को बदल देंगे, न्यूनतम है।
स्पष्टीकरणयदि एक नया ऑपरेशन "टेबल के नीचे डालो वोदका" जोड़ते समय, आपको लकड़हारा, पीने और डालने का कार्य को छूने की आवश्यकता होती है - तो ऐसा लगता है कि जिम्मेदारियां कुटिल रूप से विभाजित हैं। बेशक, यह हमेशा संभव नहीं है, लेकिन आपको इस आंकड़े को कम करने की कोशिश करने की आवश्यकता है।
4) व्यावसायिक तर्क (डेवलपर या प्रबंधक से) के बारे में एक प्रश्न स्पष्ट करते समय, आप एक कक्षा / फ़ाइल में सख्ती से चढ़ते हैं और वहां से केवल जानकारी प्राप्त करते हैं।
स्पष्टीकरणसुविधाएँ, नियम या एल्गोरिदम कॉम्पैक्ट रूप से प्रत्येक को एक स्थान पर लिखे गए हैं, और कोड स्पेस में झंडे द्वारा नहीं बिखरे हुए हैं।
5) नामकरण स्पष्ट है।
स्पष्टीकरणहमारी कक्षा या विधि एक चीज़ के लिए ज़िम्मेदार है, और यह जिम्मेदारी उसके नाम से परिलक्षित होती है।
AllManagersManagerService - सबसे अधिक संभावना है, भगवान-वर्ग
स्थानीयकरण - शायद नहीं
डिजाइन की शुरुआत में, बंदर आदमी को नहीं पता है और समस्या के सभी सूक्ष्मता को हल करने में महसूस नहीं करता है और एक गड़गड़ाहट दे सकता है। आप विभिन्न तरीकों से गलतियाँ कर सकते हैं:
- विभिन्न जिम्मेदारियों को देखकर वस्तुओं को बहुत बड़ा बनायें
- विभाजन, एक ही जिम्मेदारी को कई अलग-अलग प्रकारों में विभाजित करना
- गलत तरीके से परिभाषित सीमाओं की जिम्मेदारी
नियम को याद रखना महत्वपूर्ण है: "यह एक बड़ी गलती करना बेहतर है," या "सुनिश्चित नहीं है - विभाजित न करें।" यदि, उदाहरण के लिए, आपकी कक्षा दो जिम्मेदारियों को एकत्र करती है, तो यह अभी भी समझ में आता है और क्लाइंट कोड में न्यूनतम परिवर्तन के साथ दो में विभाजित किया जा सकता है। कई टुकड़ों में फैले संदर्भ और क्लाइंट कोड में आवश्यक निर्भरता की कमी के कारण ग्लास के टुकड़ों से एक ग्लास एकत्र करना आमतौर पर अधिक कठिन होता है।
यह दौर बंद करने का है
SRP का दायरा OOP और SOLID तक सीमित नहीं है। यह विधियों, कार्यों, कक्षाओं, मॉड्यूल, माइक्रोसॉफ़्ट और सेवाओं पर लागू होता है। यह "अंजीर-अंजीर-और-ठेस" और "रॉकेट-सेंज" विकास दोनों पर लागू होता है, जिससे दुनिया हर जगह थोड़ी बेहतर होती है। यदि आप इसके बारे में सोचते हैं, तो यह लगभग सभी इंजीनियरिंग का मूल सिद्धांत है। मैकेनिकल इंजीनियरिंग, नियंत्रण प्रणाली, और वास्तव में सभी जटिल प्रणालियां घटकों से निर्मित होती हैं, और "अधूरा विखंडन" लचीलेपन के डिजाइनरों, "विखंडन" - दक्षता और गलत सीमाओं से वंचित करता है - कारण और मन की शांति।
एसआरपी का आविष्कार प्रकृति द्वारा नहीं किया गया है और यह सटीक विज्ञान का हिस्सा नहीं है। यह हमारी जैविक और मनोवैज्ञानिक सीमाओं से बाहर निकलता है। यह मानव बंदर के मस्तिष्क का उपयोग करके जटिल प्रणालियों को नियंत्रित करने और विकसित करने का एक तरीका है। वह हमें बताता है कि सिस्टम को कैसे विघटित करना है। मूल शब्दांकन को उचित मात्रा में टेलीपैथी की आवश्यकता थी, लेकिन मुझे आशा है कि इस लेख ने स्मोकस्क्रीन को थोड़ा दूर कर दिया।