2010-04-15 25 views
8

मेरा करियर एक हार्ड-कोर कार्यात्मक-प्रतिमान डेवलपर (एलआईएसपी) के रूप में शुरू हुआ, और अब मैं एक हार्ड-कोर .NET/C# डेवलपर हूं। बेशक मैं LINQ के साथ मोहक हूँ। हालांकि, मैं नौकरी के लिए सही उपकरण का उपयोग करके (1) में विश्वास करता हूं और (2) केआईएसएस सिद्धांत को संरक्षित करता हूं: 60+ इंजीनियरों के साथ मैं काम करता हूं, शायद केवल 20% में LINQ/कार्यात्मक प्रतिमान अनुभव के घंटे हैं, और 5% इस तरह के अनुभव के 6 से 12 महीने है। संक्षेप में, मुझे LINQ से दूर रहने के लिए मजबूर होना पड़ता है जब तक कि मैं इसके बिना एक लक्ष्य प्राप्त करने में बाधा डालता हूं (जिसमें LINQ की एक पंक्ति के साथ ओ-ओ कोड की 3 पंक्तियों को प्रतिस्थापित करना "लक्ष्य" नहीं है)।LINQ (ऑब्जेक्ट्स) पर कब उपयोग किया जाता है?

लेकिन अब 12 महीनों के LINQ/कार्यात्मक-प्रतिमान अनुभव वाले इंजीनियरों में से एक, उत्पादन कोड में हर कल्पनीय स्थान में, LINQ ऑब्जेक्ट्स, या कम से कम लैम्ब्डा अभिव्यक्तियों का उपयोग कर रहा है। केआईएसएस सिद्धांत के लिए मेरी विभिन्न अपीलों ने कोई परिणाम नहीं दिया है। इसलिए ...

मैं किस प्रकाशित अध्ययन के लिए अगली अपील कर सकता हूं? क्या "कोडिंग मानक" दिशानिर्देश दूसरों को कुछ सफलता के साथ concocted है? क्या LINQ प्रदर्शन समस्याओं को प्रकाशित किया गया है जो मैं बता सकता हूं? संक्षेप में, मैं अप्रत्यक्ष दृढ़ता से अपना पहला लक्ष्य - KISS प्राप्त करने की कोशिश कर रहा हूं।

बेशक यह समस्या अनगिनत अन्य क्षेत्रों (जैसे एक्सटेंशन विधियों का अत्यधिक उपयोग) तक बढ़ाया जा सकता है। शायद एक "उबर" गाइड है, अत्यधिक सम्मानित (उदा। प्रकाशित अध्ययन, आदि), जो इस पर एक व्यापक स्विंग लेता है। कुछ भी?

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

//This looks like it was meant to become an extension method... 
public class ExtensionOfThreadPool 
{ 
    public static bool QueueUserWorkItem(Action callback) 
    { 
     return ThreadPool.QueueUserWorkItem((o) => callback()); 
    } 
} 

public class LoadBalancer 
{ 
    //other methods and state variables have been stripped... 

