1 पॉइंट द्वारा GN⁺ 3 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Go बैकएंड डेवलपमेंट की जरूरत से ज्यादा जटिलता को कम करने का एक विकल्प है, और इसके मुख्य फायदे हैं तेज़ compile, single binary deployment, और स्थिर dependency management
  • Go ने decorator, metaclass, macro, trait, monad जैसी जटिल abstraction की बजाय struct, function, interface, goroutine, channel केंद्रित सरल language design चुना है
  • embed, html/template, net/http, database/sql, encoding/json, go test, pprof जैसी standard library और बेसिक tools से ही web app, database, testing, benchmark, profiling तक संभाला जा सकता है
  • goroutine लगभग 2KB लागत वाली stackful execution unit है, और channel, sync.Mutex, race detector, context.Context के जरिए concurrency handling और cancellation propagation को सरलता से संभाला जा सकता है
  • go mod init, go build, scp, systemctl restart तक जाने वाला flow, node_modules, जटिल Docker·Kubernetes configuration, और जरूरत से ज्यादा microservices की बजाय एक Go binary और Postgres केंद्रित सरल deployment की सिफारिश करता है

Go क्यों चुनना चाहिए

  • Go बैकएंड डेवलपमेंट की जरूरत से ज्यादा जटिलता को कम करने का एक विकल्प है, और इसके मुख्य फायदे हैं तेज़ compile, single binary deployment, और स्थिर dependency management
  • जैसे frontend में HTML जरूरत से ज्यादा जटिलता के विकल्प के रूप में बचा रहा, वैसे ही Go भी 10 साल से ज्यादा समय से backend simplification के विकल्प के रूप में मौजूद है
  • सिर्फ एक साधारण form देने या प्रति सेकंड लगभग 40 request वाले CRUD app के लिए Node packages की लंबी सूची, TypeScript build tools, Kubernetes, Rails platform team, और Rust rewrite तक ले आना हद से ज्यादा है
  • Go का फोकस “चालाक abstraction” से ज्यादा पढ़ने में आसान code, deploy किए जा सकने वाले output, और कम operational burden पर है

जानबूझकर उबाऊ बनाई गई language design

  • Go के उबाऊ लगने की वजह इसकी जानबूझकर की गई design है, और यह decorator, metaclass, macro, trait, monad जैसी जटिल abstraction नहीं देता
  • इसके मुख्य building blocks लगभग struct, function, interface, goroutine, channel तक सीमित हैं
  • लक्ष्य इतनी सरलता है कि spec को थोड़े समय में पढ़कर उसी दिन productive code लिखा जा सके
  • यह उबाऊपन team codebase में फायदे का काम करता है
    • पिछले महीने join किया junior भी 2 साल पहले principal द्वारा लिखा code पढ़ सकता है
    • gofmt एक ही format लागू करता है, इसलिए code style की बहस कम होती है
    • language खुद ही codebase में जरूरत से ज्यादा जटिल abstraction ठूंसना मुश्किल बना देती है

standard library framework की भूमिका निभाती है

  • Go में अलग web framework के बिना भी सिर्फ standard library से web app बनाया जा सकता है
  • embed, html/template, net/http का उपयोग करके HTML templates को binary में शामिल कर HTTP handler से render करने वाला app बनाया जा सकता है
package main

import (
    "embed"
    "html/template"
    "net/http"
)

//go:embed templates/*.html
var files embed.FS

var tmpl = template.Must(template.ParseFS(files, "templates/*.html"))

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        tmpl.ExecuteTemplate(w, "index.html", map[string]string{
            "Name": "asshole",
        })
    })

    http.ListenAndServe(":8080", nil)
}
  • यह उदाहरण एक काम करने वाला web app है, और HTML templates compile होकर binary में शामिल हो जाते हैं
  • webpack, Vite, dev server, और विशाल node_modules के बिना go build के बाद सिर्फ एक file deploy की जा सकती है
  • standard library और बेसिक tools से ही मुख्य backend काम संभाले जा सकते हैं
    • database: database/sql
    • JSON: encoding/json
    • दूसरे service call: net/http client
    • concurrent execution: go keyword
    • testing: go test
    • benchmark: go test -bench
    • profiling: pprof

