Я рад сообщить, что решил часть своего контента вынести за пределы телеги. Поэтому завел свой микробложик https://nervprog.dev (да-да, я зарегал домен 😊), и планирую туда писать миддл и лонг риды. Причина проста - телега не очень подходит для длинных постов, да еще и с кодом. Посмотрим, как оно пойдет (и пойдет ли).
В планах - прикрутить RSS и делать варианты статей на английском с помощью чатгпт. Пока что написал небольшую пробную статейку Как правильно подключиться к базе данных в Fastapi. Статья будто бы для питонистов, но на самом деле, она больше проглобальные переменные поиск подходов. Напишите в комментах, стоит или нет такое пытаться на medium.com / dev.to / vc.ru публиковать или надо че-то посерьезнее?
P.S. Стоит зайти хотя бы раз, чтоб оценить, какой классный дизайн я выбрал 🤩
В планах - прикрутить RSS и делать варианты статей на английском с помощью чатгпт. Пока что написал небольшую пробную статейку Как правильно подключиться к базе данных в Fastapi. Статья будто бы для питонистов, но на самом деле, она больше про
P.S. Стоит зайти хотя бы раз, чтоб оценить, какой классный дизайн я выбрал 🤩
🔥8🍾2❤1🗿1
Обработка ошибок в языках программирования - это вопрос дискусионный. Какого-то консенсуса, как делать правильно, здесь нет по сей день. Где-то язык не предоставляет никаких механизмов для решения этой задачи, отдавая этот вопрос полностью на откуп программистам (привет Си), где-то ошибки - это почти обычные значения, которые возвращаются вместе с результатом выполнения функции (привет golang). Однако наибольшее распространение получил механизм исключений, представленный в таких языках как java, c#, javascript, php и др. Этот подход имеет свои недостатки, но этот пост не о них.
Этот пост об исключениях в python 🥲 Да, в python есть исключения. Есть свой блок try -catch except - finally. И эти знакомые слова могут создать иллюзию похожести. Но это обманчиво.
Первое отличие, которое бросается в глаза, это что стэк трейс в питоне "перевернут". В логах даже всегда есть строчка перед ним Traceback (most recent call last), чтоб вы не забывали. Но это ладно.
Я привык к тому, что exception - это иммутабельная структура данных. То есть, если я где то пишу throw new Exception(), то в этот момент в него помещается вся информация об ошибке и стэк трейс. И дальше уже не важно, что я там буду делать с ним - вся инфа зафиксирована, стектрейс никак не поменяется.
А в питоне? А в питоне есть офигительная возможность, добавлять заметки к эксепшнам 😂
ладно-ладно, давайте посерьезке 🤓
Честно говоря, не знаю, как там это устроено под капотом, но поведение исключения мутабельное с точки зрения логирования стектрейса 😱 Рассмотрим пример
В этом случае в стек трейсе будет 3 записи: do_smth_deeper -> do_smth -> main. Логично? Логично!
Внесем мааааленькое изменение в наш код: используем именованный raise.
Стектрейс изменился, теперь там 4 записи do_smth_deeper -> do_smth -> do_smth (raise e) -> main. Появилась еще одна запись перед main, относящаяся к строчке raise e.
Еще одна трансформация:
соответственно стэк трейс будет do_smth_deeper -> do_smth_deeper (raise e) -> do_smth (raise e) -> do_smth -> main.
Получается, в python стэкрейс зависит от количества (простихоспади) ре-raise-ов на пути всплывания к логгеру! 🤡
И это еще не все. Но продолжение уже в следующем посте, шоб сильно не грузить и дать мозгу отдохнуть
Этот пост об исключениях в python 🥲 Да, в python есть исключения. Есть свой блок try -
Первое отличие, которое бросается в глаза, это что стэк трейс в питоне "перевернут". В логах даже всегда есть строчка перед ним Traceback (most recent call last), чтоб вы не забывали. Но это ладно.
Я привык к тому, что exception - это иммутабельная структура данных. То есть, если я где то пишу throw new Exception(), то в этот момент в него помещается вся информация об ошибке и стэк трейс. И дальше уже не важно, что я там буду делать с ним - вся инфа зафиксирована, стектрейс никак не поменяется.
А в питоне? А в питоне есть офигительная возможность, добавлять заметки к эксепшнам 😂
ладно-ладно, давайте посерьезке 🤓
Честно говоря, не знаю, как там это устроено под капотом, но поведение исключения мутабельное с точки зрения логирования стектрейса 😱 Рассмотрим пример
def main():
try:
do_smth()
except Exception:
logging.error("Uncaught exception", exc_info=True)
def do_smth():
try:
do_smth_deeper()
except Exception:
raise
def do_smth_deeper():
raise RuntimeError("deep error")
В этом случае в стек трейсе будет 3 записи: do_smth_deeper -> do_smth -> main. Логично? Логично!
Внесем мааааленькое изменение в наш код: используем именованный raise.
def do_smth():
try:
do_smth_deeper()
except Exception as e:
raise e
Стектрейс изменился, теперь там 4 записи do_smth_deeper -> do_smth -> do_smth (raise e) -> main. Появилась еще одна запись перед main, относящаяся к строчке raise e.
Еще одна трансформация:
def do_smth_deeper():
try:
raise RuntimeError("deep error")
except Exception as e:
raise e
соответственно стэк трейс будет do_smth_deeper -> do_smth_deeper (raise e) -> do_smth (raise e) -> do_smth -> main.
Получается, в python стэкрейс зависит от количества (простихоспади) ре-raise-ов на пути всплывания к логгеру! 🤡
И это еще не все. Но продолжение уже в следующем посте, шоб сильно не грузить и дать мозгу отдохнуть
👍3👌2❤1
Ну шо? Отдохнули?
Тада давайте вам небольшой интерактивчик.
Я немного модифицировал код из предыдущего поста.
Я просто сохранил "deep error" в переменную, чтоб "воспользоваться" ей позднее.
Тада давайте вам небольшой интерактивчик.
Я немного модифицировал код из предыдущего поста.
def main():
try:
do_smth()
except Exception:
logging.error("Uncaught exception", exc_info=True)
def do_smth():
deep_err = None
try:
do_smth_deeper()
except Exception as e:
deep_err = e
try:
raise RuntimeError("shallow error")
except Exception:
raise deep_err
def do_smth_deeper():
raise RuntimeError("deep error")
Я просто сохранил "deep error" в переменную, чтоб "воспользоваться" ей позднее.
Итак, все кто проголосовал, те проголосовали 🤓правильный ответ: будет показана инфа об обеих ошибках, причем сначала будет показана инфа о shallow error. А вот deep error будет помечена как ошибка, которая случилась во время обработки shallow error.
During handling of the above exception, another exception occurred
При этом сама ошибка в блоке except с логгером будет именно deep error, но в логах все выглядит так, будто именно shallow error основная ошибка 🤡
Я столкнулся с этим поведением, когда решил, что мне нужно отлавливать все исключения в fastapi в одном месте. Там же я решил и логировать исключения. Я написал middleware с try except - все как завещал Deepseek. Каково же было мое удивление, когда в логах обнаружил сначала каких-то два внутренних эксепшна fastapi, а только потом уже мой эксепшн. И это типа норма 🤷 А в логах образовалась гора ненужного мусора 😢
А к чему я это все говорю? К тому, что стандартизация и консенсус важны в разработке. Они формируют ожидания и привычки, которые экономят мыслетопливо при работе, позволяют быстрее учиться. Хороший пример здесь async - await. Эта конструкция работает схожим образом, что в js, что в c#, что в kotlin, что в python. Детали могут отличаться (Promise vs Deferred vs Future), но принцип один.
Исключения в python, на мой взгляд, ломают "консенсус" исключений в ЯП. python не предлагает принципиально отличающийся механизм обработки ошибок. Это все те же исключения. Но при этом реализация будто не соответствует ожиданиям. И приходится переучиваться, что в моем возрасте уже чревато перенапряжением 😢
During handling of the above exception, another exception occurred
При этом сама ошибка в блоке except с логгером будет именно deep error, но в логах все выглядит так, будто именно shallow error основная ошибка 🤡
Я столкнулся с этим поведением, когда решил, что мне нужно отлавливать все исключения в fastapi в одном месте. Там же я решил и логировать исключения. Я написал middleware с try except - все как завещал Deepseek. Каково же было мое удивление, когда в логах обнаружил сначала каких-то два внутренних эксепшна fastapi, а только потом уже мой эксепшн. И это типа норма 🤷 А в логах образовалась гора ненужного мусора 😢
А к чему я это все говорю? К тому, что стандартизация и консенсус важны в разработке. Они формируют ожидания и привычки, которые экономят мыслетопливо при работе, позволяют быстрее учиться. Хороший пример здесь async - await. Эта конструкция работает схожим образом, что в js, что в c#, что в kotlin, что в python. Детали могут отличаться (Promise vs Deferred vs Future), но принцип один.
Исключения в python, на мой взгляд, ломают "консенсус" исключений в ЯП. python не предлагает принципиально отличающийся механизм обработки ошибок. Это все те же исключения. Но при этом реализация будто не соответствует ожиданиям. И приходится переучиваться, что в моем возрасте уже чревато перенапряжением 😢
👍3👾1
Написал еще одну небольшую статейку об обработке ошибок в Fastapi 😊
Стоит отметить, что подобные задачи возникают в других языках и микрофреймворках. Например, такой же вопрос можно поднять для expressjs, fastify, slim, open swoole и прочих. И обычно все решается либо кастомизацией обработчика, либо написанием middleware. Как и в Fastapi. А ответ чаще всего прямо написан в документации к фреймворкам.
Но отличие состоит в том, что вfastapi этого нет в документации python мы можем влиять на размер бэктрейса в логах. А раз так, то почему бы нам этим не воспользоваться. И я считаю это микро-концептуальным моментом 🤓 Можно бомбить на то, что бэктрейс в python ведет себя, как тварь. А можно обернуть это себе в пользу, почистив логи от ненужного мусора ☝️
Штош. На этом я пока что заканчиваю сезон python на канале. Надеюсь, было интересно 😘
Стоит отметить, что подобные задачи возникают в других языках и микрофреймворках. Например, такой же вопрос можно поднять для expressjs, fastify, slim, open swoole и прочих. И обычно все решается либо кастомизацией обработчика, либо написанием middleware. Как и в Fastapi. А ответ чаще всего прямо написан в документации к фреймворкам.
Но отличие состоит в том, что в
Штош. На этом я пока что заканчиваю сезон python на канале. Надеюсь, было интересно 😘
Telegram
Нервный программист
Обработка ошибок в языках программирования - это вопрос дискусионный. Какого-то консенсуса, как делать правильно, здесь нет по сей день. Где-то язык не предоставляет никаких механизмов для решения этой задачи, отдавая этот вопрос полностью на откуп программистам…
👍5❤1
Так блэт! 🤬
Во-первых, я потратил какое-то время для того, чтоб в принципе решить проблему, которую я в статье описал. Я гуглил, спрашивал Deepseek и ChatGPT, эксперементировал. Потратил на эту задачу целый рабочий день, потому что нихера не было понятно, и результат не нравился!
Во-вторых, я несколько дней писал статью! И пока я писал, я гуглил, спрашивал Deepseek и ChatGPT,экскрементировал эксперементировал!
И вот только что я чисто случайно!!! наткнулся на решение проблемы в документации. Я вообще попал на эту страницу по другому поводу. Я бы даже сказал, я не должен был туда попадать. Потому что эта страница находится в разделе How To - Recipes. А называется она Custom Request and APIRoute class.
Ну вот нахера бы мне вообще Custom Request писать, скажите пожалуйста. У меня обычная апишка. Смысл вообще мне туда заглядывать! И находится эта страница в какой-то жепе, уже после основной документации. Явно же факультативное чтиво! 😤
Но вот именно Custom APIRoute решает все проблемы! там даже сука пример есть с отловом ошибки, но он опять же в другом контексте показан. И написано рядом "лучше пользоваться exception hadnlerами, это чисто демонстрация".
Я вам клянусь, интернет не в курсе этого способа. Всех устраивает, что логи полны говна.
Буду править статью, но выбесився конечно😡 С другой стороны, раз никто об этом еще не писал, в этом может быть больше ценности. Главное все проверить еще раз, чтоб снова не обосраться!
Во-первых, я потратил какое-то время для того, чтоб в принципе решить проблему, которую я в статье описал. Я гуглил, спрашивал Deepseek и ChatGPT, эксперементировал. Потратил на эту задачу целый рабочий день, потому что нихера не было понятно, и результат не нравился!
Во-вторых, я несколько дней писал статью! И пока я писал, я гуглил, спрашивал Deepseek и ChatGPT,
И вот только что я чисто случайно!!! наткнулся на решение проблемы в документации. Я вообще попал на эту страницу по другому поводу. Я бы даже сказал, я не должен был туда попадать. Потому что эта страница находится в разделе How To - Recipes. А называется она Custom Request and APIRoute class.
Ну вот нахера бы мне вообще Custom Request писать, скажите пожалуйста. У меня обычная апишка. Смысл вообще мне туда заглядывать! И находится эта страница в какой-то жепе, уже после основной документации. Явно же факультативное чтиво! 😤
Но вот именно Custom APIRoute решает все проблемы! там даже сука пример есть с отловом ошибки, но он опять же в другом контексте показан. И написано рядом "лучше пользоваться exception hadnlerами, это чисто демонстрация".
Я вам клянусь, интернет не в курсе этого способа. Всех устраивает, что логи полны говна.
Буду править статью, но выбесився конечно😡 С другой стороны, раз никто об этом еще не писал, в этом может быть больше ценности. Главное все проверить еще раз, чтоб снова не обосраться!
Tiangolo
Custom Request and APIRoute class - FastAPI
FastAPI framework, high performance, easy to learn, fast to code, ready for production
😁3❤2⚡1
В связи с тем, что я тут немного подобосрался выше, возник вопрос "а нужно ли читать всю документацию от и до?" И как всегда в программировании не существует однозначного ответа на этот вопрос🤷
Проще всего парировать ответ "да, нужно". Вот допустим, какой-нить зарвавшийся фронтенд разработчик говорит вам, что необходимо читать ВСЕ. Так ты его сразу тогда и спроси "братик, а ты всю спецификацию ECMAScript прочитал?". ставлю очко, что этот фронтендщик ни разу ее не открывал даже (ну может пару раз, чисто, чтоб закрыть). Непонятно, как он код пишет вообще. А если в дискуссии участвует бэкендщик, то спроси его, читал ли он всю документацию по Postgres
Сложнее с теми, кто говорит, что читать всю документацию точно не нужно. Тут еще проблема в определении "всю". Практически в любой серьезной документации есть реально узкоспециализированные темы, которые даже душнилы пропускают. Но я бы определил слово всю в соответствии с принципом Парето - если прочитал более 80 процентов документации, то значит прочел "всю". И есть ситуации, когда такое необходимо. Например, наш любимый React вполне подходит сюда.
На сколько сильно стоит закапываться в документацию зависит от следующих факторов:
* Размера документации (маленькую доку можно всю просмотреть) и ее качества
* Задачи
* Опыта
Под каждую задачу должен быть адекватный набор знаний инструмента и дорожна карта. Знания инструмента - это то, что вы непосредственно читаете в документации. Дорожная карта - это понимание того, какие проблемы могут возникнуть при работе с инструментом и где найти информацию про их решение. Дорожная карта - это ваш опыт помноженный навечность чтение заголовков документации. Она не требует (но и не отрицает) погружение в документацию. Но опытный разработчик может скипнуть гораздо больше документации, чем джун. Потому что опытный разработчик лучше понимает, какой набор знаний адекватный. Новичкам недостаток опыта как раз следует компенсировать чтением доки.
Большинство инструментов в своей документации следуют этой концепции. Они дают вам Getting Started и какие-то базовые статьи - минимальный набор, чтоб начать работать. А дальше вы уже погружаетесь в ту или иную тему при необходимости. Хорошая документация имеет понятные заголовки, чтоб было проще дорожную карту составить.
Почему же все таки не прочесть всю документацию? потому что
* вам платят не за прочтение документации, а за работу
* чтение документации сжигает мыслетопливо - в итоге тупеешь, и не хватает мозгов на задачи
* вы что-то прочли и не используете это - через время вы забыли все
Одна и та же документация, может быть прочтена по диагонали или полностью в зависимости от задачи. Если вы core contributor в ЯП, то вам скорее всего придется очень хорошо прочитать документацию по языку и не раз. Иначе вы даже не сможете составить адекватный RFC. Но если вы просто пользователь языка, то вам такой щепетильности не требуется.
В комментах делитесь, согласны или нет с такой позицией? читаете ли вы документацию всегда полностью?
Проще всего парировать ответ "да, нужно". Вот допустим, какой-нить зарвавшийся фронтенд разработчик говорит вам, что необходимо читать ВСЕ. Так ты его сразу тогда и спроси "братик, а ты всю спецификацию ECMAScript прочитал?". ставлю очко, что этот фронтендщик ни разу ее не открывал даже (ну может пару раз, чисто, чтоб закрыть). Непонятно, как он код пишет вообще. А если в дискуссии участвует бэкендщик, то спроси его, читал ли он всю документацию по Postgres
Сложнее с теми, кто говорит, что читать всю документацию точно не нужно. Тут еще проблема в определении "всю". Практически в любой серьезной документации есть реально узкоспециализированные темы, которые даже душнилы пропускают. Но я бы определил слово всю в соответствии с принципом Парето - если прочитал более 80 процентов документации, то значит прочел "всю". И есть ситуации, когда такое необходимо. Например, наш любимый React вполне подходит сюда.
На сколько сильно стоит закапываться в документацию зависит от следующих факторов:
* Размера документации (маленькую доку можно всю просмотреть) и ее качества
* Задачи
* Опыта
Под каждую задачу должен быть адекватный набор знаний инструмента и дорожна карта. Знания инструмента - это то, что вы непосредственно читаете в документации. Дорожная карта - это понимание того, какие проблемы могут возникнуть при работе с инструментом и где найти информацию про их решение. Дорожная карта - это ваш опыт помноженный на
Большинство инструментов в своей документации следуют этой концепции. Они дают вам Getting Started и какие-то базовые статьи - минимальный набор, чтоб начать работать. А дальше вы уже погружаетесь в ту или иную тему при необходимости. Хорошая документация имеет понятные заголовки, чтоб было проще дорожную карту составить.
Почему же все таки не прочесть всю документацию? потому что
* вам платят не за прочтение документации, а за работу
* чтение документации сжигает мыслетопливо - в итоге тупеешь, и не хватает мозгов на задачи
* вы что-то прочли и не используете это - через время вы забыли все
Одна и та же документация, может быть прочтена по диагонали или полностью в зависимости от задачи. Если вы core contributor в ЯП, то вам скорее всего придется очень хорошо прочитать документацию по языку и не раз. Иначе вы даже не сможете составить адекватный RFC. Но если вы просто пользователь языка, то вам такой щепетильности не требуется.
В комментах делитесь, согласны или нет с такой позицией? читаете ли вы документацию всегда полностью?
👍5😁1
На днях просто сгорела жепа🤬 Все дело в том, что я послушал вот этот подкаст (только в аудио). Потом глянул, че там за гость и понял, что видел его уже в другом ролике, который не смог дослушать до конца.
Основной тезис гостя, Андрея Бреслава: скоро мы вообще перестанем писать прикладной код на привычных ЯП. Вместо этого, у нас будет обычный язык (английский), но мы будем писать требования в определенном формализованном виде. И вот это как раз будет наш НОВЫЙ язык программирования будщего!!! А "интерпретировать" наш язык будет, сюрприз-сюрприз, 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