उदाहरण चर पर स्थानीय चर पसंद करने के लिए तर्क?


109

मैं जिस कोडबेस पर काम कर रहा हूं, वह विभिन्न तुच्छ तरीकों के बीच डेटा साझा करने के लिए अक्सर उदाहरण चर का उपयोग करता है। मूल डेवलपर यह मानता है कि यह अंकल बॉब / रॉबर्ट मार्टिन द्वारा क्लीन कोड बुक में बताई गई सर्वोत्तम प्रथाओं का पालन करता है : "कार्यों का पहला नियम यह है कि वे छोटे होने चाहिए।" और "एक फ़ंक्शन के लिए तर्कों की आदर्श संख्या शून्य (एनलाइडिक) है। (...) तर्क कठिन हैं। वे बहुत अधिक वैचारिक शक्ति लेते हैं।"

एक उदाहरण:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  private byte[] encodedData;
  private EncryptionInfo encryptionInfo;
  private EncryptedObject payloadOfResponse;
  private URI destinationURI;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    getEncodedData(encryptedRequest);
    getEncryptionInfo();
    getDestinationURI();
    passRequestToServiceClient();

    return cryptoService.encryptResponse(payloadOfResponse);
  }

  private void getEncodedData(EncryptedRequest encryptedRequest) {
    encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private void getEncryptionInfo() {
    encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
  }

  private void getDestinationURI() {
    destinationURI = router.getDestination().getUri();
  }

  private void passRequestToServiceClient() {
    payloadOfResponse = serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}

मैं स्थानीय चर का उपयोग करते हुए निम्नलिखित में सुधार करूंगा:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
    EncryptionInfo encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
    URI destinationURI = router.getDestination().getUri();
    EncryptedObject payloadOfResponse = serviceClient.handle(destinationURI, encodedData,
      encryptionInfo);

    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

यह छोटा है, यह विभिन्न तुच्छ तरीकों के बीच निहित डेटा युग्मन को समाप्त करता है और यह चर स्कोप को न्यूनतम आवश्यक तक सीमित करता है। फिर भी इन लाभों के बावजूद मैं अभी भी मूल डेवलपर को यह विश्वास नहीं दिला पा रहा हूं कि यह रीक्रैक्टिंग वारंट है, क्योंकि यह ऊपर वर्णित अंकल बॉब की प्रथाओं का खंडन करता प्रतीत होता है।

इसलिए मेरे सवाल: उदाहरण के चर पर स्थानीय चर के पक्ष में उद्देश्य, वैज्ञानिक तर्क क्या है? मैं अपनी उंगली उस पर नहीं डाल सकता। मेरा अंतर्ज्ञान मुझे बताता है कि छिपे हुए कपलिंग खराब हैं और एक संकीर्ण गुंजाइश एक व्यापक से बेहतर है। लेकिन इसे वापस करने का विज्ञान क्या है?

और इसके विपरीत, क्या इस परावर्तन के लिए कोई डाउनसाइड्स हैं जिन्हें मैंने संभवतः अनदेखा कर दिया है?


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
maple_shaft

जवाबों:


170

उदाहरण के चर पर स्थानीय चर का पक्ष लेने के लिए उद्देश्य, वैज्ञानिक तर्क क्या है?

स्कोप एक द्विआधारी राज्य नहीं है, यह एक ढाल है। आप इन्हें सबसे बड़े से लेकर सबसे छोटे तक का दर्जा दे सकते हैं:

Global > Class > Local (method) > Local (code block, e.g. if, for, ...)

संपादित करें: जिसे मैं "क्लास स्कोप" कहता हूं, उसका अर्थ "उदाहरण चर" से है। मेरी जानकारी के लिए, वे समानार्थी हैं, लेकिन मैं एक सी # देव हूं, न कि जावा देव। संक्षिप्तता के लिए, मैंने सभी स्टेटिक्स को वैश्विक श्रेणी में शामिल किया है क्योंकि स्टेटिक्स प्रश्न का विषय नहीं है।

दायरा जितना छोटा होगा, उतना अच्छा होगा। तर्क यह है कि चर संभव सबसे कम दायरे में रहना चाहिए । इसके कई लाभ हैं:

  • यह आपको वर्तमान वर्ग की जिम्मेदारी के बारे में सोचने के लिए मजबूर करता है और आपको एसआरपी से चिपके रहने में मदद करता है।
  • यह आप वैश्विक नामकरण संघर्ष, जैसे यदि दो या अधिक वर्गों एक है से बचने के लिए की जरूरत नहीं करने में सक्षम बनाता Nameसंपत्ति, तो आप उन्हें तरह उपसर्ग का दबाव नहीं होता FooName, BarName... इस प्रकार के रूप में स्वच्छ और संभव के रूप में संक्षिप्त अपने चर नाम रखे हुए हैं।
  • यह उपलब्ध चर (उदाहरण के लिए Intellisense) को सीमित करके उन कोड को घोषित करता है जो प्रासंगिक रूप से प्रासंगिक हैं।
  • यह कुछ प्रकार के अभिगम नियंत्रण को सक्षम करता है, इसलिए आपके डेटा को कुछ ऐसे अभिनेता द्वारा हेरफेर नहीं किया जा सकता है जिनके बारे में आप नहीं जानते हैं (जैसे एक सहकर्मी द्वारा विकसित एक अलग वर्ग)।
  • यह कोड को अधिक पठनीय बनाता है जैसा कि आप सुनिश्चित करते हैं कि इन चरों की घोषणा से इन चरों के वास्तविक उपयोग के करीब रहने की कोशिश होती है।
  • एक व्यापक रूप से व्यापक दायरे में वेरिएबल्स की घोषणा करना अक्सर एक डेवलपर का संकेत होता है जो ओओपी को समझ नहीं पाता है या इसे कैसे लागू किया जाए। व्यापक रूप से स्कोप किए गए चर को देखकर लाल ध्वज के रूप में कार्य किया जाता है, जिसमें ओओपी दृष्टिकोण (सामान्य रूप से डेवलपर के साथ या विशिष्ट में कोडबेस) के साथ कुछ गलत हो रहा है।
  • (केविन द्वारा टिप्पणी) स्थानीय लोगों का उपयोग आपको चीजों को सही क्रम में करने के लिए मजबूर करता है। मूल (वर्ग चर) कोड में, आप गलत तरीके passRequestToServiceClient()से विधि के शीर्ष पर जा सकते हैं, और यह अभी भी संकलन करेगा। स्थानीय लोगों के साथ, आप केवल उस गलती को कर सकते हैं यदि आपने एक असिंचित चर पारित किया है, जो कि स्पष्ट रूप से पर्याप्त रूप से स्पष्ट है कि आप वास्तव में ऐसा नहीं करते हैं।

फिर भी इन लाभों के बावजूद मैं अभी भी मूल डेवलपर को यह विश्वास नहीं दिला पा रहा हूं कि यह रीक्रैक्टिंग वारंट है, क्योंकि यह ऊपर वर्णित अंकल बॉब की प्रथाओं का खंडन करता प्रतीत होता है।

और इसके विपरीत, क्या इस परावर्तन के लिए कोई डाउनसाइड्स हैं जिन्हें मैंने संभवतः अनदेखा कर दिया है?

यहां मुद्दा यह है कि स्थानीय चर के लिए आपका तर्क मान्य है, लेकिन आपने अतिरिक्त परिवर्तन भी किए हैं जो सही नहीं हैं और गंध परीक्षण को विफल करने के लिए आपके सुझाए गए फ़िक्स का कारण बनते हैं।

जब मैं आपके "नो क्लास वैरिएबल" सुझाव को समझता हूं और इसमें योग्यता है, तो आपने वास्तव में खुद के तरीकों को भी हटा दिया है, और यह एक पूरी तरह से अलग बॉलगेम है। तरीकों को रहना चाहिए था, और इसके बजाय आपको उन्हें एक वर्ग चर में स्टोर करने के बजाय उनके मूल्य को वापस करने के लिए बदल देना चाहिए:

private byte[] getEncodedData() {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
}

private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
}

