Обновить

Комментарии 104

Я писал на многих языках за свою карьеру. В частности когда-то давно на C, Asm, PHP, Perl. Сейчас пишу на C#, Python, JavaScript. Пытался несколько раз изучить Golang: ставил компилятор, открывал таториал, cмотрел на код... и в ужасе закрывал таториал до следующей попытки. Кровь из глаз и всё такое. Впрочем, я и Java не смог полюбить, хотя казалось бы она похожа на C#. Но Golang - это нечто, конечно. Буду ещё пытаться.

Я на Го писал лет 7, сейчас ушёл с него. Сложно понять, что же может там вызывать кровь из глаз - он же простой как пятка. Эдакий Си с прибамбасами.

Простой, но синтаксис какой-то не человеческий. Питон вот мне сразу зашёл, даже несмотря на списковые сокращения и прочее такое. В основном там всё же синтаксис понятный. А в Go как-то не интуитивно код выглядит.

А есть конкретные примеры?

Ну вот нечеловеческий, как по мне, это какой-нибудь Erlang. Раст местами тоже.

А в Го, вроде бы, всё довольно стандартно, если не считать синтаксис работы с каналами.

Да обычная смесь Си и Паскаля. Вот Раст с лайфтаймами и let mut выглядят порой как письмена древних.

Вот именно 'Си с прибамбасами'. Какую ценность он приносит совершенно непонятно, а раз непонятно не вижу причин использовать го вместе джавы например

Ну, если вы не разобрались в особенностях языка, то это не значит что в нём нет смысла.

Мы тут про синтаксис говорим, а не про язык в целом.

Ну, например, он компилируется напрямую в бинарник, что даёт лучшую производительность, чем джава и при этом он более высокоуровневый, чем Си, что облегчает написание программ. А также имеет легковесные горутины, которые потребляют намного меньше ресурсов, чем использование потоков напрямую в джаве, что позволяет хорошо масштабироваться. Вот вам как минимум 2 причины, когда его можно выбрать вместо джавы.

Юзкейс самый что ни на есть очевидный: Тебе нужно куча производительности и малое потребление памяти, но ты не хочешь управлять памятью вручную/писать Rust. Если тебе нужен высокопроизводительный бэкенд, Го - это лучший вариант, но если ты можешь тратить часы работы серверов только на запуск рантайма - флаг тебе в руки.

Так вы таториал открывали, а надо было tutorial - и глаза остались бы целы :)

ну если изучить историю почему его сделали таким и для каких задач,то я думаю вопросы отпадут

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

Принято что именно? Короткие имена переменных? Если человек придумал абсолютно тупейшее название toUniqueViolationError, тут как переменные не назови, лучше уже не станет. Ну а переменной m вообще нет нигде, я не знаю, что именно вы хотели этим примером показать.

p.s. почему код в картинках то?

почему код в картинках то?

"Продолжайте делать что делаете читать код с картинок, и у вас будут все шансы со временем полюбить Go так же сильно, как остальные." :)

Нет фреймворков, но есть огромная куча библиотек как std, так и сообщества. Писать велосипеды не надо.

Ну тут же смотря с какой стороны смотреть. Статья (как и изначальный доклад) больше про то, какой боли ожидать при переходе именно php-шникам. А по отзывам, для многих php-шников, которые привыкли к огромным фреймворкам и всяким доктринам, половина кода go-шных сервисов выглядит как велосипеды.

Попроси человека, который десять лет пишет на пхп с использованием Symfony, написать небольшое приложение-API на го хотя бы с использованием Gin, и можно запасаться попкорном. Symfony - комбайн, в то время как Gin - просто серп, позволяющий не рвать зерно руками.

Да в целом ничего сложного, как раз мой случай )) если конечно человек прям "Симфонист", на "голом" PHP почти не писал и т.д., тогда да, тогда возможно он долго будет недоумевать, почему всякий миддлвейр надо самому тащить. Хотя приходилось и объяснять людям, почему приложению на Go не нужен апач и "где у него интерпретатор" ))

Из самого необычного я бы выделил 2 пункта, к которым так и не смог привыкнуть до конца:

1. Имя пакета - часть имени сущности. И если в пакете auth надо создать какой-то сервис аутентификации, то надо назвать его просто Service, а не AuthService. Из-за этого местами непривычно читать код, так как часть имени любой сущности написана в самом верху кода (пруф)
2. В именах пакетов не должно быть подчёркиваний, тире и пр. Только одно слово (пруф)

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

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

Ну и местами смущает работа с ошибками. Например, функция http.ListenAndServe всегда возвращает ошибку, что вроде как укладывается в концепцию go, но лично меня интуитивно такое отталкивает. И простого if err != nil иногда не хватает (см. rows.Err() в либах для работы с БД).

