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

সফটওয়্যার বিরলভাবেই এ জন্য ব্যর্থ হয় যে তা লেখা সম্ভব নয়। এটি ব্যর্থ হয় কারণ, এক বছর পর, আর কেউ সেটি নিরাপদে পরিবর্তন করতে পারে না।
কোডবেস বাড়ার সাথে সাথে প্রতিটি “ছোট” টুইক তরঙ্গ তৈরি করতে শুরু করে: একটি বাগ দূরবর্তী ফিচার ভাঙে, একটি নতুন চাহিদা রিরাইট বাধ্য করে, এবং একটি সরল রিফ্যাক্টর এক সপ্তাহের সতর্ক সমন্বয়ে পরিণত হয়। কঠিন অংশটি কোড যোগ করা নয়—কঠিন অংশটি হল পারিপার্শ্বিক সবকিছু বদলে গেলেও আচরণটি পূর্বানুমেয় রাখা।
Edsger Dijkstra যুক্তি দিয়েছিলেন যে সঠিকতা এবং সরলতা প্রথম শ্রেণীর লক্ষ্য হওয়া উচিত, সৌন্দর্য বস্তু নয়। ফলাফল শুধু তাত্ত্বিক নয়। যখন একটি সিস্টেম বুঝতে সহজ হয়, টিমগুলো যেমন ফায়ারফাইটিংয়ে কম সময় ব্যয় করে তেমনি আরও বেশি তৈরি করে।
যখন মানুষ বলে সফটওয়্যারকে “স্কেল” করা লাগবে, তারা প্রায়ই পারফরম্যান্সই বুঝে। Dijkstra-র পয়েন্ট আলাদা: জটিলতাও স্কেল করে।
স্কেল দেখতে পাওয়া যায়:
Structured programming নিজেই কড়াকড়ি করা নয়। এটা কন্ট্রোল ফ্লো ও ডিকমপোজিশন বাছাই করার ব্যাপার যাতে দুটি প্রশ্ন সহজে জবাবযোগ্য হয়:
যখন আচরণ পূর্বানুমেয়, পরিবর্তন রুটিনের মত হয় বিপজ্জনক না। এজন্য Dijkstra এখনো প্রাসঙ্গিক: তাঁর শৃঙ্খলা বাড়তে থাকা সফটওয়্যারের প্রকৃত ব্যাঘাত—তথ্যটিকে ভালভাবে বোঝার উপরে লক্ষ্য রাখে।
Edsger W. Dijkstra (1930–2002) ছিলেন ডাচ কম্পিউটার বিজ্ঞানী যিনি নির্ভরযোগ্য সফটওয়্যার তৈরির দৃষ্টিভঙ্গি গঠন করতে সাহায্য করেছেন। তিনি প্রাথমিক অপারেটিং সিস্টেমে কাজ করেছেন, অ্যালগরিদমে অবদান রেখেছেন (তার নামবাহী শর্টেস্ট-পাথ অ্যালগরিদমসহ), এবং—দৈনন্দিন ডেভেলপারদের জন্য সবচেয়ে গুরুত্বপূর্ণ—এমন ধারণা প্রচার করেছেন যে প্রোগ্রামিংকে এমন কিছু করা উচিত যা আমরা যুক্তি করে বুঝতে পারি, শুধুমাত্র সবসময় চেষ্টা করে কাজ করলেই নয়।
Dijkstra কমই চিন্তা করতেন যে প্রোগ্রাম কয়েকটি উদাহরণে সঠিক আউটপুট দেয় কি না; তিনি বেশি ভাবেন আমরা কি বর্ণনা করতে পারি কেন এটি সঠিক সেই গুরুত্বপূর্ণ কেসগুলোর জন্য।
আপনি যদি বলতে পারেন একটি কোড অংশ কি করা উচিত, তবে আপনাকে ধাপে ধাপে যুক্তি দেখাতে সক্ষম হওয়া উচিত যে এটি সেটি করেনি। সেই মানসিকতা স্বাভাবিকভাবেই এমন কোড দেয় যা অনুসরণ করতে সহজ, রিভিউ করতে সহজ, এবং নায়কীয় ডিবাগিংয়ের উপর কম নির্ভরশীল।
Dijkstra-র লেখাগুলো মাঝে মাঝে uncompromising শোনায়। তিনি “চতুর” ট্রিক, অনিয়মিত কন্ট্রোল ফ্লো, এবং এমন কডিং অভ্যাসকে নিন্দা করেছিলেন যা reasoning কঠিন করে। কড়াকড়ি স্টাইল পুলিশের জন্য নয়; এটি অস্পষ্টতা কমানোর জন্য। যখন কোডের অর্থ পরিষ্কার, তখন উদ্দেশ্য নিয়ে তর্ক করার সময় কম লাগে এবং আচরণ যাচাইতে সময় বেশি লাগে।
Structured programming হল প্রোগ্রামগুলোকে কয়েকটি পরিষ্কার কন্ট্রোল স্ট্রাকচার থেকে তৈরি করার প্র্যাকটিস—sequence, selection (if/else), এবং iteration (loops)—পরস্পর জটিল জাম্পের উপর নির্ভর না করে। লক্ষ্য সরল: প্রোগ্রামের পথকে বোধগম্য করা যাতে আপনি তা আত্মবিশ্বাস নিয়ে ব্যাখ্যা, রক্ষণাবেক্ষণ, এবং পরিবর্তন করতে পারেন।
মানের কথা বলা হয় প্রায়ই “দ্রুত”, “সুন্দর”, বা “ফিচার-সমৃদ্ধ” হিসেবে। ব্যবহারকারীরা correctness-কে আলাদা ভাবে অনুভব করে: এটি হল নিঃশব্দ আত্মবিশ্বাস যে অ্যাপ তাদের অবাক করবে না। যখন correctness থাকে, কেউ লক্ষ্য করে না। যখন নেই, সবকিছু ততক্ষণ পর্যন্ত গুরুত্ব হারায় যতক্ষণ না এটি ঠিক হয়।
“এখন কাজ করে” সাধারণত মানে আপনি কয়েকটি পাথ চেষ্টা করেছেন এবং প্রত্যাশিত ফল পেয়েছেন। “এটি কাজ চালিয়ে রাখে” মানে এটি সময়, এজ কেস, এবং পরিবর্তনের পরও অভিপ্রেতভাবে আচরণ করে—রিফ্যাক্টরের পরে, নতুন ইন্টিগ্রেশনের পরে, উচ্চ ট্রাফিক বা নতুন টিম মেম্বারদের স্পর্শ করার পরও।
একটি ফিচার “এখন কাজ করে” বলে মনে হতে পারে কিন্তু তা ভঙ্গুর:
Correctness হল এই লুকানো অনুমানগুলো সরানো—অথবা সেগুলোকে স্পষ্ট করা।
একটি ক্ষুদ্র বাগ বিরলভাবেই ছোট থাকে যখন সফটওয়্যার বড় হয়। একটি ভুল স্টেট, একটি অফ-বাই-ওয়ান বাউন্ডারি, বা একটি অস্পষ্ট এরর-হ্যান্ডলিং নিয়ম নতুন মডিউলে কপি হয়, অন্য সার্ভিস দ্বারা মোড়া হয়, ক্যাশ করা হয়, রিট্রাই করা হয়, বা “ওয়ার্কঅ্যারাউন্ড” হিসেবে রাখা হয়। সময়ের সাথে টিমগুলো জিজ্ঞেস করা বন্ধ করে দেয় “কী সত্য?” এবং পরিবর্তে জিজ্ঞেস করে “সাধারণত কী ঘটে?” তখনই ইনসিডেন্ট রেসপন্স আরকিওলজির মত হয়ে ওঠে।
গুণবিধির কারণ হল ডেপেনডেন্সি: একটি ক্ষুদ্র অমিল অনেক ডাউনস্ট্রিম অমিলকে প্রজন্ম করে, প্রত্যেকটিরই আংশিক ফিক্স থাকে।
পরিষ্কার কোড correctness বাড়ায় কারণ এটি যোগাযোগ উন্নত করে:
Correctness মানে: যে ইনপুট ও পরিস্থিতি আমরা সমর্থন করার কথা বলি, সেগুলোর জন্য সিস্টেম ধারাবাহিকভাবে আমরা প্রতিশ্রুতি দেয়া আউটকাম তৈরি করে—এবং যখন তা করতে পারে না তখন ব্যর্থতা পূর্বানুমেয়, ব্যাখ্যাযোগ্যভাবে ঘটে।
সরলতা কোডকে “কিউট” বা কেবল লাইন কমানো নয়। এটি আচরণকে সহজে পূর্বানুমেয়, ব্যাখ্যা যোগ্য, এবং ভয় ছাড়াই পরিবর্তনযোগ্য করে তোলা। Dijkstra সরলতাকে মূল্য দেন কারণ এটি প্রোগ্রামগুলি সম্পর্কে reasoning উন্নত করে—বিশেষত যখন কোডবেস ও টিম বড় হয়।
সরল কোড এক সময়ে কম আইডিয়া চালায়: পরিষ্কার ডেটা ফ্লো, পরিষ্কার কন্ট্রোল ফ্লো, এবং পরিষ্কার দায়িত্ব। এটি পাঠকের মাথায় একসাথে অনেক বিকল্প পথ সিমুলেট করতে বাধ্য করে না।
সরলতা নয়:
অনেক সিস্টেম কঠিন হয়ে যায় না কারণ ডোমেইন স্বতঃস্ফূর্তভাবে জটিল—বরং কারণ আমরা ঘটিত (accidental) জটিলতা যোগ করি: এমন ফ্ল্যাগগুলো যা অপ্রত্যাশিতভাবে ইন্টারঅ্যাক্ট করে, বিশেষ-কেস প্যাচ যা কখনো মুছে যায় না, এবং স্তরগুলো যা মূলত আগে নেওয়া সিদ্ধান্তকে ওয়ার্কঅ্যারাউন্ড করার জন্য আছে।
প্রত্যেক অতিরিক্ত ব্যতিক্রম বোঝার উপর একটি ট্যাক্স আরোপ করে। খরচ পরে দেখা দেয়, যখন কেউ একটি বাগ ঠিক করতে চায় এবং আবিষ্কার করে এক অঞ্চলে পরিবর্তন করলে অন্য কয়েকটি জায়গায় সূক্ষ্মভাবে ভাঙে।
যখন ডিজাইন সরল, অগ্রগতি হয় নিয়মিত কাজ থেকে: রিভিউযোগ্য পরিবর্তন, ছোট diff, এবং কম জরুরি ফিক্স। টিমগুলোকে আর নায়ক ডেভেলপারদের উপর নির্ভর করতে হয় না যারা প্রতিটি ঐতিহাসিক এজ কেস মনে রাখে বা চাপের নিচে ২টা বাজে ডিবাগ করতে পারে। পরিবর্তে সিস্টেমটি স্বাভাবিক মানব মনোযোগ সামলাতে পারে।
প্র্যাকটিক্যাল টেস্ট: যদি আপনি ধারাবাহিকভাবে ব্যতিক্রম যোগ করতে থাকেন (“অথবা…” , “এক্সেপ্ট যখন…”, “শুধুই এই গ্রাহকের জন্য…”) তাহলে সম্ভবত আপনি ঘটিত জটিলতা জমাচ্ছেন। এমন সমাধান বেছে নিন যা শাখা-চলাচল কমায়—একটি নির্দিষ্ট নিয়ম পাঁচটি বিশেষ কেসের চেয়ে ভাল, এমনকি নিয়মটি প্রথমে ভাবার চেয়েও একটু সাধারণ হলে।
Structured programming একটি সরল ধারণা যার বড় পরিণতি: কোড লিখুন যাতে এর এক্সিকিউশনের পথ অনুসরণ করা সহজ হয়। সহজ কথায়, বেশিরভাগ প্রোগ্রাম তিনটি বিল্ডিং ব্লক থেকে গঠিত হতে পারে—sequence, selection, এবং repetition—অবাঞ্ছিত জাম্পে নির্ভর না করে।
if/else, switch)।for, while)।যখন কন্ট্রোল ফ্লো এই স্ট্রাকচারের সমন্বয়ে গঠিত, সাধারণত উপরে-থেকে-নিচে পড়েই বোঝা যায় প্রোগ্রামটি কী করে, ফাইল জুড়ে “টেলিপোর্ট” না করে।
Structured programming প্রচলিত হওয়ার আগে অনেক কোডবেস অযাচিত জাম্পের ওপর নির্ভর করত (goto-ধাঁচ)। সমস্যাটি ছিল অনিয়ন্ত্রিত জাম্প execution path-কে বোঝা কঠিন করে দেয়। আপনি এমন প্রশ্ন করতে থাকেন “আমরা এখানে কিভাবে পৌঁছেছি?” এবং “এই ভ্যারিয়েবলটি কোন স্টেটে?”—কোড পরিষ্কারভাবে উত্তর দেয় না।
পরিষ্কার কন্ট্রোল ফ্লো মানুষের মনেই একটি সঠিক মডেল গড়তে সাহায্য করে। সেই মডেলেই আপনি নির্ভর করে ডিবাগ, পুল রিকোয়েস্ট রিভিউ, বা সময়-সংকটে আচরণ পরিবর্তন করেন।
যখন স্ট্রাকচার কনসিস্টেন্ট, পরিবর্তন করা নিরাপদ হয়: আপনি একটি শাখা পরিবর্তন করে অপরটিকে স unintentionally প্রভাবিত করবেন না, অথবা একটি লুপ রিফ্যাক্টর করে একটা লুকানো এক্সিট পাথ মিস করবেন না। পাঠযোগ্যতা কেবল নান্দনিকতা নয়—এটি আচরণ পরিবর্তন নিরাপদভাবে করার ভিত্তি।
Dijkstra একটি সরল ধারণা প্রচার করতেন: যদি আপনি ব্যাখ্যা করতে পারেন কেন আপনার কোড সঠিক, আপনি তা কম ভয়ে পরিবর্তন করতে পারবেন। তিনটি ছোট reasoning টুল এ ঘটনাকে ব্যবহারযোগ্য করে তোলে—টিমটিকে পুরো গণিতবিদ বানাতে না হয়ে।
একটি invariant হল এমন একটি সত্য যা কোড চলাকালীন, বিশেষ করে একটি লুপের ভিতরে, সারা সময় সত্য থাকে।
উদাহরণ: আপনি কার্টের প্রাইস যোগ করছেন। একটি দরকারী invariant হবে: “total হচ্ছে এখন পর্যন্ত প্রসেস করা সব আইটেমের যোগফল।” যদি লুপের প্রতিটি ধাপে তা সত্য থাকে, লুপ শেষ হলে রেজাল্ট বিশ্বাসযোগ্য।
Invariants শক্তিশালী কারণ তারা আপনার মনোযোগ কেবল কি কখনো ভাঙবে না তার ওপর কেন্দ্রিত করে, না শুধুমাত্র পরবর্তী কি হওয়া উচিত।
Precondition হল ফাংশন চালার আগে কি সত্য হতে হবে। Postcondition হল ফাংশন শেষ হওয়ার পরে কি গ্যারান্টি দেয়া হয়।
দিন-চলতি উদাহরণ:
কোডে precondition হতে পারে “ইনপুট লিস্টটি সজ্জিত (sorted)” এবং postcondition হতে পারে “আউটপুট লিস্টটি সজ্জিত এবং একই উপাদানগুলো নিয়ে ইনসার্ট করা হয়েছে।”
যদি আপনি এগুলো লিখে রাখেন (এমনকি অপ্রাতিষ্ঠানিকভাবে), ডিজাইন তীক্ষ্ণ হয়: আপনি নির্ধারণ করেন ফাংশনটি কি প্রত্যাশা করে এবং কি প্রতিশ্রুতি দেয়, এবং স্বাভাবিকভাবেই এটি ছোট ও ফোকাসড হয়।
রিভিউতে, তর্ক স্টাইল-ভিত্তিক (“আমি অন্যভাবে লিখতাম”) থেকে correctness-ভিত্তিক (“এই কোড কি invariant বজায় রাখে?” “আমরা precondition-enforce করব নাকি ডকুমেন্ট করব?”) হয়ে যায়।
আপনাকে ফরমাল প্রুফ লিখতে হবে না। সবচেয়ে বাগি লুপ বা জটিল স্টেট আপডেট তুলে নিন এবং তার উপরে এক লাইন invariant কমেন্ট যোগ করুন। পরে কেউ কোড পরিবর্তন করলে ঐ কমেন্ট একটি গার্ডরেইলের মতো কাজ করে: যদি কোন পরিবর্তন ঐ সত্য ভাঙে, কোড আর নিরাপদ নয়।
টেস্টিং ও reasoning একই লক্ষ্যেই কাজ করে—ইচ্ছাকৃত আচরণ—কিন্তু পদ্ধতি ভিন্ন। টেস্ট সমস্যা উদ্ধারে করে উদাহরণ চালিয়ে। reasoning প্রতিরোধ করে সম্পূর্ণ শ্রেণির সমস্যা লজিক স্পষ্ট করে।
টেস্ট বাস্তব-জগতের সিনারিও ধরে ও রিগ্রেশন পায়, দলকে চালাতে দেয়।
কিন্তু টেস্ট কেবল বাগের উপস্থিতি দেখায়, অনুপস্থিতি নয়। কোনও টেস্ট সুইট সমস্ত ইনপুট, টাইমিং ভ্যারিয়েশন, বা ফিচারগুলোর ইন্টারঅ্যাকশন কভার করতে পারে না। “It works on my machine” ভুলের অনেক কারণই অটেস্টেড কম্বিনেশন—এক বিরল ইনপুট, নির্দিষ্ট অপারেশনের অর্ডার, বা বহু ধাপ পরে আসা সূক্ষ্ম স্টেট—থেকে আসে।
Reasoning কোডের প্রপার্টি প্রমাণ করার বিষয়: “এই লুপ সর্বদা শেষ হবে”, “এই ভ্যারিয়েবল কখনো নেগেটিভ হবে না”, “এই ফাংশন কখনো অবৈধ অবজেক্ট রিটার্ন করবে না।” ভালোভাবে করলে এটি নির্দিষ্ট ধরনের বাগ পুরোপুরি বাদ দেয়—বিশেষত বাউন্ডারি ও এজ কেসে।
সীমাবদ্ধতা হল শ্রম ও স্কোপ। সম্পূর্ণ প্রোডাক্টের জন্য ফরমাল প্রুফ প্রায়ই অর্থনৈতিক নয়। Reasoning বিশেষভাবে কার্যকর যখন প্রয়োগ করা হয় নির্বাচিত জায়গায়: প্রধান অ্যালগরিদম, সিকিউরিটি-সেন্সিটিভ ফ্লো, মানি/বিলিং লজিক, এবং concurrency।
বিস্তৃতভাবে টেস্ট ব্যবহার করুন, এবং যেখানে ব্যর্থতা খরচ বেশি সেখানে গভীর reasoning প্রয়োগ করুন।
একটি প্র্যাকটিক্যাল ওভারল্যাপ হলো উদ্দেশ্য executable করা:
এই কৌশলগুলো টেস্টের বিকল্প নয়—এগুলো নেটটাকে শক্ত করে। তারা বিশৃঙ্খল প্রত্যাশাগুলোকে চেকযোগ্য নিয়মে পরিণত করে, বাগ লেখাকে কঠিন ও ডায়াগনোসিসকে সহজ করে।
“চতুর” কোড এক মুহূর্তে জিত মনে করায়: কম লাইন, সুন্দর ট্রিক, এক লাইন যা আপনাকে স্মার্ট অনুভব করায়। সমস্যা হল চতুরত্ব সময়ে-সময়ে বা মানুষের মধ্যে স্কেল করে না। ছয় মাস পরে লেখক ট্রিক ভুলে যায়। নতুন সহকর্মী তা লিখিতভাবে পড়ে, লুকানো অনুমান মিস করে, এবং এমনভাবে পরিবর্তন করে যা আচরণ ভেঙে দেয়। এটিই “চতুরত্ব ঋণ”: অল্প-মেয়াদি গতির বিনিময়ে দীর্ঘ-মেয়াদী বিভ্রান্তি।
Dijkstra-র পয়েন্ট ছিল না “বোরিং কোড লেখো”—এটি ছিল যে শৃঙ্খলাবদ্ধ সীমাবদ্ধতা প্রোগ্রামগুলো reasoning-এ সহজ করে তোলে। টিমে সীমাবদ্ধতাগুলো সিদ্ধান্ত ক্লান্তি কমায়। যদি সবাই ইতিমধ্যেই ডিফল্টগুলো জানে (নামকরণ, ফাংশন গঠন, “ডান” হওয়ার মানদণ্ড), তখন প্রতিটি পুল রিকোয়েস্টে মৌলিক বিষয়গুলো পুনরমত দেওয়ার দরকার পড়ে না। সেই সময় ফিরে আসে প্রোডাক্ট কাজে।
শৃঙ্খলা দৈনন্দিন অনুশীলনে প্রকাশ পায়:
কিছু কংক্রিট অভ্যাস cleverness debt কমায়:
calculate_total() বনাম do_it())।শৃঙ্খলা সম্পূর্ণতার বিষয়ে নয়—এটি পরবর্তী পরিবর্তনকে পূর্বানুমেয় করার ব্যাপার।
মডিউলারিটি শুধুই “কোডকে ফাইল ভাগ করা” নয়। এটি সিদ্ধান্ত গুলোকে স্পষ্ট সীমার পেছনে লুকানো রাখা যাতে সিস্টেমের বাকিটা অভ্যন্তরীণ বিশদ জানার দরকার না পড়ে। একটি মডিউল জটিল অংশগুলো লুকায়—ডেটা স্ট্রাকচার, এজ কেস, পারফরম্যান্স ট্রিক—এবং একটি ছোট, স্থিতিশীল সারফেস প্রকাশ করে।
যখন একটি চেঞ্জ অনুরোধ আসে, আদর্শ ফলাফল হল: একটি মডিউল পরিবর্তন হয় এবং সবকিছু অন্যত্র অবিকৃত থাকে। এটাই “পরিবর্তন লোকাল রাখার” অর্থ। সীমাগুলো আকস্মিক কপলিং প্রতিহত করে—যেখানে একটি আপডেট নীরবে তিনটি অন্য জিনিস ভেঙে দেয় কারণ তারা একই অনুমানের উপর নির্ভর করছিল।
একটি ভাল বাউন্ডারি reasoning-ও সহজ করে। যদি আপনি বলতে পারেন একটি মডিউল কী গ্যারান্টি দেয়, আপনি সম্পূর্ণ প্রোগ্রামটির সম্পর্কে পুনরায় পড়া ছাড়াই বিচার করতে পারবেন।
একটি ইন্টারফেস একটি প্রতিশ্রুতি: “এই ইনপুট দিলে আমি এই আউটপুট দিব এবং এই নিয়মগুলো বজায় রাখব।” যখন প্রতিশ্রুতি স্পষ্ট, টিমগুলো সমান্তরালভাবে কাজ করতে পারে:
এটি রুটিন প্রশাসনিক নয়—একটি বড় কোডবেসে নিরাপদ সমন্বয় বিন্দু তৈরি করার ব্যাপার।
আপনি একটি বড় আর্কিটেকচারিক রিভিউ ছাড়াই মডিউলারিটি বাড়াতে পারেন। কিছু হালকা চেক:
ভালোভাবে আঁকা সীমাগুলো পরিবর্তনকে একটি সিস্টেম-ওয়াইড ইভেন্ট থেকে একটি লোকাল সম্পাদনায় পরিণত করে।
যখন সফটওয়্যার ছোট, আপনি সবকিছু আপনার মাথায় রাখা যায়। স্কেলে, তা সত্য নয়—এবং ব্যর্থতার মোডগুলোও পরিচিত হয়ে ওঠে।
সাধারণ উপসর্গগুলো:
Dijkstra-র মূল বাজি ছিল যে মানুষেরাই সীমা। পরিষ্কার কন্ট্রোল ফ্লো, ছোট স্পষ্ট ইউনিট, এবং এমন কোড যা আপনি reasoning করে বুঝতে পারেন—এসব নান্দনিক নয়; এগুলো ক্ষমতা বাড়ায়।
একটি বড় কোডবেসে, গঠন বোঝার জন্য একটি কোর প্রভাব ফেলে। যদি ফাংশনগুলো স্পষ্ট ইনপুট/আউটপুট দেয়, মডিউলগুলো নামযোগ্য বাউন্ডারি রাখে, এবং হ্যাপি-পাথ প্রতিটি এজ কেসে গোঁড়া না হয়ে থাকে, ডেভেলপাররা উদ্দেশ্য পুনর্নির্মাণ করার সময় কম ব্যয় করে এবং আলাদা পরিবর্তন করার সময় আরও নিশ্চিত থাকে।
টিম বড় হলে কমিউনিকেশন খরচ লাইনের সংখ্যা ছাড়িয়ে দ্রুত বাড়ে। শৃঙ্খলাবদ্ধ, পাঠযোগ্য কোড এই জাতীয় ট্রাইবাল জ্ঞানের পরিমাণ কমায় যা অংশ হতে হয়।
এটি অনবোর্ডিংয়ে স্পষ্ট হয়: নতুন ইঞ্জিনিয়াররা প্রত্যাশিত প্যাটার্ন অনুসরণ করে, একটি ছোট কনভেনশন শিখে, এবং দীর্ঘ “গটচাস” ট্যুর ছাড়াই পরিবর্তন করতে পারে। কোড নিজেই সিস্টেমটি শেখায়।
ইনসিডেন্টে সময় সীমিত এবং আত্মবিশ্বাস ভঙ্গুর। স্পষ্ট অনুমান (preconditions), অর্থপূর্ণ চেক, এবং সরাসরি কন্ট্রোল ফ্লোযুক্ত কোড চাপের মধ্যে ট্রেস করা সহজ।
ততটাই গুরুত্বপূর্ণ, শৃঙ্খলাবদ্ধ পরিবর্তনগুলোকে রোলব্যাক করাও সহজ। ছোট, লোকাল এডিট এবং স্পষ্ট বাউন্ডারি থাকা মানে rollback নতুন ব্যর্থতা ট্রিগার করার সম্ভাবনা কমায়। ফলাফল: পারফেকশন নয়—কিন্তু কম অপ্রত্যাশিততা, দ্রুত পুনরুদ্ধার, এবং বছরের পর বছর ধরে রক্ষণযোগ্য সিস্টেম।
Dijkstra-র মূল কথা ছিল না “পুরোনো ভাবে কোড লিখো।” বরং ছিল “এমন কোড লিখো যা তুমি বর্ণনা করতে পারো।” আপনি ঐ মাইন্ডসেট গ্রহণ করতে পারেন যে প্রতিটি ফিচারকে ফরমাল প্রুফ বানাতে হবে না।
শুরু করুন এমন পছন্দগুলো দিয়ে যা reasoning-কে সস্তা করে:
একটি ভালো হিউরিস্টিক: যদি আপনি একটি ফাংশন কী গ্যারান্টি দেয় তা এক বাক্যে বলতে না পারেন, সম্ভবত সেটি বেশি কাজ করছে।
বড় রিফ্যাক্টরের দরকার নেই। সার্জিস স্থানগুলোতে স্ট্রাকচার যোগ করুন:
isEligibleForRefund)।এই আপগ্রেডগুলো ইনক্রিমেন্টাল: পরবর্তী পরিবর্তন করার জটিলতা কমায়।
রিভিউ বা লেখার সময় জিজ্ঞেস করুন:
যদি রিভিউয়াররা দ্রুত জবাব দিতে না পারে, কোডটি লুকানো ডিপেনডেন্সি সংকেত দিচ্ছে।
এমন মন্তব্যগুলো যা শুধু কোডকে পুনরাবৃত্তি করে দ্রুত পুরনো হয়ে যায়। পরিবর্তে লিখুন কেন কোড সঠিক: মূল অনুমানগুলো, যে এজ কেসগুলোকে আপনি রক্ষা করছেন, এবং যদি ঐ অনুমান বদলে যায় কী ভেঙে যাবে। এক লাইন টিপ: “Invariant: total always equals sum of processed items” হয়তো একটি দীর্ঘ বর্ণনার চেয়ে বেশি মূল্যবান।
হালকা ধারণা ধরে রাখতে একটি শেয়ার্ড চেকলিস্ট তৈরি করুন (দেখুন /blog/practical-checklist-for-disciplined-code)।
আধুনিক টিমগুলো দ্রুত ডেলিভারির জন্য AI ব্যবহার বাড়িয়ে তুলছে। ঝুঁকি এখানেও পরিচিত: আজকের দ্রুততা কালকে বিভ্রান্তিতে পরিণত হতে পারে যদি জেনারেটেড কোড ব্যাখ্যা করা কঠিন হয়।
Dijkstra-সদৃশ উপায়ে AI ব্যবহার করা মানে এটিকে structured thinking-এর অ্যাক্সিলারেটর হিসেবে দেখা, রিপ্লেসমেন্ট নয়। উদাহরণস্বরূপ, যখন আপনি AI ব্যবহার করেন—অথবা Koder.ai-এর মতো প্ল্যাটফর্মে—আপনি reasoning-first অভ্যাসগুলো বজায় রাখতে পারেন:
যদি আপনি পরে সোর্স এক্সপোর্ট করে অন্য জায়গায় চালান, একই নীতি প্রযোজ্য: জেনারেটেড কোডও এমন হওয়া উচিত যে আপনি ব্যাখ্যা করতে পারেন।
এটি একটি হালকা “Dijkstra-মিতব্যয়ী” চেকলিস্ট যা আপনি রিভিউ, রিফ্যাক্টর, বা মার্জের আগে ব্যবহার করতে পারেন। এটা প্রতিদিন প্রুফ লেখার ব্যাপার নয়—এটা সঠিকতা ও স্পষ্টতাকে ডিফল্ট করা।
total always equals sum of processed items”) সূক্ষ্ম বাগ প্রতিরোধ করে।একটি গন্ডগোল মাস্টার মডিউল বেছে নিন এবং প্রথমে কন্ট্রোল ফ্লো পুনর্গঠন করুন:
তারপর নতুন বাউন্ডারিগুলোর চারদিকে কয়েকটা ফোকাসড টেস্ট যোগ করুন। আরও প্যাটার্ন দেখতে /blog দেখুন।
কারণ কোডবেস বড় হওয়ার সঙ্গে সঙ্গে প্রধান বাধাটা হয়ে যায় বোঝা—টাইপ করা নয়। Dijkstra যে নিয়মগুলো বলতেন (স্থির কন্ট্রোল ফ্লো, স্পষ্ট কন্ট্র্যাক্ট, এবং correctness) সেটি কমিয়ে দেয় সেই ঝুঁকি যে “একটা ছোট পরিবর্তন” অন্য কোথাও অপ্রত্যাশিত আচরণ সৃষ্টি করবে—এটাই সময় চালিয়ে দেয় টিমগুলোকে পিছিয়ে পড়াতে।
এখানে “স্কেল” বলতে পারফরম্যান্স কম বুঝানো হয়েছে—এখানে অর্থ হলো জটিলতা বেড়ে যাওয়া:
এই সব শক্তি reasoning ও predictability-কে cleverness-এ বেশি মূল্য দেয়।
প্র্যাকটিক্যালভাবে structured programming মানে কয়েকটি পরিষ্কার কন্ট্রোল স্ট্রাকচার ব্যবহার করা:
if/else, switch)for, while)লক্ষ্য কড়াকড়ি নয়—লক্ষ্য execution path-কে সহজে অনুসরণ যোগ্য করা, যাতে আচরণ ব্যাখ্যা, রিভিউ এবং ডিবাগ করা যায়।
সমস্যাটি হল অনিয়ন্ত্রিত জাম্পিং যা execution path-কে অপ্রেডিক্টেবল করে এবং স্টেটকে অস্পষ্ট রাখে। যখন কন্ট্রোল ফ্লো জটিল হয়, ডেভেলপাররা ব্যয়বহুল সময় নষ্ট করে মেনে নিতে: “আমি এখানে কিভাবে পৌঁছেছি?” বা “এই ভ্যারিয়েবলটি কোন স্টেটে আছে?” Modern সমতুল্যগুলো হলো গভীরভাবে নেস্টেড ব্রাঞ্চিং, ছড়িয়ে থাকা early exits, এবং জাদুকরী ভ্যালু/ইমপ্লিসিট স্টেট বদলানো।
সফটওয়্যার কী করে তা ব্যবহারকারী অনুভব করে: অ্যাপটি তাদের অবাক করবে না—এটাই correctness। এটি উপস্থিত থাকলে কেউ লক্ষ্য করে না; অনুপস্থিত হলে অন্য সব বিরক্তিকর হয়ে যায়। Correctness হল “কিছু উদাহরণে কাজ করে” বনাম “রিফ্যাক্টরের পরও, ইন্টিগ্রেশনের পরও, এবং এজ কেসগুলোতে কনসিস্টেন্ট।”
কারণ নির্ভরতা ত্বরক হিসেবে কাজ করে। একটি ছোট ভুল স্টেট বা বাউন্ডারি বাগ কপি হয়, ক্যাশ হয়, রিট্রাই হয়, বা একথা অন্য সার্ভিসে ওয়ার্কঅ্যারাউন্ড হিসেবে প্যাকেজ হয়ে যায়। সময়ের সঙ্গে টিমগুলো প্রশ্ন করা বন্ধ করে দেয়া শুরু করে: “কি সত্য?” এর বদলে তারা শুধুমাত্র জিজ্ঞেস করে “সাধারণত কি ঘটে?”—এটাই ইনসিডেন্টকে জটিল করে তোলে।
সরলতা মানে একসাথে কম আইডিয়া চলা: স্পষ্ট দায়িত্ব, পরিষ্কার ডেটা ফ্লো, এবং কম বিশেষ কেস। এটি লাইনের সংখ্যা কমানো বা ঘন ওয়ান-লাইন ট্রিক নয়।
বেছে নেওয়ার একটি ভালো পরীক্ষা: যখন রিকোয়ারমেন্ট পরিবর্তিত হয়, আচরণ কি সহজেই পূর্বাভাসযোগ্য থাকে? যদি প্রতিটি নতুন কেসে “তবে…” যোগ করতে হয়, আপনি সম্ভবত আকস্মিক জটিলতা জমাচ্ছেন।
একটি invariant হল এমন একটি সত্য যা একটি লুপ বা স্টেট ট্রানজিশনের সময় অপরিবর্তিত থাকে। হালকা ব্যবহার:
total processed আইটেমগুলোর যোগফল”)এটি পরবর্তীতে সম্পাদনাগুলোকে নিরাপদ করে কারণ পরবর্তী লেখক জানে কোনটা ভাঙলে চলবে না।
টেস্টগুলো উদাহরণ চালিয়ে সমস্যা খুঁজে বার করে; reasoning লজিককে স্পষ্ট করে কিছু বাগের পুরো ক্যাটেগরি প্রতিরোধ করে। টেস্ট ছাড়াও আমরা এডিশনাল টুলস ব্যবহার করতে পারি:
ব্যালান্স: বিস্তৃত টেস্ট + সমালোচনামূলক অংশে গভীর reasoning।
ছোট ইনক্রিমেন্টাল পদক্ষেপগুলো শুরু করুন:
isEligibleForRefund)এইগুলিই বড় রিফ্যাক্ট ছাড়াই structure বাড়ানোর উপায়।