    void ThreadWorker() 
    { 
     // The following callbacks give us an easy way to control whether 
     // we add additional headers around outbound WCF calls. 
     Action<Action> WorkRunner = null; 

     // This callback adds headers to each WCF call it scopes 
     Action<Action> WorkRunnerAddHeaders = (Action action) => 
     { 
      // Add the header to all outbound requests. 
      HttpRequestMessageProperty httpRequestMessage = new HttpRequestMessageProperty(); 
      httpRequestMessage.Headers.Add("user-agent", "Endpoint Service"); 

      // Open an operation scope - any WCF calls in this scope will add the 
      // headers above. 
      using (OperationContextScope scope = new OperationContextScope(_edsProxy.InnerChannel)) 
      { 
       // Seed the agent id header 
       OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestMessage; 

       // Activate 
       action(); 
      } 
     }; 

     // This callback does not add any headers to each WCF call 
     Action<Action> WorkRunnerNoHeaders = (Action action) => 
     { 
      action(); 
     }; 

     // Assign the work runner we want based on the userWCFHeaders 
     // flag. 
     WorkRunner = _userWCFHeaders ? WorkRunnerAddHeaders : WorkRunnerNoHeaders; 

     // This outter try/catch exists simply to dispose of the client connection 
     try 
     { 
      Action Exercise =() => 
      { 
       // This worker thread polls a work list 
       Action Driver = null; 
       Driver =() => 
       { 
        LoadRunnerModel currentModel = null; 
        try 
        { 
         // random starting value, it matters little 
         int minSleepPeriod = 10; 
         int sleepPeriod = minSleepPeriod; 

         // Loop infinitely or until stop signals 
         while (!_workerStopSig) 
         { 
          // Sleep the minimum period of time to service the next element 
          Thread.Sleep(sleepPeriod); 

          // Grab a safe copy of the element list 
          LoadRunnerModel[] elements = null; 
          _pointModelsLock.Read(() => elements = _endpoints); 

          DateTime now = DateTime.Now; 
          var pointsReadyToSend = elements.Where 
           (
            point => point.InterlockedRead(() => point.Live && (point.GoLive <= now)) 
           ).ToArray(); 

          // Get a list of all the points that are not ready to send 
          var pointsNotReadyToSend = elements.Except(pointsReadyToSend).ToArray(); 

          // Walk each model - we touch each one inside a lock 
          // since there can be other threads operating on the model 
          // including timeouts and returning WCF calls. 
          pointsReadyToSend.ForEach 
          (
           model => 
           { 
            model.Write 
            (
             () => 
             { 
              // Keep a record of the current model in case 
              // it throws an exception while we're staging it 
              currentModel = model; 

              // Lower the live flag (if we crash calling 
              // BeginXXX the catch code will re-start us) 
              model.Live = false; 

              // Get the step for this model 
              ScenarioStep step = model.Scenario.Steps.Current; 

              // This helper enables the scenario watchdog if a 
              // scenario is just starting 
              Action StartScenario =() => 
              { 
               if (step.IsFirstStep && !model.Scenario.EnableWatchdog) 
               { 
                model.ScenarioStarted = now; 
                model.Scenario.EnableWatchdog = true; 
               } 
              }; 

              // make a connection (if needed) 
              if (step.UseHook && !model.HookAttached) 
              { 
               BeginReceiveEventWindow(model, step.HookMode == ScenarioStep.HookType.Polled); 
               step.RecordHistory("LoadRunner: Staged Harpoon"); 
               StartScenario(); 
              } 

              // Send/Receive (if needed) 
              if (step.ReadyToSend) 
              { 
               BeginSendLoop(model); 
               step.RecordHistory("LoadRunner: Staged SendLoop"); 
               StartScenario(); 
              } 

             } 
            ); 
           } 
           ,() => _workerStopSig 
          ); 

          // Sleep until the next point goes active. Figure out 
          // the shortest sleep period we have - that's how long 
          // we'll sleep. 
          if (pointsNotReadyToSend.Count() > 0) 
          { 
           var smallest = pointsNotReadyToSend.Min(ping => ping.GoLive); 
           sleepPeriod = (smallest > now) ? (int)(smallest - now).TotalMilliseconds : minSleepPeriod; 
           sleepPeriod = sleepPeriod < 0 ? minSleepPeriod : sleepPeriod; 
          } 
          else 
           sleepPeriod = minSleepPeriod; 
         } 
        } 
        catch (Exception eWorker) 
        { 
         // Don't recover if we're shutting down anyway 
         if (_workerStopSig) 
          return; 

         Action RebootDriver =() => 
         { 
          // Reset the point SendLoop that barfed 
          Stagepoint(true, currentModel); 

          // Re-boot this thread 
          ExtensionOfThreadPool.QueueUserWorkItem(Driver); 
         }; 

         // This means SendLoop barfed 
         if (eWorker is BeginSendLoopException) 
         { 
          Interlocked.Increment(ref _beginHookErrors); 
          currentModel.Write(() => currentModel.HookAttached = false); 
          RebootDriver(); 
         } 
         // This means BeginSendAndReceive barfed 
         else if (eWorker is BeginSendLoopException) 
         { 
          Interlocked.Increment(ref _beginSendLoopErrors); 
          RebootDriver(); 
         } 
         // The only kind of exceptions we expect are the 
         // BeginXXX type. If we made it here something else bad 
         // happened so allow the worker to die completely. 
         else 
          throw; 
        } 
       }; 

       // Start the driver thread. This thread will poll the point list 
       // and keep shoveling them out 
       ExtensionOfThreadPool.QueueUserWorkItem(Driver); 

       // Wait for the stop signal 
       _workerStop.WaitOne(); 

      }; 

      // Start 
      WorkRunner(Exercise); 
     } 
     catch(Exception ex){//not shown} 
    } 
} 
+0

उस स्निपेट के बारे में केवल एक ही शिकायत आपके मूल प्रश्न से कोई लेना देना नहीं है। 1. स्थानीय लोगों का नामकरण करने के लिए असंगत दृष्टिकोण (वे 'ऊंटकेस' होना चाहिए, लेकिन यहां कुछ 'पास्कलकेस' हैं)। 2. यह 'अपवाद' सार्वभौमिक आधार वर्ग पकड़ता है। –

+0

@ डैनियल: आपको लैम्ब्डा की याद नहीं है कि 140 लाइन लंबी हैं, और इसमें 200 से अधिक लाइनों की एक समग्र विधि के लिए 20 से 40 लाइन लैम्बडास के 3 या 4 घोंसला वाले स्तर होते हैं? क्या आपने यह पोस्ट देखा है: http://stackoverflow.com/questions/2627662/anonymous-methods-lambdas-coding- standards –

+0

दो अलग-अलग मुद्दे हैं: 1. भेड़-बकरियां अच्छी या बुरी चीज हैं (स्वयं में)? 2. एक समारोह का दायरा कब लंबा होता है? मैं इस बात से सहमत हूं कि जब कोई कार्य वास्तव में लंबा और गहराई से हो जाता है तो इसे स्पष्ट रूप से स्पष्ट नाम के लिए अलग-अलग नामित कार्यों में विभाजित करने से लाभ हो सकता है, इसलिए यह स्पष्ट है कि कौन से चर कोड के टुकड़े दिखाई दे रहे हैं। लेकिन यह आम तौर पर लंबे कार्यों की एक समस्या है, जो लैम्बडास के लिए विशिष्ट नहीं है। (Cont ...) –

उत्तर

15

अच्छा, यह मुझे लगता है जैसे आप कोड को और अधिक जटिल बनाना चाहते हैं - क्योंकि आप मानते हैं कि आपके सहयोगी वास्तव में सरल दृष्टिकोण तक नहीं हैं।कई, कई मामलों में मुझे लगता है LINQ वस्तुओं के लिए कोड सरल बनाता है - और हाँ कि करता एक करने के लिए बस कुछ ही लाइनों को बदलने में शामिल हैं:

int count = 0; 
foreach (Foo f in GenerateFoos()) 
{ 
    count++; 
} 

int count = GenerateFoos().Count(); 
उदाहरण के लिए

हो रहा है।

कहाँ यह कोड सरल बनाने नहीं है, यह उसे LINQ से दूर चलाने की कोशिश करने के ठीक है - लेकिन ऊपर एक उदाहरण है जहां आप निश्चित रूप से काफी LINQ से बचने के द्वारा बाधा उत्पन्न नहीं कर रहे हैं है, लेकिन "किस" कोड स्पष्ट रूप से LINQ कोड है।

ऐसा लगता है कि आपकी कंपनी को सबसे कम आम denominator के लिए हमेशा अपील करने की कोशिश करने के बजाय, LINQ से ऑब्जेक्ट्स का लाभ लेने के लिए अपने इंजीनियरों को प्रशिक्षण देने से लाभ हो सकता है।

+1

मैं सहमत हूं। इंजीनियरों को LINQ और लैम्ब्डा भलाई में गोता लगाने की जरूरत है। सबकुछ के लिए, निश्चित रूप से, लेकिन इसके लिए हमेशा से बचने से कुछ भी अच्छा नहीं आ सकता है। कंपनी वक्र के पीछे गिर जाएगी, जैसे कर्मचारी होंगे। –

+0

मुझे बेचा जाता है - सिवाय इसके कि पूर्व-मौजूदा बीसीएल एक्सटेंशन विधियों (जैसे गणना() प्रदर्शित) नहीं है मेरे लिए मुद्दा नहीं है। इसके बजाए, आप लॉगिंग हस्ताक्षर के बारे में क्या सोचते हैं जो जानबूझकर स्ट्रिंग्स के बजाय केवल लैम्बडा लेता है: // इस उदाहरण के ~ 10000 घटनाओं को पूरे कोड में मानें ... लॉगर.लॉग (() => "हैलो"); // या ... लॉगर.लॉग (() => स्ट्रिंग.फॉर्मैट ("हे {0}", "वहां")); इसका उद्देश्य लॉगिंग बंद होने पर एक (संदिग्ध) प्रदर्शन को बढ़ावा देना है। –

+3

@ माइस्टागॉग: असल में, मैं कल सहयोगियों से लॉगिंग स्टेटमेंट में तर्क मूल्यांकन को परिभाषित करने के बारे में बात कर रहा था। जब कोई दुष्प्रभाव नहीं होता है, तो यह एक अच्छा विचार है, क्योंकि इसका मतलब है कि आप सशर्त रूप से महंगा-से-प्रारूप विवरणों को सशर्त रूप से लॉग कर सकते हैं, यह जानकर कि मूल्यांकन तब तक नहीं होगा जब तक कि विस्तृत लॉगिंग सक्षम न हो। मैं इसे पसंद करता हूं 'अगर (Logger.IsEnabled (जानकारी)) {Logger.Info (...); } 'जो आम विकल्प है। –

8

आप अधिक से अधिक जटिलता के साथ वस्तुओं के लिए Linq equating हो रहे हैं, क्योंकि आप मानते हैं कि यह के अनावश्यक उपयोग का उल्लंघन "इसे सरल रखें, बेवकूफ"।

मेरा पूरा अनुभव विपरीत रहा है: यह जटिल एल्गोरिदम लिखने और पढ़ने के लिए बहुत आसान बनाता है।

इसके विपरीत, अब मैं अनिवार्य, कथन आधारित, राज्य-उत्परिवर्ती प्रोग्रामिंग को "जोखिम भरा" विकल्प के रूप में उपयोग करता हूं, जब वास्तव में आवश्यक हो।

तो मैं सुझाव दूंगा कि आप लाभ को समझने के लिए अपने अधिक सहयोगियों को प्राप्त करने में प्रयास करें। यह उन लोगों के लिए आपके दृष्टिकोण को सीमित करने की कोशिश करने के लिए एक झूठी अर्थव्यवस्था है जो आप (और अन्य) पहले से ही समझते हैं, क्योंकि इस उद्योग में यह "नए" प्रथाओं के संपर्क में रहने के लिए भारी लाभांश देता है (बेशक, यह सामान शायद ही नया है, लेकिन जैसा कि आप इंगित करते हैं, यह जावा या सी # 1.x पृष्ठभूमि से कई लोगों के लिए नया है)।

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

संबंधित मुद्दे