টাস্ক-ভিত্তিক বিল্ড সিস্টেম

এই পৃষ্ঠায় টাস্ক-ভিত্তিক বিল্ড সিস্টেম, তারা কীভাবে কাজ করে এবং টাস্ক-ভিত্তিক সিস্টেমের সাথে ঘটতে পারে এমন কিছু জটিলতা কভার করে। শেল স্ক্রিপ্টের পরে, টাস্ক-ভিত্তিক বিল্ড সিস্টেমগুলি বিল্ডিংয়ের পরবর্তী যৌক্তিক বিবর্তন।

টাস্ক-ভিত্তিক বিল্ড সিস্টেম বোঝা

একটি টাস্ক-ভিত্তিক বিল্ড সিস্টেমে, কাজের মৌলিক একক হল টাস্ক। প্রতিটি টাস্ক হল একটি স্ক্রিপ্ট যা যেকোনো ধরনের লজিক চালাতে পারে, এবং টাস্ক অন্যান্য কাজগুলিকে নির্ভরতা হিসাবে নির্দিষ্ট করে যা তাদের আগে চলতে হবে। বর্তমানে ব্যবহৃত বেশিরভাগ প্রধান বিল্ড সিস্টেম, যেমন পিঁপড়া, মাভেন, গ্রেডল, গ্রান্ট এবং রেক, টাস্ক ভিত্তিক। শেল স্ক্রিপ্টের পরিবর্তে, বেশিরভাগ আধুনিক বিল্ড সিস্টেমে বিল্ড ফাইলগুলি তৈরি করতে ইঞ্জিনিয়ারদের প্রয়োজন হয় যা বিল্ডটি কীভাবে সম্পাদন করতে হয় তা বর্ণনা করে।

পিঁপড়া ম্যানুয়াল থেকে এই উদাহরণ নিন:

<project name="MyProject" default="dist" basedir=".">
   <description>
     simple example build file
   </description>
   <!-- set global properties for this build -->
   <property name="src" location="src"/>
   <property name="build" location="build"/>
   <property name="dist" location="dist"/>

   <target name="init">
     <!-- Create the time stamp -->
     <tstamp/>
     <!-- Create the build directory structure used by compile -->
     <mkdir dir="${build}"/>
   </target>
   <target name="compile" depends="init"
       description="compile the source">
     <!-- Compile the Java code from ${src} into ${build} -->
     <javac srcdir="${src}" destdir="${build}"/>
   </target>
   <target name="dist" depends="compile"
       description="generate the distribution">
     <!-- Create the distribution directory -->
     <mkdir dir="${dist}/lib"/>
     <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
     <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>
   <target name="clean"
       description="clean up">
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
</project>

বিল্ডফাইলটি XML-এ লেখা এবং বিল্ড সম্পর্কে কিছু সাধারণ মেটাডেটা সংজ্ঞায়িত করে এবং কাজের একটি তালিকা (XML-এ <target> ট্যাগ)। (Ant একটি টাস্ক প্রতিনিধিত্ব করার জন্য টার্গেট শব্দটি ব্যবহার করে, এবং এটি কমান্ডগুলি বোঝাতে টাস্ক শব্দটি ব্যবহার করে।) প্রতিটি টাস্ক এন্ট দ্বারা সংজ্ঞায়িত সম্ভাব্য কমান্ডগুলির একটি তালিকা কার্যকর করে, যার মধ্যে রয়েছে ডিরেক্টরি তৈরি করা এবং মুছে ফেলা, javac চালানো এবং একটি JAR তৈরি করা। ফাইল কমান্ডের এই সেটটি ব্যবহারকারী-প্রদত্ত প্লাগ-ইন দ্বারা প্রসারিত করা যেতে পারে যে কোনো ধরণের যুক্তিকে কভার করতে। প্রতিটি টাস্ক ডিপেন্ডেড অ্যাট্রিবিউটের মাধ্যমে যে কাজগুলির উপর নির্ভর করে তা সংজ্ঞায়িত করতে পারে। এই নির্ভরতাগুলি একটি অ্যাসাইক্লিক গ্রাফ গঠন করে, যেমনটি চিত্র 1 এ দেখা গেছে।

এক্রাইলিক গ্রাফ নির্ভরতা দেখাচ্ছে

চিত্র 1. নির্ভরতা দেখানো একটি অ্যাসাইক্লিক গ্রাফ