// and so on...

मैं इस बात से सहमत हूं कि आपने processविधि में क्या किया है , लेकिन आपको अपने शरीर को सीधे निष्पादित करने के बजाय निजी सबमिथोड को फोन करना चाहिए।

public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = getEncodedData();
    EncryptionInfo encryptionInfo = getEncryptionInfo();

    //and so on...

    return cryptoService.encryptResponse(payloadOfResponse);
}

आप चाहते हैं कि अमूर्तता की अतिरिक्त परत, खासकर जब आप उन तरीकों में दौड़ें जिन्हें कई बार पुन: उपयोग करने की आवश्यकता होती है। यहां तक ​​कि अगर आप वर्तमान में अपने तरीकों का पुन: उपयोग नहीं करते हैं , तो यह अभी भी पहले से ही सबमिथोड बनाने के लिए अच्छे व्यवहार की बात है जहां प्रासंगिक है, भले ही केवल कोड पठनीयता सहायता के लिए।

स्थानीय चर तर्क के बावजूद, मैंने तुरंत ध्यान दिया कि आपका सुझाया गया निर्धारण मूल की तुलना में काफी कम पठनीय है। मैं मानता हूं कि वर्ग चर का उपयोग भी कोड पठनीयता से अलग हो जाता है, लेकिन पहली बार में आपकी तुलना में एकल (अब लंबे समय तक घुमावदार) पद्धति में सभी तर्क को ढेर कर दिया।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
maple_shaft

79

मूल कोड तर्क जैसे सदस्य चर का उपयोग कर रहा है। जब वह तर्कों की संख्या को कम करने के लिए कहता है, तो वह वास्तव में इसका मतलब है कि कार्य करने के लिए तरीकों की आवश्यकता वाले डेटा की मात्रा को कम करना है। सदस्य चर में डेटा डालने से कुछ भी सुधार नहीं होता है।


