मैं हेडर नर्क को कैसे रोक सकता हूं?


44

हम स्क्रैच से एक नया प्रोजेक्ट शुरू कर रहे हैं। आठ डेवलपर्स के बारे में, एक दर्जन या तो सबसिस्टम, प्रत्येक चार या पांच स्रोत फ़ाइलों के साथ।

हम "हेडर नरक", एकेए "स्पेगेटी हेडर" को रोकने के लिए क्या कर सकते हैं?

  • स्रोत फ़ाइल प्रति एक हेडर?
  • प्लस प्रति सबसिस्टम?
  • फंक्शन प्रोटोटाइप से अलग टाइपडेफ़्स, स्टक्ट्स और एनमेस?
  • सबसिस्टम बाहरी सामान से आंतरिक को अलग करें?
  • जोर देकर कहते हैं कि हर एक फाइल, चाहे हेडर हो या सोर्स, स्टैंडअलोन कंपाइल करने योग्य होना चाहिए?

मैं "सर्वश्रेष्ठ" तरीके के लिए नहीं पूछ रहा हूं, बस इशारा करता हूं कि क्या देखना है और क्या दुःख का कारण बन सकता है, ताकि हम इससे बचने की कोशिश कर सकें।

यह एक C ++ प्रोजेक्ट होगा, लेकिन C जानकारी भविष्य के पाठकों की मदद करेगी।


16
लार्ज-स्केल C ++ सॉफ़्टवेयर डिज़ाइन की एक प्रति प्राप्त करें , यह सिर्फ हेडर के साथ समस्याओं से बचने के लिए नहीं सिखाएगा, लेकिन C ++ प्रोजेक्ट में स्रोत और ऑब्जेक्ट्स फ़ाइलों के बीच भौतिक निर्भरता से संबंधित कई और समस्याएं।
डॉक ब्राउन

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

1
मुझे यकीन है कि मैंने आपके साथ पहले भी काम किया है। अक्सर :-(
मगग

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

2
बूस्ट वास्तव में एक सर्व-समावेशी दृष्टिकोण रखता है। प्रत्येक इंडीविजुअल फीचर की अपनी हेडर फ़ाइल होती है, लेकिन प्रत्येक बड़े मॉड्यूल में एक हेडर भी होता है जिसमें सब कुछ शामिल होता है। यह हर बार कुछ सौ फाइलों को #include करने के लिए हेडर-नरक को कम करने के लिए वास्तव में शक्तिशाली हो जाता है।
Cort Ammon

जवाबों:


39

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

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

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


जहां यह मुश्किल हो जाता है क्रॉस-सब-सिस्टम फ़ंक्शन कॉल, अन्य सबसिस्टम में घोषित प्रकारों के मापदंडों के साथ।
मगग

6
मुश्किल या नहीं, "#include <subsystem1.h>" संकलन करना चाहिए। आप कैसे प्राप्त करते हैं, आपके ऊपर। @FrankPuffer: क्यों?
gnasher729

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

8
हेडर को सुनिश्चित करने के लिए एक अच्छी तकनीक स्वतंत्र है एक नियम है कि स्रोत फ़ाइल में हमेशा अपना हेडर पहले शामिल होता है । यह उन मामलों को पकड़ लेगा, जहां आपको निर्भरता को स्थानांतरित करने की आवश्यकता है, जिसमें शीर्षक फ़ाइल में कार्यान्वयन फ़ाइल शामिल है।
doug65536 11

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

18

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

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

अपने विशिष्ट प्रश्नों के उत्तर देने के लिए:

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

12

अन्य सिफारिशों के अलावा, निर्भरता कम करने की रेखाओं के साथ (मुख्य रूप से C ++ पर लागू):

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

5
# 3 पर, टूल में शामिल हैं-क्या-आप-उपयोग में मदद कर सकते हैं, अनुमान और जांच मैनुअल पुनर्मूल्यांकन दृष्टिकोण से बच सकते हैं।
आरएम

1
क्या आप बता सकते हैं कि इस संदर्भ में सिंगलटन का क्या लाभ है? मैं वास्तव में यह नहीं मिलता है।
फ्रैंक पफर

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

1
# 2 (आगे की घोषणाएँ) संकलन समय और निर्भरता जाँच में बहुत बड़ा अंतर ला सकती है। इस उत्तर के रूप में ( stackoverflow.com/a/9999752/509928 ) से पता चलता है, यह C ++ और C
डेव कॉम्पटन

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

6

स्रोत फ़ाइल प्रति एक हेडर, जो परिभाषित करता है कि उसका स्रोत फ़ाइल क्या लागू करता है / निर्यात करता है।

जितनी आवश्यक हो उतने हेडर फाइल, प्रत्येक सोर्स फाइल (अपने हेडर से शुरू) में शामिल है।

अन्य हेडर फ़ाइलों के भीतर हेडर फ़ाइलों को शामिल करने से (सर्कुलर निर्भरता से बचने के लिए) शामिल करने से बचें। विवरण के लिए "C ++ का उपयोग करके क्या दो वर्ग एक दूसरे को देख सकते हैं?"

इस विषय पर एक पूरी किताब है, लैकोस द्वारा लार्ज-स्केल C ++ सॉफ्टवेयर डिज़ाइन । यह सॉफ्टवेयर की "परतें" होने का वर्णन करता है: उच्च-स्तरीय परतें निम्न-स्तर की परतों का उपयोग करती हैं, इसके विपरीत नहीं, जो फिर से परिपत्र निर्भरता से बचती हैं।


4

मैं दावा करूंगा कि आपका प्रश्न मौलिक रूप से अचूक है, क्योंकि हेडर नरक के दो प्रकार हैं:

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

बात यह है कि, यदि आप पूर्व में समाप्त होने से बचने की कोशिश करते हैं, तो कुछ हद तक, बाद वाले, और इसके विपरीत।

एक तीसरे प्रकार का नरक भी है, जो परिपत्र निर्भरता है। यदि आप सावधान नहीं हैं तो ये पॉप अप हो सकते हैं ... इनसे बचना अति-जटिल नहीं है, लेकिन आपको यह सोचने की ज़रूरत है कि इसे कैसे करना है। जॉन लेकोस को CppCon 2016 (या सिर्फ स्लाइड्स ) में Levelization पर बात करें


1
आप हमेशा परिपत्र निर्भरता से बच नहीं सकते। एक उदाहरण एक मॉडल है जिसमें इकाइयां एक दूसरे को संदर्भित करती हैं। कम से कम आप सबसिस्टम में गोलाकारता को सीमित करने की कोशिश कर सकते हैं, इसका मतलब है, यदि आप सबसिस्टम के हेडर को शामिल करते हैं, तो आप परिपत्रता को समाप्त कर देते हैं।
nalply

2
@ अर्ली: मेरा मतलब हेडर की सर्कुलर निर्भरता से बचना था, कोड का नहीं ... अगर आप सर्कुलर हेडर की निर्भरता से नहीं बचते हैं तो शायद आप निर्माण नहीं कर पाएंगे। लेकिन हाँ, बिंदु लिया गया, +1।
einpoklum - मोनिका

1

decoupling

यह अंततः हमारे संकलक और लिंकर्स की विशेषताओं की बारीकियों से रहित सबसे मौलिक डिजाइन स्तर पर दिन के अंत में मुझे डिकॉउलिंग करने के बारे में है। मेरा मतलब है कि आप ऐसा कर सकते हैं जैसे प्रत्येक हेडर को केवल एक वर्ग परिभाषित करें, पिंपल्स का उपयोग करें, आगे की घोषणाओं को उन प्रकारों के लिए करें जिन्हें केवल घोषित किए जाने की आवश्यकता है, परिभाषित नहीं, शायद हेडर का भी उपयोग करें जिसमें केवल आगे की घोषणाएं शामिल हैं (पूर्व:) <iosfwd>, एक हेडर प्रति स्रोत फ़ाइल घोषित / परिभाषित, आदि के प्रकार के आधार पर सिस्टम को लगातार व्यवस्थित करें।

"संकलन-समय निर्भरता" को कम करने की तकनीक

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

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

बाहरी प्रकारों के लिए आगे की घोषणा

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

यदि आप एक Foo.hppहेडर की कल्पना करते हैं जिसमें कुछ ऐसा है:

#include "Bar.hpp"

और यह केवल Barहेडर में एक तरह से उपयोग करता है जिसके लिए इसे घोषणा की आवश्यकता होती है, परिभाषा की नहीं। तब यह हेडर में दिखाई देने वाली class Bar;परिभाषा को बनाने से बचने के लिए घोषित करने के लिए एक नो-ब्रेनर की तरह लग सकता है Bar। व्यवहार में छोड़कर अक्सर आप या तो अधिकांश संकलन इकाइयाँ प्राप्त कर लेंगे जिनका उपयोग Foo.hppअभी भी समाप्त करने की आवश्यकता Barहै, वैसे भी Bar.hppखुद को शीर्ष पर शामिल करने के अतिरिक्त बोझ के साथ परिभाषित होने की आवश्यकता है Foo.hpp, या आप किसी अन्य परिदृश्य में चलते हैं जहाँ वास्तव में मदद मिलती है और 99 आपकी संकलन इकाइयों में से% बिना शामिल किए काम कर सकते हैं Bar.hpp, इसके अलावा यह अधिक मौलिक डिजाइन प्रश्न उठाता है (या कम से कम मुझे लगता है कि इसे आजकल होना चाहिए) कि उन्हें भी घोषणा करने की आवश्यकता Barक्यों है और क्योंFoo यहां तक ​​कि इसके बारे में जानने के लिए परेशान होने की जरूरत है कि क्या यह अधिकांश उपयोग के मामलों के लिए अप्रासंगिक है (एक निर्भरता के साथ एक डिजाइन का बोझ क्यों है?

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

एंबेडेड स्क्रिप्टिंग

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

उदाहरण

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

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

यहाँ छवि विवरण दर्ज करें

डिजाइन, डिजाइन, डिजाइन

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

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


1
एक उत्कृष्ट जवाब! Althoguh मैं खोजने के लिए क्या एक सा खुदाई करने के लिए किया था pimpls है :-)
Mawg

0

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

अन्य उत्तरों के विपरीत, मैं उप-प्रणाली प्रति एक (बल्कि बड़े) सार्वजनिक हेडर की सिफारिश करता हूं (जिसमें "निजी" हेडर शामिल हो सकते हैं, शायद कई इनलाइन कार्यों के कार्यान्वयन के लिए अलग-अलग फाइलें हैं)। तुम भी एक हेडर केवल कई #include निर्देश होने पर विचार कर सकते हैं ।

मुझे नहीं लगता कि कई हेडर फ़ाइलों की सिफारिश की जाती है। विशेष रूप से, मैं प्रति वर्ग एक हेडर फ़ाइल, या प्रत्येक कुछ दर्जन लाइनों की कई छोटी हेडर फ़ाइलों की सिफारिश नहीं करता हूं।

(यदि आपके पास बहुत सारी छोटी फाइलें हैं, तो आपको हर छोटी अनुवाद इकाई में उनमें से कई को शामिल करने की आवश्यकता होगी , और समग्र निर्माण में आपको नुकसान हो सकता है)

आप वास्तव में क्या चाहते हैं, प्रत्येक उप-प्रणाली और फ़ाइल के लिए, इसके लिए जिम्मेदार मुख्य डेवलपर की पहचान करना है।

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

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

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

ध्यान दें कि C ++ में, मानक हेडर फाइलें बहुत सारे कोड खींच रही हैं । उदाहरण के लिए #include <vector>लिनक्स (18100 लाइनों) पर मेरे जीसीसी 6 पर दस हजार से अधिक लाइनें खींच रही हैं। और #include <map> लगभग 40KLOC तक फैला हुआ है। इसलिए, यदि आपके पास मानक हेडर सहित कई छोटी हेडर फाइलें हैं, तो आप बिल्ड के दौरान कई हजार लाइनों को फिर से पार्स करते हैं, और आपका संकलन समय भुगतता है। यही कारण है कि मुझे नापसंद है कई छोटी सी ++ स्रोत लाइनें (कुछ सौ लाइनों की अधिकतम), लेकिन कम लेकिन बड़ी सी ++ फ़ाइलों (कई हजार लाइनों की) के पक्ष में।

(इसलिए सैकड़ों छोटी सी ++ फाइलें शामिल हैं, जिनमें हमेशा अप्रत्यक्ष रूप से शामिल हैं- कई मानक हेडर फाइलें विशाल बिल्ड समय देती हैं, जो डेवलपर्स को प्रभावित करती हैं)

सी कोड में, अक्सर हेडर फ़ाइलों का विस्तार कुछ छोटा होता है, इसलिए व्यापार बंद अलग होता है।

प्रेरणा के लिए, मौजूदा मुफ्त सॉफ्टवेयर परियोजनाओं (जैसे जीथब पर ) में पूर्व अभ्यास में भी देखें ।

ध्यान दें कि निर्भरता को एक अच्छी बिल्ड ऑटोमेशन प्रणाली से निपटा जा सकता है। GNU मेक के प्रलेखन का अध्ययन करें । जीसीसी को विभिन्न -Mप्रीप्रोसेसर झंडे के बारे में पता होना (स्वचालित रूप से निर्भरता उत्पन्न करने के लिए उपयोगी)।

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

("हेडर नर्क" पर अपने प्रयासों पर ध्यान न दें-जो आपके लिए एक गैर-मुद्दा है-, लेकिन उन्हें एक अच्छा आर्किटेक्ट बनाने के लिए ध्यान केंद्रित करें)


आपके द्वारा उल्लेखित तकनीकी सही हो सकती हैं। हालाँकि, जैसा कि मैंने इसे समझा था, ओपी संकेत के लिए पूछ रहा था कि कोड रखरखाव और संगठन में सुधार कैसे किया जाए, समय संकलन नहीं। और मुझे इन दो लक्ष्यों के बीच सीधा संघर्ष दिखाई देता है।
मर्फी

लेकिन यह अभी भी एक राय है। और ओपी जाहिर तौर पर इतना बड़ा प्रोजेक्ट शुरू नहीं कर रहा है।
बेसिल स्टारीनेविच 11
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.