गहराई वाली standard library संरचना

  • io.Reader और io.Writer

    • io.Reader और io.Writer दोनों सिर्फ एक-एक method वाले interface हैं, लेकिन ये पूरे Go ecosystem की महत्वपूर्ण नींव की तरह काम करते हैं
    • HTTP response body को gzip writer से जोड़कर फिर disk file तक pipe करने जैसी composition बहुत कम code में की जा सकती है
    • क्योंकि मुख्य packages यही दो interfaces साझा करते हैं, वही pattern कई जगह बार-बार इस्तेमाल किया जा सकता है
  • context.Context

    • context.Context cancellation propagation का standard तरीका है
    • अगर user browser tab बंद कर दे, तो request context cancel हो जाता है, और उसके साथ database query तथा downstream HTTP calls भी cancel हो सकते हैं
    • goroutine leak या connection pool खा जाने वाली zombie query से बचने के लिए context को पहले argument के रूप में देना और उसका सम्मान करना चाहिए
  • encoding packages

    • encoding/json, encoding/xml, encoding/csv, encoding/binary सब standard library में शामिल हैं
    • struct tag pattern और pointer से decode करने का अनुभव काफी मिलता-जुलता है, इसलिए एक सीख लेने पर बाकी packages भी आसानी से इस्तेमाल किए जा सकते हैं

दर्द कम करने वाला concurrency model

  • goroutine खुद OS thread नहीं है, बल्कि runtime द्वारा OS thread के ऊपर multiplex की जाने वाली stackful execution unit है
  • goroutine की शुरुआती लागत लगभग 2KB है, और laptop पर भी 1 लाख तक बनाए जा सकते हैं
  • channel goroutine के बीच typed pipe की तरह काम करता है; एक तरफ से भेजो, दूसरी तरफ से लो, synchronization runtime संभाल लेता है
  • shared state की जरूरत होने पर sync.Mutex इस्तेमाल किया जा सकता है, और race detector data race पकड़ लेता है
  • parallel HTTP fetcher भी बिना अलग library, framework, या async/await जैसी रस्म के लिखा जा सकता है
results := make(chan string, len(urls))
for _, url := range urls {
    go func(u string) {
        resp, _ := http.Get(u)
        results <- resp.Status
    }(url)
}
for range urls {
    fmt.Println(<-results)
}

असली CRUD route का उदाहरण

  • Postgres से post पढ़कर HTML render करने वाला CRUD प्रकृति का route भी इतना सरल है कि एक स्क्रीन में समा जाए
//go:embed templates/*.html
var tmplFS embed.FS

var tmpl = template.Must(template.ParseFS(tmplFS, "templates/*.html"))

type Post struct {
    ID    int
    Title string
    Body  string
}

func postsHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        rows, err := db.QueryContext(r.Context(),
            "SELECT id, title, body FROM posts ORDER BY id DESC LIMIT 50")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        defer rows.Close()

        var posts []Post
        for rows.Next() {
            var p Post
            if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            posts = append(posts, p)
        }

        tmpl.ExecuteTemplate(w, "posts.html", posts)
    }
}
  • यह उदाहरण database, template, और HTTP handler को एक ही जगह दिखाता है
  • r.Context() SQL query तक पास होता है, इसलिए connection बंद होने पर query भी cancel हो सकती है
  • ORM, DI container, service layer, abstract base class से भरी controllers/ directory के बिना ऊपर से नीचे पढ़कर behavior समझा जा सकता है

dependency management जो आपका weekend खराब न करे

  • go mod init से module शुरू करने पर dependencies go.mod और go.sum में दर्ज हो जाती हैं
  • go.sum वास्तव में प्राप्त किए गए items का cryptographic record है, जिससे यह जांचा जा सकता है कि उम्मीद से अलग dependency तो नहीं आई
  • node_modules directory, dev environment और CI के बीच lockfile drift, peer dependencies, optional dependencies, devDependencies, peerDependenciesMeta जैसी जटिलताएं नहीं हैं
  • अगर offline build चाहिए, तो go mod vendor dependencies को vendor/ directory में डाउनलोड कर देता है, और toolchain इसे अपने आप इस्तेमाल करता है
  • पूरे project और dependencies को एक tarball में पैक किया जा सकता है, जो operations और security review के लिहाज से फायदेमंद है