А вообще обидно, что аналогов у языка нет. Если ты хочешь язык общего назначения со статической типизацией без современного ООП (как в Java, C#, C++), то выбора особо и нет. Kotlin больше под мобилки заточен, Swift явно создавался для экосистемы Apple. Так что популярность go вполне себе логична

Блин, зачем я стал читать это

Nullable columns are annoying and lead to a lot of ugly code. If you can, avoid them. I

Очередное "мы в это не можем и поэтому объявим плохим".

Ну, конечно, avoid, но много типов уже есть Nullable.

Раст - вполне неплохая замена без лишних нагромождений ООП.

"Swift явно создавался для экосистемы Apple." — да, но сейчас он работает под Линукс, есть несколько вебфреймворков и на нем пишут веб сервисы. Вообще Swift самый красивый и логичный язык, который я когда либо видел.

А вообще обидно, что аналогов у языка нет.

Есть KPHP - статическая типизация с "авто" выводом типов, и сборкой в нативный бинарник. (под капотом C++)
Совместимость с PHP обеспечивает быстрые проверки, а после сборки - быстрое исполнение.

kphp - это довольно специфичное решение, которое за пределами ВК не существует

По ссылке https://habr.com/ru/articles/686496/ про "не существует".
То, что у обычных PHP разработчиков нет проблемы скорости и защиты - это не проблема самого решения.


В любом случае это не PHP, а лишь подобие с похожим синтаксисом.

Почему "подобие"? У нас приложение одинаково хорошо работает на PHP и KPHP. KPHP относится к PHP также, как Mono к .NET. Просто другой рантайм для такого же кода.
Каких-то фич может и нет (рефлексия и что с ней связано), но это вопрос уровня поддержки рантаймом.

Если занять позицию "аналогов нет, и для быстрых сервисов давай менять язык", то конечно ничего не подойдёт. Нужна производительность но не хочется менять язык, то KPHP очень даже.
К тому же разводить зоопарк языков на проекте так себе идея.

А у вас приложение на Symfony, Laravel, Laminas или может быть Slim с Doctrine? Или всё же "просто другой рантайм" оказался не таким уж и "простым" и всё пришлось написать с нуля, т.к. язык всё же другой с похожим синтаксисом, верно?

P.S. У меня позиция, что для быстрых приложений достаточно воткнуть Swoole/RoadRunner/etc, а менять его на какой-нибудь Rust/C/Go уже только в случае критически важных секций, коих на практике оказывается обычно ровно 0.

У нас исторически свой ORM и свой роутер запросов.
KPHP - Это просто другой рантайм. Если код написан без магии на рефлексии и с нормальной типизацией (как последние версии рекомендуют), то все собирается просто. Поэтому ничего не пришлось писать с нуля для миграции кроме обеспечения рефлексии (нужна для ORM). Для которых библиотек пришлось найти реализации на чистом PHP или подключить FFI.


Рантайм (как реализация исполнения языка и всех основных функций) не обязан обеспечивать поддержку монструозных платформ которые используют "магию".
А PHP модули - у каждого рантайма свои. Я же не буду говорить "Ой, Mono не поддерживает WPF, это не правильная реализация, их язык только похож". Просто в реализации Mono нет этого модуля. Но с точки зрения реализации исполнения языка - всё хорошо.

KPHP вполне собирает код на PHP 7.4.
И хотя есть свои дополнения, но они не мешают исполнению в PHP режиме.

Ну т.е. у вас всё своё, нет ни единой библиотеки на PHP из композера, т.к. сам композер не работает, но при этом "это чуть-чуть другой рантайм", я правильно понял?)))

P.S. И с каких пор конструкции, полностью поддерживающиеся IDE, с работой автокомплита, с покрытием стат.анализатором, без каких либо инструментов метапрограммирования (get/set/call) и прочим называется "магией"?

KPHP вполне собирает код на PHP 7.4.
И хотя есть свои дополнения, но они не мешают исполнению в PHP режиме.

А теперь, финт ушами. Языком PHP может называться язык, соответствующий спецификации PHP (1) https://phplang.org/ и (2) https://github.com/php/php-langspec

Откройте, например, часть про выражения: https://github.com/php/php-langspec/blob/master/spec/10-expressions.md и скажите, KPHP всё поддерживает? Даже eval? Если нет, то о чём речь? Это не PHP и не является им. Это не "другой рантайм". Это лишь диалект/подмножество.

А другой рантайм - это вот: https://github.com/ircmaxell/php-llvm легковесный бекенд поверх llvm.

У нас есть что-то из композера. И композер работает. и KPHP даже работает с PSR структурой файлов.

Про выражения - не понял вопроса. У нас не возникло никаких проблем с ними, и с лямбдами тоже, если Вы про них.

А вот eval() не положен по безопасности. Такое возможно только в интерпретаторах.

P.S. И с каких пор конструкции, полностью поддерживающиеся IDE, с работой автокомплита, с покрытием стат.анализатором, без каких либо инструментов метапрограммирования (get/set/call) и прочим называется "магией"?

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

Если Вам это не надо, нет проблем. Ниже Вы указали "Хочу узнать о переезде", я дал ссылку на статью про переезд без переезда.

А какую метрику увеличили перейдя с PHP на Go?

Команду разработки и зарплаты :)

Не отвечу за Lamoda, но в проектах где мне довелось участвовать в миграциях с PHP основным мотивом было снижение ресурсов по памяти и CPU. И это удавалось сделать, хотя процесс перевода не был быстр и сам требовал много ресурсов на разработку. Например, из личного опыта, Lazada как пример большого проекта практически съехавшего с PHP, переезд занял несколько лет. Сейчас работаю в компании где монолит на PHP тоже имеет место и бизнес не готов его убрать совсем и вижу в сравнении, что на Go-сервисах в той же инфраструктуре потребление ресурсов ниже. Но вложение в переезд может обойтись еще дороже, чем поддержка того что есть.

В подавляющем большинстве случаев, снижение потребления ресурсов и тем более CPU обуславливается обычным рефакторингом. Причём как показывает та же практика - PHP на порядки эффективнее в утилизации памяти, нежели Go из-за специфики своей работы (что взял, то моментально отдал).

Учитывая это, образно, тачка с 500 метрами может держать хоть 1000 сервисов на PHP с пиковым потреблением в эти самые 500 метров, а в случае Go это крайне проблематично, если не невозможно.

Ну чтобы не быть голословным: Обычный рефакторинг кода на PHP, который ранее отвечал за ~0.300с сейчас у меня отвечает за 0.004с - 0.007с. Тупо рефакторинг куска бизнес-логики с выносом в отдельный сервис без смены стека.

Hidden text

Так что лично я крайне скептически отношусь к таким аргументам, т.к. в таких случаях никогда не приводятся сравнения БЕЗ рефакторинга кода. И никогда не сравнивается результат в целом: Был стек из 10 железок в кластере -> стал стек из 1000 железок или наоборот, 1 железка.

Более того, практика того же Avito, что переезд с PHP на Go с параллельным нарезанием на микросервисы всего и вся, показывает, что потребление всех ресурсов (включая человеческие) и стоимость поддержки в таком варианте возрастает кратно (пруф: https://www.youtube.com/watch?v=yLrSp174yc0).

Короче, нужно смотреть из ситуации. Не говорю что Go не несёт никаких профитов, однако, имхо, эти "профиты" зачастую или переоценены, или наоборот оцениваются некорректно и в результате плюсы только с точки зрения поддержки отрефакторенного (sic!) кода.

Как я понял, они там распределённые монолит сделали. Так что пример не самый показательный

Увы, я других примеров не знаю, где бы реально оценивалась стоимость поддержки 1 монолита на PHP до и 1000 микросервисов на Go после (железо + человеческие ресурсы). И желательно без переписывания всего кода, а копирование предметной области 1 в 1.

Так что я могу ориентироваться лишь по косвенным докладам подобным и собственным опытом.

P.S. Было бы неплохо услышать доклад/статью про "мы переехали с Go на PHP и вот что получилось". Вангую, там бы тоже получили ускорение и удешевление.

P.S. Было бы неплохо услышать доклад/статью про "мы переехали с Go на PHP и вот что получилось". Вангую, там бы тоже получили ускорение и удешевление.


Есть "Мы переехали с PHP на KPHP",
https://habr.com/ru/articles/686496/
ускорение точно есть и по опыту нагрузочных тестов - удешевление инфраструктуры.
Мы когда из интеграционных тестов небольшие скрипты через PHP-FPM дергали, то память расходовалась сильно. Добавили эти части в состав основного KPHP-сервера приложения - стало все идеально.

PHP на порядки эффективнее в утилизации памяти, нежели Go из-за специфики своей работы (что взял, то моментально отдал)

Но есть нюанс. В Go, в отличие от Java и C#, не происходит выделения всего в куче.

Компилятор может сгенерировать код так, что "взял-отдал" будет происходить на стеке и тогда GC вообще не будет принимать участие в этом движе.

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

Поэтому в целом Go не то что бы плох в плане менеджмента памяти.

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

Но код на Go в основном пишется не в функциональном стиле, а наличие структур уже говорит о каком-то стейте. А стейт придётся и так и так хранить где-то, в отличие от PHP, у которого в большинстве случаев стейта нет, а всё что он может хранить - это байткод в mmap/sysv.

P.S. Под эффективностью менеджмента я имел ввиду утилизацию в ноль, т.к. в GC у пыха вообще дефрагментации нет, например, о какой эффективности (кроме скорости работы) можно говорить.

в отличие от ... C#, не происходит выделения всего в куче.

Ну не прям все. В C# есть значимые типы, которые выделяются на стеке. И дженерики умеют в мономорфизацию.

Но есть нюанс

На Go программист не управляет размещением объектов в памяти. Доктор Компилятор сказал в хип, значит в хип.

В C# есть значимые типы, которые выделяются на стеке.

Чтобы использовать их преимущества, точно так же надо проектировать программу с учётом особенностей этих типов и компромиссов, которые придется принять.

Как минимум стек в C# (был?) не резиновый, в отличие от го.

На Go программист не управляет размещением объектов в памяти.

Плохо разве? Хорошо, меньше выбора - проще код писать.

Явно конечно не управляет, но неявно - вполне можно, хоть и сложно.

...точно так же надо проектировать программу с учётом ...

Точно так же как где?

Плохо разве?
неявно - вполне можно, хоть и сложно.

Неявность - это плохо, да.

Компилятор сказал в хип, значит в хип.

Ну что ж вы компилятор выставляете тираном :) Как минимум есть правила escape analysis, можно влиять на это.

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

