golang

Переход на Go глазами PHP-разработчика: 5 подводных камней

  • среда, 16 октября 2024 г. в 00:00:12
https://habr.com/ru/companies/lamoda/articles/850456/

Хабр, привет! Меня зовут Костя Козин, я старший PHP-разработчик Lamoda Tech. За 17 лет в коммерческой разработке я писал на JS, PHP, и теперь на Golang. Сегодня в Lamoda Tech мы учим PHP-разработчиков писать на Go, и под это создали целый онбординг. Довольно часто в локальных обсуждениях я слышал, как тяжело дается переход с PHP на Go, а у некоторых первые месяцы работы с Go вовсе отбивают желание работать с языком. Поэтому я поделюсь подводными камнями, которые ожидают вас при переходе с одного языка на другой, и с которыми сталкивался я сам и мои коллеги. Если знать о них заранее, то смена стека может пройти не так болезненно, а знакомство с Golang станет более предсказуемым.

Подводный камень №1. «В Golang так принято»

При изучении Golang вы довольно часто будете сталкиваться с этим аргументом. Действительно, в языке много идиоматики и общепринятых правил, но практически всегда есть дополнительный контекст и исключения. Даже в ядре существуют отдельные места, которые написаны не так, как рекомендуется писать на Golang. Но чаще всего этому есть объяснение, которое можно нагуглить. Проверяйте аргументы «так принято» и «это есть в ядре» — они могут означать лишь рекомендации в определенных случаях. 

Пример. Вы не раз услышите, что в Golang переменным дают очень короткие имена. Гоферы приводят довод о том, что «так принято», но у этого правила есть абсолютно разумное объяснение, которое можно найти, например, в Effective Go. В Golang существуют дополнительные ограничения, задающие условия — когда, как и насколько сокращать. Главный смысл в том, чтобы сокращения были понятны. Как только появляются вопросы, нужно остановиться. 

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

1. В первой части кода функция square, которая принимает w, h, возвращает s. Все очевидно, вопросов не возникает.

2. Другой пример. У нас есть функция сохранения, в которой мы выполняем sql-запрос и обрабатываем возможную ошибку. В условии мы вызываем некую функцию toUniqueViolationError, которая возвращает некую C.

Что такое C? Неизвестно. Более того, ниже мы берем F, присваиваем нечто из M по ключу C. Как это понять? Никак. Очевидно, что M — это какая-то мапа, а вот насчет остального остается только гадать или искать по другому коду.

Для тех, кому интересно разобраться с этим примером: C — это column, колонка, в которой произошла ошибка, а F — это field, поле для этой колонки в dto уровня домена.

Вывод: нужно помнить, что подходы, принятые в Golang, чаще всего зависят от контекста. И когда вы слышите, что «тут так принято», лучше не верить на слово, а загуглить и разобраться в вопросе. Это даст вам дополнительный контекст и понимание, почему принято именно так, а не иначе, и какую проблему таким подходом можно решить.

Подводный камень №2. Специфичность языка и маркетинг

У Golang очень активный маркетинг. Один из тезисов, который используется в продвижении, звучит так: этот язык очень простой. Но его часто понимают неправильно, из-за чего у новичков бывает сильное разочарование на практике. Поэтому подчеркну: простой синтаксис не означает, что язык прост в использовании. Он гораздо более специфичен, чем это кажется на первый взгляд. 

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

  • Один тип цикла вместо четырех не упрощает логику, зато теряется очевидная семантика, которая есть у разных типов циклов.

  • Простое распараллеливание не решает соответствующие проблемы распределенных систем вроде тех же race condition, с ними нужно работать отдельно. 

  • При простом синтаксисе требуется выстраивание системы классификации и обработки ошибок, и это отдельный квест.

Еще одно утверждение гоферов: Golang выразительный. Само понятие выразительности кода дискуссионное, и каждый под этим подразумевает что-то свое. Чтобы не разочаровываться, стоит понимать — конкретно в Golang выразительность означает наглядность и отсутствие «магии».

Пример №1. В PHP это был бы цикл while, в Golang это только for. 

Пример №2. Представим, что в PHP задана строка в условии. Чтобы узнать, как это условие сработает, нужно понимать, как именно PHP будет конвертировать строку в boolean-значение. В Golang такое не пройдет: в if нужно передавать строго boolean-значение.

Следующий момент: в Golang, в отличие от PHP, автоматизация и удобство не в моде, многое принято делать руками. К этому нужно быть готовым, особенно если вы раньше писали на PHP или Java. Например:

  • DI-контейнеры с автосвязыванием (autowiring) существуют, но их практически не используют.

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

  • Из этого следует, что придется писать много «велосипедов», по крайней мере, они будут казаться таковыми первое время.

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

Подводный камень №3. Golang не снизит количество багов

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

Поэтому нужно понимать, что если вы ожидаете от перехода на Go повышение безопасности, то можете быть разочарованы. Максимум, что вы заметите — строгую типизацию в Go, если писали на PHP без нее, а также наличие детектора race condition. Баги уйдут исключительно из-за нестрогого сравнения типов в PHP, а детектор race condition помогает далеко не во всех случаях.

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

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

Вывод: к безопасности Gо нет претензий, но в сравнении с PHP он не многим лучше. Количество багов может даже увеличиться, но это пройдет с опытом. А чтобы процесс погружения прошел легче, после базового освоения советую почитать любую книгу о подводных камнях в Golang. Например, «100 ошибок Go и как их избежать» Тейвы Харшани. На нее вам потребуется пара месяцев точно.

Подводный камень №4. На старте вас может тошнить от собственного кода, и это нормально

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

Самая логичная причина — новый синтаксис во многом непривычный. И по сравнению с PHP это низкоуровневый язык, к чему нужно быть морально готовым.

Еще один важный нюанс. Вы можете испытывать чувство, что с вами что-то не так, что Go не ваш язык, пока все вокруг будут восторженно говорить о нем. Причина в том, что сообщество гоферов крайне лояльное. Если задать вопрос о какой-либо проблеме в Go, 9 разработчиков из 10 скажут: «А мне нравится». Это непривычно для PHP- или Java-разработчиков, которые привыкли достаточно критично относиться к своему языку. Поэтому не калибруйте свои ощущения только по восторженным откликам сообщества.

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

Подводный камень №5. Низкое качество кода сразу после перехода

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

Вывод: Ваш прошлый опыт и профессиональная интуиция будут подсказывать, что качество кода просело, но это временно. Чтобы решить эту проблему, переключитесь в «режим джуна». Дайте себе такую установку: у вас нет наработанного опыта, и вы с большим трудом вспоминаете то, что давным-давно читали насчет хорошего кода. Сейчас будет проще начинать с нуля. Со временем качество кода выправится.

Выводы

  1. Не верьте сразу на слово аргументу «так принято», старайтесь проверять и перепроверять информацию. Стремитесь на уровне концепта понять, почему некоторые вещи делаются так, а не иначе.

  2. Язык гораздо более специфичен, чем кажется на первый взгляд. Дайте себе время на адаптацию, минимум полгода. 

  3. Особого роста безопасности по сравнению с PHP вы не увидите, а иногда будете попадать в неочевидные ловушки, специфичные для Go.

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

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

Какие подводные камни вы прочувствовали на себе? Поделитесь своей болью в комментариях.