compiler के साथ आने वाले tools

  • Go के बेसिक tools third-party plugin या अलग config file के बिना ही मिलते हैं
  • gofmt code formatting को standard बनाता है, जिससे formatting बहस और whitespace बदलाव से बढ़ने वाले diff कम होते हैं
  • go vet स्पष्ट गलतियां पकड़ने के लिए इस्तेमाल होता है
  • go test tests चलाता है
  • go test -race race detector के साथ tests चलाकर data race ढूंढता है
  • go test -bench benchmark चलाता है
  • go test -cover test coverage दिखाता है
  • go tool pprof running production service के HTTP endpoint के जरिए CPU और memory usage के flame graph हासिल करने देता है

deployment सिर्फ copy command तक सीमित है

  • Go deployment का मुख्य flow binary build करना, server पर copy करना, और चलाना है
GOOS=linux GOARCH=amd64 go build -o myapp ./cmd/myapp
scp myapp user@server:/usr/local/bin/
ssh user@server 'systemctl restart myapp'
  • इस flow में Dockerfile, multi-stage build, base image CVE alerts, Kubernetes manifest, Helm chart, ArgoCD, service mesh, sidecar के बिना deployment संभव है
  • लगभग 12MB की static-linked binary और 20 lines की systemd unit file से production deployment किया जा सकता है
  • अगर Docker सच में चाहिए, तो Go binary को FROM scratch image में डालना ही काफी है

framework के मुकाबले

  • Rails, Django, Express, Next.js जैसे frameworks के साथ अपने deployment procedure, ORM, admin, middleware, npm warning, routing convention बदलाव जैसी लागतें आती हैं
  • Go binary compile होकर चलती है, और 5 साल बाद भी चल सकने वाली स्थिरता इसका फायदा है
  • जहां frameworks जल्दी obsolete हो सकते हैं या maintainers burnout की शिकायत कर सकते हैं, वहां Go का सरल execution model अलग दिखता है

microservices से बेहतर single Go binary

  • microservices को default choice नहीं बनना चाहिए; पहले monolith लिखना बेहतर है
  • सुझाया गया setup है एक Go binary, एक Postgres, और सिर्फ जरूरत पड़ने पर एक Redis
  • HTML और JSON API को एक ही port पर serve करके single VPS पर चलाना संभव है
  • Go में goroutine की लागत कम है और concurrency मजबूत है, इसलिए प्रति सेकंड 10,000 request तक भी बिना दिक्कत scale किया जा सकता है
  • जब सच में अलग करने की जरूरत पड़े, तो Go monolith के packages को अलग repository में ले जाकर बांटा जा सकता है
  • क्योंकि interfaces पहले से मौजूद होते हैं, language स्वाभाविक रूप से ऐसा structure बनाने देती है जो separation को ध्यान में रखता है

generics और error handling

  • if err != nil bug नहीं, feature है
  • यह हर failure point पर खुद तय करने देता है कि क्या करना है, और errors को छिपाता नहीं है
  • try/catch की nesting errors को खत्म नहीं करती, सिर्फ production outage तक छिपा सकती है
  • generics Go 1.18 में आए थे, और जरूरत होने पर उनका उपयोग किया जा सकता है

निष्कर्ष

  • framework, microservices, Rust rewrite, या कोई नया JavaScript meta-framework हमेशा जरूरी नहीं होता
  • go mod init चलाने, main.go लिखने, templates को embed करने, फिर compile करके deploy करने वाला सरल flow सुझाया जाता है
  • उबाऊ चुनाव ही सही चुनाव है, और Go वही विकल्प है

