“আমার মেশিনে কাজ করে” (ইংরেজি: “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-লজিক, রেস কন্ডিশন — এই সব সমস্যা শুধুমাত্র বাস্তব লোড এবং বাস্তব নেটওয়ার্ক অবস্থায় দেখা দেয়। 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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন