11000 लाइनों C ++ स्रोत फ़ाइल के बारे में क्या करना है?


229

तो हमारे पास यह विशाल (11000 लाइनें बड़ी है?) हमारी परियोजना में मुख्य फ़ाइल। स्रोत फ़ाइल और हर बार जब मुझे इसे स्पर्श करना होता है तो मैं क्रिंग करता हूं।

चूंकि यह फ़ाइल इतनी केंद्रीय और बड़ी है, इसलिए यह अधिक से अधिक कोड जमा करती रहती है और मैं इसे बेहतर बनाने के लिए एक अच्छा तरीका नहीं सोच सकता।

फ़ाइल का उपयोग किया जाता है और हमारे उत्पाद के कई (> 10) रखरखाव संस्करणों में सक्रिय रूप से बदल जाता है और इसलिए इसे फिर से भरना मुश्किल है। अगर मैं इसे केवल "विभाजित" करने के लिए था, तो एक शुरुआत के लिए कहो, 3 फ़ाइलों में, फिर रखरखाव संस्करणों से वापस परिवर्तनों को मर्ज करना एक दुःस्वप्न बन जाएगा। और यह भी कि अगर आप इतने लंबे और समृद्ध इतिहास वाली फ़ाइल को विभाजित करते हैं, तो SCCइतिहास में पुराने परिवर्तनों को ट्रैक करना और जांचना बहुत कठिन हो जाता है।

फ़ाइल में मूल रूप से हमारे कार्यक्रम का "मुख्य वर्ग" (मुख्य आंतरिक कार्य प्रेषण और समन्वय) होता है, इसलिए हर बार एक विशेषता को जोड़ने पर, यह इस फ़ाइल को भी प्रभावित करता है और हर बार यह बढ़ता है। :-(

इस स्थिति में आप क्या करेंगे? SCCवर्कफ़्लो को गड़बड़ किए बिना एक अलग स्रोत फ़ाइल में नई सुविधाओं को कैसे स्थानांतरित किया जाए, इस पर कोई विचार ?

(उपकरणों पर ध्यान दें: हम C ++ का उपयोग करते हैं Visual Studio; हम उपयोग AccuRevकरते हैं, SCCलेकिन मुझे लगता SCCहै कि वास्तव में यहां कोई बात नहीं है; हम Araxis Mergeवास्तविक तुलना और फ़ाइलों के विलय का उपयोग करते हैं)


15
@ बॉलकॉक: वास्तव में विम इसे काफी तेजी से खोलेगा।
ेरेऑन

58
69305 लाइनें और मतगणना। हमारे सहयोगी की एक फाइल जो मेरे सहकर्मी ने अपने अधिकांश कोड में डंप की है, वह यहां पोस्ट करने का विरोध नहीं कर सकता है। मेरी कंपनी में किसी के पास यह रिपोर्ट करने के लिए नहीं है।
अगल कुरियन

204
मुझे नहीं मिला। "नौकरी छोड़ दें" टिप्पणी को इतने सारे उभार कैसे मिल सकते हैं? कुछ लोग एक परीलोक में रहते प्रतीत होते हैं, जहाँ सभी परियोजनाएँ स्क्रैच से लिखी जाती हैं और / या 100% फुर्तीली, टीडीडी, ... (यहाँ अपना कोई भी बज़ट डाल दिया जाता है) का उपयोग करें।
स्टीफन

39
@Stefan: जब एक समान कोड बेस के साथ सामना किया गया तो मैंने ठीक यही किया। मैंने अपने 10% पुराने कोड बेस में क्रूड के आसपास काम करने के लिए अपने समय का 95% खर्च नहीं किया , और 5% वास्तव में कोड लिख रहा था। सिस्टम के कुछ पहलुओं का परीक्षण करना वास्तव में असंभव था (और मुझे यूनिट टेस्ट का मतलब नहीं है, मेरा मतलब है कि वास्तव में यह देखने के लिए कोड चलाएं कि क्या काम किया है)। मैंने अपनी 6 महीने की परीक्षण अवधि नहीं जीती है, मैं हारने वाली लड़ाइयों और कोड लिखने से थक गया हूं जो मैं बर्दाश्त नहीं कर सकता।
बाइनरी वॉरियर

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

जवाबों:


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

  2. फ़ाइल में कुछ कोड खोजें जो मूल रूप से केवल छोटी संख्या में शाखाओं पर लागू होती हैं, और अकेले खड़ी हो सकती हैं। इससे कोई फर्क नहीं पड़ता कि शाखाओं की कम संख्या के कारण यह तेजी से बदल रहा है या नहीं। इसे अपनी कक्षाओं और फाइलों में स्थानांतरित करें। दोहराएँ।

इसलिए, हमने उस कोड से छुटकारा पा लिया है जो हर जगह समान है, और वह कोड जो कुछ शाखाओं के लिए विशिष्ट है।

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

मुझे लगता है कि यह कहना गलत है कि SCC की तरह कोई फर्क नहीं पड़ता, क्योंकि उदाहरण के लिए git की मर्जिंग क्षमताएं संभवतः उस मर्ज टूल से बेहतर हैं जिसका आप उपयोग कर रहे हैं। तो मुख्य समस्या, "विलय मुश्किल है" अलग-अलग SCCs के लिए अलग-अलग समय पर होती है। हालाँकि, आप SCCs को बदलने में सक्षम होने की संभावना नहीं रखते हैं, इसलिए मुद्दा संभवतः अप्रासंगिक है।


विलय के लिए: मैंने जीआईटी को देखा है और मैंने एसवीएन को देखा है और मैंने पेरफोर्स को देखा है और आपको बता दूं कि मैंने जो कुछ भी देखा है वह AccuRev + Araxis के लिए नहीं है जो हम करते हैं। :-) (हालांकि GIT यह कर सकता है [ stackoverflow.com/questions/1728922/… ] और AccuRev नहीं कर सकता - हर किसी को खुद के लिए फैसला करना होगा कि क्या यह विलय या इतिहास विश्लेषण का हिस्सा है।)
मार्टिन बा

पर्याप्त रूप से उचित - शायद आपके पास पहले से ही सबसे अच्छा उपकरण उपलब्ध है। Git में शाखा X पर फ़ाइल A में, शाखा B पर फ़ाइल A में, एक परिवर्तन को मर्ज करने की क्षमता है, जिसे शाखाबद्ध फ़ाइलों को विभाजित करना आसान बनाना चाहिए, लेकिन संभवत: आपके द्वारा उपयोग की जाने वाली प्रणाली में आपके पसंद के फायदे हैं। वैसे भी, मैं आपको git पर स्विच करने का प्रस्ताव नहीं दे रहा हूँ, बस यह कह रहा हूँ कि SCC को यहाँ फर्क पड़ता है, लेकिन फिर भी मैं आपसे सहमत हूँ कि यह छूट दी जा सकती है :-)
स्टीव जेसप

129

विलय इतना बड़ा दुःस्वप्न नहीं होगा क्योंकि यह तब होगा जब आपको भविष्य में 30000 LOC फ़ाइल मिलेंगी। इसलिए:

  1. उस फ़ाइल में अधिक कोड जोड़ना बंद करें।
  2. उसका विभाजन कर दो।

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


@Martin: सौभाग्य से आपने अपनी फ़ाइल यहाँ पेस्ट नहीं की है, इसलिए मुझे इसकी संरचना के बारे में कोई जानकारी नहीं है। लेकिन सामान्य विचार इसे तार्किक भागों में विभाजित करना है। ऐसे तार्किक भागों में आपके "मुख्य वर्ग" से कार्यों के समूह हो सकते हैं या आप इसे कई सहायक वर्गों में विभाजित कर सकते हैं।
किरिल वी। लयाडविंस्की

3
10 रखरखाव संस्करणों और कई सक्रिय डेवलपर्स के साथ, यह संभावना नहीं है कि फ़ाइल लंबे समय तक जमी हो सकती है।
कोबी

9
@Martin, आप GOF पैटर्न की एक जोड़ी है कि चाल करना होगा, एक भी है फसाड कि mainmodule.cpp के कार्यों के नक्शे, वैकल्पिक रूप से (मैं नीचे की सिफारिश की है) का एक सूट बनाने कमान कक्षाएं एक समारोह के लिए प्रत्येक नक्शे कि / mainmodule.app की सुविधा। (मैंने अपने जवाब पर इस पर विस्तार किया है।)
ओडोको

2
हां पूरी तरह से सहमत हैं, कुछ बिंदु पर आपको इसमें कोड जोड़ना बंद करना होगा या अंत में इसका 30k, 40k, 50k होना चाहिए, kaboom mainmodule सिर्फ seg दोषपूर्ण है। :-)
क्रिस

67

यह मुझे लगता है जैसे आप यहां कई कोड की गंध का सामना कर रहे हैं। सबसे पहले मुख्य वर्ग खुले / बंद सिद्धांत का उल्लंघन करता प्रतीत होता है । यह भी लगता है जैसे यह बहुत सारी जिम्मेदारियों को संभाल रहा है । इसके कारण मुझे लगता है कि कोड को अधिक भंगुर होने की आवश्यकता है क्योंकि यह होना चाहिए।

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

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

इसे फिर से बनाना छोटे चरणों में किया जाना चाहिए। यदि संभव हो तो किसी भी चीज़ को फिर से चालू करने से पहले वर्तमान व्यवहार को सत्यापित करने के लिए स्वचालित परीक्षण जोड़ें । फिर अलग-अलग कार्यक्षमता के छोटे क्षेत्रों को चुनें और जिम्मेदारी को सौंपने के लिए इन प्रकारों को निकालें।

किसी भी मामले में, यह एक बड़ी परियोजना की तरह लगता है, इसलिए शुभकामनाएं :)


18
इसमें बहुत बदबू आ रही है: यह बू आ रही है जैसे कि डा-हाउस में ब्लॉब विरोधी पैटर्न है ... en.wikipedia.org/wiki/God_object । उनका पसंदीदा भोजन स्पेगेटी कोड है: en.wikipedia.org/wiki/Spaghetti_code :-)
jdehaan

@ जदन: मैं इसके बारे में कूटनीतिक होने की कोशिश कर रहा था :)
ब्रायन रासमुसेन

+1 मुझसे भी, मैं इसे कवर करने के लिए परीक्षण के बिना लिखे गए जटिल कोड को छूने की भी हिम्मत नहीं करता।
डैनी थॉमस

49

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

मूल मुख्य वर्ग के ऊपर एक नया cpp वर्ग डालें। अभी के लिए, यह मूल रूप से वर्तमान मुख्य वर्ग के लिए सभी कॉल पुनर्निर्देशित करेगा, लेकिन इस नए वर्ग के एपीआई को स्पष्ट और संभव के रूप में बनाने का उद्देश्य है।

एक बार यह हो जाने के बाद, आपको नई कक्षाओं में नई कार्यक्षमता जोड़ने की संभावना मिलती है।

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

मुझे पता है कि यह सही नहीं है, हालांकि मुझे आशा है कि यह मदद कर सकता है, और प्रक्रिया को आपकी आवश्यकताओं के अनुकूल होना चाहिए!

अतिरिक्त जानकारी

ध्यान दें कि Git एक SCC है जो एक फ़ाइल से दूसरी फ़ाइल के कोड का अनुसरण कर सकता है। मैंने इसके बारे में अच्छी बातें सुनी हैं, इसलिए जब आप उत्तरोत्तर अपने काम को आगे बढ़ा रहे हैं तो यह मदद कर सकता है।

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


GIT यह कैसे करता है / आप इसे GIT के साथ कैसे करते हैं, इस संदर्भ में आपका स्वागत है।
मार्टिन बा

@ मर्टिन गिट यह स्वचालित रूप से करता है।
मैथ्यू

4
@Martin: Git इसे स्वचालित रूप से करता है - क्योंकि यह फ़ाइलों को ट्रैक नहीं करता है, यह सामग्री को ट्रैक करता है। यह वास्तव में सिर्फ "एक फ़ाइल का इतिहास प्राप्त करें" के लिए अधिक कठिन है।
अराफंगियन

1
@ मर्टिन youtube.com/watch?v=4XpnKHJAok8 एक ऐसी बात है, जहां टॉर्वाल्ड गित की बात करते हैं। वह बाद में बात में इसका उल्लेख करता है।
मैथ्यू

6
@ मॉर्टिन, इस सवाल को देखें: stackoverflow.com/questions/1728922/…
बेंजोल

30

कन्फ्यूशियस कहते हैं: "छेद से बाहर निकलने का पहला कदम खुदाई छेद को रोकना है।"


25

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

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

इससे पहले कि आप फ़ाइल को भागों में तोड़ने का प्रयास करें, आपको दस शाखाओं को एक-दूसरे के साथ वापस लाने की आवश्यकता है ताकि आप एक ही बार में सभी कोड को देख और आकार दे सकें। आप एक बार में एक ही कोड कर सकते हैं, एक ही मुख्य कोड फ़ाइल के खिलाफ दोनों शाखाओं का परीक्षण कर सकते हैं। कस्टम व्यवहार को लागू करने के लिए, आप #ifdef और दोस्तों का उपयोग कर सकते हैं, लेकिन यह उतना ही बेहतर है जितना कि साधारण का उपयोग करना संभव है / यदि परिभाषित स्थिरांक के खिलाफ / तो। इस तरह, आपका कंपाइलर सभी प्रकारों को सत्यापित करेगा और संभवत: वैसे भी "डेड" ऑब्जेक्ट कोड को खत्म कर देगा। (आप मृत कोड के बारे में चेतावनी को बंद करना चाह सकते हैं, हालांकि।)

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

#Ifdefs उन वर्गों के लिए मुख्य रूप से बेहतर हैं जहाँ प्रभावित कोड केवल अन्य प्रति-शाखा अनुकूलन के संदर्भ में समझ में आता है। कोई यह तर्क दे सकता है कि ये एक ही शाखा-विलय योजना के लिए एक अवसर प्रस्तुत करते हैं, लेकिन हॉग-वाइल्ड नहीं जाते हैं। एक समय में एक विशाल परियोजना, कृपया।

थोड़े समय में, फ़ाइल बढ़ती दिखाई देगी। यह ठीक है। आप जो कर रहे हैं, वह चीजों को एक साथ ला रहा है जो एक साथ होना चाहिए। बाद में, आपको ऐसे क्षेत्र दिखाई देने लगेंगे जो संस्करण की परवाह किए बिना स्पष्ट रूप से समान हैं; इन्हें अकेले छोड़ दिया जा सकता है या वसीयत में रिफलेक्ट किया जा सकता है। अन्य क्षेत्र संस्करण के आधार पर स्पष्ट रूप से भिन्न होंगे। इस मामले में आपके पास कई विकल्प हैं। एक विधि प्रति-संस्करण रणनीति वस्तुओं के अंतर को सौंपना है। एक अन्य एक सामान्य अमूर्त वर्ग से ग्राहक संस्करणों को प्राप्त करना है। लेकिन जब तक आपके पास विभिन्न शाखाओं में विकास के दस "सुझाव" नहीं होते हैं, इनमें से कोई भी परिवर्तन संभव नहीं है।


