Задать вопрос
  • Новичёк без предыдущего опыта в разработке, способен устроиться сейчас Junior Golang Developer?

    EvgenyMamonov
    @EvgenyMamonov
    Senior software developer, system architect
    Если в программировании опыта нет - лучше начните с Python.

    То, что Go простой в изучении язык - это так, но не на столько простой как пишут в рекламе курсов по Go :)

    Еще в рекламе не учитывается один небольшой, но очень важный нюанс - на Go вам предстоит решать задачи, которые будут значительно сложнее тех, которые будут у вас если вы устроитесь Python/PHP/Frontend программистом.

    Смысл в том, что работодателям, которым нужны Go программисты, нужны люди, которые могут работать с большими нагрузками (как минимум).

    Порог входа в Go + highload + микросервисы значительно выше, чем в Python без highload.

    Можно устроиться на работу на Python + Django и при этом даже с базами не особо уметь работать. Но при этом вы сможете выполнить поставленную задачу и по итогу все будут счастливы.

    А вот с go так не получится, вам нужно будет не просто уметь работать с базами, а делать это очень хорошо, понимать как оптимизировать запросы, структуру базы, как и когда нужно применять денормализацию, вы быстро столкнётесь с проблемой, когда база не поместится на одном сервере, т.е. нужно уметь на практике писать сразу горизонтально масштабируемое приложение и т.п.

    Итого: если взять сроки подготовки с нуля до трудоустройства - то, скорее всего, путь Python будет в несколько раз быстрее. Скорее всего во много раз быстрее :)

    Как вариант можно попробовать Fronend: ReactJS, VueJS и т.п. - тоже будет вполне быстрым стартом.

    Ну и посмотрите developer roadmaps:
    https://roadmap.sh/frontend
    https://roadmap.sh/backend
    https://roadmap.sh/golang (тут надо понимать, что до того, как начнёте изучать Go - надо изучить backend в целом)
    Ответ написан
    1 комментарий
  • Как распарсить json в массив структур golang (gin)?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Можно через map[string]Params
    Например вот так
    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    )
    
    type Params struct {
        NativeId string `json:"nativeId"`
        Source   string `json:"source"`
        Url      string `json:"url"`
        Title    string `json:"title"`
        Price    string `json:"price"`
    }
    
    func main() {
        jsonDataBytes := []byte(`{
            "test_2407811386": {"nativeId":"2407811386","source":"test","url":"https://test.ru/123","title":"TEST»","price":"123"},
            "test_2415474304": {"nativeId":"2415474304","source":"test","url":"https://test/234","title":"TEST2»","price":"234"}
        }`)
        objects := map[string]Params{}
        err := json.Unmarshal(jsonDataBytes, &objects)
        if err != nil {
            log.Fatalf("unmarshal error: %s\n", err.Error())
        }
        fmt.Printf("%v\n", objects)
    }
    Ответ написан
    Комментировать
  • Зачем нужны интерфейсы в go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    В вашем примере не хватает самого важного, чтобы стало понятно - вызова функции с параметром типа интерфейс.
    func someFunc(numbers NumberInterface) {
       numbers.Sum()
    }


    Если не будет интерфейсов - вы можете передать только конкретный тип Numbers.
    А если вы создадите тип Numbers2 - то вы не сможете передать его в туже функцию, у которой тип аргумента Numbers.
    Эта проблема отлично решается при помощи интерфейсов.
    Ответ написан
    4 комментария
  • Как сделать автоматическое заполнение форм на сайте через скрипт Golang?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Можно использовать встроенную функцию, так будет надёжнее:
    formData := url.Values{}
    formData.Set("user_forms[0][name]", authDate.fName)
    ...
    resp, err := http.PostForm(postUrl, formData)


    Но судя по коду, вам нужно больше, чем просто отправить данные формы.
    Вы явно хотите пройти аутентификацию, результатом отправки данных в подобную форму, скорее всего, будет cookie, по которому вас дальше сайт будет аутентифицировать.

    Для решения такой задачи будет лучше использовать какой нибудь web scraping framework.

    Например:
    https://github.com/gocolly/colly
    https://github.com/anaskhan96/soup
    Ответ написан
    2 комментария
  • Может кто-то посоветовать книги для создания блокчейна?

    EvgenyMamonov
    @EvgenyMamonov
    Senior software developer, system architect
    Хорошие книги:
    Андреас Антонопулос - Осваиваем биткойн. Программирование блокчейна.
    Имран Башир - Блокчейн архитектура криптовалюты
    Калле Розенбаум - Грокаем технологию Биткоин
    Ответ написан
    Комментировать
  • Выполнение/вызов функции из Go файла при нажатии на кнопку html?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Алгоритм у вас будет примерно таким...
    При нажатии на кнопку у вас будет вызвана функция (обработчик события onClick у кнопки).
    В этой функции вы сделаете AJAX запрос по протоколу HTTP на ваш сервер, где запущено ваше ПО на Go.
    В main.go вы запускаете HTTP сервер, который примет запрос от вашей функции JavaScript, обработает его и ответит.

    Разберём самый простой вариант с методом GET, чтобы вам было проще тестировать.

    На сервере (своём компьютере) запускаете main.go примерно такого содержания
    package main
    
    import (
        "fmt"
        "net/http"
    )
    
    func helloHandler(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, "hello\n")
    }
    
    func main() {
        http.HandleFunc("/hello", helloHandler)
    
        http.ListenAndServe(":8081", nil)
    }

    Этот сервис будет слушать порт 8081 любого IP адреса на сервере, где будет запущен.
    Предположим, что вы тестируете на своём компьютере, в этом случае для проверки вам нужно в браузере откройте url `127.0.0.1:8081/hello`
    После этого вы должны увидеть в ответе просто текст: "hello".
    Когда этот этап будет завершен - вы сможете перейти к вызову этого URL уже из JavaScript.
    Для этого можете использовать то, что вам привычнее, если такого нет - можете воспользоваться этим примером
    const req = new XMLHttpRequest();
      const url='http://127.0.0.1:8081/hello';
      req.open("GET", url);
      req.send();
      req.onreadystatechange=(e)=>{
        console.log(req.responseText)
      }

    PS: Если не понятно или что-то не получится - пишите, помогу разобраться.
    Ответ написан
    21 комментарий
  • Как получить адресс биткоин кошелька?

    EvgenyMamonov
    @EvgenyMamonov
    Senior software developer, system architect
    Попробуйте вот такой вариант
    import ecdsa
    import hashlib
    import base58
    
    # тут ваш ключ
    str_private_key = "L3KijrvAsMuLaCaEMaj2LcHwRpp3Koxkab6ipX7s9LfewoEU69g6"
    
    private_key = base58.b58decode_check(str_private_key)
    private_key = private_key[1:]
    
    signing_key = ecdsa.SigningKey.from_string(private_key, curve = ecdsa.SECP256k1)
    verifying_key = signing_key.get_verifying_key()
    public_key = bytes.fromhex("04") + verifying_key.to_string()
    
    sha256_1 = hashlib.sha256(public_key)
    
    ripemd160 = hashlib.new("ripemd160")
    ripemd160.update(sha256_1.digest())
    
    hashed_public_key = bytes.fromhex("00") + ripemd160.digest()
    checksum_full = hashlib.sha256(hashlib.sha256(hashed_public_key).digest()).digest()
    checksum = checksum_full[:4]
    bin_addr = hashed_public_key + checksum
    
    result_address = base58.b58encode(bin_addr)
    print ("Bitcoin address ", result_address)


    В этом видео https://www.youtube.com/watch?v=tX-XokHf_nI объясняют все детали.
    Ответ написан
  • Для чего нужен указатель структуры в слайсе?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Тут сильно зависит от того, как вы будете использовать данные.

    Например, если вы во все функции передаёте players
    someFunc1(players)
    someFunc2(players)
    someFunc3(players)

    тогда указатели на конкретного player'a использовать особо смысла нет, от этого будет даже хуже, т.к. при создании нового player'a (при взятии адреса) будет задействован сборщик мусора, что вызовет бесполезную доп. нагрузку.

    Если же player структура не маленькая или их очень много, и обработка будет происходить каждого player'a в отдельности + при этом будет использоваться много разных функций, например вот так
    func main() {
        var players[] *Player
        players = append(players, &Player{Id: 1, Name: "Bob"})
        ...
        players = append(players, &Player{Id: 100, Name: "Bob"})
        for i := range players {
            someFunc1(players[i])
            someFunc2(players[i])
            someFunc3(players[i])
            someFunc4(players[i])
            // или одна из someFunc вызывает еще какие то функции и передаёт players туда 
        }
    }

    в этом случае вы получите выигрыш в производительности за счёт того, что при вызове каждой функции будет копироваться лишь указатель (8байт на 64битных процессорах) вместо всей структуры
    Если точнее - вы получите доп. нагрузку за счёт того, что будет задействован сборщик мусора, но за счёт того, что вместо большого объёма данных при каждом вызове функции будет копироваться лишь указатель - вы получите выигрыш, который нивелирует проигрыш от сборщика мусора.

    На всякий случай о том, когда есть смысл использовать указатель, а когда нет
    https://qna.habr.com/q/1046708#answer_2019152
    Ответ написан
    3 комментария
  • Go run автоматическая пересборка при изменении кода?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Я использую github.com/cespare/reflex для автоматической сборки при изменении кода, очень удобно
    Ответ написан
    Комментировать
  • Как обычно логируют краши от паник?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Если говорить про http сервер - я перенял практику из Django.

    У меня есть http middleware, который:
    - вызывает recover
    - нормально отвечает на запрос, а не падает, т.е. 500 + что мы уже знаем об ошибке и работаем над её устранением
    - собирает всю информацию по запросу, http заголовки, cookies, настройки сервера, переменные окружения и т.д. и оповещает меня по почте/телеграм

    Это даёт мне возможность узнавать о проблеме до того, как кто-то напишет в поддержку.

    Люди, в хорошем смысле, удивляются, когда у них что-то не получается, сервер отвечает 500, они не поймут что делать. А я уже узнал об этом, исправил ошибку и написал им письмо о том, что была ошибка, но уже всё исправлено :)
    Ответ написан
    Комментировать
  • Как создать переменую областью видимости пакета,чтобы не видели другие горутины и без их блокировки?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Можно сделать что-то тапа такого.
    Реализация не очень красивая, но, думаю, это даст вам понимание в каком направлении можно двигаться.
    package pkg2
    import "fmt"
    
    type Pkg2 struct {
         str2 []string
    }
    
    func New() *Pkg2 {
        return &Pkg2{
            str2: []string{},
        }
    }
    
    func (p *Pkg2) Test(str string){
        p.str2 = append(p.str2, str)
        fmt.Printf("str:%v %v \n", str, p.str2)
    }


    package main
    
    import (
      "sync"
      "pkg2"
    )
    var wg sync.WaitGroup
    
    func main() {
      text:=[]string{"a1", "a2", "a3", "a4", "a5"}
      for i,str:=range text{
        wg.Add(1)
        p := pkg2.New()
        go start(str, p)
      }
      wg.Wait()
    }
    
    func start(str string, p *pkg2.Pkg2){
        p.Test(str)
        wg.Done()
    }
    Ответ написан
    3 комментария
  • Ефир это solidity, то как называется язык для контрактов на bsc?

    EvgenyMamonov
    @EvgenyMamonov
    Senior software developer, system architect
    Тоже solidity, в BSC работает тот же EVM от эфира.
    Т.е. вы можете даже разрабатывать и деплоить смарт-контракты из Remix.
    Ответ написан
    Комментировать
  • Как вытянуть id и текс сообщения в телеграме на go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Вот тут расписаны все поля структуры Message https://pkg.go.dev/github.com/go-telegram-bot-api/...

    Пример того, как можно получить нужные вам данные
    package main
    
    import (
    	"log"
    
    	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
    )
    
    func main() {
    	bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
    	if err != nil {
    		log.Panic(err)
    	}
    
    	u := tgbotapi.NewUpdate(0)
    	u.Timeout = 60
    
    	updates := bot.GetUpdatesChan(u)
    
    	for update := range updates {
                if update.Message == nil { // не обрабатываем если нет сообщения
                    continue
                }
    
                // ID сообщения, int
                log.Printf("message id: %s\n", update.Message.MessageID)
    
                // так вы можете получить текст сообщения полный (тип string)
                log.Printf("message: %s\n", update.Message.Text)
    
                if update.Message.IsCommand() {
                    // так вы получаете команду
                    log.Printf("command: %s\n", update.Message.Command())
    
                    // так вы получаете аргументы (параметры) команды, string
                    log.Printf("command: %s\n", update.Message.CommandArguments())
                }
            }
        }
    }
    Ответ написан
    Комментировать
  • Не могу загрузить в базу данных mysql значения golang. как это решить?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    У вас не запущен сервис MySQL, либо MySQL не слушает localhost:3306
    Ответ написан
  • Почему Go с горутинами работает на одном ядре?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Горутины выполняются на разных процессорах как и должны, у вас четвёртое число слишком большое, все горутины завершают выполнение, а одна продолжает работать. По этому и создаётся впечатление, что они все работают на одном ядре.

    Чтобы в этом убедиться добавим два fmt.Printf, чтобы получилось вот так
    package main
    
    import (
        "fmt"
        "runtime"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func main() {
        runtime.GOMAXPROCS(8)
        arr := []int{1343434, 1343434300, 234343400, 334343434000, 400434340, 203434340, 4232, 23545, 15535, 353535, 33434434, 5334345, 3533434345, 3535}
        for idx, el := range arr {
            wg.Add(1)
            go test(el, idx)
        }
        wg.Wait()
    }
    
    func test(el int, idx int) {
        fmt.Printf("%d started: %d\n", idx, el)
        for i := 0; i < el; i++ {
            el = el - 1
        }
        fmt.Printf("%d completed: %d\n", idx, el)
        defer wg.Done()
    }


    Вывод будет примерно таким
    4 started: 400434340
    8 started: 15535
    8 completed: 7767
    13 started: 3535
    13 completed: 1767
    6 started: 4232
    6 completed: 2116
    10 started: 33434434
    3 started: 334343434000
    7 started: 23545
    7 completed: 11772
    5 started: 203434340
    12 started: 3533434345
    11 started: 5334345
    2 started: 234343400
    1 started: 1343434300
    11 completed: 2667172
    9 started: 353535
    9 completed: 176767
    0 started: 1343434
    0 completed: 671717
    10 completed: 16717217
    5 completed: 101717170
    4 completed: 200217170
    2 completed: 117171700
    1 completed: 671717150
    12 completed: 1766717172

    При внимательном просмотре станет видно, что нет записи 3 completed.

    меняю элементы с индексами 4 и 5 на такие же числа 334343434000, 334343434000, т.е. делаем чтобы все горутины отработали, но чтобы 3 осталось, т.е. вот так

    arr := []int{1343434, 1343434300, 234343400, 334343434000, 334343434000, 334343434000, 4232, 23545, 15535, 353535, 33434434, 5334345, 3533434345, 3535}


    Запускаем заново и видим, что теперь 3 ядра отлично загружены
    %Cpu0  :  0.3 us,  1.0 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu1  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu2  :  1.7 us,  0.7 sy,  0.0 ni, 97.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu3  :  1.6 us,  2.9 sy,  0.0 ni, 95.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu4  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu5  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu6  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu7  :  5.6 us,  1.0 sy,  0.0 ni, 93.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    Ответ написан
    Комментировать
  • Как можно измерить производительность http сервера?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Для подобного тестового кода можно использовать ab (Apache HTTP server benchmarking tool)

    Например так
    ab -n 10000 -c 1000 http://localhost:8080/

    Где:
    -n это количество запросов, которое нужно сделать
    -с это количество одновременных запросов

    Запустил у себя на одном из серверов, результат вот такой
    Server Software:
    Server Hostname:        localhost
    Server Port:            8080
    
    Document Path:          /
    Document Length:        5 bytes
    
    Concurrency Level:      1000
    Time taken for tests:   0.509 seconds
    Complete requests:      10000
    Failed requests:        0
    Write errors:           0
    Total transferred:      1210000 bytes
    HTML transferred:       50000 bytes
    Requests per second:    19627.39 [#/sec] (mean)
    Time per request:       50.949 [ms] (mean)
    Time per request:       0.051 [ms] (mean, across all concurrent requests)
    Transfer rate:          2319.25 [Kbytes/sec] received

    Т.е. при 1000 одновременных запросов сервер сможет обрабатывать в среднем 19627 запросов в секунду

    Но важно понимать, что в реальном проекте у вас будет не один endpoint, и что каждый endpoint, в зависимости от того, что он будет делать - будет показывать разный RPS.

    Например если сейчас вы добавите еще один endpoint и будете делать запросы в базу для формирования ответа - RPS будет значительно меньше.
    Ответ написан
  • Как узнать цену токенов через web3?

    EvgenyMamonov
    @EvgenyMamonov
    Senior software developer, system architect
    В смарт-контракте самого токена (ERC-20), в котором вы получаете баланс, информации о цене нет.
    Информацию о цене нужно получать на биржах, т.е. там, где эти токены торгуются.

    Самый простой способ получения цены - по API биржи, обычно это HTTP или WebSocket.
    Например у тех пар, что торгуются на бинанс можно получить вот так https://binance-docs.github.io/apidocs/spot/en/#sy...

    Если же нужно получать цены с децентрализованной биржи или получать цену внутри своих смарт-контрактов - то нужно брать цены из смарт-контрактов самих DEX.

    Например для Pancake вот так можно узнать цену
    // 0.0001 - кол-во токена1
    // 18 - кол-во знаков после запятой
    const token1AmountIn = ethers.utils.parseUnits('0.0001', 18)
    const amounts = await pancakeRouterV2Contract.getAmountsOut(token1AmountIn, [Token1Address, Token2Address])
    // в amounts[1] будет кол-во токенов2, которые можно получить после обмена на кол-во токена 1
    const price = amounts[1] / token1AmountIn


    Код контракта Pancake Router можно посмотреть тут https://bscscan.com/address/0x10ed43c718714eb63d5a...
    Ответ написан
    Комментировать
  • Является ли передача переменной по указателю затратной операцией?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Я видел эти же или похожие бенчмарки, которые приведены в этой статье, год или два назад.
    Тут важно отметить, что методика тестирования в статье не учитывает очень важный момент - там передача значения происходит всего один раз, т.е. функцию вызвали один раз и на том всё.

    Но часто бывает так, что данные приходится передавать многократно.

    Например есть функция, которая извлекает из базы данные, вторая функция обрабатывает эти данные, во время работы второй функции - вызываются еще несколько разных функций и все эти данные в каждую из них передаются, а потом еще все эти данные передаются в JSON сериализатор и т.д.
    Т.е. одни и те же данные передаются много раз из функции в функцию.

    Если не использовать передачу по указателю - данные будут копироваться каждый раз при вызове функции.
    В таком случае передача данных по указателю однозначно отработает быстрее даже с учётом того, что будет задействован сборщик мусора.

    В общем если структуры небольшого размера и используются всего один-два раза - быстрее отработает передача/создание такой структуры по значению как и написано в статье.

    Но если эти данные нужно будет передавать во много разных функций - то в большинстве случаев передача через указатель будет быстрее, даже с учётом того, что garbage collector это ресурсоёмко.
    Ответ написан
    Комментировать
  • Как сделать редирект всех запросов к домену на другой домен, без конкретной uri?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Для этого лучше сделать middleware и уже там делать всё, что вам нужно
    Т.е. либо дальше передаёте управление, либо редирект и завершение обработки запроса.
    https://github.com/gin-gonic/gin#custom-middleware
    Что то типа такого
    func DomainRedirect() gin.HandlerFunc {
        return func(c *gin.Context) {
            if ваше_условие {
                c.Redirect(302, "https://wifer-test.ru/" + c.Request.URL.String())
                return
            }
            c.Next()
        }
    }
    ....
    r := gin.New()
    r.Use(DomainRedirect())
    Ответ написан
  • В чем сложность поддержки проектов на Go?

    EvgenyMamonov
    @EvgenyMamonov Куратор тега Go
    Senior software developer, system architect
    Более четырёх лет пишу на Go, лично для меня поддерживать проекты на других языках сложнее ))
    До Go много лет писал на Perl/PHP/Python/Java/C/Ruby on rails/JavaScript и "крутил" еще не мало чего.
    Сейчас пишу только на Go и Python.

    Основная сложность в Go - это то, что если вы начинаете писать "криво" - то писать так очень трудно :))
    Подход к реализации в Go достаточно непривычный для тех, кто приходит из скриптовых языков.
    Например запрет циклических импортов - это самое первое, что "взрывает" мозг :)
    Нужно время чтобы адаптироваться после скриптовых языков.

    Про обработку ошибок - это да, это, пожалуй, единственное что мне не нравится в Go.
    Для себя я решил эту проблему за 1-2 часа :) и больше меня это не беспокоит.

    По ООП - в Go оно есть, лично мне оно нравится намного больше, чем ООП в других языках ))
    Всё, что реально нужно - всё есть, но при этом ничего лишнего нет.
    Интерфейсы - просто прекрасны :)) Каналы, горутины - это просто "счастье" :))

    А если объективно - то я бы не стал говорить о сложности поддержки проекта применимо к какому то конкретному языку.

    Как правило сложность поддержки возникает там, где нормальная архитектура не заложена в проект.
    Т.е. проект как могла так и писала куча людей плюс, как обычно, сделать нужно было побыстрее )), от этого никто вообще не думал об архитектуре и получилось то, что получилось :))
    Про покрытие тестами и документацию мы вообще не говорим )))

    А когда в таком проекте нужно что-то доработать или исправить ошибку, то почти всегда очень не просто найти то место, где нужно править, и после правок в одном месте, как правило, что-то ломается в другом :)

    Как минимум, нужно соблюдать принципы SOLID, иначе код получается, мягко говоря, не поддерживаемым.
    Но понимание этих принципов так же приходит с опытом, их нельзя научиться соблюдать просто прочитавши книгу или статью. Нужно сделать несколько проектов используя эти принципы, написать криво, понять как было бы правильно, всё переделать и так несколько раз.
    Тогда, со временем, начнёт получаться понятный и легко поддерживаемый код.

    Так мы приходим к тому, что если опыта нет - тогда проект поддерживать будет достаточно тяжело не взирая на язык и т.д.

    Хочется добавить, что как бы не писали про Go, что он простой и т.д. - он явно сложнее Python/PHP и т.д.
    Это еще один повод сказать, что поддерживать код на Go сложно ))

    Также стоит учитывать, что проекты которые пишут на Go зачастую сложнее, чем проекты для которых выберут скриптовый язык. Go выбирают когда планируются большие нагрузки, параллельная обработка чего-либо и т.д., а это, в свою очередь, дополнительно усложняет проект.
    Ответ написан
    7 комментариев