परिचय: आर्किटेक्चर विलासिता क्यों नहीं, बल्कि आवश्यकता क्यों है
\n\nजब आप Go में लिखना शुरू करते हैं, तो सब कुछ सरल लगता है: गोरूटीन उड़ती हैं, चैनल गूंजते हैं, और कंपाइलर गति से खुश करता है। लेकिन एक-दो महीने बीतते हैं, और आपका pet-प्रोजेक्ट package main के साथ 3000 लाइनों के राक्षस में बदल जाता है और प्रार्थना करता है "बस गिरे नहीं"। परिचित लगता है?
Go शक्तिशाली उपकरण देता है, लेकिन सख्त सीमाएँ नहीं थोपता। यह फायदा और नुकसान दोनों है। स्पष्ट आर्किटेक्चर के बिना, आप जल्दी से अपनी गोरूटीन में उलझ जाएंगे। यहीं पर Go में आर्किटेक्चरल पैटर्न मदद करते हैं — डिज़ाइन की सामान्य समस्याओं के सिद्ध समाधान।
\n\nइस लेख में, हम चार प्रमुख पैटर्न पर चर्चा करेंगे जो वास्तव में जीवन को आसान बनाते हैं: Repository, Service Layer, Worker Pool और Pipeline। आप कोड उदाहरण देखेंगे, समझेंगे कि कब कौन सा पैटर्न लागू करना है, और उन्हें तुरंत अपने प्रोजेक्ट में शामिल कर सकेंगे। चलिए शुरू करते हैं!
\n\n1. Repository Pattern: बिज़नेस लॉजिक को डेटाबेस से अलग करना
\n\nपहला पैटर्न जो हर Go डेवलपर को सीखना चाहिए — Repository। इसका सार सरल है: बिज़नेस लॉजिक और डेटा स्टोरेज (DB, फ़ाइलें, बाहरी API) के बीच एक परत बनाना।
\n\nइसकी आवश्यकता क्यों है?
\n- \n
- परीक्षण क्षमता: वास्तविक DB को आसानी से मॉक से बदला जा सकता है। \n
- लचीलापन: PostgreSQL से MongoDB पर जाना? केवल रिपॉजिटरी बदलें। \n
- कोड की सफाई: handler को नहीं पता कि डेटा कहाँ से आ रहा है — यह रिपॉजिटरी का काम है। \n
कार्यान्वयन का उदाहरण
\nमान लीजिए, हमारे पास एक उपयोगकर्ता मॉडल है:
\n\ntype User struct {\n ID int64\n Name string\n Email string\n}\n\nहम रिपॉजिटरी इंटरफ़ेस परिभाषित करते हैं:
\n\ntype UserRepository interface {\n GetByID(ctx context.Context, id int64) (*User, error)\n Create(ctx context.Context, user *User) error\n Update(ctx context.Context, user *User) error\n Delete(ctx context.Context, id int64) error\n}\n\nऔर PostgreSQL के लिए इसका कार्यान्वयन:
\n\ntype PostgresUserRepo struct {\n db *sql.DB\n}\n\nfunc (r *PostgresUserRepo) GetByID(ctx context.Context, id int64) (*User, error) {\n user := &User{}\n err := r.db.QueryRowContext(ctx, "SELECT id, name, email FROM users WHERE id = $1", id).\n Scan(&user.ID, &user.Name, &user.Email)\n if err != nil {\n return nil, fmt.Errorf("get user by id: %w", err)\n }\n return user, nil\n}\n\nअब आपका handler या सेवा केवल UserRepository इंटरफ़ेस के साथ काम करता है, न कि किसी विशिष्ट DB के साथ। यही है Go में Repository आर्किटेक्चरल पैटर्न क्रियान्वयन में।
2. Service Layer: बिज़नेस लॉजिक नियंत्रण में
\n\nयदि Repository डेटा के लिए जिम्मेदार है, तो Service Layer बिज़नेस नियमों के लिए। यह पैटर्न बिखरे हुए ऑपरेशनों को सार्थक क्रियाओं में एकत्रित करता है।
\n\nService Layer के बिना समस्या
\nअक्सर मैं ऐसा कोड देखता हूँ जहाँ handler सब कुछ करता है: अनुरोध को मान्य करना, अधिकार जाँचना, DB में लिखना और लॉग करना। यह एकल जिम्मेदारी सिद्धांत (SRP) का उल्लंघन करता है।
\n\nइसे कैसे ठीक करें?
\nहम सेवा परत शुरू करते हैं:
\n\ntype UserService interface {\n Register(ctx context.Context, name, email string) (*User, error)\n GetProfile(ctx context.Context, userID int64) (*User, error)\n}\n\ntype userService struct {\n repo UserRepository\n mail MailSender\n}\n\nfunc (s *userService) Register(ctx context.Context, name, email string) (*User, error) {\n // 1. वैलिडेशन\n if name == "" || email == "" {\n return nil, ErrInvalidInput\n }\n\n // 2. बिज़नेस लॉजिक: जाँचें कि ईमेल पहले से नहीं है\n existing, _ := s.repo.GetByEmail(ctx, email)\n if existing != nil {\n return nil, ErrEmailAlreadyExists\n }\n\n // 3. उपयोगकर्ता बनाएँ\n user := &User{Name: name, Email: e