А кто не использует-то?

Как выглядел рефакторинг ? Переход на Swoole, отказ от больших фреймворков, грузящихся на каждый запрос?

Ну просто взялся классический монолит и от него запилился сервис с отдельной бизнес-логикой на PHP 8.3 + Symfony 7.1 (изначально 6.4) с Доктриной, JMS, DDD, гекасгоналкой и прочим. Ну т.е. дефолтный стек вообще весь. В качестве аналогии по коду/архитектуре могу привести в пример вот эту репку с наброском сервиса https://github.com/SerafimArts/packagist.app/tree/master/app

Единственный "тюнинг" - это просто вместо FPM установлен RR (благо в симфе любой сервер 1 кнопкой меняется), да и то не для скорости, а просто чтобы весь сервис в один контейнер можно было собрать (ради удобства деплоя), вместо двух nginx+fpm.

Т.е. рефакторинг выглядел как рефакторинг, а скорость - просто сайд-эффект. Случайно получилось.

RR это RoadRunner ? Так и есть, это полноценный живущий cgi как Swoole, без постоянной инициализации на каждый запрос, а не умирающий после каждого запроса FPM.

RR и Swoole принципиально разные инструменты для совершенно разных задач. Одно тупо альтернатива FPM почти 1 в 1 с такой же однопоточной и блокирующей работой, а другое набор инструментов для написания асинхронных и многопоточных приложений, где просто есть в наличии API для работы с HTTP. Но не будем об этом...

Да, RR -- RoadRunner, просто полноценно живущий CGI, причём не самый быстрый, прошу заметить. Его преимущество только в том, что можно взять FPM и заменить на RR без каких-либо доработок и наоборот.

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

Учитывая это, образно, тачка с 500 метрами может держать хоть 1000 сервисов на PHP с пиковым потреблением в эти самые 500 метров, а в случае Go это крайне проблематично, если не невозможно.

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

P.s. могу даже помочь с написанием гошных сервисов

Можно и на С++ настолько плохо написать, что будут жраться ресурсы как не в себя. В 2004 году я переписывал счётчик HotLog (если кто-то помнит такой), Была производительность 100 хитов/секунду, стало 5000 хитов в секунду. Причина: применялась "копирка" c Perl с коллекциями (хеши). После рефакоринга на правильные типы данные и правильные коллекции (rbtree) скорость заметно выросла и количество необходимых серверов уменьшилось.

Учитывая это, образно, тачка с 500 метрами может держать хоть 1000 сервисов на PHP с пиковым потреблением в эти самые 500 метров, а в случае Go это крайне проблематично, если не невозможно.

Отвечу за Ламоду

В первую очередь нас заботила ТТМ. Мы довольно большие и у нас много сервисов, и средняя скорость разработки в старых PHP монолитах заметно меньше, чем в новых перенесенных на Go. Тут конечно не только стек решает, но и сам рефакторинг. Очень позитивно сказывается на онбординге новичков, тут тоже помогает микросервисная архитектура, а Go для этого и создан. По техническим метрикам разница значительная в некоторых параметрах десятки раз. Память Go из коробки расходует скромнее и стабильнее) Еще одна не маловажная метрика это счастье разработчиков. И 90% перешедших безусловно не хотят возвращаться. И при прочих "равных" тут явный перевес)

"Подводные камни" в высшей степени странные. ИМХО чистый субъективизм.

Я немного знаю PHP, но основные языки для меня - C/C++, поэтому появление Go и возможность использовать его в вебе вместо PHP/Python для меня был как глоток свежего воздуха.

Имена переменных можно делать любой длины, как и во всех языках. Главное чтобы было понятно.