20
पूर्णतया सहमत! वे सदस्य चर बस फ़ंक्शन फ़ंक्शन तर्क हैं। वास्तव में यह बदतर है क्योंकि अब उन चर और फ़ंक्शन उपयोग (एक बाहरी पीओवी से) के मूल्य के बीच कोई स्पष्ट लिंक नहीं है
रेमी

1
मैं कहूंगा कि यह किताब का मतलब नहीं है। कितने कार्यों को चलाने के लिए बिल्कुल शून्य इनपुट डेटा की आवश्यकता होती है? मुझे लगता है कि पुस्तक में से एक बिट गलत था।
क्वर्टी

1
@Qwertie यदि आपके पास कोई ऑब्जेक्ट है, तो यह जिस डेटा पर काम करता है, वह इसके अंदर पूरी तरह से समाविष्ट हो सकता है। फ़ंक्शंस जैसे process.Start();या myString.ToLowerCase()बहुत अजीब नहीं लगने चाहिए (और वास्तव में समझने में सबसे आसान हैं)।
आर। शमित्ज़

5
दोनों का एक तर्क है: निहित this। इस तर्क को एक व्यक्ति भी स्पष्ट रूप से दे सकता है - डॉट से पहले।
ब्लैकजैक

47

अन्य उत्तर पहले से ही स्थानीय चर के लाभों को पूरी तरह से समझा चुके हैं, इसलिए यह सब आपके प्रश्न का हिस्सा है:

फिर भी इन लाभों के बावजूद मैं अभी भी मूल डेवलपर को यह विश्वास नहीं दिला पा रहा हूं कि यह रीक्रैक्टिंग वारंट है, क्योंकि यह ऊपर वर्णित अंकल बॉब की प्रथाओं का खंडन करता प्रतीत होता है।

यह आसान होना चाहिए। बस उसे अंकल बॉब के क्लीन कोड में निम्नलिखित उद्धरण की ओर इशारा करें:

कोई साइड इफेक्ट नहीं है

दुष्प्रभाव झूठ हैं। आपका कार्य एक काम करने का वादा करता है, लेकिन यह अन्य छिपी चीजें भी करता है। कभी-कभी यह अपने स्वयं के वर्ग के चर में अप्रत्याशित परिवर्तन करेगा। कभी-कभी यह उन्हें फ़ंक्शन या सिस्टम ग्लोबल्स में पारित किए गए मापदंडों के लिए बना देगा। या तो मामले में वे कुटिल और हानिकारक mistruths हैं जो अक्सर अजीब अस्थायी कपलिंग और आदेश निर्भरता में परिणाम करते हैं।

(उदाहरण छोड़ा गया)

यह दुष्प्रभाव एक अस्थायी युग्मन बनाता है। यही है, चेकपास को केवल निश्चित समय पर (दूसरे शब्दों में, जब सत्र शुरू करने के लिए सुरक्षित हो) कहा जा सकता है। यदि इसे ऑर्डर आउट कहा जाता है, तो सत्र डेटा अनजाने में खो सकता है। टेम्पोरल कप्लिंग भ्रमित कर रहे हैं, खासकर जब साइड इफेक्ट के रूप में छिपाया गया हो। यदि आपके पास एक अस्थायी युग्मन होना चाहिए, तो आपको इसे फ़ंक्शन के नाम पर स्पष्ट करना चाहिए। इस मामले में हम फ़ंक्शन checkPasswordAndInitializeSession का नाम बदल सकते हैं, हालांकि यह निश्चित रूप से "एक काम करो" का उल्लंघन करता है।

यही है, अंकल बॉब केवल यह नहीं कहते हैं कि एक फ़ंक्शन को कुछ तर्क देना चाहिए, वह यह भी कहता है कि जब भी संभव हो गैर-स्थानीय राज्य के साथ बातचीत करने से बचना चाहिए।


3
"प्रीफेक्ट दुनिया" में, यह सूचीबद्ध दूसरा उत्तर होगा। आदर्श स्थिति के लिए पहला जवाब जो सहकर्मी तर्क से सुनता है - लेकिन अगर सहकर्मी एक उत्साही है, तो यहां यह जवाब बहुत अधिक फजीहत के बिना स्थिति से निपटेगा।
आर। शमित्ज़

2
इस विचार पर अधिक व्यावहारिक भिन्नता के लिए, यह बस इतना है कि उदाहरण के लिए या वैश्विक राज्य की तुलना में स्थानीय स्थिति के बारे में जानना बहुत आसान है। अच्छी तरह से परिभाषित और कसकर समरूपता और साइड इफेक्ट्स शायद ही कभी मुद्दों को जन्म देते हैं। उदाहरण के लिए, कई प्रकार के कार्य साइड इफेक्ट के माध्यम से इन-प्लेस संचालित होते हैं, लेकिन स्थानीय स्कोप के बारे में तर्क करना आसान है।
बीफ़स्टर

1
आह, अच्छा पुराना "एक विरोधाभासी स्वयंसिद्ध में, यह कुछ भी साबित करना संभव है"। चूंकि कोई कठिन सच्चाई और झूठ IRL नहीं हैं, इसलिए किसी भी हठधर्मिता को उन बयानों को शामिल करना होगा जो विपरीत चीजों को राज्य करते हैं अर्थात विरोधाभासी हों।
ivan_pozdeev

26

"यह विरोधाभास करता है कि किसी के चाचा को क्या लगता है" यह एक अच्छा तर्क है। कभी नहीँ। चाचाओं से ज्ञान न लें, अपने लिए सोचें।

उदाहरण के लिए, उदाहरण के चर का उपयोग उन सूचनाओं को संग्रहीत करने के लिए किया जाना चाहिए जो वास्तव में स्थायी या अर्ध-स्थायी रूप से संग्रहीत की जानी चाहिए। यहाँ जानकारी नहीं है। उदाहरण चर के बिना रहना बहुत सरल है, इसलिए वे जा सकते हैं।

परीक्षण: प्रत्येक उदाहरण चर के लिए एक दस्तावेजी टिप्पणी लिखें। क्या आप कुछ भी लिख सकते हैं जो पूरी तरह से व्यर्थ नहीं है? और चार एक्सेसर्स के लिए एक डॉक्यूमेंटेशन कमेंट लिखें। वे समान रूप से निरर्थक हैं।

सबसे खराब है, परिवर्तनों को डिक्रिप्ट करने का तरीका, क्योंकि आप एक अलग क्रिप्टोकरेंसी का उपयोग करते हैं। कोड की चार लाइनों को बदलने के बजाय, आपको चार उदाहरण चर को अलग-अलग, चार गेटर्स को अलग-अलग लोगों के साथ बदलना होगा और कोड की चार लाइनों को बदलना होगा।

लेकिन निश्चित रूप से पहला संस्करण बेहतर है यदि आपको कोड की लाइन द्वारा भुगतान किया जाता है। 11 लाइनों के बजाय 31 लाइनें। लिखने के लिए तीन गुना अधिक लाइनें, और हमेशा बनाए रखने के लिए, जब आप किसी चीज़ पर डिबगिंग कर रहे हों, तब पढ़ने के लिए, जब बदलाव की आवश्यकता हो तो उसे अनुकूलित करने के लिए, यदि आप दूसरी क्रिप्टोकरेंसी का समर्थन करते हैं तो डुप्लिकेट करने के लिए।

(महत्वपूर्ण बिंदु को याद किया कि स्थानीय चर का उपयोग आपको कॉल को सही क्रम में करने के लिए मजबूर करता है)।


16
अपने लिए सोचना निश्चित रूप से अच्छा है। लेकिन आपके शुरुआती पैराग्राफ में शिक्षार्थियों या वरिष्ठों के इनपुट को खारिज करने वाले शिक्षार्थी या जूनियर शामिल हैं; जो बहुत दूर तक जाता है।
फ्लर्ट

9
@ फैलेटर शिक्षकों या वरिष्ठों के इनपुट के बारे में सोचने के बाद, और उन्हें गलत देखना, उनके इनपुट को खारिज करना ही सही बात है। अंत में, यह खारिज करने के बारे में नहीं है, लेकिन इसके बारे में सवाल करना और केवल इसे खारिज करना अगर यह निश्चित रूप से गलत साबित होता है।
प्रातः

10
@ChristianHackl: मैं पूरी तरह से पारंपरिक रूप से आँख बंद करके पारंपरिकता का पालन नहीं कर रहा हूँ, लेकिन मैं इसे आँख मूंदकर भी खारिज नहीं करूँगा। उत्तर प्रतीत होता है कि आपके अपने दृष्टिकोण के पक्ष में अर्जित ज्ञान को बचाना है, और यह एक स्वस्थ दृष्टिकोण नहीं है। दूसरों की राय का अंधा पालन करते हुए, नहीं। जब आप असहमत हों तो कुछ सवाल करना, जाहिर है हां। इसे खारिज करना क्योंकि आप असहमत हैं, नहीं। जैसा कि मैंने इसे पढ़ा, जवाब के पहले पैराग्राफ में कम से कम लगता है उत्तरार्द्ध सुझाव देने के लिए। यह बहुत हद तक इस बात पर निर्भर करता है कि "अपने लिए सोचें" के साथ gnasher का क्या मतलब है, जिसे विस्तार की आवश्यकता है।
फ्लेटर

9
एक साझा ज्ञान मंच पर, यह थोड़ी सी जगह से बाहर लगता है ...
drjpizzle

4
कभी-कभी यह भी एक अच्छा तर्क है ... मैं पूरी तरह से सहमत हूं कि नियम मार्गदर्शन करने के लिए मौजूद हैं, न कि निर्धारित करने के लिए। हालाँकि, नियमों के बारे में नियम हैं, लेकिन नियमों का एक उपवर्ग है, इसलिए आपने अपना फैसला सुनाया ...
cmaster

14

