অবিচ্ছিন্নভাবে ফাংশনটি রেফারেন্স প্যারামিটারকে অবৈধ করে দেয় - কী ভুল হয়েছে?


54

আজ আমরা একটি বাজে বাগের কারণ খুঁজে পেয়েছি যা কেবলমাত্র নির্দিষ্ট প্ল্যাটফর্মে মাঝে মধ্যেই ঘটেছিল। সিদ্ধ হয়ে গেছে, আমাদের কোডটি এমন দেখাচ্ছে:

class Foo {
  map<string,string> m;

  void A(const string& key) {
    m.erase(key);
    cout << "Erased: " << key; // oops
  }

  void B() {
    while (!m.empty()) {
      auto toDelete = m.begin();
      A(toDelete->first);
    }
  }
}

এই সরল ক্ষেত্রে সমস্যাটি সম্ভবত সুস্পষ্ট বলে মনে হতে পারে: Bকীটির একটি রেফারেন্স Aদেয় যা মুদ্রণের চেষ্টা করার আগে মানচিত্রের এন্ট্রি সরিয়ে দেয়। (আমাদের ক্ষেত্রে এটি মুদ্রিত হয়নি, তবে আরও জটিল উপায়ে ব্যবহার করা হয়েছিল) এটি অবশ্যই অপরিজ্ঞাত আচরণ, যেহেতু keyআহ্বানের পরে ডাঙ্গালিং রেফারেন্স erase

এই স্থির তুচ্ছ ছিল - আমরা শুধু থেকে প্যারামিটার প্রকার পরিবর্তন const string&করতে string। প্রশ্নটি হ'ল: আমরা কীভাবে প্রথমে এই বাগটি এড়াতে পারি? মনে হচ্ছে উভয় ফাংশনই সঠিক কাজ করেছে:

  • Aএটি জানার কোনও উপায় নেই যা keyএটি ধ্বংস করতে চলেছে to
  • Bএটি পাস করার আগে একটি অনুলিপি তৈরি করতে পারত A, তবে মান দ্বারা বা রেফারেন্সের মাধ্যমে প্যারামিটারগুলি গ্রহণ করা হবে কিনা তা সিদ্ধান্ত নেওয়া কলির কাজ নয়?

কিছু নিয়ম আমরা অনুসরণ করতে ব্যর্থ হয় কি?

উত্তর:


35

Aএটি জানার কোনও উপায় নেই যা keyএটি ধ্বংস করতে চলেছে to

যদিও এটি সত্য, Aনিম্নলিখিত জিনিসগুলি কি জানেন:

  1. এর উদ্দেশ্য হ'ল কিছু ধ্বংস করা

  2. এটি একটি প্যারামিটার নেয় যা একেবারে একই ধরণের জিনিসটি ধ্বংস করবে।

এই ঘটনা দেওয়া, এটা সম্ভব জন্য Aনিজস্ব পরামিতি ধ্বংস করতে যদি এটি একটি পয়েন্টার / রেফারেন্স হিসেবে পরামিতি গ্রহণ করে। এটি সি ++ এর একমাত্র জায়গা নয় যেখানে এই জাতীয় বিবেচনার দিকে মনোযোগ দেওয়া প্রয়োজন।

এই পরিস্থিতিটি যেমন কোনও operator=অ্যাসাইনমেন্ট অপারেটরের প্রকৃতির অর্থ, তার জন্য আপনাকে স্ব-অ্যাসাইনমেন্ট সম্পর্কে উদ্বিগ্ন হওয়া দরকার to এটি একটি সম্ভাবনা কারণ thisরেফারেন্স প্যারামিটারের ধরণ এবং প্রকার একই।

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

এটি একটি মন্তব্যের জন্য ভাল জায়গা হবে।

কিছু নিয়ম আমরা অনুসরণ করতে ব্যর্থ হয় কি?

সি ++ এ আপনি এই ধারনাটির অধীনে কাজ করতে পারবেন না যে আপনি যদি নিয়মের কোনও সেট অন্ধভাবে অনুসরণ করেন তবে আপনার কোডটি 100% নিরাপদ থাকবে। আমাদের সব কিছুর নিয়ম থাকতে পারে না ।

