मेरी टीम में अन्य प्रोग्रामरों के लिए मेरे कोड को अधिक पठनीय बनाने की आवश्यकता है


11

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

  1. PostgreSQL स्थापना / स्थापना रद्द करें
  2. myapplication (myapplication की स्थापना nsi का उपयोग करके बनाई गई है) स्थापना / स्थापना रद्द करें।
  3. स्क्रिप्ट (बैच फ़ाइलों) के माध्यम से पोस्टग्रेज में टेबल बनाना

हर चीज ठीक और सुचारू रूप से चलती है, लेकिन अगर कुछ विफल होता है तो मैंने एक LogToFileger बनाया है जो इस प्रक्रिया के हर चरण को LogToFile करेगा,
जैसे कि

LogToFileToFile.LogToFile('[DatabaseInstallation]  :  [ACTION]:Postgres installation started');

फ़ंक्शन LogToFileToFile.LogToFile()यह सामग्री को किसी फ़ाइल में लिख देगा। यह अच्छी तरह से काम कर रहा है, लेकिन समस्या यह है कि इसने कोड को गड़बड़ कर दिया है क्योंकि इसमें कोड को पढ़ना मुश्किल हो गया है क्योंकि एक सीए केवल LogToFileToFile.LogToFile()कोड में हर जगह फ़ंक्शन कॉल देखता है।

एक उदाहरण

 if Not FileExists(SystemDrive+'\FileName.txt') then
 begin
    if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying FileName.txt to '+SystemDrive+'\ done')
       else
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying FileName.txt to '+SystemDrive+'\ Failed');
 end;
 if Not FileExists(SystemDrive+'\SecondFileName.txt')      then
   begin
     if CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False) then
       LogToFileToFile.LogToFile('[DatabaseInstallation] : copying SecondFileName.txt to '+SystemDrive+'\ done')
   else
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying SecondFileName.txt to '+SystemDrive+'\ Failed');
 end;

जैसा कि आप देख सकते हैं कि बहुत सारे LogToFileToFile.LogToFile()कॉल थे,
पहले यह था

 if Not FileExists(SystemDrive+'\FileName.txt') then
    CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) 
 if Not FileExists(SystemDrive+'\SecondFileName.txt')      then
   CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False)

अब मेरे पूरे कोड में यही स्थिति है।
पढ़ना मुश्किल है।

क्या कोई मुझे LogToFile पर कॉल को अव्यवस्थित करने का एक अच्छा तरीका सुझा सकता है?

