Нервный программист
174 subscribers
99 photos
3 videos
1 file
56 links
Эмоционально об айти и программировании
Download Telegram
Давно у меня не горело сзади, но седня я просто кричал криком в монитор! 😡

Все дело в doctrine orm и в ебучих таймзонах.

Я самый несчастный человек на земле, когда дело касается базы данных. Потому что у нас на проекте до сих пор mysql - основная бд 😔 Фан факт про mysql - долгое время эта СУБД не позволяла хранить таймзоны в полях с датами. Ситуация изменилась только в 2020м с версией 8.0.19. Там добавили возможность хранить смещение в поле с датой.

Но суть даже не в этом. Открываем доку доктрины по типам. Там мы можем увидеть следующие типы, касательно времени: datetime, datetime_immutable, datetimetz, datetimetz_immutable. Впринципи любой более менее программистский человек по названию может догадаться, о чем каждый из этих типов.

У меня пользователи в разных таймзонах, и важно точное время события. Поэтому таймзоны я не могу отбросить, и я должен использовать datetimetz. Ведь в описании написано

> Maps and converts date with time and timezone information data. If you know that the data to be stored always contains date, time and timezone information, you should consider using this type.

О боже, это же мой сценарий!

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

Также под типом datetimetz можно увидеть предупреждение о том, что не все СУБД поддерживают хранения таймзон, поэтому результат чтения может не совпадать с записью. Типа вставили 1986-22-03 19:45:30-03:00, а прочитали 1986-22-03 22:45:30-00:00. В целом это понятно, и мне ок!

Каково же было мое удивление, когда я обнаружил, что доктрина просто на похуй отбрасывает таймзону и сохраняет значение как есть! То есть, сохраняю я например текущую дату 2026-05-18 10:40:50 в таймзоне America/Toronto. В бд я вижу значение 2026-05-18 10:40:50. Без таймзоны. Загружаю сущность после

date_default_timezone_set('Europe/Moscow');

получаю ту же самую дату в москве. Просто херак и проебал 7 часов на ровном месте.

По факту datetimetz не хэндлит таймзоны! Меняю тип на datetime - поведение не отличается! И в коде все одинаково для обоих типов. Ну пиздейшн конечно!

И я сижу такой обосравшийся и не понимаю, почему мои ожидания, что тип datetimetz конвертнет дату в utc перед сохранением и из utc при загрузке, оказались на столько завышенными. И нахуя этот тип тогда нужен! И почему в mysql уже 6 лет как поддерживаются таймзоны, а доктрина их не сохраняет!

Не ну это не самое прикольное. Самое прикольное, как раз то, что есть страница в доке Working with DateTime Instances, где и описывается подход с конвертацией в/из utc при сохранении/загрузке. И говорится, что это тру вей (с чем трудно спорить). В качестве решения предлагается мне самому написать кастомный тип, который это бы делал🤡 и даже код этого типа предоставили, чтоб я скопипастил.

Но почему не включить этот тип по умолчанию в доктрину!!! Почему написать о подходе в доке, предоставить код для копипасты - это тру вей! 😡

Эх, столько "почему" сегодня. Я устал😔
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7💔5😁2❤1
Отличная идея! И другая ллмка отрисует экран чисто по наитию форме ответа👍 А пользователь пойдет нахер
😁9❤2🤡1
удар в псину 🐶 от вардампа!

вардамп был выбран для hell2shape, потому что он
* есть у всех
* провайдит типы

И, казалось бы, все хорошо.

Но я не знаю, как так получилось, но мы с клодом пропустили капец важный корнер кейс. аж стыдно!😢

дело в том, что вардамп не экранирует двойные кавычки. и получается как-то так.


$v = ['k' => 'v"v'];
var_dump($v);



array(1) {
["k"]=>
string(3) "v"v"
}


ну и как бы все! лексер сломан! идея о том, что мы одной регуляркой распарсим все на токены сразу идет в очко.

И если щас кто-то скажет "да ты просто не умеешь готовить регулярки" (что в целом правда), то как вам такое


$a = [
'govno' => 'жопа"
["лох"]=>
string(8) "тигр',
];
$b = ['govno' => 'жопа', 'лох' => 'тигр'];
var_dump($a, $b);



array(1) {
["govno"]=>
string(46) "жопа"
["лох"]=>
string(8) "тигр"
}
array(2) {
["govno"]=>
string(8) "жопа"
["лох"]=>
string(8) "тигр"
}


разница только в цифрах в скобочках. и получается, что надо по-хорошему добавлять препроцессор, и только потом уже в лексер все это пихать😔

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

пока закинул фикс с positive lookahead на пустую строку после кавычки. ну теперь лексер ломается только если кавычка с переносом строки.

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

С другой стороны, может быть, если бы я об этом кейсе знал, я бы до сих пор ничо не выпустил😂
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8❤1🐳1
о! кстати, а знаете, еще в чем показательность этого кейса. я ж поделился со своим напраником, клодом, нашим фиаско. говорю, мол, так и так, двойные кавычки сгубили.

И клод мне как давай накидывать решения! какие-то страшные регулярки подсовывать со словами "вот это точно все зафиксит! нет? а может вот эта регулярка? ща-ща, еще че нить придумаю"

так и не смог пацан смириться, что задача не решается регулярками😔

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

так шо, кожанные, мы все еще нужны иногда!
❤4🔥3😁2
Это как java и javascript, да?

P.S. Сравнение с pornhub было бы более корректным, если бы там можно было принимать PR (porn request)
😁12🍓1
Сегодня немного пололировал с поста на реддите, где до чувака на собесе по golang докопались с вопросом о том, как реализовать перегрузку методов. Вот уж реально, когда на собесах не знают, как бы изъебнуться, чтоб... а я даже не знаю, чтобы что 🤷хуже только вопрос, почему канализационные люки круглые.

Но меня это навело на определенные мысли. Когда-то давно я начинал свой путь в айти с книги Брюса Эккеля про java. И я прям помню, как там много говорили про перегрузку методов, и как это круто. Ну я тогда ваще ничо не понимал в погромировании. Даже меньше, чем щас 😱 раз сказали, что это круто, значит круто. а. ну мы еще лабы на плюсах писали в универе с перегрузкой операторов.

С джавой у меня так и не задалось. Но код писать продолжил. И все это время писал на ЯП, которые не поддерживают перегрузку. А это кстати все популярные скриптовые языки. И даже не скриптовые (типа go, rust).

И вот щас будет наброс. Че то я не особо ощущаю какой-то дискомфорт от отсутствия перегрузки в бизнес коде. Мне кажется, это вообще самая переоцененная фича в ЯП.

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

С точки зрения типов, перегрузка это так называемы ad-hoc полиморфизм: конкретная реализация выбирается в зависимости от типов. И кажется, что это збс. Но по факту, хуйня. Ну используем мы одно и тоже слово в названии метода, и чо. Сэкономили на записи. Как это читать потом? Поди потом разберись, какая реализация тут отработала.

В языках без перегрузки у нас параметрический полимфорфизм, т.е. мы принимаем пачку типов на вход, на выходе также пачка типов, а реализация уже там разбирается, чо к чему. На первый взгляд кажется, что такой подход это больший пиздейшн. Но у нас же есть тулинг. Например, typescript поддерживает перегрузку функций. В phpstan есть conditional types. Да даже в ебучем mypy есть такое. И в целом, будто это норм. Когда читаем код, всегда прыгаем в конкретную реализацию. Хочешь другую реализацию для конктреного типа, ну напиши отдельный метод. Не еби мозги себе и другим 😡

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

Но может собеседующий прав, и долбаеб я? Может реально все мечтают о перегрузке?🤔 вы скажите, кароч
👍8❤2
Приношу заранее извинения за пост о ллм. Сам от этого устал🫠но разок-то можно🙏

По моим ощущениям, большиство разработчиков используют агентов в TUI. Потому что почти каждый из них предоставляет TUI версию. И это типа универсально. Я же продал очко душу ide от jetbrains, поэтому сразу искал решение - плагин. Поэтому когда-то давно я выбрал cline, ибо у них был адекватный плагин.

И таким образом, я выбрал DX, который трудно найти, легко потерять и довольно тяжело повторить.

3го дня все ide от jetbrains обновились на мажорную версию. Из-за этого cline плагин перестал работать. И тут я понял, что время TUI версии пришло. И охерел от того, что там все не то и не так.

Прежде всего стоит отметить, что я использую ллм в режиме "ты конечно генерируй, но я блэт все чекаю". Потому что я тот еще контрол фрик. В ide это видно как diff после каждого изменения. Пока я не заапрувлю diff, дальше ничо не двигается. Обычно изменения ллм делает разумными чанками, и это все реально просмотреть (ну кроме тестов, там пиздейшн портянка обычно).

Есть ли что-то похожее в Cline TUI? вообще нет! все, что там можно сделать - это поставить аппрув на каждый tool call. но это просто ужас как заебывает. Потому что, сюрприз-сюрприз, под капотом агент делает десятки таких вызовов даже для простых задач. И, главное, он не показывает дифф🤷короче это вообще не то. в TUI ты должен просто проверять в конце все.

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

Другой момент, заключается в том, что плагин "видит" все ошибки ide. То есть фактически он использует стат анализатор, который уже есть в ide (а он то крутой). TUI агенты обычно предлагают еще lsp прикрутить рядом. В целом можно, но зачем? В ide у меня не только стат анализ для основного языка, но и для всего сопутствующего. Например, если ide показывает ошибку в sql, агент это видит. По непродтвержденной информации, даже ошибки quality tools, которые отдельно запускаются, видны.

Короче, мне по кайфу!😊

А в чем же минусы? чем приходится платить?

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

К сожалению похожих решений с другими плагинами я не нашел. Попробовал kilocode - ну это просто ужас. Он тупо виснет посреди простого таска. Навайбколили там нормально.

TUI open code что-то близкое позволил сделать. Там можно настроить пермишны на ask при каждом редактировании файла и видеть диффы. Но конечно же ни о каком редактировании речи нет. Ты можешь словами рассказать, че тебе не понравилось. И да, надо подрубать lsp, если хочешь больше гарантий по качеству кода (хотя в работе не проверял). Но хоть что-то похожее на альтернативу.

Пока что откатил версию IDE до предыдущей 🤷 но если cline перестанут поддерживать плагин, будет беда
❤1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍4
Никак не можете найти в себе силы поменять работу? Просто выполните этот sql запрос, и за вами скоро придут
😁12
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Вчера прилетел код на ревью от фронтенда. А там цепочки вложенных тернарников. Кучи их🫠 И я поймал себя на мысли, что эти цепочки мне капец как тяжело воспринимать. Я прям все мыслетопливо на них сжег и устал.

Вот сравните

это

const buttonText =
action === 'manage' && selectedProductId === purchasedPlan?.subscriptionProduct
? strings.manage_button
: action === 'downgrade'
? strings.downgrade_button
: strings.upgrade_button;


или это

let buttonText;

if (action === 'manage' && selectedProductId === purchasedPlan?.subscriptionProduct) {
buttonText = strings.manage_button;
} else if (action === 'downgrade') {
buttonText = strings.downgrade_button;
} else {
buttonText = strings.upgrade_button; }


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

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

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

Кроме того, цепочки тернарников работают по разному в разных ЯП. И если в js цепочки правоассоциативные (если условие false, то весь хвост - это новое выражение), то в той же пыхе до версии 8 они были левоассоциативные. А щас так вообще вложенные тернарники без скобок запрещены. Может быть это меня и травмировало🤔

А в питоне смарите какая красота 😀

score = 85

grade = "A" if score >= 90 else "B" if score >= 80 else "C"
print(grade) # Хуй знает че тут будет


че думаете? лучше старый проверенный if - else или тернарники зато const?
😁2❤1
Please open Telegram to view this post
VIEW IN TELEGRAM
Кароче, в комментах пришли к выводу, что я лох, и надо было добавить switch - case в опросник, ибо это единственный норм варик (с чем не поспорить). Но что ж фронтендщики вообще его не используют?🤔

(получается, что в итоге лох не я, а фронтендщики)
🤣10
Внатуре
😁12😱3
Я тут путешествую. Вчера заехал в Воронеж, и, кажется, нашел там место, где пыхарей приводят в порядок🤩 ну либо это замаскированный офис @sergei_predvoditelev. Других вариков нет.
😁21❤5🤣4😍2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14🔥4🤡2❤1🤯1
Не вижу ничего смешного. Он предложил создавать PRы с помощью AI. Но он не обещал, что будет их мержить.
🤣9👍3