То что в Go не принято использовать все эти ваши фреймворки - это же прекрасно! Язык программирования (любой, не только Go) по опеделению проще и надежнее, чем фреймворк. Проще в изучении, проще в использовании, содержит на порядки меньше ошибок (вообще ошибки в компиляторах это суперэкзотика). И то что называется "написание велосипедов" на самом деле лично я воспринимаю как просто обычное классическое программирование. А вот продирание сквозь дебри фреймворков в попытке сделать что-то чуть нестандартное воспринимается лично мной не иначе как танцы с бубном (но это конечно тоже субъективная оценка).

А вот важнейшее на мой возгял преимущество Go перед PHP/Python - это даже не статическая типизация (хотя она тоже очень важна), а то что в языке нормально, ЯВНО объявляются переменные. Т.е. переменная явно объявляется один раз (оператором var или :=), а все остальные упоминания имени - это ее использование. В случае опечатки в имени не возникнет новая переменная, а будет ошибка компиляции.

Конечно субъективизм, никто и не спорит. Это топ жалоб именно php-шников, тут вся статья рождена из доклада на внутреннее php-комьюнити на тему "какой боли ждать и к чему вам готовиться морально".
Безусловно, у тех, кто переходит из C, ощущения будут совсем другие.

явная декларация не гарантирует ничего

func main() {
	a := 1
	func() {
		// ошибочка вышла - опечатались := вместо =
		a := 2
		doSmth(a)
	}()
	if a == 2 {
		println("ok")
	} else {
		println("obosrams")
	}
}

что выведет эта програмка на "безопасном" го?

вопрос решается сторонними тулзами (линтерами), которые на php/python есть

а для го есть?

да, пример с затенением тут так и напрашивается
но линтеры есть и даже ide такое подсвечивают

Есть.
И такое у меня IDE выделяет подсветкой.

go vet ткнёт носом в строку с затенением.

Ещё в го нормальная система сборки и крайне лёгкий деплой.

камон, у го даже нет разделяемых библиотек

т.е. вы обречены на каждый чих компилять, компилять и компилять

и вот это уже реальная проблема, в отличие от шелухи описанной в статье

Как по мне это плюс)

Учит понимать что делает программа и не смотреть логи на каждый чих)

Что конкретно компилять? На какой каждый чих? То, что Го собирает статические бинарники по дефолту, как по мне, просто отлично. Деплоить проще, зависимостей нет.

Ну а если нужно, то через CGO можно .so подключить

Если надо с разделяемыми библиотеками, то можно и так. Если есть нужда использовать модель плагинов - есть поддержка https://pkg.go.dev/plugin. Команда go build -buildmode=plugin myplug.go. Думаю это используют, но мне проекты такие не попадались. Компиляция достаточно быстрая. Деплоить 1 бинарь удобно, чем тянуть 100500 зависимостей.

Проблема с переменной в пхп надуманная. Так сделать, конечно, можно и язык это позволит. Но косячить можно вообще на всем, были бы способности. Если мы говорим о коммерческом коде, то любое пыховское приложение на этапе сборки прогоняется через статический анализатор после чего запускаются юнит и e2e тесты. На десятке проектов за последние надцать лет я не видел ни одной подобной проблемы. За тот же период времени количество 500х, которые попадались в проде могу по пальцам одной руки пересчитать. Тут не совсем в языке дело.

Я вообще PHP-шник, но начал писать приложение на Python для обработки большого количества событий, получаемых из сети по WebSocket.

Я упёрся в проблему, когда даже асинхронные подходы и даже с параллельными выполнениями в разных процессорах не давали необходимую скорость.

Я попробовал в этот момент GoLang, и он оказался очень быстрым. Мне понравилась его философия, и могу сказать, что в своей нише это очень классный язык.

Все, что касается i/o задач он очень хорош. Но вот работа с мютексами немного нервы потрепала.

После php это вообще другой мир. Но я бы не стал переносить на него все. Только там где логика не очень сложная, и нужна скорость

Ну так Golang я так понимаю прямо заточен под многопоточность, быстрые сервисы и всё вот это вот. А Python изначально скриптовый язык, и то, что теперь это универсальный комбайн, на котором хочешь в дата сайенс играйся, хочешь сервисы пиши, хочешь GUI изображай, не делает его лучше приспособленным для каких-то таких вещей, где важна каждая миллисекунда. Я бы высоконагруженные сервисы на Python писать не стал, хотя и люблю его в целом. Каждому языку своё предназначение.

Но вот работа с мютексами немного нервы потрепала.

Инкапсулируйте код.

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

И что, этот код прошёл бы ревью, типа нормально так? 🤦‍♂️
И что, этот код прошёл бы ревью, типа нормально так? 🤦‍♂️