2
मैं मानता हूं कि लक्ष्य सॉफ्टवेयर का एक संस्करण होना चाहिए, लेकिन क्या यह कॉन्फिग फाइल (रनटाइम) का उपयोग करने के लिए बेहतर नहीं होगा और समय की हिरासत को संकलित नहीं करना चाहिए
Esben Skov Pedersen

या यहां तक ​​कि प्रत्येक ग्राहक के निर्माण के लिए "कॉन्फ़िगर कक्षाएं"।
टीसी

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

22

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

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

मुझे लगता है कि आपके पास केवल ये विकल्प हैं:

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

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

  3. अपने सहकर्मियों को कुछ अच्छे केक के साथ समझाने की कोशिश करें कि वर्कफ़्लो खत्म हो गया है और आपको गंभीर व्यवसाय करने के लिए आवेदन के कुछ हिस्सों को फिर से लिखना होगा।


19

वास्तव में इस समस्या को "वर्किंग इफेक्टिवली विथ लेगेसी कोड" ( http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0133077052 ) पुस्तक के अध्यायों में से एक में संभाला गया है ।


Informit.com/store/product.aspx?isbn=0131177052 इस पुस्तक की TOC (और 2 नमूना अध्यायों) को देखना संभव बनाता है। अध्याय 20 कब तक है? (सिर्फ यह महसूस करने के लिए कि यह कितना उपयोगी हो सकता है।)
मार्टिन बा

17
अध्याय २०,००० की पंक्तियाँ १०,००० लंबी हैं, लेकिन लेखक का काम यह है कि इसे सुपाच्य विखंडू में कैसे विभाजित किया जाए ...
टोनी डेलरो

1
इसके बारे में 23 पृष्ठों, लेकिन 14 छवियों के साथ। मुझे लगता है कि आपको इसे प्राप्त करना चाहिए, आप एक बहुत अधिक आत्मविश्वास महसूस करेंगे कि यह तय करने की कोशिश कर रहा है कि क्या करना है।
एमिल व्रजदग्ग्स

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

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

14

मुझे लगता है कि आप mainmodule.cpp के एपीआई बिंदुओं पर मैप करने वाले कमांड कक्षाओं का एक सेट बनाकर सर्वश्रेष्ठ होंगे।

एक बार जब वे जगह पर होते हैं, तो आपको कमांड कोड के माध्यम से इन एपीआई बिंदुओं तक पहुंचने के लिए मौजूदा कोड बेस को फिर से भरना होगा, एक बार ऐसा करने के बाद, आप प्रत्येक कमांड के कार्यान्वयन को एक नए वर्ग ढांचे में बदलने के लिए स्वतंत्र हैं।

बेशक, 11 केएलओसी के एक एकल वर्ग के साथ कोड संभवतः बहुत अधिक युग्मित और भंगुर है, लेकिन व्यक्तिगत कमांड कक्षाएं बनाने से किसी भी अन्य प्रॉक्सी / मुखौटा रणनीति की तुलना में बहुत अधिक मदद मिलेगी।

मैं इस कार्य से ईर्ष्या नहीं करता, लेकिन जैसे-जैसे समय बीतता जाएगा, यह समस्या और भी बदतर होती जाएगी, अगर इससे निपटा नहीं जाए।

अपडेट करें

मेरा सुझाव है कि कमांड पैटर्न एक मुखौटा के लिए बेहतर है।

एक (अपेक्षाकृत) मोनोलिथिक फेकडे के ऊपर कई अलग-अलग कमांड कक्षाओं को बनाए रखना / व्यवस्थित करना बेहतर है। 11 KLOC फ़ाइल पर एक एकल मुखौटा को मैप करना संभवतः कुछ अलग समूहों में ही टूट जाएगा।

क्यों परेशान इन मुखौटा समूहों का पता लगाने की कोशिश कर रहा? कमांड पैटर्न के साथ आप इन छोटे वर्गों को व्यवस्थित रूप से समूह और व्यवस्थित करने में सक्षम होंगे, इसलिए आपके पास बहुत अधिक लचीलापन है।

बेशक, दोनों विकल्प एकल 11 KLOC और बढ़ते, फ़ाइल से बेहतर हैं।


+1 के समाधान का एक विकल्प जो मैंने प्रस्तावित किया था, एक ही विचार के साथ: बड़ी समस्या को छोटे में अलग करने के लिए एपीआई को बदलें।
बेनोइट

13

एक महत्वपूर्ण सलाह: रिफैक्टिंग और बगफिक्स को न मिलाएं। आप जो चाहते हैं वह आपके प्रोग्राम का एक संस्करण है जो पिछले संस्करण के समान है, सिवाय इसके कि स्रोत कोड अलग है।

