অতিরিক্ত শর্ত পরীক্ষা করে দেখা কি খারাপ স্টাইল?


10

আমি প্রায়শই আমার কোডে অবস্থান করি যেখানে আমি নিজেকে বার বার একটি নির্দিষ্ট শর্ত পরীক্ষা করে দেখি।

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

# ...
clear_lines() # removes every other line than those starting with "a" or "b"
for line in lines:
    if (line.startsWith("a")):
        # do stuff
    elif (line.startsWith("b")):
        # magic
    else:
        # this else is redundant, I already made sure there is no else-case
        # by using clear_lines()
# ...

আপনি কল্পনা করতে পারেন আমি কেবল এখানে এই শর্তটি পরীক্ষা করব না, তবে অন্যান্য ফাংশনগুলিতেও।

আপনি কি এটিকে গোলমাল মনে করেন বা এটি আমার কোডের কোনও মূল্য যুক্ত করে?


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

আপনার 'অন্য' কেসটি মূলত মৃত / অ্যাক্সেসযোগ্য কোড। এটি নিষিদ্ধ করে এমন কোনও সিস্টেম বিস্তৃত প্রয়োজনীয়তা নেই তা পরীক্ষা করে দেখুন।
NWS

@ এনডাব্লুএস: আপনি কি বলছেন যে আমার অন্য মামলা রাখা উচিত? দুঃখিত আমি আপনাকে সম্পূর্ণ বুঝতে পারি না।
মার্কতানি

2
বিশেষত প্রশ্নের সাথে সম্পর্কিত নয় - তবে আমি সেই 'দৃser়তা'টিকে একটি আক্রমণকারী হিসাবে তৈরি করবো - যার জন্য একটি নতুন "লাইন" শ্রেণি প্রয়োজন (সম্ভবত এ ও বি এর জন্য প্রাপ্ত ক্লাস সহ) লাইনগুলি স্ট্রিং হিসাবে গণ্য করার পরিবর্তে এবং তাদের কী বলা উচিত তারা বাইরে থেকে প্রতিনিধিত্ব করে। আমি এই উপর সম্প্রসারিত খুশি হবেন CodeReview
MattDavey

তুমি কি বোঝাতে elif (line.startsWith("b"))চাও? যাইহোক, আপনি শর্তগুলির উপর ভিত্তি করে গ্রাউন্ডিং করা প্রথম বন্ধনীগুলি সুরক্ষিতভাবে মুছে ফেলতে পারেন, তারা পাইথনে মূর্তিমান নয়।
টোকল্যান্ড

উত্তর:


14

এটি একটি বাহ্যিকভাবে সাধারণ অনুশীলন এবং এর সাথে ডিল করার উপায় হ'ল অর্ডার ফিল্টারগুলির মাধ্যমে ।

মূলত, আপনি যে তালিকা / ক্রমটির বিরুদ্ধে ফিল্টার করতে চান তার সাথে ফিল্টার পদ্ধতিতে আপনি একটি ফাংশন পাস করেন এবং ফলস্বরূপ তালিকা / সিকোয়েন্সগুলিতে কেবল যে উপাদানগুলি চান তা রয়েছে।

আমি পাইথন সিনট্যাক্সের সাথে অপরিচিত (যদিও এটি উপরের লিঙ্কটিতে দেখা যায় যেমন একটি ফাংশন ধারণ করে), তবে সি # / এফ # তে এটি দেখতে এটির মতো দেখাচ্ছে:

গ #:

var linesWithAB = lines.Where(l => l.StartsWith("a") || l.StartsWith("b"));
foreach (var line in linesWithAB)
{
    /* line is guaranteed to ONLY start with a or b */
}

f # (অনুমানযোগ্য নয়ন, অন্যথায় List.filter ব্যবহৃত হবে):

let linesWithAB = lines
    |> Seq.filter (fun l -> l.StartsWith("a") || l.StartsWith("b"))

for line in linesWithAB do
    /* line is guaranteed to ONLY start with a or b */

সুতরাং, পরিষ্কার হয়ে উঠুন: আপনি যদি পরীক্ষিত কোড এবং নমুনা পরীক্ষা করে থাকেন তবে এটি খারাপ স্টাইল। এটি, এবং ক্লিয়ার_লাইনগুলির মাধ্যমে আপনি যেভাবে উপস্থিত হন সেই তালিকাটিকে মেমোরিট করে () আপনার থ্রেড সুরক্ষা এবং সমান্তরালতার কোনও আশা হারিয়ে ফেলতে পারেন যা আপনি করতে পারতেন।


3
একটি নোট, এই জন্য পাইথন সিনট্যাক্স জেনারেটরের অভিব্যক্তি হতে হবে: (line for line in lines if line.startswith("a") or line.startswith("b"))
লেটি

1
এটি চিহ্নিত করার জন্য +1 যে (অপ্রয়োজনীয়) এর অপরিহার্য বাস্তবায়ন clear_linesআসলেই একটি খারাপ ধারণা। পাইথনে আপনি সম্ভবত জেনারেটরগুলি মেমরিতে সম্পূর্ণ ফাইলটি লোড করা এড়াতে ব্যবহার করবেন।
টোকল্যান্ড

ইনপুট ফাইলটি উপলব্ধ মেমরির চেয়ে বড় হলে কী হবে?
blrfl

@ ব্লারফ্ল: ভাল, যদি জেনারেটর শব্দটি সি # / এফ # / পাইথনের মধ্যে সামঞ্জস্যপূর্ণ হয়, তবে @ টোকল্যান্ড এবং @ ল্যাটিওয়্যারটি সি # / এফ # ফলন এবং / বা ফলনের মধ্যে কী অনুবাদ করে! বিবৃতি। এটি আমার এফ # উদাহরণে কিছুটা স্পষ্ট কারণ সেক.ফিল্টার কেবলমাত্র আইনিম্যুয়াল <T> এর সংগ্রহগুলিতে প্রয়োগ করা যেতে পারে তবে linesউত্পন্ন সংগ্রহ হিসাবে কোডের দুটি উদাহরণই কাজ করবে ।
স্টিভেন ইভার্স

@ এমসিওয়াই: আপনি যখন এইভাবে চালিত অন্যান্য উপলব্ধ ফাংশনগুলির দিকে নজর দেওয়া শুরু করেন তখন এটি সত্যই সেক্সি এবং অবিশ্বাস্যরূপে ভাবপূর্ণ হতে শুরু করে কারণ এগুলি সমস্ত একসাথে জড়িত এবং রচনা করা যেতে পারে। তাকান skip, take, reduce( aggregate.NET মধ্যে), map( select.NET মধ্যে), এবং আরো আছে কিন্তু যে সত্যিই একটি কঠিন শুরু।
স্টিভেন ইভার্স

14

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

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

এটি সঠিক উপায়ে করতে আমার আরও দুই ঘন্টা অতিরিক্ত সময় লেগেছিল, তবে সমস্যা সমাধানের ক্ষেত্রে অন্য লোকের সময় নষ্ট করে দেয়। এটি খুব বিরল যে কয়েকটি প্রসেসরের চক্র নষ্ট সমস্যা সমাধানের এক দিনের জন্য মূল্যবান।

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


"এটি খুব বিরল যে কয়েকটি প্রসেসর চক্র নষ্ট সমস্যা সমাধানের জন্য মূল্যবান।" উত্তরের জন্য ধন্যবাদ, আপনি একটি ভাল পয়েন্ট আছে।
মার্কতানি

5

ক্ষেত্রে আপনি একটি ব্যতিক্রম বাড়াতে পারেন else। এইভাবে এটি অনর্থক নয়। ব্যতিক্রমগুলি এমন কিছু নয় যেগুলি ঘটবে বলে মনে করা হচ্ছে না তবে তা যাচাই করা আছে।

clear_lines() # removes every other line than those starting with "a" or "b"
for line in lines:
    if (line.startsWith("a)):
        # do stuff
    if (line.startsWith("b")):
        # magic
    else:
        throw BadLineException
# ...

আমি যুক্তি দেব যে এটি একটি খারাপ ধারণা, কারণ এটি কম স্পষ্ট - আপনি যদি পরে কোনও যুক্ত করার সিদ্ধান্ত নেন তবে "c"এটি কম পরিষ্কার হতে পারে।
লেটি

প্রথম পরামর্শটির যোগ্যতা আছে ... দ্বিতীয় (ধরে নিন "বি") একটি খারাপ ধারণা
অ্যান্ড্রু

@ ল্যাটিওয়্যার আমি উত্তরটি উন্নত করেছি। তোমার মন্তব্যের জন্য ধন্যবাদ.
তুলাইনস কর্ডোভা

1
@ অ্যান্ড্রু আমি উত্তরটি উন্নত করেছি। তোমার মন্তব্যের জন্য ধন্যবাদ.
তুলাইনস কর্ডোভা

3

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

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

চুক্তির জন্য ধন্যবাদ, একটি ফাংশন নিশ্চিত যে তার ক্লায়েন্টরা এটি সঠিকভাবে ব্যবহার করেছে এবং ক্লায়েন্ট নিশ্চিত যে ফাংশনটি তার কাজটি সঠিকভাবে করে does

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

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

এর পরে আরও শক্ত অংশটি নির্ধারণ করা হয় যে কোন ক্রিয়াটি কোনটির জন্য দায়ী তা নির্ধারণ করা এবং এই ভূমিকাগুলি কঠোরভাবে নথিভুক্ত করা।


1

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

এটি কেবল খারাপ শৈলী নয়, এটি গণনার দিক থেকেও খারাপ।


2
এটি হতে পারে যে সেই লাইনগুলি অন্য কোনও কিছুর জন্য ব্যবহৃত হচ্ছে এবং "a"/ "b"লাইনগুলির সাথে ডিল করার আগে সেগুলি মোকাবেলা করা দরকার । এটি সম্ভবত বলা হচ্ছে না ( পরিষ্কার নামটি বোঝায় যে তারা ফেলে দেওয়া হচ্ছে), কেবলমাত্র এটির দরকার হওয়ার সম্ভাবনা রয়েছে। ভবিষ্যতে যদি সেই লাইনের সেটটি বারবার পুনরাবৃত্তি হয় তবে প্রচুর অর্থহীন পুনরাবৃত্তি এড়াতে আগেই এগুলি সরিয়ে ফেলা সার্থক হতে পারে।
লেটি

0

যদি আপনি কোনও অকার্যকর স্ট্রিং (উদাহরণস্বরূপ আউটপুট ডিবাগ পাঠ্য) খুঁজে পান তবে আপনি যদি কিছু করতে চান তবে আমি বলব এটি একেবারে ঠিক। কিছু অতিরিক্ত লাইন এবং কয়েক মাস লাইনটি ডাউন হয়ে যায় যখন এটি কোনও অজানা কারণে কাজ করা বন্ধ করে দেয় তবে আপনি কেন এটি খুঁজে বের করতে আউটপুটটি দেখতে পারেন।

তবে, যদি এটি কেবল এটি উপেক্ষা করা নিরাপদ, বা আপনি নিশ্চিতভাবে জানেন যে আপনি কখনই একটি অবৈধ স্ট্রিং পাবেন না তবে অতিরিক্ত শাখার দরকার নেই।

ব্যক্তিগতভাবে আমি সর্বদা যে কোনও অপ্রত্যাশিত অবস্থার জন্য কমপক্ষে কোনও ট্রেস আউটপুট রাখার জন্য আছি - আপনার আউটপুট যুক্ত কোনও বাগ থাকলে ঠিক কী ভুল হয়েছে তা বলার ফলে জীবনটি আরও সহজ হয়।


0

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

# ...
clear_lines() # removes every other line than those starting with "a" or "b"
for line in lines:
    if ...

আমি if...then...elseনির্মাণকে ঘৃণা করি । আমি পুরো বিষয়টি এড়িয়ে যাব:

process_lines_by_first_character (lines,  
                                  'a' => { |line| ... a code ... },
                                  'b' => { |line| ... b code ... } )
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.