На днях просто сгорела жепа🤬 Все дело в том, что я послушал вот этот подкаст (только в аудио). Потом глянул, че там за гость и понял, что видел его уже в другом ролике, который не смог дослушать до конца.
Основной тезис гостя, Андрея Бреслава: скоро мы вообще перестанем писать прикладной код на привычных ЯП. Вместо этого, у нас будет обычный язык (английский), но мы будем писать требования в определенном формализованном виде. И вот это как раз будет наш НОВЫЙ язык программирования будщего!!! А "интерпретировать" наш язык будет, сюрприз-сюрприз, LLM.😱
Какая же база стоит за этим серьезным завлением? А база очень простая. Она называется АНАЛогия. Андрей утверждает, что с развитием индустрии постепенно рос уровень абстракции. И сейчас то самое время, когда LLM позволяют нам сделать очередной скачок в этой лестнице абстракции, перестать задуматься о таких вещах, как переменные, циклы, списки, классы и прочее, по аналогии с тем, как мы не задумываемся о машинном коде, когда пишем на петухоне - утверждает Андрей.
Но при этом игнорируются фундаментальные различия между предыдущими шагами развития ЯП и подходом, который предлагает Андрей. Я предлагаю поговорить об этих различиях.
* Отсутствие детерминизма в работе LLM. На один и тот же input ты можешь получить кучу ouputов. Соответственно, нельзя относиться к такому ЯП как к исходникам.
* Продукт "транспиляции" такого ЯП - другой существующий высокоуровневый ЯП (js, python и тд). Предполагается возможность "поправить" результат прям там, если что-то пойдет не так. Это уже сразу признак херовой абстракции. Если у тебя сейчас что-то не так с байткодом, ты не пойдешь править байткод. Ты пойдешь править компилятор.
* Отсутствие понимания процесса отладки в таком ЯП. Как это могло бы выглядеть хотя бы в теории не знает сам гость.
* Как вообще валидировать результат? Тесты написать? Так их же тоже нагенерят. Непонятно, куда в таком процессе человеку в целом воткнуться.
Это я по самым верхам прошелся. Тут еще и вопросы, связанные с развитием "артефактных" ЯП вроде js и python, как обучать llm новым версиям, если они станут не нужны. Также вопрос по скорости работы и цене такого решения. А что насчет безопасности🤷
Гость натягивает свою аналогию ровно так, как это нужно натягивать, чтоб получить первый раунд инвестиций (о чем прямо говорит). И это бесит. Потому что нет здесь никакого визионерства, нет теории, нет ответов на вопросы. Есть просто желание попилить бабки.
А я вот тоже хочу позаниматься визионерством!
Когда я только начинал работать, то были такие IDE, как Netbeans и Eclipse (олды тут?). Там был бэйсик автокомплит без каких-то особых возможностей форматирования, рефакторинга и прочего. А до этого, вообще люди в блокноте писали, код, где даже такого не было. Затем ворвались Jetbrains с Idea. Они подняли удобство написания кода на новый уровень. Статический анализ, рефакторинг крупных модулей, более качественный атокомплит - это все появилось там и эволюционировало с течением времени. И другие IDE тоже старались не отставать в этом. Короче говоря, за 15 лет индустрии процесс кодирования существенно изменился, его удобство повысилось на порядки.
Мне кажется, настало время кардинально улучшить наши IDE. LLM позволит вывести их на НОВЫЙ уровень!
Как вам идея? думаете стоит к инвесторам с ней пойти, чтоб сделать IDE БУДУЩЕГО, где LLM будет заниматься автокомлитом и рефакторингом? Это будет РЕВОЛЮЦИЯ по аналогии с той, что Jetbrains произвели в своей время.
А, стоп! так такие IDE уже есть! и блять наверное они есть, потому что это естественный процесс развития отрасли, а не надуманная херня под которую надо ходить на подкасты, чтоб ебалом посветить🤬
В заключении хотелось бы сказать, что аналогия может быть хороша для объяснения явления. Но никакой аналогии недостаточно для принятия решения☝️
Основной тезис гостя, Андрея Бреслава: скоро мы вообще перестанем писать прикладной код на привычных ЯП. Вместо этого, у нас будет обычный язык (английский), но мы будем писать требования в определенном формализованном виде. И вот это как раз будет наш НОВЫЙ язык программирования будщего!!! А "интерпретировать" наш язык будет, сюрприз-сюрприз, LLM.😱
Какая же база стоит за этим серьезным завлением? А база очень простая. Она называется АНАЛогия. Андрей утверждает, что с развитием индустрии постепенно рос уровень абстракции. И сейчас то самое время, когда LLM позволяют нам сделать очередной скачок в этой лестнице абстракции, перестать задуматься о таких вещах, как переменные, циклы, списки, классы и прочее, по аналогии с тем, как мы не задумываемся о машинном коде, когда пишем на петухоне - утверждает Андрей.
Но при этом игнорируются фундаментальные различия между предыдущими шагами развития ЯП и подходом, который предлагает Андрей. Я предлагаю поговорить об этих различиях.
* Отсутствие детерминизма в работе LLM. На один и тот же input ты можешь получить кучу ouputов. Соответственно, нельзя относиться к такому ЯП как к исходникам.
* Продукт "транспиляции" такого ЯП - другой существующий высокоуровневый ЯП (js, python и тд). Предполагается возможность "поправить" результат прям там, если что-то пойдет не так. Это уже сразу признак херовой абстракции. Если у тебя сейчас что-то не так с байткодом, ты не пойдешь править байткод. Ты пойдешь править компилятор.
* Отсутствие понимания процесса отладки в таком ЯП. Как это могло бы выглядеть хотя бы в теории не знает сам гость.
* Как вообще валидировать результат? Тесты написать? Так их же тоже нагенерят. Непонятно, куда в таком процессе человеку в целом воткнуться.
Это я по самым верхам прошелся. Тут еще и вопросы, связанные с развитием "артефактных" ЯП вроде js и python, как обучать llm новым версиям, если они станут не нужны. Также вопрос по скорости работы и цене такого решения. А что насчет безопасности🤷
Гость натягивает свою аналогию ровно так, как это нужно натягивать, чтоб получить первый раунд инвестиций (о чем прямо говорит). И это бесит. Потому что нет здесь никакого визионерства, нет теории, нет ответов на вопросы. Есть просто желание попилить бабки.
А я вот тоже хочу позаниматься визионерством!
Когда я только начинал работать, то были такие IDE, как Netbeans и Eclipse (олды тут?). Там был бэйсик автокомплит без каких-то особых возможностей форматирования, рефакторинга и прочего. А до этого, вообще люди в блокноте писали, код, где даже такого не было. Затем ворвались Jetbrains с Idea. Они подняли удобство написания кода на новый уровень. Статический анализ, рефакторинг крупных модулей, более качественный атокомплит - это все появилось там и эволюционировало с течением времени. И другие IDE тоже старались не отставать в этом. Короче говоря, за 15 лет индустрии процесс кодирования существенно изменился, его удобство повысилось на порядки.
Мне кажется, настало время кардинально улучшить наши IDE. LLM позволит вывести их на НОВЫЙ уровень!
Как вам идея? думаете стоит к инвесторам с ней пойти, чтоб сделать IDE БУДУЩЕГО, где LLM будет заниматься автокомлитом и рефакторингом? Это будет РЕВОЛЮЦИЯ по аналогии с той, что Jetbrains произвели в своей время.
А, стоп! так такие IDE уже есть! и блять наверное они есть, потому что это естественный процесс развития отрасли, а не надуманная херня под которую надо ходить на подкасты, чтоб ебалом посветить🤬
В заключении хотелось бы сказать, что аналогия может быть хороша для объяснения явления. Но никакой аналогии недостаточно для принятия решения☝️
✍3❤3👍2
Кстати про динамическую типизацию. Возникла тут задачка у меня одна. На вход приходит строка, которая может содержать int или float. Например, "4" или "3.14". И надо сконвертировать эту строку либо в int, либо во float соответственно. А пишу я код на php. И я че то забыл с этими питонами и (особенно) jsами, на сколько пхп хорош в своем приведении типов. Этот код
выдаст корректные
Если на вход придет неприводимая строка, то php выбросит TypeError, который можно поймать.
Обычно в коде я не использую strict_types, за что многие могут меня поругать. Поэтому код выше работает без проблем. Но на самом деле статический анализатор и так требует от меня соответствие типов, а там, где он выключен намеренно, приведение типов в php только радует. Но все же, что делать, если strict_types включен или анализатор ругается. Даже в этом случае php остается верен своим корням. Магический + 0 сделает свое дело.
"Но это же кринге!" скажете вы. А я прошепчу вам на ушко в ответ "Покажи писькуЭто строгая динамическая типизация, братик. А кринге - это тип number в js 🤡". И мы разойдемся так и не узнав, что в голэнг придется ввести структуру с 4мя полями, чтоб решить эту задачу🥲
<?php
$a = '4';
$b = '3.14';
function test(int|float $t): void {
var_dump($t);
}
test($a);
test($b);
выдаст корректные
int(4)
float(3.14)
Если на вход придет неприводимая строка, то php выбросит TypeError, который можно поймать.
Обычно в коде я не использую strict_types, за что многие могут меня поругать. Поэтому код выше работает без проблем. Но на самом деле статический анализатор и так требует от меня соответствие типов, а там, где он выключен намеренно, приведение типов в php только радует. Но все же, что делать, если strict_types включен или анализатор ругается. Даже в этом случае php остается верен своим корням. Магический + 0 сделает свое дело.
<?php
declare(strict_types=1);
$a = '4';
$b = '3.14';
function test(int|float $t): void {
var_dump($t);
}
test($a + 0);
test($b + 0);
"Но это же кринге!" скажете вы. А я прошепчу вам на ушко в ответ "
😁3❤2
Послушал тут подкаст с Егором Бугаенко. Много что мог бы сказать по этому поводу, и люди в комментах там активно это делают. Но вместо этого, я бы хотел зацепиться за один конкретный кейс, который привлек мое внимание прям сразу во время прослушивания. Его кстати даже не Егор ввел, а ведущий Кирилл.
Говоря про концепцию null в ЯП, и ее плохость, Кирилл предложил пример с объектом юзер, который нужен в куче мест в коде. И по его мнению, проверки типа if user === null появляются повсеместно, что сильно огорчает. Поэтому Кирилл предлагает всегда иметь инстанцированный объект user, и в случае если пользователь не аутентифицрован, это будет какой-то guest user с пустыми значениями.
И я тут че-то не совсем согласен с Кириллом. Хотя я знаю, что такая концепция с дефолтным юзером много где используется.
Поскольку на бэкенде все завязано на циклах запрос-ответ, то возможные варианты развития событий можно классифицировать по типам ендпоинтов
* ендпоинты с обязательной аутентификацией
* ендпоинты без аутентификации
* ендпоинты с опциональной аутентификацией
Не благодарите вашего капитана🤡
Первая группа ендпоинтов может даже не начинать выполнять логику, если пользователя нет. Поэтому, там не нужна проверка пользователя. Во второй группе у вас пользователь в принципе не должен фигурировать. И только в третьей группе ендпоинтов нужны подобные проверки. На моей практике таких ендпоинтов вообще немного. Поэтому и проблема будто бы не сильно существует🤷
Тем не менее, для 3й группы ендпоинтов мы обсуждаем 2 варианта, как действовать.
* Мы передаем default user и притворяемся, что у нас всегда "все хорошо"
* Мы передаем null, и тогда нам нужны проверки на null, которые так бесят Кирилла
И на эти два варианта я бы посмотрел не с точки "лучше-хуже", а с точки зрения цикломатической сложности и абстракции. Если у вас цикломатическая сложность вытарчивает прямо в ендпоинтском коде, т.е. у вас путь выполнения кардинально отличается в зависимости от того, аноним юзер или нет, то if-ов вам не избежать. И какая разница, будет это if user === null или if user.id === 0. Для читающего код, это примерно одинаковая когнитивная нагрузка.
Если же у вас цикломатическая сложность не видна сразу, то, кажется что default user - лучший вариант. Реально, избавляемся от чертовых if-ов прям тут. Ура! 🥳
Но в программировании ничего не бывает бесплатно. Так чем же мы платим тут? 🤔
А платим мы тут подтекающей, как старая жопа, абстракцией. Проблема в том, что авторизованный юзер и неавторизованный юзер в реальности не эквивалентны! Вот есть у вас метод public save(User user): void у репозитория. И как только вы завели в вашей системе дефолтного юзера, готовы ли вы поставить очко, что дефолтный юзер никогда не попадет в этот метод?
Обратите внимание, что это не про "злой null". Вместо null здесь мог бы быть тип AnonymousUser и юнион тип. Это просто очередной вопрос компромиссов, повсеместно встречающийся в разработке.
Че думаете? Как у вас с юзерами на проектах?
Говоря про концепцию null в ЯП, и ее плохость, Кирилл предложил пример с объектом юзер, который нужен в куче мест в коде. И по его мнению, проверки типа if user === null появляются повсеместно, что сильно огорчает. Поэтому Кирилл предлагает всегда иметь инстанцированный объект user, и в случае если пользователь не аутентифицрован, это будет какой-то guest user с пустыми значениями.
И я тут че-то не совсем согласен с Кириллом. Хотя я знаю, что такая концепция с дефолтным юзером много где используется.
Поскольку на бэкенде все завязано на циклах запрос-ответ, то возможные варианты развития событий можно классифицировать по типам ендпоинтов
* ендпоинты с обязательной аутентификацией
* ендпоинты без аутентификации
* ендпоинты с опциональной аутентификацией
Не благодарите вашего капитана🤡
Первая группа ендпоинтов может даже не начинать выполнять логику, если пользователя нет. Поэтому, там не нужна проверка пользователя. Во второй группе у вас пользователь в принципе не должен фигурировать. И только в третьей группе ендпоинтов нужны подобные проверки. На моей практике таких ендпоинтов вообще немного. Поэтому и проблема будто бы не сильно существует🤷
Тем не менее, для 3й группы ендпоинтов мы обсуждаем 2 варианта, как действовать.
* Мы передаем default user и притворяемся, что у нас всегда "все хорошо"
* Мы передаем null, и тогда нам нужны проверки на null, которые так бесят Кирилла
И на эти два варианта я бы посмотрел не с точки "лучше-хуже", а с точки зрения цикломатической сложности и абстракции. Если у вас цикломатическая сложность вытарчивает прямо в ендпоинтском коде, т.е. у вас путь выполнения кардинально отличается в зависимости от того, аноним юзер или нет, то if-ов вам не избежать. И какая разница, будет это if user === null или if user.id === 0. Для читающего код, это примерно одинаковая когнитивная нагрузка.
Если же у вас цикломатическая сложность не видна сразу, то, кажется что default user - лучший вариант. Реально, избавляемся от чертовых if-ов прям тут. Ура! 🥳
Но в программировании ничего не бывает бесплатно. Так чем же мы платим тут? 🤔
А платим мы тут подтекающей, как старая жопа, абстракцией. Проблема в том, что авторизованный юзер и неавторизованный юзер в реальности не эквивалентны! Вот есть у вас метод public save(User user): void у репозитория. И как только вы завели в вашей системе дефолтного юзера, готовы ли вы поставить очко, что дефолтный юзер никогда не попадет в этот метод?
Обратите внимание, что это не про "злой null". Вместо null здесь мог бы быть тип AnonymousUser и юнион тип. Это просто очередной вопрос компромиссов, повсеместно встречающийся в разработке.
Че думаете? Как у вас с юзерами на проектах?
❤3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
К недавнему посту о чтении доки)
😁5👍1🤣1
сук, я не хотел вообще этот пост писать. Наоборот, у меня контент по плану было кое-что позитивное. Но у меня щас просто разбомбило сракатан в пух и прах!😡
В чем же дело, спросите вы. Да, блять в том, как в python описываются типы в mypy. Постоянно какая-то хрень вылазиет из жопы, когда работаешь с ним.
Вот у меня есть generic класс
я хочу в него добавить метод, который будет возвращать новый инстанс этого класса по типу
Давайте поможем Даше найти, как расставить типы в объявлении метода!
ну что вы напишите в этом случае? ну наверное что-то типа
Обратите внимание, как же сука говяно описываются колаблы. Ну это ладно. Этот код впринципи некорректный!
А знаете какой код корректный? Вот такой
Задача: найти два отличия.
Ответ:левая кавычка и правая кавычка.
Причем, сука задаешь этот вопрос дипсику и perplexity, так он тебе старый способ объявления дженериков в ответ ставит, который еще более уебский с пежней типа
Я не знаю, че там с самой системой типов в питоне. Наверное там умные мужики все делали, и там все корректно и правильно. Но с точки зрения синтаксиса эти дядьки похоже класть хотели на принцип наименьшего удивления😤
Извинити, просто реал бомбануло
В чем же дело, спросите вы. Да, блять в том, как в python описываются типы в mypy. Постоянно какая-то хрень вылазиет из жопы, когда работаешь с ним.
Вот у меня есть generic класс
class Result[T]:
pass
я хочу в него добавить метод, который будет возвращать новый инстанс этого класса по типу
def transform(self, transformer):
data = transformer(self.__data)
return Result(data)
Давайте поможем Даше найти, как расставить типы в объявлении метода!
ну что вы напишите в этом случае? ну наверное что-то типа
def transform[V](self, transformer: Callable[[str], V]) -> Result[V]:
pass
Обратите внимание, как же сука говяно описываются колаблы. Ну это ладно. Этот код впринципи некорректный!
А знаете какой код корректный? Вот такой
def transform[V](self, transformer: Callable[[str], V]) -> "Result[V]":
pass
Задача: найти два отличия.
Ответ:
Причем, сука задаешь этот вопрос дипсику и perplexity, так он тебе старый способ объявления дженериков в ответ ставит, который еще более уебский с пежней типа
T = TypeVar('T')
class Result(Generic[T]):
pass
Я не знаю, че там с самой системой типов в питоне. Наверное там умные мужики все делали, и там все корректно и правильно. Но с точки зрения синтаксиса эти дядьки похоже класть хотели на принцип наименьшего удивления😤
Извинити, просто реал бомбануло
👍4😁4
Тут на меня навалилось всякое, и я что-то не нашел времени отметить знаменательное событие. Ведь на прошлой неделе самому умирающему языку программирования исполнилось 30 лет🥳 с днем рождения php!
Какой бы топ ЯП вы не взяли, php стабильно где-то в жепе! Наверное трудно найти какой-то другой язык, который хейтили бы больше, но который также активно использовался бы в продакшне. А между тем множество из хейтеров вкатывались в АЙТИ именно через php. Но ощущение такое, что php развивался, а хейтеры нет. Ведь за последнюю декаду в языке появилось столько всего, что удобство разработки и качество кода перешло на новый уровень. Перечислю список новых фич за последние 10 лет, которые, на мой взгляд, оказали наибольшее влияние на процесс разработки:
* строгая типизация в рантайме
* enums
* JIT компиляция
* атрибуты
* стрелочные функции
* first-class callable
* readonly свойства и классы, проперти хуки
* распаковка массивов, деструктурирующее присваивание (прям как в этом вашем js)
* файберы
И это я перечислил только то, что мне пришло на ум, и то, чем я пользуюсь. Там еще до хера всего. И вы можете сказать "но постой, это есть во всех других современных языках". Так в этом и соль, что php - это нормис. Это хороший современный язык! И он отлично справляется с работой, для которой он и создавался, а именно веб приложения. Его "умирающая" модель исполнения идеально подходит для веба, где большая часть взаимодействия построена по принципу request-response.
Кстати про умирающую модель. И здесь у пхп большие подвижки. На момент написания этого поста у пхп есть уже 2 продакшн реди решения (roadrunner и frankenphp), где используется воркерная модель, когда php процессы живут "вечно". А еще есть асинхронные библиотеки openswoole и reactphp. Так что даже в этом плане php такой же нормис.
Но вот что делает php очень крутым, так это тулинг и фреймворки. Что касается тулинга то тут у нас и статические анализаторы, и линтеры, и тулзы для рефакторинга. Казалось бы, в других языках это тоже все есть, но в пхп это все унифицированно (нету тысячи вариантов сделать одну и ту же задачу), работает быстро и очень хорошо поддерживается. Поверьте, разница с тем же питоном и жс есть, и она не в пользу последних.
Короче говоря за 10 лет php проделал огромный путь. У меня ощущение, что php 5 и php 8 это два разных языка - уж на столько их возможности отличаются. Будем надеяться, что следующая декада пройдет не менее активно. Нам тут уже обещают дженерики и async-await, но в целом, я был бы рад если бы в язык встроили дебаггер 🤡
Короче говоря, не умер и ладно!
Какой бы топ ЯП вы не взяли, php стабильно где-то в жепе! Наверное трудно найти какой-то другой язык, который хейтили бы больше, но который также активно использовался бы в продакшне. А между тем множество из хейтеров вкатывались в АЙТИ именно через php. Но ощущение такое, что php развивался, а хейтеры нет. Ведь за последнюю декаду в языке появилось столько всего, что удобство разработки и качество кода перешло на новый уровень. Перечислю список новых фич за последние 10 лет, которые, на мой взгляд, оказали наибольшее влияние на процесс разработки:
* строгая типизация в рантайме
* enums
* JIT компиляция
* атрибуты
* стрелочные функции
* first-class callable
* readonly свойства и классы, проперти хуки
* распаковка массивов, деструктурирующее присваивание (прям как в этом вашем js)
* файберы
И это я перечислил только то, что мне пришло на ум, и то, чем я пользуюсь. Там еще до хера всего. И вы можете сказать "но постой, это есть во всех других современных языках". Так в этом и соль, что php - это нормис. Это хороший современный язык! И он отлично справляется с работой, для которой он и создавался, а именно веб приложения. Его "умирающая" модель исполнения идеально подходит для веба, где большая часть взаимодействия построена по принципу request-response.
Кстати про умирающую модель. И здесь у пхп большие подвижки. На момент написания этого поста у пхп есть уже 2 продакшн реди решения (roadrunner и frankenphp), где используется воркерная модель, когда php процессы живут "вечно". А еще есть асинхронные библиотеки openswoole и reactphp. Так что даже в этом плане php такой же нормис.
Но вот что делает php очень крутым, так это тулинг и фреймворки. Что касается тулинга то тут у нас и статические анализаторы, и линтеры, и тулзы для рефакторинга. Казалось бы, в других языках это тоже все есть, но в пхп это все унифицированно (нету тысячи вариантов сделать одну и ту же задачу), работает быстро и очень хорошо поддерживается. Поверьте, разница с тем же питоном и жс есть, и она не в пользу последних.
Короче говоря за 10 лет php проделал огромный путь. У меня ощущение, что php 5 и php 8 это два разных языка - уж на столько их возможности отличаются. Будем надеяться, что следующая декада пройдет не менее активно. Нам тут уже обещают дженерики и async-await, но в целом, я был бы рад если бы в язык встроили дебаггер 🤡
Короче говоря, не умер и ладно!
🔥5❤3
немношк бомбанул очком 😤 https://www.youtube.com/shorts/wA2ToBLrl6o
вам задача: найти базированного челика в шортсе!
вам задача: найти базированного челика в шортсе!
YouTube
Стрёмно ли Писать Код на PHP в 2025 году? #ОлегКозырев #айти #программирование
С вами ОлегКозырев, здесь про рост в IT без выгорания и пафоса.👉 Лучшее закрытое сообщество для гоферов по самой доступной цене: https://t.me/olezhek28_cour...
😁4
Как не зайдешь в эти ваши интернеты, везде одни истории успеха😔Один навайбкодил стартап, другой выкатил обнову для своей библиотеки, третий на подкаст пришел и рассказал, какой он крутой. И никто сука не рассказывает о факапах и тупняках. Поэтому об этом буду рассказывать я😊
На работе делаем супер продвинутого ИИ помощника (на питоне, разумеется). Как истинный хороший программист, я решил внедрить статусное программирование (спасибо Кириллу Мокевнину с его докладами). Это означает, что сессия пользователя может находиться только в одном из доступных состояний. Например, есть состояние awaiting, когда помощник готов принимать запрос, или processing, когда происходит обработка запроса пользователя. Переходы между состояниями запрограммированы через finite state machine (fsm).
Однако в какой-то момент потребовалось научиться "ждать" определенного перехода между состояниями. Например, приходит запрос на создание новой сессии, но предыдущая сессия находится в состоянии summarizing, когда llm подгатавливает саммари по ней. И надо дождаться, когда состояние станет finished, прежде, чем продолжать операцию.
И вот трое нас, я, чатгпт и дипсик, родили совершенно потрясающее решение, основанное на Lockах и Eventах. Я даже тесты написал!🥳
И вдруг сижу и чувствую, что по штанам что-то течет. Ведь ничо тот факт, что у меня кубернетис и может быть хоть 10 реплик приложения с 10ю локами, которым по барабану друг на друга. Пришлось полностью выбросить это решение. Но хотя бы тесты остались.
И тут бы мне остановиться придумывать херню, ведь можно сделать классический поллинг - просто периодически долбить базу с запросом "ну че там, статус поменялся?". Но нет, случился очередной ступор мозговины. Ведь мне нужно КРАСИВОЕ решение.
И тут начинается полезная инфа для вас. Если вы работаете с postgres, то подобную задачу можно решить используя механизм LISTEN / NOTIFY. То есть в одной сессии подпиcываетесь на определенный ивент с помощью команды LISTEN event, а в другой сессии можно уведомить подписоту с помощью NOTIFY event. Еще payload можно передать. Ну круто же!
Но есть одна сложность. Допустим вы прочитали значение из бд, оно вам не понравилось, и вы хотите подождать другого. Если вы просто оформляете подписку после чтения, значение уже может измениться в этот момент. Это классическая гонка данных. Поэтому и listen, и notify важно делать в транзакциях с локами. В частности в транзакции, где у вас notify, нужно сделать select ... for update, а там, где listen должно быть select ... for share.
В итоге, такое решение работает. Но оно явно сложнее, чем если бы был простой поллинг. Да, у поллинга будет задержка. Но зато оно просто выглядит, меньше подвержено ошибкам и быстрее в реализации.
Вывод: не выпендривайтесь, делайте просто! 👆
Из бонусов, я кайфанул от того, что написал тесты, а затем полностью переписал реализацию, а тесты почти не трогал! Почти оргазм! 🥹
На работе делаем супер продвинутого ИИ помощника (на питоне, разумеется). Как истинный хороший программист, я решил внедрить статусное программирование (спасибо Кириллу Мокевнину с его докладами). Это означает, что сессия пользователя может находиться только в одном из доступных состояний. Например, есть состояние awaiting, когда помощник готов принимать запрос, или processing, когда происходит обработка запроса пользователя. Переходы между состояниями запрограммированы через finite state machine (fsm).
Однако в какой-то момент потребовалось научиться "ждать" определенного перехода между состояниями. Например, приходит запрос на создание новой сессии, но предыдущая сессия находится в состоянии summarizing, когда llm подгатавливает саммари по ней. И надо дождаться, когда состояние станет finished, прежде, чем продолжать операцию.
И вот трое нас, я, чатгпт и дипсик, родили совершенно потрясающее решение, основанное на Lockах и Eventах. Я даже тесты написал!🥳
И вдруг сижу и чувствую, что по штанам что-то течет. Ведь ничо тот факт, что у меня кубернетис и может быть хоть 10 реплик приложения с 10ю локами, которым по барабану друг на друга. Пришлось полностью выбросить это решение. Но хотя бы тесты остались.
И тут бы мне остановиться придумывать херню, ведь можно сделать классический поллинг - просто периодически долбить базу с запросом "ну че там, статус поменялся?". Но нет, случился очередной ступор мозговины. Ведь мне нужно КРАСИВОЕ решение.
И тут начинается полезная инфа для вас. Если вы работаете с postgres, то подобную задачу можно решить используя механизм LISTEN / NOTIFY. То есть в одной сессии подпиcываетесь на определенный ивент с помощью команды LISTEN event, а в другой сессии можно уведомить подписоту с помощью NOTIFY event. Еще payload можно передать. Ну круто же!
Но есть одна сложность. Допустим вы прочитали значение из бд, оно вам не понравилось, и вы хотите подождать другого. Если вы просто оформляете подписку после чтения, значение уже может измениться в этот момент. Это классическая гонка данных. Поэтому и listen, и notify важно делать в транзакциях с локами. В частности в транзакции, где у вас notify, нужно сделать select ... for update, а там, где listen должно быть select ... for share.
В итоге, такое решение работает. Но оно явно сложнее, чем если бы был простой поллинг. Да, у поллинга будет задержка. Но зато оно просто выглядит, меньше подвержено ошибкам и быстрее в реализации.
Вывод: не выпендривайтесь, делайте просто! 👆
Из бонусов, я кайфанул от того, что написал тесты, а затем полностью переписал реализацию, а тесты почти не трогал! Почти оргазм! 🥹
💅7
Штош, шутки шутками, но настало время более серьезно поговорить про вайбкодинг, а точнее, про влияние вайбкодинга на разработчика. Так получилось, что сам я не выйбкодю. И далее по тексту вы увидите мои оправдашки, почему так.
В качестве поддержки своего мнения, я бы хотел обратиться к офигенной статье Why I stopped using AI code editors. На момент написания поста оригинал статьи почему-то недоступен, но есть копия в вебархиве. Я советую прочитать, очень отрезвляюще. Особенно прикольна аналогия с теслой, когда долгое использование автопилота привело к деградации навыка вождения у автора.
Почему же я не вайбкодю? Я отвечаю себе на этот вопрос так: прекращение работы над простыми вещами делает сложные вещи еще сложнее. В статье об этом говорится в части про Fingerspitzengefühl.
Приведу свою налогию. Какое-то время назад я занимался единоборствами. Одним из ключевых упражнений в тренировках было бить по мешку один и тот же удар определенное количество раз. Ну например, надо 100 раз ударить прямым ударом руки по мешку. Затем поменять руку и стойку и также 100 раз ударить. Потом тоже самое с другими видами ударов руками и ногами. Скучно кабзда! Но мне кажется, мало кто сомневается в полезности таких упражнений. Тренер всегда объяснял нам, зачем это делать. Нужно довести наши удары до автоматизма в "тепличных" условиях. В спаринге не будет таких условий. В спаринге часто оказываешься в неудобной позиции, тебя бьют, ты устаешь. Но ключ к победе в том, чтоб "прошел" один единственный удар, который ты наносишь, находясь в супер неудобных условиях. Вот для этого ты и долбишь часами один и тот же удар. И даже самые опытные бойцы продолжают бить эти самые удары и связки ударов. Потому что это важно.
Теперь представьте, что у вас появляется ИИ в тренировке. И он добавляет "множитель" к вашим ударам. Например, множитель 5: теперь вместо 100 ударов, надо сделать всего 20. Формально ты выполнишь тренировку, нанеся всего 20 ударов. Сделает ли это твою жизнь проще? Конечно сделает! Но в спарринге, человек, который честно набил 100 ударов будет иметь преимущество. У него и удары техничнее, и руки "набиты" лучше.
Любая аналогия ложна, в том числе и эта. Все таки тренировка не работа разработчиком, а спаринг не построение архитектуры ПО. Но я все равно считаю, что каким бы ремеслом ты не занимался (а программирование - это ремесло), важно продолжать делать "простые" вещи, если хочешь оставаться в этом ремесле и не терять квалификацию. При этом эти самые простые вещи можно делать с помощью современного инструментария: крутой IDE, фреймворка или даже ИИ. Но главное, делать.
Проблема вайбкодинга в том, что он отобирает возможность делать простые вещи. Это особенно черевато для джунов и тех, кто только хочет вкатиться в IT. Обманчивая иллюзия скорости и эффективности, которая по итогу приводит к отсуствию навыка у джунов и потере навыка у более опытных разработчиков. Кроме того, согласно недавнему исследованию Microsoft, само по себе использование ИИ оказывает негативное влияние на способность человека мыслить критически и к чрезмерной зависимости от этого самого ИИ.
Я непротив использования ИИ в целом. Я считаю, что ИИ пришел всерьез и надого, и сам активно использую его в работе. Оно очень помогает погрузиться в какую-то тему максимально быстро, получить ответ на вопрос, накинуть множество вариантов решения для выбора, объяснить что-то. Глупо спорить, что с ИИ продуктивность разработчиков сильно выросла по сравнению с традицонным гуглом + стэковефлоу.
Но на мой взгляд, вайбкодинг - это когда ИИ переступает уже черту крутого инструмента, забирая локус контроля у разработчика. Сам я боюсь потери навыка. Поэтому пока без него.
В завершении отмечу, что я тут не говорю о влиянии на бизнес, о корректности работы самого ИИ, о влиянии ИИ на код и индустрию. Я думаю, никто не сможет сказать, как это будет через год, два или пять лет. Но в одном я уверен: пока ИИ оперирует обычными ЯП, пока валидация решения остается на уровне обычного кода, никуда программистские навыки не денутся, кто бы там что не говорил.
В качестве поддержки своего мнения, я бы хотел обратиться к офигенной статье Why I stopped using AI code editors. На момент написания поста оригинал статьи почему-то недоступен, но есть копия в вебархиве. Я советую прочитать, очень отрезвляюще. Особенно прикольна аналогия с теслой, когда долгое использование автопилота привело к деградации навыка вождения у автора.
Почему же я не вайбкодю? Я отвечаю себе на этот вопрос так: прекращение работы над простыми вещами делает сложные вещи еще сложнее. В статье об этом говорится в части про Fingerspitzengefühl.
Приведу свою налогию. Какое-то время назад я занимался единоборствами. Одним из ключевых упражнений в тренировках было бить по мешку один и тот же удар определенное количество раз. Ну например, надо 100 раз ударить прямым ударом руки по мешку. Затем поменять руку и стойку и также 100 раз ударить. Потом тоже самое с другими видами ударов руками и ногами. Скучно кабзда! Но мне кажется, мало кто сомневается в полезности таких упражнений. Тренер всегда объяснял нам, зачем это делать. Нужно довести наши удары до автоматизма в "тепличных" условиях. В спаринге не будет таких условий. В спаринге часто оказываешься в неудобной позиции, тебя бьют, ты устаешь. Но ключ к победе в том, чтоб "прошел" один единственный удар, который ты наносишь, находясь в супер неудобных условиях. Вот для этого ты и долбишь часами один и тот же удар. И даже самые опытные бойцы продолжают бить эти самые удары и связки ударов. Потому что это важно.
Теперь представьте, что у вас появляется ИИ в тренировке. И он добавляет "множитель" к вашим ударам. Например, множитель 5: теперь вместо 100 ударов, надо сделать всего 20. Формально ты выполнишь тренировку, нанеся всего 20 ударов. Сделает ли это твою жизнь проще? Конечно сделает! Но в спарринге, человек, который честно набил 100 ударов будет иметь преимущество. У него и удары техничнее, и руки "набиты" лучше.
Любая аналогия ложна, в том числе и эта. Все таки тренировка не работа разработчиком, а спаринг не построение архитектуры ПО. Но я все равно считаю, что каким бы ремеслом ты не занимался (а программирование - это ремесло), важно продолжать делать "простые" вещи, если хочешь оставаться в этом ремесле и не терять квалификацию. При этом эти самые простые вещи можно делать с помощью современного инструментария: крутой IDE, фреймворка или даже ИИ. Но главное, делать.
Проблема вайбкодинга в том, что он отобирает возможность делать простые вещи. Это особенно черевато для джунов и тех, кто только хочет вкатиться в IT. Обманчивая иллюзия скорости и эффективности, которая по итогу приводит к отсуствию навыка у джунов и потере навыка у более опытных разработчиков. Кроме того, согласно недавнему исследованию Microsoft, само по себе использование ИИ оказывает негативное влияние на способность человека мыслить критически и к чрезмерной зависимости от этого самого ИИ.
Я непротив использования ИИ в целом. Я считаю, что ИИ пришел всерьез и надого, и сам активно использую его в работе. Оно очень помогает погрузиться в какую-то тему максимально быстро, получить ответ на вопрос, накинуть множество вариантов решения для выбора, объяснить что-то. Глупо спорить, что с ИИ продуктивность разработчиков сильно выросла по сравнению с традицонным гуглом + стэковефлоу.
Но на мой взгляд, вайбкодинг - это когда ИИ переступает уже черту крутого инструмента, забирая локус контроля у разработчика. Сам я боюсь потери навыка. Поэтому пока без него.
В завершении отмечу, что я тут не говорю о влиянии на бизнес, о корректности работы самого ИИ, о влиянии ИИ на код и индустрию. Я думаю, никто не сможет сказать, как это будет через год, два или пять лет. Но в одном я уверен: пока ИИ оперирует обычными ЯП, пока валидация решения остается на уровне обычного кода, никуда программистские навыки не денутся, кто бы там что не говорил.
web.archive.org
Why I stopped using AI code editors ·
Luciano Nooijen
Luciano Nooijen
In the past I used AI code editors for all of my programming, but I stopped using it and recommend others to consider this as well
❤5🔥4👍1
Корочи, на работе продолжаем пилить жесткую тему связанную с ИИ🤖Для этого у нас в команде есть специально обученный (нет) человек, чтоб заниматься непотребствами с llm и всячески их тюнить. Ибо тема эта новая, и, кажется, человечество создало нечто такое, в чем само поитогу разобраться не может. Требуются бесконечные эксперименты с промптами и всякими агентами.
Разумеется, то тут, то там, начали вылезать фреймворки для разработки "expressive, customizable agent workflows". Суть их в том, чтоб ускорить накидывание говна в llm, в надежде получить че-то хорошее на выходе. По сути - ускорить обратную связь. Одним из таких фреймворков является набирающий популярность сейчас langgraph. Решили попробовать часть функционала переписать с помощью него. Потому что на бумаге все звучит очень круто🤩
Основная идея, на которой построен langgraph - представление логики обработки запроса пользователя в виде графа. В этом графе каждый узел - это какая-то функция, которая может сходить в llm или вызвать локальный инструмент (tool) или запросить помощь от пользователя. Можно определить условия перехода в тот или иной узел. А еще langgraph позволяет работать с состоянием. Каждая нода ведет себя каксучька редьюсер в react redux - принимает на вход старое состояние и возвращает новое. Ну не красота ли!
Но по факту опыт получился смешанный. Потому что нахуевертили!
Если вы начнете погружаться в langgraph, то обнаружите, что там довольно много документации. Ситуация осложняется еще и тем, что разработчики предоставили миллиард способов сделать одну и ту же херню. Да там даже 2 разных независимых API существует зачем-то! Короче, готовьтесь пару дней тратить только на чтение буков🤓
Ну это ладно. Самая большая проблема для нас оказалась в персистентности. Ведь логично предположить, что агент, который забывает предыдущий ответ пользователя - это как дед с деменцией - вроде парень неплохой, только ссытся и глухой. Поэтому разработчики добавили "память" в langgraph. Но сделали это через жепу.
Вам предлагается модель чекпоинтеров, когда переход через каждый узел сохраняется в хранилище. Поэтому всегда можно восстановить состояние и продолжить.
Проблема в том, что я могу НЕ хотеть сохранять промежуточный мусор пока запрос не выполнился полностью. Потому что если на середине пути у меня вывалилась ошибка, то я хочу просто начать сначала без предыдущих потуг. И langgraph не особо дает это сделать. Более того, разработчики, видимо поняв, что идея с чекпоинтерами не слишком гибкая, добавили еще один вид памяти long term. И это какая то невнятная дичь. Вдовесок ко всему, модель хранения langgraph по сути скрыта. Например, захотите вы проанализировать транскрипт пользователя - ну удачи вам.
В итоге, мы решили использовать langgraph только как способ организовать код в виде графа. Это реально облегчило прототипирование, поскольку позволило отвязать весь наш остальной код от логики работы агента. Мы сами храним и состояние, и транскрипт, и общую память о пользователе, а в langgraph бегаем просто как в black box. На вход ему подаем наши загруженные данные + запрос пользователя. После обработки запроса графом, мы используем результат для обновления состояний, метрик, транскрипта и т.п.
Я считаю, что в этом и состоялась основная польза от использования langgraph. Именно отделение кода логики агента от остального кода - основная ценность. Поскольку этими двумя частями заведуют разные люди в команде.
А сам по себе langgraph на 5.5 из 10. Много что есть сразу, но не гибко, сложно, потно!😰Будем надеяться, что это просто первые попытки человечества создать фреймворк под написание агентов, и дальше будет лучше.
Разумеется, то тут, то там, начали вылезать фреймворки для разработки "expressive, customizable agent workflows". Суть их в том, чтоб ускорить накидывание говна в llm, в надежде получить че-то хорошее на выходе. По сути - ускорить обратную связь. Одним из таких фреймворков является набирающий популярность сейчас langgraph. Решили попробовать часть функционала переписать с помощью него. Потому что на бумаге все звучит очень круто🤩
Основная идея, на которой построен langgraph - представление логики обработки запроса пользователя в виде графа. В этом графе каждый узел - это какая-то функция, которая может сходить в llm или вызвать локальный инструмент (tool) или запросить помощь от пользователя. Можно определить условия перехода в тот или иной узел. А еще langgraph позволяет работать с состоянием. Каждая нода ведет себя как
Но по факту опыт получился смешанный. Потому что нахуевертили!
Если вы начнете погружаться в langgraph, то обнаружите, что там довольно много документации. Ситуация осложняется еще и тем, что разработчики предоставили миллиард способов сделать одну и ту же херню. Да там даже 2 разных независимых API существует зачем-то! Короче, готовьтесь пару дней тратить только на чтение буков🤓
Ну это ладно. Самая большая проблема для нас оказалась в персистентности. Ведь логично предположить, что агент, который забывает предыдущий ответ пользователя - это как дед с деменцией - вроде парень неплохой, только ссытся и глухой. Поэтому разработчики добавили "память" в langgraph. Но сделали это через жепу.
Вам предлагается модель чекпоинтеров, когда переход через каждый узел сохраняется в хранилище. Поэтому всегда можно восстановить состояние и продолжить.
Проблема в том, что я могу НЕ хотеть сохранять промежуточный мусор пока запрос не выполнился полностью. Потому что если на середине пути у меня вывалилась ошибка, то я хочу просто начать сначала без предыдущих потуг. И langgraph не особо дает это сделать. Более того, разработчики, видимо поняв, что идея с чекпоинтерами не слишком гибкая, добавили еще один вид памяти long term. И это какая то невнятная дичь. Вдовесок ко всему, модель хранения langgraph по сути скрыта. Например, захотите вы проанализировать транскрипт пользователя - ну удачи вам.
В итоге, мы решили использовать langgraph только как способ организовать код в виде графа. Это реально облегчило прототипирование, поскольку позволило отвязать весь наш остальной код от логики работы агента. Мы сами храним и состояние, и транскрипт, и общую память о пользователе, а в langgraph бегаем просто как в black box. На вход ему подаем наши загруженные данные + запрос пользователя. После обработки запроса графом, мы используем результат для обновления состояний, метрик, транскрипта и т.п.
Я считаю, что в этом и состоялась основная польза от использования langgraph. Именно отделение кода логики агента от остального кода - основная ценность. Поскольку этими двумя частями заведуют разные люди в команде.
А сам по себе langgraph на 5.5 из 10. Много что есть сразу, но не гибко, сложно, потно!😰Будем надеяться, что это просто первые попытки человечества создать фреймворк под написание агентов, и дальше будет лучше.
langchain-ai.github.io
Overview
Build reliable, stateful AI systems, without giving up control
❤5👍2
В прошлый раз рассказывал про langgraph. а сегодня расскажу о том, почему у меня сгорела дыра из-за него🌚
Дело в том, что langgraph пытается казаться на столько удобным решением, что они даже запилили собственную IDE, и назвали ее langgraph studio (далее lgs). Очень блять оригинально.
Как же выглядит IDE для разработки агентов? Нужно ли там писать код? Можно ли там вайбкодить с помощью агента, которого сам же пишешь? 🤔 Все эти вопросы сразу остро встают на повестке дня.
Но все гораздо прозаичнее (см. картинку). Эта присрачка позволяет запускать каждый узел в графе (функцию) отдельно, мейнтейнить стейт, менять входные параметры. Короче говоря, позволяет всячески эксперементировать с узлами без необходимости работать с полным циклом запрос-ответ. Удобно? Не то слово! Идея просто бомбическая.
Разумеется, наш специально обученный человек сразу захотел lgs использовать. И тут его трудно осуждать.
Сначала все было хорошо. Сплошные востороженные возгласы. Но внезапно мне прилетает тревожное сообщение "В lgs не работает подключение к бд"😱
Начал разбираться в проблеме. Как вы можете помнить, коннекшн к бд я храню в contextvars. Подробнее об этом я писал тут. Когда lgs запускает отдельно ноду, то contextvars пустые. Поэтому и подключения нет. Надо как-то подключиться к бд и положить коннекшн в переменную перед запуском каждой ноды. Изи!
И вот тут меня настигло абсолютное разочарование. Потому что никакого способа это сделать разработчики не предоставили. Ни хуков, ни api для плагинов, вообще ни-ху-я. Просто нет возможности выполнить код в этой IDE помимо кода узла😔
ТО ЕСТЬ, разрабы lgs дали способ работать с каждым узлом изолированно от всего остального кода, но не подумали, что может потребоваться ЧТО-ТО от этого остального кода. Гении ебать!
В общем ключе задача формулируется так: "У библиотеки или тулзы отсутствует нужный api для взаимодействия, а вам позарез надо вмешаться в ее модель выполнения". Звучит конечно так себе. Поэтому добавим "...для разработки или тестирования"😏
Это был пост-затравка. В следующем посте я расскажу, как решал эту проблему в python. Но подобный метод может применяться практически в любых интерпретируемых ЯП. В комментах пишите, как бы вы решали подобную проблему👇
Дело в том, что langgraph пытается казаться на столько удобным решением, что они даже запилили собственную IDE, и назвали ее langgraph studio (далее lgs). Очень блять оригинально.
Как же выглядит IDE для разработки агентов? Нужно ли там писать код? Можно ли там вайбкодить с помощью агента, которого сам же пишешь? 🤔 Все эти вопросы сразу остро встают на повестке дня.
Но все гораздо прозаичнее (см. картинку). Эта присрачка позволяет запускать каждый узел в графе (функцию) отдельно, мейнтейнить стейт, менять входные параметры. Короче говоря, позволяет всячески эксперементировать с узлами без необходимости работать с полным циклом запрос-ответ. Удобно? Не то слово! Идея просто бомбическая.
Разумеется, наш специально обученный человек сразу захотел lgs использовать. И тут его трудно осуждать.
Сначала все было хорошо. Сплошные востороженные возгласы. Но внезапно мне прилетает тревожное сообщение "В lgs не работает подключение к бд"😱
Начал разбираться в проблеме. Как вы можете помнить, коннекшн к бд я храню в contextvars. Подробнее об этом я писал тут. Когда lgs запускает отдельно ноду, то contextvars пустые. Поэтому и подключения нет. Надо как-то подключиться к бд и положить коннекшн в переменную перед запуском каждой ноды. Изи!
И вот тут меня настигло абсолютное разочарование. Потому что никакого способа это сделать разработчики не предоставили. Ни хуков, ни api для плагинов, вообще ни-ху-я. Просто нет возможности выполнить код в этой IDE помимо кода узла😔
ТО ЕСТЬ, разрабы lgs дали способ работать с каждым узлом изолированно от всего остального кода, но не подумали, что может потребоваться ЧТО-ТО от этого остального кода. Гении ебать!
В общем ключе задача формулируется так: "У библиотеки или тулзы отсутствует нужный api для взаимодействия, а вам позарез надо вмешаться в ее модель выполнения". Звучит конечно так себе. Поэтому добавим "...для разработки или тестирования"😏
Это был пост-затравка. В следующем посте я расскажу, как решал эту проблему в python. Но подобный метод может применяться практически в любых интерпретируемых ЯП. В комментах пишите, как бы вы решали подобную проблему👇
❤5