دا د "Clean Code in Go" لړۍ درې مقاله ده. مخکینی برخو: Clean Code: په Go کې د فعالیتونو او غلطیونو په کارولو: له خوځښت څخه تر clarity [Part 1] Clean Code په چلولو کې (د 2 برخه): جوړښتونه، روشونه، او د وارثولو په اړه ترکیب د انټرنیټونه - Go's Secret Weapon زه ټیمونه وګورئ چې د 20 میټرو انټرنیټونه جوړ کړي چې د آزموینې، د خنډ کولو یا د ساتنې لپاره غیر ممکن دي. بيا دوی پوهیږي چې څنګه چې د Go احساس کوي. "د انټرنیټونه راټول، جوړښتونه راټول کړئ" - که تاسو یوازې یو Go انډیوم ولرئ، دا احتمالا دا دی. خو څنګه چې دا ډیر مهم دی؟ او څنګه چې د واحد میټرو انټرنیټونه په Go کې نږدې استثنا نه دي؟ د عادي انټرنېټ غلطۍ چې ما په لټه کې شتون لري: - د 10 + روشونو سره انټرنیټونه: ~ 45٪ د شرکت Go کوډ - د پیژندنې ځای کې انټرنیټونه تنظیم کول: ~70٪ بسته - د کنترول ډولونه په ځای کې د انټرنېټونو ته ورسیږي: ~ 55٪ دندهونه - په هر ځای کې د خالی انټرنېټ کارولو: ~30٪ APIs - nil interface vs nil pointer confusion: ~25٪ subtle بګونه د Go سره د 8 کلونو کار کولو وروسته او د انټرنېټ په اړه د بیلابیلو ستونزو ډبرګون کولو وروسته، زه کولی شئ وايي: د انټرنېټونو په مناسب توګه کارول د کوډ چې د ژور سره مبارزه کوي او کوډ چې د اوبو په څیر جریان کوي تر منځ د فرق دی. د انټرنیټ رضایت: د بالغانو لپاره د ډک ټیپینګ په Go کې، یو ډول په اتوماتيک ډول کې د انټرنیټ سره پوره کوي، پرته له ځانګړي اعلاناتو پرته: // Interface defines a contract type Writer interface { Write([]byte) (int, error) } // File satisfies Writer automatically type File struct { path string } func (f *File) Write(data []byte) (int, error) { // implementation return len(data), nil } // Buffer also satisfies Writer type Buffer struct { data []byte } func (b *Buffer) Write(data []byte) (int, error) { b.data = append(b.data, data...) return len(data), nil } // Function accepts interface func SaveLog(w Writer, message string) error { _, err := w.Write([]byte(message)) return err } // Usage - works with any Writer file := &File{path: "/var/log/app.log"} buffer := &Buffer{} SaveLog(file, "Writing to file") // OK SaveLog(buffer, "Writing to buffer") // OK کوچني انټرنیټونه: د ساده په قدرت د واحد طریقې قانون د Go معياري کتابتون وګورئ: type Reader interface { Read([]byte) (int, error) } type Writer interface { Write([]byte) (int, error) } type Closer interface { Close() error } type Stringer interface { String() string } یو لاره - یو انټرنیټ. چرا؟ // BAD: large interface type Storage interface { Save(key string, data []byte) error Load(key string) ([]byte, error) Delete(key string) error List(prefix string) ([]string, error) Exists(key string) bool Size(key string) (int64, error) LastModified(key string) (time.Time, error) } // Problem: what if you only need Save/Load? // You'll have to implement ALL methods! // GOOD: small interfaces type Reader interface { Read(key string) ([]byte, error) } type Writer interface { Write(key string, data []byte) error } type Deleter interface { Delete(key string) error } // Interface composition type ReadWriter interface { Reader Writer } type Storage interface { ReadWriter Deleter } // Now functions can require only what they need func BackupData(r Reader, keys []string) error { for _, key := range keys { data, err := r.Read(key) if err != nil { return fmt.Errorf("read %s: %w", key, err) } // backup process } return nil } // Function requires minimum - only Reader, not entire Storage Interface Separation اصول په عمل کې // Instead of one monstrous interface type HTTPClient interface { Get(url string) (*Response, error) Post(url string, body []byte) (*Response, error) Put(url string, body []byte) (*Response, error) Delete(url string) (*Response, error) Head(url string) (*Response, error) Options(url string) (*Response, error) Patch(url string, body []byte) (*Response, error) } // Create focused interfaces type Getter interface { Get(url string) (*Response, error) } type Poster interface { Post(url string, body []byte) (*Response, error) } // Function requires only what it uses func FetchUser(g Getter, userID string) (*User, error) { resp, err := g.Get("/users/" + userID) if err != nil { return nil, fmt.Errorf("fetch user %s: %w", userID, err) } // parse response return parseUser(resp) } // Testing becomes easier type mockGetter struct { response *Response err error } func (m mockGetter) Get(url string) (*Response, error) { return m.response, m.err } // Only need to mock one method, not entire HTTPClient! د انټرنېټونو قبول کول، جوړښتونه راټول کړئ چرا دا مهمه ده // BAD: returning interface func NewLogger() Logger { // Logger is interface return &FileLogger{ file: os.Stdout, } } // Problems: // 1. Hides actual type // 2. Loses access to type-specific methods // 3. Complicates debugging // GOOD: return concrete type func NewLogger() *FileLogger { // concrete type return &FileLogger{ file: os.Stdout, } } // But ACCEPT interface func ProcessData(logger Logger, data []byte) error { logger.Log("Processing started") // processing logger.Log("Processing completed") return nil } د عملی مثال // Repository returns concrete types type UserRepository struct { db *sql.DB } func NewUserRepository(db *sql.DB) *UserRepository { return &UserRepository{db: db} } func (r *UserRepository) FindByID(id string) (*User, error) { // SQL query return &User{}, nil } func (r *UserRepository) Save(user *User) error { // SQL query return nil } // Service accepts interfaces type UserFinder interface { FindByID(id string) (*User, error) } type UserSaver interface { Save(user *User) error } type UserService struct { finder UserFinder saver UserSaver } func NewUserService(finder UserFinder, saver UserSaver) *UserService { return &UserService{ finder: finder, saver: saver, } } // Easy to test - can substitute mocks type mockFinder struct { user *User err error } func (m mockFinder) FindByID(id string) (*User, error) { return m.user, m.err } func TestUserService(t *testing.T) { mock := mockFinder{ user: &User{Name: "Test"}, } service := NewUserService(mock, nil) // test with mock } د انټرنېټ composition د انټرنیټونو // Base interfaces type Reader interface { Read([]byte) (int, error) } type Writer interface { Write([]byte) (int, error) } type Closer interface { Close() error } // Composition through embedding type ReadWriter interface { Reader Writer } type ReadWriteCloser interface { Reader Writer Closer } // Or more explicitly type ReadWriteCloser interface { Read([]byte) (int, error) Write([]byte) (int, error) Close() error } Type Assertions او Type Switches // Type assertion - check concrete type func ProcessWriter(w io.Writer) { // Check if Writer also supports Closer if closer, ok := w.(io.Closer); ok { defer closer.Close() } // Check for buffering if buffered, ok := w.(*bufio.Writer); ok { defer buffered.Flush() } w.Write([]byte("data")) } // Type switch - handle different types func Describe(i interface{}) string { switch v := i.(type) { case string: return fmt.Sprintf("String of length %d", len(v)) case int: return fmt.Sprintf("Integer: %d", v) case fmt.Stringer: return fmt.Sprintf("Stringer: %s", v.String()) case error: return fmt.Sprintf("Error: %v", v) default: return fmt.Sprintf("Unknown type: %T", v) } } nil Interfaces: د Gotchas // WARNING: classic mistake type MyError struct { msg string } func (e *MyError) Error() string { return e.msg } func doSomething() error { var err *MyError = nil // some logic return err // RETURNING nil pointer } func main() { err := doSomething() if err != nil { // TRUE! nil pointer != nil interface fmt.Println("Got error:", err) } } // CORRECT: explicitly return nil func doSomething() error { var err *MyError = nil // some logic if err == nil { return nil // return nil interface } return err } د نيلې لپاره چمتو // Safe nil check for interface func IsNil(i interface{}) bool { if i == nil { return true } // Check if value inside interface is nil value := reflect.ValueOf(i) switch value.Kind() { case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan, reflect.Func: return value.IsNil() } return false } د معياري کتابتون څخه حقیقي مثالونه io.Reader/Writer - د هر څه بنسټ // Copy between any Reader and Writer func Copy(dst io.Writer, src io.Reader) (int64, error) // Works with files file1, _ := os.Open("input.txt") file2, _ := os.Create("output.txt") io.Copy(file2, file1) // Works with network conn, _ := net.Dial("tcp", "example.com:80") io.Copy(conn, strings.NewReader("GET / HTTP/1.0\r\n\r\n")) // Works with buffers var buf bytes.Buffer io.Copy(&buf, file1) http.Handler — Web Server in One Method type Handler interface { ServeHTTP(ResponseWriter, *Request) } // Any type with ServeHTTP method can be a handler type MyAPI struct { db Database } func (api MyAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/users": api.handleUsers(w, r) case "/posts": api.handlePosts(w, r) default: http.NotFound(w, r) } } // HandlerFunc - adapter for regular functions type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) // call the function } // Now regular function can be a handler! http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!") }) د Patterns او Anti-Patterns د نمونوي: شرایطي انټرنیټ اپلوز // Optional interfaces for extending functionality type Optimizer interface { Optimize() error } func ProcessData(w io.Writer, data []byte) error { // Basic functionality if _, err := w.Write(data); err != nil { return err } // Optional optimization if optimizer, ok := w.(Optimizer); ok { return optimizer.Optimize() } return nil } Anti-Pattern: ډیر عمومي انټرنیټونه // BAD: interface{} everywhere func Process(data interface{}) interface{} { // type assertions everywhere switch v := data.(type) { case string: return len(v) case []byte: return len(v) default: return nil } } // GOOD: specific interfaces type Sized interface { Size() int } func Process(s Sized) int { return s.Size() } د عملی ټیپونه د مصرفي سایټ کې انټرنیټونه، نه پیژندنه د کوچني انټرنیټونه د لویانو ترټولو غوره کړئ د انټرنېټ composition لپاره embedding کارول د اړتيا پرته د انټرنېټونه نه ورکړئ په یاد ولرئ nil interface vs nil pointer د ډول ادعاونو په احتیاط سره کارول د انټرنېټ {} د وروستۍ لارښود ده، نه لومړی د انټرنېټ Checklist - د انټرنیټ د 1-3 طریقو په حد لري - د کارولو په نزدیک کې د انټرنېټ تعریف شوی - دندهونه انټرنیټونه، نه konkretes ډولونه قبول کوي - دندهونه د کنټرول ډولونه، نه انټرنیټونه ته ورسیږي - په انټرنېټونو کې نه کارول شوي طریقې - ډول ادعاونه په هر دوو صورتونو کې کار کوي (OK / نه OK) - انټرنیټ {} یوازې کله چې اړتیا لري کارول د پایلو د انټرنیټونه د لنډیز دی چې Go پروګرامونه یوځای کوي. دوی د انعطاف، ازمايښت او ساتلو وړ کوډ وړوي، د پیچلي وارثولو ژرارتونو پرته. یاد وکړئ: په Go کې، انټرنیټونه غیرقانوني، کوچنی، او composable دي. په راتلونکي مقاله کې، موږ به د بستهونو او بستې په اړه خبرې وکړي: څنګه د کوډ جوړ کړي نو د وارداتو ګراګون فلیټ دی او بستې یوځای دي. ستاسو د انټرنېټ ډیزاین په اړه څه دي؟ څومره کوچني ډیر کوچني ده؟ څومره تاسو پوه شئ چې څومره یو انټرنېټ جوړ کړئ په مقابل کې د کارولو سره د کارتنونو ډول په کارولو سره؟ ستاسو تجربه په تبصره کې شریک کړئ!