उदाहरण के चर पर स्थानीय चर का पक्ष लेने के लिए उद्देश्य, वैज्ञानिक तर्क क्या है? मैं अपनी उंगली उस पर नहीं डाल सकता। मेरा अंतर्ज्ञान मुझे बताता है कि छिपे हुए कपलिंग खराब हैं और एक संकीर्ण गुंजाइश एक व्यापक से बेहतर है। लेकिन इसे वापस करने का विज्ञान क्या है?

इंस्टेंस चर अपने मेजबान वस्तु के गुणों का प्रतिनिधित्व करने के लिए होते हैं, कि कम्प्यूटेशन के थ्रेड्स के लिए विशिष्ट गुणों का प्रतिनिधित्व करने के लिए, जो वस्तु की तुलना में अधिक संकीर्ण रूप से स्कूप किए जाते हैं। इस तरह के अंतर को चित्रित करने के कुछ कारण जो पहले से ही कवर नहीं किए गए हैं, वे संगामिति और पुनरावृत्ति के चारों ओर घूमते हैं। यदि विधियाँ उदाहरण चर के मानों को निर्धारित करके डेटा का आदान-प्रदान करती हैं, तो दो समवर्ती धागे उन उदाहरणों चर के लिए एक दूसरे के मूल्यों को आसानी से रोक सकते हैं, आंतरायिक, कठिन-से-ज्ञात कीड़े पैदा कर सकते हैं।

यहां तक ​​कि अकेले एक धागा उन रेखाओं के साथ समस्याओं का सामना कर सकता है, क्योंकि एक उच्च जोखिम है कि उदाहरण के चर पर भरोसा करने वाला एक डेटा विनिमय पैटर्न तरीकों को गैर-रीएंट्रेंट बनाता है। इसी तरह, यदि एक ही चर का उपयोग विभिन्न जोड़े विधियों के बीच डेटा को संप्रेषित करने के लिए किया जाता है, तो एक जोखिम है कि विधि आवेगों की गैर-पुनरावर्ती श्रृंखला को निष्पादित करने वाला एक एकल धागा भी शामिल होगा, जिसमें शामिल चर चर के अनपेक्षित संशोधनों के आसपास घूमते हुए कीड़े होंगे।

ऐसे परिदृश्य में विश्वसनीय रूप से सही परिणाम प्राप्त करने के लिए, आपको प्रत्येक जोड़ी के तरीकों के बीच संवाद करने के लिए अलग-अलग चर का उपयोग करने की आवश्यकता है, जहां एक दूसरे को आमंत्रित करता है, या फिर हर विधि के कार्यान्वयन को ध्यान में रखते हुए सभी अन्य कार्यान्वयन विवरणों को लेना होगा। यह तरीके, चाहे प्रत्यक्ष या अप्रत्यक्ष रूप से। यह भंगुर है, और यह खराब पैमाने पर है।


7
अब तक, यह एकमात्र उत्तर है जिसमें थ्रेड-सेफ्टी और कंसिस्टेंसी का उल्लेख है। यह इस तरह का आश्चर्यजनक है कि प्रश्न में विशिष्ट कोड उदाहरण दिया गया है: SomeBusinessProcess का उदाहरण सुरक्षित रूप से एक ही बार में कई एन्क्रिप्टेड अनुरोधों को संसाधित नहीं कर सकता है। विधि public EncryptedResponse process(EncryptedRequest encryptedRequest)सिंक्रनाइज़ नहीं है, और समवर्ती कॉल संभवतया उदाहरण चर के मानों को बंद कर देंगे। यह एक अच्छा मुद्दा है।
जोशुआ टेलर

9

सिर्फ चर्चा करना process(...), आपके सहयोगियों का उदाहरण व्यावसायिक तर्क की दृष्टि से कहीं अधिक सुपाठ्य है। इसके विपरीत आपका काउंटर उदाहरण किसी भी अर्थ को निकालने के लिए सरसरी नज़र से अधिक लेता है।

