В один момент мне написали из Ozon: «П̶с̶с̶,̶ ̶п̶а̶р̶е̶н̶ь̶,̶ ̶п̶о̶к̶о̶д̶и̶т̶ь̶ ̶н̶а̶ ̶G̶o̶ ̶н̶е̶ ̶х̶о̶ч̶е̶ш̶ь̶?̶ Предлагаем переход на Golang с текущего стека, обучение за счёт компании».
Каждый инженер десятки раз в своей карьере сталкивается с выбором: оставаться дальше на той технологии, на которой он работает, или уходить на другую. В статье я расскажу, по каким критериям я сравнивал две технологии, и почему принял решение переехать на другой язык.
![](https://habrastorage.org/webt/2z/0-/3d/2z0-3db7nbidnehdjk0wid8i3mw.png)
Среди разработчиков бытует мнение, что язык вторичен. Мол, главное — уметь в computer science, а на чём писать — не так уж важно. Но так считают хардкорные разработчики, они вертят деревья, смотрят на всех свысока и зарабатывают 300кк в наносекунду. Я же программист-полукровка (без высшего технического образования, а ещё мои родители — маглы) и считаю, что смена языка — важный шаг и нужно хорошенько прикинуть, прежде чем в это вписываться. Будем откровенны, если у вас за плечами десять лет на плюсах, вряд ли вам предложат должность senior iOS-разработчика на Swift. Проблема в том, что каждый язык имеет свои особенности и на их изучение требуется время.
Дисклеймер: сравнивая два языка, я не считаю один плохим, а другой — хорошим. У меня также нет цели ответить на вопрос, какой язык лучший (такая постановка в принципе некорректна, ведь каждый язык — для своих задач). Я лишь рассказываю о своём способе мышления и о том, на что я обращал внимание, делая выбор, переезжать или нет.
Python как первая любовь
Обожаю этот язык. По-прежнему слежу за ним и экспериментирую с машинным обучением. Он занял ряд ниш, где правит почти единолично: машинное обучение, аналитика, DevOps, скриптинг для различных нужд, например, датафикса. И, конечно же, Python широко используется в вебе. Рейтинг языков программирования PYPL ставит его на первое место с огромным отрывом.
![](https://habrastorage.org/webt/2c/ks/_4/2cks_47fj4itioprztxz05iv3pe.png)
На Python легко состряпать прототип веб-сервиса и получить proof of concept от рынка. Например, на Django можно за считанные дни собрать MVP — сразу бэкенд и фронтенд. Сильнейшее сообщество Python-разработчиков написало кучу прекрасных библиотек, которые дружат с Django так крепко, что в проект можно добавить какие-то хитрые модули буквально парой строк кода.
Golang — вечно молодой
В 2005 году перестало работать важное следствие закона Мура: «производительность процессоров должна удваиваться каждые 18 месяцев из-за сочетания роста количества транзисторов и увеличения тактовых частот процессоров». Тактовая частота упёрлась в ограничение, но начало расти количество ядер, используемых в процессоре.
![](https://habrastorage.org/webt/kw/1s/jf/kw1sjfs7i-n6bxklng2sen2u8ys.jpeg)
Все основные языки, которые используются в бэкенде, были созданы, когда закон Мура работал и казалось, что так будет всегда: C (1972), C++ (1983), Python (1991), Java (1995), PHP (1995), JavaScript (1995), C# (2000). Дизайн этих языков изначально не подразумевал работу с несколькими ядрами.
Go — достаточно молодой язык. Ему всего 12 лет, и он сразу делался с оглядкой на то, что код будет выполняться на нескольких ядрах процессора. И в этом его невероятная сила.
А ещё Go изначально задумывался Робом Пайком, как язык, который ускоряет всё: процесс написания кода и процесс компиляции. Никаких ожиданий — всё под девизом «Make programming fun again».
Плох тот бэкендер, который не хочет писать хайлоад
Я всегда мечтал писать хайлоад — и это было первым аргументом в пользу Go. Вы можете возразить, что на Python тоже есть хайлоад, и будете правы. Когда говорят про Python, всегда упоминают, что на нём написаны Instagram и Dropbox.
На сегодняшний день Instagram — проект с самым большим трафиком, написанный на Python. Чтобы заскейлить горизонтально бэкенд на Python при миллиарде MAU (monthly active users), нужно вложить очень много денег в железо — на десятки процентов больше, чем если бы он был написан на более производительном языке. При таких объёмах затраты на железо бьют по карману. Но есть хорошая новость: такая задача в принципе решаема. Скорее в Instagram используют Python, потому что они заложники легаси-кода, который долго и дорого переписывать.
Dropbox, изначально написанный на Python, переписали часть бэка именно на Golang. Некоторые микросервисы до сих пор работают на Python, но это периферийная ненагруженная часть, core-функционал переписан на Go. И причина простая — Golang более производительный.
Основной язык бэкенда компании Lyft — Python. Агрегатор вычислил стоимость железа на одну поездку в такси, заказанную через приложение, — 14 центов. Количество поездок, совершённых в 2018 году, — порядка 650 миллионов. Lyft тратил 100 миллионов долларов в год на инфраструктуру, и сейчас эта сумма ещё больше. Если бы это был Golang стоимость железа могла бы быть меньше на несколько десятков миллионов долларов.
Хайлоаду важен производительный бэкенд — это вопрос экономики. Железо дешевле, чем люди, но на объёмах в сотни миллионов MAU затраты на разработку сравнимы по цене с железом, и выбор непроизводительного языка может привести компанию в ловушку, когда на железо будут сливаться сотни миллионов долларов в год. При этом переписывание бэкенда тоже влетит в копеечку, а, возможно, и вовсе будет невыполнимой задачей.
У Python есть три фундаментальные проблемы:
- GIL (global interpreter lock) съедает профит от concurrency. GIL нужен для того, чтобы синхронизировать потоки для работы сборщика мусора. При изменении количества ссылок на переменные GIL блочит все потоки и даёт исполняться только одному. Те, кто пишут код на Python, давно просят разработчиков языка убрать GIL, но он пустил свои корни так глубоко, что, скорее всего, останется с нами навсегда.
- Перед выполнением любых операций с любыми объектами Python проверяет их тип. Это боль языков с динамической типизацией, которая съедает производительность.
- Почти все объекты в Python аллоцируются на куче, а не на стеке. Неиспользуемая память на куче освобождается медленнее.
Тут нужно оговориться, что невысокая скорость Python — это не баг, а фича. Это расплата за лёгкий синтаксис, с которым можно не заботиться о памяти. Возможность создавать резиновые списки, hashmap’ы, set’ы и т. д. не может быть бесплатной.
Golang же идеален для написания хайлоада. Распараллелить флоу программы на несколько ядер и собрать результат воедино можно без танцев с бубном, а с помощью синтаксиса из коробки. Тут стоит упомянуть, что многоядерность — это не панацея и что она работает до определённого предела.
По закону Амдала, при распараллеливании вычислений быстро достигается предел производительности, после чего дополнительные ядра не обеспечивают предельной производительности.
![](https://habrastorage.org/webt/s0/ju/tl/s0jutln_o0d6wuxd6kqj_pyk8ke.jpeg)
Ещё одним преимуществом Go являются горутины. Это легковесные потоки исполнения программы. В отличие от тредов в операционной системе горутины:
- быстро стартуют;
- имеют расширяемый стек памяти;
- могут эффективно коммуницировать друг с другом через пакет sync и каналы;
- менеджерятся планировщиком от Go и не завязываются на ОС.
Читаемость и предсказуемость кода
На одно написание кода приходится в среднем пять его прочтений. А некоторые критические места любого сервиса перечитываются десятки раз. В Zen of Python есть такие строки:
Должен существовать один — и, желательно, только один — очевидный способ сделать что-то
На деле мне как-то на собеседовании задали вопрос про то, сколько существует способов развернуть список.
lst = [1, 2, 3, 4, 5]
# 1, разворачивает список in-place, возвращает None
lst.reverse()
# 2, возвращает reversed object, который надо завернуть в list()
new_lst = list(reversed(lst))
# 3, разворачивает список с использованием слайса, возвращает новый объект списка
new_lst = lst[::-1]
Очень легко запутаться и забыть, какой способ что возвращает. Это порождает ошибки.
Python пошёл по пути добавления синтаксического сахара. В какой-то момент его стало чересчур много. Например, объединить два хешмапа до версии 3.9 можно было вот таким способом:
new_dict = {**dict1, **dict2}
Но в 3.9 для этой операции появился ещё один вариант:
new_dict = dict1 | dict2
На вопрос: «А как же Zen of Python?» — в стандарте дан ответ: «Ну мы же говорим про один очевидный способ». А какой из них очевидный-то?
Там же в стандарте кодеры ругаются, что синтаксический сахар затрудняет чтение.
В Golang нет built-in-способа объединить два хешмапа. Приходится делать так:
for k, v := range b {
a[k] = v
}
Ужасно? Но я сразу понимаю замысел программиста, который писал этот код.
Синтаксический сахар порой становится миной замедленного действия. Например, в Python есть прекрасное средство для быстрого создания списков — list comprehension.
lst = [i for i in range(5)] # [0, 1, 2, 3, 4]
Но если такое средство есть, то в один момент ты встречаешь в чужом коде вот такую конструкцию.
init_data_struct = [{'a': 10, 'b': 20}, {'p': 10, 'u': 100}]
# нам нужно объединить два словаря внутри списка, выкинув оттуда ключи 'b','u'
new_data_struct = [[(k,v) for k,v in d.items() if k not in ['b','u']] for d in init_data_struct]
# [[('a', 10)], [('p', 10)]]
И чип начинает искриться. А что делает эта конструкция? Что хотел сказать автор? Сложность кода и так растёт экспоненциально. А если это часть какой-нибудь функции-портянки строк на 50, то восприятие теряется, ты снова и снова утыкаешься в это место и не понимаешь, что происходит. Я наблюдал, как среди разработчиков иногда начинается гонка, как уложить код в как можно меньшее количество строк. В итоге получается огромная цепочка вызовов в рамках строки — и никто не знает, как она работает.
В Golang реально есть только один очевидный способ сделать что-то. Без дзенов. Там просто нет синтаксического сахара. На написание любой конструкции требуется больше кода, чем в Python, но зато паттерны видны сразу, постоянно встречаются одни и те же конструкции, которые упрощают коммуникацию разработчиков через код.
Статическая vs динамическая типизация
У Python динамическая типизация — это значит, что тип переменной определяется в рантайме. У Go тип переменной определяется при компиляции.
a := "UpdateReviewStatus"
b := 1
c := a + b
Этот код в Golang просто не скомпилируется. Возможно, дело даже не дойдёт до компиляции, так как IDE начнёт ругаться и разработчик заметит это. Проект на Python с подобным кодом запустится, но выдаст ошибку в рантайме (хотя и тут IDE поругается и укажет на ошибки). За это Go-разработчики расплачиваются тем, что приходится писать похожие функции для разных типов. Кажется, небольшая плата за баги, отловленные на моменте компиляции. Если код на Go скомпилировался, то он рабочий в подавляющем большинстве случаев.
В версии Python 3.6 появились аннотации типов. Они подсказывают разработчику, какой тип заходит в функцию и что возвращается. Аннотации типов сделаны для того, чтобы подсказать разработчику, как функция работает. Даже если передать в функцию с аннотированными типами значения с другими типами, код запустится и будет работать.
def add(x: int, y: int) -> int:
return x + y
add("a", "b")
# ab
На аннотацию типов немного поругается IDE, а в остальном интерпретатор будет безразличен. Многие разработчики считают, что аннотация типов — это не Pythonic way. Хотя лично я считаю аннотации обязательными: с ними код читается гораздо легче, хоть и нет никаких гарантий, что в функцию зайдёт нужный тип.
Где больше денег, Лебовски?
По данным исследования Stack Overflow, медианная зарплата Go-разработчиков выше, чем у разработчиков на Python, на 27%: $75 669 против $59 454. В России, по данным Хабр Карьеры, разрыв ещё больше — 38%: 180 000 рублей против 130 000 рублей.
Здесь стоит упомянуть, что на Python, например, пишутся парсеры и прочие скриптовые истории, — они тянут медиану зарплат вниз. Но если взять 90-ый процентиль, то есть 10% самых дорогих специалистов, то разница между самыми дорогими разработчиками на Go и на Python составит примерно 10%. Для меня это был приятный бонус при переезде.
Тут стоит упомянуть, что переход на другую технологию почти всегда сопровождается падением по зарплате. Рынок верит в то, что опыт работы на конкретном языке важнее, чем опыт в целом. Но когда тебя хантят, то тебе компенсируют упущенную выгоду на твоём языке. Ты можешь учиться за счёт работодателя, что является приятным бенефитом.
Вывод
Отрефлексировав свой опыт, я убедился в правильности своего решения о переезде на Go:
- Во многих технологических компаниях он стал языком номер один. Если всё будет хорошо, то Golang станет стандартом высоконагруженного бэкенда — кажется, к этому всё и идёт.
- На Go пишется хайлоад, а это другой уровень задач и их разнообразия. В Ozon в период осенних распродаж держали планку в 5000 заказов в минуту.
- У Go прозрачный синтаксис и статическая типизация, что улучшает читаемость кода и уменьшает количество просаженных багов.
- Go-разработчикам больше платят. В России они вообще входят в топ-3 по зарплатам.
Но и Python я забывать не планирую. Я внимательно слежу за ним и продолжаю решать на нём свои задачи.
Комментарии (105)
MentalBlood
28.12.2021 16:56+11new_data_struct = [[(k,v) for k,v in d.items() if k not in ['b','u']] for d in init_data_struct]
Можно использовать форматирование:
new_data_struct = [ [ (k, v) for k,v in d.items() if k not in ['b','u'] ] for d in init_data_struct ]
JJOSKEY Автор
28.12.2021 17:00+3Да, вы правы. Но, кажется, с форматированием, код не стал понятнее. Хотя это моя вкусовщина, но я бы точно поставил nitpick, когда ревьювил код.
VPryadchenko
28.12.2021 23:01+1Лёгкость понимания таких конструкций дело привычки, а форматировать их не можно, а нужно )
perestroika
29.12.2021 12:34+7Тогда уж лучше просто:
new_data_struct = [] for d in init_data_struct: for k, v in d.items(): if k in ['b', 'u']: new_data_struct.append((k, v)
OGR_kha
28.12.2021 17:23+3# нам нужно объединить два словаря внутри списка, выкинув оттуда ключи 'b','u'
[[('a', 10)], [('p', 10)]]
Так задача не выполнена. Получилось не объединение словарей внутри списка, а список списков кортежей
JJOSKEY Автор
30.12.2021 14:41Хотел хитрый пример найти, но, видимо, не получилось ( замечание полностью валидно, сорян (
katletmedown
28.12.2021 17:26+2Те, кто пишут код на Python, давно просят разработчиков языка убрать GIL
Вы драматизируете, с этим вполне можно жить не слишком страдая.
RC_Cat
28.12.2021 17:30+2Вы драматизируете, с этим вполне можно жить не слишком страдая.
Но зачем жить и страдать. Тоже как автор перекатился на Go.
katletmedown
28.12.2021 17:33+3Тогда поподробнее, в чем заключались ваши страдания?
RC_Cat
28.12.2021 20:24GIL
Настройка venv для каждого проекта
Отсутствие типизации
katletmedown
28.12.2021 20:54+6Ещё конкретнее) GIL вам мешал в ситуации, когда... Я не издеваюсь, просто пишу конкурентные программы, и мне не мешает, вдруг я что-то не так делаю.
igrishaev
29.12.2021 15:53+1Не совсем про GIL, но все же: была задача распарсить лог апача на 10 гигов и собрать стату. Программа на питоне делала это час, программа на си — пять минут.
masai
29.12.2021 16:39+1Так речь же о GIL. Просто его очень часто упоминают как недостаток, но потом оказывается, что не особо он и мешает в большинстве случаев.
masai
29.12.2021 16:50+1Создание venv — одноразовый процесс, который легко автоматизируется с помощью того же Poetry.
Про GIL было бы интересно послушать, как именно он мешал. Какие-то экзотические задачи были?
Отсутствие статической проверки типов — тут соглашусь, в больших проектах не хватает. Mypy, увы не очень удобен.
RC_Cat
30.12.2021 16:20Мне нужно скачать 100k файлов с разных ресурсов и записвать в файлы. Может я что-то делаю не так, но работает это не очень быстро.
masai
30.12.2021 22:43Это как раз типичная I/O-bound задача. Почему Вы думаете, что тормозит из-за GIL? Тут он как раз не очень мешает.
Посмотрите презентацию с EuroPython 2019. Там миллиард файлов скачивали примерно за 8 часов (синхронный код работал 48 дней). Использовали комбинированный подход: asyncio + потоки + процессы.
JJOSKEY Автор
29.12.2021 15:56+1Съедается выгода от асинхронщины. Потому что весь флоу исполняется в один поток. Я не старался драматизировать, но многие говорят об этом. При этом, прекрасно понимаю, что не каждому сервису это нужно. Как я уже сказал в статье, Python решает свои задачи, и делает это хорошо.
masai
29.12.2021 16:47+4Асинхронщина и многопоточность — вещи ортогональные. Она и без GIL однопоточная, если сами поток не запустите.
GIL мешает только если вы параллельно делаете вычисления на чистом Python (что бывает очень редко), то есть у вас CPU-bound задача. А большинство задач на чистом Python I/O-bound, и тут GIL не мешает вовсе.
К тому же в расширениях GIL можно отпускать, что и делают всякие числодробильные библиотеки (например, Numpy) — они многопоточные внутри. Можно в Cython легко отпускать его, если не хочется связываться с другими языками.
Разработчики давно говорят, что убрали бы GIL, если кто-то предложит реализацию, которая не замедлит однопоточные скрипты. Пока что такой реализации не видно. Даже в недавно попытке выпиливания GIL прирост скорости от оптимизаций, а не от убирания GIL.
Ну и наконец, есть реализации Python без GIL. Это особенность интерпретатора, а не языка.
JJOSKEY Автор
29.12.2021 18:59Позвольте порассуждаю, если не прав, поправьте. Реально, хочу разобраться.
Работа какого-нибудь апи метода - это не на 100% i/o-bound задача. Там всегда есть cpu-bound составляющая. Парсинг запроса и json'а, формирование запроса в бд, манипуляция с полученными данными, какая-то дополнительная логика, формирование ответа и так далее. Это всё cpu-bound. Значит, что при каких-то понятных нагрузках, в сервисе всегда будут cpu-bound задачи, то есть вся система перейдёт в работу в один поток.masai
29.12.2021 19:50+2Запрос в БД — это I/O bound задача и она на порядок или два дольше, чем всё остальное.
Парсинг JSON — это код, вызывающий библиотеку, написанную на C или C++, и она, скорее всего, отпускает GIL, так что может работать в фоне.
Манипуляция с данными и формирование ответа — это маленький кусочек времени.
Да, на Go код будет работать быстрее, спорить смысла нет, но это больше заслуга того, что Go — компилируемый язык.
Ну и никто не отменял запуск отдельных процессов-воркеров. На процессы GIL никак не влияет.
Я не говорю, что GIL полезен. Нет, если бы можно было без него, то конечно было бы лучше. К сожалению, он появился не просто так и от него не так просто избавиться.
Я лишь хочу сказать, что GIL часто называют среди главных недостатков Python (точнее CPython). У языка много недостатков, но GIL далеко не главный, и Python медленный в типовых задачах вовсе не из-за него.
vtb_k
29.12.2021 21:13Парсинг JSON — это код, вызывающий библиотеку, написанную на C или C++, и она, скорее всего, отпускает GIL, так что может работать в фоне.
Парсинг json'a в недавнем проекте съедал 40% всего времени работы в профайлере
masai
29.12.2021 21:47+1Я не говорил, что это быстро, я лишь утверждал, что это делается внутри библиотеки, которая теоретически может отпускать GIL. Впрочем, я подумал, там, скорее всего GIL всё же будет, так как внутри строится дерево питоновских объектов.
40 % выглядит как довольно большая доля. Не пользуетесь базой или у вас JSON такие большие?
В любом случае решение нужно принимать исходя из проекта. Если у вас нагрузка — запрос в минуту и 40 % — это процент от 10 мс, которые устраивают пользователя, то всё прекрасно.
Если вы не можете использовать процессы по каким-то причинам и нужны именно потоки, и упирается всё именно в то, что декодирование JSON не отпускает GIL, тогда Python не для вас.
Я вовсе не пропагандирую Python сейчас.
vtb_k
30.12.2021 01:07+1В любом случае решение нужно принимать исходя из проекта. Если у вас нагрузка — запрос в минуту и 40 % — это процент от 10 мс, которые устраивают пользователя, то всё прекрасно.
Я просто перекладываю json'ы из кафки в базу. И чем больше база, тем дольше перекладывать. Занимало в среднем 24-32 часов для базы ~500гиг. Переписали на го и теперь 12-14 часов. Json'ы сложные, многоуровневые документы
pesh1983
30.12.2021 10:02+2Тут часто время зависит от того, какую библиотеку вы для этого использовали. Стандартная медленная, попробуйте https://github.com/ijl/orjson.
Terras
28.12.2021 17:30+10«большого количества вакансий для Python-разработчиков — изи катка для входа в профессию» — это ложь, на бек на Python вакансий меньше, чем на C#/Java/PHP и там требуется сразу адекатные ребята с прямыми руками.
Лучше скажи автор честно — насмотрелся инфоцыган и повелся на хайп.JJOSKEY Автор
29.12.2021 16:03Иду прямо сейчас на hh.ru, выбираю Москва. Ищу только Junior вакансии:
"python junior": 264 вакансии;
"java junior": 192;
"php junior": 93;
"php junior": 93.
Ну и я сам нашёл работу джуном без проблем. Кажется, ваш поинт невалиден )Terras
29.12.2021 17:32+1Может быть со знанием Django можно пойти на:
Product/Data Analyst (Junior)
Junior Data Scientist
Разработчик ботов (Python & JS)
Junior ML Engineer
Инженер поддержки (Junior)
Младший специалист по верификации RTL (Junior)
Стажёр-инженер АСУ / Automation junior engineer
И прочие непрофильные сферы, которые показываются по этому запросу? Или инфоцыгане научили, что на Питон вакансий куча, а то что, ты со знанием Django не сможешь пойти в условный ML или QA-Automation (так как это другая сфера и нужен другой стек знанаий) как-то забыли объяснить? Или вот Junior Devops тоже проходит как python junior?JJOSKEY Автор
29.12.2021 18:43Не понимаю, при чём здесь инфоцыгане? Я даже курс не покупал, когда начинал, учился сам. Вы хотите оспорить тезис про популярность языка Python? Пыху он точно подвинет. C# и Java, кажется, для других задач, Python им тоже не конкурент.
almaz1c
28.12.2021 18:00Есть ли в Go, какой-нибудь условно типовой стек наподобие Питоновского: Flask + SQL-Alchemy + Alembic? Было бы интересно узнать, насколько сложно было перейти с Python на Go в бэкенде, заменив один стек на другой, оставив при этом применяемые и тут и там: Docker, Postgersql и Postman?
valis
28.12.2021 19:07+2Я не юзаю пока как таковые веб фреймворки. Мне роутера Gorilla/Mux за глаза.
С докером вообще круто - юзаешь самый минимальный контейнер после билда.
Я даже на Golang реализовывал немного машинного обучения (распознание лиц)
rinat_crone
28.12.2021 20:01+1Почитайте вот эту статью: habr.com/ru/company/agima/blog/591435. Для новичка в Го она будет неплохим стартом для погружения.
random1st
28.12.2021 20:30Там конкретного стека нет, но на Go и не пишут монолиты. Есть какие-то простейшие фреймворки - отдельно для работы с базой, отдельно для HTTP API (если встроенной недостаточно) и прочее. Попытки наворотить что-то наподобие Django есть - но это совсем не тру.
JJOSKEY Автор
29.12.2021 16:07+2В Go нет ORM. Точнее есть, но сообщество пришло к тому, что это не Go way.
По поводу фреймворка, они есть, но Golang используют в основном в крупных корпорациях, и там юзают свою обвязку на Golang.
Так что в Go фреймворк вторичен, нужно учить сам язык и синтаксис. Также советую посмотреть вот этот видосик, он прольёт больше света по проблеме, которую вы озвучили: https://youtu.be/XR9NiwuiK-k
OlegZH
28.12.2021 18:24+2Сам по себе переход на другой язык программирование — это сама по себе хорошая идея. Надо меняться.
valis
28.12.2021 19:08+4Сам перешел и не жалею! Это по моему мнению самый логичный язык программирования из всех, что я только учил (помимо Python JS,C#, Dart, Visual Basic, Delphi, Lua)
GBR-613
28.12.2021 19:10+1Интересно, что народ думает про Юлю? (Она же Julia.) Её разработчики утверждают, что она проста как Питон и при этом быстра как С, но у меня что-то нет особого впечатления, что ей кто-то пользуется. Почему?
omxela
28.12.2021 22:53+1Чтобы переползти на новый язык, нужна мотивация и немного любопытства. Юлия столь же молода, что и GoLang. При этом её изначально позиционировали как вычислительный язык. Ну, типа, фортран сегодня. Вернее, Матлаб, но быстрый. Вот название русскоязычного руководства: "Язык программирования математических вычислений JULIA". Это сильно сбивает, на самом деле. Язык современный, действительно очень простой, но при этом подключает питоновские библиотеки, например. И фортрановские. И сишные. Параллельный не хуже Go. Но вот кому он нужен и где используется - вопрос. Мне хорошо - я одиночка, программирую физические задачки, сделал пару проектов на Юлии просто из чистого любопытства. Поставил галочку - и вернулся обратно. Не думаю, что у этого чудесного языка есть какие-то широкие перспективы, кроме его узкой ниши. Ну, отрежет он что-то у R. Что-то у Питона (биг дату немножко). У Матлаба, безусловно (если он кому-то нужен). Это не тот размах, имхо.
z0ic
29.12.2021 00:10+2Julia это достойная (и бесплатная) замена таким системам, как Matlab или R. Последнее время в неё вливаются колоссальные деньги https://juliacomputing.com/media/2021/07/series-a/. Но это не язык общего назначения, у неё очень тяжеловесная среда, примерно как Anaconda.
GBR-613
29.12.2021 08:09Если программу можно откомпилировать, кому потом помешает тяжеловесная среда?
В чём заключается это "не язык общего назначения"? Нет средств для HTML? GUI? Это вопрос наличия библиотек, а не языка.
masai
29.12.2021 16:56Идея у языка интересная (хоть и есть странности в дизайне), но нет экосистемы, а без неё никто на Julia переходить не будет.
worldmind
28.12.2021 20:22+6Вот что-то никогда го меня не возбуждал (хотя может я просто не понял чего, не углублялся):
Exceptions убрали, но ничего взамен для error propagation не предложили, возвращай кол ошибки как в сяз, зотя именно из-за этого эксепшены и появились. Как понимаю в расте слелали нормально.
Компилятор не ловит null-pointer exception, можно получить его в проде, расты/хаскелы ловят на сталии компиляции.
Нет дженериков, надо или копипастить код или кодогенерацией заниматься, не аккуратно как-то. Везде считай есть
Нет механизма чистки языка от легаси, помню был какой-то косяк со строками, который видимо никогда не пофиксят из-за обратной совместимости. В расте вроде решили.
icecube092
28.12.2021 23:24+2В расте все хорошо. Только попробуй найти работу на нем :)
А дженерики через пару месяцев завезут, но их отсутствие не проблема
worldmind
29.12.2021 00:59+1Да, работы нет.
Ну поглядим, давно говорят, если дженерики заведут, то по идее и null-pointer проблему можно пофиксить, но опять же на практике обратная совместимость не позволит.
WASD1
29.12.2021 15:56+2Не понял, а как дженерики связаны с NPE?
NPE - это же завезти "засахаренную ad-hoc монаду Maybe" + поломать обратную совместимость (в Java / С# вон уже сколько лет пытаются - не выходит аленький цветочке).marshinov
30.12.2021 09:22+1Ну в c# получилось (почти) для новых проектов (хотя для value и reference сделано по разному), а в Java получился Kotlin. Стало получше. Но в общем случае вы правы, надо вообще к херам систему типов ломать, чтобы совсем null победить
AnthonyMikh
30.12.2021 17:35Но в общем случае вы правы, надо вообще к херам систему типов ломать, чтобы совсем null победить
Нет, нет, нет. Само наличие null в системе типов — это баг, который пошёл ещё от Алгола. Убрать null — это не сломать систему типов, а, наоборот, починить.
QeqReh
29.12.2021 07:16-1Компилятор не ловит null-pointer exception, можно получить его в проде, расты/хаскелы ловят на сталии компиляции.
Существует линтер: https://staticcheck.io/docs/checks#SA5011
worldmind
29.12.2021 10:26+1Это хорошо, но это костыль, придётся всё обложить проверками, хотя в идеали они нужны только там где пустое значение может быть использовано.
QeqReh
30.12.2021 09:37Линтеры приучают писать корректный и правильный код.
Код надо покрывать тестами.
И уже научившись писать правильно у тебя не будет проблем с nil-pointer.
worldmind
30.12.2021 10:45Гыгы, слышал похожие рассуждения про перл. Зачем тогда изобретают новые языки? Так можно сказать, что и на си можно писать правильный код.
Насколько знаю го появился как раз потому что умные и талантливые гуглеры (знающие почему люки круглые и решающие весь letitcode за вечер) не осиливали писать правильный код.
143672
29.12.2021 12:35В 18 версии дженерики. Я либу пишу, чтоб перенести Option, Result, Either в Go. Конечно enum типа нет и размер структуры будет из за этого больше, но проблема с nil pointer будет решена, как в скале. Если все просто начнут использовать option и явно его обрабатывать
worldmind
29.12.2021 14:50+2Не, надо чтобы по умолчанию nil был невалидным значением для типа указатель.
dikey_0ficial
29.12.2021 13:47вместо экзепшнов есть panic, генерики уже в бете, легаси потихоньку чистят. вот нулпоинтеры это грустно, пару раз попадался вроде бы рабочий код, но с неинициализированными мапами, в итоге всё ломалось
JJOSKEY Автор
29.12.2021 16:11+1Да, по началу самого бесили эти постоянные if err != nil, но сейчас привык, и мне нравится. Перехват ошибки может осуществляться где-то в непонятном месте, что увеличивает когнитивную сложность системы, а тут ты ошибки протягиваешь через цепочку исполнения и явно видишь их.
Проблема, согласен.
Дженерики завозят скоро.
Всё-таки, к этому можно по-разному относится. Для кого-то это преимущество, и возможность без проблем обновлять систему на новую версию языка.
worldmind
29.12.2021 16:41Так понятно что исключения это разновидность go to, но не руками же пробрасывать коды ошибок по всему стэку, в расте вроде макрос для этого есть.
Ну в реальном мире сходу идеально никто не умеет делать, надо развивать и фиксить, обратная совместимость тормозит и даже блокирует развитие, для беспробоемного обновления нужны другие механизмы, вроде фиксации версии языка, могу наврать, но вроде в расте так сделали.
random1st
28.12.2021 20:34+10Какой смысл ограничиваться одним языком вообще? Я знаю что на питоне я смогу написать быстро сложную бизнес-логику с тяжелыми зависимостями, а Go использовать для оптимизации отдельных частей. Если понадобится CMS - я возьму Wordpress, просто потому что в код мне придется заглядывать крайне редко. Еще что-то - Java тоже рабочий инструмент. Go как раз тем и хорош, что можно обвешаться линтерами, помимо уже имеющихся ограничений, и писать по крайней мере читабельный код. Но это не значит, что он лучше Python, это значит, что в него порог входа ниже. На самом деле после питона на голанг пишешь и страдаешь. Возможно, выходцам из PHP он лучше заходит :)
QeqReh
29.12.2021 07:19-1Поддерживаю. Языки программирвоания это по сути инструменты со своей экосистемой, и все наилучше подходят для разных задач. Нет универсальных языков.
dzaytsev91
29.12.2021 16:26+1У меня ровно обратные ощущения после перехода на го, на питон смотреть больно. А вообще изучение новых языков сильно помогает развить кругозор, замыкаясь в одном языке перестаешь видеть его проблемы, например питонисты до сих пор считают что GIL не проблема или что питон быстрый язык. В целом не надо быть рокстар программистом чтобы понимать что разные языки программирования подходят под разные ситуации и не нужно микроскопом забивать гвозди
masai
29.12.2021 17:04например питонисты до сих пор считают что GIL не проблема
Приведите, пожалуйста, какой-то конкретный пример из Вашей практики, когда GIL сильно мешал и ничего нельзя было сделать.
или что питон быстрый язык.
Это где такие утверждения? Питонисты так не считают.
uldashev
28.12.2021 23:11+3Dropbox, изначально написанный на Python, переписали часть бэка именно на Golang.
А я помню эту историю, когда пошел хайп, переписывать все на Go, хипстеры из Dropbox тутже кинулись перписывать все с python на golang, конференции, статьи, много шума, закончилось тем, что часть они таки перписали, но вот производительность была не на много выше чем у python, а тут rust пошел на хайп и что? правильно - перпишем все на rust. И в результате, пока google drive, onedrive? да тот же yandex пилили новые фичи, команда dropbox занималась перписыванием старых, кончилось все закономерно, а ведь когда то dropbox был №1 в мире облачных хранилищ.
z0ic
29.12.2021 00:19+1Чтобы чип не искрился при виде [[(k,v) for k,v in d.items() if k not in ['b','u']] for d in init_data_struct] нужно было учить Хаскель. Кстати, на нём даже веб-сервисы можно программировать (наверное).
RarogCmex
30.12.2021 21:17Можно, я пробовал WAI/Warp. Проблема в том, что хаскель -- это такой C++ от мира функциональщины, и я в один момент начал болеть и перестал справляться с его сложностью. А ещё Servant -- фреймворк не для начинающих, проверено на личном опыте.
В тему с пояснениями, почему хаскель рано или поздно должен сдохнуть, кастуется @0xd34df00d
warlock13
29.12.2021 06:00+4На написание любой конструкции требуется больше кода, чем в Python, но зато паттерны видны сразу, постоянно встречаются одни и те же конструкции, которые упрощают коммуникацию разработчиков через код.
Вот как раз существование постоянно повторяемых паттернов, которые видны сразу, означает, что когда вы читаете код, то вы воспринимаете эти самые конструкции-паттерны как целое, как элементы синтаксиса некоего "Го с сахаром", существующего неявно в головах раработчиков на Го. Всё отличие от языков с сахаром только в том, что записываются эти конструкции излишне громоздко, что повышает сложность чтения. То есть простота Го для в меру опытных Го-разработчиков - липовая, по факту она отрицательная.
Да, такой подход, вероятно, делает кривую обучения более пологой, и это может быть и перевешивает минусы, но в статье-то этот вопрос и не рассматривается, а рассматривается читаемость кода, лёгкость понимания того, "что хотел сказать" программист.
При этом в качестве "сложного для понимания кода" почему-то приводится код, как раз более точно и однозначно выражающий это самое что-хотел-сказать, то есть объективно (насколько вообще можно здесь говорить об объективности) как раз более простой для понимания.
QeqReh
29.12.2021 07:37+1Не согласен. Благодаря простоте Go, его код легко читаем. Из-за знакомых конструкций глаз сразу цепляется за нужные места и в целом чтение кода похоже на чтение книги.
Тогда как в языках с сахаром часто приходится ломать голову. Особенно если ты только познакомился с каким-то языком на базовом уровне и начинаешь разбираться в коде какого-то проекта или библиотеки. И такие конструкции часто сложно как-то загуглить.
В итоге тратится больше времени разработчика и в целом увеличивается сложность кода, что чревато ошибками и трудно выявляемыми багами, которые скрыты за магией сахара.
QeqReh
29.12.2021 07:07+2Go — достаточно молодой язык. Ему всего 12 лет, и он сразу делался с
оглядкой на то, что код будет выполняться на нескольких ядрах
процессора. И в этом его невероятная сила.Тут я с вами немножко поспорю. Go это результат опыта полученного от работ над такими языками как Alef и Limbo, а так же платформой plan9. В первых версиях Go был полностью основан на plan9. А это внимание: 1989 год!
Настоятельно рекомендую посмотреть доклад Филиппа Кулина: https://www.youtube.com/watch?v=ql-uncsqoAU
Так что истоки у Go очень древние. Это кстати объясняет подход к работе с ошибками, так как тогда ещё подход с exceptions был не столь популярным среди языков.
медианная зарплата Go-разработчиков выше, чем у разработчиков на Python
Есть предположение, что в этом виноват финтех.
Gizmich
30.12.2021 08:42+2Что странно, в го работать с финансовыми данными не удобно, есть пропозал на добавление нативного decimal64 и decimal128, но это не так модно как дженерики и поэтому движения в эту сторону никакого нету. Кстати кому не лень найдите и лайкните )
worldmind
30.12.2021 10:55Язык-то для сетевых микросервисов, на универсальность не претендовал вроде.
Кстати, пример пхп показывает, что идея языка под задачу не работает в этом мире.
bbc_69
29.12.2021 11:10+4Вот не понимаю я этого гонева на GIL. Всё равно в проде запускаешь всё через какой-нибудь uwsgi с кучей воркеров, которые рассаживаются по разным ядрам. Концепция многопоточности может и не идеальная, но вполне стройная и понятная. Т.е. по факту проигрыш в скорости не такой уж и значительный. Особенно, если запариться над оптимизацией некоторых моментов.
JJOSKEY Автор
29.12.2021 16:16Но в рамках воркера с async/await синтаксисом всё исполняется в рамках одного треда.
bbc_69
29.12.2021 16:20+1И? Процессоры-то все утилизированы. А то, что сделано не так, как в другом языке... Ну тык языки-то разные!
masai
29.12.2021 17:08Но в рамках воркера с async/await синтаксисом всё исполняется в рамках одного треда.
Если это какой-то веб-сервис, который большую часть времени сидит в ожидании I/O, то в чём проблема? Ожидание не блокирует исполнение.
vwvw
29.12.2021 18:46Как я понял, вот откуда "гонево" на GIL:
Основной язык бэкенда компании Lyft — Python. Агрегатор вычислил
стоимость железа на одну поездку в такси, заказанную через приложение, —
14 центов. Количество поездок, совершённых в 2018 году, — порядка 650 миллионов.
Lyft тратил 100 миллионов долларов в год на инфраструктуру, и сейчас
эта сумма ещё больше. Если бы это был Golang стоимость железа могла бы
быть меньше на несколько десятков миллионов долларов.masai
29.12.2021 19:36А где в цитате GIL? Тут о Python в целом. Python менее производительный как минимум потому, что он интерпретируемый, и это не исправить убрав GIL.
Речь не о том, быстрый Python или нет. Очевидно, он проигрывает комилируемым языкам. Речь о том, что если убрать GIL, то код вообще может замедлится.
Ну и ко всему прочему You are not Google.
bbc_69
29.12.2021 21:17Я даже не про конкретно эту статью, а в целом. Любят у питона GIL покритиковать. Есть что-то стереотипное в этом наезде.
marshinov
30.12.2021 09:31+2Докину 5 копеек. В C# быстрее всего поняли, что постоянно трактовая частота расти не будет и завезли async/await, который затем победоносно завезли в JS и Python почти один в один. Плюс у .NET'а сразу был мощный интероп, unsafe и value type. А с появлением .NET 6 с pgo и кучей оптимизаций asp.net вообще ворвался в топ самых быстрых фреймворков по версии tech empower. И все это с дженериками, орм, исключением и возможностью писать коротко. Так что аргумент go моложе, там по-умолчанию все круче, чем в старших собратьях - ну такое:)
yulchurin
30.12.2021 11:06+1Тоже подумывал перейти с PHP на Go, потом посмотрел сравнение производительности Go и PHP8 и передумал.
Может начну изучать Rust...
Gizmich
30.12.2021 11:39+1А в php8 уже можно как-то хранить состояние ? В реальном пииложении выигрыш го дает за счет того что однажды проинициализированные переменные уже существуют в памяти, а php строит все при каждом обращении насколько я знаю...
olafars
30.12.2021 16:26Позвольте возразить.
Вы сравниваете несравниваемое. Два совершенно разных языка для совершенно разных задач.
Как человек, некогда писавший на PHP и перешедший на Go, говорю Вам об этом.
OkunevPY
31.12.2021 08:55+1Свои пять копеек.
Любой хайлоад, настоящий хайлоад, к проектированию которого подошли с головой, а не с парадигмой что нужно взять язык например GoLang и всё взлетит, это всегда сурогат из совершенно разных решений, разных подходов и как правило на разных языках.
Нет универсального языка, нет универсальных решений. Любое решение это всегда компромис, и за частую сюда подмешиваються ещё и факторы доступности разработчиков, финансовые затраты и т.д.
Мы у себя лабаем на чём бог послал пока формируем mvp, потом выделяем критические секции и переписываем на том, что в данном конкретном сценарии покажет лучший результат. Мероприятие крайне затратное, но без этого никогда не получить максимально эффективное решение
mondzucker
31.12.2021 13:50+1Согласен почти со всем! Особенно про неявность в Python.
Предрекали что он уничтожит неявность, а не будет её плодить.Тоже перешёл на Golang в качестве основного. Спустя пару лет некоторых вещей всё-таки не хватает.
kalombo
Сходил по ссылке, там говорится, что они Garbage collector отключают, а не gil. Gil можно отключить в расширениях на си, только придется писать на си)
JJOSKEY Автор
Спасибо огромное, действительно неточность. Убрал эту штуку из статьи.