Чтобы узнать, как это условие сработает, нужно понимать, как именно PHP будет конвертировать строку в boolean-значение

Вот как раз если знать, то такого в жизни не напишешь. Например, если прилетит "0", то код под if не выполнится. И вообще это поведение может меняться от версии к версии.

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

всегда удивляло как люди умудряются большие проекты тянуть на языках вроде PHP или Питона

Да нормально. У меня у самого немаленький проект на РНР - хорошо за миллион строк кода. И начинался когда там ещё никакой типизации, кроме динамической, и в мыслях не было. Это скорее вопрос культуры кодинга, внутренних стандартов. Если так писать, то в крупном проекте действительно упаришься баги ловить.

На культуре, к сожалению, можно выехать только в маленькой команде как мне кажется.

А в остальном остаётся надеяться на тесты и IDE, которых часто бывает недостаточно.

По крайней мере по моему опыту разработки на Питоне часто вылезали какие-то ошибки которые кроме как в рантайме (или тестах) не поймаешь, IDE и прочие анализаторы их не видят.

Со статической типизацией же всё просто: накосячил - не собралось. А в каком-нибудь Расте не собралось и ещё по куче более сложных причин)

...прочие анализаторы их не видят.

Со статической типизацией же всё просто: накосячил - не собралось.

Так статические анализаторы полностью заменяют/реализуют это поведение, т.к. и реализуют компилятор по факту. Тот же вывод типов, то же построение CFG, всякие анализы DCE и проч. Лично я не могу представить, где бы наличие строгой типизации в языке решило бы проблему, которую не решают статанализаторы. Скорее наоборот, т.к. в PHP нет ни алгебраических типов (пользовательских имею ввиду), ни зависимых, ни шейпов, ни каких-либо более узких скаляров (class-string, non-empty-string, int<0, 2>, etc), ни чего-то ещё. Плюс taint-анализ...

А пример можно привести косяков статанализа? Потому что что-то не могу такого представить.

А IDE... Ну IDE (если мы говорим про PHPStorm) довольно примитивный анализ реализует. Да и в CI не воткнуть её в отличие от PHPStan/Psalm.

А пример можно привести косяков статанализа? Потому что что-то не могу такого представить.

Анализатор показывает ошибку там, где её нет, и приходиться переписывать код под анализатор. У меня было такое с Resharper'ом.

Ну IDE (если мы говорим про PHPStorm) довольно примитивный анализ реализует. Да и в CI не воткнуть её в отличие от PHPStan/Psalm.

Это взаимодополняющие инструменты, оба должны использоваться. Код, не прошедший статику, должно быть невозможно вмержить в рабочую ветку.

На культуре, к сожалению, можно выехать только в маленькой команде как мне кажется.

Маленькая – это сколько? У меня 25 человек только непосредственно на разработке – справляемся. В конторах FAANG класса опыта нет, но думаю, там процессы контроля кода ещё жёстче прописаны. А если программист знает, что за такой код можно получить по башке, то и писать будет аккуратнее.

Ну это плохой код. Обычно, разработчики миддл+ и выше так не пишут, как минимум потому что статический анализатор такое не пропустит.

такой код порицается сообществом, заворачивается на ревью, а автора очень ласково просят так больше никогда не делать.

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

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

РНР в последнее время сильно усовершенствовался, особенно начиная с 8.х. Если сейчас начинать на нём новый проект, так совсем хорошо. Ещё бы дженерики нативные завезли, вообще отлично бы стало. Правда, это если и случится, то нескоро. Но как ни крути - сейчас подавляющее большинство проектов лютое легаси, куда новые фичи лезут с трудом. Но такой код, как в примере автора, писать всё равно не нужно 🙂 Да и сравнивать с Го, по-моему, тоже - это два разных инструмента для разных задач.

Большие проекты люди такими условиями как на скриншоте не пишут. Понимают что может и приведёт к ошибкам.

Ну а ноги растут из самого C. Типизация в C++ более строгая, чем в C, но именно на последнем написаны Python, PHP и много ещё чего.

Само собой, на скриншоте просто крайний случай. Но в динамической типизации полно других более тонких мест где можно накосячить.

А насчёт строгой типизации - не очень мне понятно как язык, на котором написан интерпретатор, влияет на типизацию того языка, который интерпретируется.

Следуя вашему примеру - С++ был изначально написан на С. Ну и С является подмножеством С++, так что я не сказал бы что в общем смысле С++ более строгий.

Это не гипотезы или предположения.

1 пример, про void*
#include <stdio.h>

int main() {
    int a = 10;
    void* p = &a;
    double* d = p;
    printf("%f\n", *d);
    return 0;
}

C допускает неявное преобразование void* в любой другой тип указателя. Программа скомпилируется.

C++ требует использовать явное приведение. Программа не скомпилируется.

2 пример, про const
#include <stdio.h>

void modify(const int* ptr) {
    int* modifiable = (int*)ptr;
    *modifiable = 42;
}

int main() {
    const int x = 10;
    modify(&x);
    printf("%d\n", x);
    return 0;
}

Результат будет разным: в С будет 42, а в C++ 10.

3 пример, про void
#include <stdio.h>

void func() {
    printf("Hello\n");
}

int main() {
    func(42);
    return 0;
}

В C скомпилируется, т.к. передать. А в C++ нет.

В C функция, объявленная как void func(), означает, что она принимает произвольное количество аргументов.

C++ строго проверяет соответствие сигнатуры функции.

Вот несколько примеров. Так что я не согласен что C++ не более строгий.

Ну, "может" только в теории. Пока планов на изменение правил кастинга нет. А так - да, тяжелое наследие царского режима. Можно настроить статический анализатор, чтобы не пропускал.

Ну, "может" только в теории. Пока планов на изменение правил кастинга нет.

Вообще-то как раз их и меняли не так давно. И ещё какие-то похожие изменения были, сейчас не вспомню уже. Типа поведение empty() подкорректировали, или что-то подобное.

Я на go перешел с чистого C, переход очень плавный получился, мне просто завезли чего не хватало плюс немного чистой архетиктуры, я после на C стал писать в Го стиле

С тезисом, что поначалу собственный код на Го кажется уродливым убожеством, полностью соглашусь. Добавлю только, что спустя четыре года работы на языке полюбить его я смог, а вот писать на нём код, который мне нравится визуально, так и не сумел.

Я спустя 8 лет и полюбить не смог, скорее сила привычки.

Ага, понимаю, кодинг по расчёту :)

Ох тыж. Ору в голос! ) И ведь в этом есть смысл. Одна из проблем того же пыха - проекты, которые вместе с ним приезжают. Чаще всего это что-то максимально неинтересное или плохо написанное. И тут хочешь не хочешь, а задумаешься о смене языка, чтобы просто сменить проекты.

А мне нравится пхп. Я когда пишу на нём, представляю что он как этакий гопник с тупой мордой и замашками зэка, который вырос и наконец остепенился, устроился на работу и даже успешно торгует на бирже. Но замашки зэка никуда не делись.

Почему я убежал в Go из PHP так, что аж пятки сверкали:

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

  • Настоящая строгая типизация, а не эта поделка в PHP, которая позволяет нерадивым и ленивым на неё просто забить. По этой причине специфики в Go на порядки меньше, чем в динамических языках. Запомнить несколько особенностей мап, слайсов и интерфейсов не так сложно.

  • Дешёвая многозадачность. Любая функция может стать горутиной. Вы ничего не окрашиваете бестолковыми async. Все race conditions в начале тупо обмазываете мьютексами. Из-за относительно высокой производительности самого языка этого в 90% случаев достаточно. Если нет, то потом оптимизируете.

  • Не перегруженная система типов. Да, сначала может показаться, что этого недостаточно, но пока ребята на Typescript и Rust ублажают себя изысканными типами, способными решить задачу трёх тел, ребята на Go выпускают проект на рынок.

  • Утиная типизация плюс интерфейсы и новые дженерики позволяют сделать ваши слои проекта настолько независимыми, что даже умные книжки про чистый код обзавидуются.

  • DI - это хорошо. DI контейнер - это зло! Не ведитесь на эту лживую "простоту". Внедряйте зависимости вручную. Поверьте, километровую простыню ручного внедрения зависимостей дебажить легко, как дышать в сосновом лесу утром, а дебажить проблемы, возникшие из-за непонимания, как оно всё связано в проекте с контейнером - это ад.

  • Стандартная библиотека и инструменты из коробки выше всяческих похвал. В моих проектах число внешних зависимостей чаще всего не превышает количество пальцев на одной руке старого фрезеровщика)

  • И т.д. и т.п.

Согласен. По 6 пункту (DI) - еще применяется кодогенерация, благо не сложно это реализовать. Вот например небольшой пример https://habr.com/ru/companies/omprussia/articles/558690/

Выскажу личное мнение. Нормально все в нем после php, нет никаких болей кроме одной - if err != nil. Когда на 20 строк бизнесового кода пишется 10 проверок и код тонет в этом. В такие моменты с тоской вспоминается замечательный принцип "fail fast!", который в продуктовом коде просто бесценен.

Причем все аргументы и наезды на обычные exception, которые мне попадались на глаза в холиварах, базировались только на том, что если накосячить в куске кода, который ловит ошибки, будут проблемы. Да, это так, причем очень большие. Ну дак накосячить можно на чем угодно, были бы способности к этому. Можно и канал закрыть в куске кода, который из него читает. Дак и что, каналы из Go нужно убрать? А если допустить, что отлов ошибок реализован нормально?