कहा जा रहा है कि, साफ कोड दोनों सुपाठ्य और अच्छी गुणवत्ता वाला है - स्थानीय राज्य को अधिक वैश्विक स्थान पर धकेलना उच्च स्तरीय विधानसभा है, इसलिए गुणवत्ता के लिए एक शून्य है।

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest request) {
    checkNotNull(encryptedRequest);

    return encryptResponse
      (routeTo
         ( destination()
         , requestData(request)
         , destinationEncryption()
         )
      );
  }

  private byte[] requestData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo destinationEncryption() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI destination() {
    return router.getDestination().getUri();
  }

  private EncryptedObject routeTo(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }

  private void encryptResponse(EncryptedObject payloadOfResponse) {
    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

यह एक प्रतिपादन है जो किसी भी दायरे में चर की आवश्यकता को दूर करता है। हाँ संकलक उन्हें उत्पन्न करेगा लेकिन महत्वपूर्ण हिस्सा यह है कि यह नियंत्रित करता है कि कोड कुशल होगा। जबकि अपेक्षाकृत सुपाठ्य भी।

नामकरण पर सिर्फ एक बिंदु। आप सबसे छोटा नाम चाहते हैं जो सार्थक हो और पहले से उपलब्ध जानकारी पर विस्तार करता हो। अर्थात। गंतव्य, 'URI' पहले से ही हस्ताक्षर के द्वारा जाना जाता है।


4
सभी चर को खत्म करना जरूरी नहीं है कि कोड को पढ़ना आसान हो।
फाप

पॉइंटफ्री स्टाइल के साथ सभी वैरिएबल को पूरी तरह से खत्म करें en.wikipedia.org/wiki/Tacit_programming
Marcin

@ सच, ​​चर की कमी से सुगमता सुनिश्चित नहीं होती। कुछ मामलों में यह डिबगिंग को और भी कठिन बना देता है। मुद्दा यह है कि अच्छी तरह से चुने गए नाम, अभिव्यक्ति का स्पष्ट उपयोग, एक विचार को बहुत स्पष्ट रूप से संवाद कर सकते हैं, जबकि अभी भी कुशल हैं।
Kain0_0

7

मैं इन चरों और निजी तरीकों को पूरी तरह से हटा दूंगा। यहाँ मेरा रिफ्लेक्टर है:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    return cryptoService.encryptResponse(
        serviceClient.handle(router.getDestination().getUri(),
        cryptoService.decryptRequest(encryptedRequest, byte[].class),
        cryptoService.getEncryptionInfoForDefaultClient()));
  }
}

निजी पद्धति के लिए, उदाहरण के router.getDestination().getUri()लिए स्पष्ट और अधिक पठनीय है getDestinationURI()। मैं यहां तक ​​कहूंगा कि यदि मैं एक ही कक्षा में दो बार एक ही लाइन का उपयोग करता हूं। इसे दूसरे तरीके से देखने के लिए, अगर वहाँ की आवश्यकता है getDestinationURI(), तो यह संभवतः किसी अन्य वर्ग में है, कक्षा में नहीं SomeBusinessProcess

चरों और गुणों के लिए, उनके लिए आम आवश्यकता है कि समय के बाद उपयोग किए जाने वाले मानों को धारण करना। यदि वर्ग में गुणों के लिए कोई सार्वजनिक इंटरफ़ेस नहीं है, तो संभवतः उन्हें गुण नहीं होने चाहिए। साइड इफेक्ट्स के माध्यम से निजी तरीकों के बीच मूल्यों को पारित करने के लिए शायद सबसे खराब प्रकार का वर्ग गुण है।

वैसे भी, वर्ग को केवल करने की आवश्यकता है process()और फिर वस्तु को फेंक दिया जाएगा, किसी भी राज्य को स्मृति में रखने की आवश्यकता नहीं है। इसके अलावा रिफ्लैक्टर क्षमता क्रिप्टो सर्विस को उस वर्ग से बाहर निकालने की होगी।

टिप्पणियों के आधार पर, मैं इस उत्तर को जोड़ना चाहता हूं जो वास्तविक विश्व अभ्यास पर आधारित है। दरअसल, कोड की समीक्षा में, पहली चीज जो मैं बाहर निकालूंगा, वह है क्लास को रिफलेक्टर करना और एन्क्रिप्ट / डिक्रिप्ट वर्क को बाहर करना। एक बार जब ऐसा हो जाता है, तो मैं पूछता हूं कि क्या तरीकों और चर की जरूरत है, क्या उन्हें सही तरीके से नाम दिया गया है और इसी तरह। अंतिम कोड संभवतः इसके करीब होगा:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;

  public Response process(Request request) {
    return serviceClient.handle(router.getDestination().getUri());
  }
}

उपरोक्त कोड के साथ, मुझे नहीं लगता कि इसे और अधिक रिफ्लेक्टर की आवश्यकता है। नियमों के रूप में, मुझे लगता है कि यह जानना अनुभव होता है कि उन्हें कब और कैसे लागू करना है। नियम वे सिद्धांत नहीं हैं जो सभी स्थितियों में काम करने के लिए सिद्ध होते हैं।

दूसरी ओर कोड की समीक्षा का वास्तविक प्रभाव होता है कि कोड का एक टुकड़ा कितनी देर पहले गुजर सकता है। मेरी चाल कम कोड है और इसे समझना आसान है। एक चर नाम चर्चा का विषय हो सकता है, अगर मैं इसे हटा सकता हूं तो समीक्षकों को इसके बारे में सोचने की आवश्यकता नहीं होगी।


मेरा उत्थान, हालांकि कई यहाँ संकोच करेंगे। बेशक कुछ सार, समझ में आता है। (बीटीडब्ल्यू "प्रक्रिया" नामक एक विधि भयानक है।) लेकिन यहां तर्क न्यूनतम है। हालांकि ओपी का सवाल पूरी तरह से कोड शैली पर है, और वहां मामला अधिक जटिल हो सकता है।
जोप इगेन

