ডাইজস্ট্রা ও স্ট্রাকচার্ড প্রোগ্রামিং: শৃঙ্খলা যা স্কেল করে
Edsger Dijkstra-র স্ট্রাকচার্ড প্রোগ্রামিং ধারণাগুলো ব্যাখ্যা করে কেন শৃঙ্খলাবদ্ধ, সরল কোড টিম, ফিচার ও সিস্টেম বড় হলেও সঠিক ও রক্ষণযোগ্য থাকে।

কেন Dijkstra এখনও গুরুত্বপূর্ণ যখন সফটওয়্যার বড় হয়
সফটওয়্যার বিরলভাবেই এ জন্য ব্যর্থ হয় যে তা লেখা সম্ভব নয়। এটি ব্যর্থ হয় কারণ, এক বছর পর, আর কেউ সেটি নিরাপদে পরিবর্তন করতে পারে না।
কোডবেস বাড়ার সাথে সাথে প্রতিটি “ছোট” টুইক তরঙ্গ তৈরি করতে শুরু করে: একটি বাগ দূরবর্তী ফিচার ভাঙে, একটি নতুন চাহিদা রিরাইট বাধ্য করে, এবং একটি সরল রিফ্যাক্টর এক সপ্তাহের সতর্ক সমন্বয়ে পরিণত হয়। কঠিন অংশটি কোড যোগ করা নয়—কঠিন অংশটি হল পারিপার্শ্বিক সবকিছু বদলে গেলেও আচরণটি পূর্বানুমেয় রাখা।
প্রতিশ্রুতি: সঠিকতা ও সরলতা দীর্ঘমেয়াদী খরচ কমায়
Edsger Dijkstra যুক্তি দিয়েছিলেন যে সঠিকতা এবং সরলতা প্রথম শ্রেণীর লক্ষ্য হওয়া উচিত, সৌন্দর্য বস্তু নয়। ফলাফল শুধু তাত্ত্বিক নয়। যখন একটি সিস্টেম বুঝতে সহজ হয়, টিমগুলো যেমন ফায়ারফাইটিংয়ে কম সময় ব্যয় করে তেমনি আরও বেশি তৈরি করে।
- সঠিকতা ভুলের খরচ কমায়: কম ইনসিডেন্ট, কম রিগ্রেশন, কম “এটা স্পর্শ করো না” কোড।
- সরলতা পরিবর্তনের খরচ কমায়: কম লুকানো অনুমান, কম বিশেষ কেস, রিভিউয়ের সময় কম অপ্রত্যাশিত আচরণ।
“স্কেল” আসলে কী বোঝায়
যখন মানুষ বলে সফটওয়্যারকে “স্কেল” করা লাগবে, তারা প্রায়ই পারফরম্যান্সই বুঝে। Dijkstra-র পয়েন্ট আলাদা: জটিলতাও স্কেল করে।
স্কেল দেখতে পাওয়া যায়:
- আরও ফিচার: নতুন ফ্লো, এজ কেস, এবং ব্যবহারকারীর প্রত্যাশা।
- আরও মানুষ: হ্যান্ডঅফ, বিভিন্ন স্টাইল, এবং ভিন্ন প্রসঙ্গ।
- আরও ইন্টিগ্রেশন: এক্সটার্নাল API, ডেটা সোর্স, এবং ব্যর্থতার মোড।
- আরও সময়: লেগ্যাসি সিদ্ধান্ত, বদলানো চাহিদা, আংশিক রিরাইট।
মূল ধারণা: স্ট্রাকচার আচরণকে পূর্বানুমেয় করে
Structured programming নিজেই কড়াকড়ি করা নয়। এটা কন্ট্রোল ফ্লো ও ডিকমপোজিশন বাছাই করার ব্যাপার যাতে দুটি প্রশ্ন সহজে জবাবযোগ্য হয়:
- “পরের কী হবে?”
- “কোন শর্তে?”
যখন আচরণ পূর্বানুমেয়, পরিবর্তন রুটিনের মত হয় বিপজ্জনক না। এজন্য Dijkstra এখনো প্রাসঙ্গিক: তাঁর শৃঙ্খলা বাড়তে থাকা সফটওয়্যারের প্রকৃত ব্যাঘাত—তথ্যটিকে ভালভাবে বোঝার উপরে লক্ষ্য রাখে।
Edsger Dijkstra ও তাঁর লক্ষ্য—একটি সহজ পরিচিতি
Edsger W. Dijkstra (1930–2002) ছিলেন ডাচ কম্পিউটার বিজ্ঞানী যিনি নির্ভরযোগ্য সফটওয়্যার তৈরির দৃষ্টিভঙ্গি গঠন করতে সাহায্য করেছেন। তিনি প্রাথমিক অপারেটিং সিস্টেমে কাজ করেছেন, অ্যালগরিদমে অবদান রেখেছেন (তার নামবাহী শর্টেস্ট-পাথ অ্যালগরিদমসহ), এবং—দৈনন্দিন ডেভেলপারদের জন্য সবচেয়ে গুরুত্বপূর্ণ—এমন ধারণা প্রচার করেছেন যে প্রোগ্রামিংকে এমন কিছু করা উচিত যা আমরা যুক্তি করে বুঝতে পারি, শুধুমাত্র সবসময় চেষ্টা করে কাজ করলেই নয়।
তাঁর মূল ফোকাস: “it runs on my machine”-এর বদলে যুক্তি করা
Dijkstra কমই চিন্তা করতেন যে প্রোগ্রাম কয়েকটি উদাহরণে সঠিক আউটপুট দেয় কি না; তিনি বেশি ভাবেন আমরা কি বর্ণনা করতে পারি কেন এটি সঠিক সেই গুরুত্বপূর্ণ কেসগুলোর জন্য।
আপনি যদি বলতে পারেন একটি কোড অংশ কি করা উচিত, তবে আপনাকে ধাপে ধাপে যুক্তি দেখাতে সক্ষম হওয়া উচিত যে এটি সেটি করেনি। সেই মানসিকতা স্বাভাবিকভাবেই এমন কোড দেয় যা অনুসরণ করতে সহজ, রিভিউ করতে সহজ, এবং নায়কীয় ডিবাগিংয়ের উপর কম নির্ভরশীল।
কেন তিনি কখনো বেআকায়ক মনে হতে পারেন—এবং কেন সেটি কাজে লাগে
Dijkstra-র লেখাগুলো মাঝে মাঝে uncompromising শোনায়। তিনি “চতুর” ট্রিক, অনিয়মিত কন্ট্রোল ফ্লো, এবং এমন কডিং অভ্যাসকে নিন্দা করেছিলেন যা reasoning কঠিন করে। কড়াকড়ি স্টাইল পুলিশের জন্য নয়; এটি অস্পষ্টতা কমানোর জন্য। যখন কোডের অর্থ পরিষ্কার, তখন উদ্দেশ্য নিয়ে তর্ক করার সময় কম লাগে এবং আচরণ যাচাইতে সময় বেশি লাগে।
“Structured programming” কী অর্থে (উচ্চ-স্তরে)
Structured programming হল প্রোগ্রামগুলোকে কয়েকটি পরিষ্কার কন্ট্রোল স্ট্রাকচার থেকে তৈরি করার প্র্যাকটিস—sequence, selection (if/else), এবং iteration (loops)—পরস্পর জটিল জাম্পের উপর নির্ভর না করে। লক্ষ্য সরল: প্রোগ্রামের পথকে বোধগম্য করা যাতে আপনি তা আত্মবিশ্বাস নিয়ে ব্যাখ্যা, রক্ষণাবেক্ষণ, এবং পরিবর্তন করতে পারেন।
Correctness: লুকানো ফিচার যা ব্যবহারকারীরা ভরসা করে
মানের কথা বলা হয় প্রায়ই “দ্রুত”, “সুন্দর”, বা “ফিচার-সমৃদ্ধ” হিসেবে। ব্যবহারকারীরা correctness-কে আলাদা ভাবে অনুভব করে: এটি হল নিঃশব্দ আত্মবিশ্বাস যে অ্যাপ তাদের অবাক করবে না। যখন correctness থাকে, কেউ লক্ষ্য করে না। যখন নেই, সবকিছু ততক্ষণ পর্যন্ত গুরুত্ব হারায় যতক্ষণ না এটি ঠিক হয়।
“এখন কাজ করে” বনাম “এটি কাজ চালিয়ে রাখে”
“এখন কাজ করে” সাধারণত মানে আপনি কয়েকটি পাথ চেষ্টা করেছেন এবং প্রত্যাশিত ফল পেয়েছেন। “এটি কাজ চালিয়ে রাখে” মানে এটি সময়, এজ কেস, এবং পরিবর্তনের পরও অভিপ্রেতভাবে আচরণ করে—রিফ্যাক্টরের পরে, নতুন ইন্টিগ্রেশনের পরে, উচ্চ ট্রাফিক বা নতুন টিম মেম্বারদের স্পর্শ করার পরও।
একটি ফিচার “এখন কাজ করে” বলে মনে হতে পারে কিন্তু তা ভঙ্গুর:
- এটি ধরেই নেয় ইনপুট সবসময় পরিষ্কার থাকবে।
- এটি ধরে নেয় একটি নেটওয়ার্ক কল সবসময় দ্রুত প্রত্যাবর্তন করবে।
- এটি কেবল হ্যাপি-পাথ কভার করে এমন টেস্ট পাস করে।
Correctness হল এই লুকানো অনুমানগুলো সরানো—অথবা সেগুলোকে স্পষ্ট করা।
কিভাবে ছোট বাগ বড় সিস্টেমে গুণে বাড়ে
একটি ক্ষুদ্র বাগ বিরলভাবেই ছোট থাকে যখন সফটওয়্যার বড় হয়। একটি ভুল স্টেট, একটি অফ-বাই-ওয়ান বাউন্ডারি, বা একটি অস্পষ্ট এরর-হ্যান্ডলিং নিয়ম নতুন মডিউলে কপি হয়, অন্য সার্ভিস দ্বারা মোড়া হয়, ক্যাশ করা হয়, রিট্রাই করা হয়, বা “ওয়ার্কঅ্যারাউন্ড” হিসেবে রাখা হয়। সময়ের সাথে টিমগুলো জিজ্ঞেস করা বন্ধ করে দেয় “কী সত্য?” এবং পরিবর্তে জিজ্ঞেস করে “সাধারণত কী ঘটে?” তখনই ইনসিডেন্ট রেসপন্স আরকিওলজির মত হয়ে ওঠে।
গুণবিধির কারণ হল ডেপেনডেন্সি: একটি ক্ষুদ্র অমিল অনেক ডাউনস্ট্রিম অমিলকে প্রজন্ম করে, প্রত্যেকটিরই আংশিক ফিক্স থাকে।
স্পষ্টতা একটি correctness টুল (শুধু স্টাইল নয়)
পরিষ্কার কোড correctness বাড়ায় কারণ এটি যোগাযোগ উন্নত করে:
- কোড রিভিউ: যখন উদ্দেশ্য স্পষ্ট, বাস্তব ইস্যুগুলো সহজে ধরা পড়ে।
- অনবোর্ডিং: নিয়ম সহজে পাঠ্য হলে জ্ঞানের বাহুল্য কমে।
- ইনসিডেন্ট: কন্ট্রোল ফ্লো ও ব্যর্থতার মোড ট্রেস করতে সহজ হলে দ্রুত সমাধান হয়।
প্রোডাক্ট টিমগুলোর জন্য একটি প্র্যাকটিক্যাল ডেফিনিশন
Correctness মানে: যে ইনপুট ও পরিস্থিতি আমরা সমর্থন করার কথা বলি, সেগুলোর জন্য সিস্টেম ধারাবাহিকভাবে আমরা প্রতিশ্রুতি দেয়া আউটকাম তৈরি করে—এবং যখন তা করতে পারে না তখন ব্যর্থতা পূর্বানুমেয়, ব্যাখ্যাযোগ্যভাবে ঘটে।
কৌশল হিসেবে সরলতা, স্টাইল পছন্দ নয়
সরলতা কোডকে “কিউট” বা কেবল লাইন কমানো নয়। এটি আচরণকে সহজে পূর্বানুমেয়, ব্যাখ্যা যোগ্য, এবং ভয় ছাড়াই পরিবর্তনযোগ্য করে তোলা। Dijkstra সরলতাকে মূল্য দেন কারণ এটি প্রোগ্রামগুলি সম্পর্কে reasoning উন্নত করে—বিশেষত যখন কোডবেস ও টিম বড় হয়।
সরলতা কী (এবং কী না)
সরল কোড এক সময়ে কম আইডিয়া চালায়: পরিষ্কার ডেটা ফ্লো, পরিষ্কার কন্ট্রোল ফ্লো, এবং পরিষ্কার দায়িত্ব। এটি পাঠকের মাথায় একসাথে অনেক বিকল্প পথ সিমুলেট করতে বাধ্য করে না।
সরলতা নয়:
- যে কোনও মূল্যায়ে কম লাইন
- “কিউট” ট্রিক, ঘন ওয়ান-লাইনার, বা ভারী অ্যাবস্ট্র্যাকশন
- বাঁধন হারিয়ে নমনীয় দেখানোর জন্য গঠন এড়ানো
ঘটিত জটিলতা: আপনি যা ইচ্ছে করে যোগ করেননি
অনেক সিস্টেম কঠিন হয়ে যায় না কারণ ডোমেইন স্বতঃস্ফূর্তভাবে জটিল—বরং কারণ আমরা ঘটিত (accidental) জটিলতা যোগ করি: এমন ফ্ল্যাগগুলো যা অপ্রত্যাশিতভাবে ইন্টারঅ্যাক্ট করে, বিশেষ-কেস প্যাচ যা কখনো মুছে যায় না, এবং স্তরগুলো যা মূলত আগে নেওয়া সিদ্ধান্তকে ওয়ার্কঅ্যারাউন্ড করার জন্য আছে।
প্রত্যেক অতিরিক্ত ব্যতিক্রম বোঝার উপর একটি ট্যাক্স আরোপ করে। খরচ পরে দেখা দেয়, যখন কেউ একটি বাগ ঠিক করতে চায় এবং আবিষ্কার করে এক অঞ্চলে পরিবর্তন করলে অন্য কয়েকটি জায়গায় সূক্ষ্মভাবে ভাঙে।
সরল ডিজাইন নায়কদের প্রয়োজন কমায়
যখন ডিজাইন সরল, অগ্রগতি হয় নিয়মিত কাজ থেকে: রিভিউযোগ্য পরিবর্তন, ছোট diff, এবং কম জরুরি ফিক্স। টিমগুলোকে আর নায়ক ডেভেলপারদের উপর নির্ভর করতে হয় না যারা প্রতিটি ঐতিহাসিক এজ কেস মনে রাখে বা চাপের নিচে ২টা বাজে ডিবাগ করতে পারে। পরিবর্তে সিস্টেমটি স্বাভাবিক মানব মনোযোগ সামলাতে পারে।
নিয়ম-কথা: কম বিশেষ কেস, কম আচমকা পরিস্থিতি
প্র্যাকটিক্যাল টেস্ট: যদি আপনি ধারাবাহিকভাবে ব্যতিক্রম যোগ করতে থাকেন (“অথবা…” , “এক্সেপ্ট যখন…”, “শুধুই এই গ্রাহকের জন্য…”) তাহলে সম্ভবত আপনি ঘটিত জটিলতা জমাচ্ছেন। এমন সমাধান বেছে নিন যা শাখা-চলাচল কমায়—একটি নির্দিষ্ট নিয়ম পাঁচটি বিশেষ কেসের চেয়ে ভাল, এমনকি নিয়মটি প্রথমে ভাবার চেয়েও একটু সাধারণ হলে।
Structured Programming: বিশ্বাসযোগ্য স্পষ্ট কন্ট্রোল ফ্লো
Structured programming একটি সরল ধারণা যার বড় পরিণতি: কোড লিখুন যাতে এর এক্সিকিউশনের পথ অনুসরণ করা সহজ হয়। সহজ কথায়, বেশিরভাগ প্রোগ্রাম তিনটি বিল্ডিং ব্লক থেকে গঠিত হতে পারে—sequence, selection, এবং repetition—অবাঞ্ছিত জাম্পে নির্ভর না করে।
তিনটি ব্লক (মানব ভাষায়)
- Sequence: ধাপে ধাপে A, তারপর B, তারপর C করা।
- Selection: শর্তের উপর ভিত্তি করে পথ নির্বাচন (উদাহরণ:
if/else,switch)। - Repetition: শর্ত থাকা পর্যন্ত ধাপগুলো 반복 করা (উদাহরণ:
for,while)।
যখন কন্ট্রোল ফ্লো এই স্ট্রাকচারের সমন্বয়ে গঠিত, সাধারণত উপরে-থেকে-নিচে পড়েই বোঝা যায় প্রোগ্রামটি কী করে, ফাইল জুড়ে “টেলিপোর্ট” না করে।
যা এটি প্রতিস্থাপন করেছে: স্প্যাগেটি এক্সিকিউশন পথ
Structured programming প্রচলিত হওয়ার আগে অনেক কোডবেস অযাচিত জাম্পের ওপর নির্ভর করত (goto-ধাঁচ)। সমস্যাটি ছিল অনিয়ন্ত্রিত জাম্প execution path-কে বোঝা কঠিন করে দেয়। আপনি এমন প্রশ্ন করতে থাকেন “আমরা এখানে কিভাবে পৌঁছেছি?” এবং “এই ভ্যারিয়েবলটি কোন স্টেটে?”—কোড পরিষ্কারভাবে উত্তর দেয় না।
কেন বাস্তব টিমের জন্য স্পষ্টতা জরুরি
পরিষ্কার কন্ট্রোল ফ্লো মানুষের মনেই একটি সঠিক মডেল গড়তে সাহায্য করে। সেই মডেলেই আপনি নির্ভর করে ডিবাগ, পুল রিকোয়েস্ট রিভিউ, বা সময়-সংকটে আচরণ পরিবর্তন করেন।
যখন স্ট্রাকচার কনসিস্টেন্ট, পরিবর্তন করা নিরাপদ হয়: আপনি একটি শাখা পরিবর্তন করে অপরটিকে স unintentionally প্রভাবিত করবেন না, অথবা একটি লুপ রিফ্যাক্টর করে একটা লুকানো এক্সিট পাথ মিস করবেন না। পাঠযোগ্যতা কেবল নান্দনিকতা নয়—এটি আচরণ পরিবর্তন নিরাপদভাবে করার ভিত্তি।
যুক্তি করার সরঞ্জাম: Invariants, Preconditions, এবং Postconditions
Dijkstra একটি সরল ধারণা প্রচার করতেন: যদি আপনি ব্যাখ্যা করতে পারেন কেন আপনার কোড সঠিক, আপনি তা কম ভয়ে পরিবর্তন করতে পারবেন। তিনটি ছোট reasoning টুল এ ঘটনাকে ব্যবহারযোগ্য করে তোলে—টিমটিকে পুরো গণিতবিদ বানাতে না হয়ে।
Invariants: “যা সত্য হিসেবে থাকে”
একটি invariant হল এমন একটি সত্য যা কোড চলাকালীন, বিশেষ করে একটি লুপের ভিতরে, সারা সময় সত্য থাকে।
উদাহরণ: আপনি কার্টের প্রাইস যোগ করছেন। একটি দরকারী invariant হবে: “total হচ্ছে এখন পর্যন্ত প্রসেস করা সব আইটেমের যোগফল।” যদি লুপের প্রতিটি ধাপে তা সত্য থাকে, লুপ শেষ হলে রেজাল্ট বিশ্বাসযোগ্য।
Invariants শক্তিশালী কারণ তারা আপনার মনোযোগ কেবল কি কখনো ভাঙবে না তার ওপর কেন্দ্রিত করে, না শুধুমাত্র পরবর্তী কি হওয়া উচিত।
Preconditions ও postconditions: দৈনন্দিন কন্ট্রাক্ট
Precondition হল ফাংশন চালার আগে কি সত্য হতে হবে। Postcondition হল ফাংশন শেষ হওয়ার পরে কি গ্যারান্টি দেয়া হয়।
দিন-চলতি উদাহরণ:
- Precondition: “আপনি কেবল তখনই টাকা তোলতে পারবেন যদি আপনার অ্যাকাউন্টে পর্যাপ্ত টাকা থাকে।”
- Postcondition: “উইথড্রয়ালের পরে ব্যালান্স ঠিক সেই পরিমাণে কমে এবং কখনো নেগেটিভ হয় না।”
কোডে precondition হতে পারে “ইনপুট লিস্টটি সজ্জিত (sorted)” এবং postcondition হতে পারে “আউটপুট লিস্টটি সজ্জিত এবং একই উপাদানগুলো নিয়ে ইনসার্ট করা হয়েছে।”
এগুলো লিখে রাখা কিভাবে কোডিং ও রিভিউ বদলে দেয়
যদি আপনি এগুলো লিখে রাখেন (এমনকি অপ্রাতিষ্ঠানিকভাবে), ডিজাইন তীক্ষ্ণ হয়: আপনি নির্ধারণ করেন ফাংশনটি কি প্রত্যাশা করে এবং কি প্রতিশ্রুতি দেয়, এবং স্বাভাবিকভাবেই এটি ছোট ও ফোকাসড হয়।
রিভিউতে, তর্ক স্টাইল-ভিত্তিক (“আমি অন্যভাবে লিখতাম”) থেকে correctness-ভিত্তিক (“এই কোড কি invariant বজায় রাখে?” “আমরা precondition-enforce করব নাকি ডকুমেন্ট করব?”) হয়ে যায়।
হালকা অনুশীলন: যেখানে বাগ বেশি, সেখানে মন্তব্য দিন
আপনাকে ফরমাল প্রুফ লিখতে হবে না। সবচেয়ে বাগি লুপ বা জটিল স্টেট আপডেট তুলে নিন এবং তার উপরে এক লাইন invariant কমেন্ট যোগ করুন। পরে কেউ কোড পরিবর্তন করলে ঐ কমেন্ট একটি গার্ডরেইলের মতো কাজ করে: যদি কোন পরিবর্তন ঐ সত্য ভাঙে, কোড আর নিরাপদ নয়।
টেস্টিং বনাম যুক্তি: প্রতিটির কি গ্যারান্টি দেয় এবং কি দেয় না
টেস্টিং ও reasoning একই লক্ষ্যেই কাজ করে—ইচ্ছাকৃত আচরণ—কিন্তু পদ্ধতি ভিন্ন। টেস্ট সমস্যা উদ্ধারে করে উদাহরণ চালিয়ে। reasoning প্রতিরোধ করে সম্পূর্ণ শ্রেণির সমস্যা লজিক স্পষ্ট করে।
টেস্ট ভালো কোন জিনিসগুলোতে
টেস্ট বাস্তব-জগতের সিনারিও ধরে ও রিগ্রেশন পায়, দলকে চালাতে দেয়।
কিন্তু টেস্ট কেবল বাগের উপস্থিতি দেখায়, অনুপস্থিতি নয়। কোনও টেস্ট সুইট সমস্ত ইনপুট, টাইমিং ভ্যারিয়েশন, বা ফিচারগুলোর ইন্টারঅ্যাকশন কভার করতে পারে না। “It works on my machine” ভুলের অনেক কারণই অটেস্টেড কম্বিনেশন—এক বিরল ইনপুট, নির্দিষ্ট অপারেশনের অর্ডার, বা বহু ধাপ পরে আসা সূক্ষ্ম স্টেট—থেকে আসে।
reasoning কী গ্যারান্টি দিতে পারে (এবং কি দেয় না)
Reasoning কোডের প্রপার্টি প্রমাণ করার বিষয়: “এই লুপ সর্বদা শেষ হবে”, “এই ভ্যারিয়েবল কখনো নেগেটিভ হবে না”, “এই ফাংশন কখনো অবৈধ অবজেক্ট রিটার্ন করবে না।” ভালোভাবে করলে এটি নির্দিষ্ট ধরনের বাগ পুরোপুরি বাদ দেয়—বিশেষত বাউন্ডারি ও এজ কেসে।
সীমাবদ্ধতা হল শ্রম ও স্কোপ। সম্পূর্ণ প্রোডাক্টের জন্য ফরমাল প্রুফ প্রায়ই অর্থনৈতিক নয়। Reasoning বিশেষভাবে কার্যকর যখন প্রয়োগ করা হয় নির্বাচিত জায়গায়: প্রধান অ্যালগরিদম, সিকিউরিটি-সেন্সিটিভ ফ্লো, মানি/বিলিং লজিক, এবং concurrency।
একটি ব্যালান্সড পন্থা যা স্কেল করে
বিস্তৃতভাবে টেস্ট ব্যবহার করুন, এবং যেখানে ব্যর্থতা খরচ বেশি সেখানে গভীর reasoning প্রয়োগ করুন।
একটি প্র্যাকটিক্যাল ওভারল্যাপ হলো উদ্দেশ্য executable করা:
- অভ্যন্তরীণ অনুমানের জন্য assertions (উদাহরণ: "index ইন রেঞ্জে")।
- ফাংশন ইনপুট/আউটপুটের জন্য preconditions ও postconditions (চুক্তি)।
- স্থায়ী সত্যের জন্য invariants (উদাহরণ: “cart total equals sum of items”)।
এই কৌশলগুলো টেস্টের বিকল্প নয়—এগুলো নেটটাকে শক্ত করে। তারা বিশৃঙ্খল প্রত্যাশাগুলোকে চেকযোগ্য নিয়মে পরিণত করে, বাগ লেখাকে কঠিন ও ডায়াগনোসিসকে সহজ করে।
শৃঙ্খলা: টিমগুলো কিভাবে “চতুরত্ব ঋণ” এড়ায়
“চতুর” কোড এক মুহূর্তে জিত মনে করায়: কম লাইন, সুন্দর ট্রিক, এক লাইন যা আপনাকে স্মার্ট অনুভব করায়। সমস্যা হল চতুরত্ব সময়ে-সময়ে বা মানুষের মধ্যে স্কেল করে না। ছয় মাস পরে লেখক ট্রিক ভুলে যায়। নতুন সহকর্মী তা লিখিতভাবে পড়ে, লুকানো অনুমান মিস করে, এবং এমনভাবে পরিবর্তন করে যা আচরণ ভেঙে দেয়। এটিই “চতুরত্ব ঋণ”: অল্প-মেয়াদি গতির বিনিময়ে দীর্ঘ-মেয়াদী বিভ্রান্তি।
শৃঙ্খলা টিমকে দ্রুত করে
Dijkstra-র পয়েন্ট ছিল না “বোরিং কোড লেখো”—এটি ছিল যে শৃঙ্খলাবদ্ধ সীমাবদ্ধতা প্রোগ্রামগুলো reasoning-এ সহজ করে তোলে। টিমে সীমাবদ্ধতাগুলো সিদ্ধান্ত ক্লান্তি কমায়। যদি সবাই ইতিমধ্যেই ডিফল্টগুলো জানে (নামকরণ, ফাংশন গঠন, “ডান” হওয়ার মানদণ্ড), তখন প্রতিটি পুল রিকোয়েস্টে মৌলিক বিষয়গুলো পুনরমত দেওয়ার দরকার পড়ে না। সেই সময় ফিরে আসে প্রোডাক্ট কাজে।
শৃঙ্খলা দৈনন্দিন অনুশীলনে প্রকাশ পায়:
- কোড রিভিউ যেখানে স্পষ্টতাকে প্রাধান্য দেয়া হয়, novelty নয় ("অন্য কেউ কি নিরাপদে পরিবর্তন করতে পারবে?")।
- শেয়ার্ড স্ট্যান্ডার্ড (ফরম্যাটিং, নামকরণ, এরর হ্যান্ডলিং) যাতে কোডবেস এক কণ্ঠস্বরের মত পড়ে।
- রিফ্যাক্টরিংকে রক্ষণাবেক্ষণ হিসেবে দেখা, উদ্ধার অপারেশনের মতো নয়—ছোট ক্লিনআপ অবিরত রাখা।
কোডে “শৃঙ্খলাবদ্ধ” কেমন দেখায়
কিছু কংক্রিট অভ্যাস cleverness debt কমায়:
- ছোট ফাংশন যা এক কাজ করে, স্পষ্ট ইনপুট ও আউটপুট সহ।
- পরিষ্কার নাম (উদাহরণ:
calculate_total()বনামdo_it())। - কোনও লুকানো স্টেট নেই: গ্লোবাল কম রাখুন; ডিপেনডেন্সিগুলো স্পষ্টভাবে পাঠান।
- সরল কন্ট্রোল ফ্লো: সূক্ষ্ম অর্ডারিং, ম্যাজিক ভ্যালু, বা “ট্রিক জানলে কাজ করে” এমন লজিক এড়ান।
শৃঙ্খলা সম্পূর্ণতার বিষয়ে নয়—এটি পরবর্তী পরিবর্তনকে পূর্বানুমেয় করার ব্যাপার।
মডিউলারিটি ও সীমা: পরিবর্তন লোকাল রাখুন
মডিউলারিটি শুধুই “কোডকে ফাইল ভাগ করা” নয়। এটি সিদ্ধান্ত গুলোকে স্পষ্ট সীমার পেছনে লুকানো রাখা যাতে সিস্টেমের বাকিটা অভ্যন্তরীণ বিশদ জানার দরকার না পড়ে। একটি মডিউল জটিল অংশগুলো লুকায়—ডেটা স্ট্রাকচার, এজ কেস, পারফরম্যান্স ট্রিক—এবং একটি ছোট, স্থিতিশীল সারফেস প্রকাশ করে।
মডিউল কীভাবে ব্লাস্ট রেডিয়াস ছোট করে
যখন একটি চেঞ্জ অনুরোধ আসে, আদর্শ ফলাফল হল: একটি মডিউল পরিবর্তন হয় এবং সবকিছু অন্যত্র অবিকৃত থাকে। এটাই “পরিবর্তন লোকাল রাখার” অর্থ। সীমাগুলো আকস্মিক কপলিং প্রতিহত করে—যেখানে একটি আপডেট নীরবে তিনটি অন্য জিনিস ভেঙে দেয় কারণ তারা একই অনুমানের উপর নির্ভর করছিল।
একটি ভাল বাউন্ডারি reasoning-ও সহজ করে। যদি আপনি বলতে পারেন একটি মডিউল কী গ্যারান্টি দেয়, আপনি সম্পূর্ণ প্রোগ্রামটির সম্পর্কে পুনরায় পড়া ছাড়াই বিচার করতে পারবেন।
ইন্টারফেসকে প্রতিশ্রুতি হিসেবে দেখা (এবং কিভাবে এটি সমান্তরাল কাজকে সক্ষম করে)
একটি ইন্টারফেস একটি প্রতিশ্রুতি: “এই ইনপুট দিলে আমি এই আউটপুট দিব এবং এই নিয়মগুলো বজায় রাখব।” যখন প্রতিশ্রুতি স্পষ্ট, টিমগুলো সমান্তরালভাবে কাজ করতে পারে:
- একজন ব্যক্তি মডিউলটি ইমপ্লিমেন্ট করে।
- আরেকজন কলার লিখে ইন্টারফেস ব্যবহার করে।
- QA প্রতিশ্রুত আচরণের উপর ভিত্তি করে টেস্ট ডিজাইন করে।
এটি রুটিন প্রশাসনিক নয়—একটি বড় কোডবেসে নিরাপদ সমন্বয় বিন্দু তৈরি করার ব্যাপার।
মডিউলারিটি রক্ষা করার সহজ চেক
আপনি একটি বড় আর্কিটেকচারিক রিভিউ ছাড়াই মডিউলারিটি বাড়াতে পারেন। কিছু হালকা চেক:
- ইনপুট/আউটপুট: আপনি কি কয়েক লাইনে মডিউলের ইনপুট, আউটপুট, এবং সাইড-এফেক্টস তালিকাভুক্ত করতে পারবেন? না হলে সম্ভবত এটি বেশি কাজ করছে।
- ওনারশিপ: এর আচরণ ও পরিবর্তনের জন্য কেউ কি দায়ী? অনিয়ন্ত্রিত মডিউলগুলো ডাম্পিং গ্রাউন্ডে পরিণত হয়।
- ডিপেনডেন্সি: এটি কি “সবকিছুর” উপর নির্ভর করে, নাকি কেবল যা সত্যিই দরকার? কম ডিপেনডেন্সি মানে কম অপ্রত্যাশিত ব্রেক।
ভালোভাবে আঁকা সীমাগুলো পরিবর্তনকে একটি সিস্টেম-ওয়াইড ইভেন্ট থেকে একটি লোকাল সম্পাদনায় পরিণত করে।
কেন এই ধারণাগুলো দল, কোডবেস, ও সময় সহ স্কেল করে
যখন সফটওয়্যার ছোট, আপনি সবকিছু আপনার মাথায় রাখা যায়। স্কেলে, তা সত্য নয়—এবং ব্যর্থতার মোডগুলোও পরিচিত হয়ে ওঠে।
সাধারণ উপসর্গগুলো:
- একটি অব্যাহত সমস্যা যেটি এক চমকপ্রদ কর্ণারে ফিরে যায়
- রিলিজ ধীর হয়ে যায় কারণ প্রতিটি পরিবর্তন ঝুঁকিপূর্ণ মনে হয়
- নমনশীল ইন্টিগ্রেশন যেখানে ছোট আপডেট তিনটি ডাউনস্ট্রিম সিস্টেম ভাঙে
গঠন কগনিটিভ লোড কমায়
Dijkstra-র মূল বাজি ছিল যে মানুষেরাই সীমা। পরিষ্কার কন্ট্রোল ফ্লো, ছোট স্পষ্ট ইউনিট, এবং এমন কোড যা আপনি reasoning করে বুঝতে পারেন—এসব নান্দনিক নয়; এগুলো ক্ষমতা বাড়ায়।
একটি বড় কোডবেসে, গঠন বোঝার জন্য একটি কোর প্রভাব ফেলে। যদি ফাংশনগুলো স্পষ্ট ইনপুট/আউটপুট দেয়, মডিউলগুলো নামযোগ্য বাউন্ডারি রাখে, এবং হ্যাপি-পাথ প্রতিটি এজ কেসে গোঁড়া না হয়ে থাকে, ডেভেলপাররা উদ্দেশ্য পুনর্নির্মাণ করার সময় কম ব্যয় করে এবং আলাদা পরিবর্তন করার সময় আরও নিশ্চিত থাকে।
এটি কেবল কোড নয়—টিমের সাথে স্কেল করে
টিম বড় হলে কমিউনিকেশন খরচ লাইনের সংখ্যা ছাড়িয়ে দ্রুত বাড়ে। শৃঙ্খলাবদ্ধ, পাঠযোগ্য কোড এই জাতীয় ট্রাইবাল জ্ঞানের পরিমাণ কমায় যা অংশ হতে হয়।
এটি অনবোর্ডিংয়ে স্পষ্ট হয়: নতুন ইঞ্জিনিয়াররা প্রত্যাশিত প্যাটার্ন অনুসরণ করে, একটি ছোট কনভেনশন শিখে, এবং দীর্ঘ “গটচাস” ট্যুর ছাড়াই পরিবর্তন করতে পারে। কোড নিজেই সিস্টেমটি শেখায়।
ইনসিডেন্ট ডিবাগ করা সহজ ও নিরাপদ করে
ইনসিডেন্টে সময় সীমিত এবং আত্মবিশ্বাস ভঙ্গুর। স্পষ্ট অনুমান (preconditions), অর্থপূর্ণ চেক, এবং সরাসরি কন্ট্রোল ফ্লোযুক্ত কোড চাপের মধ্যে ট্রেস করা সহজ।
ততটাই গুরুত্বপূর্ণ, শৃঙ্খলাবদ্ধ পরিবর্তনগুলোকে রোলব্যাক করাও সহজ। ছোট, লোকাল এডিট এবং স্পষ্ট বাউন্ডারি থাকা মানে rollback নতুন ব্যর্থতা ট্রিগার করার সম্ভাবনা কমায়। ফলাফল: পারফেকশন নয়—কিন্তু কম অপ্রত্যাশিততা, দ্রুত পুনরুদ্ধার, এবং বছরের পর বছর ধরে রক্ষণযোগ্য সিস্টেম।
Dijkstra প্রয়োগ করবেন কিভাবে—কঠোর হলে না হলেও
Dijkstra-র মূল কথা ছিল না “পুরোনো ভাবে কোড লিখো।” বরং ছিল “এমন কোড লিখো যা তুমি বর্ণনা করতে পারো।” আপনি ঐ মাইন্ডসেট গ্রহণ করতে পারেন যে প্রতিটি ফিচারকে ফরমাল প্রুফ বানাতে হবে না।
নীতিগুলোকে দৈনিক অভ্যাসে রূপান্তর করুন
শুরু করুন এমন পছন্দগুলো দিয়ে যা reasoning-কে সস্তা করে:
- সরল কন্ট্রোল ফ্লো পছন্দ করুন: একটি বড় বহু-শাখা রুটিনের বদলে কয়েকটি ছোট ফাংশন।
- সাইড-ইফেক্ট কমান: মিউটেশন যেখানে দরকার সেখানেই রাখুন, এবং ফাংশনগুলো নিঃশব্দে গ্লোবাল স্টেট বদলাকোক না।
- পরিষ্কার কন্ট্রাক্ট ব্যবহার করুন: টাইপ, নাম, এবং কমেন্টে ইনপুট, আউটপুট, এবং এরর আচরণ স্পষ্ট করুন।
একটি ভালো হিউরিস্টিক: যদি আপনি একটি ফাংশন কী গ্যারান্টি দেয় তা এক বাক্যে বলতে না পারেন, সম্ভবত সেটি বেশি কাজ করছে।
ছোট “স্ট্রাকচার আপগ্রেড” (রিরাইট নয়)
বড় রিফ্যাক্টরের দরকার নেই। সার্জিস স্থানগুলোতে স্ট্রাকচার যোগ করুন:
- একটি জটিল লুপকে একটি নামকৃত ফাংশনে বের করে নিন এবং প্রতিটি ইটারেশনে কী সত্য তা সংজ্ঞায়িত করুন।
- “ম্যাজিক” কন্ডিশনালগুলোকে ভাল নামকৃত predicate দিয়ে বদলান (উদা:
isEligibleForRefund)। - একটি জটিল স্টেট ট্রানজিশনকে একটি একক ফাংশনের পেছনে এনক্যাপসুলেট করুন যাতে বাকী কোডবেস এটি ভুলভাবে ব্যবহার করতে না পারে।
এই আপগ্রেডগুলো ইনক্রিমেন্টাল: পরবর্তী পরিবর্তন করার জটিলতা কমায়।
কোড রিভিউ প্রম্পট যা আপনাকে সতর্ক রাখে
রিভিউ বা লেখার সময় জিজ্ঞেস করুন:
- “এখানে কি সত্য হওয়াটা আবশ্যক?” (invariants, assumptions, প্রয়োজনীয় স্টেট)
- “কি নিরাপদে পরিবর্তন করা যাবে?” (কোন অংশগুলো কলারদের জন্য ভ্যারিয়েবল না)
যদি রিভিউয়াররা দ্রুত জবাব দিতে না পারে, কোডটি লুকানো ডিপেনডেন্সি সংকেত দিচ্ছে।
কেবল ধাপগুলো নয়—যুক্তিটি ডকুমেন্ট করুন
এমন মন্তব্যগুলো যা শুধু কোডকে পুনরাবৃত্তি করে দ্রুত পুরনো হয়ে যায়। পরিবর্তে লিখুন কেন কোড সঠিক: মূল অনুমানগুলো, যে এজ কেসগুলোকে আপনি রক্ষা করছেন, এবং যদি ঐ অনুমান বদলে যায় কী ভেঙে যাবে। এক লাইন টিপ: “Invariant: total always equals sum of processed items” হয়তো একটি দীর্ঘ বর্ণনার চেয়ে বেশি মূল্যবান।
হালকা ধারণা ধরে রাখতে একটি শেয়ার্ড চেকলিস্ট তৈরি করুন (দেখুন /blog/practical-checklist-for-disciplined-code)।
AI-সহায়ক বিল্ডিং কোথায় ফিট করে (শৃঙ্খলা হারানোর ঝুঁকি ছাড়াই)
আধুনিক টিমগুলো দ্রুত ডেলিভারির জন্য AI ব্যবহার বাড়িয়ে তুলছে। ঝুঁকি এখানেও পরিচিত: আজকের দ্রুততা কালকে বিভ্রান্তিতে পরিণত হতে পারে যদি জেনারেটেড কোড ব্যাখ্যা করা কঠিন হয়।
Dijkstra-সদৃশ উপায়ে AI ব্যবহার করা মানে এটিকে structured thinking-এর অ্যাক্সিলারেটর হিসেবে দেখা, রিপ্লেসমেন্ট নয়। উদাহরণস্বরূপ, যখন আপনি AI ব্যবহার করেন—অথবা Koder.ai-এর মতো প্ল্যাটফর্মে—আপনি reasoning-first অভ্যাসগুলো বজায় রাখতে পারেন:
- স্পষ্ট কন্ট্রাক্ট চান: “এই endpoint-এর জন্য preconditions, postconditions এবং error behavior সংজ্ঞায়িত কর।”
- স্টেটফুল ফ্লোতে invariants চান: “এই checkout state machine-এর প্রতিটি ধাপের পরে কী সত্য থাকতে হবে?”
- planning mode ব্যবহার করুন যাতে জেনারেশনের আগে মডিউল, ইন্টারফেস, এবং দায়িত্বে বিভাজন ঘটানো হয়।
- স্ন্যাপশট ও রোলব্যাক ব্যবহার করে পরিবর্তনগুলো ছোট ও উল্টানো যায় এমন রাখুন—স্থানীয় এডিট ও নিরাপদ undo পথের শৃঙ্খলার প্রতিচ্ছবি।
যদি আপনি পরে সোর্স এক্সপোর্ট করে অন্য জায়গায় চালান, একই নীতি প্রযোজ্য: জেনারেটেড কোডও এমন হওয়া উচিত যে আপনি ব্যাখ্যা করতে পারেন।
সঠিক, সরল, শৃঙ্খলাবদ্ধ কোডের জন্য একটি প্র্যাকটিক্যাল চেকলিস্ট
এটি একটি হালকা “Dijkstra-মিতব্যয়ী” চেকলিস্ট যা আপনি রিভিউ, রিফ্যাক্টর, বা মার্জের আগে ব্যবহার করতে পারেন। এটা প্রতিদিন প্রুফ লেখার ব্যাপার নয়—এটা সঠিকতা ও স্পষ্টতাকে ডিফল্ট করা।
দ্রুত স্ব-চেক (নতুন কোড ও রিফ্যাক্টর)
- আমি কি ৬০ সেকেন্ডে সহকর্মীকে কোডটি ব্যাখ্যা করতে পারি? যদি ব্যাখ্যার সঙ্গে অনেকটা “শুধু ভরসা করো” থাকে, সরল করুন।
- কন্ট্রোল ফ্লো কি স্পষ্ট? সরল লাইন কোড পছন্দ করুন; লুপ ও কন্ডিশন ছোট রাখুন; লুকানো exit এবং গভীর নেস্টিং এড়ান।
- Preconditions ও postconditions কি আছে? কমেন্ট, docstring, বা ফাংশন নামের মাধ্যমে লিখে রাখুন। না পারলে সম্ভবত ফাংশনটি বেশি কাজ করছে।
- প্রতিটি ফাংশনের এক কাজ আছে কি? ইনপুট ইন, আউটপুট আউট—গ্লোবাল স্টেট উপর নির্ভর কম।
- কোন invariant লুপটিকে সৎ রাখে? এমন এক লাইনের নোটও (যেমন “
totalalways equals sum of processed items”) সূক্ষ্ম বাগ প্রতিরোধ করে। - প্রয়োজনীয় চতুর 트্রিকের সংখ্যা কম আছে? যদি কোডটি একটি ট্যুর গাইড চাই, এটি cleverness debt জমাচ্ছে।
গুণগতভাবে কি পরিমাপ করবেন
- ব্যাখ্যার সহজতা: মডিউলের সাথে অপরিচিত কেউ কি বলবে এটি কি করে এবং কেন এটি সঠিক?
- টেস্ট সহজতা: এজ কেস কি স্বাভাবিকভাবে টেস্টযোগ্য, নাকি জটিল সেটআপ ও মকিং দরকার?
- পরিবর্তনের ঝুঁকি: যখন চাহিদা বদলে যায়, আপনি কি পূর্বাভাস করতে পারেন কি ভাঙবে? যদি প্রতিটি পরিবর্তন ভীতিজনক হয়, বাউন্ডারি লিক করছে।
একটি ব্যবহারিক পরবর্তী পদক্ষেপ
একটি গন্ডগোল মাস্টার মডিউল বেছে নিন এবং প্রথমে কন্ট্রোল ফ্লো পুনর্গঠন করুন:
- ছোট ফাংশনে এক্সট্র্যাক্ট করুন এবং স্পষ্ট নাম দিন।
- জটিল শাখাগুলোকে সরল, স্পষ্ট কেসে পরিবর্তন করুন।
- ইনপুট ভ্যালিডেশন ও early returns-এ বিশেষ কেস সরান।
তারপর নতুন বাউন্ডারিগুলোর চারদিকে কয়েকটা ফোকাসড টেস্ট যোগ করুন। আরও প্যাটার্ন দেখতে /blog দেখুন।
সাধারণ প্রশ্ন
আধুনিক সফটওয়্যার টিমের জন্য কেন Dijkstra এখনও গুরুত্বপূর্ণ?
কারণ কোডবেস বড় হওয়ার সঙ্গে সঙ্গে প্রধান বাধাটা হয়ে যায় বোঝা—টাইপ করা নয়। Dijkstra যে নিয়মগুলো বলতেন (স্থির কন্ট্রোল ফ্লো, স্পষ্ট কন্ট্র্যাক্ট, এবং correctness) সেটি কমিয়ে দেয় সেই ঝুঁকি যে “একটা ছোট পরিবর্তন” অন্য কোথাও অপ্রত্যাশিত আচরণ সৃষ্টি করবে—এটাই সময় চালিয়ে দেয় টিমগুলোকে পিছিয়ে পড়াতে।
এই পোস্টে “স্কেল” বলতে কি বোঝানো হয়েছে—পারফরম্যান্স নাকি কিছু অন্য?
এখানে “স্কেল” বলতে পারফরম্যান্স কম বুঝানো হয়েছে—এখানে অর্থ হলো জটিলতা বেড়ে যাওয়া:
- বেশি ফিচার ও এজ কেস
- বেশি অবদানকারী ও হ্যান্ডঅফ
- বেশি ইন্টিগ্রেশন ও ব্যর্থতা মোড
- সময় বাড়ার সঙ্গে লেগ্যাসি সিদ্ধান্ত
এই সব শক্তি reasoning ও predictability-কে cleverness-এ বেশি মূল্য দেয়।
প্র্যাকটিক্যালভাবে structured programming কি?
প্র্যাকটিক্যালভাবে structured programming মানে কয়েকটি পরিষ্কার কন্ট্রোল স্ট্রাকচার ব্যবহার করা:
- sequence (প্রথম A, তারপর B)
- selection (
if/else,switch) - repetition (
for,while)
লক্ষ্য কড়াকড়ি নয়—লক্ষ্য execution path-কে সহজে অনুসরণ যোগ্য করা, যাতে আচরণ ব্যাখ্যা, রিভিউ এবং ডিবাগ করা যায়।
কেন স্প্যাগেটি কন্ট্রোল ফ্লো (যেমন অনিয়ন্ত্রিত `goto`) মেইনটেন্যান্সে সমস্যা করে?
সমস্যাটি হল অনিয়ন্ত্রিত জাম্পিং যা execution path-কে অপ্রেডিক্টেবল করে এবং স্টেটকে অস্পষ্ট রাখে। যখন কন্ট্রোল ফ্লো জটিল হয়, ডেভেলপাররা ব্যয়বহুল সময় নষ্ট করে মেনে নিতে: “আমি এখানে কিভাবে পৌঁছেছি?” বা “এই ভ্যারিয়েবলটি কোন স্টেটে আছে?” Modern সমতুল্যগুলো হলো গভীরভাবে নেস্টেড ব্রাঞ্চিং, ছড়িয়ে থাকা early exits, এবং জাদুকরী ভ্যালু/ইমপ্লিসিট স্টেট বদলানো।
প্রোডাক্ট সফটওয়্যারের জন্য একটি প্র্যাকটিক্যাল ডেফিনিশন কি?
সফটওয়্যার কী করে তা ব্যবহারকারী অনুভব করে: অ্যাপটি তাদের অবাক করবে না—এটাই correctness। এটি উপস্থিত থাকলে কেউ লক্ষ্য করে না; অনুপস্থিত হলে অন্য সব বিরক্তিকর হয়ে যায়। Correctness হল “কিছু উদাহরণে কাজ করে” বনাম “রিফ্যাক্টরের পরও, ইন্টিগ্রেশনের পরও, এবং এজ কেসগুলোতে কনসিস্টেন্ট।”
কেন ছোট বাগ বড় সিস্টেমে ব্যয়বহুল হয়ে ওঠে?
কারণ নির্ভরতা ত্বরক হিসেবে কাজ করে। একটি ছোট ভুল স্টেট বা বাউন্ডারি বাগ কপি হয়, ক্যাশ হয়, রিট্রাই হয়, বা একথা অন্য সার্ভিসে ওয়ার্কঅ্যারাউন্ড হিসেবে প্যাকেজ হয়ে যায়। সময়ের সঙ্গে টিমগুলো প্রশ্ন করা বন্ধ করে দেয়া শুরু করে: “কি সত্য?” এর বদলে তারা শুধুমাত্র জিজ্ঞেস করে “সাধারণত কি ঘটে?”—এটাই ইনসিডেন্টকে জটিল করে তোলে।
এখানে “সরলতা” বলতে কী বোঝায় (এবং কী বোঝায় না)?
সরলতা মানে একসাথে কম আইডিয়া চলা: স্পষ্ট দায়িত্ব, পরিষ্কার ডেটা ফ্লো, এবং কম বিশেষ কেস। এটি লাইনের সংখ্যা কমানো বা ঘন ওয়ান-লাইন ট্রিক নয়।
বেছে নেওয়ার একটি ভালো পরীক্ষা: যখন রিকোয়ারমেন্ট পরিবর্তিত হয়, আচরণ কি সহজেই পূর্বাভাসযোগ্য থাকে? যদি প্রতিটি নতুন কেসে “তবে…” যোগ করতে হয়, আপনি সম্ভবত আকস্মিক জটিলতা জমাচ্ছেন।
কিভাবে invariants দৈনন্দিন কোডে ফরমাল প্রুফ না করেই সাহায্য করে?
একটি invariant হল এমন একটি সত্য যা একটি লুপ বা স্টেট ট্রানজিশনের সময় অপরিবর্তিত থাকে। হালকা ব্যবহার:
- লুপের উপরে এক লাইন কমেন্ট লিখুন (উদাহরণ: “
totalprocessed আইটেমগুলোর যোগফল”) - কোডটি পরিবর্তন করুন যতক্ষণ না প্রতিটি ইটারেশনে ঐ বক্তব্য সত্য থাকে
- যেখানে সুবিধাজনক, assertion যোগ করুন
এটি পরবর্তীতে সম্পাদনাগুলোকে নিরাপদ করে কারণ পরবর্তী লেখক জানে কোনটা ভাঙলে চলবে না।
টেস্টিং বনাম reasoning—কীভাবে ব্যালান্স করা উচিত?
টেস্টগুলো উদাহরণ চালিয়ে সমস্যা খুঁজে বার করে; reasoning লজিককে স্পষ্ট করে কিছু বাগের পুরো ক্যাটেগরি প্রতিরোধ করে। টেস্ট ছাড়াও আমরা এডিশনাল টুলস ব্যবহার করতে পারি:
- assertions (ভিতরের অনুমান চেক করতে)
- preconditions ও postconditions
- invariants
ব্যালান্স: বিস্তৃত টেস্ট + সমালোচনামূলক অংশে গভীর reasoning।
কিভাবে Dijkstra-র ধারণাগুলো প্রয়োগ করা যায়—বিনা ডগম্যাটিক্ ভাবেই?
ছোট ইনক্রিমেন্টাল পদক্ষেপগুলো শুরু করুন:
- জটিল লুপ থেকে একটি নামকৃত ফাংশন বের করে নিন এবং প্রতিটি ইটারেশনে কী সত্য থাকে তা নির্দিষ্ট করুন
- “জাদুকরী” কন্ডিশনালগুলিকে ভালো নামকৃত predicate দিয়ে পরিবর্তন করুন (উদা:
isEligibleForRefund) - জটিল স্টেট ট্রানজিশনকে একটি একক ফাংশনের পেছনে এনক্যাপসুলেট করুন
- কেন কোডটি সঠিক তা ধরে রাখার ছোট কমেন্ট লিখুন (invariants, assumptions)
এইগুলিই বড় রিফ্যাক্ট ছাড়াই structure বাড়ানোর উপায়।