“मेरी मशीन पर काम करता है” (अंग्रेज़ी: “Works on my machine”) — डेवलपर का क्लासिक वाक्यांश जो अपने स्थानीय वातावरण में बग को दोहरा नहीं पाता, जबकि बग टीम के अन्य सदस्यों या प्रोडक्शन पर स्थिर रूप से दिखाई देता है। यह स्थिति कॉन्फ़िगरेशन, डिपेंडेंसी वर्शन, ऑपरेटिंग सिस्टम या डेटा में अंतर के कारण डेवलपर की मशीन और उस वातावरण के बीच उत्पन्न होती है जहाँ बग दोहराया जाता है। Stack Overflow Survey 2023 के अनुसार, 58% डेवलपर महीने में कम से कम एक बार यह वाक्यांश कहते हैं, और 31% — साप्ताहिक। समझते हैं कि कोड हर जगह एक जैसा क्यों काम नहीं करता और वातावरण को कैसे मानकीकृत करें।
मुख्य बातें
“मेरी मशीन पर काम करता है” — वह वाक्यांश जो डेवलपर तब बोलता है जब कोई सहकर्मी या परीक्षक बग की रिपोर्ट करता है, लेकिन डेवलपर की मशीन पर वह बग दोहराया नहीं जाता। बाहरी तौर पर यह समस्या से इनकार जैसा लगता है, लेकिन तकनीकी रूप से स्थिति वास्तविक है: कोड वास्तव में एक वातावरण में काम कर सकता है और दूसरे में फेल हो सकता है। कॉन्फ़िगरेशन का एक बिट भी बदल जाए और एप्लिकेशन का व्यवहार पूरी तरह बदल जाता है।
यह वाक्यांश IT समुदाय में एक मीम बन गया है क्योंकि यह एक साथ सच्चा और बेकार है। डेवलपर के दृष्टिकोण से — कोड वास्तव में उसकी मशीन पर काम करता है। टीम के दृष्टिकोण से — समस्या मौजूद है और इसे हल करना आवश्यक है, बहाने बनाना नहीं। स्थिति का हास्य यह है कि डेवलपर सच कहता है, लेकिन यह सच बग को ठीक करने में मदद नहीं करता। यह मीम इतना लोकप्रिय है कि इस पर Reddit, XKCD और DevOps सम्मेलनों में हज़ारों पोस्ट समर्पित हैं।
प्रक्रिया के दृष्टिकोण से, “मेरी मशीन पर काम करता है” वाक्यांश वातावरण पुनरुत्पादन समस्याओं का संकेतक है। यदि दो डेवलपर समान कोड पर समान परिणाम प्राप्त नहीं कर सकते — तो वातावरण सेटअप प्रक्रिया मानकीकृत नहीं है। DevOps अभ्यास कहता है: वातावरण को बिना मैन्युअल क्रियाओं के रिपॉजिटरी से एक कमांड द्वारा पुनरुत्पादित किया जाना चाहिए।
डेवलपर का स्थानीय वातावरण लगभग हमेशा प्रोडक्शन से भिन्न होता है। डेवलपर macOS या Windows का उपयोग करता है, जबकि सर्वर Linux पर चलता है। विभिन्न ऑपरेटिंग सिस्टम में अलग-अलग फ़ाइल सिस्टम, एन्कोडिंग, थ्रेड टाइमिंग और सिस्टम कॉल होते हैं। भले ही दोनों वातावरण Linux हों — कर्नेल, glibc, OpenSSL वर्शन भिन्न हो सकते हैं।
दूसरा कारण — स्थापित सॉफ़्टवेयर का सेट। डेवलपर की मशीन पर Node.js 20 का ग्लोबल वर्शन स्थापित हो सकता है, जबकि CI/CD कॉन्फ़िगरेशन में वर्शन 18 निर्दिष्ट है। या डेवलपर स्थानीय रूप से PostgreSQL 16 का उपयोग करता है, जबकि प्रोडक्शन पर — PostgreSQL 14। माइनर वर्शन में अंतर अक्सर ध्यान देने योग्य नहीं होते, लेकिन मेजर अपडेट SQL क्वेरी के व्यवहार को बदल सकते हैं। npm Inc. के अनुसार, डिपेंडेंसी से संबंधित 67% बग पैच वर्शन में अंतर के कारण होते हैं।
तीसरा कारण — नेटवर्क स्थितियाँ। स्थानीय मशीन पर कोई विलंब, बैंडविड्थ सीमा या DNS समस्याएँ नहीं होतीं। प्रोडक्शन पर बाहरी API का कोई भी अनुरोध 5 ms के बजाय 500 ms ले सकता है। टाइमआउट, retry-लॉजिक, race conditions — ये सभी समस्याएँ केवल वास्तविक लोड और वास्तविक नेटवर्क स्थितियों में दिखाई देती हैं। Toxiproxy जैसे उपकरणों के माध्यम से नेटवर्क अनुकरण डिप्लॉय से पहले ऐसी समस्याओं का पता लगाने में मदद करता है।
पहला कारण — डेटा की कमी। डेवलपर परीक्षण फिक्स्चर के साथ काम करता है, जबकि प्रोडक्शन में अप्रत्याशित मानों वाले लाखों रिकॉर्ड हैं। NULL जिसे डेवलपर अनिवार्य मानता था, नाम में Unicode कैरेक्टर, अत्यधिक लंबी स्ट्रिंग — ये सब बग पैदा कर सकते हैं जो सिंथेटिक डेटा वाली स्थानीय DB पर दोहराए नहीं जा सकते।
दूसरा कारण — अलग-अलग कंपाइलेशन और बिल्ड फ़्लैग। रिलीज़ बिल्ड (Release/Distribution) डीबग बिल्ड (Debug) से भिन्न हो सकता है। कंपाइलर ऑप्टिमाइज़ेशन, डीबग लॉग हटाना, फ़ंक्शन इनलाइनिंग — ये सब बग को छिपा सकते हैं या, इसके विपरीत, प्रकट कर सकते हैं। सामान्य उदाहरण: डीबग बिल्ड में assert काम करता है जो रिलीज़ में वेरिएबल इनिशियलाइज़ेशन के अलग क्रम के कारण फेल होता है।
तीसरा कारण — स्थानीय कैश और अस्थायी फ़ाइलें। डेवलपर बग को नोटिस नहीं कर सकता क्योंकि ब्राउज़र में पुरानी स्क्रिप्ट कैश्ड हैं, Redis में पुराना डेटा सहेजा गया है, और फ़ाइल सिस्टम में पिछले रन की अस्थायी फ़ाइलें हैं। स्वच्छ रन (incognito-मोड, कैश साफ़ करना, fresh install) अक्सर उस बग को दोहराता है जो “अपने आप” प्रकट नहीं हुआ था।
चौथा कारण — ग्लोबल और स्थानीय डिपेंडेंसी का विरोध। Ruby gems, Python pip, Node.js npm जैसे उपकरणों में ग्लोबल रूप से स्थापित पैकेज हो सकते हैं जो कोड को स्थानीय रूप से काम करने में “मदद” करते हैं लेकिन प्रोडक्शन में गायब हैं। वर्चुअल वातावरण (virtualenv, venv, nvm) का उपयोग प्रोजेक्ट को ग्लोबल इंस्टॉलेशन से अलग करता है और वातावरण को दोहराने योग्य बनाता है।
“मेरी मशीन पर काम करता है” वाक्यांश टीम में विश्वास को नष्ट करता है। यदि डेवलपर नियमित रूप से बग दोहरा नहीं पाता, तो सहकर्मी उसकी क्षमता या परीक्षण की गहनता पर संदेह करने लगते हैं। समय के साथ यह माइक्रोमैनेजमेंट की ओर ले जाता है: प्रत्येक बदलाव के लिए दूसरे डेवलपर द्वारा जाँच की आवश्यकता होती है, जो विकास को धीमा कर देता है। Google Project Aristotle के अनुसार, टीम में मनोवैज्ञानिक सुरक्षा सीधे उत्पादकता को प्रभावित करती है, और वातावरण के बारे में लगातार विवाद इसे कम करने वाले कारकों में से एक है।
दूसरी समस्या — code review का धीमा होना। यदि डेवलपर स्थानीय रूप से बग दोहरा नहीं पाता, तो वह सहकर्मी के pull request को “मेरे पास काम करता है — मतलब समस्या तुम्हारी है” कहकर अस्वीकार कर सकता है। यह संघर्ष को बढ़ावा देता है और फीचर डिलीवरी में देरी करता है। वातावरण का मानकीकरण इस संघर्ष को समाप्त करता है: यदि दोनों डेवलपर समान Docker कंटेनर में काम करते हैं, तो “किसके पास काम करता है” का सवाल अर्थहीन हो जाता है।
तीसरी समस्या — ट्रैकर में बग का नुकसान। बग जो “डेवलपर के पास दोहराए नहीं जाते” अक्सर “दोहराया नहीं जा सकता” (Cannot Reproduce) नोट के साथ बंद कर दिए जाते हैं। एक महीने बाद बग प्रोडक्शन में सामने आता है, और उसका सुधार 10 गुना अधिक महंगा होता है। नियम: यदि बग कम से कम एक व्यक्ति में दोहराया जाता है — वह अस्तित्व में है, भले ही वह डेवलपर के पास काम करता हो या नहीं।
पहला और सबसे प्रभावी तरीका — Docker। पूरा प्रोजेक्ट बिना किसी अतिरिक्त क्रिया के docker-compose up के माध्यम से चलना चाहिए। डेटाबेस, कैश, मैसेज क्यू, वेब सर्वर — सब कंटेनर में चलता है। डेवलपर केवल Docker और Git इंस्टॉल करता है। बाकी — कंटेनर के अंदर। यह सुनिश्चित करता है कि OS की परवाह किए बिना टीम के सभी सदस्यों का वातावरण समान हो।
दूसरा तरीका — वर्शन मैनेजर। यदि Docker संभव नहीं है (लाइसेंस सीमाएँ, legacy-इन्फ्रास्ट्रक्चर), तो nvm (Node.js), rbenv (Ruby), pyenv (Python), sdkman (Java) का उपयोग करें। वर्शन मैनेजर प्रोजेक्ट के भीतर भाषाओं और उपकरणों के वर्शन स्विच करने की अनुमति देते हैं। .nvmrc, .ruby-version, .python-version फ़ाइलें रिपॉजिटरी में होनी चाहिए और CI/CD द्वारा जाँची जानी चाहिए।
तीसरा तरीका — वर्चुअल मशीनों के लिए Vagrant। Vagrant VirtualBox या VMware पर निर्दिष्ट OS और कॉन्फ़िगरेशन के साथ वर्चुअल मशीन चलाता है। VM के अंदर provisioning-स्क्रिप्ट (shell, Ansible, Puppet) के माध्यम से सभी डिपेंडेंसी स्थापित की जाती हैं। Vagrant Docker से भारी है लेकिन OS स्तर पर पूर्ण अलगाव देता है — Linux कर्नेल के विशिष्ट वर्शन पर निर्भर प्रोजेक्ट्स के लिए उपयोगी।
चौथा — makefile और bootstrap स्क्रिप्ट। एक साधारण Makefile भी install, test, build, clean लक्ष्यों के साथ नियमित कार्यों को मानकीकृत कर सकता है। make install कमांड को सभी डिपेंडेंसी स्थापित करनी चाहिए, DB कॉन्फ़िगर करनी चाहिए और परीक्षण डेटा बनाना चाहिए। सभी डेवलपर्स के लिए एकल प्रवेश बिंदु वातावरण सेटअप में मैन्युअल त्रुटियों को समाप्त करता है।
मुख्य उपकरण — डिपेंडेंसी के lock-फ़ाइलें। package-lock.json (npm), yarn.lock (Yarn), Podfile.lock (CocoaPods), pubspec.lock (Flutter) प्रत्येक पैकेज के सटीक वर्शन को स्थिर करते हैं। lock-फ़ाइल के बिना, अलग-अलग समय पर डिपेंडेंसी स्थापित करने वाले दो डेवलपर अलग-अलग माइनर वर्शन प्राप्त कर सकते हैं। Lock-फ़ाइल रिपॉजिटरी में होनी चाहिए और मैन्युअल रूप से संपादित नहीं की जानी चाहिए।
दूसरा उपकरण — रिपॉजिटरी में .env.example। टिप्पणियों के साथ पर्यावरण चर की टेम्पलेट फ़ाइल। डेवलपर इसे .env में कॉपी करता है और अपने मान भरता है। CI/CD पाइपलाइन जाँचती है कि सभी अनिवार्य चर सेट हैं। GitLab 2023 के अनुसार, .env.example का उपयोग करने वाली टीमें पर्यावरण चर से संबंधित घटनाओं की संख्या 40% तक कम करती हैं।
तीसरा उपकरण — pre-commit हुक्स। स्वचालित जाँच जो प्रत्येक कमिट से पहले चलती है: लिंटर, फ़ॉर्मेटर, टाइप जाँच, टेस्ट। यदि हुक्स सभी डेवलपर्स में समान रूप से कॉन्फ़िगर किए गए हैं, तो फ़ॉर्मेटिंग या टाइप की त्रुटियाँ जो “स्थानीय मशीन पर चल गईं” प्रोडक्शन तक नहीं पहुँचेंगी। JavaScript के लिए Husky और Python के लिए pre-commit लोकप्रिय समाधान हैं।
चौथा — CI/CD पाइपलाइन जो स्वच्छ वातावरण में टेस्ट चलाती है। यदि टेस्ट CI में पास होते हैं लेकिन स्थानीय रूप से नहीं — समस्या स्थानीय वातावरण सेटअप में है। यदि टेस्ट CI में पास नहीं होते — pull request मर्ज नहीं होता। यह सख्त नियम “स्थानीय रूप से काम करने वाले” बग को मुख्य शाखा में आने से रोकता है।
अक्सर पूछे जाने वाले प्रश्न
यह एक रक्षात्मक प्रतिक्रिया है: डेवलपर डीबगिंग पर बहुत समय बिताता है, और यह सुनना कि कोड काम नहीं करता — मनोवैज्ञानिक रूप से कष्टदायक है। यह वाक्यांश दोष की भावना के बिना “स्विच” करने और कारण खोजना शुरू करने का समय देता है।
स्वच्छ वातावरण (clean install, incognito-मोड) पर बग दोहराने के लिए कहें। यदि दोहराया नहीं जाता — डिपेंडेंसी वर्शन और पर्यावरण चर की तुलना करें। यदि मदद नहीं मिलती — प्रोडक्शन के समान Docker वातावरण चलाएँ।
Docker निश्चित कॉन्फ़िगरेशन वाला एक पृथक कंटेनर प्रदान करता है जो किसी भी OS पर समान रूप से काम करता है। सभी डेवलपर एक ही Dockerfile का उपयोग करते हैं, इसलिए वातावरण समान होता है। यदि बग कंटेनर में दोहराया नहीं जाता — तो समस्या वास्तव में कोड में है, सिस्टम में नहीं।
Lock-फ़ाइल सभी ट्रांज़िटिव डिपेंडेंसी के सटीक हैश और वर्शन को स्थिर करती है। भले ही पैकेज रजिस्ट्री में डिपेंडेंसी का नया वर्शन आया हो, lock-फ़ाइल से स्थापना गारंटी देती है कि प्रत्येक डेवलपर को वही पैकेज सेट मिलेगा जो बाकियों को।
VirtualBox के साथ Vagrant उचित है यदि प्रोजेक्ट OS कर्नेल के विशिष्ट मॉड्यूल पर निर्भर करता है या कर्नेल स्तर पर पूर्ण अलगाव की आवश्यकता है। 90% प्रोजेक्ट्स के लिए Docker हल्का, तेज़ और अधिक सुविधाजनक है। चुनाव इस पर निर्भर करता है कि प्रोजेक्ट OS के साथ कितनी गहराई से इंटरैक्ट करता है।
निष्कर्ष
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें