Содержание

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


Обертки обработчиков HTTP


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


Но отбросим это в сторону, допустим, нам потребовалась аутентификация для определенного URL. Сейчас наш обработчик главной страницы выглядит так:


func indexHandler(m *model.Model) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, indexHTML)
    })
}

Мы можем написать функцию, которая принимает http.Handler в качестве аргумента и возвращает (другой) http.Handler. Возвращенный обработчик проверяет, аутентифицирован ли пользователь, с помощью m.IsAuthenticated() (неважно, что конкретно там происходит) и перенаправляет пользователя на страницу входа или выполняет оригинальный обработчик, вызывая его метод ServeHTTP().


func requireLogin(h http.Handler, m *model.Model) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !m.IsAuthenticated(r) {
            http.Redirect(w, r, loginURL, http.StatusFound)
            return
        }
        h.ServeHTTP(w, r)
    })
}

С учетом этого, регистрация обработчика теперь будет выглядеть так:


   http.Handle("/", requireLogin(indexHandler(m), m))

Таким способом можно обернуть обработчики в любое необходимое количество слоев и этот очень гибкий подход. Все, начиная от установки заголовков до сжатия вывода, может быть выполнено с помощью обертки. Также отмечу, что мы можем передавать любые нужные нам аргументы, например, нашу *model.Model.


Параметры в URL


В какой-то момент нам могут понадобиться параметры в URL, например, /Person/3, где 3 — это идентификатор человека. Стандартная библиотека Go ничего для этого не предоставляет, оставляя эту задачу в качестве упражнения для разработчика. Программный компонент, ответственный за такую штуку, называется Mux, т.е. «мультиплексор», или «маршрутизатор», и его можно заменить нестандартной реализацией. Маршрутизатор также реализует метод ServeHTTP(), что означает, что он удовлетворяет интерфейсу http.Handler, то есть он является обработчиком.


Очень популярным вариантом маршрутизатора является Gorilla Mux. Ему можно делегировать целые пути в тех местах, где требуется больше гибкости. Например, мы можем решить, что все, от /person и ниже, обрабатывается маршрутизатором Gorilla, и мы хотим, чтобы все это еще было аутентифицировано, тогда это может выглядеть так:


    // import "github.com/gorilla/mux"
    pr := mux.NewRouter().PathPrefix("/person").Subrouter()
    pr.Handle("/{id}", personGetHandler(m)).Methods("GET")
    pr.Handle("/", personPostHandler(m)).Methods("POST")
    pr.Handle("/{id}", personPutHandler(m)).Methods("PUT")
    http.Handle("/person/", requireLogin(pr))

Примечание: я обнаружил, что слэши в конце важны, а правила на счет того, когда они требуются, немного запутаны.


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


Обработка статики


Одна из самых изящных вещей в Go — это то, что скомпилированная программа представляет собой единственный двоичный файл, а не большую кучу файлов, как это часто бывает с большинством скриптовых языков и даже с некоторыми компилируемыми. Но если наша программа зависит от статических файлов (JS, CSS, изображений и других файлов), нам нужно будет скопировать и их на сервер во время развертывания.


Мы можем сохранить эту характерную особенность — «один бинарник» — нашей программы, включив статику как часть самого двоичного файла. Для этого существует проект go-bindata и его племянник go-bindata-assetsfs.


Поскольку упаковка статики в двоичный файл несколько выходит за пределы того, что может сделать go build, нам понадобится какой-то скрипт, который об этом позаботится. Лично я предпочитаю использовать проверенный и "трушный" make, и не так уж редко можно встретиться с «Makefile» в проекте Go.


Вот пример подходящего правила Makefile:


ASSETS_DIR = "assets"
build:
    @export GOPATH=$${GOPATH-~/go} &&     go get github.com/jteeuwen/go-bindata/... github.com/elazarl/go-bindata-assetfs/... &&     $$GOPATH/bin/go-bindata -o bindata.go -tags builtinassets ${ASSETS_DIR}/... &&     go build -tags builtinassets -ldflags "-X main.builtinAssets=${ASSETS_DIR}"

Это правило создает файл bindata.go, который помещается в тот же каталог, где находится main.go, соответственно, он становится частью пакета main. main.go как-то узнает, что статические файлы встроены, — это получается с помощью трюка -ldflags "-X main.builtinAssets=${ASSETS_DIR}", так мы можем присваивать значения переменным на этапе компиляции. Это значит, что теперь наш код может проверять значение builtinAssets, чтобы решить, что делать дальше, например:


    if builtinAssets != "" {
        log.Printf("Running with builtin assets.")
        cfg.UI.Assets = &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: builtinAssets}
    } else {
        log.Printf("Assets served from %q.", assetsPath)
        cfg.UI.Assets = http.Dir(assetsPath)
    }

Вторая важная вещь заключается в том, что мы определяем build tag с именем builtinassets. Мы также сообщаем go-bindata о нем, что означает «скомпилируй меня, только когда установлен builtinassets», а это позволяет контролировать, при каких условиях необходимо компилировать bindata.go (который содержит нашу статику в виде кода Go).