एक तरीका यह हो सकता है कि कम से कम बड़े फंक्शन / भाग को स्वयं की फ़ाइल में विभाजित करना शुरू करें और फिर या तो हेडर के साथ शामिल करें (इस प्रकार main.cpp को #includes की सूची में बदल दें, जो अपने आप में एक कोड गंध लगता है * मैं नहीं हूं) C ++ गुरु हालांकि), लेकिन कम से कम अब यह फाइलों में विभाजित है)।

फिर आप सभी रखरखाव रिलीज़ को "नए" main.cpp या जो भी आपकी संरचना है, पर स्विच करने का प्रयास कर सकते हैं। फिर से: कोई अन्य परिवर्तन या बगफिक्स नहीं है क्योंकि उन लोगों को ट्रैक करना नरक के रूप में भ्रमित है।

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

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


1
बाहर फैक्टरिंग के लिए +1 और # वापस बाहर कर दें। यदि आपने यह सभी 10 शाखाओं के लिए किया है (तो वहां काम करने की थोड़ी सी भी, लेकिन प्रबंधनीय) आपको अभी भी दूसरी समस्या होगी, आपकी सभी शाखाओं में परिवर्तन पोस्ट करने की, लेकिन वह समस्या नहीं होगी ' टी का विस्तार (आवश्यक) है। क्या यह बदसूरत है? हाँ, यह अभी भी है, लेकिन यह समस्या के लिए थोड़ी समझदारी ला सकता है। कई वर्षों तक रखरखाव और वास्तव में बड़े उत्पाद के लिए सर्विसिंग पर खर्च करने के बाद, मुझे पता है कि रखरखाव में बहुत दर्द होता है। बहुत कम से कम इससे सीखते हैं, और दूसरों के लिए एक सतर्क कहानी के रूप में काम करते हैं।
जे

10

Rofl, यह मुझे मेरी पुरानी नौकरी की याद दिलाता है। ऐसा लगता है कि, मेरे शामिल होने से पहले, सब कुछ एक बड़ी फ़ाइल (C ++) के अंदर था। फिर उन्होंने इसे तीन (अभी भी बड़ी फ़ाइलों) में शामिल करके (पूरी तरह से यादृच्छिक बिंदुओं का उपयोग करके) विभाजित किया है। इस सॉफ़्टवेयर की गुणवत्ता, जैसा कि आप उम्मीद कर सकते हैं, भयानक था। यह परियोजना लगभग 40k LOC पर आधारित थी। (लगभग कोई टिप्पणी नहीं है लेकिन बहुत सारे डुप्लिकेट कोड के)

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

मेरा कहना है कि इसमें लगभग आधा साल लग गया और उस दौरान बगफिक्स के पास पुराने कोड बेस का कोई विकास नहीं हुआ था।


संपादित करें:

आकार लगभग 40k LOC पर रहा, लेकिन नए अनुप्रयोग में 8 साल पुराने सॉफ़्टवेयर की तुलना में इसके प्रारंभिक संस्करण में कई अधिक विशेषताएं और संभवतः कम कीड़े थे। पुनर्लेखन का एक कारण यह भी था कि हमें नई विशेषताओं की आवश्यकता थी और पुराने कोड के अंदर उन्हें पेश करना लगभग असंभव था।

सॉफ्टवेयर एक एम्बेडेड सिस्टम, एक लेबल प्रिंटर के लिए था।

एक और बिंदु जो मुझे जोड़ना चाहिए वह यह है कि सिद्धांत में परियोजना सी ++ थी। लेकिन यह बिल्कुल भी OO नहीं था, यह C. हो सकता था। नया संस्करण ऑब्जेक्ट ओरिएंटेड था।


9
हर बार मैं "खरोंच से" विषय पर सुनता हूं कि मैं बिल्ली का बच्चा मारता हूं!
कुगेल

मैं बहुत ही समान लगने वाली स्थिति में रहा हूं, हालांकि मुख्य कार्यक्रम लूप को मुझे केवल ~ 9000 एलओसी के साथ पकड़ना था। और वह काफी बुरा था।
एंडीयूके

8

उत्पादन कोड के अधिकांश भाग को फिर से लिखना एपीआई के लिए ठीक है एक शुरुआत के रूप में एक बुरा विचार है। दो चीजें होने की जरूरत है।

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

दो, आपको इस उत्पादन संस्करण को लेने और एक शाखा बनाने की ज़रूरत है जो बड़ी फ़ाइल को विभाजित करने के लिए प्रीप्रोसेसिंग निर्देशों का उपयोग करके बिल्ड का प्रबंधन करती है। JUST preprocessor directives (#ifdefs, #includes, #endifs) का उपयोग करके संकलन को विभाजित करना API को रीकोड करने से ज्यादा आसान है। यह निश्चित रूप से आपके SLAs और चल रहे समर्थन के लिए आसान है।

यहां आप केवल उन कार्यों को काट सकते हैं जो वर्ग के भीतर एक विशेष उप-प्रणाली से संबंधित हैं और उन्हें एक फाइल में कहते हैं mainloop_foostuff.cpp और सही स्थान पर mainloop.cpp में शामिल करें।

या

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

इस दृष्टिकोण में वे घटक शामिल होंगे जो आपके द्वारा संकलित किए जा रहे संस्करण के आधार पर उपयोग किए जाते हैं।

मूल संरचना यह है कि आपके mainclass.cpp में निम्नलिखित जैसे बयानों के ब्लॉक के बाद MainClassCompords.cpp नामक एक नई फ़ाइल शामिल होगी:

#if VARIANT == 1
#  define Uses_Component_1
#  define Uses_Component_2
#elif VARIANT == 2
#  define Uses_Component_1
#  define Uses_Component_3
#  define Uses_Component_6
...

#endif

#include "MainClassComponents.cpp"

मेनक्लासकॉमपर्सिट.कैप फाइल की प्राथमिक संरचना इस तरह उप घटकों के भीतर निर्भरता को बाहर करने के लिए होगी:

#ifndef _MainClassComponents_cpp
#define _MainClassComponents_cpp

/* dependencies declarations */

#if defined(Activate_Component_1) 
#define _REQUIRES_COMPONENT_1
#define _REQUIRES_COMPONENT_3 /* you also need component 3 for component 1 */
#endif

#if defined(Activate_Component_2)
#define _REQUIRES_COMPONENT_2
#define _REQUIRES_COMPONENT_15 /* you also need component 15 for this component  */
#endif

/* later on in the header */

#ifdef _REQUIRES_COMPONENT_1
#include "component_1.cpp"
#endif

#ifdef _REQUIRES_COMPONENT_2
#include "component_2.cpp"
#endif

#ifdef _REQUIRES_COMPONENT_3
#include "component_3.cpp"
#endif


#endif /* _MainClassComponents_h  */

और अब प्रत्येक घटक के लिए आप एक कंपोनेंट_xx.cpp फ़ाइल बनाते हैं।

बेशक मैं संख्याओं का उपयोग कर रहा हूं, लेकिन आपको अपने कोड के आधार पर कुछ और तार्किक उपयोग करना चाहिए।

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

एक बार जब आपका उत्पादन व्यवस्थित हो जाता है तो आप वास्तव में रीडिजाइन पर काम कर सकते हैं।


यह अनुभव के कार्यों-लेकिन-शुरू-दर्दनाक परिणामों की तरह दिखता है।
JBRWilkinson

वास्तव में, यह एक ऐसी तकनीक है जिसका उपयोग बोरलैंड C ++ कंपाइलर में हेडल फाइलों के प्रबंधन के लिए पास्कल स्टाइल यूसेज का अनुकरण करने के लिए किया गया था। खासकर जब उन्होंने अपने पाठ-आधारित विंडिंग सिस्टम का प्रारंभिक बंदरगाह किया।
एल्फ किंग

8

वैसे मुझे आपका दर्द समझ में आता है :) मैं इस तरह की कुछ परियोजनाओं में रहा हूँ और यह बहुत अच्छा नहीं है। इसका कोई आसान जवाब नहीं है।

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

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


4

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


हमेशा की तरह, मैं डाउनवोट के लिए एक स्पष्टीकरण प्राप्त करना चाहूंगा।
ब्योर्न पोलेक्स

4

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


4

यह बड़ी समस्या का जवाब नहीं है, लेकिन इसका एक विशिष्ट टुकड़ा करने के लिए एक सैद्धांतिक समाधान है:

  • यह पता लगाएं कि आप उप-फाइल में बड़ी फाइल को कहाँ विभाजित करना चाहते हैं। उन बिंदुओं में से प्रत्येक पर कुछ विशेष प्रारूप में टिप्पणियां डालें।

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

  • स्क्रिप्ट चलाएँ। मूल फ़ाइल को हटाएं।

  • जब आपको किसी शाखा से विलय करने की आवश्यकता होती है, तो पहले टुकड़ों को एक साथ वापस करके बड़ी फ़ाइल को फिर से बनाएँ, मर्ज करें, और फिर इसे फिर से विभाजित करें।

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


4

बहुत अधिक खतरे के बिना इसे विभाजित करने का एक तरीका सभी लाइन परिवर्तनों पर एक ऐतिहासिक नज़र डालना होगा। क्या कुछ ऐसे कार्य हैं जो दूसरों की तुलना में अधिक स्थिर हैं? परिवर्तन के हॉट स्पॉट यदि आप करेंगे

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


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

3

वाह, बहुत अच्छा लग रहा है। मुझे लगता है कि अपने बॉस को समझाते हुए, कि जानवर को फिर से तैयार करने के लिए आपको बहुत समय चाहिए। यदि वह सहमत नहीं है, तो छोड़ना एक विकल्प है।

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


3

मेरी सहानुभूति - मेरी पिछली नौकरी में मैंने एक ऐसी फाइल के साथ एक ऐसी स्थिति का सामना किया था जो आपके साथ सौदा करने से कई गुना बड़ा था। समाधान था:

  1. विचाराधीन प्रोग्राम में फ़ंक्शन का संपूर्ण परीक्षण करने के लिए कोड लिखें। लगता है जैसे आप पहले से ही इस हाथ में नहीं होगा ...
  2. कुछ कोड की पहचान करें जिन्हें एक सहायक / उपयोगिताओं वर्ग में सार किया जा सकता है। बड़ा होने की जरूरत नहीं है, बस कुछ ऐसा है जो वास्तव में आपके 'मुख्य' वर्ग का हिस्सा नहीं है।
  3. 2. एक अलग वर्ग में 2. कोड की पहचान की।
  4. कुछ भी न टूटे, यह सुनिश्चित करने के लिए अपने परीक्षणों को फिर से चलाएँ।
  5. जब आपके पास समय हो, गोटो 2. और कोड को प्रबंधनीय बनाने के लिए आवश्यकतानुसार दोहराएं।

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

मैं भी जोड़ सकता है:

0: विरासत कोड के साथ काम करने पर माइकल फेदर्स की किताब खरीदें

दुर्भाग्य से इस प्रकार का काम बहुत आम है, लेकिन मेरा अनुभव यह है कि काम करने में सक्षम होने में बहुत महत्व है, लेकिन काम करते समय डरावने कोड को कम से कम भयानक रूप से कम डरावनी है।


2

संपूर्ण एप्लिकेशन को अधिक समझदार तरीके से फिर से लिखने के तरीकों पर विचार करें। हो सकता है कि इसके एक छोटे से खंड को एक प्रोटोटाइप के रूप में फिर से देखें कि क्या आपका विचार संभव है।

यदि आपने एक व्यावहारिक समाधान की पहचान की है, तो उसके अनुसार एप्लिकेशन को रिफलेक्टर करें।

यदि अधिक तर्कसंगत वास्तुकला का उत्पादन करने के सभी प्रयास विफल हो जाते हैं, तो कम से कम आप जानते हैं कि समाधान संभवतः कार्यक्रम की कार्यक्षमता को फिर से परिभाषित करने में है।


+1 - इसे अपने समय में फिर से लिखें हालांकि कोई व्यक्ति अपनी डमी को थूक सकता है।
जॉन ब्लैक

2

मेरे 0.05 यूरोकेंट्स:

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

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

रीडिज़ाइन को एक अलग प्रोजेक्ट होने की आवश्यकता होगी, इसे एक चलती लक्ष्य पर करने की कोशिश करने से काम नहीं चलेगा।

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

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

इस तरह से मैं कम से कम समस्या से निपटना शुरू कर दूंगा।


2

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



2

कुछ ऐसा करने के लिए मुझे उपयोगी लगता है (और मैं इसे अब कर रहा हूं, हालांकि आप जिस पैमाने का सामना नहीं कर रहे हैं), कक्षाओं के रूप में तरीकों को निकालने के लिए है (विधि ऑब्जेक्ट रिफैक्टिंग)। आपके अलग-अलग संस्करणों में अलग-अलग विधियाँ अलग-अलग वर्ग बन जाएँगी जिन्हें अलग-अलग व्यवहार के लिए एक सामान्य आधार में इंजेक्ट किया जा सकता है।


2

मुझे यह वाक्य आपकी पोस्ट का सबसे दिलचस्प हिस्सा लगा:

> फ़ाइल का उपयोग किया जाता है और सक्रिय रूप से हमारे उत्पाद के कई (> 10) रखरखाव संस्करणों में बदल जाता है और इसलिए इसे फिर से भरना मुश्किल है

सबसे पहले, मैं आपको सलाह दूंगा कि आप इन 10 + रखरखाव संस्करणों को विकसित करने के लिए एक स्रोत नियंत्रण प्रणाली का उपयोग करें जो ब्रांचिंग का समर्थन करता है।

दूसरा, मैं दस शाखाएँ (आपके प्रत्येक रखरखाव संस्करण के लिए एक) बनाऊंगा।

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

अब आप जिस ब्रांच में काम करते हैं - उसे रिफलेक्टर करें क्योंकि आप फिट हैं, इस ज्ञान में सुरक्षित हैं कि आप अपने उत्पाद की अन्य नौ शाखाओं को परेशान नहीं करेंगे।

मैं थोड़ा चिंतित होगा कि आपके मुख्य () फ़ंक्शन में आपके बहुत सारे हैं।

मेरे द्वारा लिखी जाने वाली किसी भी परियोजना में, मैं मुख्य () केवल मुख्य वस्तुओं के आरंभीकरण का उपयोग करूंगा - जैसे कि अनुकार या अनुप्रयोग ऑब्जेक्ट - ये कक्षाएं वह जगह हैं जहां वास्तविक काम करना चाहिए।

मैं मुख्य रूप से पूरे कार्यक्रम में विश्व स्तर पर उपयोग के लिए एक एप्लिकेशन लॉगिंग ऑब्जेक्ट को इनिशियलाइज़ करूँगा।

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

आप कहते हैं कि

> फ़ाइल में मूल रूप से हमारे कार्यक्रम का "मुख्य वर्ग" (मुख्य आंतरिक कार्य प्रेषण और समन्वय) शामिल है

ऐसा लगता है कि इन दो कार्यों को दो अलग-अलग वस्तुओं में विभाजित किया जा सकता है - एक समन्वयक और एक कार्य प्रेषण।

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

यदि आप निर्णय लेने में सक्षम नहीं हैं, तो इसके लिए अपने प्रबंधक के साथ दाँत और नाखून लड़ें - आपके आवेदन को वापस लेने की आवश्यकता है - और इसके ध्वनियों से बुरी तरह से! एक उत्तर के लिए नहीं ले लो!


जैसा कि मैं समझता हूं, समस्या यह है: यदि आप बुलेट और रिफैक्टर को काटते हैं, तो आप अब संस्करणों के बीच पैच नहीं ले सकते। SCC पूरी तरह से स्थापित किया जा सकता है।
पीटरचेन

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

2

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

  • संघनन के दौरान कुछ पूर्व लाइनें हटाएं (जैसे गार्ड शामिल करें)
  • यदि आवश्यक हो तो अलग आउटपुट से अन्य सामान निकालें

आप इसे तब भी बना सकते हैं जब भी कोई चेकइन होता है, कॉन्टेक्टेशन चलता है और आपको सिंगल-फाइल वर्जन के खिलाफ अलग से कुछ तैयार करना होता है।


2
  1. कभी भी इस फ़ाइल और कोड को दोबारा न छूएं!
  2. इलाज कुछ ऐसा है जो आप के साथ फंस गए हैं। वहाँ एन्कोडेड कार्यक्षमता के लिए एडेप्टर लिखना शुरू करें।
  3. अलग-अलग इकाइयों में नया कोड लिखें और केवल एडेप्टर से बात करें जो राक्षस की कार्यक्षमता को बढ़ाता है।
  4. ... यदि उपरोक्त में से केवल एक ही संभव नहीं है, तो नौकरी छोड़ दें और आपको एक नया प्राप्त करें।

2
+/- 0 - गंभीरता से, आप कहां रहते हैं कि आप इस तरह के तकनीकी विवरण के आधार पर नौकरी छोड़ने की सलाह देंगे?
मार्टिन बा

1

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

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

    // declaration
    std::map<ID, ICommand*> dispatchTable;
    ...

    // populating using some loader
    dispatchTable[id] = concreteCommand;

    ...
    // using
    dispatchTable[id]->Execute();

2
नहीं, वास्तव में कोई बड़ा स्विच नहीं है। वाक्य सिर्फ निकटतम है मैं इस गंदगी का वर्णन करने के लिए आ सकता हूं :)
मार्टिन बा