উপরের পয়েন্ট # 2 বিবেচনা করুন। Aকী থেকে আলাদা কোনও ধরণের কিছু প্যারামিটার নিতে পারত, তবে বস্তুটি নিজেই মানচিত্রে একটি কী-এর সাব-সাবজেক্ট হতে পারে। সি ++ এ, findকী টাইপ থেকে কোনও প্রকারের আলাদা নিতে পারে, যতক্ষণ না তাদের মধ্যে বৈধ তুলনা হয়। সুতরাং আপনি যদি m.erase(m.find(key))তা করেন তবে প্যারামিটারের ধরণটি মূল ধরণের না হলেও আপনি প্যারামিটারটি ধ্বংস করতে পারেন।

সুতরাং "যদি প্যারামিটারের ধরণ এবং কী টাইপ একই হয় তবে এটিকে মান দিয়ে নিন" এর মতো একটি নিয়ম আপনাকে সংরক্ষণ করবে না। আপনার কেবলমাত্র এটির চেয়ে আরও তথ্যের প্রয়োজন হবে।

শেষ পর্যন্ত, আপনাকে আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে মনোযোগ দিতে হবে এবং অভিজ্ঞতার দ্বারা রায় দেওয়া উচিত exercise


10
ঠিক আছে, আপনার পক্ষে "কখনও পরিবর্তনীয়
স্থিতি

7
@ ক্যালথ আপনি যদি এই নিয়মগুলি ব্যবহার করতে চান তবে সি ++ আপনার পক্ষে ভাষা নয়।
ব্যবহারকারী 253751

3
@ ক্যালথ আপনি মরিচা বর্ণনা করছেন?
ম্যালকম

1
"আমাদের সব কিছুর নিয়ম থাকতে পারে না।" হ্যাঁ আমরা পারি. cstheory.stackexchange.com/q/4052
আওরোবরাস

23

আমি হ্যাঁ বলব, মোটামুটি সহজ নিয়ম আপনি ভেঙে দিয়েছেন যা আপনাকে বাঁচাতে পারে: একক দায়িত্বের নীতি।

এই মুহুর্তে, Aএকটি প্যারামিটারটি পাস করা হয়েছে যা এটি উভয়ই কোনও মানচিত্র থেকে কোনও আইটেম সরানোর জন্য ব্যবহার করে এবং অন্য কিছু প্রক্রিয়াজাতকরণ করে (উপরে দেখানো হিসাবে মুদ্রণ করা, আসল কোডে দৃশ্যত অন্য কিছু)। এই দায়িত্বগুলির সংমিশ্রণটি আমার কাছে সমস্যার উত্সের মতো বলে মনে হচ্ছে।

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

std::string &key = get_value_from_map();
destroy(key);
continue_to_use(key);

মঞ্জুর, আমি যে নামগুলি ব্যবহার করেছি নিঃসন্দেহে প্রকৃত নামগুলির তুলনায় সমস্যাটি আরও সুস্পষ্ট করে তুলেছে তবে নামগুলি যদি অর্থবোধক হয় তবে তারা প্রায় নিশ্চিত হয়ে যায় যে আমরা রেফারেন্সটি ব্যবহারের পরেও চালিয়ে যাওয়ার চেষ্টা করছি অবৈধ করা হয়েছে। প্রসঙ্গের সাধারণ পরিবর্তন সমস্যাটিকে আরও প্রকট করে তোলে।


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

5
@ বেনভয়েগ্ট: কেবলমাত্র এর প্যারামিটারটি অবৈধ করার ফলে কোনও সমস্যা হয় না। এটি পরামিতিটি অবৈধ হওয়ার পরেও ব্যবহার অব্যাহত রাখে যা সমস্যার দিকে পরিচালিত করে। তবে শেষ পর্যন্ত হ্যাঁ, আপনি ঠিক বলেছেন: যদিও এটি তাকে এই ক্ষেত্রে বাঁচাতে পারত, নিঃসন্দেহে এমন ঘটনা আছে যেখানে এটি অপর্যাপ্ত।
জেরি কফিন

