Переход на новый язык — это всегда большой шаг. Особенно, если этим языком владеет только один член команды. В начале этого года мы поменяли основной язык программирования в Stream — с Python на Go. В этой статье я приведу 9 причин почему — и 3 минуса, выявленных в процессе.
Причина 1. Производительность
Go — быстрый. Очень быстрый! По скорости его можно сравнить с Java или C++. В нашем сценарии использования Go обычно в 40 раз быстрее Python. Вот небольшая игра-бенчмарк, в которой сравниваются Go и Python.
Причина 2. Скорость языка имеет значение
Во многих приложениях язык программирования является лишь связующим звеном между самим приложением и базой данных. Скоростью самого языка обычно можно пренебречь. Однако наше приложение обеспечивает работу каналов и чат-платформы для 700 компаний и более 500 млн конечных пользователей. Несколько лет мы оптимизировали Cassandra, PostgreSQL, Redis и другие компоненты и, в конце концов, достигли пределов возможностей используемого языка. Python — прекрасный язык, но его скорости недостаточно для таких сценариев использования, как сериализация/десериализация, ранжирование и агрегирование. У нас часто возникали проблемы со скоростью: Cassandra извлекала данные за 1 мс, а Python тратил еще 10 мс, чтобы преобразовать их в объекты.
Причина 3. Продуктивность разработчиков и ограничение креативности
Взгляните на этот небольшой фрагмент кода на Go из руководства по началу работы с Go. (Это отличное руководство и хорошая отправная точка для знакомства с этим языком.)
Если вы новичок в Go, то вас вряд ли что-то удивит при чтении этого небольшого фрагмента кода. В нем показано несколько присвоений, структуры данных, указатели, форматирование и встроенная библиотека HTTP.
Когда я только начал программировать, я старался использовать более продвинутые возможности Python. Python позволяет подойти к написанию кода творчески. Например, вы можете:
использовать метаклассы для самостоятельной регистрации классов при инициализации кода;
заменять True на False и наоборот;
добавлять функции в список встроенных функций;
создавать перегрузку операторов с помощью магических методов;
использовать функции в качестве свойств через декоратор @property.
С этими функциями интересно поэкспериментировать, но они зачастую усложняют понимание чужого кода (и со мной согласится большинство программистов). Go заставляет следовать основам. Это позволяет читать чужой код и сразу понимать, как что работает. Примечание. Разумеется, простота сильно зависит от вашего сценария использования. Если вы хотите создать базовый интерфейс CRUD API, я бы порекомендовал связку Django + DRF или Rails.
Причина 4. Параллелизм и каналы
Go пытается оставаться простым. Он не вводит множество новых концепций. Главное — создание понятного и невероятно быстрого языка, с которым легко работать. Единственная инновация в нем — это гоурутины и каналы. (Если быть на 100% точным, то концепция CSP появилась в 1977 году, поэтому данное нововведение — это скорее новый подход к хорошо забытому старому.)
Гоурутины (смотри тут) — это упрощенный подход Go к многопоточности. Создание гоурутин обходится очень дешево, а сами они занимают всего несколько килобайт дополнительной памяти. Из-за столь низких запросов их можно запускать сотнями или даже тысячами одновременно.
Для взаимодействия между гоурутинами можно использовать каналы. Все сложности берет на себя среда выполнения Go. Реализация многопоточности с ними позволяет легко использовать все доступные ядра ЦП и обрабатывать параллельный ввод-вывод данных без усложнения разработки. По сравнению с языками Python или Java запуск функции с помощью гоурутины требует минимального шаблонного кода. Вам нужно всего лишь добавить к вызову функции ключевое слово «go»:
С используемой в Go реализацией многопоточности очень легко работать. Это довольно интересный подход, учитывая, что в том же Node разработчику приходится внимательно следить за обработкой асинхронного кода.
Другим важным аспектом многопоточности в Go является детектор гонки (Go Race Detector). Он позволяет легко выявлять наличие гонки в асинхронном коде.
Вот несколько полезных ресурсов для знакомства с Go и каналами:
http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
https://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html
Goroutines vs Green threads (Сравнение гоурутин и «зеленых» потоков)
Причина 5. Быстрая компиляция
На текущий момент компиляция нашего самого крупного микросервиса на Go занимает 4 секунды. Быстрая компиляция — главное преимущество Go перед медлительными Java и C++. Мне нравится сражаться на мечах, но еще приятнее, когда к завершению компиляции я ещё помню, что должен делать код:
Причина 6. Возможность собрать команду
Во-первых, начнем с очевидного: разработчиков на Go куда меньше, чем разработчиков на более старых языках типа C++ и Java. Согласно данным StackOverflow, 38% разработчиков знает Java, 19,3% — C++ и только 4,6% — Go. Данные GitHub показывают аналогичную тенденцию: язык Go встречается чаще, чем языки типа Erlang, Scala и Elixir, но не так популярен, как Java и C++. К счастью, Go легок и прост в изучении. Он предлагает только базовые необходимые функции и ничего более.
Среди новшеств — вводятся оператор defer и встроенное управление многопоточностью с помощью гоурутин и каналов. Для сторонников пуризма: Go не был первым языком, реализовавшим эти концепции, но именно в нем они приобрели популярность.
Благодаря простоте языка любой новоприбывший разработчик на Python, Elixir, C++, Scala или Java сможет влиться в процессы уже через месяц. Получается, собрать команду разработчиков на Go гораздо проще, чем на других языках. А это важное преимущество, если вы набираете сотрудников в таких конкурентных экосистемах, как Боудер и Амстердам.
Причина 7. Сильная экосистема
В нашей команде 20 человек, и для нас экосистема очень важна. Вы просто не сможете создавать добавленную стоимость для своих клиентов, если вам придется заново изобретать каждую маленькую функцию. В Go есть отличная поддержка инструментов, которыми мы пользуемся. Надежные библиотеки уже доступны для Redis, RabbitMQ, PostgreSQL, разбора шаблонов, планирования задач, разбора выражений и RocksDB.
Безусловно, экосистема Go уступает Java, Python или Node, но она с большим отрывом выигрывает у языков поновее, типа Rust или Elixir. Это крепкая экосистема с готовыми высококачественными пакетами под многие базовые задачи.
Причина 8. Gofmt, принудительное форматирование кода
Начнем с того, что такое Gofmt. И нет, это не ругательство. Gofmt — это потрясающая утилита командной строки, встроенная в компилятор Go и предназначенная для форматирования кода. По функциональности она очень похожа на autopep8 в Python. И что бы ни показывали в «Кремниевой долине», большинству из нас не очень интересно спорить о табуляциях и пробелах. Главное, чтобы форматирование было единообразным, но каким оно будет конкретно, особо не важно. Gofmt избавляет от подобных споров, предлагая один официальный способ форматирования кода.
Причина 9. gRPC и буферы протокола
У Go первоклассная поддержка буферов протоколов и gRPC. Они прекрасно работают в тандеме при создании микросервисов, взаимодействующих через RPC. Вам нужно только написать манифест, где будут установлены допустимые вызовы RPC и принимаемые ими аргументы. Затем из этого манифеста автоматически генерируется серверный и клиентский код.
Получившийся код будет быстрым и простым в использовании, а еще он практически не нагрузит сеть. Один и тот же манифест позволяет сгенерировать клиентский код на самых разных языках, даже на C++, Java, Python и Ruby. Так что больше никаких неоднозначных конечных точек REST для внутреннего трафика, для которых каждый раз приходится писать практически один и тот же клиентский и серверный код.
Недостаток 1. Отсутствие фреймворков
У Ruby есть Rails, у Python — Django, у PHP — Laravel. А вот у Go нет ни одного ведущего фреймворка. По этой теме в сообществе постоянно ведутся жаркие дебаты. Многие считают, что никакие фреймворки языку в принципе не нужны. Я частично соглашусь, в некоторых сценариях они не потребуются. Но если кто-то захочет создать простой интерфейс CRUD API, ему будет гораздо проще с Django/DJRF, Rails, Laravel или Phoenix.
Дополнение. Комментаторы указали несколько проектов, которые предлагают фреймворк для Go — Revel, Iris, Echo, Macaron и Buffalo. Мы для своих сценариев предпочли не использовать фреймворк. Однако для многих новых проектов, нацеленных запилить простой интерфейс CRUD API, отсутствие ведущего фреймворка станет серьезным недостатком.
Недостаток 2. Обработка ошибок
При возникновении ошибки Go просто возвращает эту ошибку функции и ожидает, что ее обработает вызывающий код — либо вернет ее выше, в стек вызывающей программы. Такой подход вполне работоспособен, но можно легко упустить из виду, что что-то пошло не так, и не выдать пользователям соответствующее сообщение об ошибке.
Пакет errors решает эту проблему, позволяя добавлять контекст и выполнять трассировку стека до ваших ошибок. Другая проблема заключается в том, что можно случайно забыть обработать ошибку. Да, в этом случае помогут инструменты статического анализа типа errcheck и megacheck. Эти обходные решения прекрасно работают, но все же прибегать к ним как-то неправильно. Хочется, чтобы язык поддерживал надлежащую обработку ошибок.
Недостаток 3. Управление пакетами
Управление пакетами в Go оставляет желать лучшего. По умолчанию в нем нельзя указывать конкретную версию зависимости и создавать воспроизводимые сборки. У Python, Node и Ruby с этим получше. Впрочем, при использовании подходящих инструментов можно наловчиться управлять пакетами и в Go. Для указания и закрепления версий подходит Dep. Кроме того, мы участвовали в разработке VirtualGo — он упрощает работу над несколькими проектами параллельно.
Дополнение. С момента публикации статьи механизм управления пакетами в Go поменялся в лучшую сторону. Эффективным решением стали модули Go. Единственной проблемой, с которой я столкнулся — они ломают некоторые инструменты статического анализа, такие как errcheck. Вот руководство по использованию Go и модулей Go.
Сравниваем Python и Go
Мы провели интересный эксперимент, взяв функционал нашего ранжирования каналов на Python и переписав его на Go. Взгляните на этот пример метода ранжирования:
Для его поддержки код как на Python, так и на Go должен выполнить следующее:
Разобрать выражение для оценки. В данном случае мы хотим превратить строку «simple_gauss(time)*popularity» в функцию, которая на входе принимает активность, а на выходе возвращает оценку (score).
Создать частично вычисляемые функции на основе конфигурации JSON. Например, нам нужно, чтобы функция simple_gauss вызывала decay_gauss со шкалой (scale) в 5 дней, смещением (offset) в 1 день и коэффициентом затухания (decay) 0,3.
Разобрать конфигурацию по умолчанию (defaults), чтобы у вас была возможность перейти в резервный режим работы, если какое-либо поле в активности окажется не определено.
Использовать функцию из шага 1 для оценки всех активностей на канале.
Разработка кода ранжирования на Python заняла примерно 3 дня. Сюда входит написание кода, модульных тестов и документации. Затем мы потратили примерно 2 недели на оптимизацию кода. Одна из оптимизаций состояла в переводе выражения оценки (simple_gauss(time)*popularity) в абстрактное синтаксическое дерево. Мы также реализовали логику кэширования, которая предварительно вычисляла оценку для определенного времени в будущем.
Написание этого же кода на Go заняло примерно 4 дня. Дополнительные оптимизации не потребовались. Хотя поначалу разработка на Python шла быстрее, с Go было гораздо меньше возни. Плюсом с Go мы получили более высокую скорость работы кода — в 40 раз быстрее, чем высокооптимизированный код на Python.
Это лишь один из примеров буста производительности, который мы получили при переходе на Go. Ну и, конечно же, сравнение несопоставимого:
код ранжирования был моим первым проектом на Go;
на Go мы писали уже после того, как написали код на Python, поэтому я лучше понимал сценарий использования;
библиотека Go для разбора выражений была исключительно высокого качества.
Может, у вас было по-другому. Стоит признаться, что какие-то другие компоненты системы на Go разрабатывались гораздо дольше, чем на Python. В целом разработка на Go требует чуть больше усилий, но зато на оптимизацию уходит гораздо меньше времени.
Дополнение. С момента публикации статьи разница в производительности Python и Go возросла. Go стал ещё быстрее, а Python — нет.
Сравнение Elixir и Go. Серебряный призер
Еще мы рассматривали Elixir. Он построен на виртуальной машине Erlang. Один наш коллега с ним долго работал, и мы решили его проверить. В наших сценариях использования мы заметили, что исходная скорость Go намного выше. И Go, и Elixir отлично справляются с тысячами параллельных запросов, но если оценивать скорость отдельных запросов, то Go гораздо быстрее.
Другой причиной стала экосистема. Для Go уже были готовы проверенные библиотеки для нужных нам компонентов, тогда как библиотеки Elixir было невозможно использовать в рабочей среде без предварительной подготовки. Кроме того, найти или обучить разработчиков на Elixir сложнее. В общем, наши взоры вновь устремились на Go. Но если вы захотите его опробовать, обратите внимание на потрясающий фреймворк Phoenix — он определенно заслуживает внимания.
Заключение
Go — высокопроизводительный язык с отличной поддержкой многопоточности. Он практически такой же быстрый, как C++ и Java. Хотя разработка на Go занимает больше времени, чем разработка на Python или Ruby, вы сэкономите массу времени на оптимизации кода.
У нас небольшая команда разработчиков поддерживает работу каналов и чата для более чем 500 млн конечных пользователей. Благодаря сочетанию отличной экосистемы, простоты адаптации новых разработчиков, высокой производительности, хорошей поддержки многопоточности и продуктивной среды разработки язык Go стал отличным вариантом. Мы по-прежнему используем Python в Stream для информационного табло, сайта и машинного обучения для персонализированных каналов, и прощаться с ним не планируем. Но теперь весь высокопроизводительный код будет писаться на Go. Наш новый Chat API также полностью написан на Go. Если вы хотите узнать больше о языке Go, ознакомьтесь со статьями из списка ниже.
Остаётесь верны Python? Напишите нам — мы подберём для вас что-нибудь подходящее. Сейчас нам очень нужны Python-разработчики для работы удалённо или с релокацией. Если вы ищете разработчиков, тоже пишите. :)
Дополнительные материалы по переходу на Golang
Изучение Go
Читайте также:
Комментарии (32)
antarx
15.08.2022 18:11+9На мой взгляд есть куда более важный аргумент: Go разработчикам больше платят. Вот статистика по 2021 году:
https://habr.com/ru/article/649423/#rec407700951 (Россия, +33%)
https://insights.stackoverflow.com/survey/2021#section-salary-salary-and-experience-by-language (мир, +25%)
Аргумент, конечно, манипулятивный: Go разработчики в целом больше знают и умеют ввиду большей сложности задач и большей нагрузки на продакшен (и собеседования заметно хардкорнее), и по некоторым исследованиями сравнимые кандидаты мало отличаются по оплате.
Тем не менее, это работает как мотивация выбрать Go для разработчика, и как мотивация не выбирать Go для компании.
gunGarave
15.08.2022 18:15+36Думаю, для Python-разработчика проще перейти на Julia (а она умеет ещё и Python код выполнять через биндинги). А если вы рубист - то Crystal.
А теперь по пунктам. Есть немного критики
Производительность: а чем это отличается от следующего пункта?
Скорость языка имеет значение: давайте разделять задачи. В рамках web (для которого Golang получил наибольшее распространение) - есть два основных узких места. Это - база данных (тут Golang ничего не сделает) и обработка JSON (и тут он медленный). Так, что "+/-" у этого аргумента. И как ни смешно, для микросервисов, которые часто работают с JSON прекрасным выбором является NodeJS. Не хуже Aio у Python. Прекрасно показыают себя Julia и Crystal. Ну а такие стеки как Erlang, Elixir, Java, Haskell, Racket... да масса на самом деле... работает с данными узкими местами не хуже. Если говорить об оптимизации на низком уровне - лучше Pure C я пока ничего не встречал. Даже Rust просто даёт не защищённый режим, где вы можете сделать "быстро". Но тут да, вопрос где именно надо сделать быстро. Вполне возможно, что Golang в этой задачи легко "сольёт".
Продуктивность разработчиков и ограничение креативности: Код, который вы показали - выглядит отвратительно, это ИМХО. Большая часть тех, кто работал на Python, думаю, так же скажут. Ранние выходы, куча странных нотаций, своеобразный и многословный синтаксис. Про ограничения... за ними скорее в Rust. Если нужна "золотая середина", то я сказал бы DLang. Ну а на Python настроенный линтер и аннотации типов в целом решают проблему без смены языка.
Параллелизм и каналы: ничего нового, на самом деле. "Новизна" - скорее маркетинг. Легкие потоки давно есть в Erlang, Racket, etc. Асинхронщина - Promise и разные его аналоги есть уже очень давно. В Python есть инструменты, чуть сложнее синтаксически (хотя не на много), слабый аргумент для смены "рабочей лошадки". Уж тогда смотреть в сторону Julia, которая по синтаксису ближе к Python, но умеет все перечисленное и много всего сверху.
Быстрая компиляция: сомнительный плюс, интересен больше в dev-режиме (на проде - не так принципиально, но бывают случаи). Скорее интереснее REPL и горячая замена кода. Erlang и Lisp тут никто не превзошёл. Разве что рядом Julia (которая по сути - DSL над Lisp).
Возможность собрать команду: смотря какого уровня нужна. У Golang часто та же проблема, что и у Python - средний по больнице уровень кандидатов достаточно низкий. Про API и возможности язка - Golang в целом не принёс ни одной новой идеи. Это хороший энтерпрайзный язык, который делался под конкретные цели и экосистемы. И там он хорош, но за рамками них...Мало чем лучше Python, если мы не говорим о синтетических тестах или очень узких кейсах.
Сильная экосистема: сильнее, чем на NodeJS я не видел экосистемы (без шуток). Если честно. И уж тем более на Golang менять ради экосистемы, отказываться от Python - это бред. Та же Julia выстреливает в том числе потому, что она совместима с экосистемой "ползучего". Golang... стандартно, где-то даже ощутимо хуже. Ощущение как от Dart - если Google хотели так применять, то всё в целом "ок". Если нет - то в лучшем случае никак. И в чём тут аргумент против Python?
Gofmt, принудительное форматирование кода: а в Python форматирование является частью синтаксиса. А ещё есть куча инструментов, которые делают это в других экосистемах. А ещё есть IDE, которые из коробки это умеют. В общем - ещё один недоаргумент, который ещё раз подтверждает - оснований переходить с Python на Golang просто нет.
gRPC и буферы протокола: вообще слабый аргумент. Ещё одна ниша, которая нужна конкретно Google и затачивалась под их конкретные задачи. Тем более - gRPC умеет куча экосистем и стеков. Шутка ли - даже в древний Common Lisp находил реализации. Python - уж тем более не исключение. Про "плюсы" и "минусы" самого gRPC можно спорить очень долго. Скажу лишь пару аргументов "против" - фронт и gRPC лучше не дружить (приходится проксировать через Gateway и делать что-то REST-подобное на фасаде), тотальный вендорлок гугла. Ну а автогенерённый код... он и в Африке автогенерённый. Хотя да, на Golang это всё наиболее прозрачно (кстати, в Dart было не хуже, пока Google не замкнули язык на Flutter). Но ниша слишком узкая. Да и на Python не на много хуже обстоят дела.
Итого: не убедили. Из 8 причин - ни одной существенной.
А вот недостатки... давайте отдельно, тоже.
Отсутствие фреймворков: вот тут то, что я писал. Если Golang интересен в этой нише Google - будет инструмент, нет - не будет. В Web ещё не так всё плохо (есть зайчатки), а вот в каком-нибудь вопросе ORM/ODM для разных СУБД будет примерно так же как в Raku - пишешь сам, поддерживаешь сам.
Обработка ошибок: да нет её толком. Это сложная и ресурсоёмкая тема. И как правило - она усложняет инструмент. Golang проектировался, чтобы быть простым. Поэтому... просто плодим if, улыбаемся и машем (и после этого кто-то сетует на JS с его Callback/Promise Hell).
Управление пакетами: А ведь это важно. Особенно для enterprise. А почему нет? Правильно, все интересные пакеты Google будут мейнтейниться Google. И будет всё хорошо. А остальной рынок мало интересен для создателей Golang.
Бонусом уж совсем понесло.
Сравнение Golang и Elixir: а почему именно Elixir? А не сравнить с изначально более выигрышной NodeJS, не сравнить с простой, быстрой и понятной Julia. Не сравнить с элегантным и не уступающим ни в чём Crystal. Вы бы ещё с LFE сравнили. Или со Scala. Да, они подходят под "асинхронщину" и "параллельщину". Но явно рассчитанные на уровень в среднем выше, чем у среднего python-разработчика (ему просто много из ФП не нужно).
Итого по статье - спасибо, было интересно. Но эффект обратный. Вы скорее доказали, что Golang не стоит внимания, а сообщество его сторонников - не может аргументировать выбор инструмента (мало чем подкрепленные аргументы).
antarx
15.08.2022 20:51+4По моему опыту (несколько десятков разработчиков) у Go самый низкий порог входа: новичкам в языке (но минимум мидлам бэкенда) выдаётся задача на Go, и они с первого дня выдают деливери на уровне мидлов. tour.golang.org — великая вещь, которой не хватает многим языкам, как и простой документации по языку или стандартной библиотеке.
В целом, сравнивать промышенные и эзотерические языки имеет мало практического смысла — последние мало где получится использовать.
По пунктам, судя по аргументу про пакеты, это либо очень старая статья, либо автор не в теме. В Go важны другие вещи.Экосистема. Go — редкое место, где можно спокойно апгрейдить зависимости большого проекта, и почти всегда это не портит работу приложения. По опыту разработки и менеджмента разработки — не хватает разве что больших фреймворков и универсальных ORM, но они не go way. Нет прекрасных проблем в духе миллиона версий питона и ноды
Понятная IDE система типов, вызовов, зависимостей итп. Можно быть уверенным, что поиск по функции (не по текстовому названию, именно по функции) найдёт все её использования, без какой-либо магии, и клик по параметру/функции найдёт именно её. Невозможна ситуация, когда из-за отсутствия (пустого init.py) файла приложение падает в (казалось бы) случайном месте.
Крутой инструментарий: в 1 строчку делается профайлинг прода (по CPU, памяти, горутинам, итп), отлов data race в 1 параметр, просто работающий дебаг, максимально простая система тестов и бенчмарков, максимально простой вылов протекающей памяти или горутин. Вылов data race — штука практически уникальная. К этому добавляется простая возможность оптимизаций вплоть до asm, засчёт чего производительность Go редко является проблемой.
Нет проблем со сборками: нет вечно падающих gyp зависимостей и прочих psycopg — в Go принято делать зависимости на чистом Go, а редкие биндинги к C-библиотекам без проблем собираются даже под другую ОС.
Обработка ошибок. Засчёт того, что разработчика принуждают обрабатывать ошибки, куда чаще они действительно обработаны.
Линейный код. В отличие от промисов и лямбда-программирования, код на Go обычно беглым взглядом прочитывается правильно.
Переносимость опыта. Go разработчик с рынка работал в той же экосистеме, с похожим до неразличимости code style, и в похожей по структуре кодовой базе => существенно короче онбординг.
Универсальность сериализации. В Go никогда нет проблемы «залогировать класс», не нужно изобретать сериализаторы полей итп — оно работает просто и предсказуемо.
Стабильность. Для Go нормально оставить крупное приложение на год без какой-либо поддержки, например перезапуска от медленно текущей памяти или моргнувшей сети.
Установка. Системная утилита на Go переносится 1 бинарником, без каких-либо зависимостей и проблем.
Результат хорошо виден: подавляющее количество опенсорсных системных утилит и сервисов (все эти докеры, кубернейтисы, прометеи, графаны, весь стек хешикорп и прочие кокроачи) пишутся на Go прямо с релиза. Т.е. в условиях чистой конкуренции Go уже победил конкурентов.
Недостатки, впрочем, тоже есть:
if err != nil вместо эксепшенов. Это замусоривает код, а решение пока в глубоком драфте. Зато мотивирует не делать излишне длинные функции, и обрабатывать пойманные ошибки (см. п.5), а эксепшены (паники) исп
Generic'и. Их долго не было, сейчас они весьма ограничены и не всегда удобны. Без них не получается приносить привычные из других языков паттерны, и некоторые библиотечные штуки вроде кастомных сетевых протоколов делать неудобно. С другой стороны, см. п.2 и п.6.
Фреймворки с огромным инструментарием типа админок. Это больно, аналога Django в Go нет и не предвидится. Кажется что для задач Django лучше использовать Django.
ORM. Они есть в урезанном виде без явного лидера. Это проблема, пока не появляются задачи собрать полноценный DDD со всеми агрегатами и value object'ами, или оптимизировать SQL запросы на 5 джойнов и window функцию.
Areso
15.08.2022 21:33+1А можете подсказать хорошие примеры про связку mux / websocket? Как если бы я хотел бы сделать свой динамический роутинг и подписывать на него клиентов. observer/subscriber
gunGarave
15.08.2022 22:28+4Про продакшен код за пару дней изучения - не удивительно. Именно такую задачу и ставил Google. Вернее, чтобы "даже питонисты могли быстро влиться и начать писать производительный код". Это делает Golang хорошим инструментом, но не хорошим языком.
Далее - Scala, Rust, Julia иди Crystal не эзотерические. Вполне себе инструменты. NodeJS тем более. Но сравнивают почему-то с Elixir. Niff said.
Про экосистему. Я уже писал, что она хороша там где была интересна Google. Найдите ODM для той же ArangoDB или Couchdb. А это вполне промышленный СУБД. И нет никакого в этом go way (в случае с Golang - это просто агитка, чтобы не писали сложного, инструмент не заточен), есть интерес основного инвестора. И именно поэтому почти всегда не портит - есть пакеты не интересные корпорации, а остальные - на свой страх и риск.
Про IDE, извините. Я настраивал 7 лет назад Emacs под Dlang, Python и NodeJS. Потом накрутил еще модули для Julia. Вопрос инструмента и рук.
Про init.py - скорее особенность и условие. Тут не хорошо и не плохо. Функция main у K&R тоже условность.
Про инструментарий вообще не в кассу. Julia - похоже. На Nodejs еще раньше сделали, чем Golang. Древний Common Lisp умеет очень многое (сложно найти чего нельзя сделать через снапшот). Дебаг легких потоков - Erlang. А так из промышленного удобный инструментарий и IDE - идеи Smalltalk никто не отменял. Другое дело, что порог входа инструментов - низкий. Правда их функциональность соответствует порогу входа.
Проблемы со сборками... Давайте не сравнивать Python , а возьмем Dlang или Rust. У них их тоже нет. И C они редко дергают. Иными словами - мало удивительного. Плюсы компилируемого языка. И минусы. Так как на С давно уже это написано, зачем велосипедить? Ну а так - если честно, я встречал проблемы с зависимостям. В Python только под Wondows. И были проблемы с установкой каких-то пакетов под форточкамит и в Golang. Хотя может за 4 года, что я не прикасался - что-то поменялось.
Ага. Видел я в продакшене обработку. Примерно на уровне Python'новского try/catch+pass. Если ошибка - упасть, если не ошибка - делать. Другая крайность if-hell с диким уровнем вложений. Без нормальной типизации и единой точки обработки. Ничем не лучше callback hell, лапша.
Линейный код никто не запрещает писать на Python, Erlang, JS (asunc/await, generators) и кучи других языков. Собственно не линейный код свойственный языкам где кроме вызова callbacks нет ничего. А таких уже почти нет. Про лямбды - for тоже лямбда). Ничего, живут с ней все.
Пункт 7 можно применить к любому языку. Вообще любому. Главное, чтобы команда применяла best practice и работала с code style. Говнокодить можно на любом языке. Что чаще всего и делают. А сказки переносимости опыта - идеальная ситуация, которой не будет скорее всего.
Универсальность сериализации есть в любом языке, который проповедует "код есть данные". На Lisp 1 еще. В ФП не сложнее, как и в ООП. Чуть побольше пары строк, но не rocket science . Smalltalk, Julia, Ruby...примеров можно найти при желании много. Даже древний TCL позволял (своими руками такое делал). Но может не понял задачу какую имеете ввиду.
Стабильность - Erlang, CL, Racket, Clojure, Scala, Haskell...да даже Nodejs (мой сервис работал один несколько лет без передёргивания), ну в самом деле. Тут ничего нового. Erlang тот же в целом идеал на счет стабильности - что-то стало работать не так, пристрели и заспавни. Ну а GC вполне себе защищает от утечек (тут опять Go ничего не привнес). И тут можно вспомнить еще и тот же D (все было еще в нем + гора сверху). Или даже Rust с его подходом из современных.
Установка... А тут что нового? Тонны языков с бородатых лет. С современных тоже хватает. Тоже ничего нового. Либо я не так вас понял. Но, банально - даже на Racket я могу всю VM упаковать, со всеми либами. У мейнстримных языков это тоже давно есть.
А недостатки...
Да, согласен - исключений нормальных нет. Видимо и не будет. В XXI веке смотреть на это больно.
Дженериков таких лучше бы не было (судя по спеке). Ситуация напоминает лямбды в Python.
Про фреймворки - лозунги рекламы, они нужны. В том числе и "жирные". То, что их нет скорее показатель ниши и сложности сделать из на Go.
Про ORM/ODM - мир СУБД не ограничен PGSQL и еще парой реляционных баз. И язык запросов - не только SQL. СУБД много. И ORM хорошо подходят под микросервисы, позволяют работать с высоким уровнем абстракций. Там где нужно лопатить терабайты данных Go мало что может предложить (Julia, R и Fortran он не замени ), нет нужных инструментов тоже. Вот и получается - как все на Golang. Примитивные решения для небольших вещей.
Итог - Golang стал популярным благодаря маркетингу. У него нет приемуществ кроме предельно низкого порога входа (правда в D он не выше в тех же границах использования) и заточенности под определенные задачи (gRPC , частично network).
З. Ы.: писал как на Python, так и на Golang. И даже в пьяном угаре не стал бы советовать последний.
Source
16.08.2022 02:16+1Далее - Scala, Rust, Julia иди Crystal не эзотерические. Вполне себе инструменты. NodeJS тем более. Но сравнивают почему-то с Elixir. Niff said.
У вас какая-то предвзятость к Elixir)
Конкретно для веб-разработки он всё-таки популярнее Rust и уж тем более популярнее Scala, Julia и Crystal. Посмотрите хотя бы на те же звёздочки на Github для самых популярных веб-фреймворков на этих языках. А по опросу StackOverflow Phoenix вообще 1-е место в списке most loved фреймворков занял в этом году. Да и сам Elixir занял 2-е место после Rust в списке most loved языков.gunGarave
16.08.2022 09:31+3Ничего не имею против Elixir. Более того могу сказать, он мне нравится.
Я имел ввиду то, что берётся для сравнения в статье изначально более требовательный к погружению стек. Всё же вхождение в Erlang-окружение (а у Elixir много инструментов и подходов от "родителя") сложнее, чем JVM или NodeJS. Но да, Elixir не корректно "выбрасывать" из сравнения. Это язык, который на порядок лучше Golang и он вполне себе хорошая альтернатива для миграции с Ruby/Python.
Про Rust... это специфичный инструмент. Я не могу сказать, что он плохой. Он как раз требовательный, сложный и функциональный. Кстати, уж если заговорили про него - его экосистема ничуть не хуже Golang, а местами даже куда лучше. И если уж сравнивать компилируемые языки между собой - то оставить без внимания его было бы не верно. Как не верно и "забыть" сравнивать Golang с Dlang, который умеет всё то же самое, что и первый и ещё сверху много приятного (нормальные ошибки, дженерики, шаблоны, etc.). Последний, кстати, не на много сложнее изучить, чем Golang. В том числе за счёт достаточно простого и понятного синтаксиса.
За ссылку на рейтинг спасибо, как раз хотел посмотреть каков тренд и менялся ли).
Areso
16.08.2022 02:43+1А можете сказать что-то про Nim, а то его там выше рекомендуют.
gunGarave
16.08.2022 10:07+2Очень интенсивно недавно развивался, потом как-то затухло.
Мало с ним поработал. Так, для пары простых микросервисов заюзал. Не могу ничего плохого сказать - это один из череды "простых и производительных" языков, вроде Julia, Crystal, Elixir и им подобных. Чаще всего видел их позиционирование как "работа над ошибками Python/Ruby/$LanguageName". Но тут, думаю, проблемой стало позиционирование - Crystal и Elixir взяли такой хороший курс на Web, Julia пытается прижиться в наших ML и числодробилок...
А вот куда Nim приложить предлагают, я так и не смог понять. Были, на сколько помню, потуги его затащить в gamedev, но вроде как не взлетело (хотя могу ошибаться).
Как альтернатива Python... а зачем, если есть Julia? Последнее время она и в web стала хорошо уметь (прекрасный фреймворк Genie уже до 5 версии обновили), имеет свои notebooks (Pluto.jl) для датасаентистов и т.п. Плюс из неё можно делать вызовы Python-кода.
Любой язык, чтобы стать успешным, должен быть инструментом конкретной ниши, для конкретной ЦА. Надеюсь Nim найдёт своих пользователей. Язык то очень даже не плохой.
ValentinDom
16.08.2022 14:04-1Виталик, привет!
Ждал тебя увидеть в треде. :) Как раз вспоминал твой доклад на Moscow Python Conf - https://www.youtube.com/watch?v=a8oEETIRpCk
Source
16.08.2022 02:04+1Если говорить об оптимизации на низком уровне - лучше Pure C я пока ничего не встречал. Даже Rust просто даёт не защищённый режим, где вы можете сделать "быстро".
Тут ещё важный аспект, что либу на C или на Rust легко можно подключить почти к любому популярному ЯП через NIF или FFI. С Go такое не прокатит.
Сравнение Golang и Elixir: а почему именно Elixir?
Я, кстати, в 2015 году тоже именно такое сравнение устраивал. В моём сравнении победил Elixir, для веб-разработки он подходит гораздо лучше, чем Go. А за счёт применения возможностей OTP ещё и в скорости его обходит на большинстве практических задач. Веб-разработка она де-факто про ФП, и то что на неё под влиянием моды натянули ООП в стиле GUI-программ - это, пожалуй, один из самых больших косяков во всей этой отрасли. Пол Грэм ещё 20 лет назад всё объяснил, но большинство до сих пор отказывают себе в быстрой веб-разработке. Кстати, Elixir по сути своей является диалектом Lisp, и весь его синтаксис ничто иное, как DSL на этом лиспе написанный.
Насчёт Julia ничего не могу сказать. Не видел пока, чтобы её кто-то именно для веб-разработки использовал. А Crystal пока сыроват в плане конкурентности и параллелизма. Насколько мне известно, пока нет способа сделать так, чтобы программа на нём использовала, допустим, все 8 ядер процессора и нигде не сбоила.
ValentinDom
16.08.2022 14:05+1Спасибо за содержательный комментарий!
Про Julia, кстати, был интересный доклад на нашей конференции: https://www.youtube.com/watch?v=REVmhiJ1Zi8Есть также расшифровка на Хабре, если кому-то так удобней: https://habr.com/ru/company/oleg-bunin/blog/476114/
saga111a
15.08.2022 18:20+2Python идет странным путем развития и не могу сказать что понимаю в чем смысл некоторых "нововедений".Если бегло то парадигма читаемости кода -- это ключевое, но от нее объективно уходят, (привет моржи). Go наверное интересен в первую очередь простотой сборки, надежностью запуска(независимые приложения не тянущие за собой тонны зависимостей, которые не всегда ведут себя адекватно), независимость запуска от С++, которая иногда вызывает проблемы поведения в питоне.
А вот с отрицательными вещами все тоже хорошо, дайте аналог numpy/scipy библиотек машинного обучения итп да и готовых бибилотек для развертывания сервера на коленке.
Но на мой взгляд Go идет верной дорогой, но для себя использовать пока не могу, хотя и очень бы хотел, сильно не туда повернул Python, простота не довела его до хорошего контингента.
Pastoral
15.08.2022 19:01+2Неплохая статья, хороший перевод. Хочется привести две причины, с точки зрения мало просвещённого читателя, разумеется, не переходить на Go. Но кому? Автор далеко, переводчик демонстративно лишь переводчик… Был бы раздел «от переводчика» - может и приводить ничего не пришлось бы.
Причина 1. Python удобно использовать вместо калькулятора.
Причина 2. Python позволяет, по крайней мере пока, обойти без использования виртуальной машины ограничения W^X политики на мобильных устройствах.
s_f1
15.08.2022 19:35+1Мне казалось, Go – это замена C и C++, а не Питону?
Areso
15.08.2022 20:05+1Зависит от задач. На Питоне писали довольно много инфраструктурной обвязки; теперь переписывают Go.
Areso
15.08.2022 20:07+1Или, как пример из моего хобби.
Раньше был игровой сервер на Питоне, сейчас переписываю на Go. Страдаю, правда :)
Source
16.08.2022 01:18+1Ну уж для хобби-проекта переписали бы на Nim. К чему эти страдания с Go? :)
Areso
16.08.2022 02:38+1Освоить новый для себя ЯП; сэкономить на ресурсах - потому что текущая реализация больше 40 человек онлайна не держит. Ну и идея с корутинами тоже манит - у меня там есть, что в них закинуть. Плюсом - быстрая сборка в один бинарник без зависимостей. После определенного момента подготовка окружения для крупных Питон проектов стали раздражать проблемой с зависимостями, когда разные зависимости требуют одного пакета, но разных версий.
Source
16.08.2022 02:53+1Вопрос был в том, почему не Nim? Он с вашими задачами тоже справился бы, но больше на Python похож и лишён многих недостатков Go.
Areso
16.08.2022 02:57+1Честно, я не рассматривал его на тот момент.
Откинул Java, C# (dotnet core), и в общем-то оказалось, что других относительно мейнстримовых языков для игрового сервера я и назвать не могу. Rust, C, C++ были откинуты по причине их относительной хардкорности.
Source
16.08.2022 14:17При откидывании языков под JVM и .NET действительно остаётся не так много из относительно мейнстримовых (я определяю по наличию веб-фреймворка с кол-вом звёзд более 10k):
Elixir, Go, NodeJS - которые под вашу задачу подходят.Ну и знаменитая троица PHP, Python, Ruby, которые для игрового сервера не особо подходят.
gunGarave
16.08.2022 11:41+3Golang как замена Pure C и C++ не взлетел.
Для использования вместо Pure C - надо выкидывать GC и как-то давать интерфейс работы с памятью. Это сложно и противоречит изначальной цели Go - быть простым.
Для использования вместо С++ - не гибокий, мало возможностей (в том числе работы с памятью) и слабая реализация элементов ООП.
Плюс конского размера бинари и невозможность использовать через какой-нибудь FFI.
А вот как альтернатива Python и подобным языкам для того, чтобы плодить web - вполне себе альтернатива, если нужна асинхронщина а в NodeJS не хочется, а в Erlang не можется.
Source
15.08.2022 19:57+7Безусловно, экосистема Go ... с большим отрывом выигрывает у языков поновее, типа Rust или Elixir.
А какие-то доказательства будут или так просто вбросили?
Что Rust, что Elixir изначально имеют качественный тулинг и экосистема у них достаточно сфокусированная. А Go первые лет 10 страдал фигнёй, когда каждый изобретал свой велосипед для любой задачи, будь то управление зависимостями или работа с Redis. Хуже экосистемы я, честно говоря, не встречал. Потому что при поиске либы под любую популярную задачу у тебя будет минимум 5 примерно одинаковых вариантов, из которых хз как выбирать. И что бы ты ни выбрал, через 3-4 года это скорее всего будет deprecated.
nmrulin
15.08.2022 21:47+3"Go — быстрый. Очень быстрый! По скорости его можно сравнить с Java или C++. В нашем сценарии использования Go обычно в 40 раз быстрее Python. Вот небольшая игра-бенчмарк, в которой сравниваются " - это почти любой язык быстрее Питона начиная от школьного Паскаля и кончая всем. Если бы быстрота была в 100% случаев критична, Питон бы вообще не возник. Тем более хороший питонист умеет пользоваться библиотеками, которых вполне себе производительны.
h1pp0
16.08.2022 00:32+3Не могу быть объективен полностью, как человек который искренне любит Python, но также использую Go в проде, поэтому могу сравнить.
Надо сказать, что аргументы выше уже были разобраны подробнее, чем у меня.
Интересно, что уже первый пункт автора, Производительность, не имеет смысл без второго Скорость языка имеет значение, потому что производительность не требуется, если скорость не важна. А скорости Python вполне хватает даже для относительно нагруженных веб-приложений. Ещё есть PyPy, правда не очень применимо для веба.
Продуктивность разработчиков и ограничение креативности. Мне кажется, что простота сама по себе не является преимуществом. Сложно придумать что-то более простое, чем ассемблер (по крайней мере, основные команды), но на нём редко разрабатывают веб-приложения. Если посмотреть на Go, то это чуство меня не покидает. Обработка ошибок это одно из первых, что увидят новички. Лично меня это оттолкнуло. Дженерики появились в 1.18. Система типов есть, но везде и всюду будет
interface{}
. И в Python есть опциональные аннотации типов и mypy для их проверкиПараллелизм и каналы. В Python есть asyncio, который для типичных сценариев проще каналов.
Быстрая компиляция. А в Python компиляции как таковой нет вовсе, если сравнение с ним.
Сильная экосистема. Не все инструменты я видел, но мне экосистема Python кажется значительно более взрослой. Если сравнивать инструменты сходной популярности, то в Python будет больше функционала.
Gofmt, принудительное форматирование кода. Мне кажется довольно занятным, что проверку на длину строк gofmt не делает, поэтому в экосистеме есть golines, постформаттер для этого. Для Python форматтеров много, например, black.
gRPC и буферы протокола, это просто протокол. Каких-то значимых преимуществ у Go тут нет, но он может подходить лучше.
Мне также кажется, что причин выбирать один язык вместо другого не так уж и много. Вариант писать всё на Python, а часть на Golang вполне рабочий. И для большинства так будет лучше т.к. программистов на Python искать проще, а необходимости переписывания на Golang может и не появиться. А даже если и появится, то программист Python вполне способен разобраться в небольшом сервисе/микросервисе на Golang.
tzlom
16.08.2022 14:37+1Написание этого же кода на Go заняло примерно 4 дня. Дополнительные оптимизации не потребовались. Хотя поначалу разработка на Python шла быстрее, с Go было гораздо меньше возни. Плюсом с Go мы получили более высокую скорость работы кода — в 40 раз быстрее, чем высокооптимизированный код на Python.
Ваша задача должна занимать хотя бы 36 минут времени чтобы как-нибудь оправдать Go вместо Python.
А учитывая чтона Go мы писали уже после того, как написали код на Python, поэтому я лучше понимал сценарий использования;
ясно что эта оценка сильно занижена.
Alexufo
Мне казалось модель асинхронности легче для понимания и дебага, чем многопоточности. Не поэтому ли евент луп кто то в го потащил?