Есть ощущение, что когда достали компилятор из Plan 9 и отряхнули с него пыль стало понятно, что языки за это время ушли вперед. Что во всех популярных языках катаются на тех же exception. Но воткнуть обработку исключений в этот компилятор не прокатит чисто технически. Как мне кажется это и есть причина, а не вот это вот все светлое и молодежное. Поэтому была придумана красивая легенда про ясность.

В остальном язык просто прет! Простой как табуретка синтаксис, свой планировщик, дешевые горутины и принцип с каналами вызывают восхищение.

if err != nil.

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

И хорошо что не приняли.

Говнище, это когда пишут:

if err != nil {
  return err
}

А надо:

if err != nil {
  return fmt.Errorf("some do, some_var=%s: %w", someVar, err)
}

А лучше так:

if err != nil {
  return someError{err: err, v: someVar}
}

И тогда все будет норм.

Меняйте подход в голове. Почитайте статьи и книги про работу с ошибками в го.

Я писал на Go лет семь, так что примерно понимаю как там ошибки работают.

И вот эта череда if-ов выглядит ужасным boilerplate, по сравнению даже с Rust:

let request = Request::new().context("unable to create request")?;

let response = self
    .client
    .execute(request)
    .await
    .context("unable to execute HTTP request")?;

Я на PHP писал лет 15 и меня всё это время раздражало пхпэшное сообщество со своими "не изобретай велосипед".

Во первых если бы люди не изобретали, то мы так бы и жили в каменном веке.

А во вторых лучше написать небольшой велосипед созданный под конкретную задачу, чем ставить готовый бандл в котором 90% существующих умелок тебе не нужно, а 90% умелок которые нужны твоему бизнесу там нет. В итоге это всё надо как-то наследовать, расширять, магия магией погоняет, неповоротливо и нестабильно.

Сообщество в го говорит "лучше небольшой копипаст, чем небольшая зависимость". В го приходят не за удобным кодом, в котором должно быть всё предусмотрено наперёд, в го приходят за скоростью и возможностями. В го не боятся произносить вслух слово "рефакторинг", как например в php, если ты собрался рефакторить, а не наследовать, значит ты плохой архитектор.

А отказ от доктрины это отдельный кайф.

Когда ты сам управляешь своими запросами и не чешешь голову почему база не нагружена, а приложение уже еле дышит (потому что orm само по себе выжирает всё что можно).

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

Вот о таком сообществе я и говорю.

Написание идеального инструмента под задачу бизнеса назвали угаром по вилосипедостроению.

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

И наконец оправдали всё это ненужной универсальностью.

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

И, по моему скромному мнению, проблему объема кода вы сильно преувеличиваете, учитывая, что его не умещают в мизерную память МК и не отправляют по мобильной сети клиентское устройство.

Выглядит что код бы просто отрефакторили и все. Переписали бы на новом php, скажем 8.4, было бы и быстрее и дешевле, а возможно и приятнее, так как есть библиотеки для всего. Php проигравает в скорости, но в вэбе не так много задач на скорость. Их можно вынести в очереди и jobы. Единственно где php проигрывает это go рутины и паралельные вычисленя. Это есть но на значительно более низком уровне. Но это и не очень php нужно.

Php безусловно приятнее. Go с точки зрения архитектора кажется сильно кастрированным в сравнении с php. Тут соглашусь.

А что касается скоростей в вебе это неправда. Сейчас всё на вебе завязано, все сайты, все приложения, весь онлайн бэкэнд требует скорости. И в случае с php мы рано или поздно упираемся в производительность и закупку дополнительных серверов. Напомню, что я говорю не про сам php, а про идеологию сообщества - поставить друпал, наставить на него модулей, а потом как-то в хуках костылями допиливать проект под требования ТЗ.

Ну в вэбе остновная нагрузка ложится на базу, кэш, движек полнотекстного поиска. Логика где надо сделать миллион вычислений без образещения к внешним источникам - редкий сценарий. По крайней мере в моих проектах так. Хотя я видел тормозащие системы на PHP , например оч популярный коммерческий магаз Shopware.
касательно Drupal или Wordpress, там плагин кэша поставил, и все летает если простой вабсайт. Но вообще иметь опцию использовать готовое решение дорогого стоит, например тот же Magento, Opencart. С точки зрения намного дешевле запилить магаз на PHP опенсоурс чем писать там что то с нуля на GO и потом это суппортить.
На мой взгляд основная сила PHP не в языке, а софте который уже есть и работает. Хотя мне и ООП PHP ближе чем обрезок Go или Rust.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Информация

Сайт
tech.lamoda.ru
Дата регистрации
Дата основания
Численность
5 001–10 000 человек
Местоположение
Россия