- PVSM.RU - https://www.pvsm.ru -
В один момент мне написали из Ozon: «П̶с̶с̶,̶ ̶п̶а̶р̶е̶н̶ь̶,̶ ̶п̶о̶к̶о̶д̶и̶т̶ь̶ ̶н̶а̶ ̶G̶o̶ ̶н̶е̶ ̶х̶о̶ч̶е̶ш̶ь̶?̶ Предлагаем переход на Golang с текущего стека, обучение за счёт компании».
Каждый инженер десятки раз в своей карьере сталкивается с выбором: оставаться дальше на той технологии, на которой он работает, или уходить на другую. В статье я расскажу, по каким критериям я сравнивал две технологии, и почему принял решение переехать на другой язык.
Среди разработчиков бытует мнение, что язык вторичен. Мол, главное — уметь в computer science, а на чём писать — не так уж важно. Но так считают хардкорные разработчики, они вертят деревья, смотрят на всех свысока и зарабатывают 300кк в наносекунду. Я же программист-полукровка (без высшего технического образования, а ещё мои родители — маглы) и считаю, что смена языка — важный шаг и нужно хорошенько прикинуть, прежде чем в это вписываться. Будем откровенны, если у вас за плечами десять лет на плюсах, вряд ли вам предложат должность senior iOS-разработчика на Swift. Проблема в том, что каждый язык имеет свои особенности и на их изучение требуется время.
Дисклеймер: сравнивая два языка, я не считаю один плохим, а другой — хорошим. У меня также нет цели ответить на вопрос, какой язык лучший (такая постановка в принципе некорректна, ведь каждый язык — для своих задач). Я лишь рассказываю о своём способе
Python как первая любовь
Обожаю этот язык. По-прежнему слежу за ним и экспериментирую с машинным обучением. Он занял ряд ниш, где правит почти единолично: машинное обучение, аналитика, DevOps, скриптинг для различных нужд, например, датафикса. И, конечно же, Python широко используется в вебе. Рейтинг языков программирования PYPL [2] ставит его на первое место с огромным отрывом.
На Python легко состряпать прототип веб-сервиса и получить proof of concept от рынка. Например, на Django можно за считанные дни собрать MVP — сразу бэкенд и фронтенд. Сильнейшее сообщество Python-разработчиков написало кучу прекрасных библиотек, которые дружат с Django так крепко, что в проект можно добавить какие-то хитрые модули буквально парой строк кода.
В 2005 году перестало работать важное следствие закона Мура [3]: «производительность процессоров должна удваиваться каждые 18 месяцев из-за сочетания роста количества транзисторов и увеличения тактовых частот процессоров». Тактовая частота упёрлась в ограничение, но начало расти количество ядер, используемых в процессоре.
Все основные языки, которые используются в бэкенде, были созданы, когда закон Мура работал и казалось, что так будет всегда: C (1972), C++ (1983), Python (1991), Java (1995), PHP (1995), JavaScript (1995), C# (2000). Дизайн этих языков изначально не подразумевал работу с несколькими ядрами.
Go — достаточно молодой язык. Ему всего 12 лет, и он сразу делался с оглядкой на то, что код будет выполняться на нескольких ядрах процессора. И в этом его невероятная сила.
А ещё Go изначально задумывался Робом Пайком [4], как язык, который ускоряет всё: процесс написания кода и процесс компиляции. Никаких ожиданий — всё под девизом «Make programming fun again».
Я всегда мечтал писать хайлоад — и это было первым аргументом в пользу Go. Вы можете возразить, что на Python тоже есть хайлоад, и будете правы. Когда говорят про Python, всегда упоминают, что на нём написаны Instagram и Dropbox.
На сегодняшний день Instagram — проект с самым большим трафиком, написанный на Python [5]. Чтобы заскейлить горизонтально бэкенд на Python при миллиарде MAU (monthly active users), нужно вложить очень много денег в железо — на десятки процентов больше, чем если бы он был написан на более производительном языке. При таких объёмах затраты на железо бьют по карману. Но есть хорошая новость: такая задача в принципе решаема. Скорее в Instagram используют Python, потому что они заложники легаси-кода, который долго и дорого переписывать.
Dropbox, изначально написанный на Python, переписали часть бэка именно на Golang [6]. Некоторые микросервисы до сих пор работают на Python, но это периферийная ненагруженная часть, core-функционал переписан на Go. И причина простая — Golang более производительный.
Основной язык бэкенда компании Lyft — Python. Агрегатор вычислил стоимость железа на одну поездку в такси, заказанную через приложение, — 14 центов [7]. Количество поездок, совершённых в 2018 году, — порядка 650 миллионов [8]. Lyft тратил 100 миллионов долларов в год на инфраструктуру, и сейчас эта сумма ещё больше. Если бы это был Golang стоимость железа могла бы быть меньше на несколько десятков миллионов долларов.
Хайлоаду важен производительный бэкенд — это вопрос экономики. Железо дешевле, чем люди, но на объёмах в сотни миллионов MAU затраты на разработку сравнимы по цене с железом, и выбор непроизводительного языка может привести компанию в ловушку, когда на железо будут сливаться сотни миллионов долларов в год. При этом переписывание бэкенда тоже влетит в копеечку, а, возможно, и вовсе будет невыполнимой задачей.
У Python есть три фундаментальные проблемы:
Тут нужно оговориться, что невысокая скорость Python — это не баг, а фича. Это расплата за лёгкий синтаксис, с которым можно не заботиться о памяти. Возможность создавать резиновые списки, hashmap’ы, set’ы и т. д. не может быть бесплатной.
Golang же идеален для написания хайлоада. Распараллелить флоу программы на несколько ядер и собрать результат воедино можно без танцев с бубном, а с помощью синтаксиса из коробки. Тут стоит упомянуть, что многоядерность — это не панацея и что она работает до определённого предела.
По закону Амдала [9], при распараллеливании вычислений быстро достигается предел производительности, после чего дополнительные ядра не обеспечивают предельной производительности.
Ещё одним преимуществом 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?» — в стандарте [10] дан ответ: «Ну мы же говорим про один очевидный способ». А какой из них очевидный-то?
Там же в стандарте кодеры ругаются, что синтаксический сахар затрудняет чтение.
В 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, но зато паттерны видны сразу, постоянно встречаются одни и те же конструкции, которые упрощают коммуникацию разработчиков через код.
У 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 [11], медианная зарплата Go-разработчиков выше, чем у разработчиков на Python, на 27%: $75 669 против $59 454. В России, по данным Хабр Карьеры [12], разрыв ещё больше — 38%: 180 000 рублей против 130 000 рублей.
Здесь стоит упомянуть, что на Python, например, пишутся парсеры и прочие скриптовые истории, — они тянут медиану зарплат вниз. Но если взять 90-ый процентиль, то есть 10% самых дорогих специалистов, то разница между самыми дорогими разработчиками на Go и на Python составит примерно 10%. Для меня это был приятный бонус при переезде.
Тут стоит упомянуть, что переход на другую технологию почти всегда сопровождается падением по зарплате. Рынок верит в то, что опыт работы на конкретном языке важнее, чем опыт в целом. Но когда тебя хантят, то тебе компенсируют упущенную выгоду на твоём языке. Ты можешь учиться за счёт работодателя, что является приятным бенефитом.
Отрефлексировав свой опыт, я убедился в правильности своего решения о переезде на Go:
Но и Python я забывать не планирую. Я внимательно слежу за ним и продолжаю решать на нём свои задачи.
Автор: Александр Ильин
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/370862
Ссылки в тексте:
[1] мышления: http://www.braintools.ru
[2] PYPL: https://pypl.github.io/PYPL.html
[3] закона Мура: https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%9C%D1%83%D1%80%D0%B0
[4] изначально задумывался Робом Пайком: https://youtu.be/rKnDgT73v8s?t=165
[5] написанный на Python: https://thenewstack.io/instagram-makes-smooth-move-python-3/
[6] именно на Golang: https://habr.com/ru/post/335056/
[7] 14 центов: https://twitter.com/mohapatrahemant/status/1102401615263223809
[8] порядка 650 миллионов: https://expandedramblings.com/index.php/lyft-statistics/
[9] По закону Амдала: https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%90%D0%BC%D0%B4%D0%B0%D0%BB%D0%B0
[10] стандарте: https://www.python.org/dev/peps/pep-0584/#id3
[11] исследования Stack Overflow: https://insights.stackoverflow.com/survey/2021#technology-top-paying-technologies
[12] данным Хабр Карьеры: https://career.habr.com/user_graphs/468?utm_source=habr&utm_medium=megapost&utm_campaign=salaries1h2021
[13] входят в топ-3: https://habr.com/ru/article/569026/
[14] Источник: https://habr.com/ru/post/598381/?utm_source=habrahabr&utm_medium=rss&utm_campaign=598381
Нажмите здесь для печати.