3
সরল উদাহরণ লেখার সময় আপনাকে কিছু বিশদ বাদ দিতে হবে এবং কখনও কখনও দেখা যায় যে এই বিবরণগুলির মধ্যে একটি গুরুত্বপূর্ণ ছিল। আমাদের ক্ষেত্রে, Aআসলে খোঁজ keyদুটি ভিন্ন মানচিত্রে এবং যদি পাওয়া যায় নি, এন্ট্রি প্লাস কিছু অতিরিক্ত পরিষ্করণ সরানো হয়েছে। সুতরাং এটি স্পষ্ট নয় যে আমাদের Aলঙ্ঘিত এসআরপি। আমি ভাবছি এই মুহুর্তে আমার প্রশ্নটি আপডেট করা উচিত কিনা।
নিকোলাই

2
@ বেনভয়েগের বক্তব্যকে প্রসারিত করার জন্য: নিকোলাইয়ের উদাহরণে m.erase(key)প্রথম দায়িত্ব cout << "Erased: " << keyরয়েছে এবং দ্বিতীয় দায়িত্ব রয়েছে, সুতরাং এই উত্তরে দেখানো কোডটির কাঠামো আসলে উদাহরণের কোডের কাঠামোর চেয়ে আলাদা নয়, তবে বাস্তব বিশ্বের সমস্যা উপেক্ষা করা হয়েছিল। একক দায়িত্বের নীতিটি নিশ্চিত করার জন্য বা এটি আরও বেশি সম্ভাবনা তৈরি করার জন্য কিছুই করে না যে একক ক্রিয়াকলাপের পরস্পরবিরোধী ক্রমগুলি বাস্তব-বিশ্বের কোডে সান্নিধ্যে উপস্থিত হবে।
sdenham

10

কিছু নিয়ম আমরা অনুসরণ করতে ব্যর্থ হয় কি?

হ্যাঁ, আপনি ফাংশনটি নথিভুক্ত করতে ব্যর্থ হয়েছেন

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

উদাহরণস্বরূপ, সি ++ স্ট্যান্ডার্ড নিজেই এটি নির্দিষ্ট করে:

যদি কোনও ফাংশনের পক্ষে যুক্তির একটি অবৈধ মান থাকে (যেমন ফাংশনের ডোমেনের বাইরের কোনও মান বা এর উদ্দেশ্যে ব্যবহারের জন্য অবৈধ পয়েন্টার) থাকে তবে আচরণটি অপরিবর্তিত।

তবে এটি কেবল কলটি করা তাত্ক্ষণিকভাবে বা পুরো ফাংশনটির সম্পাদনের সময় প্রযোজ্য কিনা তা নির্দিষ্ট করে ব্যর্থ হয়। যাইহোক, অনেক ক্ষেত্রে এটি স্পষ্ট যে কেবল পরেরটি এমনকি সম্ভব - যথা যখন অনুলিপিটি অনুলিপি করে বৈধ রাখা যায় না।

বেশ কয়েকটি বাস্তব-জগতের কেস রয়েছে যেখানে এই পার্থক্যটি কার্যকর হয়। উদাহরণস্বরূপ, নিজের মধ্যে একটি যুক্ত std::vector<T>করা


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

@ জ্ঞানজনক হলেও, ইউবি পুনঃক্রমটি আমি এই উত্তরে যা আলোচনা করেছি তার সাথে পুরোপুরি সম্পর্কিত নয়, যা বৈধতা নিশ্চিত করার দায়িত্ব (যাতে ইউবি কখনই ঘটে না)।
বেন ভয়েগট

যা আমার বক্তব্যটি হ'ল: কোডটি লেখার ব্যক্তিকে সমস্যায় পূর্ণ একটি খরগোশের ছিদ্র এড়াতে ইউবি এড়ানোর জন্য দায়বদ্ধ হওয়া দরকার।

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

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

2

কিছু নিয়ম আমরা অনুসরণ করতে ব্যর্থ হয় কি?

হ্যাঁ, আপনি এটি সঠিকভাবে পরীক্ষা করতে ব্যর্থ হয়েছেন। আপনি একা নন, এবং আপনি শেখার সঠিক জায়গায় রয়েছেন :)


