DRY (Don't Repeat Yourself) হল একটি মৌলিক ডেভেলপমেন্ট নীতি যা অ্যান্ডি হান্ট এবং ডেভ থমাস “The Pragmatic Programmer” বইয়ে প্রণয়ন করেছেন। এটি বলে: সিস্টেমের জ্ঞানের প্রতিটি অংশের একটি একক, দ্ব্যর্থহীন, কর্তৃত্বপূর্ণ উপস্থাপনা থাকতে হবে। The Pragmatic Programmer, 20th Anniversary Edition অনুসারে, DRY লঙ্ঘন করলে একটি উপাদান পরিবর্তনের জন্য ডজনখানেক জায়গায় সম্পাদনার প্রয়োজন হয় এবং প্রতিটি বাদ পড়া খণ্ড বাগের উৎস হয়ে ওঠে।
মূল বিষয়
DRY (Don't Repeat Yourself) একটি ডেভেলপমেন্ট নীতি যা একটি প্রজেক্টে প্রতিটি জ্ঞান উপাদান ঠিক একবার সংরক্ষণের প্রয়োজন। এর অর্থ হল যেকোনো লজিক, কনফিগারেশন বা মেটাডেটা কেবল একটি জায়গায় বিদ্যমান থাকা উচিত।
শব্দটি অ্যান্ডি হান্ট এবং ডেভ থমাস 1999 সালে “The Pragmatic Programmer” বইয়ে প্রবর্তন করেন। লেখকরা DRY-কে সংজ্ঞায়িত করেছেন “জ্ঞানের প্রতিটি অংশের সিস্টেমের মধ্যে একটি একক, দ্ব্যর্থহীন, কর্তৃত্বপূর্ণ উপস্থাপনা থাকতে হবে।” DRY-এর বিপরীত হল WET (Write Everything Twice) পদ্ধতি, যেখানে ডুপ্লিকেশন স্বাভাবিক বলে বিবেচিত হয়।
University of California, Davis (2019)-এর একটি গবেষণা অনুসারে, উচ্চ মাত্রার কোড ডুপ্লিকেশনযুক্ত প্রজেক্টগুলি বাগ ঠিক করতে 42% বেশি সময় ব্যয় করে। কারণ হল ডেভেলপারদের একই খণ্ডের সমস্ত কপি খুঁজে বের করতে এবং পরিবর্তন করতে হয় — এবং ম্যানুয়াল অনুসন্ধানে অনিবার্যভাবে ভুল হয়।
কোড গুণমানের মানদণ্ড হিসেবে DRY প্রয়োগ করুন। যদি আপনি দেখেন যে একই প্যাটার্ন প্রজেক্টে তিনবার দেখা যাচ্ছে — চতুর্থ পুনরাবৃত্তির অপেক্ষা না করে এটিকে অ্যাবস্ট্রাকশনে নিষ্কাশন করুন।
SOLID-এর একক দায়িত্ব নীতি (SRP) বলে যে একটি ক্লাসের পরিবর্তনের একটাই কারণ থাকা উচিত। DRY আরও বিস্তৃত: এটি কেবল ক্লাস নয়, ডেটা, কনফিগারেশন, ডকুমেন্টেশন এবং এমনকি ব্যবসায়িক নিয়মও কভার করে। SRP দায়িত্বের সীমানা নিয়ে; DRY কপি করা প্রতিরোধ নিয়ে।
মোবাইল ডেভেলপমেন্টে, এই পার্থক্য বিশেষভাবে লক্ষণীয়। যদি একই ব্যবসায়িক নিয়ম (কর গণনা, তারিখ ফর্ম্যাটিং) প্রজেক্টের Android এবং iOS উভয় অংশে পুনরাবৃত্তি হয় — এটি DRY লঙ্ঘন, যদিও SRP আনুষ্ঠানিকভাবে প্রতিটি প্ল্যাটফর্মের মধ্যে পালন করা হয়। সমাধান হল সাধারণ লজিক একটি শেয়ার্ড মডিউলে (KMM, C++) নিষ্কাশন করা।
Google Android Architecture Guidelines (2023) রিপোর্ট অনুসারে, ব্যবসায়িক লজিকের জন্য শেয়ার্ড মডিউল ব্যবহারকারী দলগুলি প্ল্যাটফর্ম জুড়ে লজিক ডুপ্লিকেট করা প্রজেক্টের তুলনায় প্রয়োজনীয়তা পরিবর্তনের সময় বাগের সংখ্যা 37% কমায়।
ডুপ্লিকেশন মোবাইল প্রজেক্টে প্রযুক্তিগত ঋণের প্রধান উৎস। প্রতিটি কোড কপি একটি লুকানো নির্ভরতা তৈরি করে: আচরণ পরিবর্তন করতে, আপনাকে সমস্ত কপি খুঁজে বের করতে এবং আপডেট করতে হবে। একটি বাদ দিলেই বাগ।
একটি ক্লাসিক পরিস্থিতি বিবেচনা করুন: একটি Android অ্যাপে, তিনটি ভিন্ন Activity-তে তারিখ ফর্ম্যাটিং করা হয়। নতুন ফর্ম্যাটে (যেমন ISO 8601) স্যুইচ করার সময়, ডেভেলপার দুটি ফাইল ঠিক করে, তৃতীয়টি ভুলে যায় — এবং ব্যবহারকারী পুরানো ফর্ম্যাটে তারিখ দেখে। অ্যাপ রেটিং কমে যায় এবং বাগ খুঁজতে দ্বিগুণ সময় লাগে।
Google Research (2020)-এর একটি গবেষণায় দেখা গেছে যে মোবাইল অ্যাপ্লিকেশনের 68% গুরুতর বাগ ডুপ্লিকেট কোডে অসমকালীন পরিবর্তনের সাথে সম্পর্কিত। তাছাড়া, প্রোডাকশনে এই ধরনের বাগ ঠিক করতে কোড শুরু থেকে একীভূত থাকলে তার চেয়ে 4.5 গুণ বেশি খরচ হয়।
স্ট্যাটিক বিশ্লেষক (Detekt, SwiftLint) নিয়ম সহ ব্যবহার করুন যা copy-paste সনাক্ত করে। CI কনফিগার করুন যাতে N লাইনের বেশি ডুপ্লিকেশনযুক্ত পুল রিকোয়েস্ট ন্যায্যতা ছাড়া পর্যালোচনা পাস না করে।
একটি সাধারণ অ্যান্টি-প্যাটার্ন হল সামান্য পরিবর্তন সহ RecyclerView অ্যাডাপ্টার কপি করা। একটি সার্বজনীন অ্যাডাপ্টারের পরিবর্তে, ডেভেলপাররা প্রতিটি স্ক্রিনের জন্য আলাদা ক্লাস তৈরি করে। একটি সাধারণ বেস ক্লাস নিষ্কাশন করে রিফ্যাক্টরিং কোড 30–50% কমিয়ে দেয়।
// ডুপ্লিকেশন: দুটি পৃথক অ্যাডাপ্টার
class UserAdapter {
fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
fun bind(item: Product) { /* ... */ }
}
// DRY রিফ্যাক্টরিং: সাধারণ বেস ক্লাস
abstract class BaseAdapter<T> {
abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }
প্রথম উদাহরণে, প্রতিটি অ্যাডাপ্টার স্ক্র্যাচ থেকে bind মেকানিজম পুনরায় বাস্তবায়ন করে। নতুন লজিক (অ্যানালিটিক্স, লগিং) যোগ করার সময়, প্রতিটি ফাইল পরিবর্তন করতে হবে। একটি বেস ক্লাস এই ডুপ্লিকেশন দূর করে: সাধারণ লজিক এক জায়গায় থাকে, নির্দিষ্ট লজিক সাবক্লাসে।
iOS প্রজেক্টে, URLSession কনফিগারেশন — হেডার, টাইমআউট, ত্রুটি ব্যবস্থাপনা — প্রায়শই ডুপ্লিকেট করা হয়। প্রতিটি পরিষেবা পুনরাবৃত্ত সেটিংস সহ নিজস্ব সেশন তৈরি করে।
// ডুপ্লিকেশন: প্রতিটি পরিষেবা নতুন করে সেশন কনফিগার করে
class UserService {
let session = URLSession(configuration: {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return cfg
}())
}
// DRY: একীভূত সেশন ফ্যাক্টরি
struct NetworkConfig {
static var session: URLSession {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return URLSession(configuration: cfg)
}
}
কনফিগারেশন একটি একীভূত NetworkConfig-এ নিষ্কাশন করা নিশ্চিত করে যে সমস্ত পরিষেবা একই হেডার এবং টাইমআউট ব্যবহার করে। এক জায়গায় পরিবর্তন স্বয়ংক্রিয়ভাবে সমস্ত অনুরোধে প্রযোজ্য হয় — এটি API কী বা প্রোটোকল সংস্করণ পরিবর্তনের সময় ত্রুটির ঝুঁকি হ্রাস করে।
ইনহেরিটেন্স ডুপ্লিকেশন দূর করার একটি প্রাকৃতিক উপায়: সাধারণ লজিক একটি বেস ক্লাসে স্থানান্তরিত হয় এবং নির্দিষ্ট লজিক সাবক্লাসে। তবে মোবাইল ডেভেলপমেন্টে, ইনহেরিটেন্সের অত্যধিক ব্যবহার কঠোর শ্রেণিবিন্যাস তৈরি করে যা বজায় রাখা কঠিন। কম্পোজিশন (ডিপেন্ডেন্সি ইনজেকশন) একটি আরও নমনীয় বিকল্প।
Google I/O 2023: Modern Android Architecture-এর একটি বিশ্লেষণে দেখা গেছে যে 76% Google টিম ডুপ্লিকেশন দূর করতে ইনহেরিটেন্সের চেয়ে কম্পোজিশন পছন্দ করে। ডজনখানেক মেথড সহ BaseViewModel-এর পরিবর্তে, প্রতিটি ব্যবসায়িক অপারেশনের জন্য আলাদা UseCase ক্লাস নিষ্কাশন এবং প্রয়োজনীয় স্থানে ইনজেক্ট করার পরামর্শ দেওয়া হয়।
“is-a” সম্পর্ক ছাড়া সব ক্ষেত্রে কম্পোজিশন বেছে নিন। যদি ক্লাস A, ক্লাস B-এর বিশেষায়ন হয় — ইনহেরিটেন্স উপযুক্ত। যদি A কেবল B-এর কার্যকারিতা ব্যবহার করে — কম্পোজিশন ব্যবহার করুন।
ইউটিলিটি ক্লাস (Extensions, Helpers) ডুপ্লিকেশন এড়ানোর সবচেয়ে সহজ উপায়। সাধারণ প্রার্থী: তারিখ ফর্ম্যাটিং, ইমেল বৈধতা, ইউনিট রূপান্তর, SharedPreferences/UserDefaults নিয়ে কাজ করা।
// DRY: একীভূত তারিখ ফর্ম্যাটিং ফাংশন
fun Date.toDisplayFormat(): String {
val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
return sdf.format(this)
}
// অ্যাপ্লিকেশনের যেকোনো জায়গায় ব্যবহার
textView.text = Date().toDisplayFormat()
Date.toDisplayFormat() এক্সটেনশন একবার ঘোষণা করা হয় এবং পুরো প্রজেক্ট জুড়ে উপলব্ধ। যদি ফর্ম্যাটটি “dd.MM.yyyy” থেকে “yyyy-MM-dd”-এ পরিবর্তনের প্রয়োজন হয় — সংশোধন একটি ফাইলে, প্রতিটি Activity বা Fragment-এ নয় যেখানে ফর্ম্যাটিং হয়। এটি DRY-এর সারমর্ম।
মাল্টি-মডিউল Android প্রজেক্ট প্রায়ই প্রতিটি build.gradle-এ ডিপেন্ডেন্সি সংস্করণ ডুপ্লিকেট করে। সমাধান হল একটি ভার্সন ক্যাটালগ (libs.versions.toml) যা সমস্ত সংস্করণ একটি ফাইলে কেন্দ্রীভূত করে।
Android ডেভেলপার ডকুমেন্টেশন (2024) অনুসারে, ভার্সন ক্যাটালগে মাইগ্রেট করলে ডিপেন্ডেন্সি দ্বন্দ্ব 52% হ্রাস পায় এবং সম্পাদনার একক পয়েন্টের মাধ্যমে বিল্ড গতি বাড়ে।
প্রজেক্ট শুরুতে বা প্রথম মডিউল পুনর্গঠনের সময় ভার্সন ক্যাটালগ প্রয়োগ করুন। যদি প্রজেক্টে ইতিমধ্যে ডুপ্লিকেশন থাকে — মাইগ্রেশনের জন্য একটি দিন আলাদা রাখুন: এটি পরবর্তী লাইব্রেরি আপডেটে লাভজনক হবে।
অকাল অ্যাবস্ট্রাকশন শিক্ষানবিশদের সবচেয়ে সাধারণ ভুল। একজন ডেভেলপার কোডের দুটি অনুরূপ লাইন দেখে এবং সঙ্গে সঙ্গে সেগুলি একটি সাধারণ ফাংশনে নিষ্কাশন করে। এক মাস পরে, প্রয়োজনীয়তা পরিবর্তিত হয় এবং সাধারণ ফাংশনটি প্যারামিটার এবং ফ্ল্যাগে ভরে যায় — মূল ডুপ্লিকেশনের চেয়ে জটিল। Rule of Three ঠিক এই থেকেই রক্ষা করে: এমন কিছু অ্যাবস্ট্রাক্ট করবেন না যা কেবল এক বা দুবার দেখা গেছে।
মার্টিন ফাউলার তার বই Refactoring (2019)-এ পরামর্শ দেন: “কোড ডুপ্লিকেশন সবসময় খারাপ নয়। জ্ঞানের ডুপ্লিকেশন খারাপ।” যদি দুটি লাইন কাকতালীয়ভাবে মিলে কিন্তু ভিন্ন ধারণা প্রকাশ করে — এটি ডুপ্লিকেশন নয়, এটি কাকতালীয়। Rule of Three আকস্মিক কাকতালীয়কে পদ্ধতিগত ডুপ্লিকেশন থেকে আলাদা করতে সাহায্য করে।
অ্যাবস্ট্রাক্ট করার আগে, শব্দার্থ মূল্যায়ন করুন। একই অর্থ সহ কপি করা কোড — DRY লঙ্ঘন। ভিন্ন অর্থ কিন্তু অনুরূপ সিনট্যাক্স সহ কোড — কাকতালীয় যার অ্যাবস্ট্রাকশনের প্রয়োজন নেই।
অতিরিক্ত প্যারামিটারাইজেশন ঘটে যখন একটি ফাংশন ফ্ল্যাগ এবং বুলিয়ান প্যারামিটারের মাধ্যমে সমস্ত সম্ভাব্য পরিস্থিতি কভার করার চেষ্টা করে। এই ধরনের কোড SRP লঙ্ঘন করে এবং অপাঠ্য হয়ে যায়। লক্ষণ: যদি একটি ফাংশনে দুটির বেশি বুলিয়ান প্যারামিটার থাকে — এটি অতিরিক্ত অ্যাবস্ট্রাকশনের কোড স্মেল।
useCache: Boolean ফ্ল্যাগ সহ একটি ফাংশনের পরিবর্তে, স্পষ্ট নাম সহ দুটি পৃথক ফাংশন তৈরি করা ভাল: fetchFromNetwork() এবং fetchFromCache()। স্পষ্টতা শুষ্ক অ্যাবস্ট্রাকশনের চেয়ে গুরুত্বপূর্ণ — এটি KISS নীতির সাথে সামঞ্জস্যপূর্ণ।
যখন একটি ফাংশন 3+ বুলিয়ান প্যারামিটারে পৌঁছায় তখন অতিরিক্ত প্যারামিটারাইজেশন রিফ্যাক্টর করুন। স্পষ্ট নাম সহ পৃথক ফাংশনে বিভক্ত করুন — প্রতিটি কল স্ব-ডকুমেন্টিং হয়ে যাবে।
সচরাচর জিজ্ঞাসা
DRY (Don't Repeat Yourself) একটি নীতি যা প্রতিটি লজিক্যাল ইউনিট একটি একক জায়গায় সংরক্ষণের প্রয়োজন। যদি একই কোড প্রজেক্টের একাধিক অংশে দেখা দেয় — এটি DRY লঙ্ঘন। সমাধান: পুনরাবৃত্ত লজিক একটি পৃথক ফাংশন, ক্লাস বা মডিউলে নিষ্কাশন করুন।
WET (Write Everything Twice) DRY-এর বিপরীত, যেখানে ডুপ্লিকেশন গ্রহণযোগ্য বলে বিবেচিত হয়। WET প্রজেক্টে, একই কোড খণ্ড পাঁচটি কপিতে বিদ্যমান থাকতে পারে এবং প্রয়োজনীয়তা পরিবর্তিত হলে ডেভেলপার প্রতিটি কপি আলাদাভাবে ঠিক করে। WET বাগের ঝুঁকি বাড়ায় এবং উন্নয়ন ধীর করে দেয়।
DRY ক্ষতিকর হয় যখন এটি অকাল অ্যাবস্ট্রাকশনের দিকে নিয়ে যায়: যখন দুটি অনুরূপ কিন্তু শব্দার্থগতভাবে ভিন্ন কোড বিভাগ জোর করে একটি ফাংশনে একীভূত করা হয়। এটি জটিল, প্যারামিটার-ওভারলোডেড কোড তৈরি করে। Rule of Three এই ভুল এড়াতে সাহায্য করে: তৃতীয় পুনরাবৃত্তির পরেই অ্যাবস্ট্রাক্ট করুন।
Android-এ, DRY ভার্সন ক্যাটালগ (libs.versions.toml), অ্যাডাপ্টারের জন্য সাধারণ বেস ক্লাস, ViewModel ফ্যাক্টরি এবং ইউটিলিটি Kotlin এক্সটেনশনের মাধ্যমে প্রয়োগ করা হয়। ব্যবসায়িক লজিক শেয়ার্ড মডিউলে (KMM) নিষ্কাশন এবং findViewById ডুপ্লিকেশন দূর করতে View Binding ব্যবহার করার পরামর্শ দেওয়া হয়।
iOS-এ, DRY ডিফল্ট ইমপ্লিমেন্টেশন সহ প্রোটোকল, শেয়ার্ড নেটওয়ার্ক কনফিগারেশন (NetworkConfig), UICollectionView সেল ফ্যাক্টরি এবং সাধারণ ব্যবসায়িক লজিক সহ SPM প্যাকেজের মাধ্যমে অর্জিত হয়। স্ট্যান্ডার্ড টাইপের (Date, String, URL) এক্সটেনশন ফর্ম্যাটিং এবং বৈধতায় ডুপ্লিকেশন হ্রাস করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন