Спасибо Брагилевскому за просвещение, оказывается, Brainfuck - не просто какой-то смешной эзотерический язык. Он основан на языке P′′, придуманном Corrado Böhm аж в 1964 году для описания машины Тьюринга. Т.е. это были вполне себе математические исследования.
P′′ - это первый язык без goto, для которого доказана Тьюринг-полнота. Можно сказать прародитель структурного программирования.
Брейнфак - по сути тот же P′′, почти один в один, только с операторами ввода вывода.
(P.S. В русской Википедии есть интерпретатор Брейнфака на перле. По-моему, по читабельности Перл не очень далеко ушел от брейнфака.)
P′′ - это первый язык без goto, для которого доказана Тьюринг-полнота. Можно сказать прародитель структурного программирования.
Брейнфак - по сути тот же P′′, почти один в один, только с операторами ввода вывода.
(P.S. В русской Википедии есть интерпретатор Брейнфака на перле. По-моему, по читабельности Перл не очень далеко ушел от брейнфака.)
#!/usr/bin/perl
open F, shift;
@code = grep {/[+-\.,\[\]><]/} split '', <F>;
for (my $_ = 0; $_ < @code; ++$_) {
++$cpu[$i] if $code[$_] eq '+';
--$cpu[$i] if $code[$_] eq '-';
--$i if $code[$_] eq '<';
++$i if $code[$_] eq '>';
print chr $cpu[$i] if $code[$_] eq '.';
$cpu[$i] = ord <STDIN> if $code[$_] eq ',';
if ($code[$_] eq '[') {
if (!$cpu[$i]) {
++$brc;
while ($brc) {
++$_;
++$brc if $code[$_] eq '[';
--$brc if $code[$_] eq ']';
}
} else {
next;
}
} elsif ($code[$_] eq ']') {
if (!$cpu[$i]) {
next;
} else {
++$brc if $code[$_] eq ']';
while ($brc) {
--$_;
--$brc if $code[$_] eq '[';
++$brc if $code[$_] eq ']';
}
--$_;
}
}
}
😁1👀1
Есть вещи, с которыми сложно смириться в языке Go.
Переходя на Go с другого языка, проходишь все стадии: отрицание, гнев, торг, депрессия, принятие. Ибо язык сильно отличается от классических Java, PHP, JS и их общепринятых стандартов написания кода. Паттерны-фигаттерны, которые вы учили, можно забыть.
Всё можно понять: это намеренно упрощенный язык с околонулевым порогом входа, хорошо подходит для написания микросервисов.
Но с некоторыми вещами смириться все же по-настоящему сложно.
Во-первых, это, конечно же, бесконечное
if err != nil {
return nil, err
}
которое засирает бизнес-логику приложения. Ты читаешь код, и хочется протереть глаза, логика как будто в каком-то тумане. GoLand визуально сворачивает это до одной строчки, но все равно как-то мешает.
Существует proposal (https://habr.com/ru/post/472758/ ), упрощающий синтаксис обработки ошибок при вызове фунций. Такая же явная обработка, как и раньше, только в 10 раз меньше писанины. Примерно аналогичная штука есть в Rust (пишешь знак ? и проброс ошибок происходит автоматически, оставаясь при этом явным).
Но нет же, прошло почти 2 года, а proposal так и остался предложением. Видимо, дополнительное ключевое слово - это капец слишком сложно.
Во-вторых, комментарии, которые на самом деле являются не комментариями, а своего рода аннотациями. Вместо того, чтобы сделать специальную синтаксическую конструкцию для аннотаций, в го приходится писать так:
//go:generate stringer -type=Pill
//go:embed assets/*
они выглядят как комментарии, подсвечиваются в IDE как комментарии, но на самом деле не они. Непонятно, для кого сделано такое упрощение, разве что для токенайзера. Точно не для людей )
Ну и в-третьих, общепринятые нормы, которые программисты на других языках считают говнокодерскими:
Повсеместно используются сокращения в именах переменных. Можно увидеть, как server сокращено до srv или даже s. Writer точно будет w, а Logger - l. Если вы пришли из C, то вам норм. Если вы из Java, то будет больно.
Дублирование кода. Дженериков пока что нет, и приходится дублировать или автогенерировать дублированный код. Но даже если не брать такую ситуацию, дублирование в Go считается норм. "A little copying is better than a little dependency" - один из основных постулатов.
В целом, Go хорош для написания написания эффективных микросервисов, он эффективно использует ресурсы и всё такое, но до чего же он странный ))))))
Переходя на Go с другого языка, проходишь все стадии: отрицание, гнев, торг, депрессия, принятие. Ибо язык сильно отличается от классических Java, PHP, JS и их общепринятых стандартов написания кода. Паттерны-фигаттерны, которые вы учили, можно забыть.
Всё можно понять: это намеренно упрощенный язык с околонулевым порогом входа, хорошо подходит для написания микросервисов.
Но с некоторыми вещами смириться все же по-настоящему сложно.
Во-первых, это, конечно же, бесконечное
if err != nil {
return nil, err
}
которое засирает бизнес-логику приложения. Ты читаешь код, и хочется протереть глаза, логика как будто в каком-то тумане. GoLand визуально сворачивает это до одной строчки, но все равно как-то мешает.
Существует proposal (https://habr.com/ru/post/472758/ ), упрощающий синтаксис обработки ошибок при вызове фунций. Такая же явная обработка, как и раньше, только в 10 раз меньше писанины. Примерно аналогичная штука есть в Rust (пишешь знак ? и проброс ошибок происходит автоматически, оставаясь при этом явным).
Но нет же, прошло почти 2 года, а proposal так и остался предложением. Видимо, дополнительное ключевое слово - это капец слишком сложно.
Во-вторых, комментарии, которые на самом деле являются не комментариями, а своего рода аннотациями. Вместо того, чтобы сделать специальную синтаксическую конструкцию для аннотаций, в го приходится писать так:
//go:generate stringer -type=Pill
//go:embed assets/*
они выглядят как комментарии, подсвечиваются в IDE как комментарии, но на самом деле не они. Непонятно, для кого сделано такое упрощение, разве что для токенайзера. Точно не для людей )
Ну и в-третьих, общепринятые нормы, которые программисты на других языках считают говнокодерскими:
Повсеместно используются сокращения в именах переменных. Можно увидеть, как server сокращено до srv или даже s. Writer точно будет w, а Logger - l. Если вы пришли из C, то вам норм. Если вы из Java, то будет больно.
Дублирование кода. Дженериков пока что нет, и приходится дублировать или автогенерировать дублированный код. Но даже если не брать такую ситуацию, дублирование в Go считается норм. "A little copying is better than a little dependency" - один из основных постулатов.
В целом, Go хорош для написания написания эффективных микросервисов, он эффективно использует ресурсы и всё такое, но до чего же он странный ))))))
👀2
Немного холиварная тема про правила (линтеры, тесты и т.д).
Я считаю, что правила нужны, но только когда они нужны. Ваш кэп.
Программисты почему-то делятся на два лагеря, одним вообще всё по барабану и любой говнокод норм, а другие наоборот упарываются: 100% покрытие тестами, всё обложено линтерами, которые тебя затрахают до полусмерти.
Взять например, пункты из PSR-12 (стандарты языка PHP).
1) All PHP files MUST end with a non-blank line, terminated with a single LF.
А что будет-то, если я допущу еще одну пустую строку в конце файла? Читабельность ухудшится, может быть?
2) Declare statements MUST contain no spaces and MUST be exactly declare(strict_types=1) (with an optional semi-colon terminator).
Оу, а если я не дай бог перед скобкой поставлю пробел? Другой программист команды будет понимать этот код с эффективностью на 0.0001% меньше, это превратится в легаси?.
Да ни фига. Это просто отсутствие системного подхода. Мы почему-то поставили единообразие как абсолютную ценность. При этом остальные параметры системы проигнорировали. Например, дофаминовая радость от выполненной задачи может быть уменьшена необходимостью считать бессмысленные пробелы и переводы строк перед тем как отправить код на ревью. (если есть автофиксер - это ок, но обычно они не всё могут)
При этом есть правила, которые действительно могут привнести такое единообразие, которое улучшит читабельность. Просто не надо упарываться, всегда надо смотреть, что на самом деле важно, а что - нет.
Точно также и с Go. Казалось бы, в нем встроены инструменты gofmt / goimports, что еще надо, однако всё равно, если вы посмотрите любой реальный проект, там будет дописана куча сомнительных правил для линтера. Например, что надо писать getJSON вместо getJson (ну, или наоборот). Оба написания легко читаются, тут не нужно особое правило.
Я не знаю, почему так, но это прям повсеместная проблема. Мы решаем какую-то боль (большое разнообразие в коде разных людей), возводим эту боль в 100% абсолют и забываем про проблемы системы в целом.
Ладно пробелы и наименования, часть этих проблем может решить автофиксер. Но есть и более сложные правила, которыми тебя задрочат на код ревью ради абстрактного единообразия.
Например, мантра, что контроллер должен быть ВСЕГДА настолько тонким, насколько это возможно, приведет к тому, что даже пара лишних строк, нормально читаемых, строк, которые никто и никогда не будет переиспользовать и не собирался, приведут к спорам на код ревью и исправлениям. Потому что порядок-то нужон. Т.е. вместо правил "код должен быть понятен" и "все важные места протестированы", вводятся правила по тонкости контроллеров, переиспользуемости классов и т.д., что выливается в 100 слоёв абстракции в участке кода, который правится-то раз в год и в целом не особо что делает полезное.
Ну или switch / case, одинаково используемый в двух местах, всегда ли надо переделывать на иерархию классов? Ну нет, it depends. Во главе угла - общая читаемость и гибкость кода, а в еще большем углу - деньги бизнеса. Важна система в целом. Непонимание этого часто приводит к паттернам головного мозга.
Про системный подход я еще обязательно напишу отдельный пост, так что не забудьте подписаться на канал
Я считаю, что правила нужны, но только когда они нужны. Ваш кэп.
Программисты почему-то делятся на два лагеря, одним вообще всё по барабану и любой говнокод норм, а другие наоборот упарываются: 100% покрытие тестами, всё обложено линтерами, которые тебя затрахают до полусмерти.
Взять например, пункты из PSR-12 (стандарты языка PHP).
1) All PHP files MUST end with a non-blank line, terminated with a single LF.
А что будет-то, если я допущу еще одну пустую строку в конце файла? Читабельность ухудшится, может быть?
2) Declare statements MUST contain no spaces and MUST be exactly declare(strict_types=1) (with an optional semi-colon terminator).
Оу, а если я не дай бог перед скобкой поставлю пробел? Другой программист команды будет понимать этот код с эффективностью на 0.0001% меньше, это превратится в легаси?.
Да ни фига. Это просто отсутствие системного подхода. Мы почему-то поставили единообразие как абсолютную ценность. При этом остальные параметры системы проигнорировали. Например, дофаминовая радость от выполненной задачи может быть уменьшена необходимостью считать бессмысленные пробелы и переводы строк перед тем как отправить код на ревью. (если есть автофиксер - это ок, но обычно они не всё могут)
При этом есть правила, которые действительно могут привнести такое единообразие, которое улучшит читабельность. Просто не надо упарываться, всегда надо смотреть, что на самом деле важно, а что - нет.
Точно также и с Go. Казалось бы, в нем встроены инструменты gofmt / goimports, что еще надо, однако всё равно, если вы посмотрите любой реальный проект, там будет дописана куча сомнительных правил для линтера. Например, что надо писать getJSON вместо getJson (ну, или наоборот). Оба написания легко читаются, тут не нужно особое правило.
Я не знаю, почему так, но это прям повсеместная проблема. Мы решаем какую-то боль (большое разнообразие в коде разных людей), возводим эту боль в 100% абсолют и забываем про проблемы системы в целом.
Ладно пробелы и наименования, часть этих проблем может решить автофиксер. Но есть и более сложные правила, которыми тебя задрочат на код ревью ради абстрактного единообразия.
Например, мантра, что контроллер должен быть ВСЕГДА настолько тонким, насколько это возможно, приведет к тому, что даже пара лишних строк, нормально читаемых, строк, которые никто и никогда не будет переиспользовать и не собирался, приведут к спорам на код ревью и исправлениям. Потому что порядок-то нужон. Т.е. вместо правил "код должен быть понятен" и "все важные места протестированы", вводятся правила по тонкости контроллеров, переиспользуемости классов и т.д., что выливается в 100 слоёв абстракции в участке кода, который правится-то раз в год и в целом не особо что делает полезное.
Ну или switch / case, одинаково используемый в двух местах, всегда ли надо переделывать на иерархию классов? Ну нет, it depends. Во главе угла - общая читаемость и гибкость кода, а в еще большем углу - деньги бизнеса. Важна система в целом. Непонимание этого часто приводит к паттернам головного мозга.
Про системный подход я еще обязательно напишу отдельный пост, так что не забудьте подписаться на канал
👀2
Однажды на кодревью обратили внимание ревьюируемого на то, что один из его методов слишком большой, и его сложно воспринимать. Мол, нельзя ли разбить его на части. На что был получен ответ, что это было сделано специально, чтобы не скакать лишний раз по функциям туда-сюда.
Я вмешался в процесс, сказал, что в данном случае лучше разбить, потому что мы же не объединяем всё приложение в один файл index.php, как делали наши деды, а всё же скачем по классам и методам.
Сказать-то я сказал, однако такое объяснение с дедами не очень-то объективно. Оно основано скорее на опыте и интуиции. И тут я задумался, а нельзя ли рассмотреть код как структуру данных, а процесс программирования - как алгоритм поиска места для вставки кода.
Не то, чтобы я продумал эту мысль до конца, просто наброс для размышления.
В случае, когда весь код в одном файле (или в одной большой функции) - это полный перебор, т.е. сложность O(n). Если же есть какая-то структура папок, файлов, методов, то это дерево, а поиск по дереву будет примерно O(log n). (Я тут не настоящий сварщик, поправьте меня в коментах, если я гоню лажу).
И дураку ясно, что быстрее всего было бы искать нужную строчку в бинарном дереве, т.е. чтобы каждый метод вызывал максимум два других метода.
Тут прикольно отметить, что примерно так и советуют в Чистом коде, цитата: “Функции не должны быть большими. Лучший размер для функции — 2–3 строки”.
Однако, в отличие от Роберта Мартина, абсолютное большинство программистов не готовы так упарываться, и на это есть какая-то причина.
Тут я не уверен, но думаю, что у человека просто не хватает оперативной памяти в мозгу, когда он скачет по дереву исполнения. Представьте, что в коде есть некоторая формула для расчета зарплаты, которую надо изменить, чтобы пофиксить баг. Если для исправления бага нужно понять её всю целиком, то мозгу будет сложнее, если каждая ее часть будет лежать в отдельной функции, а таких частей будет десяток. Говорят, что человек может запомнить за раз 5-7 единиц информации.
Т.е. это обход дерева с очень жёстким ограничением по памяти.
В итоге мы логично приходим к принципам SRP и high cohesion.
Т.е. один класс (или один метод, модуль - не важно) должен делать что-то одно (чтобы не перегружать поиск нужного участка кода), но при этом вещи из одной области бизнес-логики не должны быть сильно разбросаны по разным концам дерева.
Т.е. если вернуться к нашему примеру, формула для расчета зарплат должна быть по возможности видна в коде целиком, но при этом другие формулы или работа с выводом результата - точно должны быть отделены.
Я вмешался в процесс, сказал, что в данном случае лучше разбить, потому что мы же не объединяем всё приложение в один файл index.php, как делали наши деды, а всё же скачем по классам и методам.
Сказать-то я сказал, однако такое объяснение с дедами не очень-то объективно. Оно основано скорее на опыте и интуиции. И тут я задумался, а нельзя ли рассмотреть код как структуру данных, а процесс программирования - как алгоритм поиска места для вставки кода.
Не то, чтобы я продумал эту мысль до конца, просто наброс для размышления.
В случае, когда весь код в одном файле (или в одной большой функции) - это полный перебор, т.е. сложность O(n). Если же есть какая-то структура папок, файлов, методов, то это дерево, а поиск по дереву будет примерно O(log n). (Я тут не настоящий сварщик, поправьте меня в коментах, если я гоню лажу).
И дураку ясно, что быстрее всего было бы искать нужную строчку в бинарном дереве, т.е. чтобы каждый метод вызывал максимум два других метода.
Тут прикольно отметить, что примерно так и советуют в Чистом коде, цитата: “Функции не должны быть большими. Лучший размер для функции — 2–3 строки”.
Однако, в отличие от Роберта Мартина, абсолютное большинство программистов не готовы так упарываться, и на это есть какая-то причина.
Тут я не уверен, но думаю, что у человека просто не хватает оперативной памяти в мозгу, когда он скачет по дереву исполнения. Представьте, что в коде есть некоторая формула для расчета зарплаты, которую надо изменить, чтобы пофиксить баг. Если для исправления бага нужно понять её всю целиком, то мозгу будет сложнее, если каждая ее часть будет лежать в отдельной функции, а таких частей будет десяток. Говорят, что человек может запомнить за раз 5-7 единиц информации.
Т.е. это обход дерева с очень жёстким ограничением по памяти.
В итоге мы логично приходим к принципам SRP и high cohesion.
Т.е. один класс (или один метод, модуль - не важно) должен делать что-то одно (чтобы не перегружать поиск нужного участка кода), но при этом вещи из одной области бизнес-логики не должны быть сильно разбросаны по разным концам дерева.
Т.е. если вернуться к нашему примеру, формула для расчета зарплат должна быть по возможности видна в коде целиком, но при этом другие формулы или работа с выводом результата - точно должны быть отделены.
👀2
Говорят, в chrome встроили генерацию puppeteer скриптов. Пара кликов прямо в браузере, и тестовый скрипт готов.
Схематично это работает так: вы открываете нужную страницу, в DevTools включаете запись действий, и после делаете что-то на странице обычным образом (кликаете по ссылкам и кнопкам, переходите на другие страницы, вводите текст). По мере выполнения действий браузер наполняет DevTools-вкладку с виртуальным файлом записи JS-кодом, описывающим через API Puppeteer все действия. После этого запись можно остановить, и сохранить полученный код в виде реального JS-файла.
https://habr.com/ru/post/539156/
Схематично это работает так: вы открываете нужную страницу, в DevTools включаете запись действий, и после делаете что-то на странице обычным образом (кликаете по ссылкам и кнопкам, переходите на другие страницы, вводите текст). По мере выполнения действий браузер наполняет DevTools-вкладку с виртуальным файлом записи JS-кодом, описывающим через API Puppeteer все действия. После этого запись можно остановить, и сохранить полученный код в виде реального JS-файла.
https://habr.com/ru/post/539156/
Хабр
Автогенерация тестов на Puppeteer встроена в Chrome DevTools
В Chrome 89 в DevTools добавлена экспериментальная поддержка автогенерации JS-скриптов на Puppeteer . Схематично это работает так: вы открываете нужную страницу, в DevTools включаете запись действий,...
👀2
Срач в go-сообществе.
Matthew Dempsky, один из разработчиков компилятора Go, написал в твиттере, что отказывается работать над языком (за исключением прямых указаний менеджмента). До тех пор, пока ему не дадут вмержить ветку с разработкой дженериков в master.
Дело в том, что разработка такого фунционала затрагивает очень многие части системы, что приводит к постоянным решениям merge-конфликтов. Но похоже, что никому, кроме Мэтью нет дела до этих проблем, и ему пришлось вынести обсуждение в твиттер.
Для тех, кто не знает, дженерики - одна из самых ожидаемых фич в Go
https://twitter.com/mdempsky/status/1354512588495671297
Matthew Dempsky, один из разработчиков компилятора Go, написал в твиттере, что отказывается работать над языком (за исключением прямых указаний менеджмента). До тех пор, пока ему не дадут вмержить ветку с разработкой дженериков в master.
Дело в том, что разработка такого фунционала затрагивает очень многие части системы, что приводит к постоянным решениям merge-конфликтов. Но похоже, что никому, кроме Мэтью нет дела до этих проблем, и ему пришлось вынести обсуждение в твиттер.
Для тех, кто не знает, дженерики - одна из самых ожидаемых фич в Go
https://twitter.com/mdempsky/status/1354512588495671297
Twitter
Matthew Dempsky
To emphasize how frustrated I am with Go leadership undervaluing my contributions and time, I refuse to do any further work on Go that's not directly assigned to me by management until #43651 or #43931 are accepted.twitter.com/mdempsky/statu…
👀2
В репозиторий Postgres упал комит, упрощающий работу с jsonb. Теперь можно обращаться к частям jsonb с помощью квадратных скобок, причем это работает и на чтение, и на запись.
Прощай jsonb_set и прочие костыли типа data = data - 'a' || '{"a":5}'
Несколько примеров:
Изменения войдут в postgreSQL14!
#postgresql
Прощай jsonb_set и прочие костыли типа data = data - 'a' || '{"a":5}'
Несколько примеров:
-- Получаем значение объекта по ключу "a"
SELECT ('{"a": 1}'::jsonb)['a'];
-- Или можно указать длинный путь
SELECT ('{"a": {"b": {"c": 1}}}'::jsonb)['a']['b']['c'];
-- Элемент массива по индексу
SELECT ('[1, "2", null]'::jsonb)[1];
-- Обновляем значение объекта по ключу. Единица взята в кавычки, потому что присваиваемое значение должно быть тоже jsonb
UPDATE table_name SET jsonb_field['key'] = '1';
-- Фильтруем таблицу по полю key=value. Value тоже записано в форме jsonb: '"value"'
SELECT * FROM table_name WHERE jsonb_field['key'] = '"value"';
Изменения войдут в postgreSQL14!
#postgresql
👀2
Как же бесит, когда “гуру” пытаются высосать из пальца новый вид архитектуры приложения, назвать его по-умному, обмазать кучей слов и выдавать за гениальное творение.
Луковая архитектура, гексагональная архитектура, архитектура портов и адаптеров - давайте еще придумаем 100500 терминов для того, чтобы сказать, что программа станет гибче, если использовать интерфейсы. И уж точно никто из гуру-архитекторов не упомянет, что иногда интерфейсы не нужны (как и излишняя гибкость).
Особенно доставляет гексагон. Никто не может нормально объяснить, почему архитектура именно гексагональная и у нее именно 6 граней-портов. Потому что fuck you, that’s why.
Почему интерфейсы внезапно назвали портами, а имплементации интерфейсов - адаптерами? Чем не угодили старые добрые интерфейсы и имплементации?
Я прям вижу, как кто-то выжимал из себя статью, рисовал прикольную картинку с шестиугольником, и тут его озарило - гексагональная архитектура, какое наукообразное мудрёное название, надо брать!
В общем, когда кто-то вместо сути пытается делать умное лицо и включает словоблудие, я обычно начинаю задавать короткие прямые вопросы, и всё становится яснее. Порой за ответами вообще ничего важного нет.
Луковая архитектура, гексагональная архитектура, архитектура портов и адаптеров - давайте еще придумаем 100500 терминов для того, чтобы сказать, что программа станет гибче, если использовать интерфейсы. И уж точно никто из гуру-архитекторов не упомянет, что иногда интерфейсы не нужны (как и излишняя гибкость).
Особенно доставляет гексагон. Никто не может нормально объяснить, почему архитектура именно гексагональная и у нее именно 6 граней-портов. Потому что fuck you, that’s why.
Почему интерфейсы внезапно назвали портами, а имплементации интерфейсов - адаптерами? Чем не угодили старые добрые интерфейсы и имплементации?
Я прям вижу, как кто-то выжимал из себя статью, рисовал прикольную картинку с шестиугольником, и тут его озарило - гексагональная архитектура, какое наукообразное мудрёное название, надо брать!
В общем, когда кто-то вместо сути пытается делать умное лицо и включает словоблудие, я обычно начинаю задавать короткие прямые вопросы, и всё становится яснее. Порой за ответами вообще ничего важного нет.
👀2
Прочитал забавную статью про mutation driven testing.
Прежде чем рассказать об этом подходе сначала в двух словах объясню, что такое мутационное тестирование вообще. Для тех, кто не в курсе.
Когда вы пишете тесты, по TDD или нет, даже с формальным 100% покрытием, вы никогда не будете уверены в том, что в коде на самом деле протестировано всё. Например, можно банально ошибиться в вызове assert в самом тесте. Или не учесть детали преобразования типов, что никак не повлияет на coverage.
Чтобы убедиться в том, что тесты реально тестируют, есть такой способ: самому вносить в код баги, и смотреть, валятся ли от этого тесты. Если тесты по-прежнему зелёные при явном баге, значит протестировано не всё.
Например, заменили плюс на минус, или добавили "не" к условию, и смотрите.
Обычно это делают в очень ответственных областях программирования, где ошибки вообще не допустимы. Например, софт марсохода или медицинское ПО.
Конечно в марсоходостроении это все делается автоматически: специальный инструмент уродует вашу программу и смотрит, слетели ли тесты.
Проблема в этом подходе в том, что это довольно муторно настраивается, много нюансов, как описать, что надо мутировать, что нет. И всё это потребляет дикое количество ресурсов: разбор кода в AST, мутирование и обратное преобразование.
Автор статьи предлагает подход, аналогичный TDD, но как бы наоборот и совсем другой 🙂
1) сначала добавляете новый код в проект
2) временно вносите в какие-то строки баг
3) пишете тест, который ловит этот баг
Для меня такой подход видится интересным тем, что можно ничего не настраивать в CI, не просить выделить доп ресурсы для обработки пайплайнов, а просто писать полностью покрытый код, даже если тимлиду или вообще никому в твоей команде в целом такой подход неинтересен.
Конечно, это не бесплатно, и пожирает ресурсы программиста. Имхо mutation driven testing можно и нужно применять только там, где есть ответственная логика. Работа с деньгами, медицинский софт и т.д. Понятно, что на эндпоинт, выдающий текущую погоду или прочую ерунду, можно не тратить ресурсы, как ручные, так и автоматические.
Прежде чем рассказать об этом подходе сначала в двух словах объясню, что такое мутационное тестирование вообще. Для тех, кто не в курсе.
Когда вы пишете тесты, по TDD или нет, даже с формальным 100% покрытием, вы никогда не будете уверены в том, что в коде на самом деле протестировано всё. Например, можно банально ошибиться в вызове assert в самом тесте. Или не учесть детали преобразования типов, что никак не повлияет на coverage.
Чтобы убедиться в том, что тесты реально тестируют, есть такой способ: самому вносить в код баги, и смотреть, валятся ли от этого тесты. Если тесты по-прежнему зелёные при явном баге, значит протестировано не всё.
Например, заменили плюс на минус, или добавили "не" к условию, и смотрите.
Обычно это делают в очень ответственных областях программирования, где ошибки вообще не допустимы. Например, софт марсохода или медицинское ПО.
Конечно в марсоходостроении это все делается автоматически: специальный инструмент уродует вашу программу и смотрит, слетели ли тесты.
Проблема в этом подходе в том, что это довольно муторно настраивается, много нюансов, как описать, что надо мутировать, что нет. И всё это потребляет дикое количество ресурсов: разбор кода в AST, мутирование и обратное преобразование.
Автор статьи предлагает подход, аналогичный TDD, но как бы наоборот и совсем другой 🙂
1) сначала добавляете новый код в проект
2) временно вносите в какие-то строки баг
3) пишете тест, который ловит этот баг
Для меня такой подход видится интересным тем, что можно ничего не настраивать в CI, не просить выделить доп ресурсы для обработки пайплайнов, а просто писать полностью покрытый код, даже если тимлиду или вообще никому в твоей команде в целом такой подход неинтересен.
Конечно, это не бесплатно, и пожирает ресурсы программиста. Имхо mutation driven testing можно и нужно применять только там, где есть ответственная логика. Работа с деньгами, медицинский софт и т.д. Понятно, что на эндпоинт, выдающий текущую погоду или прочую ерунду, можно не тратить ресурсы, как ручные, так и автоматические.
👀1
Через несколько дней заканчивается голосование по первой итерации реализации enum в PHP 8.1 (https://wiki.php.net/rfc/enumerations#voting ). Уже видно, что голосов “за” гораздо больше, так что давайте кратко пройдемся и посмотрим, что же нам приготовили авторы языка.
Зачем нужны enum?
Зачем вообще нужны enum? По сути они служат цели улучшенного описания типов. Давайте рассмотрим пример без енумов и с ними. Допустим, у нас продаются машины трех цветов: красные, черные и белые. Как описать цвет, какой тип выбрать?
class Car {
private string $color;
function setColor(string $color): void {
$this->color = $color;
}
}
Если мы опишем цвет машины как простой string, то во-первых при вызове $myCar->setColor(..) непонятно, что за строку туда писать. “red” или “RED” или "ff0000", а во вторых, легко ошибиться, просунув туда случайно что-то не то (пустую строку, к примеру). То же самое будет, если использовать не строки, а числа, например.
Это приводит к тому, что многие php-программисты заводят константы и объединяют их в одном классе, чтобы явно видеть все варианты.
class Color {
public const RED = "red";
public const BLACK = "black";
public const WHITE = "white";
}
и задавая цвет, пишут $myCar->setColor(Color::RED);
Уже лучше. Но если мы впервые видим метод $myCar->setColor(...), мы можем и не знать, что где-то есть константы для цветов. И мы всё еще можем сунуть туда любую строку без какого-либо сообщения об ошибке.
Поэтому здесь нужен не класс, а отдельный тип. Этот тип называется enum
Pure enum
В самом простом случае (pure enum), enum описывается так:
enum Color {
case Red;
case Black;
case White;
}
Описав такой тип, мы можем использовать его везде:
class Car {
private Color $color;
function setColor(Color $color): void {
$this->color = $color;
}
}
Из сигнатуры метода всё сразу видно, какие варианты есть. И метод setColor можно использовать только так: $myCar->setColor(Color::White), никаких строк и доморощенных списков констант. Ничего лишнего не сунешь. Читабельность и поддерживаемость кода стала выше.
Каждый из case-ов (Color::Red, Color::Black, Color::White) является объектом типа Color (можно проверить через instanseof ). Т.е. под капотом это не числа 0,1,2 как в некоторых языках, а именно объекты. Их нельзя сравнивать оператором >, например. У каждого такого объекта есть встроенное свойство $name:
print Color::Red->name; // вернет строку “Red”
Enum со скалярами
Но если бы это было всё, то было бы слишком просто. После названия enum можно указать скалярный тип, например string. И у каждого кейса указать скалярное значение. Это может быть полезно для некоторых целей, например для сортировки или записи в базу данных.
enum Color: string {
case Red = "R";
case Black = "B";
case White = "W";
}
Скалярное значение можно получить потом так:
Color::Red->value //вернет строку “R”
И наоборот, т.е. получить case через значение, тоже можно:
Color::from("R") // вернет объект Color::Red
Помимо полей "case" в enum может быть еще много всего. По сути это разновидность класса. Там могут быть методы, он может реализовывать интерфейсы или использовать трейты:
https://gist.github.com/anton-okolelov/f5e8787b6dfe9b28cbeef7bf5fa9e611
При этом $this будет тот конкретный объект case, для которого мы вызываем метод.
Лично я горячо одобряю введение enum в PHP, это очень удобно и читабельно, и в большинстве языков, где есть какие-никакие типы, enum уже давно есть (кроме, разве что Go).
Дальше - больше. Tagged Unions (тип-сумма)
Есть RFC, которые развивают идею enums дальше, чтобы можно было хранить в одном enum значения разных типов. Как в языке Rust, например. Тогда можно будет сделать, допустим, enum Result с двумя case-ами Result::Ok и Result::Err, причем эти объекты будут хранить данные: Ok будет хранить результат, а Err - ошибку, у каждого из этих значений будет свой тип. И всё это не в Расте, а в PHP!
Об этом мы расскажем в деталях в ближайших постах телеграм-канала Cross Join, не забудьте подписаться!
Зачем нужны enum?
Зачем вообще нужны enum? По сути они служат цели улучшенного описания типов. Давайте рассмотрим пример без енумов и с ними. Допустим, у нас продаются машины трех цветов: красные, черные и белые. Как описать цвет, какой тип выбрать?
class Car {
private string $color;
function setColor(string $color): void {
$this->color = $color;
}
}
Если мы опишем цвет машины как простой string, то во-первых при вызове $myCar->setColor(..) непонятно, что за строку туда писать. “red” или “RED” или "ff0000", а во вторых, легко ошибиться, просунув туда случайно что-то не то (пустую строку, к примеру). То же самое будет, если использовать не строки, а числа, например.
Это приводит к тому, что многие php-программисты заводят константы и объединяют их в одном классе, чтобы явно видеть все варианты.
class Color {
public const RED = "red";
public const BLACK = "black";
public const WHITE = "white";
}
и задавая цвет, пишут $myCar->setColor(Color::RED);
Уже лучше. Но если мы впервые видим метод $myCar->setColor(...), мы можем и не знать, что где-то есть константы для цветов. И мы всё еще можем сунуть туда любую строку без какого-либо сообщения об ошибке.
Поэтому здесь нужен не класс, а отдельный тип. Этот тип называется enum
Pure enum
В самом простом случае (pure enum), enum описывается так:
enum Color {
case Red;
case Black;
case White;
}
Описав такой тип, мы можем использовать его везде:
class Car {
private Color $color;
function setColor(Color $color): void {
$this->color = $color;
}
}
Из сигнатуры метода всё сразу видно, какие варианты есть. И метод setColor можно использовать только так: $myCar->setColor(Color::White), никаких строк и доморощенных списков констант. Ничего лишнего не сунешь. Читабельность и поддерживаемость кода стала выше.
Каждый из case-ов (Color::Red, Color::Black, Color::White) является объектом типа Color (можно проверить через instanseof ). Т.е. под капотом это не числа 0,1,2 как в некоторых языках, а именно объекты. Их нельзя сравнивать оператором >, например. У каждого такого объекта есть встроенное свойство $name:
print Color::Red->name; // вернет строку “Red”
Enum со скалярами
Но если бы это было всё, то было бы слишком просто. После названия enum можно указать скалярный тип, например string. И у каждого кейса указать скалярное значение. Это может быть полезно для некоторых целей, например для сортировки или записи в базу данных.
enum Color: string {
case Red = "R";
case Black = "B";
case White = "W";
}
Скалярное значение можно получить потом так:
Color::Red->value //вернет строку “R”
И наоборот, т.е. получить case через значение, тоже можно:
Color::from("R") // вернет объект Color::Red
Помимо полей "case" в enum может быть еще много всего. По сути это разновидность класса. Там могут быть методы, он может реализовывать интерфейсы или использовать трейты:
https://gist.github.com/anton-okolelov/f5e8787b6dfe9b28cbeef7bf5fa9e611
При этом $this будет тот конкретный объект case, для которого мы вызываем метод.
Лично я горячо одобряю введение enum в PHP, это очень удобно и читабельно, и в большинстве языков, где есть какие-никакие типы, enum уже давно есть (кроме, разве что Go).
Дальше - больше. Tagged Unions (тип-сумма)
Есть RFC, которые развивают идею enums дальше, чтобы можно было хранить в одном enum значения разных типов. Как в языке Rust, например. Тогда можно будет сделать, допустим, enum Result с двумя case-ами Result::Ok и Result::Err, причем эти объекты будут хранить данные: Ok будет хранить результат, а Err - ошибку, у каждого из этих значений будет свой тип. И всё это не в Расте, а в PHP!
Об этом мы расскажем в деталях в ближайших постах телеграм-канала Cross Join, не забудьте подписаться!
👀1
Когда нужно выделять абстракцию, а когда нет? Есть два похожих класса, нужно ли их обобщать? Или лучше поддерживать по отдельности (читай - местами это будет копипаста).
Язык Go говорит, что немного копипасты лучше, чем дополнительная абстракция.
Кто-то, из классических ООП-языков, скажет, что DRY священен, и нельзя повторяться.
На мой взгляд, тут всё просто. Если две сущности похожи не только внешне, но и по бизнес-логике должны быть похожи - можно выделять абстракцию при необходимости.
Если два класса похожи парочкой методов, но имеют разную суть, то ни в коем случае нельзя обобщать. Даже если сложно избавиться от дублирования кода другими способами. Лучше копипаста, ей богу.
Потому что в будущем такой код будет сложнее понять и сложнее поддерживать: с каждым изменением придется со скрипом натягивать такое обобщение, и всё будет становиться еще страннее
Язык Go говорит, что немного копипасты лучше, чем дополнительная абстракция.
Кто-то, из классических ООП-языков, скажет, что DRY священен, и нельзя повторяться.
На мой взгляд, тут всё просто. Если две сущности похожи не только внешне, но и по бизнес-логике должны быть похожи - можно выделять абстракцию при необходимости.
Если два класса похожи парочкой методов, но имеют разную суть, то ни в коем случае нельзя обобщать. Даже если сложно избавиться от дублирования кода другими способами. Лучше копипаста, ей богу.
Потому что в будущем такой код будет сложнее понять и сложнее поддерживать: с каждым изменением придется со скрипом натягивать такое обобщение, и всё будет становиться еще страннее
👀1
Семимониторный ноут уже можно заказать )
У майкрософт как-то были исследования, что размер экрана увеличивает производительность программиста, но тут чутка перебрали
https://m.habr.com/ru/company/selectel/blog/541472/
У майкрософт как-то были исследования, что размер экрана увеличивает производительность программиста, но тут чутка перебрали
https://m.habr.com/ru/company/selectel/blog/541472/
Хабр
Стартовали продажи ноутбука Aurora 7 с семью дисплеями
Разработчики этого чуда техники, создавая прототип, явно проговаривали про себя: «Маловато будет!», имея в виду количество экранов. Два дисплея? Банально и относительно часто встречается. Три? Ну нет....
Опубликовал статью про tagged unions в PHP (этот RFC еще не принят, и даже голосования не было, однако всё равно было любопытно).
https://habr.com/ru/post/541670/
https://habr.com/ru/post/541670/
Хабр
Tagged Unions в PHP (примерно как в Rust)
UPD. Во избежание путаницы по просьбам трудящихся хочу еще раз уточнить, что это только черновик, который еще пока что не был официально предложен В предыдущей с...
Proposal Go generics был только что принят. Это означает, что дженерики скоро попадут в язык. Ну как скоро, ожидается к 1.18beta, т.е. где-то в декабре.
ссылка на proposal: https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md
примеры использования: https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#examples
обсуждение на reddit: https://www.reddit.com/r/golang/comments/lh2158/proposal_43650_generics_by_type_parameters_just/
ссылка на proposal: https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md
примеры использования: https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#examples
обсуждение на reddit: https://www.reddit.com/r/golang/comments/lh2158/proposal_43650_generics_by_type_parameters_just/
Reddit
From the golang community on Reddit: Proposal 43650 (generics by type parameters) just got accepted!
Explore this post and more from the golang community
👀1
В подкасте "Цинковый прод" записали необычный выпуск. Не про языки и базы данных, а внезапно про правильное питание. Айтишники склонны работать круглые сутки за компом, зачастую мало двигаются, питаются черт знает чем, и тема еды всплывала в чате подкаста не раз.
Лишний вес, вредны ли энергетики, нужно ли голодать, что лучше - спорт или диета и так далее. Всё это мы обсудили в выпуске. Инет местами лагал, но гость жёг напалмом, очень веселый парень.
https://www.youtube.com/watch?v=9pyZcKv1hsg
Лишний вес, вредны ли энергетики, нужно ли голодать, что лучше - спорт или диета и так далее. Всё это мы обсудили в выпуске. Инет местами лагал, но гость жёг напалмом, очень веселый парень.
https://www.youtube.com/watch?v=9pyZcKv1hsg
YouTube
#099 Айтишники и еда. Диетолог Антоний Мальков в Цинковом проде
Сидишь скрюченный, не отрывая жопы, и ешь печеньки? Заработал лишние килограммы и изжогу? Или наоборот, дофига спортсмен, и хочешь более эффективно питаться?
00:00 Приветствие. В гостях Антоний Мальков
6:43 Типичный айтишник - как выработать полезные привычки…
00:00 Приветствие. В гостях Антоний Мальков
6:43 Типичный айтишник - как выработать полезные привычки…
Женя Антонов недавно писал, что сложные дела лучше делать с утра, на свежую голову. А вечер оставлять для рутины и ерунды. В целом я согласен, часто сам так и делал, но есть дополнение.
Когда работаешь из дома, а сейчас очень много, кто работает из дома, иногда появляется возможность полноценно отдохнуть днем. Можно даже изловчиться и поспать полчаса в обеденный перерыв. (Те, кто меня знают лично, видели, что я и в офисе (!) умудрялся поспать в сидячем положении).
Были исследования НАСА, что получасовой дневной сон увеличивает продуктивность на треть!
Не всегда удается заснуть, но даже просто полежать бездумно, выбросив из мозга текущие проблемы - это своего рода медитация, которая позволяет перезагрузить работоспособность.
Тут надо упомянуть, что есть люди, которые, засыпая днем, не могут остановиться и дрыхнут часа три. Я подозреваю, что зачастую так сказывается общий фоновый недостаток сна. Я бы посоветовал спать 8 часов в сутки, а не играть/смотреть сериалы по ночам.
Вывод
Лучше вовремя отдыхать, тогда работа будет эффективнее. И тогда можно будет приоритезировать задачи не по сложности, а по важности для бизнеса.
Когда работаешь из дома, а сейчас очень много, кто работает из дома, иногда появляется возможность полноценно отдохнуть днем. Можно даже изловчиться и поспать полчаса в обеденный перерыв. (Те, кто меня знают лично, видели, что я и в офисе (!) умудрялся поспать в сидячем положении).
Были исследования НАСА, что получасовой дневной сон увеличивает продуктивность на треть!
Не всегда удается заснуть, но даже просто полежать бездумно, выбросив из мозга текущие проблемы - это своего рода медитация, которая позволяет перезагрузить работоспособность.
Тут надо упомянуть, что есть люди, которые, засыпая днем, не могут остановиться и дрыхнут часа три. Я подозреваю, что зачастую так сказывается общий фоновый недостаток сна. Я бы посоветовал спать 8 часов в сутки, а не играть/смотреть сериалы по ночам.
Вывод
Лучше вовремя отдыхать, тогда работа будет эффективнее. И тогда можно будет приоритезировать задачи не по сложности, а по важности для бизнеса.
Telegram
Тимлид Очевидность
Делаю сложные дела утром
Часто замечаю, что многие люди (как и я раньше) попадают в ситуацию, когда надо бы сделать сегодня что-то сложное, но хочется сначала выполнить простенькое, разобраться с мелочами, вдохновиться легкими победами.
Я считаю это большой…
Часто замечаю, что многие люди (как и я раньше) попадают в ситуацию, когда надо бы сделать сегодня что-то сложное, но хочется сначала выполнить простенькое, разобраться с мелочами, вдохновиться легкими победами.
Я считаю это большой…
👍2
Меня попросили распространить новость о том, что скоро будет мегастрим, где будет обсжуждаться будущее и прошлое PHP с core-разработчиками, фреймворк-мейкерами и прочими инфлюенсерами: https://habr.com/ru/company/skyeng/blog/542070/
Ну и чтобы два раза не вставать, сразу добавлю свои 5 копеек.
Куда движется PHP?
С одной стороны, PHP становится всё круче и круче: еще больше возможностей для типизации (например, enums), еще выше скорость работы (куча оптимизаций движка + еще JIT), много хороших полноценных фреймворков (Symfony для чистоты кода, Laravel для скорости разработки + Yii еще есть). Засчет развития языка, говнокодеров на PHP все меньше и меньше, плохая репутация языка потихоньку уходит.
С другой стороны, в языке есть один гигантский недостаток, который перебивает многие достоинства.
Нет нормальной возможности для разработки асинхронных i/o-bound приложений.
Давайте посмотрим на ближайших конкурентов на этом поле:
В NodeJS - встроен event loop из коробки, есть async/await и т.д
В Go - есть goroutines, которые запускаются добавлением одного ключевого слова "go" перед вызовом функции
Можно перечислять долго, но в целом по-моему на данный момент чуть ли не все языки кроме PHP обзавелись какой-то такой штукой. Можно на уровне самого языка сделать сервер (без связки nginx+php-fpm) и обрабатывать одновременно и http, и общаться по вебсокетам, и слушать кафку и т.д.
В php есть AmPHP, swoole и т.д., но они являются сторонними решениями, а не first-class citizen, неизвестно их будущее (может, проекты закроют завтра), и самое главное - никто из пхпшников их толком не знает и не применяет на проде. Чуть ниже будет опрос на эту тему.
Более того, даже если бы в язык был встроен event loop и async/await, то стандартная библиотека к этому не готова. Например, PDO - сплошь синхронно (в AmPHP сделана своя асинхронная реализация подключения к Postgres). Чтение из сокета можно перевести в неблокирующий режим (socket_set_nonblock() ), но придется писать много обвязок, всё неудобно и не по-людски.
Но самое печальное, что Дмитрий Стогов, core-разработчик языка не считает это проблемой.
Итого, что мы имеем.
На php удобно писать, язык хороший, но нельзя или очень-очень неудобно писать современные вещи:
1) Микросервисы ( часто требуют асинхронной обработки сообщений и кроме того невыгодно тащить nginx+php-fpm для каждого микросервиса)
2) graphql. Хотя на php можно писать под graphql, но части запроса не будут отрабатывать параллельно без ReactPHP и его друзей
3) websockets
4) grpc-сервер
Затащив асинхронность, можно было бы всё это починить, и PHP начал бы отъедать рынок обратно.
попытка с Fibers
Есть RFC c добавлением Fibers. Но там же всё жутко сложно, и не предназначено для прямого использования. Это скорее для облегчения разработки Swoole и подобных решений; стандартизация подходов с самодельным event-loop
Вот пример приложения которое умеет читать и писать в сокет: https://github.com/amphp/ext-fiber/blob/master/examples/002-read-write.php
Там столько деталей, что сходу непонятно вообще, что программа делает.
Ну и стандартная библиотека всё равно нифига не готова.
Тем не менее то, что идет работа в этом направлении, уже радует, так как десятилетиями не было и этого. Возможно, это первый шаг, после которого плотину наконец-то прорвёт.
Если не будет поздно. Другие языки не стоят на месте и обрастают новыми подходами. ( Взять хотя бы React Server Components - адская клиент-серверная смесь. Неизвестно, выстрелит это или нет, просто пример).
Т.е. к тому моменту, когда PHP наконец пройдет этот путь (сделает конструкции в самом языке, перепишет стандартную библиотеку, адаптирует все фреймворки), javanoscript/typenoscript будет уже где-то в космосе по количеству новых интересных подходов.
Ну и чтобы два раза не вставать, сразу добавлю свои 5 копеек.
Куда движется PHP?
С одной стороны, PHP становится всё круче и круче: еще больше возможностей для типизации (например, enums), еще выше скорость работы (куча оптимизаций движка + еще JIT), много хороших полноценных фреймворков (Symfony для чистоты кода, Laravel для скорости разработки + Yii еще есть). Засчет развития языка, говнокодеров на PHP все меньше и меньше, плохая репутация языка потихоньку уходит.
С другой стороны, в языке есть один гигантский недостаток, который перебивает многие достоинства.
Нет нормальной возможности для разработки асинхронных i/o-bound приложений.
Давайте посмотрим на ближайших конкурентов на этом поле:
В NodeJS - встроен event loop из коробки, есть async/await и т.д
В Go - есть goroutines, которые запускаются добавлением одного ключевого слова "go" перед вызовом функции
Можно перечислять долго, но в целом по-моему на данный момент чуть ли не все языки кроме PHP обзавелись какой-то такой штукой. Можно на уровне самого языка сделать сервер (без связки nginx+php-fpm) и обрабатывать одновременно и http, и общаться по вебсокетам, и слушать кафку и т.д.
В php есть AmPHP, swoole и т.д., но они являются сторонними решениями, а не first-class citizen, неизвестно их будущее (может, проекты закроют завтра), и самое главное - никто из пхпшников их толком не знает и не применяет на проде. Чуть ниже будет опрос на эту тему.
Более того, даже если бы в язык был встроен event loop и async/await, то стандартная библиотека к этому не готова. Например, PDO - сплошь синхронно (в AmPHP сделана своя асинхронная реализация подключения к Postgres). Чтение из сокета можно перевести в неблокирующий режим (socket_set_nonblock() ), но придется писать много обвязок, всё неудобно и не по-людски.
Но самое печальное, что Дмитрий Стогов, core-разработчик языка не считает это проблемой.
Итого, что мы имеем.
На php удобно писать, язык хороший, но нельзя или очень-очень неудобно писать современные вещи:
1) Микросервисы ( часто требуют асинхронной обработки сообщений и кроме того невыгодно тащить nginx+php-fpm для каждого микросервиса)
2) graphql. Хотя на php можно писать под graphql, но части запроса не будут отрабатывать параллельно без ReactPHP и его друзей
3) websockets
4) grpc-сервер
Затащив асинхронность, можно было бы всё это починить, и PHP начал бы отъедать рынок обратно.
попытка с Fibers
Есть RFC c добавлением Fibers. Но там же всё жутко сложно, и не предназначено для прямого использования. Это скорее для облегчения разработки Swoole и подобных решений; стандартизация подходов с самодельным event-loop
Вот пример приложения которое умеет читать и писать в сокет: https://github.com/amphp/ext-fiber/blob/master/examples/002-read-write.php
Там столько деталей, что сходу непонятно вообще, что программа делает.
Ну и стандартная библиотека всё равно нифига не готова.
Тем не менее то, что идет работа в этом направлении, уже радует, так как десятилетиями не было и этого. Возможно, это первый шаг, после которого плотину наконец-то прорвёт.
Если не будет поздно. Другие языки не стоят на месте и обрастают новыми подходами. ( Взять хотя бы React Server Components - адская клиент-серверная смесь. Неизвестно, выстрелит это или нет, просто пример).
Т.е. к тому моменту, когда PHP наконец пройдет этот путь (сделает конструкции в самом языке, перепишет стандартную библиотеку, адаптирует все фреймворки), javanoscript/typenoscript будет уже где-то в космосе по количеству новых интересных подходов.
👍2
Опрос только для PHP-програмистов. Используете ли вы в реальной работе на проде ReactPHP, AmPHP или Swoole?
Просьба пошарить этот опрос, так как канал новый, и подписчиков здесь пока маловато.
Просьба пошарить этот опрос, так как канал новый, и подписчиков здесь пока маловато.
Anonymous Poll
5%
Да
50%
Нет
45%
Я не PHP-шник
Cross Join - канал о разработке pinned «Опрос только для PHP-програмистов. Используете ли вы в реальной работе на проде ReactPHP, AmPHP или Swoole?
Просьба пошарить этот опрос, так как канал новый, и подписчиков здесь пока маловато.»
Просьба пошарить этот опрос, так как канал новый, и подписчиков здесь пока маловато.»