पसंद


  1. इस तरह से 'LogToFileToFile.LogToFile () कॉल का संकेत

       if Not FileExists(SystemDrive+'\FileName.txt') then
         begin
             if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then
            {Far away--->>}                   LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful')
       else
            {Far away--->>}                   LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed');
       end;
    
  2. अलग इकाई की तरह LogToFileger
    इस इकाई में एक में सभी LogToFile संदेशों होगा switch caseइस तरह

     Function LogToFilegingMyMessage(LogToFilegMessage : integer)
    
     begin
    case  LogToFilegMessage of
    
    1         :  LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful');
    2         :  LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed');
       150        :  LogToFileToFile.LogToFile(2,'[somthing] :  [ACTION]: somthing important);
    
    end;
    

इसलिए मैं बस LogToFilegingMyMessage (1) को कॉल कर सकता हूं जहां कभी भी आवश्यकता हो।

क्या कोई मुझे बता सकता है कि इस तरह से LogToFileging के लिए एक बेहतर और क्लीनर दृष्टिकोण क्या है?


5
अपने विषय का उत्तर देने के लिए: क्या आपने अपनी टीम से यह पूछने की कोशिश की है कि क्या वे इसे समझते हैं या यदि यह सब समझ में आता है? यदि हाँ, तो यह "पर्याप्त" पठनीय होना चाहिए।
Spoike

@ साइकाइक: मैंने पूछा, इसका पढ़ना थोड़ा मुश्किल है, क्योंकि हर जगह logBook.log()इसका सामना करना पड़ता है।
प्रेस्लीडियस

"दो मुख्य भाग हैं" 1 से 3 की संख्या। मुझे लगता है कि मैं देख रहा हूं कि आपके पास पठनीयता पर सवाल क्यों है। आप किसी ऐसे व्यक्ति को ढूंढना चाहते हैं जो स्थिरता के लिए "संपादन" कर सके।
S.Lott

@ एस.लॉट आई ने 'दो' को 'तीन' के लिए संपादित किया .. गलती के लिए
प्रेस्लीडियस

आप चाहें तो codereview.stackexchange.com
Kirk

जवाबों:


11

जब आप लॉगिंग जोड़ते हैं, तो आपने दो चीजें पेश की हैं:

  1. कोड बड़ा हो गया क्योंकि लगभग हर क्रिया के लिए, आपने एक पंक्ति जोड़ी जो उस क्रिया (या उसकी विफलता) को जोड़ती है
  2. लॉग लाइनें स्वयं फूला हुआ दिखाई देती हैं और पठनीयता से दूर ले जाती हैं क्योंकि वे इतना कमरा लेते हैं।

इन समस्याओं में से प्रत्येक का अपना, अपेक्षाकृत सरल समाधान है:

  1. छोटे कार्यों में कोड को तोड़ें। एक विशाल फ़ंक्शन होने के बजाय जिसमें आपकी सभी प्रतियां शामिल हैं और साथ ही त्रुटि / सफलता के लिए लॉग संदेश भी हैं, आप एक फ़ंक्शन "CopyFile" पेश कर सकते हैं, जो बिल्कुल एक फ़ाइल की प्रतिलिपि बनाएगा और लॉग इसका स्वयं का परिणाम होगा। इस तरह से आपका मुख्य कोड सिर्फ CopyFile कॉल से युक्त होगा और पढ़ना आसान होगा।

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

यदि आप अनुसरण करते हैं (1), तो आपके पास ऐसा कोड हो सकता है जो इस तरह दिखता है:

CopyFile( sOSDrive, 'Mapannotation.txt' )
CopyFile( sOSDrive, 'Mappoints.txt' )
CopyFile( sOSDrive, 'Mapsomethingelse.txt' )
. . . .

तब आपके CopyFile () को कार्रवाई करने और इसके परिणाम को लॉग करने के लिए कोड की कुछ पंक्तियों की आवश्यकता होती है, इसलिए आपका सभी कोड संक्षिप्त और पढ़ने में आसान रहता है।

मैं आपके दृष्टिकोण # 2 से दूर रहूंगा क्योंकि आप विभिन्न मॉड्यूलों में एक साथ रहने की जानकारी का पता लगा रहे हैं। आप बस अपने मुख्य कोड को अपने लॉग स्टेटमेंट के साथ सिंक से बाहर निकलने के लिए कह रहे हैं। लेकिन LogMyMessage (5) को देखते हुए, आप कभी नहीं जान पाएंगे।

अद्यतन (टिप्पणी पर प्रतिक्रिया): मैं आपके द्वारा उपयोग की जा रही सटीक भाषा से परिचित नहीं हूं, इसलिए इस भाग को थोड़ा अनुकूलित करना पड़ सकता है। ऐसा लगता है कि आपके सभी लॉग संदेश 3 चीजों की पहचान करते हैं: घटक, कार्रवाई, परिणाम।

मुझे लगता है कि यह बहुत ज्यादा है जो मेनमा ने सुझाया था। वास्तविक स्ट्रिंग को पारित करने के बजाय, स्थिरांक को परिभाषित करें (C / C ++ / C # में, वे एनम एन्यूमरेशन प्रकार का हिस्सा होंगे)। इसलिए घटकों के लिए उदाहरण के लिए, आपके पास हो सकता है: DbInstall, AppFiles, रजिस्ट्री, शॉर्टकट ... कुछ भी जो कोड को छोटा बनाते हैं, उन्हें पढ़ना आसान हो जाएगा।

यह भी मदद करेगा यदि आपकी भाषा चर पैरामीटर का समर्थन करती है, तो निश्चित नहीं है कि यह संभव है। इसलिए उदाहरण के लिए यदि क्रिया "FileCopy" है, तो आप उस क्रिया को दो अतिरिक्त उपयोगकर्ता पैरामीटर: फ़ाइल नाम और गंतव्य निर्देशिका को परिभाषित कर सकते हैं।

तो आपकी फाइल कॉपी लाइनें कुछ इस तरह दिखेंगी:

Bool isSuccess = CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False)
LogBook.Log( DbInstall, FileCopy, isSuccess, 'Mapannotation.txt', sOSDrive )

* ध्यान दें, लॉग लाइन को दो बार कॉपी / पेस्ट करने का कोई कारण नहीं है यदि आप एक अलग स्थानीय चर में ऑपरेशन के परिणाम को स्टोर कर सकते हैं और बस उस चर को लॉग () में पास कर सकते हैं।

आप यहाँ विषय देखते हैं, है ना? कम दोहराव वाला कोड -> अधिक पठनीय कोड।


+1, क्या आप मुझे इसके बारे में और बता सकते हैं you could pass in enumerations values ?
प्रेसलेडियस

@PresleyDias: अद्यतन पोस्ट
DXM

ठीक है, हाँ, कम दोहरावदार-> अधिक पठनीय कोड
प्रेस्लीडियस

2
+1 "छोटे कार्यों में कोड को तोड़ें।" आप इतना जोर नहीं दे सकते। यह सिर्फ इतनी समस्याओं को गायब कर देता है।
ओलिवर वीलर

10

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

जब से मैंने डेल्फी लिखी है तब से बहुत साल हो गए हैं, इसलिए यह बहुत ही अधिक # प्रेरित छद्म कोड है, लेकिन मैंने सोचा होगा कि आप कुछ ऐसा चाहते हैं

void LoggableAction(FunctionToCallPointer, string logMessage)
{
    if(!FunctionToCallPointer)
    {  
        Log(logMessage).
    }
}

तब आपका कॉलिंग कोड बन जाता है

if Not FileExists(sOSdrive+'\Mapannotation.txt') then
    LoggableAction(CopyFile(PChar(sTxtpath+'Mapannotation.txt'), "Oops, it went wrong")

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


मैं शायद खुद इस तरह से जाऊंगा, लेकिन ओपी का कोड कैसे संरचित है, इसके बारे में अधिक जानकारी के बिना, यह बताना मुश्किल है कि क्या यह कॉल करने के लिए अतिरिक्त तरीकों के एक जोड़े को परिभाषित करने से बेहतर होगा, बिना विधि संकेत के संभावित भ्रम को जोड़े बिना (निर्भर करता है) ओपी ऐसी चीजों के बारे में कितना जानता है।
रॉबिन्स

+1, LoggableAction()यह अच्छा है, मैं सीधे जाँच और लेखन के बदले दिए गए मान को लिख सकता हूँ।
प्रेसलेडियस

मैं +100, महान जवाब चाहता हूं, लेकिन मैं केवल एक ही उत्तर स्वीकार कर सकता हूं :( .. मैं अपने अगले आवेदन में इस सुझाव की कोशिश करूंगा, इस विचार के लिए धन्यवाद
प्रेसलेडियस

3

एक संभव दृष्टिकोण है कि निरंतर का उपयोग करके कोड को कम करना।

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
   LogBook.Log(2,'[POSTGRESQL INSTALLATION] :  [ACTION]:copying Mapannotation.txt to '+sOSdrive+'\ sucessful')
   else
   LogBook.Log(2,'[POSTGRESQL INSTALLATION] :  [ACTION]:copying Mapannotation.txt to '+sOSdrive+'\ Failed');

बन जाएगा:

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
   Log(2, SqlInstal, Action, CopyMapSuccess, sOSdrive)
   else
   Log(2, SqlInstal, Action, CopyMapFailure, sOSdrive)

स्क्रीन पर वर्णों की संख्या गिनते समय एक बेहतर लॉग कोड / अन्य कोड अनुपात होता है।

यह आपके प्रश्न के बिंदु 2 में आपने जो सुझाव दिया है, उसके करीब है, सिवाय इसके कि मैं अभी तक नहीं जाऊंगा: Log(9257)जाहिर है कि इससे छोटा है Log(2, SqlInstal, Action, CopyMapSuccess, sOSdrive), लेकिन पढ़ने में भी काफी मुश्किल है। 9257 क्या है? क्या यह एक सफलता है? एक्शन? क्या यह एसक्यूएल से संबंधित है? यदि आप पिछले दस वर्षों के लिए इस कोडबेस पर काम करते हैं, तो आप उन नंबरों को दिल से सीखेंगे (यदि कोई तर्क है, तो 9xxx सफलता कोड हैं, x2xx SQL से संबंधित हैं, आदि), लेकिन एक नए डेवलपर के लिए जो पता चलता है कोडबेस, शॉर्ट कोड एक बुरा सपना होगा।

आप दो दृष्टिकोणों को मिलाकर आगे बढ़ सकते हैं: एकल स्थिर का उपयोग करें। व्यक्तिगत रूप से, मैं ऐसा नहीं करूंगा। या तो आपके स्थिरांक आकार में बढ़ेंगे:

Log(Type2SuccessSqlInstallCopyMapSuccess, sOSdrive) // Can you read this? Really?

या स्थिरांक कम रहेंगे, लेकिन बहुत स्पष्ट नहीं:

Log(T2SSQ_CopyMapSuccess, sOSdrive) // What's T2? What's SSQ? Or is it S, followed by SQ?
// or
Log(CopyMapSuccess, sOSdrive) // Is it an action? Is it related to SQL?

इसकी भी दो कमियां हैं। तुमको करना होगा:

  • लॉग इन से संबंधित जानकारी को उनके संबंधित स्थिरांक के लिए एक अलग सूची रखें। एक निरंतर के साथ, यह तेजी से बढ़ेगा।

  • अपनी टीम में एकल प्रारूप लागू करने का तरीका खोजें। उदाहरण के लिए, क्या होगा अगर इसके बजाय T2SSQ, कोई लिखने का फैसला करेगा ST2SQL?


+1, स्वच्छ logकॉल के लिए, लेकिन क्या आप मुझे और अधिक समझा सकते हैं, यह समझ में नहीं आया Log(2, SqlInstal, Action, CopyMapFailure, sOSdrive), आपके कहने का मतलब है कि SqlInstalमेरा परिभाषित वैरिएबल होगा SqlInstal:=[POSTGRESQL INSTALLATION] ?
प्रेसलेडियस

@PresleyDias: SqlInstalउदाहरण के लिए, कुछ भी हो सकता है 3। फिर, लॉग संदेश के अन्य भागों के साथ संक्षिप्त होने से पहले Log()इस मूल्य को प्रभावी ढंग से अनुवादित किया जाएगा [POSTGRESQL INSTALLATION]
Arseni Mourzenko

single format in your teamएक अच्छा / महान विकल्प है
प्रेसलेडियस

3

गन्दा दिखने वाले सभी सामानों को संभालने के लिए छोटे कार्यों की एक श्रृंखला निकालने का प्रयास करें। बहुत सारे बार-बार कोड हैं जो बहुत आसानी से एक ही स्थान पर किए जा सकते हैं। उदाहरण के लिए:

procedure CopyIfFileDoesNotExist(filename: string);
var
   success: boolean;
begin
   if Not FileExists(sOSdrive+'\'+filename') then
   begin
      success := CopyFile(PChar(sTxtpath+filename), PChar(sOSdrive+filename), False);

      Log(filename, success);
   end;
end;

procedure Log(filename: string; isSuccess: boolean)
var
   state: string;
begin
   if isSuccess then
   begin
      state := 'success';
   end
   else
   begin
      state := 'failed';
   end;

   LogBook.Log(2,'[POSTGRESQL INSTALLATION] : [ACTION]:copying ' + filename + ' to '+sOSdrive+'\ ' + state);
end;

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


+1, सफ़ेद स्थान अच्छा तरीका है .. success := CopyFile()इस विचार के लिए धन्यवाद, यह मेरे मामले में कोड की कुछ अनावश्यक लाइनों को कम कर देगा
PresleyDias

@ S.Robins क्या मैंने आपका कोड सही पढ़ा है? आपकी विधि LogIfFileDoesNotExistप्रतियां फ़ाइलों को कहा जाता है?
जोहो पोर्टेला

1
@ JoãoPortela हाँ ... यह बहुत सुंदर नहीं है और एकल जिम्मेदारी सिद्धांत से नहीं जुड़ा है। यह ध्यान में रखते हुए कि यह मेरे सिर के ऊपर से गुजरने वाला पहला पास था और ओपी को अपने कोड में कुछ अव्यवस्था को कम करने के अपने उद्देश्य को पूरा करने में मदद करने के उद्देश्य से किया गया था। यह शायद पहली जगह में विधि के लिए नाम का एक खराब विकल्प है। मैं इसे सुधारने के लिए थोड़ा ट्विक करूंगा। :)
S.Robins

यह देखने के लिए अच्छा है कि आपने उस मुद्दे को संबोधित करने के लिए समय लिया, +1।
जोहो पोर्टेला

2

मैं कहूंगा कि विकल्प 2 के पीछे का विचार सबसे अच्छा है। हालांकि, मुझे लगता है कि आपने जो दिशा ली है, वह चीजों को बदतर बनाती है। पूर्णांक का कोई मतलब नहीं है। जब आप कोड देख रहे हैं, तो आप देखेंगे कि कुछ लॉग किया जा रहा है, लेकिन आप नहीं जानते कि क्या है।

इसके बजाय मैं कुछ ऐसा करूंगा:

void logHelper(String phase, String message) {
   LogBook.Log(2, "[" + phase + "] :  [Action]: " + message);
}

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

if (!FileExists(sOSdrive+'\Mapannotation.txt')) {
    if (CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False)) {
       logHelper(POSTGRESQL, 'copying Mapannotation.txt to '+ sOSdrive +'\ sucessful')
    } else {
       logHelper(POSTGRESQL, 'copying Mapannotation.txt to '+ sOSdrive +'\ Failed');
    }
}

यह कुछ ऐसा नहीं है जिसका आपने अपने प्रश्न में उल्लेख किया है, लेकिन मैंने आपके कोड के बारे में देखा। आपका इंडेंटेशन सुसंगत नहीं है। पहली बार जब आप इसका उपयोग beginकरते हैं तो यह इंडेंट नहीं होता है, लेकिन दूसरी बार यह होता है। आप एक समान काम करते हैं else। मैं कहूंगा कि यह लॉग लाइनों की तुलना में बहुत अधिक महत्वपूर्ण है। जब इंडेंटेशन सुसंगत नहीं होता है, तो कोड को स्कैन करना और प्रवाह का पालन करना कठिन हो जाता है। स्कैन करते समय बहुत सी दोहरावदार लॉग लाइनें फ़िल्टर करना आसान होता है।


1

कैसे इस लाइन के साथ कुछ के बारे में:

LogBook.NewEntry( 2,'POSTGRESQL INSTALLATION', 'copying Mapannotation.txt to '+sOSdrive);

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
    LogBook.Success()
else
    LogBook.Failed();

NewEntry () विधि पाठ की लाइन (उचित प्रविष्टियों के आसपास [और] को जोड़ने सहित) का निर्माण करेगी और उसे तब तक रोक कर रखेगी जब तक कि सफलता () या विफलता () विधियों को नहीं कहा जाता है, जो 'सफलता' के साथ लाइन को जोड़ देती है। 'असफलता', और फिर लॉग को लाइन आउटपुट। आप अन्य तरीके भी बना सकते हैं, जैसे कि जानकारी () के लिए जब लॉग एंट्री सफलता / विफलता के अलावा किसी और चीज के लिए हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.