1

मुझे लगता है कि फ़ाइल को विभाजित करते समय स्रोत के इतिहास को ट्रैक करने का सबसे आसान तरीका कुछ इस तरह होगा:

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

"जो भी हिस्ट्री-प्रोटेक्टिंग कॉपी आपके एससीएम सिस्टम को उपलब्ध कराता है उसका उपयोग करके" ... बुरी बात यह कोई प्रदान नहीं करती है
मार्टिन बा

बहुत बुरा। यह अकेला ही एक और आधुनिक वस्तु को बदलने के अच्छे कारण की तरह लगता है। :-)
क्रिस्टोफर क्रुत्ज़िग

1

मुझे लगता है कि इस स्थिति में मैं क्या करूंगा बुलेट और बिट:

  1. पता लगाएँ कि मैं फ़ाइल को कैसे विभाजित करना चाहता था (वर्तमान विकास संस्करण के आधार पर)
  2. फ़ाइल पर एक प्रशासनिक लॉक लगाएं ("शुक्रवार शाम 5 बजे के बाद कोई भी mainmodule.cpp को न छुए !!!"
  3. अपने लंबे सप्ताहांत को उस परिवर्तन को लागू करते हुए> 10 रखरखाव संस्करणों (सबसे पुराने से नवीनतम तक) को लागू करें, वर्तमान संस्करण तक और सहित।
  4. सॉफ़्टवेयर के सभी समर्थित संस्करणों से mainmodule.cpp को हटाएं। यह एक नया युग है - अधिक मेनमॉडल नहीं है। सीपीपी।
  5. प्रबंधन को आश्वस्त करें कि आपको सॉफ़्टवेयर के एक से अधिक रखरखाव संस्करण का समर्थन नहीं करना चाहिए (कम से कम एक बड़ा $$$ समर्थन अनुबंध के बिना)। यदि आपके प्रत्येक ग्राहक का अपना विशिष्ट संस्करण है .... yeeeeeshhhh मैं 10 + कांटे को बनाए रखने की कोशिश करने के बजाय संकलक निर्देश जोड़ रहा हूं।

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

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