1
एक स्पष्ट तरीका यह सब एक विधि कॉल में पीछा करने के साथ सरासर पठनीयता है। यदि आप किसी दिए गए ऑब्जेक्ट पर एक से अधिक ऑपरेशन की आवश्यकता है तो भी यह काम नहीं करता है। इसके अलावा, यह डीबग करना असंभव है क्योंकि आप संचालन के माध्यम से कदम नहीं उठा सकते हैं और वस्तुओं का निरीक्षण नहीं कर सकते हैं। हालांकि यह तकनीकी स्तर पर काम करता है, मैं इसके लिए वकालत नहीं करूंगा क्योंकि यह सॉफ्टवेयर विकास के गैर-रनटाइम पहलुओं की बड़े पैमाने पर उपेक्षा करता है।
10

@ मैं आपकी टिप्पणियों से सहमत हूं, हम इसे हर जगह लागू नहीं करना चाहते हैं। मैंने अपनी व्यावहारिक स्थिति स्पष्ट करने के लिए अपना उत्तर संपादित किया। मैं जो दिखाना चाहता हूं वह यह है कि व्यवहार में हम उचित होने पर ही नियम लागू करते हैं। इस उदाहरण में चेनिंग विधि कॉल ठीक है, और यदि मुझे डिबग करने की आवश्यकता है, तो मैं जंजीर विधियों के लिए परीक्षणों का आह्वान करूंगा।
imel96

@JupEggen हाँ, सार समझ में आता है। उदाहरण में, निजी तरीके किसी भी तरह का कोई सार नहीं देते हैं, वर्ग के उपयोगकर्ता उनके बारे में भी नहीं जानते हैं
imel96

1
@ imel96 यह मज़ेदार है कि आप शायद यहाँ कुछ लोगों में से एक हैं जिन्होंने देखा कि ServiceClient और CryptoService के बीच युग्मन से CS को SBP में इंजेक्ट करने पर ध्यान केंद्रित करने लायक हो जाता है बजाय इसके कि SBP में उच्च वास्तुशिल्प स्तर पर अंतर्निहित समस्या को हल किया जाए ... इस कहानी का मुख्य बिंदु IMVHO है; विवरणों पर ध्यान केंद्रित करते हुए बड़ी तस्वीर का ट्रैक रखना बहुत आसान है।
vaxquis

4

फ्लैटर का उत्तर स्कूपिंग के मुद्दों को अच्छी तरह से कवर करता है, लेकिन मुझे लगता है कि यहां एक और मुद्दा भी है।

ध्यान दें कि डेटा को संसाधित करने वाले फ़ंक्शन और बस डेटा तक पहुंचने वाले फ़ंक्शन के बीच अंतर है ।

पूर्व वास्तविक व्यापार तर्क को निष्पादित करता है, जबकि बाद वाला टाइपिंग बचाता है और शायद एक सरल और अधिक पुन: प्रयोज्य इंटरफ़ेस जोड़कर सुरक्षा जोड़ता है।

इस मामले में ऐसा लगता है कि डेटा-एक्सेस फ़ंक्शंस टाइपिंग को सहेजते नहीं हैं, और कहीं भी पुन: उपयोग नहीं किए जाते हैं (या उन्हें हटाने में अन्य मुद्दे होंगे)। तो इन कार्यों को बस अस्तित्व में नहीं होना चाहिए।

नामित कार्यों में केवल व्यावसायिक तर्क रखने से, हम दोनों दुनिया के सर्वश्रेष्ठ (कहीं-कहीं फ़्लेटर के उत्तर और imel96 के उत्तर के बीच ) प्राप्त करते हैं:

public EncryptedResponse process(EncryptedRequest encryptedRequest) {

    byte[] requestData = decryptRequest(encryptedRequest);
    EncryptedObject responseData = handleRequest(router.getDestination().getUri(), requestData, cryptoService.getEncryptionInfoForDefaultClient());
    EncryptedResponse response = encryptResponse(responseData);

    return response;
}

// define: decryptRequest(), handleRequest(), encryptResponse()

3

पहली और सबसे महत्वपूर्ण बात: अंकल बॉब कभी-कभी एक उपदेशक की तरह लगते हैं, लेकिन कहते हैं कि उनके नियमों के अपवाद हैं।

स्वच्छ संहिता का पूरा विचार पठनीयता में सुधार और त्रुटियों से बचने के लिए है। कई नियम हैं जो एक दूसरे का उल्लंघन कर रहे हैं।

फ़ंक्शंस पर उनका तर्क यह है कि निलादिक फ़ंक्शंस सर्वश्रेष्ठ हैं, हालांकि तीन पैरामीटर तक स्वीकार्य हैं। मुझे व्यक्तिगत रूप से लगता है कि 4 भी ठीक हैं।

जब उदाहरण चर का उपयोग किया जाता है, तो उन्हें एक सुसंगत वर्ग बनाना चाहिए। इसका मतलब है, चर का उपयोग कई में किया जाना चाहिए, यदि सभी गैर-स्थिर तरीके नहीं हैं।