সি ++ এর প্রচুর অপরিজ্ঞাত আচরণ রয়েছে, অনির্ধারিত আচরণটি সূক্ষ্ম ও বিরক্তিকর উপায়ে উদ্ভাসিত হয়।

আপনি সম্ভবত 100% নিরাপদ সি ++ কোড লিখতে পারবেন না, তবে আপনি অবশ্যই বেশ কয়েকটি সরঞ্জাম নিযুক্ত করে আপনার কোড বেসে অপ্রত্যাশিত আচরণটি প্রবর্তনের সম্ভাবনা হ্রাস করতে পারেন।

  1. সংকলক সতর্কতা
  2. স্ট্যাটিক বিশ্লেষণ (সতর্কতার বর্ধিত সংস্করণ)
  3. ইনস্ট্রুমেন্টড টেস্ট বাইনারি
  4. কঠোর উত্পাদনের বাইনারি

আপনার ক্ষেত্রে, আমি সন্দেহ করি (1) এবং (2) অনেক সাহায্য করতে পারত, যদিও সাধারণভাবে আমি সেগুলি ব্যবহার করার পরামর্শ দিই। আপাতত আসুন অন্য দুটিতে মনোনিবেশ করা যাক।

জিসিসি এবং ক্ল্যাং উভয়েই একটি -fsanitizeপতাকা বৈশিষ্ট্যযুক্ত যা বিভিন্ন ইস্যুগুলি পরীক্ষা করার জন্য আপনি যে প্রোগ্রামগুলি সংকলন করে তা ইনস্ট্রুমেন্ট করে instrument -fsanitize=undefinedউদাহরণস্বরূপ স্বাক্ষরিত পূর্ণসংখ্যার আন্ডারফ্লো / ওভারফ্লোটি ধরা পড়বে, খুব বেশি পরিমাণে বদল করা হবে ইত্যাদি ইত্যাদি your আপনার নির্দিষ্ট ক্ষেত্রে -fsanitize=addressএবং -fsanitize=memoryসম্ভবত এই সমস্যাটি গ্রহণ করা সম্ভব হবে ... তবে আপনাকে ফাংশনটিতে ডাকার একটি পরীক্ষা প্রদান করবে। সম্পূর্ণতার জন্য, -fsanitize=threadআপনার যদি মাল্টি-থ্রেডযুক্ত কোডবেস ব্যবহার করা উপযুক্ত worth আপনি যদি বাইনারি বাস্তবায়ন করতে না পারেন (উদাহরণস্বরূপ, তাদের উত্স ব্যতীত আপনার তৃতীয় পক্ষের লাইব্রেরি রয়েছে), তবে আপনি valgrindএটি সাধারণভাবে ধীরে ধীরে হলেও ব্যবহার করতে পারেন ।

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

উভয় (3) এবং (4) এর বিন্দু হ'ল একটি বিরতিহীন ব্যর্থতা একটি নির্দিষ্ট ব্যর্থতায় রূপান্তরিত করা : তারা উভয়ই ব্যর্থ দ্রুত নীতি অনুসরণ করে । এই যে মানে:

  • আপনি ল্যান্ডমাইনটি সরাতে গেলে সর্বদা ব্যর্থ হয়
  • এটি অবিলম্বে ব্যর্থ হয় , এলোমেলোভাবে স্মৃতি দুর্নীতি ইত্যাদির পরিবর্তে আপনাকে ত্রুটির দিকে নির্দেশ করে ...

(3) একটি ভাল পরীক্ষার কভারেজের সাথে সংযুক্ত করা বেশিরভাগ সমস্যাগুলিকে উত্পাদন হিট করার আগে ধরা উচিত। উত্পাদনে (4) ব্যবহার করা বিরক্তিকর বাগ এবং শোষণের মধ্যে পার্থক্য হতে পারে।


0

@ নোট: এই পোস্টটি বেন ভয়েগ্টের উত্তরের উপরে আরও যুক্তি যুক্ত করেছে ।