Предварительная транспиляция JavaScript


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


  • В принципе, вы можете пойти на уступки — установить npm и настроить файл package.json.


  • Как только npm установлен, банально устанавливается компилятор командной строки Babel — babel-cli, который является одним из способов транспиляции JavaScript.


  • Более сложный, в чем-то разочаровывающий, но в конечном счете более гибкий способ — использовать webpack. Webpack будет не только претранспиливать JS-код, но и объединит все JS-файлы в один, а также минимизирует его.


  • Я был удивлен тому, насколько сложно было обеспечить функциональность импорта модулей в JavaScript. Проблема в том, что есть стандарт ES6 для ключевых слов import и export, но нет реализации, и даже Babel предполагает, что реализовывать их для вас будет кто-нибудь другой. В конце концов, я остановился на SystemJS. Некоторое осложнение с SystemJS заключается в том, что внутрибраузерная транспиляция Babel должна быть чем-то, понятным для SystemJS, поэтому мне пришлось использовать его плагин для Babel. Webpack, в свою очередь (если я правильно понял), предоставляет свою собственную реализацию поддержки модулей, поэтому при упаковке SystemJS не нужен. В любом случае, это было довольно неприятно.

Заключение


Я бы сказал, что в примере, который я описываю в этой серии из четырех частей, Go безусловно блистает, а вот JavaScript — не особо. Но как только я преодолел начальные трудности с тем, чтобы заставить все это заработать, React/JSX оказался простым и, возможно, даже приятным для работы.


На этом я, пожалуй, закончу. Надеюсь, статьи оказались вам полезными.

Поделиться с друзьями
-->

Комментарии (52)


  1. jehy
    28.05.2017 15:22
    +16

    Прочитал внимательно все четыре части, впечатление осталось странное.


    1. Из преимуществ Go заметил (видимо, основное) указание (раз пять) на то, что на выходе один бинарник, а не куча файликов. Ну… Ээээ… Это действительно актуально?


    2. Автор не может решить фронтовые задачи без установки npm и его пакетов. Но при этом у него "Go блистает, а JavaScript не очень".


    3. Автор преподносит практику написания прямых SQL запросов как некое позитивное новаторство и хорошую практику, которой больше нигде нет… То же самое и насчёт фреймворков, но не так смешно.


    4. Автор рассказывает, что Go такой крутой, что вам больше не нужен ни redis ни nginx… Ну вот можно ещё только РСУБД оставить.

    Не в первый взгляд вижу подобные утверждения. Ещё было забавно как-то услышать, что для проекта на Go писали тесты на Node.js...


    В общем, переводчик молодец, спасибо за труд. Но пока что вижу, что ёжики продолжают плакать, колоться и писать на Go. До сих пор жду статью, которая покажет мне профит использования Go. Искренне верю в то, что он есть, но до сих пор подозреваю, что use cases довольно узкие.


    1. comerc
      28.05.2017 15:57

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


    1. vsb
      28.05.2017 16:13

      Профит Go:
      1. Это язык от гугла, в его разработке участвуют достаточно именитые авторы.
      2. На выходе получается довольно быстрый машинный код.
      3. Память управляется сборщиком мусора. Сборщик мусора оптимизирован на минимум пауз.
      4. Сам по себе язык очень простой, быстро изучить его по силам любому программисту.
      5. Язык предлагает довольно полное описание того, как на нём надо писать; в стандартной библиотеке довольно много всего нужного, в общем при разработке будет минимум душевных терзаний, а максимум продуктивности. То же про инструментарий.
      6. Насколько я знаю, потребление памяти у Go невелико. Т.е. можно писать достаточно неприхотливые к оперативной памяти микросервисы.
      7. Быстрый старт.

      На мой взгляд идеальной нишей для Go являются HTTP-микросервисы.


      1. akzhan
        28.05.2017 16:45
        +1

        1. Мы тут недавно в одной Telegram-группе обсуждали (в основном новые) языки программирования. Так вот — за любым языком стоят 1-2 автора. И где язык создаётся — не так уж и важно.

        Остальное можно считать плюсом Go :-)


      1. jehy
        28.05.2017 17:02
        +3

        1. Google glass, Google lively, Google wave, Google answers… Не всё то хорошо, что Google.
        2. Может и получается, но я до сих пор видел только бенчмарки, которые сравнивают go и однопоточную ноду или php 5 на apache.
        3. Да это уже почти везде так...
        4. Когда я смотрел go, первым плевком в мою душу было отсутствие "while". У меня больше 10 лет опыта разработки, я пишу на c++, c#, php, java, Pascal, javascript — и везде, везде я мог написать "while". Не представляете, сколько ангста у меня вызвала эта мелочь. И go был единственным языком, с которым у меня за вечер hello world не стартовал. Уж не помню, что были за грабли, может слишком сложную задачку себе придумал. Но впечатление осталось именно "а давайте сделаем хипстерский язык не как у всех"… Но это, конечно, индивидуально.
        5. С этим пунктом согласен. Когда приходится изучать лучшие практики парсинга json на языке X — это вымораживает.
        6. Тоже хочется бенчмарков :)
        7. Вы имеете в виду старт приложения? Потому что о старте разработке написали в пункте 4. А время старта приложения сейчас значения не имеет — хорошие CI инструменты позволяют, например, раскатать обе версии приложения, а затем переключиться между ними — как мгновенно, так и постепенно.

        Было бы интересно посмотреть на наглядное сравнение node.js vs Go на микросервисах. Потому что сейчас лидирую разработку банковских микросервисов на Node.js — и больше года проблем не знаю…
        По-моему, для go должен оптимально подходить или какой-то лютый highload с экономией на каждом мегагерце процессора и байте памяти, либо математика.


        1. vsb
          28.05.2017 17:48

          Основной плюс Go в сравнении с нодой — он может без лишних телодвижений использовать все ядра сервера. На ноде, насколько я понимаю, для этого нужно уже писать полноценное масштабируемое приложение и пускать N экземпляров. Ну и статическая типизация, хотя тут при желании можно TypeScript/Flow использовать или жить с динамической, кому как. В остальном, наверное, каких-то других особых преимуществ не будет.


        1. pawlo16
          29.05.2017 23:14

          Вот мнение maintainer’а кучи популярных nodejs библиотек — https://medium.com/@tjholowaychuk/farewell-node-js-4ba9e7f3e52b Товарищ плюнул на нодкжс и перешёл на go, глупый наверное. Стоп… и Матц туда же, контрибьютит гошные поректы.


          Да что это с ними творится со всеми??


          Все эти упоротые неадекваты переходят с node.js на Go — https://medium.com/digg-data/the-way-of-the-gopher-6693db15ae1f.
          На node.js остаются только нормальные разработчики .


          Даже вконтакте перешел с node.js на go — https://twitter.com/M0sth8/status/638132331295952896 :


          Готов ли Go для продакшена? VK переписали push уведомления c nodejs на Go и вместо 60 упоротых стало 24 ненагруженных сервера

          вот ведь ламеры!


          1. jehy
            30.05.2017 06:46
            +1

            1. Первому упомянутому скорее просто надоела нода. Такое бывает с разработчиками — когда долго на чём-то пишешь, то перейти на другое в кайф.
            2. Извините, не знаю никакого Матца.
            3. А вот про digg и вконтактик я охотно верю. Но это как раз те кейсы, о которых я говорил выше — большая экономия при хайлоаде. Плюс ещё надо учесть, что это хайлоад на довольно простых проектах. И есть ли ещё кейсы оправданного использования go — я по прежнему не знаю...


            1. pawlo16
              30.05.2017 12:11

              1) Абсолютно нет. Кайф — это перейти с плохого инструмента на хороший. Переход с хорошего инструмента на плохой — это кайф только для мазахистов и монадирующих неадекватов. Bower переводит инфраструктуру с node.js на go — https://twitter.com/bower/status/717426243730345986 Сначала переходят капитаны, а за ними побегут и все остальные, как крысы с тонущего корабля. Over9000 других переходов с node.js на go — http://lmgtfy.com/?q=switching+from+node+to+go


              2) Автор Руби


              3) "Плюс ещё надо учесть, что это хайлоад на довольно простых проектах. " — чтобы стать аргументом это утверждение нуждается в доказательствах. Но если вы имеете ввиду под сложными проектами типичный кровавый ынтырпрайз из гигабайтов бессмысленного кода, то будем надеяться, что go там не приживется. Пусть в этой нише остается java и c# :)


              Остаётся выяснить в чём заключается простота ноды-жс в сравнении с Гоу. Видимо в отсутствии стат. гарантий, callback hell и идиотском module resolving


              1. jehy
                30.05.2017 13:08

                1. Отдых это смена деятельности. Так что инструменты вполне могут быть одинаковые по качеству. Меня вот радует переключаться между Node.JS, C# и Java. И иногда даже на PHP, если понимаю, что быстрее напишу на PHP без всяких актуальных недостатков.

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

                2. Это вроде говорит о том, что автор перешёл конкретно с руби на Go. Руби мне никогда не нравились, так что понимаю его…

                3. Там я писал про конкретные кейсы. И для digg и для вконтактика миграция осуществлялась для довольно простых проектов. Можете прочитать статьи по своим ссылкам — там всё описано, не совсем понятно, что нужно доказывать.

                По сложными проектами я ни в коем случае не имею в виду кровавый энтерпрайз. Понятно, что там так и будет Java и C#. Под сложными проектами я имею в виду не-хайлоад средней руки, который представляет собой 99% веба — это то, что сейчас пишут на Laravel, Symphony и Yii для PHP, и нодовые микросервисы — например, на express и socket.io. Которые не хайлоад, но работают со сложными структурами и взаимосвязями. Вот для них я не вижу смысла перехода. И смысл начинания проектов такого масштаба на Go для меня под вопросом.

                Про простоту Node.JS по сравнению с Go я ни разу не писал. Хотя имхо сейчас Node.JS гораздо больше похожа на любой классический язык разработки, и мигрировать на неё легче, чем на Go. Но на этом я ни в коем случае не настаиваю.

                Что у вас не так с module resolving — не знаю, что такое «стат. гарантии» сходу придумать не могу, а callback hell уже несколько лет как неактуален.


    1. akzhan
      28.05.2017 16:34

      Все про делу, кроме "один бинарник".


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


      Другое дело, что вроде все современные языки это умеют.


      1. k4ir05
        28.05.2017 18:10
        -1

        Другое дело, что вроде все современные языки это умеют.

        Даже интерпретируемые PHP, Python, Ruby?


        1. Borro
          28.05.2017 18:56
          +1

          Для PHP это phar для остальных, не знаю, но 100% есть.


          1. k4ir05
            29.05.2017 02:45
            -2

            По сути, это просто архив, а не бинарник. Для его выполнения всё-равно понадобится PHP.


        1. akzhan
          29.05.2017 12:29

          для Ruby как минимум есть Ocra и Releasy.


          Но я имел ввиду, конечно, современные языки, которые сейчас активно развиваются. Nim, Go, Crystal, Kotlin etc.


          1. k4ir05
            29.05.2017 14:18

            для Ruby как минимум есть Ocra и Releasy.

            Благодарю за подсказку. Про releasy, по-моему, даже где-то слышал.
            Но я имел ввиду, конечно, современные языки, которые сейчас активно развиваются. Nim, Go, Crystal, Kotlin etc.

            Ну так это компилируемые языки. Хотя, для Kotlin всё же нужна виртуальная машина, в нативные приложения он ещё не компилируется. Но в статье то Go сравнивался именно с Ruby и Python. И, как правило, именно они (вместе с PHP) используются в веб-разработке.


      1. sshikov
        28.05.2017 22:01

        Ну да, ну да. А потом вы решите статику чуть-чуть поменять, ну так, слегка допилить CSS, и будете собирать заново этот свой единственный бинарник? Вы извините, но это не является преимуществом, не для веб приложений однозначно.

        Статика скорее всего снаружи. А потом выясняется, что ее вообще удобнее через CDN например. Причем выбрать решение возможно будет лучше всего потом, когда будет ясно что у нас с нагрузкой.

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

        Т.е. это такие решения, которые не следует (как правило) хардкодить в Go, а нужно откладывать и принимать в Runtime. Это верно и для классических уже решений типа Apache, и в мире Java оно так, и во многих других местах.

        Я бы еще про работу с базой добавил… где автору тоже в общем нечем гордиться.


        1. OnYourLips
          29.05.2017 15:01
          +1

          А потом вы решите статику чуть-чуть поменять, ну так, слегка допилить CSS, и будете собирать заново этот свой единственный бинарник?
          Да, новый релиз. Как и на скриптовых языках.

          А вы вместо подготовки релиза будете сразу на продакшене css править?

          И все бы было хорошо, но только вопрос выбора обработчика зачастую решается на этапе конфигурирования — и это на самом деле удобно.

          Не вижу разницы между компилируемыми и некомпилируемыми языками.


          1. sshikov
            29.05.2017 20:24

            Кто вам сказал, что во всех случаях будет новый релиз? В приличных местах над веб частью работает отдельная команда, дизайнеры-верстальщики и все такое. И релизится будет только то, что поменялось. Понимаете, тут претензия не к тому, что Go умеет собираться в один бинарник — лучше что-то умееть, чем не уметь. Претензия к тому, что собирать туда же статические ресурсы, которые почти совсем от этого бинарника не зависят — это плохой пример для демонстрации преимущества.

            Зачем при этом собирать код бэкенда, делая статику зависимой от него? Не, я могу себе представить, что такие случаи бывают, какая-нибудь эмбеддед железка с веб внутри, роутер там к примеру — и их даже много наверное. Но это сугубо частные случаи.

            >Не вижу разницы между компилируемыми и некомпилируемыми языками.

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


            1. Razaz
              29.05.2017 20:55
              -1

              Или вы поставляете софт клиентам, и что бы они не лазали куда не надо? ;)


              1. sshikov
                29.05.2017 21:13

                Не совсем уверен, что понял эту фразу.

                Но вообще говоря, веб — это не тот случай, когда вы «поставляете» софт клиенту. И самое главное — клиенты бывают разные. В том числе такие, которым по работе надо лазать туда, куда якобы «не надо». Т.е. скажем в случае заказного софта для одного конкретного заказчика я всегда предпочту, чтобы и разработчик, и поддержка заказчика именно что могли, если надо, залезть и поправить.

                P.S. Я выше написал, что вполне допускаю существование «эмбеддед» веба, в виде веб-морды для роутера или там веб-камеры. Наверное в таком случае один бинарник имел бы право на жизнь, хотя и тут это не факт.


                1. Razaz
                  29.05.2017 21:20

                  То есть веб приложение которое поставляется клиенту уже не веб? :)
                  Я про готовое решение — клиент покупает лицензию/суппорт и пользуется им.
                  Большие корпоративные приложения то же не должны позволять менять свои ресурсы.


                  1. sshikov
                    29.05.2017 21:26

                    Условия поставки бывают разные, как и сами приложения. А также и способы запретить менять ресурсы. Кому не надо — тем не выдаются права на запись, и все дела. При чем тут один бинарник, особено если учесть, что все равно ни одно реальное приложение к одному бинарнику не сводится?

                    Более того, в мире JavaEE скажем, явно различаются фазы разработки и деплоя, и деплоер, т.е. как правило админ или саппортер заказчика, может менять очень многое. А еще бывают плагины, которые опять же пишутся персоналом потребителя. И в вебе тоже.


                    1. Razaz
                      29.05.2017 21:31

                      Как вы запретите клиенту менять то, что стоит у него на серваке и он никогда не признается суппорту, что поковырялся, пока по логам/косвенным признакам не будет вычислен?

                      Если разрешено менять. А плагины ставятся через веб морду и сервак сам раздает их, при этом проверяя еще и целостность/подпись.


                      1. sshikov
                        29.05.2017 21:55
                        +1

                        Видите ли, я в этой ситуации был много раз, и с обех сторон — как разработчик, и как заказчик. Расскажу небольшую историю из жизни:

                        — широко известная компания XYZ присылает новую версию своего софта.
                        — в софте обнаруживается баг в десериализаторе JSON, JSON генерится веб приложением, там есть плагины, они самописные (т.е. наши, а не XYZ), и могут содержать ошибки, особенно при разработке
                        — софт на этом баге и кривом JSON падает, пишет в лог одну строчку, которая не позволяет идентифицировать место ошибки, и продолжает дальше как ни в чем ни бывало
                        — десериализованная модель данных приложения при этом частично пустая.

                        Пара дней копания в логах позволяют найти зацепку, и конкретный класс. Благо это java, байткод не обсфуцированный, и нормально декомпилируется. Баг тривиальный, типично индусский код, без проверок на null там где они обязательны (как я говорил, это были внешние для бэкенда данные, на минутку). В классе порядка 500 строк, вполне обозримы, и понятно что делают. В итоге находится еще два таких же места, где оно может падать. Фиксим, компилируем, собираем, деплоимся. Ура, все работает!!!

                        Репортим баг в багтрекере компании XYZ. Реверс инжиниринг запрещен лицензией, так что о нем молчок.

                        Через месяц-два в очередном релизе нам сообщают, что баг исправлен. Ставим, проверяем — а вот фигвам. Одно место исправили, код вокруг переписали, еще два других места не нашли. Репортим еще один баг.

                        Итог — через полгода и два или три релиза все наконец заработало. Угадайте, на какой версии мы работали все это время?

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


                        1. Razaz
                          30.05.2017 19:34

                          Я смотрю с другой стороны — заказчик что-то сделал по себя, в обход СДК/лицензии. При обновлении все бабахнуло, получаем запрос в суппорт, тратим кучу времени, что бы разобраться с проблемой. Потом всплывает, что клиент лазал туда, куда не надо и начинается долгий процесс разборок кто будет платить за потраченное время поддержки/разработчиков, кто будет отвечать.

                          Красиво звучит. Только это фантастика.
                          Потребитель заплатил за право пользования софтом в соответствие лицензией.

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

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

                          Плюс вы не учитываете разные категории систем. Допустим на SSO провайдере я бы все ресурсы залочил так, что бы никто кроме избранных людей не мог их менять.

                          Все зависит от клиентов и категории систем.


                          1. sshikov
                            31.05.2017 20:16

                            Я вам давно сказал, что условия поставки и софт бывают разными. О чем мы спорим, непонятно?


            1. kilgur
              30.05.2017 08:38

              Как вариант — веб-морда к сетевому сервису. Изменения в веб-интерфейсе чаще всего потребуется внести при изменениях в основной логике сервиса, т.е. новая сборка и деплой.
              Мне кажется, у автора именно такой случай — поэтому и возник вопрос встраивания статики в бинарник. В случае, когда главная цель сервиса — API для веб-сайта, согласен с вами — отдельные файлы удобнее.
              PS. А что вы подразумевали под «частный случай», говоря об «ембеддед»? Мне кажется, это такой же кейс, как и api для сайта или сетевой сервис.


              1. sshikov
                30.05.2017 09:10

                Ну я тут нечетко выразился. Не частный, а просто другой. Все-таки, когда говорят про веб, чаще подразумевается интернет, а не веб морды к роутерам. Ну т.е. если мы говорим, что собрать статику в бинарник это хорошо и полезно — надо уточнять, для какого проекта. А то для других это вовсе и не хорошо и не полезно.


              1. sshikov
                30.05.2017 09:13

                У автора в этой части в примере речь про персоны — ну какой сетевой сервис в самом деле? )


                1. kilgur
                  30.05.2017 09:45

                  Надо же было на чем-то пример показать, основной проект — закрытый )
                  На статике просто показан пример «задела на будущее» — сначала обработка статики выполняется передачей файлов с диска (http.Dir(assetsPath)), а уже в текущей части приведен пример встраивания статики в бинарник (и вытаскивания).
                  С тем же успехом можно было кэшировать статику в redis'е например. Т.е., на мой взгляд, смысл тут в том, чтобы показать гибкость. Nginx классно отдает статику — к нему обычно вопросов нет, но если зачем-то понадобится отдавать ее не с диска, то можно вот так.


            1. OnYourLips
              31.05.2017 10:16

              Кто вам сказал, что во всех случаях будет новый релиз?

              Вы:
              И релизится будет только то


              Фронтенд и бекенд сейчас — это 2+ разных приложения. Но вы будете релизить как раз какое-либо приложение целиком.

              но в описанной тут архитектуре (к которой опять же и претензии) вся логика обработки хардкодится

              У нас же все конфиги компилируются, в некомпилируемом языке при сборке. Поэтому это ничем не отличается от компилируемых по способу распространения и работы. Ведь в обоих случаях есть сборка.


      1. majorius
        29.05.2017 08:00
        +2

        Нода кстати тоже нынче умеет "один бинарник"
        https://github.com/zeit/pkg


    1. pawlo16
      30.05.2017 00:20

      1. jehy
        30.05.2017 06:23

        Насколько я вижу данные тестов, опять ноду на один процессор сравнивают с Go на четырёх… Ну то есть понятно, что процессор и память она будет есть в любом случае больше в разы, но время, делёное на 4, уже получается таким же как у Go.


        1. pawlo16
          30.05.2017 09:47
          -1

          == я вижу данные тестов, опять ноду на один процессор сравнивают с Go на четырёх


          Не выдумывайте. Все тесты выполнялись в одинаковом окружении. Больно признать правду?


          == время, делёное на 4, уже получается таким же как у Go.


          тут вынужден вас огорчить. Не только с нодойжс, с Гоу тоже — внезапно! — можно такой фокус провернуть — запустить не один процесс, а 4. Вот только нодажс отсосёт у Го по производительности в этом случае не в 4 раза, а раз эдак в 50.


          1. jehy
            30.05.2017 09:58

            Окружение одинаковое — 4 ядра. А тест написан так, что года задействует только одно. А Go нынче по умолчанию задействует все.


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


            1. pawlo16
              30.05.2017 10:57
              -1

              Хм… а я то думал, что нодажс не умеет в многопоточность — это проблемы нодежс, а не Гоу.
              И почему всего лишь 4? Давайте уже сразу 100500 нод vs. одного процеса на Гоу.


              ещё раз. Имеем Go 1 процесс ос, Nodejs 1 процесс ос. Это — одинаковое окружение.
              То, что предложили вы, Go 1 процесс ос, Nodejs — 4 процесс ос — это ни разу не одинаковое окружение, поскольку 4 > 1


              Приложение Гоу тоже можно запустить 4-мя процесами ос. тогда уже давайте тестировать 4 ноды против 4 Гоу


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


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


              1. jehy
                30.05.2017 11:11

                Хм… а я то думал, что нодажс не умеет в многопоточность — это проблемы нодежс, а не Гоу.

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


                Приложение Гоу тоже можно запустить в 4-мя процесами ос. тогда уже давайте тестировать 4 ноды против 4 Гоу

                Ну таки да.


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

                Приведённый тест заведомо некорректен. Простая логика подсказывает, что при использовании cluster результаты будут заметно отличаться. Писать свой тест только ради спора с вами — откровенно лень.


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

                Гмм.


                Больно признать правду?
                Вот только нодажс отсосёт у Го по производительности в этом случае не в 4 раза, а раз эдак в 50.

                Вижу заметно эмоциональные голословные утверждения с предвзятостью. Понимаю, что понравилась новая классная игрушка (и она правда классная, я ни разу не спорил), но это же не повод вот так некрасиво её форсить.


                1. pawlo16
                  30.05.2017 13:17

                  == Простая логика подсказывает, что при использовании cluster результаты будут заметно отличаться.


                  ага, вот только совершенно не факт, что в лучшeю для ноды сторону, поскольку в Гоу сверхнизкий оверхэд на межпотоковое взаимодействие. Ну и если уж на то пошло гошный код намного проще накачать стероидами, чем нодовский. Можно переписать узкие места на Go-ассемблер. Использовать sync.Pool (хранилище повторно используемых объектов, куда можно складывать неприменяемые объекты, чтобы кто-то другой смог их достать и повторно использовать), оптимизированyый под использование на многоядерных компьютерах. Плюс ещё пачка хаков. А вы тут мне про кластер-шмастер рассказываете, который всего-то потоки (или процесcы?) создаёт. тот ещё bubble effect.


                  == Писать свой тест только ради спора с вами — откровенно лень.


                  ну разумеется! ведь делать заявления намного проще, чем писать код.


                  == Вижу заметно эмоциональные голословные утверждения с предвзятостью


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


                  == это же не повод вот так некрасиво её форсить.


                  Ок, покажите что я не прав, продемонстрировав убедительный и не надуманный пример торжества нодежс над Гоу. Буду признателен.


                  1. jehy
                    30.05.2017 13:28

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


                    1. pawlo16
                      30.05.2017 14:21

                      Из того, что разработчик кода тестов на нодежс не использовал Кластер, ни каким образом логически не следует, что он не умеет в Кластер. Более правдоподобное предположение — Кластер вызовет ещё бОльшую деградацию перформанса нравится вам это или нет.


                      "хоть CUDA прицепить" — о, ну из Гоу вызывать сишный код тоже можно и примерно с тем же результатом, при чём без приседаний как там описано по ссылке. Вот только речь шла о языковых инструментах, а не интеграции со сторонними платформами.


    1. pawlo16
      30.05.2017 08:45
      +2

      Вот преимущества Гоу, которые вы или не поняли, или не упомянули, или автор их не достаточно раскрыл:


      1) Горутины предоставляют основное преимущество программирования потоков перед событийно-асинхронным и асинхронным программированием — простой и понятный линейный синхронный код, который легко поддерживать, дебажить и расширять + два дополнительных преимущества, благодаря которым программа на Go может спокойно работать с миллионом одновременно запущенных горутин:


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


      • динамически растущий стек для каждой горутины, начальный размер которого составляет 2Кб. Это в 1000 раз меньше стандартного стека для потоков, размер которого фиксируется при старте потока.

      При программировании на Go не нужно помнить, где именно использовать генератор или поставить await / async / yield — за вас это делает компилятор, который ошибается намного реже среднестатистического программиста


      2) — простой синтаксис и go fmt, благодаря которым код на go легко понимать


      3) сборка программы в один самодостаточный бинарник без каких-либо внешних зависимостей автоматически решает типичные проблемы деплоя новых версий программы — dll hell, dependency hell и jvm hell и избавляет от костылей в виде docker-а


      4) кросс-платформенная компиляция out of the box — программу можно скомпилировать под любую поддерживаемую платформу на любой платформе. под виндой собрать бинарник для линукс или наоборот;


      5) поддержка всех необходимых средств для тестирования и замеров производительности out of the box. Благодаря этому тесты с бенчмарками на go пишутся и читаются очень просто


      6) поддержка профилирования по cpu, memory allocation’ам и блокировкам out of the box. Причем профилирование можно включать/отключать удаленно в продакшн в любой момент времени, и это не снизит существенно скорость программы


      7) отсутствие "убийц времени", существенно замедляющих разработку программ на практике — эксепшнов, наследования, перегрузки операторов и функций, конструкторов, неявных преобразований типов и generic-ов


      8) высокая скоростью компиляции


      9) стандартная библиотека, содержащая действительно полезную на практике функциональность, а не нафиг не нужную хрень


      Так что "ёжики продолжают плакать, колоться и писать на Go" — это у вас стокгольмский синдром на нодежс или на чём вы там пишите программы


      1. jehy
        30.05.2017 09:42
        +2

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


        Про ёжиков, которые продолжают плакать и колоться — я имел в виду использование Go исключительно по той причине что "он же крутой". Как тимлид, я прикидываю, на чём мне писать различные компоненты системы — и использование Go выходит очень дорогим во внедрении. Хотя бы потому что или надо брать дорогих разработчиков, или переходить имеющимися, что в любом случае подразумевает затраты времени. Вопрос — стоит ли игра свеч, и в какой перспективе. Оговариваюсь — рассматриваю случай, когда не хайлоад, а некий относительно стандартный веб сервис. Проблемы в производительности которого (если возникают) гораздо легче решить горизонтальным масштабированием, чём писать хоть что-то новое. Думаю, у большинства ситуация такая же, как у меня — время разработчиков стоит гораздо дороже железа.


        Подводя итог — меня просто огорчает, когда в очередной раз пишут на Go то, что с тем же успехом и с на порядок меньшими затратами работало бы на php или node.js.


        1. pawlo16
          31.05.2017 10:20
          -2

          я имел в виду использование Go исключительно по той причине что "он же крутой"

          Тут дело не в моде, а в прагматичности. Go для тех, кто хочет быстрый, простой в сопровождении и расширении код. Для модников, любителей смузи, callback и dependency hell’a есть nodejs.


          меня просто огорчает, когда в очередной раз пишут на Go то, что с тем же успехом и с на порядок меньшими затратами работало бы на php или node.js.

          В node и похапэ затраты будут значительно больше на деплой, сопровождение, отладку, тестирование. В отличие от Go в них на каждый чих надо прикручивать интеграцию со сторонними инструментами на подобие redis или memcached, поскольку платформы на столько ущербные, что не позволяют сделать даже банальный твердотельный кэш БД без жима лёжа с груди


          В Go затраты будут значительно меньше, поскольку


          2) отлично масштабируются на все ядра процессора, в отличие от однопоточного nodejs. При этом не нужно извращаться с shared memory при взаимодействии между процессами nodejs, ведь в Go достаточно одного процесса, чтобы загрузить работой все ядра CPU. И для этого не нужно извращаться с асинхронностью, калбэками, промисами, async / await и т.п. костылями при обращении к файлам и внешним сервисам типа базы данных, key-value storage/cache или самописным микросервисам — достаточно обычного простого и понятного синхронного кода.


          1. работают быстрее программ на nodejs и php — меньше нагрев железа и требования к нему


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


          1. jehy
            31.05.2017 11:36

            Тут дело не в моде, а в прагматичности. Go для тех, кто хочет быстрый, простой в сопровождении и расширении код. Для модников, любителей смузи, callback и dependency hell’a есть nodejs.

            Повторюсь в пятый раз. В Node.JS как минимум уже три года как нет callback hell. Dependency hell возникает крайне редко в случае использования огромного количества разношёрстных библиотек разной степени давности. Просто не надо так делать. Кстати, такие случаи возникают обычно в случае использования всякого клиентского Javascript. Учитывая то, что в примере данной статьи клиентский javascript собирается той же нодой, Go не даёт ровным счётом никакой выгоды.

            В node и похапэ затраты будут значительно больше на деплой, сопровождение, отладку, тестирование.

            Может быть правдой только в том случае, если у вас исходно нет никакой инфраструктуры. Если есть, то затрат на развёртывание новых модулей никаких нет.

            на каждый чих надо прикручивать интеграцию со сторонними инструментами на подобие redis или memcached

            Во-первых, не на каждый, во вторых, прикручивается элементарно, в третьих — вы видимо просто не знаете, зачем используется redis.

            отлично масштабируются на все ядра процессора, в отличие от однопоточного nodejs.

            Опять повторюсь — если это нужно, то все ядра нагружаются кластером.

            извращаться с shared memory при взаимодействии между процессами nodejs

            Wut?

            В Go затраты будут значительно меньше, поскольку...

            У вас правда затраты измеряются исключительно затратами на железо? И снова повторюсь — большая часть затрат (опять же, если у вас не лютый хайлоад) — не на железо, а на время разработчиков. Время PHP разработчиков в 3-4 раза дешевле, чем Go разработчиков. Время Node.JS разработчиков в 1.5-2 раза дешевле, чем время Go разработчиков. В 99% случаев время окупаемости затрат на более дорогую разработку стремится к бесконечности. Аргумент про «содержат меньше багов» я просто опущу, поскольку это полнейший холивар.


            1. pawlo16
              31.05.2017 12:55
              -2

              В Node.JS как минимум уже три года как нет callback hell.

              Да, чатично ему на смену, частично в дополнение, пришёл promises hell и мучительные попытки понять в каких местах нужно ставить async await. Ещё через лет 10 они придут к пониманию, что надо сделать легковесные потоки как в Гоу, потом ешё через 5 их реализуют.


              вы видимо просто не знаете, зачем используется redis.

              Из чего вы сделали такой вывод? Рассказать вам как Гоу делается в 10 строчек кода на базе стандартного map-а и стандартных примитивов синхронизации то, для чего в ноде нужно костылить с помощью сторонних глючных и неудобных в использовании говномодулей?


              извращаться с shared memory при взаимодействии между процессами nodejs
              Wut?

              А вы почитайте про проблемы конкурентного программирования (очень полезные знания для тимлида), прежде чем гневно топить за ноду


              Время PHP разработчиков в 3-4 раза дешевле, чем Go разработчиков. Время Node.JS разработчиков в 1.5-2 раза дешевле, чем время Go разработчиков.

              Пруф в студию.


              Аргумент про «содержат меньше багов» я просто опущу, поскольку это полнейший холивар.

              так это статистика гитхаба — из проектов с овер 10000 звёзд наиболее надёжные — Гоу, Erlang и Clojure.


            1. pawlo16
              31.05.2017 16:36
              -2

              клиентский javascript собирается той же нодой, Go не даёт ровным счётом никакой выгоды

              клиентский код собирается webpack-ом. На клиенте автор использует ноду для npm, это к сожалению почти неизбежно для веб клиентских приложений. и никакого отношения к бэкенду на гоу не имеет от слова вообще


              В node и похапэ затраты будут значительно больше на деплой, сопровождение, отладку, тестирование.

              Может быть правдой только в том случае, если у вас исходно нет никакой инфраструктуры. Если есть, то затрат на развёртывание новых модулей никаких нет.

              с каких это пор создание, сопровождение и интеграция инфраструктуры стали бесплатными?


    1. pawlo16
      31.05.2017 09:05

      Вот еще один бенчмарк, где node.js со swift’ом проиграли Go почти в 20 раз — https://github.com/valyala/swift-response


      1. jehy
        31.05.2017 09:48

        Имейте совесть и смотрите бенчмарки, которые приводить в пример.
        Там сравнивается производительность Go с кодом из пяти строк и использованием нативных библиотек с производительностью ноды с экспрессом. Если вы не в курсе, экспресс — один из самых универсальных и тяжёлых серверов для ноды. Всё то же самое можно было бы написать в такое же количество строк кода на нативных библиотеках, и работало бы это минимум раз в пять быстрее. Минимум.

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


        1. pawlo16
          31.05.2017 11:51
          -1

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

          к сожалению это не более чем ещё одно голословное утверждение.
          почему именно в 5, а например не в 7.5? Может быть всё же реальный коэффициент — 1.1...1.2?
          и на фига тогда нужен Express, если нативные библиотеки быстрее?


  1. bugagazavr
    28.05.2017 18:10
    +3

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

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