1 टिप्पणियां

 
GN⁺ 3 시간 전
Lobste.rs की राय
  • संदेशवाहक को दोष नहीं देना चाहता, लेकिन ऐसी ब्लॉग शैली थकाऊ और बचकानी लगती है। शुरुआत में शायद मज़ेदार लगी हो, लेकिन बार-बार होने पर झुंझलाहट घातीय रूप से बढ़ती है
    फिर भी Go अच्छा है। हाल ही में TypeScript प्रोजेक्ट से Go प्रोजेक्ट पर आया हूँ, और मानसिक स्वास्थ्य व काम का मनोबल तेज़ी से बेहतर हो रहा है
    मैं मान लेता हूँ कि if err != nil बग नहीं बल्कि फीचर है, लेकिन फिर भी इसे Go की सबसे बड़ी कमी मानता हूँ। अगर sum types होते, तो runtime type assertion पर निर्भर हुए बिना इसे कहीं ज़्यादा ergonomic बनाया जा सकता था

    • हर चीज़ पर दोनों तरफ़ की बात करके असल में कोई रुख़ न रखने वाले AI भरे हुए लेखों से तो यह बेहतर है
    • पढ़ने में मज़ा आया, लेकिन इस तरह की बहुत-सी पोस्ट मैंने नहीं देखीं। फिर भी “dipshit” की जगह “walnut” कहना ज़्यादा मज़ेदार लगा
      अगर इस अंदाज़ में लिखना है, तो कम से कम गालियाँ थोड़ी चतुर तो हों
    • सहमत। क्या इसे रिपोर्ट करने का कोई तरीका है? यह किसी भी report category में फिट नहीं बैठता
  • दूसरे कमेंट देखकर लगता है यह अलोकप्रिय राय है, और मैं रूखा नहीं लगना चाहता, लेकिन मुझे Go सच में नापसंद है
    Go एक ऐसी भाषा है जिसमें concurrency के लिए efficient runtime के ऊपर ठीक-ठाक syntax चढ़ाया गया है, और Google की ताकत से ecosystem को आगे बढ़ाया गया है। उसके अलावा, मुझे यह भयानक लगती है
    सबसे बड़ी समस्या यह है कि ऐसा लगता है मानो इसे दशकों के programming language design research और यहाँ तक कि व्यावहारिक best practices को जानबूझकर नज़रअंदाज़ करने के लिए बनाया गया हो। दशकों बाद जाकर generics आए, वह भी सही
    मेरा मतलब यह नहीं कि हर जगह dependent types चाहिए, लेकिन एक हद होती है। Go में data modeling, invariants modeling, और code structuring के वे लगभग सभी फीचर नहीं हैं जो एक modern language में होने चाहिए। Rust की learning curve ज़्यादा steep है, लेकिन इस मामले में वह बहुत बेहतर है, और ज़रूरी नहीं कि type system Rust जितना sophisticated ही हो। अगर compile time की चिंता है, तब भी सिर्फ़ सरल लेकिन उपयोगी फीचर्स के साथ तेज़, expressive और sound type system बनाया जा सकता है
    और if err != nil मुझे error handling noise से कोड पाट देने का सबसे ख़राब तरीका लगता है। Go वाले sum types से इतनी चिढ़ क्यों रखते हैं, समझ नहीं आता। इस मामले में तो Java exceptions भी बेहतर हैं। हक़ीक़त यह है कि भाषा में errors को बेहतर ढंग से संभालने की सुविधा नहीं है, इसलिए लोग सबसे ख़राब जुगाड़ को ही फीचर समझ बैठे हैं
    वैसे भी, अगर मूल लेख इतना दंभी न होता तो मैं यह कमेंट भी न लिखता। “बस X इस्तेमाल करो” एक बेवकूफ़ी भरी बात है। जो टूल use case के हिसाब से सही, आरामदायक और productive लगे, वही इस्तेमाल करो। अगर वह Go है तो Go, नहीं तो कुछ और

    • मुझे लगता है language design space में Go की जगह यह है कि बड़े codebase और बड़े संगठन में काम करने वाले junior developers की simplicity को लगभग हर चीज़ से ऊपर रखा गया है। इसलिए कम अनुभव वाला developer भी बहुत context इकट्ठा किए बिना कोड पढ़ सकता है और local बदलाव कर सकता है
      खासकर Google जैसे संगठन में, जहाँ हज़ारों developers होते हैं और किसी टीम या कंपनी में टिके रहने की अवधि छोटी हो सकती है, यह मददगार है
      इस संदर्भ में, खासकर कम अनुभवी developers के लिए advanced type system की अनुपस्थिति कुछ हद तक फ़ायदा भी बन जाती है। क्योंकि basic types और struct जैसी बुनियादी चीज़ों से आगे types के बारे में लगभग सोचना ही नहीं पड़ता। यह data modeling के टूल लगभग नहीं देता, लेकिन बदले में बिना ज़्यादा सोचे बहुत-सा कोड लिखने देता है
      language-level correctness के लिए यह बहुत अच्छा नहीं है। लेकिन बड़े संगठन monorepo analysis, CI/CD, canary testing, observability tools जैसी आसपास की infrastructure पर ज़्यादा निर्भर हो जाते हैं। छोटे संगठनों की तुलना में वही infrastructure ज़्यादा भार उठाती है
      मुझे भी इसी कम cognitive load की वजह से Go कुछ हद तक पसंद है। क्योंकि मैं कुछ प्रोजेक्ट्स में कभी-कभार ही कोड लिखता हूँ, और रोज़ किसी long-term project में गहराई से शामिल नहीं रहता। एक महीने तक न देखे गए codebase में जाकर एक घंटे से कम में काम कर पाना बड़ा फ़ायदा है। हालाँकि अगर मैं किसी जटिल प्रोजेक्ट पर full-time developer होता, तो शायद इतना पसंद न करता
    • Dart भी Google की ऐसी भाषा है जो दशकों के शोध को नज़रअंदाज़ करती हुई नहीं लगती, लेकिन Flutter के बाहर उसे कोई इस्तेमाल नहीं करता। Go ठीक-ठाक है
    • यह लेख एक आक्रामक और दंभी meme format की नकल है। इसलिए साफ़ है कि यह लोगों को उकसाएगा, और मुझे लगता है कि इसका विषय flamewar नहीं बल्कि सही बातचीत के लायक है, इसलिए यह पसंद नहीं आया
      मेरे हिसाब से Go developers ने basics को सही करने पर ध्यान दिया। क्योंकि अब तक की भाषाओं और programming language theory research community ने basics को नज़रअंदाज़ किया है। लोग सबसे व्यापक type system के पीछे भागते हैं, लेकिन type system जितना complex और expressive होता जाता है, उतना ही returns घटते जाते हैं। और type system पर कितना भी ज़ोर दे लो, वह भयानक package management, ऐसे build tools जिनके कारण टीम को नया DSL सीखना पड़े, ऐसे documentation systems जो type information या third-party package docs के लिंक अपने-आप generate नहीं करते, कमज़ोर standard library, गंभीर performance issues, static compilation strategy का अभाव, दर्दनाक build times, steep learning curve, दंडात्मक type system, पढ़ने में कठिन syntax, और बेकार editor integration की भरपाई नहीं कर सकता
      यह कहना कि Go में data modeling के लिए कुछ भी नहीं है, साफ़ तौर पर ग़लत है। किसी भी भाषा में data और invariants को model किया जा सकता है, और Go के पास उन्हें enforce करने के लिए काफ़ी type system है
      Rust शानदार है, और अगर iteration speed महत्वपूर्ण नहीं है, या bare metal पर deploy करना है, या correctness/performance की माँग बहुत सख़्त है, तो यह अच्छा विकल्प है। लेकिन सामान्य application development, खासकर टीम-आधारित development के लिए default के रूप में यह अच्छा नहीं है। if err != nil बहुत टाइप करना पड़ता है, लेकिन मुझे नहीं लगता किसी की bottleneck प्रति सेकंड key presses हैं
    • Rust के अलावा इस तरह के फीचर वाली modern languages बहुत कम हैं। अगर आप Gleam या Swift में प्रोग्राम करना चाहते हैं तो ठीक, लेकिन अगर बात इतनी niche हो जाए तो फिर लगभग Haskell ही इस्तेमाल करने जैसा है
  • यह कहना ग़लत है कि if err != nil बग नहीं बल्कि फीचर है और यह आपको हर संभावित failure point दिखाता है
    असल में यह enforce नहीं करता। अगर आप खुद जाँच न करें, तो error को अनदेखा करना और भी आसान है
    errors को handle या propagate करने के तरीक़े में Rust अब भी एक चमकदार उदाहरण है

    • सही। errcheck जैसी चीज़ न हो तो errors को अनदेखा करना बहुत आसान है, और यह बस मूर्खतापूर्ण है। कम से कम errors को explicit रूप से discard करने के लिए मजबूर करना चाहिए
      शुक्र है, पिछले कुछ सालों में जिन भी Go projects पर मैंने काम किया, उनमें Go की कमज़ोर built-in static checks के ऊपर golangci-lint लगाया गया था। ईमानदारी से कहूँ तो हर Go project में यह अनिवार्य होना चाहिए
    • इस हिस्से में Swift बेहतर है। functional रूप से model वही है, लेकिन Swift में अलग-अलग libraries के बीच error propagation आसान हो जाता है। हालाँकि यह सिर्फ़ pros/cons और design choices का फ़र्क है, इसे सीधा बेहतर या बदतर कहना सही नहीं होगा
  • इस तरह की लिखाई का ट्रेंड मुझे सच में नापसंद है, लेकिन लेख जो मुख्य बात कह रहा है उससे सहमत हूँ
    “Volkswagen के आकार का node_modules नहीं है” यह बात सही है, लेकिन project-local node_modules की जगह बस ~/go में रखा हुआ global package cache है

    • ऊपर से यह home directory भी गंदी करता है। आगे dot तक नहीं है। यह कैसे स्वीकार्य है, समझ नहीं आता
    • दूसरे language ecosystems की dependency tree के आकार पर तंज़ कसने से पहले मैं हमेशा कहना चाहता हूँ कि पहले wc -l go.sum चला कर देखो
  • पेज खोलते ही “Hey, dipshit.” दिखा, और मैंने तुरंत बंद कर दिया

  • यह ज़्यादातर programming language को बढ़ावा देने वाली पोस्टों जैसी ही समस्या रखता है। इसमें मौजूदा भाषा कितनी बढ़िया है, इस पर कम और पहले इस्तेमाल की गई भाषा कितनी भयानक थी, इस पर ज़्यादा ज़ोर है
    लेखक शायद Ruby और TypeScript, शायद Python से भी, बुरी तरह परेशान था और Go ने उसकी वह समस्या हल कर दी। लेकिन मैं Ruby या TypeScript इस्तेमाल नहीं करता, इसलिए यह लेख मुझ पर ख़ास असर नहीं डाल पाया
    वर्षों में मैंने इसके ऐसे दर्जनों रूप पढ़े हैं। Python और JavaScript के विपरीत static types हैं, इसलिए Haskell इस्तेमाल करो। Perl और Erlang के विपरीत single binary के रूप में deploy किया जा सकता है, इसलिए Rust इस्तेमाल करो। Ruby और Tcl के विपरीत सही concurrency और channels हैं, इसलिए Elixir इस्तेमाल करो
    लेखक को अपने लिए सही भाषा मिल गई, यह अच्छी बात है, लेकिन मैं उसकी सलाह नहीं मानूँगा

    • लगता है यहाँ काफ़ी लोग सोचते हैं कि Lobsters के पाठकों को Go बेचना ज़रूरी है। कुछ लोगों पर इसका उल्टा reverse effect भी पड़ सकता है
  • Go के zero values मुझे हमेशा एक कमी लगे हैं। मुझे लगता है कि users को default values explicitly बताने के लिए मजबूर करना बेहतर होता। इसके अलावा, यह OCaml नहीं है, इसे ध्यान में रखें तो भाषा काफ़ी अच्छी है

    • मुझे zero values पसंद हैं और यह काफ़ी चतुर अवधारणा लगती है। लेकिन default value setting feature की कमी सच में खलती है। उदाहरण के लिए, ऐसा JSON object marshal करना बहुत मुश्किल है जिसमें missing bool का मान true होना चाहिए
  • deployment और compilation का अनुभव शानदार है, लेकिन भाषा में खुद लिखना मुझे सच में नापसंद है। हर बार इस्तेमाल करने पर अनुभव बुरा ही रहता है। क्या Go जितनी restrictive न होकर भी deployment experience देने वाली कोई और भाषा है?
    क्या मैं Go में कुछ मिस कर रहा हूँ?
    हाल ही में एक छोटा Rails application deploy किया, और इतनी configuration लगी कि Go का फ़ायदा ज़रूर appreciate हुआ

    • हाल ही में मैंने Rust projects को x86_64-unknown-linux-musl पर compile करना शुरू किया है। इससे ऐसी static binary बनती है जो हर 64-bit Linux मशीन पर बस चल जाती है। फिर उसे scp से कॉपी करके चला देता हूँ
      अभी भी port assign करने और manually start करने की समस्या है, लेकिन थोड़ा-सा systemd जादू करके इसे सुलझाने का इरादा है
    • deployment experience के लिहाज़ से, हमारी कंपनी ने nix bundler के साथ उम्मीद से ज़्यादा सफलता पाई है। संदर्भ के लिए, हम Qt6 GUI app बना रहे हैं
      bundler इस्तेमाल करने पर single executable बनाया जा सकता है, और उसे किसी दूसरी distro वाली Linux मशीन पर भी डाल दो, यहाँ तक कि Qt installed न हो, तब भी user सिर्फ़ executable चलाकर पूरा GUI इस्तेमाल कर सकता है
      हालाँकि OpenGL drivers के साथ दिक्कत होने की caveat है। फिर भी यह संभव है, बस “copy karke chalao” से थोड़ा ज़्यादा जटिल हो जाता है
  • यह दावा करते हुए कि Go concurrency के लिए डिज़ाइन की गई है, उसमें गलती से भी आसानी से share हो जाने वाले raw pointers built-in होना ही सबसे बड़ी समस्या है

  • उबाऊ होना अपने-आप में ठीक है, लेकिन मुझे लगता है Go वास्तव में उबाऊ भाषा बनने में असाधारण रूप से असफल है
    “decorators नहीं हैं” कहा जाता है, लेकिन struct tags और reflection तो हैं। चलाकर देखे बिना समझना मुश्किल होता है कि ये कैसे interact करेंगे
    structural interfaces और reflection दूर बैठे behavior बदल देने के डरावने स्रोत हैं। struct में एक ग़लत method जोड़ दी, और library का behavior पूरी तरह बदल सकता है
    documentation के नज़रिए से भी यह अजीब है। अगर कोई type किसी interface को satisfy करने के इरादे से बनाया गया है, तो उसे साफ़-साफ़ दिखाने से परहेज़ क्यों?
    goroutines को सीधे thread क्यों नहीं कहा जाता, समझ नहीं आता
    channels भाषा का फीचर क्यों होने चाहिए? मुझे लगता है क्योंकि यह मानने में 10 साल देर लगी कि generics सिर्फ़ तीन तरह के types से ज़्यादा जगह भी उपयोगी हैं

    • goroutines thread नहीं हैं, बल्कि thread pool के ऊपर चलने वाला हल्का abstraction हैं। इसलिए हज़ारों goroutines आसानी से बनाई जा सकती हैं
      channels runtime का हिस्सा इसलिए हैं क्योंकि goroutine scheduler को channels के बारे में पता होना चाहिए, ताकि channel non-empty होने पर receiving goroutine को ज़्यादा आसानी से जगाया जा सके। शायद यह तरीका आसान रहा होगा
    • क्योंकि goroutines असल में अतिरिक्त सुविधाओं वाले green threads हैं