প্রশ্নটি হ'ল: আমরা কীভাবে প্রথমে এই বাগটি এড়াতে পারি? মনে হচ্ছে উভয় ফাংশনই সঠিক কাজ করেছে:

  • এটিকে জানার উপায় নেই যে কীটি এটি ধ্বংস করতে চলেছে to
  • বি এ তে পাস করার আগে একটি অনুলিপি তৈরি করতে পারত, তবে মান দ্বারা বা রেফারেন্সের মাধ্যমে প্যারামিটারগুলি নেবে কিনা তা সিদ্ধান্ত নেওয়াকেই কলিগের কাজ নয়?

উভয় ফাংশনই সঠিক কাজ করেছিল।

সমস্যাটি ক্লায়েন্ট কোডের মধ্যে রয়েছে, যা এটিকে কল করার পার্শ্ব প্রতিক্রিয়াগুলিকে বিবেচনা করে নি which

সি ++ এর ভাষাতে পার্শ্ব প্রতিক্রিয়া নির্দিষ্ট করার সরাসরি কোনও উপায় নেই।

এর অর্থ কোডে (ডকুমেন্টেশন হিসাবে) পার্শ্ব প্রতিক্রিয়া সম্পর্কিত জিনিসগুলি দৃশ্যমান এবং কোড সহ রক্ষণাবেক্ষণ করা (আপনার সম্ভবত প্রাক-শর্তাদি, পোস্ট-কন্ডিশন এবং আক্রমণকারীদের ডকুমেন্টিং বিবেচনা করা উচিত) এটি নিশ্চিত করা আপনার (এবং আপনার দলের) উপর নির্ভর করে পাশাপাশি, দৃশ্যমানতার কারণেও)

কোড পরিবর্তন:

class Foo {
  map<string,string> m;

  /// \sideeffect invalidates iterators
  void A(const string& key) {
    m.erase(key);
    cout << "Erased: " << key; // oops
  }
  ...

এই জায়গা থেকে আপনার এপিআই-র শীর্ষে কিছু রয়েছে যা আপনাকে বলে যে এটির জন্য আপনার ইউনিট পরীক্ষা করা উচিত; এটি আপনাকে কীভাবে API ব্যবহার করবেন (এবং ব্যবহার করবেন না) তাও বলে দেয়।


-4

আমরা এই বাগটি কীভাবে প্রথম এড়াতে পারতাম?

বাগগুলি এড়ানোর একমাত্র উপায়: কোড লেখা বন্ধ করুন। অন্য সব কিছু কোনওভাবে ব্যর্থ হয়েছে।

তবে বিভিন্ন স্তরে টেস্টিং কোড (ইউনিট টেস্ট, ফাংশনাল টেস্টস, ইন্টিগ্রেশন টেস্টস, গ্রহণযোগ্যতা পরীক্ষা ইত্যাদি) কোডের মান কেবল উন্নত করবে না, তবুও বাগের সংখ্যা হ্রাস করবে।


1
এটি সম্পূর্ণ আজেবাজে কথা। নেই না শুধুমাত্র একটি উপায় বাগ এড়ানো। যদিও এটি তুচ্ছভাবে সত্য যে ত্রুটির অস্তিত্ব সম্পূর্ণরূপে এড়ানোর একমাত্র উপায় হ'ল কখনও কোড না লিখে, এটিও সত্য (এবং আরও কার্যকর) যে বিভিন্ন সফ্টওয়্যার ইঞ্জিনিয়ারিং পদ্ধতি রয়েছে যা আপনি অনুসরণ করতে পারেন, প্রাথমিকভাবে কোড লেখার সময় এবং এটি পরীক্ষা করার সময়, এটি বাগের উপস্থিতি উল্লেখযোগ্যভাবে হ্রাস করতে পারে। পরীক্ষার পর্ব সম্পর্কে প্রত্যেকেই জানেন, তবে কোডটি প্রথম স্থানে লেখার সময় দায়বদ্ধ নকশা অনুশীলন এবং আইডিয়ামগুলি অনুসরণ করে সবচেয়ে বড় প্রভাবটি প্রায়শই সর্বনিম্ন ব্যয়ে হতে পারে।
কোডি গ্রে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.