ব্যবহারকারীরা পিঁপড়ার কমান্ড-লাইন টুলে কাজ প্রদান করে বিল্ডগুলি সম্পাদন করে। উদাহরণস্বরূপ, যখন একজন ব্যবহারকারী ant dist টাইপ করে, তখন Ant নিম্নলিখিত পদক্ষেপগুলি গ্রহণ করে:

  1. বর্তমান ডিরেক্টরিতে build.xml নামে একটি ফাইল লোড করে এবং চিত্র 1-এ দেখানো গ্রাফ গঠন তৈরি করতে পার্স করে।
  2. কমান্ড লাইনে সরবরাহ করা dist নামের টাস্কটি সন্ধান করে এবং আবিষ্কার করে যে এটি compile নামের টাস্কের উপর নির্ভরশীলতা রয়েছে।
  3. compile নামক টাস্কের সন্ধান করে এবং আবিষ্কার করে যে এটি init নামের টাস্কের উপর নির্ভরশীল।
  4. init নামের টাস্কের সন্ধান করে এবং আবিষ্কার করে যে এটির কোন নির্ভরতা নেই।
  5. init টাস্কে সংজ্ঞায়িত কমান্ডগুলি চালায়।
  6. compile টাস্কে সংজ্ঞায়িত কমান্ডগুলি কার্যকর করে যে টাস্কের সমস্ত নির্ভরতা চালানো হয়েছে।
  7. dist টাস্কে সংজ্ঞায়িত কমান্ডগুলি কার্যকর করে যে টাস্কের সমস্ত নির্ভরতা চালানো হয়েছে।

শেষ পর্যন্ত, dist টাস্ক চালানোর সময় পিপীলিকার দ্বারা নির্বাহিত কোডটি নিম্নলিখিত শেল স্ক্রিপ্টের সমতুল্য:

