পূর্ববর্তী পৃষ্ঠাগুলি দেখতে গিয়ে, একটি থিম বারবার পুনরাবৃত্তি হয়: আপনার নিজের কোড পরিচালনা করা মোটামুটি সহজ, কিন্তু এর নির্ভরতাগুলি পরিচালনা করা অনেক বেশি কঠিন। সব ধরণের নির্ভরতা রয়েছে: কখনও কখনও কোনও কাজের উপর নির্ভরতা থাকে (যেমন "আমি একটি রিলিজকে সম্পূর্ণ হিসাবে চিহ্নিত করার আগে ডকুমেন্টেশনটি পুশ করি"), এবং কখনও কখনও কোনও শিল্পকর্মের উপর নির্ভরতা থাকে (যেমন "আমার সর্বশেষ সংস্করণ থাকা দরকার আমার কোড তৈরি করতে কম্পিউটার ভিশন লাইব্রেরি")। কখনও কখনও, আপনার কোডবেসের অন্য অংশে আপনার অভ্যন্তরীণ নির্ভরতা থাকে, এবং কখনও কখনও আপনার কোড বা অন্য দলের মালিকানাধীন ডেটার উপর বাহ্যিক নির্ভরতা থাকে (হয় আপনার সংস্থা বা তৃতীয় পক্ষের)। কিন্তু যাই হোক না কেন, "আমার এটি পাওয়ার আগে আমার প্রয়োজন" ধারণাটি এমন কিছু যা বিল্ড সিস্টেমের ডিজাইনে বারবার পুনরাবৃত্তি হয় এবং নির্ভরতা পরিচালনা করা সম্ভবত একটি বিল্ড সিস্টেমের সবচেয়ে মৌলিক কাজ।
মডিউল এবং নির্ভরতা নিয়ে কাজ করা
ব্যাজেলের মতো শিল্পকর্ম-ভিত্তিক বিল্ড সিস্টেম ব্যবহার করে এমন প্রকল্পগুলি মডিউলগুলির একটি সেটে বিভক্ত হয়, মডিউলগুলি BUILD
ফাইলগুলির মাধ্যমে একে অপরের উপর নির্ভরতা প্রকাশ করে। এই মডিউলগুলির সঠিক সংগঠন এবং নির্ভরতা বিল্ড সিস্টেমের কার্যকারিতা এবং এটি বজায় রাখতে কতটা কাজ নেয় উভয়ের উপর একটি বিশাল প্রভাব ফেলতে পারে।
সূক্ষ্ম দানাদার মডিউল এবং 1:1:1 নিয়ম ব্যবহার করা
একটি আর্টিফ্যাক্ট-ভিত্তিক বিল্ড গঠন করার সময় যে প্রথম প্রশ্নটি আসে তা হল একটি পৃথক মডিউলের কতটা কার্যকারিতা অন্তর্ভুক্ত করা উচিত তা নির্ধারণ করা। Bazel-এ, একটি মডিউল একটি লক্ষ্য দ্বারা উপস্থাপিত হয় যা একটি java_library
বা একটি go_binary
এর মতো একটি নির্মাণযোগ্য ইউনিট নির্দিষ্ট করে। একটি চরম পর্যায়ে, একটি BUILD
ফাইল রুটে রেখে এবং সেই প্রোজেক্টের সমস্ত সোর্স ফাইলগুলিকে পুনরাবৃত্তভাবে গ্লব করার মাধ্যমে পুরো প্রকল্পটিকে একটি একক মডিউলে রাখা যেতে পারে। অন্য চরমে, প্রায় প্রতিটি সোর্স ফাইলকে তার নিজস্ব মডিউলে তৈরি করা যেতে পারে, কার্যকরভাবে প্রতিটি ফাইলের উপর নির্ভর করে একটি BUILD
ফাইলে তালিকাভুক্ত করা প্রয়োজন।
বেশিরভাগ প্রকল্পগুলি এই চরমগুলির মধ্যে কোথাও পড়ে, এবং পছন্দটি কর্মক্ষমতা এবং রক্ষণাবেক্ষণের মধ্যে একটি ট্রেড-অফ জড়িত। সম্পূর্ণ প্রজেক্টের জন্য একটি মডিউল ব্যবহার করার অর্থ হতে পারে যে বাহ্যিক নির্ভরতা যোগ করা ব্যতীত আপনাকে কখনই BUILD
ফাইলটি স্পর্শ করতে হবে না, তবে এর মানে হল যে বিল্ড সিস্টেমটি সর্বদা পুরো প্রকল্পটি একবারে তৈরি করতে হবে। এর মানে হল যে এটি বিল্ডের অংশগুলিকে সমান্তরাল বা বিতরণ করতে সক্ষম হবে না, বা এটি ইতিমধ্যে তৈরি করা অংশগুলিকে ক্যাশে করতে সক্ষম হবে না। এক-মডিউল-প্রতি-ফাইল এর বিপরীত: বিল্ড সিস্টেমে বিল্ডের ক্যাশিং এবং শিডিউলিং ধাপে সর্বাধিক নমনীয়তা রয়েছে, কিন্তু প্রকৌশলীদের নির্ভরশীলতার তালিকা বজায় রাখার জন্য আরও বেশি প্রচেষ্টা ব্যয় করতে হবে যখনই তারা কোন ফাইলের রেফারেন্স পরিবর্তন করে।
যদিও সঠিক গ্রানুলারিটি ভাষা অনুসারে পরিবর্তিত হয় (এবং প্রায়শই এমনকি ভাষার মধ্যেও), Google সাধারণত একটি টাস্ক-ভিত্তিক বিল্ড সিস্টেমে লেখার চেয়ে উল্লেখযোগ্যভাবে ছোট মডিউলের পক্ষে থাকে। Google-এ একটি সাধারণ উৎপাদন বাইনারি প্রায়ই হাজার হাজার লক্ষ্যের উপর নির্ভর করে এবং এমনকি একটি মাঝারি আকারের দল তার কোডবেসের মধ্যে কয়েকশ টার্গেটের মালিক হতে পারে। প্যাকেজিংয়ের একটি শক্তিশালী অন্তর্নির্মিত ধারণা আছে এমন জাভার মতো ভাষাগুলির জন্য, প্রতিটি ডিরেক্টরিতে সাধারণত একটি একক প্যাকেজ, লক্ষ্য এবং BUILD
ফাইল থাকে (প্যান্ট, ব্যাজেলের উপর ভিত্তি করে আরেকটি বিল্ড সিস্টেম, এটিকে 1:1:1 নিয়ম বলে)। দুর্বল প্যাকেজিং কনভেনশন সহ ভাষাগুলি প্রায়শই প্রতি BUILD
ফাইলের একাধিক লক্ষ্য নির্ধারণ করে।
ছোট বিল্ড টার্গেটের সুবিধাগুলি সত্যিই স্কেলে দেখাতে শুরু করে কারণ তারা দ্রুত বিতরণ করা বিল্ডের দিকে নিয়ে যায় এবং লক্ষ্যগুলি পুনর্নির্মাণের জন্য কম ঘন ঘন প্রয়োজন হয়। পরীক্ষার চিত্রে প্রবেশ করার পরে সুবিধাগুলি আরও বেশি বাধ্যতামূলক হয়ে ওঠে, কারণ সূক্ষ্ম-দানাযুক্ত লক্ষ্যগুলির অর্থ হল যে কোনও প্রদত্ত পরিবর্তন দ্বারা প্রভাবিত হতে পারে এমন পরীক্ষার একটি সীমিত উপসেট চালানোর ক্ষেত্রে বিল্ড সিস্টেমটি অনেক বেশি স্মার্ট হতে পারে। যেহেতু Google ছোট লক্ষ্যগুলি ব্যবহার করার পদ্ধতিগত সুবিধাগুলিতে বিশ্বাস করে, তাই আমরা বিকাশকারীদের বোঝা এড়াতে BUILD
ফাইলগুলি স্বয়ংক্রিয়ভাবে পরিচালনা করার জন্য টুলিং-এ বিনিয়োগ করে নেতিবাচক দিকগুলি হ্রাস করার জন্য কিছু অগ্রগতি করেছি৷
এই টুলগুলির মধ্যে কিছু, যেমন buildifier
এবং buildozer
, buildtools
ডিরেক্টরিতে Bazel- এর সাথে উপলব্ধ।
মডিউল দৃশ্যমানতা হ্রাস করা
Bazel এবং অন্যান্য বিল্ড সিস্টেম প্রতিটি লক্ষ্যকে একটি দৃশ্যমানতা নির্দিষ্ট করার অনুমতি দেয় - একটি বৈশিষ্ট্য যা নির্ধারণ করে যে অন্যান্য লক্ষ্যগুলি এটির উপর নির্ভর করতে পারে। একটি ব্যক্তিগত লক্ষ্য শুধুমাত্র তার নিজস্ব BUILD
ফাইলের মধ্যে উল্লেখ করা যেতে পারে। একটি লক্ষ্য BUILD
ফাইলগুলির একটি সুস্পষ্টভাবে সংজ্ঞায়িত তালিকার লক্ষ্যগুলিকে বা, সর্বজনীন দৃশ্যমানতার ক্ষেত্রে, কর্মক্ষেত্রে প্রতিটি লক্ষ্যকে বৃহত্তর দৃশ্যমানতা প্রদান করতে পারে।
বেশিরভাগ প্রোগ্রামিং ভাষার মতো, সাধারণত যতটা সম্ভব দৃশ্যমানতা হ্রাস করা ভাল। সাধারনত, Google-এর টিমগুলি শুধুমাত্র তখনই লক্ষ্যগুলিকে সর্বজনীন করবে যখন সেই লক্ষ্যগুলি Google-এর যেকোনো টিমের কাছে উপলব্ধ ব্যাপকভাবে ব্যবহৃত লাইব্রেরিগুলিকে উপস্থাপন করে৷ যে দলগুলির কোড ব্যবহার করার আগে অন্যদের তাদের সাথে সমন্বয় করতে হবে তারা তাদের লক্ষ্যের দৃশ্যমানতা হিসাবে গ্রাহক লক্ষ্যগুলির একটি অনুমোদিত তালিকা বজায় রাখবে। প্রতিটি দলের অভ্যন্তরীণ বাস্তবায়ন লক্ষ্যমাত্রা শুধুমাত্র দলের মালিকানাধীন ডিরেক্টরির মধ্যে সীমাবদ্ধ থাকবে এবং বেশিরভাগ BUILD
ফাইলের শুধুমাত্র একটি লক্ষ্য থাকবে যা ব্যক্তিগত নয়।
নির্ভরতা ব্যবস্থাপনা
মডিউলগুলি একে অপরকে উল্লেখ করতে সক্ষম হওয়া দরকার। একটি কোডবেসকে সূক্ষ্ম-দানাযুক্ত মডিউলগুলিতে ভাঙ্গার নেতিবাচক দিক হল যে আপনাকে সেই মডিউলগুলির মধ্যে নির্ভরতাগুলি পরিচালনা করতে হবে (যদিও সরঞ্জামগুলি এটিকে স্বয়ংক্রিয় করতে সহায়তা করতে পারে)। এই নির্ভরতা প্রকাশ করা সাধারণত একটি BUILD
ফাইলের বিষয়বস্তুর বেশিরভাগ অংশ হয়ে থাকে।
অভ্যন্তরীণ নির্ভরতা
সূক্ষ্ম দানাদার মডিউলে বিভক্ত একটি বড় প্রকল্পে, বেশিরভাগ নির্ভরতা অভ্যন্তরীণ হতে পারে; অর্থাৎ একই সোর্স রিপোজিটরিতে সংজ্ঞায়িত এবং নির্মিত অন্য টার্গেটে। অভ্যন্তরীণ নির্ভরতাগুলি বাহ্যিক নির্ভরতা থেকে আলাদা যে তারা বিল্ড চালানোর সময় একটি পূর্বনির্মাণ আর্টিফ্যাক্ট হিসাবে ডাউনলোড করার পরিবর্তে উত্স থেকে তৈরি করা হয়। এর মানে হল যে অভ্যন্তরীণ নির্ভরতাগুলির জন্য "সংস্করণ"-এর কোনও ধারণা নেই—একটি লক্ষ্য এবং এর সমস্ত অভ্যন্তরীণ নির্ভরতা সবসময় সংগ্রহস্থলে একই প্রতিশ্রুতি/সংশোধনে নির্মিত হয়। একটি সমস্যা যা অভ্যন্তরীণ নির্ভরতা সম্পর্কে সাবধানতার সাথে পরিচালনা করা উচিত তা হ'ল ট্রানজিটিভ নির্ভরতাকে কীভাবে চিকিত্সা করা যায় (চিত্র 1)। ধরুন লক্ষ্য A লক্ষ্য B এর উপর নির্ভর করে, যা একটি সাধারণ লাইব্রেরি লক্ষ্য C এর উপর নির্ভর করে। লক্ষ্য A কি লক্ষ্য C-তে সংজ্ঞায়িত ক্লাসগুলি ব্যবহার করতে সক্ষম হবে?
চিত্র 1 । ট্রানজিটিভ নির্ভরতা
যতদূর অন্তর্নিহিত সরঞ্জাম উদ্বিগ্ন, এটির সাথে কোন সমস্যা নেই; B এবং C উভয়ই লক্ষ্য A এর সাথে সংযুক্ত করা হবে যখন এটি নির্মিত হবে, তাই C-তে সংজ্ঞায়িত যেকোন চিহ্ন A-এর কাছে পরিচিত। ব্যাজেল বহু বছর ধরে এটির অনুমতি দিয়েছে, কিন্তু Google বৃদ্ধির সাথে সাথে আমরা সমস্যা দেখতে শুরু করেছি। ধরুন যে B-কে এমনভাবে রিফ্যাক্টর করা হয়েছে যে এটিকে আর C-এর উপর নির্ভর করার প্রয়োজন নেই। যদি C-এর উপর B-এর নির্ভরতা সরিয়ে দেওয়া হয়, A এবং B-এর উপর নির্ভরতার মাধ্যমে C ব্যবহার করা অন্য কোনো লক্ষ্য ভেঙ্গে যাবে। কার্যকরভাবে, একটি লক্ষ্যের নির্ভরতা তার পাবলিক চুক্তির অংশ হয়ে ওঠে এবং নিরাপদে পরিবর্তন করা যায় না। এর মানে হল যে Google-এ সময়ের সাথে সঞ্চিত নির্ভরতা এবং বিল্ডগুলি ধীর হতে শুরু করেছে।
Google অবশেষে Bazel-এ একটি "কঠোর ট্রানজিটিভ নির্ভরতা মোড" প্রবর্তন করে এই সমস্যার সমাধান করেছে। এই মোডে, Bazel সনাক্ত করে যে একটি টার্গেট সরাসরি তার উপর নির্ভর না করে একটি চিহ্ন উল্লেখ করার চেষ্টা করে এবং যদি তাই হয়, একটি ত্রুটি এবং একটি শেল কমান্ড যা স্বয়ংক্রিয়ভাবে নির্ভরতা সন্নিবেশ করতে ব্যবহার করা যেতে পারে তার সাথে ব্যর্থ হয়। Google-এর পুরো কোডবেস জুড়ে এই পরিবর্তনটি রোল করা এবং আমাদের লক্ষ লক্ষ বিল্ড টার্গেটগুলির প্রত্যেককে তাদের নির্ভরতাগুলি স্পষ্টভাবে তালিকাভুক্ত করার জন্য পুনর্বিন্যাস করা একটি বহু বছরের প্রচেষ্টা ছিল, তবে এটির মূল্য ছিল। আমাদের বিল্ডগুলি এখন আরও দ্রুততর হয়েছে কারণ লক্ষ্যগুলিতে কম অপ্রয়োজনীয় নির্ভরতা রয়েছে এবং প্রকৌশলীদের তাদের উপর নির্ভরশীল লক্ষ্যগুলি ভাঙার বিষয়ে চিন্তা না করে তাদের প্রয়োজনীয় নির্ভরতাগুলি সরিয়ে দেওয়ার ক্ষমতা দেওয়া হয়েছে।
যথারীতি, কঠোর ট্রানজিটিভ নির্ভরতা প্রয়োগ করা একটি বাণিজ্য বন্ধের সাথে জড়িত। এটি বিল্ড ফাইলগুলিকে আরও ভার্বোস করে তুলেছে, কারণ প্রায়শই ব্যবহৃত লাইব্রেরিগুলি এখন ঘটনাক্রমে টানার পরিবর্তে অনেক জায়গায় স্পষ্টভাবে তালিকাভুক্ত করা প্রয়োজন, এবং ইঞ্জিনিয়ারদের BUILD
ফাইলগুলিতে নির্ভরতা যুক্ত করার জন্য আরও বেশি প্রচেষ্টা ব্যয় করতে হবে। আমরা তখন থেকে এমন সরঞ্জামগুলি তৈরি করেছি যা স্বয়ংক্রিয়ভাবে অনেকগুলি অনুপস্থিত নির্ভরতা সনাক্ত করে এবং কোনও বিকাশকারীর হস্তক্ষেপ ছাড়াই একটি BUILD
ফাইলে যুক্ত করে এই পরিশ্রমকে হ্রাস করে৷ কিন্তু এই ধরনের সরঞ্জামগুলি ছাড়াও, আমরা কোডবেস স্কেলগুলির হিসাবে ট্রেড-অফটিকে যথেষ্ট মূল্যবান বলে মনে করেছি: BUILD
ফাইলে স্পষ্টভাবে একটি নির্ভরতা যুক্ত করা একটি এককালীন খরচ, তবে অন্তর্নিহিত ট্রানজিটিভ নির্ভরতাগুলির সাথে মোকাবিলা করা দীর্ঘ সময়ের জন্য চলমান সমস্যাগুলির কারণ হতে পারে যেমন বিল্ড টার্গেট বিদ্যমান। ব্যাজেল ডিফল্টরূপে জাভা কোডের উপর কঠোর ট্রানজিটিভ নির্ভরতা প্রয়োগ করে।
বাহ্যিক নির্ভরতা
যদি একটি নির্ভরতা অভ্যন্তরীণ না হয় তবে এটি অবশ্যই বাহ্যিক হতে হবে। বাহ্যিক নির্ভরতা হ'ল আর্টিফ্যাক্টগুলির উপর যা নির্মিত এবং বিল্ড সিস্টেমের বাইরে সংরক্ষণ করা হয়। নির্ভরতা সরাসরি একটি আর্টিফ্যাক্ট রিপোজিটরি থেকে আমদানি করা হয় (সাধারণত ইন্টারনেটের মাধ্যমে অ্যাক্সেস করা হয়) এবং উৎস থেকে তৈরি করার পরিবর্তে ব্যবহার করা হয়। বাহ্যিক এবং অভ্যন্তরীণ নির্ভরতার মধ্যে সবচেয়ে বড় পার্থক্য হল যে বাহ্যিক নির্ভরতাগুলির সংস্করণ রয়েছে এবং সেই সংস্করণগুলি প্রকল্পের উত্স কোড থেকে স্বাধীনভাবে বিদ্যমান।
স্বয়ংক্রিয় বনাম ম্যানুয়াল নির্ভরতা ব্যবস্থাপনা
বিল্ড সিস্টেমগুলি বাহ্যিক নির্ভরতার সংস্করণগুলিকে ম্যানুয়ালি বা স্বয়ংক্রিয়ভাবে পরিচালনা করার অনুমতি দিতে পারে। যখন ম্যানুয়ালি পরিচালিত হয়, বিল্ডফাইল স্পষ্টভাবে আর্টিফ্যাক্ট রিপোজিটরি থেকে যে সংস্করণটি ডাউনলোড করতে চায় তা তালিকাভুক্ত করে, প্রায়শই একটি শব্দার্থিক সংস্করণ স্ট্রিং যেমন 1.1.4
ব্যবহার করে। স্বয়ংক্রিয়ভাবে পরিচালিত হলে, উৎস ফাইল গ্রহণযোগ্য সংস্করণের একটি পরিসীমা নির্দিষ্ট করে এবং বিল্ড সিস্টেম সর্বদা সর্বশেষ সংস্করণ ডাউনলোড করে। উদাহরণস্বরূপ, গ্র্যাডল একটি নির্ভরতা সংস্করণকে "1.+" হিসাবে ঘোষণা করার অনুমতি দেয় যে নির্ভরতার যে কোনও ছোট বা প্যাচ সংস্করণ যতক্ষণ পর্যন্ত প্রধান সংস্করণ 1 হয় ততক্ষণ গ্রহণযোগ্য।
স্বয়ংক্রিয়ভাবে পরিচালিত নির্ভরতাগুলি ছোট প্রকল্পগুলির জন্য সুবিধাজনক হতে পারে, তবে এগুলি সাধারণত অতুচ্ছ আকারের প্রকল্পগুলিতে বিপর্যয়ের জন্য একটি রেসিপি বা যেগুলির উপর একাধিক প্রকৌশলী কাজ করছেন৷ স্বয়ংক্রিয়ভাবে পরিচালিত নির্ভরতাগুলির সমস্যা হল যে সংস্করণটি আপডেট করার সময় আপনার কোন নিয়ন্ত্রণ নেই। গ্যারান্টি দেওয়ার কোন উপায় নেই যে বাহ্যিক দলগুলি ব্রেকিং আপডেট করবে না (এমনকি যখন তারা শব্দার্থিক সংস্করণ ব্যবহার করার দাবি করে), তাই একটি বিল্ড যা একদিন কাজ করেছে তা পরের দিন ভেঙে যেতে পারে কোন সহজ উপায়ে কী পরিবর্তন হয়েছে তা সনাক্ত করার বা এটিকে ফিরিয়ে আনার কোন সহজ উপায় ছাড়াই একটি কর্মক্ষম রাষ্ট্রে। এমনকি বিল্ড ভেঙ্গে না গেলেও, সূক্ষ্ম আচরণ বা কর্মক্ষমতা পরিবর্তন হতে পারে যা ট্র্যাক করা অসম্ভব।
বিপরীতে, যেহেতু ম্যানুয়ালি পরিচালিত নির্ভরতাগুলির জন্য উত্স নিয়ন্ত্রণে একটি পরিবর্তন প্রয়োজন, সেগুলি সহজেই আবিষ্কার করা যায় এবং ফিরিয়ে আনা যায় এবং পুরানো নির্ভরতাগুলির সাথে তৈরি করার জন্য সংগ্রহস্থলের একটি পুরানো সংস্করণ পরীক্ষা করা সম্ভব। Bazel-এর জন্য প্রয়োজন যে সমস্ত নির্ভরতার সংস্করণ ম্যানুয়ালি নির্দিষ্ট করা হবে। এমনকি মাঝারি মাপকাঠিতে, ম্যানুয়াল সংস্করণ পরিচালনার ওভারহেড এটি যে স্থিতিশীলতা প্রদান করে তার জন্য এটি উপযুক্ত।
এক-সংস্করণ নিয়ম
একটি লাইব্রেরির বিভিন্ন সংস্করণ সাধারণত বিভিন্ন শিল্পকর্ম দ্বারা উপস্থাপিত হয়, তাই তত্ত্বগতভাবে একই বাহ্যিক নির্ভরতার বিভিন্ন সংস্করণগুলিকে বিভিন্ন নামে বিল্ড সিস্টেমে ঘোষণা করা যায় না এমন কোন কারণ নেই। এইভাবে, প্রতিটি লক্ষ্য নির্ভরতার কোন সংস্করণটি ব্যবহার করতে চায় তা চয়ন করতে পারে। এটি অনুশীলনে অনেক সমস্যার সৃষ্টি করে, তাই Google আমাদের কোডবেসে সমস্ত তৃতীয়-পক্ষ নির্ভরতার জন্য একটি কঠোর এক-সংস্করণ নিয়ম প্রয়োগ করে৷
একাধিক সংস্করণের অনুমতি দেওয়ার ক্ষেত্রে সবচেয়ে বড় সমস্যা হল হীরা নির্ভরতা সমস্যা। ধরুন যে লক্ষ্য A লক্ষ্য B এবং একটি বহিরাগত লাইব্রেরির v1 এর উপর নির্ভর করে। যদি লক্ষ্য B কে পরবর্তীতে একই বাহ্যিক লাইব্রেরির v2 এর উপর নির্ভরতা যোগ করার জন্য রিফ্যাক্টর করা হয়, তাহলে লক্ষ্য A ভেঙে যাবে কারণ এটি এখন একই লাইব্রেরির দুটি ভিন্ন সংস্করণের উপর নির্ভর করে। কার্যকরীভাবে, একাধিক সংস্করণ সহ যেকোন তৃতীয় পক্ষের লাইব্রেরিতে লক্ষ্য থেকে নতুন নির্ভরতা যোগ করা কখনই নিরাপদ নয়, কারণ সেই লক্ষ্যের ব্যবহারকারীদের মধ্যে যে কোনো একটি ভিন্ন সংস্করণের উপর নির্ভর করতে পারে। এক-সংস্করণ বিধি অনুসরণ করা এই বিরোধকে অসম্ভব করে তোলে-যদি একটি লক্ষ্য তৃতীয় পক্ষের লাইব্রেরির উপর নির্ভরতা যোগ করে, তবে বিদ্যমান কোনো নির্ভরতা ইতিমধ্যেই একই সংস্করণে থাকবে, যাতে তারা আনন্দের সাথে সহাবস্থান করতে পারে।
ট্রানজিটিভ বাহ্যিক নির্ভরতা
বাহ্যিক নির্ভরতার ট্রানজিটিভ নির্ভরতা মোকাবেলা করা বিশেষভাবে কঠিন হতে পারে। অনেক আর্টিফ্যাক্ট ভান্ডার যেমন মাভেন সেন্ট্রাল, আর্টিফ্যাক্টগুলিকে রিপোজিটরির অন্যান্য আর্টিফ্যাক্টের নির্দিষ্ট সংস্করণের উপর নির্ভরতা নির্দিষ্ট করার অনুমতি দেয়। Maven বা Gradle-এর মতো টুল তৈরি করুন প্রায়ই ডিফল্টরূপে প্রতিটি ট্রানজিটিভ নির্ভরতাকে পুনরাবৃত্তভাবে ডাউনলোড করে, যার অর্থ হল আপনার প্রোজেক্টে একটি একক নির্ভরতা যোগ করলে মোট কয়েক ডজন আর্টিফ্যাক্ট ডাউনলোড হতে পারে।
এটি খুবই সুবিধাজনক: একটি নতুন লাইব্রেরির উপর নির্ভরতা যোগ করার সময়, সেই লাইব্রেরির প্রতিটি ট্রানজিটিভ নির্ভরতা ট্র্যাক করতে এবং সেগুলিকে ম্যানুয়ালি যুক্ত করতে একটি বড় কষ্ট হবে৷ তবে একটি বিশাল নেতিবাচক দিকও রয়েছে: যেহেতু বিভিন্ন লাইব্রেরি একই তৃতীয় পক্ষের লাইব্রেরির বিভিন্ন সংস্করণের উপর নির্ভর করতে পারে, এই কৌশলটি অগত্যা এক-সংস্করণ নিয়ম লঙ্ঘন করে এবং ডায়মন্ড নির্ভরতা সমস্যাটির দিকে নিয়ে যায়। যদি আপনার লক্ষ্য দুটি বহিরাগত লাইব্রেরির উপর নির্ভর করে যা একই নির্ভরতার বিভিন্ন সংস্করণ ব্যবহার করে, তবে আপনি কোনটি পাবেন তা বলার অপেক্ষা রাখে না। এর মানে হল যে একটি বাহ্যিক নির্ভরতা আপডেট করা কোডবেস জুড়ে আপাতদৃষ্টিতে সম্পর্কহীন ব্যর্থতার কারণ হতে পারে যদি নতুন সংস্করণটি তার কিছু নির্ভরতাগুলির বিরোধপূর্ণ সংস্করণগুলিকে টানতে শুরু করে।
এই কারণে, Bazel স্বয়ংক্রিয়ভাবে ট্রানজিটিভ নির্ভরতা ডাউনলোড করে না। এবং, দুর্ভাগ্যবশত, কোন সিলভার বুলেট নেই—ব্যাজেলের বিকল্প হল এমন একটি গ্লোবাল ফাইলের প্রয়োজন যা রিপোজিটরির বাহ্যিক নির্ভরতাগুলির প্রতিটি একক তালিকা করে এবং সেই নির্ভরতার জন্য একটি সুস্পষ্ট সংস্করণ ব্যবহার করা হয়। সৌভাগ্যবশত, Bazel এমন সরঞ্জামগুলি সরবরাহ করে যা স্বয়ংক্রিয়ভাবে মাভেন শিল্পকর্মের একটি সেটের ট্রানজিটিভ নির্ভরতা সহ এমন একটি ফাইল তৈরি করতে সক্ষম। একটি প্রকল্পের জন্য প্রাথমিক WORKSPACE
ফাইল তৈরি করতে এই টুলটি একবার চালানো যেতে পারে এবং সেই ফাইলটি প্রতিটি নির্ভরতার সংস্করণ সামঞ্জস্য করতে ম্যানুয়ালি আপডেট করা যেতে পারে।
তবুও আবার, এখানে পছন্দটি সুবিধা এবং মাপযোগ্যতার মধ্যে একটি। ছোট প্রকল্পগুলি নিজেরাই ট্রানজিটিভ নির্ভরতা পরিচালনার বিষয়ে চিন্তা না করতে পছন্দ করতে পারে এবং স্বয়ংক্রিয় ট্রানজিটিভ নির্ভরতা ব্যবহার করে দূরে যেতে সক্ষম হতে পারে। এই কৌশলটি সংগঠন এবং কোডবেস বৃদ্ধির সাথে সাথে কম এবং কম আকর্ষণীয় হয়ে ওঠে এবং দ্বন্দ্ব এবং অপ্রত্যাশিত ফলাফলগুলি আরও ঘন ঘন হয়ে ওঠে। বৃহত্তর স্কেলে, স্বয়ংক্রিয় নির্ভরতা ব্যবস্থাপনার কারণে সৃষ্ট সমস্যাগুলি মোকাবেলা করার খরচের তুলনায় ম্যানুয়ালি নির্ভরতা পরিচালনার খরচ অনেক কম।
বাহ্যিক নির্ভরতা ব্যবহার করে ক্যাশিং বিল্ড ফলাফল
বাহ্যিক নির্ভরতাগুলি প্রায়শই তৃতীয় পক্ষ দ্বারা সরবরাহ করা হয় যা লাইব্রেরির স্থিতিশীল সংস্করণ প্রকাশ করে, সম্ভবত উত্স কোড প্রদান না করে। কিছু সংস্থা তাদের নিজস্ব কিছু কোডকে আর্টিফ্যাক্ট হিসাবে উপলব্ধ করতে বেছে নিতে পারে, কোডের অন্যান্য অংশগুলিকে অভ্যন্তরীণ নির্ভরতার পরিবর্তে তৃতীয় পক্ষ হিসাবে তাদের উপর নির্ভর করার অনুমতি দেয়। এটি তাত্ত্বিকভাবে বিল্ডের গতি বাড়াতে পারে যদি আর্টিফ্যাক্টগুলি তৈরি করতে ধীর কিন্তু ডাউনলোড করা দ্রুত হয়।
যাইহোক, এটি অনেক বেশি ওভারহেড এবং জটিলতারও পরিচয় দেয়: কাউকে সেই আর্টিফ্যাক্টগুলির প্রতিটি তৈরি করার জন্য এবং আর্টিফ্যাক্ট রিপোজিটরিতে আপলোড করার জন্য দায়ী হতে হবে এবং ক্লায়েন্টদের নিশ্চিত করতে হবে যে তারা সর্বশেষ সংস্করণের সাথে আপ টু ডেট থাকবে। ডিবাগিংও অনেক বেশি কঠিন হয়ে ওঠে কারণ সিস্টেমের বিভিন্ন অংশ সংগ্রহস্থলের বিভিন্ন পয়েন্ট থেকে তৈরি করা হবে, এবং উত্স ট্রিটির একটি সামঞ্জস্যপূর্ণ দৃশ্য আর নেই।
আর্টিফ্যাক্টগুলি তৈরি করতে দীর্ঘ সময় নেওয়ার সমস্যা সমাধানের একটি ভাল উপায় হল একটি বিল্ড সিস্টেম ব্যবহার করা যা রিমোট ক্যাশিং সমর্থন করে, যেমনটি আগে বর্ণিত হয়েছে। এই ধরনের একটি বিল্ড সিস্টেম প্রতিটি বিল্ড থেকে প্রাপ্ত আর্টিফ্যাক্টগুলিকে এমন একটি অবস্থানে সংরক্ষণ করে যা ইঞ্জিনিয়ারদের মধ্যে ভাগ করা হয়, তাই যদি একজন বিকাশকারী এমন একটি আর্টিফ্যাক্টের উপর নির্ভর করে যা সম্প্রতি অন্য কেউ তৈরি করেছে, তাহলে বিল্ড সিস্টেম এটি নির্মাণের পরিবর্তে স্বয়ংক্রিয়ভাবে ডাউনলোড করে। এটি আর্টিফ্যাক্টগুলির উপর সরাসরি নির্ভর করার সমস্ত কার্যকারিতা সুবিধা প্রদান করে এবং এখনও নিশ্চিত করে যে বিল্ডগুলি ততটা সামঞ্জস্যপূর্ণ যেন তারা সবসময় একই উত্স থেকে তৈরি করা হয়েছিল। এটি Google দ্বারা অভ্যন্তরীণভাবে ব্যবহৃত কৌশল, এবং Bazel একটি দূরবর্তী ক্যাশে ব্যবহার করার জন্য কনফিগার করা যেতে পারে।
বাহ্যিক নির্ভরতার নিরাপত্তা এবং নির্ভরযোগ্যতা
তৃতীয় পক্ষের উত্স থেকে শিল্পকর্মের উপর নির্ভর করা সহজাতভাবে ঝুঁকিপূর্ণ। যদি তৃতীয় পক্ষের উৎস (যেমন একটি আর্টিফ্যাক্ট সংগ্রহস্থল) কমে যায় তাহলে একটি প্রাপ্যতার ঝুঁকি রয়েছে, কারণ আপনার সম্পূর্ণ বিল্ডটি বন্ধ হয়ে যেতে পারে যদি এটি একটি বাহ্যিক নির্ভরতা ডাউনলোড করতে অক্ষম হয়। এছাড়াও একটি নিরাপত্তা ঝুঁকি রয়েছে: যদি কোনো আক্রমণকারী দ্বারা তৃতীয় পক্ষের সিস্টেমের সাথে আপস করা হয়, তাহলে আক্রমণকারী রেফারেন্সকৃত আর্টিফ্যাক্টটিকে তাদের নিজস্ব ডিজাইনের একটি দিয়ে প্রতিস্থাপন করতে পারে, যাতে তারা আপনার বিল্ডে নির্বিচারে কোড ইনজেকশন করতে পারে। উভয় সমস্যাই প্রশমিত করা যেতে পারে যেকোন আর্টিফ্যাক্টগুলিকে মিরর করে যা আপনি নিয়ন্ত্রণ করেন এমন সার্ভারগুলিতে আপনি নির্ভর করেন এবং আপনার বিল্ড সিস্টেমকে মাভেন সেন্ট্রালের মতো তৃতীয় পক্ষের আর্টিফ্যাক্ট রিপোজিটরিগুলি অ্যাক্সেস করা থেকে ব্লক করে৷ ট্রেড-অফ হল যে এই আয়নাগুলি বজায় রাখার জন্য প্রচেষ্টা এবং সংস্থান গ্রহণ করে, তাই প্রায়শই সেগুলি ব্যবহার করবেন কিনা তা প্রকল্পের স্কেলের উপর নির্ভর করে। প্রতিটি থার্ড-পার্টি আর্টিফ্যাক্টের হ্যাশকে সোর্স রিপোজিটরিতে নির্দিষ্ট করার প্রয়োজন করে সামান্য ওভারহেড দিয়ে নিরাপত্তা সমস্যাটি সম্পূর্ণরূপে প্রতিরোধ করা যেতে পারে, যার ফলে আর্টিফ্যাক্টের সাথে বিকৃত করা হলে বিল্ড ব্যর্থ হয়। আরেকটি বিকল্প যা সম্পূর্ণভাবে সমস্যাটিকে পাশ কাটিয়ে দেয় তা হল আপনার প্রকল্পের নির্ভরতা বিক্রেতা করা। যখন একটি প্রকল্প তার নির্ভরতা বিক্রেতা করে, এটি প্রকল্পের সোর্স কোডের পাশাপাশি উত্স নিয়ন্ত্রণে তাদের পরীক্ষা করে, হয় উত্স হিসাবে বা বাইনারি হিসাবে। এর কার্যকরী অর্থ হল যে প্রকল্পের সমস্ত বাহ্যিক নির্ভরতা অভ্যন্তরীণ নির্ভরতায় রূপান্তরিত হয়। Google এই পদ্ধতিটি অভ্যন্তরীণভাবে ব্যবহার করে, Google জুড়ে উল্লেখ করা প্রতিটি তৃতীয় পক্ষের লাইব্রেরি Google-এর উৎস গাছের মূলে একটি third_party
-পার্টি ডিরেক্টরিতে পরীক্ষা করে। যাইহোক, এটি শুধুমাত্র Google-এ কাজ করে কারণ Google-এর সোর্স কন্ট্রোল সিস্টেম একটি অত্যন্ত বড় মনোরেপো পরিচালনা করার জন্য কাস্টম তৈরি করা হয়েছে, তাই সব প্রতিষ্ঠানের জন্য ভেন্ডরিং একটি বিকল্প নাও হতে পারে।