গোলাঙ্গ ত্রুটি হ্যান্ডলিং স্পেসিফিকেশন
ত্রুটির প্রকার
ত্রুটি ঘোষণা করার জন্য কিছু অপশন রয়েছে। আপনার ব্যবহারে সবচেয়ে ভালো হবে কোনটি নিবেন তা নির্ধারণ করার আগে নীচের প্রশ্নগুলি মনে রাখুন:
- কলারকে ত্রুটি ম্যাচ করতে হবে কিনা? যদি হয়, তাহলে আমাদের উচিত
errors.Is
বাerrors.As
ফাংশন সমর্থন করার জন্য শীর্ষ-স্তরের ত্রুটি ভেরিয়েবল বা কাস্টম প্রকার ডিক্লেয়ার করা দরকার। - ত্রুটির বার্তা একটি স্ট্যাটিক স্ট্রিং নিবন্ধন করবে কিনা এমন বা নির্দিষ্ট সংদর্ভ তথ্য প্রয়োজন হবে? স্ট্যাটিক স্ট্রিংগুলির জন্য, আমরা
errors.New
ব্যবহার করতে পারি, কিন্তু অন্যথায়, আমাদের আবশ্যক হবেfmt.Errorf
বা কাস্টম ত্রুটি প্রকার ব্যবহার করতে হবে। - আমরা নতুন ত্রুটি কি নিচের ফাংশনগুলি থেকে পাচ্ছি? যদি হয়, তাহলে ত্রুটি চুপ করার অনুভূতি অনুসরণ করুন।
ত্রুটি ম্যাচ? | ত্রুটির বার্তা | নির্দেশনা |
---|---|---|
না | স্ট্যাটিক | errors.New |
না | ডায়নামিক | fmt.Errorf |
হ্যাঁ | স্ট্যাটিক | শীর্ষ-স্তরের var এর সাথে errors.New |
হ্যাঁ | ডায়নামিক | কাস্টম error প্রকার |
যেমন, স্ট্যাটিক স্ট্রিংগুলির ত্রুটিগুলি প্রদর্শন করার জন্য উপরের উদাহরণ। যদি কলারটি এই ত্রুটির সাথে ম্যাচ করতে এবং হ্যান্ডল করতে দরকার হয়, তাহলে এটি ম্যাচ করার জন্য প্রকাশ করুন 'errors.Is' এর সাথে।
কোন ত্রুটি ম্যাচ নেই
// প্যাকেজ foo
func Open() error {
return errors.New("could not open")
}
// প্যাকেজ bar
if err := foo.Open(); err != nil {
// ত্রুটিটি নিয়ে হ্যান্ডেল করা সম্ভব নয়।
panic("অজানা ত্রুটি")
}
ত্রুটি ম্যাচ
// প্যাকেজ foo
var ErrCouldNotOpen = errors.New("could not open")
func Open() error {
return ErrCouldNotOpen
}
// প্যাকেজ bar
if err := foo.Open(); err != nil {
if errors.Is(err, foo.ErrCouldNotOpen) {
// ত্রুটিটি হ্যান্ডেল করুন
} else {
panic("অজানা ত্রুটি")
}
}
ছাপানোর জন্য ডায়নামিক স্ট্রিং সহ ত্রুটিসমূহের জন্য, যদি কলারটি এটি ম্যাচ না করে তাহলে fmt.Errorf
ব্যবহার করুন। যদি কলারটি সত্যিই এটি ম্যাচ করতে হয় তবে এটি একটি কাস্টম error
ব্যবহার করুন।
কোন ত্রুটি ম্যাচ নেই
// প্যাকেজ foo
func Open(file string) error {
return fmt.Errorf("file %q not found", file)
}
// প্যাকেজ bar
if err := foo.Open("testfile.txt"); err != nil {
// ত্রুটিটি নিয়ে হ্যান্ডেল করা সম্ভব নয়।
panic("অজানা ত্রুটি")
}
ত্রুটি ম্যাচ
// প্যাকেজ foo
type NotFoundError struct {
File string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("file %q not found", e.File)
}
func Open(file string) error {
return &NotFoundError{File: file}
}
// প্যাকেজ bar
if err := foo.Open("testfile.txt"); err != nil {
var notFound *NotFoundError
if errors.As(err, ¬Found) {
// ত্রুটিটি হ্যান্ডেল করুন
} else {
panic("অজানা ত্রুটি")
}
}
লক্ষ্য করুন, যদি আপনি প্যাকেজ থেকে ত্রুটি ভেরিয়েবল বা প্রকার নির্যাতন করেন, তাহলে তারা প্যাকেজের পাবলিক API এর অংশ হয়।
ত্রুটি পরিধান
অন্যান্য একটি মেথড কল করার সময় ত্রুটি ঘটতে পারে তখন সাধারণভাবে সেটা হ্যান্ডেল করার তিনটি উপায় থাকে:
- মূল ত্রুটি যে মূল অবস্থানে return করা।
-
fmt.Errorf
ব্যবহার করুন%w
দিয়ে ত্রুটিতে সংদর্ভ যুক্ত করে শেষ করে return করুন। -
fmt.Errorf
ব্যবহার করুন%v
দিয়ে ত্রুটিতে সংদর্ভ যুক্ত করে শেষ করে return করুন।
যদি অতিরিক্ত সংদর্ভ যুক্ত করার কোন সময় না থাকে, তবে মূল ত্রুটি যে মূল অবস্থানে থাকে return করা হয়। এটি মূল ত্রুটির প্রকার এবং বার্তা সংরক্ষণ করবে। এটি বিশেষত উপযুক্ত যখন নীচের ত্রুটি বিশেষ ধরণের যাতে স
ভুল ব্যবস্থাপনা
যখন কলার কলার থেকে একটি ত্রুটি পেয়ে, তখন সে ত্রুটি সম্পর্কে বুঝে বিভিন্ন উপায়ে তা হ্যান্ডেল করতে পারে। এটা যেমনই হোক,
- যদি কলাকারীরা নির্দিষ্ট ত্রুটির সংজ্ঞা পর্যাপ্তভাবে করে থাকে, তাদের মধ্যে
errors.Is
বাerrors.As
দিয়ে ত্রুটির সঙ্গে মিল দেওয়া, এবং বিভিন্নভাবে উত্তরণ করা - ত্রুটি লগ করা এবং সৌজন্যপূর্ণভাবে ডিগ্রেড করা যাবে যদি ত্রুটি পুনরুদ্ধারযোগ্য হয়
- স্পষ্টভাবে অপরিপন্ন ক্ষেত্রসমূহ সাপেক্ষে একটি ভালো-সংজ্ঞায়িত ত্রুটি রিটার্ন করা
- ত্রুটি, যা প্যাকজ করা হয়েছে বা প্রকটভাবে, রিটার্ন করা
কলার যদিও ত্রুটির সাথে কীভাবে ব্যবস্থা করে, সে সাধারণত প্রতি ত্রুটি শুধু একবার হ্যান্ডেল করতে হবে। উদাহরণস্বরূপ, কলারটি ত্রুটি লগ করে তারপর এর রিটার্ন করবে না, কারণ এর কলারের নিমিত্তের ত্রুটি উপরের কলারগুলি প্রত্যাবর্তন করতে পারে।
উদাহরণ হিসেবে, নিম্নলিখিত পরিস্থিতিগুলি বিবেচনা করুন:
খারাপ: ত্রুটি লগ করে এবং তাকে রিটার্ন করা
অন্য কলারগুলি পরিস্থিতিতে সমকক্ষ ব্যবস্থা নিতে পারে। এটা অ্যাপ্লিকেশন লগে অনেক শব্দাড়িত তৈরি করে যা বিনামূল্যে কমদামি লাভ নেয়।
u, err := getUser(id)
if err != nil {
// খারাপ: বিবরণের জন্য দেখুন
log.Printf("Could not get user %q: %v", id, err)
return err
}
ভাল: ত্রুটি প্যাকজ করে এবং রিটার্ন করা
উপরের স্ট্যাকের ত্রুটিগুলি এই ত্রুটির সঙ্গে ব্যবস্থা নেবে। %w
ব্যবহার করা হয়েছে যাতে যদি প্রাসঙ্গিক হয় তবে তারা ত্রুটির সঙ্গে মিল দিতে পারে।
u, err := getUser(id)
if err != nil {
return fmt.Errorf("get user %q: %w", id, err)
}
ভাল: ত্রুটি লগ করে এবং সৌজন্যপূর্ণভাবে ডিগ্রেড করা
যদি প্রক্রিয়াটি প্রয়োজনীয় না হয়, আমরা অপরিপন্নভাবে অপসারণ করে তা প্রদান করতে পারি। যদি ত্রুটি হয়,
if err := emitMetrics(); err != nil {
// মেট্রিক লিখতে ব্যর্থ হওয়া উচিত নয়
// অ্যাপ্লিকেশনটি ভেঙ্গে নাও।
log.Printf("Could not emit metrics: %v", err)
}
ভাল: ত্রুটির সাথে মিল দেওয়া এবং হ্যান্ডেল করা
যদি কলারী তার চুক্তিতে একটি নির্দিষ্ট ত্রুটি সংজ্ঞা করে থাকে এবং ব্যর্থতা পুনরায় লাভযোগ্য হয়, তবে ঐ ত্রুটির বিন্যাস এবং সৌজন্যপূর্ণভাবে ডিগ্রেড করা নিয়ে তা মিলান। অন্য সমস্ত মামলার জন্য, ত্রুটি প্যাকজ করে এবং রিটার্ন করে দিয়েছে। উপরের স্ট্যাকের ত্রুটিগুলি অন্যান্য ত্রুটিগুলি নিয়ে হ্যান্ডেল করতে পারবে।
tz, err := getUserTimeZone(id)
if err != nil {
if errors.Is(err, ErrUserNotFound) {
// ব্যবহারকারী অস্তিত্বও নেই। UTC ব্যবহার করুন।
tz = time.UTC
} else {
return fmt.Errorf("get user %q: %w", id, err)
}
}
আশাকরি ব্যর্থতা হ্যান্ডেল করা এবং থারসন ফেইলার সম্পর্কে
টাইপ অ্যাসারশন অশুদ্ধ প্রकার শনাক্তির সংকেতে একলা রিটার্ন ভ্যালু দিবে। অতএব, সর্বদা "কমা, ঠিক" পদ্ধতিটি ব্যবহার করুন।
প্রস্তাবিত নয়:
t := i.(string)
প্রস্তাবিত:
t, ok := i.(string)
if !ok {
// ত্রুটি সৌজন্যভাবে হ্যান্ডেল করুন
}
প্যানিক ব্যবহার এড়িয়ে চলুন
প্রোডাকশন পরিবেশে কোড চালানোর সময় প্যানিক অনুবর্তন করা উচিত। প্যানিক হলো প্রাথমিক ক্ষতিকারক ঘটনা এর একমাত্র উৎস। যদি কোন ভুল ঘটে, তবে ফাংশন অবশ্যই তা রিটার্ন করে এবং কলারের কাছে তা কিভাবে হ্যান্ডেল করা উচিত তা তাদের নির্ধারণ করা দরকার।
প্রস্তাবিত নয়:
func run(args []string) {
if len(args) == 0 {
panic("an argument is required")
}
// ...
}
func main() {
run(os.Args[1:])
}
প্রস্তাবিত:
func run(args []string) error {
if len(args) == 0 {
return errors.New("an argument is required")
}
// ...
return nil
}
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
প্যানিক/রিকভার হচ্ছে কোন ত্রুটি হ্যান্ডেলিং রণনীতি নয়। এটি শুধুমাত্র অসমর্থক ঘটনা (উদাহরণস্বরূপ, নিল রেফারেন্স) ঘটলেই প্যানিক হতে হবে। কোড ইনিশিয়ালাইজেশনে: প্রোগ্রাম যে অবস্থার জন্য প্যানিক ঘটিতে হতে পারে, সেই অবস্থা প্রোগ্রাম শুরুর সময়ে হ্যান্ডেল করা উচিত।
var _statusTemplate = template.Must(template.New("name").Parse("_statusHTML"))
টেস্ট কোডে এবারও প্রিয়তম হলো t.Fatal
বা t.FailNow
ব্যবহার করা যেতে যেন বিফলতা সুনির্দিষ্ট করা হয় এবং প্যানিক করা না হয়।
প্রস্তাবিত নয়:
// func TestFoo(t *testing.T)
f, err := os.CreateTemp("", "test")
if err != nil {
panic("failed to set up test")
}
প্রস্তাবিত:
// func TestFoo(t *testing.T)
f, err := os.CreateTemp("", "test")
if err != nil {
t.Fatal("failed to set up test")
}