./createTimestamp.sh
mkdir build/
javac src/* -d build/
mkdir -p dist/lib/
jar cf dist/lib/MyProject-$(date --iso-8601).jar build/*

যখন সিনট্যাক্সটি সরানো হয়, বিল্ডফাইল এবং বিল্ড স্ক্রিপ্ট আসলে খুব আলাদা নয়। কিন্তু আমরা ইতিমধ্যে এটি করে অনেক লাভ করেছি। আমরা অন্যান্য ডিরেক্টরিতে নতুন বিল্ড ফাইল তৈরি করতে পারি এবং তাদের একসাথে লিঙ্ক করতে পারি। আমরা সহজে নতুন কাজ যোগ করতে পারি যা বিদ্যমান কাজের উপর নির্ভর করে নির্বিচারে এবং জটিল উপায়ে। আমাদের শুধুমাত্র একটি টাস্কের নাম ant কমান্ড-লাইন টুলে পাঠাতে হবে, এবং এটি চালানোর জন্য প্রয়োজনীয় সবকিছু নির্ধারণ করে।

পিঁপড়া হল একটি পুরানো সফ্টওয়্যার, যা মূলত 2000 সালে প্রকাশিত হয়েছিল৷ মাভেন এবং গ্রেডলের মতো অন্যান্য সরঞ্জামগুলি মধ্যবর্তী বছরগুলিতে পিঁপড়ে উন্নত হয়েছে এবং অপরিহার্যভাবে এটিকে বাহ্যিক নির্ভরতার স্বয়ংক্রিয় ব্যবস্থাপনা এবং কোনও XML ছাড়াই একটি ক্লিনার সিনট্যাক্সের মতো বৈশিষ্ট্যগুলি যোগ করে প্রতিস্থাপন করেছে৷ কিন্তু এই নতুন সিস্টেমগুলির প্রকৃতি একই রয়ে গেছে: তারা ইঞ্জিনিয়ারদের কাজ হিসাবে নীতিগত এবং মডুলার উপায়ে বিল্ড স্ক্রিপ্ট লিখতে দেয় এবং সেই কাজগুলি সম্পাদন করার জন্য এবং তাদের মধ্যে নির্ভরতা পরিচালনা করার জন্য সরঞ্জাম সরবরাহ করে।

টাস্ক-ভিত্তিক বিল্ড সিস্টেমের অন্ধকার দিক

যেহেতু এই সরঞ্জামগুলি মূলত ইঞ্জিনিয়ারদের যে কোনও স্ক্রিপ্টকে একটি কাজ হিসাবে সংজ্ঞায়িত করতে দেয়, সেগুলি অত্যন্ত শক্তিশালী, আপনি তাদের সাথে কল্পনা করতে পারেন এমন কিছু করতে দেয়। তবে সেই শক্তিটি ত্রুটির সাথে আসে এবং টাস্ক-ভিত্তিক বিল্ড সিস্টেমগুলির সাথে কাজ করা কঠিন হয়ে উঠতে পারে কারণ তাদের বিল্ড স্ক্রিপ্টগুলি আরও জটিল হয়ে ওঠে। এই ধরনের সিস্টেমের সমস্যা হল যে তারা আসলে ইঞ্জিনিয়ারদের খুব বেশি শক্তি দেয় এবং সিস্টেমে পর্যাপ্ত শক্তি দেয় না । কারণ সিস্টেমের কোন ধারণা নেই যে স্ক্রিপ্টগুলি কী করছে, কর্মক্ষমতা ক্ষতিগ্রস্থ হয়, কারণ এটি কীভাবে বিল্ডের পদক্ষেপগুলি নির্ধারণ করে এবং কার্যকর করে তাতে এটি অবশ্যই খুব রক্ষণশীল হতে হবে। এবং সিস্টেমের পক্ষে নিশ্চিত করার কোন উপায় নেই যে প্রতিটি স্ক্রিপ্ট যা করা উচিত তাই করছে, তাই স্ক্রিপ্টগুলি জটিলতার মধ্যে বাড়তে থাকে এবং শেষ পর্যন্ত অন্য জিনিস হয়ে যায় যার ডিবাগিং প্রয়োজন।

নির্মাণের ধাপগুলিকে সমান্তরাল করার অসুবিধা

আধুনিক ডেভেলপমেন্ট ওয়ার্কস্টেশনগুলি বেশ শক্তিশালী, একাধিক কোর যা সমান্তরালভাবে বেশ কয়েকটি বিল্ড ধাপ কার্যকর করতে সক্ষম। কিন্তু টাস্ক-ভিত্তিক সিস্টেমগুলি প্রায়শই টাস্ক এক্সিকিউশনকে সমান্তরাল করতে অক্ষম হয় এমনকি যখন মনে হয় তাদের সক্ষম হওয়া উচিত। ধরুন যে টাস্ক A টাস্ক B এবং C এর উপর নির্ভর করে। কারণ B এবং C এর একে অপরের উপর কোন নির্ভরশীলতা নেই, সেগুলিকে একই সময়ে চালানো কি নিরাপদ যাতে সিস্টেমটি আরও দ্রুত A টাস্কে যেতে পারে? হতে পারে, যদি তারা একই সম্পদের কোনো স্পর্শ না করে। কিন্তু নাও হতে পারে—সম্ভবত উভয়ই তাদের স্ট্যাটাস ট্র্যাক করতে একই ফাইল ব্যবহার করে এবং একই সময়ে সেগুলি চালানোর ফলে একটি দ্বন্দ্ব সৃষ্টি হয়। সিস্টেমের জন্য সাধারণভাবে জানার কোন উপায় নেই, তাই হয় এটিকে এই দ্বন্দ্বগুলির ঝুঁকি নিতে হবে (যা বিরল কিন্তু খুব কঠিন-ডিবাগ বিল্ড সমস্যাগুলির দিকে পরিচালিত করে), অথবা এটি সম্পূর্ণ বিল্ডটিকে একটি একক থ্রেডে চালানোর জন্য সীমাবদ্ধ করতে হবে একক প্রক্রিয়া। এটি একটি শক্তিশালী বিকাশকারী মেশিনের একটি বিশাল বর্জ্য হতে পারে এবং এটি একাধিক মেশিনে বিল্ড বিতরণের সম্ভাবনাকে সম্পূর্ণরূপে বাতিল করে দেয়।

ক্রমবর্ধমান বিল্ড সম্পাদন করতে অসুবিধা

একটি ভাল বিল্ড সিস্টেম ইঞ্জিনিয়ারদের নির্ভরযোগ্য ক্রমবর্ধমান বিল্ডগুলি সম্পাদন করতে দেয় যাতে একটি ছোট পরিবর্তনের জন্য পুরো কোডবেসটিকে স্ক্র্যাচ থেকে পুনর্নির্মাণের প্রয়োজন হয় না। এটি বিশেষ করে গুরুত্বপূর্ণ যদি বিল্ড সিস্টেম ধীর হয় এবং পূর্বোক্ত কারণগুলির জন্য বিল্ড ধাপগুলিকে সমান্তরাল করতে অক্ষম হয়। কিন্তু দুর্ভাগ্যবশত, টাস্ক-ভিত্তিক বিল্ড সিস্টেম এখানেও সংগ্রাম করে। যেহেতু কাজগুলি কিছু করতে পারে, সেগুলি ইতিমধ্যে সম্পন্ন হয়েছে কিনা তা পরীক্ষা করার কোনও উপায় নেই৷ অনেক কাজ কেবল সোর্স ফাইলের একটি সেট নেয় এবং বাইনারিগুলির একটি সেট তৈরি করতে একটি কম্পাইলার চালায়; সুতরাং, অন্তর্নিহিত উত্স ফাইলগুলি পরিবর্তিত না হলে তাদের পুনরায় চালানোর দরকার নেই। কিন্তু অতিরিক্ত তথ্য ছাড়া, সিস্টেম এটি নিশ্চিতভাবে বলতে পারে না-হয়ত টাস্কটি এমন একটি ফাইল ডাউনলোড করে যা পরিবর্তন হতে পারে, অথবা হতে পারে এটি একটি টাইমস্ট্যাম্প লিখে যা প্রতিটি রানে ভিন্ন হতে পারে। সঠিকতার গ্যারান্টি দেওয়ার জন্য, সিস্টেমটিকে সাধারণত প্রতিটি বিল্ডের সময় প্রতিটি কাজ পুনরায় চালাতে হবে। কিছু বিল্ড সিস্টেম ইনক্রিমেন্টাল বিল্ডগুলিকে সক্ষম করার চেষ্টা করে প্রকৌশলীদের সেই শর্তগুলি উল্লেখ করে যেগুলির অধীনে একটি টাস্ক পুনরায় চালানো দরকার। কখনও কখনও এটি সম্ভব হয়, কিন্তু প্রায়শই এটি প্রদর্শিত হওয়ার চেয়ে অনেক জটিল সমস্যা। উদাহরণ স্বরূপ, C++ এর মত ভাষাগুলিতে যেগুলি ফাইলগুলিকে অন্য ফাইলগুলিকে সরাসরি অন্তর্ভুক্ত করার অনুমতি দেয়, ইনপুট উত্সগুলিকে পার্স না করে পরিবর্তনের জন্য যে ফাইলগুলি দেখতে হবে তার সম্পূর্ণ সেট নির্ধারণ করা অসম্ভব৷ প্রকৌশলীরা প্রায়শই শর্টকাট গ্রহণ করে, এবং এই শর্টকাটগুলি বিরল এবং হতাশাজনক সমস্যার দিকে নিয়ে যেতে পারে যেখানে একটি টাস্ক ফলাফল পুনরায় ব্যবহার করা হয় এমনকি যখন এটি হওয়া উচিত নয়। যখন এটি প্রায়শই ঘটে, তখন প্রকৌশলীরা একটি নতুন অবস্থা পেতে প্রতিটি বিল্ডের আগে পরিষ্কারভাবে চালানোর অভ্যাস করে ফেলেন, যা প্রথম স্থানে ক্রমবর্ধমান বিল্ড করার উদ্দেশ্যকে সম্পূর্ণভাবে পরাজিত করে। যখন একটি কাজ পুনরায় চালানোর প্রয়োজন হয় তা খুঁজে বের করা আশ্চর্যজনকভাবে সূক্ষ্ম, এবং এটি মানুষের চেয়ে মেশিন দ্বারা ভালভাবে পরিচালনা করা একটি কাজ।

স্ক্রিপ্ট রক্ষণাবেক্ষণ এবং ডিবাগ করার অসুবিধা

অবশেষে, টাস্ক-ভিত্তিক বিল্ড সিস্টেম দ্বারা আরোপিত বিল্ড স্ক্রিপ্টগুলির সাথে কাজ করা প্রায়শই কঠিন। যদিও তারা প্রায়শই কম যাচাই-বাছাই করে, বিল্ড স্ক্রিপ্টগুলি তৈরি করা সিস্টেমের মতোই কোড, এবং বাগ লুকানোর জন্য সহজ জায়গা। এখানে বাগগুলির কিছু উদাহরণ রয়েছে যা একটি টাস্ক-ভিত্তিক বিল্ড সিস্টেমের সাথে কাজ করার সময় খুব সাধারণ:

  • আউটপুট হিসাবে একটি নির্দিষ্ট ফাইল তৈরি করতে টাস্ক A টাস্ক B এর উপর নির্ভর করে। টাস্ক বি এর মালিক বুঝতে পারে না যে অন্যান্য কাজগুলি এটির উপর নির্ভর করে, তাই তারা এটিকে অন্য জায়গায় আউটপুট তৈরি করতে পরিবর্তন করে। এটি সনাক্ত করা যাবে না যতক্ষণ না কেউ টাস্ক A চালানোর চেষ্টা করে এবং এটি ব্যর্থ হয়।
  • টাস্ক A টাস্ক B এর উপর নির্ভর করে, যা টাস্ক C এর উপর নির্ভর করে, যেটি একটি নির্দিষ্ট ফাইলকে আউটপুট হিসাবে তৈরি করছে যা টাস্ক A এর জন্য প্রয়োজন। টাস্ক B এর মালিক সিদ্ধান্ত নেয় যে এটিকে আর টাস্ক C এর উপর নির্ভর করতে হবে না, যার ফলে টাস্ক হয় A ব্যর্থ হতে পারে যদিও টাস্ক B টাস্ক C কে মোটেও পাত্তা দেয় না!
  • একটি নতুন টাস্কের বিকাশকারী ঘটনাক্রমে টাস্কটি চালানো মেশিন সম্পর্কে একটি অনুমান করে, যেমন একটি সরঞ্জামের অবস্থান বা নির্দিষ্ট পরিবেশের ভেরিয়েবলের মান। টাস্কটি তাদের মেশিনে কাজ করে, কিন্তু যখনই অন্য ডেভেলপার চেষ্টা করে তখন ব্যর্থ হয়।
  • একটি টাস্কে একটি ননডিটারমিনিস্টিক উপাদান থাকে, যেমন ইন্টারনেট থেকে একটি ফাইল ডাউনলোড করা বা একটি বিল্ডে একটি টাইমস্ট্যাম্প যোগ করা। এখন, লোকেরা প্রতিবার বিল্ড চালানোর সময় সম্ভাব্য ভিন্ন ফলাফল পায়, যার অর্থ হল প্রকৌশলীরা সর্বদা একটি স্বয়ংক্রিয় বিল্ড সিস্টেমে ঘটে যাওয়া একে অপরের ব্যর্থতা বা ব্যর্থতাগুলি পুনরুত্পাদন করতে এবং ঠিক করতে সক্ষম হবে না।
  • একাধিক নির্ভরতা সহ কাজগুলি জাতি পরিস্থিতি তৈরি করতে পারে। টাস্ক A যদি টাস্ক B এবং টাস্ক C উভয়ের উপর নির্ভর করে এবং টাস্ক B এবং C উভয়ই একই ফাইল পরিবর্তন করে, টাস্ক A একটি ভিন্ন ফলাফল পায় তার উপর নির্ভর করে যে B এবং C টাস্কগুলির মধ্যে কোনটি প্রথমে শেষ হয়।

এখানে দেওয়া টাস্ক-ভিত্তিক কাঠামোর মধ্যে এই কর্মক্ষমতা, সঠিকতা বা রক্ষণাবেক্ষণের সমস্যাগুলি সমাধান করার কোনও সাধারণ-উদ্দেশ্য উপায় নেই। যতক্ষণ পর্যন্ত ইঞ্জিনিয়াররা নির্বিচারে কোড লিখতে পারে যা বিল্ড চলাকালীন চলে, সিস্টেমের কাছে পর্যাপ্ত তথ্য থাকতে পারে না যাতে সর্বদা বিল্ডগুলি দ্রুত এবং সঠিকভাবে চালানো যায়। সমস্যা সমাধানের জন্য, আমাদের প্রকৌশলীদের হাত থেকে কিছু ক্ষমতা বের করে সিস্টেমের হাতে ফিরিয়ে দিতে হবে এবং সিস্টেমের ভূমিকাকে চলমান কাজ হিসাবে নয়, বরং শিল্পকর্মের উত্পাদন হিসাবে পুনর্বিবেচনা করতে হবে।

এই পদ্ধতির ফলে আর্টিফ্যাক্ট-ভিত্তিক বিল্ড সিস্টেম তৈরি হয়, যেমন ব্লেজ এবং বেজেল।