चर जो कक्षा के कई स्थानों पर उपयोग नहीं किए जाते हैं, उन्हें स्थानांतरित किया जाना चाहिए।

मैं न तो मूल और न ही रिफलेक्ट किए गए संस्करण इष्टतम पर विचार करूंगा, और @Fater ने पहले ही बहुत अच्छी तरह से कहा कि वापसी मूल्यों के साथ क्या किया जा सकता है। यह पठनीयता में सुधार करता है और रिटर्न मान का उपयोग करने के लिए त्रुटियों को कम करता है।


1

स्थानीय चर गुंजाइश कम कर देते हैं, इसलिए चर को उपयोग करने के तरीकों को सीमित करते हैं और इसलिए कुछ वर्गों की त्रुटि को रोकने में मदद करते हैं, और पठनीयता में सुधार करते हैं।

इंस्टेंस वेरिएबल उन तरीकों को कम करता है जिनमें फ़ंक्शन को कहा जा सकता है जो कुछ निश्चित वर्गों की त्रुटि को कम करने में मदद करता है, और पठनीयता में सुधार करता है।

यह कहना कि एक सही है और दूसरा गलत है, किसी एक विशेष मामले में एक अच्छा निष्कर्ष हो सकता है, लेकिन सामान्य सलाह के रूप में ...

TL; DR: मुझे लगता है कि आपके कारण बहुत अधिक जोश की गंध होती है, बहुत अधिक उत्साह है।


0

इस तथ्य के बावजूद कि तरीकों की शुरुआत हो रही है ... शून्य नहीं लौटना चाहिए, तरीकों के भीतर अमूर्तता के स्तर का पृथक्करण पहले समाधान में दिया गया है। हालांकि दूसरा उपाय अधिक स्कोप है, फिर भी विधि में क्या चल रहा है, इसके बारे में तर्क करना अभी भी कठिन है। स्थानीय चर के कार्य की यहाँ आवश्यकता नहीं है। मैं विधि नाम रखूंगा और कोड को कुछ इस तरह से रिफलेक्टर करूंगा:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    return getEncryptedResponse(
            passRequestToServiceClient(getDestinationURI(), getEncodedData(encryptedRequest) getEncryptionInfo())
        );
  }

  private EncryptedResponse getEncryptedResponse(EncryptedObject encryptedObject) {
    return cryptoService.encryptResponse(encryptedObject);
  }

  private byte[] getEncodedData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI getDestinationURI() {
    return router.getDestination().getUri();
  }

  private EncryptedObject passRequestToServiceClient(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}

0

दोनों चीजें समान हैं और प्रदर्शन अंतर ध्यान देने योग्य नहीं हैं, इसलिए मुझे नहीं लगता कि एक वैज्ञानिक तर्क है। यह तो व्यक्तिपरक वरीयताओं के लिए नीचे आता है।

और मैं भी अपने सहकर्मी से बेहतर आपके तरीके को पसंद करता हूं। क्यों? क्योंकि मुझे लगता है कि कुछ पुस्तक लेखक क्या कहते हैं, इसके बावजूद पढ़ना और समझना आसान है।

दोनों ही तरीके एक ही चीज को पूरा करते हैं, लेकिन उसका तरीका ज्यादा फैला हुआ है। उस कोड को पढ़ने के लिए आपको कई फ़ंक्शन और सदस्य चर के बीच आगे-पीछे शिफ्ट करना होगा। यह सभी एक जगह पर गाढ़ा नहीं है, आपको इसे समझने के लिए अपने दिमाग में वह सब याद रखना होगा। यह एक बहुत बड़ा संज्ञानात्मक भार है।

इसके विपरीत, आपका दृष्टिकोण सब कुछ बहुत अधिक घनत्व में पैक करता है, लेकिन इसे अभेद्य बनाने के लिए ऐसा नहीं है। आप बस लाइन के बाद इसे पढ़ते हैं, और आपको इसे समझने के लिए इतना याद करने की आवश्यकता नहीं है।

लेकिन अगर वह है इस्तेमाल किया तरह के एक फैशन में बाहर रखी जा रही कोड के लिए, मैं कल्पना कर सकते हैं कि उसके लिए यह इसका उल्टा हो सकता है।


यह वास्तव में प्रवाह को समझने के लिए मेरे लिए एक बड़ी बाधा साबित हुई है। यह उदाहरण काफी छोटा है, लेकिन एक अन्य ने अपने मध्यवर्ती परिणामों के लिए 35 (!) उदाहरण चर का इस्तेमाल किया, न कि निर्भरता वाले दर्जनों उदाहरण चर की गिनती। इसके साथ पालन करना काफी कठिन था, क्योंकि आपको पहले से तय किए गए कार्यों का ट्रैक रखना होगा। कुछ को बाद में पुन: उपयोग भी किया गया, जिससे यह और भी कठिन हो गया। सौभाग्य से यहाँ प्रस्तुत तर्कों ने अंतत: मेरे सहयोगी को फिर से विचार करने के लिए सहमत कर लिया।
अलेक्जेंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.