Привет! Меня зовут Паша, я 6 лет писал бекенды на Ruby и рельсах, и ещё писал фронтенды на React. Я жил в прекрасном мире, где проблематика реализации любой задачи сходилась к поиску готового решения или инструментария.
Что пошло не так? Расскажу эту историю в следующей статье (честное слово в следующей!). Но я стал писать на Go!
В течение двух последних лет в процессе обсуждения старта нового проекта, в котором планировался сервер, первым вариантом стека реализации практически всегда предлагался Go. На мои вопросы: зачем? Поступали ответы: модно, молодёжно, горутины.
Активная PR-кампания Google, популяризирующая язык Go, привела к тому, что люди просто захотели Go.
Давайте разберём, что в этом хорошего и что в этом плохого?
Go — хороший язык программирования
Важный момент, который хочу подчеркнуть. Go — это хороший язык программирования. Создатели языка сразу определили вектор развития языка, его принципы и до сих пор их придерживаются. Несмотря на растущую популярность языка и давление сообщества core-team не поддаётся на провокации и не херачит в язык всё, чего требует коммьюнити.
В отличие от того же самого Rust, который часто меняет интерфейсы стандартной библиотеки, и после минорного обновления может не скомпилится, в Go всё стабильно. Хотя, если говорить про интерфейсы, тут не всё радужно.
В общем, Go — хороший язык программирования. Говорим дальше!
Опять во всём виноват бизнес
Частая ситуация, которая происходит на рынке аутсорс-разработки. В компанию приходит лид, где клиент уже заранее знает язык реализации своего проекта. И этот язык Go. При том клиент, как говорят, нетехнический. С чего он взял, что нужен Go? Очень просто. Проконсультировался вкратце по знакомству, либо он просто сам погуглил (ключевое слово гугл:) ). и сам наткнулся на Go.
Порой переубеждать такого заказчика сложно, а аутсорсу нужны проекты, чтобы деньги зарабатывать. Поэтому безответственные аутсорс-компании начинают вестись на поводу у таких заказчиков, чтобы не потерять их. Начинают делать проекты на Go, в тех случаях, когда лучше использовать другой стек. Проектов на Go становится больше, аутсорс-компании развивают у себя Go-отделы. Начинают учить спецов Go, переучивать людей из других стеков. Потом проектов на Go становится меньше, и аутсорс-компании начинают делать на Go проекты, которые можно было сделать на других стеках, но у них есть спецы в Go, а проект терять не хочется и нужно делать. В итоге проектов на Go становится снова больше.
Итак, мы приходим к тому, что на Go начинают делать проекты, для которых этот язык и его инфраструктура в данный момент совсем не предназначены.
А для чего предназначен Go сегодня?
У Go, как и любого другого языка программирования, есть своя зона применимости. Эта зона определяется как правило исторически. На это воздействует инструментарий, который разрабатывался на этом языке. Популярные и успешные проекты, разработанные с использованием этого языка. Бывают случаи, когда влияет core-team языка, которая держит его фичи на определённом уровне, позволяющем работать именно в той или иной предметной области.
Для чего по-моему скромному мнению предназначен сегодня язык программирования Go. Грубо говоря, что на нём лучше всего делать:
- микросервисы. Хотя большинство из читающих считает это капитанством, потому что слышали со всех сторон, что на Go пишут микросервисы. А ответьте себе на вопрос: а почему удобно писать микросервисы? А? А? Если вы не знаете ответа на этот вопрос, значит, ещё не делали на Go продакшн :) Потому что это становится очевидно через пару недель работы с ним. Главная причина, почему на Go удобно писать микросервисы по моему мнению — это архитектура packag-eй. Если вы когда-нибудь пытались распределить функциональность равномерно по пекеджам по Go-проекту от 3000 строк кода, то заметили, что там ничего бесплатно не получается. Это ты в Ruby можешь подключить в одном файле модуль и использовать его везде по проекту, здесь не так. Такая архитектура как бы намекает на то, что ты должен делать небольшие приложения, иначе плохо будет;
- гружённые процессы — не путать с высоконагруженными системами. Тот случай, когда процессу нужно сделать много связанных друг с другом действий и сделать их быстро, это к Go. Какой-нибудь текстовый процессор, который проверить по десятку словарей некое выражение — пожалуйста. Нужно сделать, чтобы такой процесс работал за < 1 секунды? Вязыке есть все инструменты для этого;
- системные утилиты — должна же быть причина, почему Docker сделан в основном на Go. Никогда не писал системные утилиты, а с такими сложными, как Docker, встречался только как пользователь, поэтому сходу не могу сказать, какие тут преимущества есть у языка. Если кто в курсе, напишите в комментах, буду признателен.
Для чего Go не предназначен, а его туда суют
Тут хочется выделить одну важную вещь: на Go не нужно писать REST!!!
Ну типа можно, но если это набор операций для одной сущности. Только так. Если это одна операция для нескольких сущностей, то нет. Если много операций для многих сущностей, берите Рельсы, Джангу, ASP, Феникс, Spring, что угодно. Навалом отличных инструментов, в большинстве из которых всё работает из коробки, как часы. Тут тебе и стабильная ORM, работающая система миграций в БД, вьюхи, контроллеры. Короче, всё, что мы любим. В Go нет ни одного полноценного веб-фреймворка. Всё нужно собирать из говна и палок.
В последних версиях Go сделали поддержку компиляции в Web Assembly. Здесь никак не буду комментировать, посмотрим, что будет в итоге.
Общие ощущения от языка после 3 месяцев работы
Напомню на всякий случай про свой бекграунд, который был до этого. 6 лет разрабатывал веб-приложения с использование Ruby (в основном Rails) и порой был фулстеком на проекте, делая фронт на (ReactJS и всём компоте, что идёт с ним обычно).
Первое впечатление от языка были в основном отрицательные:
- у меня отобрали все любимые игрушки. Ни тебе мапа, ни тебе редьюса, ни других привычных функций;
- приведение типов работает так как должно работать в Go, но для рубиста — это шок;
- вообще, статическая типизация угнетает после многих лет работы с динамической;
- скудная стандартная библиотека. Привычных методов для работы со строками, числами, другими типами данных, в основном, нет. Да, развернуть строку задом-наперёд с использованием стандартной библиотеки нельзя. Это было грустно. После таких вещей начинаешь ценить то, что есть в Ruby и JS;
- ощущения от того, что пишешь C/C++. Только первое время;
- процедурность: приводит к забытым уже сущностям, например, глобальным переменным. А что? А как ты сохранишь состояние системы, кроме как не глобальной переменной?
- как нет пакетного менеджера? Ну он есть, но по сравнению с рубишным bundler или аналогами, go get не может ровным счётом ничего. А признанных аналогов нет. Да чёрт! Ты даже версию не можешь выставить пакета, которую забрать хочешь. И если не озаботиться этим, то CI быстро выгрузит новую версию, где высоколобый мейнтейнер решил, что пора менять API;
- интерфейсы. Выглядит, как костыль. Который начинают использовать в тех местах, где что-то не нравится. Смотрел исходники разных библиотек, интерфейс там используются в тот момент, когда без него будет сложно организовать работу функционала. Как костыль, короче;
- непонятная конвенция. В Руби понятная конвенция написания кода. Она описана в rubocop. У Рельс есть доктрина (настолько серьёзно всё). Здесь пока непонятно. Все делают, как угодно. Сегодня мы работаем только со ссыками в аргументах, завтра возвращаем результат из функции, как будто в объектно-ориентированном языке. Есть типа golint, но я не почувствовал от него поддержки;
- как нет нормального отладчика?! Мне известны все сложности с отладчиками в Go, но мне-то что делать? Мне фичи пилить нужно. А ваш delve меня совершенно не устраивает. Когда нельзя настроить отладчик под свои привычки, это очень грустно? Это… Страдания/
Выглядит так, как будто нет ничего положительного. Есть конечно:
- компилятор. Признаюсь отвык, что тебе спасают задницу и в этом месте тоже
- в языке отлично реализован принцип “явное лучше неявного”. Как правило, то, что ты видишь в коде, то и будет исполняться. Окружение очень редко влияет на результаты действий (если конечно всё не пронизано глобальным переменными)
- приятно и удобно писать чистые функции
Вам может показаться, что хорошего мало? Так отрицательные эмоции — были именно эмоциями, да и то, те, которые сопровождали только в начале. Некоторые из них пофиксились, некоторые придумал, как закрыть. А положительные аспекты со временем не пропадут — это качество самого языка, а не окружения.
Вывод
Go — хороший язык программирования, если он используется в тех местах, где действительно востребован и незаменим.
Вроде очевидная мысль, но вот только не все её понимают, к сожалению.
Ранее статья была опубликована тут.