<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xml:base="https://graker.ru/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Программирование</title>
    <link>https://graker.ru/</link>
    <description>RSS домовой страницы</description>
    <language>ru</language>
    
    <item>
  <title>Критическое обновление безопасности PHP</title>
  <link>https://graker.ru/news/2026/10/21/php-critical-security-update</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Сегодня в 14:00 UTC (в 5 вечера по Москве) выйдет критическое обновление безопасности PHP &lt;a href=&quot;https://www.php.net/archive/2026.php#2026-10-20-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.php.net/archive/2026.php#2026-10-20-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Обновление такой чудовищной критичности, что никаких деталей не раскрывают, чтобы заранее не взломали вообще всех.&lt;/p&gt;
&lt;p&gt;Так что заготавливаем консольки, открываем докер-конфиги и вперёд, обновлять всё по кругу. &lt;/p&gt;
&lt;p&gt;Но если уязвимости и обновления так и будут сыпаться, как из рога изобилия, придется когда-то уже действительно пускать на проды роботов и пусть они там сами. Иначе как это всё успевать-то?&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Wed, 21 Oct 2026 08:55:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2245 at https://graker.ru</guid>
    </item>
<item>
  <title>PR на шиссот!</title>
  <link>https://graker.ru/news/2026/10/07/pr-600</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;На днях PR на 610 файлов был окончательно повержен и смерджен! На выходе получился полный редизайн Доктуриста. Наружной части (лендинга и блога) немного тоже, но в первую очередь — всего внутряка. Всех страниц, форм и диалогов самой crmки.  &lt;/p&gt;
&lt;p&gt;Это еще один пример как можно увлечься, решая задачи с нейросетью. Изначально идея была значительно скромнее. Дэшборд, он же рабочий стол, он же главная страница внутри системы — был сделан довольно простеньким. Вот так он выглядел:&lt;/p&gt;&lt;/div&gt;
&lt;figure data-component-id=&quot;grakerru:figure&quot; class=&quot;figure figure--center figure--medium&quot;&gt;
      &lt;a href=&quot;/sites/default/files/uploads/2026-10/dashboard.png&quot; data-lightbox=&quot;node-2243&quot;&gt;
    &lt;img loading=&quot;lazy&quot; srcset=&quot;/sites/default/files/styles/content_medium/public/uploads/2026-10/dashboard.png.webp?itok=yo1Bng8q 850w, /sites/default/files/styles/content_medium_2x/public/uploads/2026-10/dashboard.png.webp?itok=S8nvKheF 1700w&quot; sizes=&quot;(min-width: 1200px) 850px, (min-width: 768px) 75vw, calc(100vw - 30px)&quot; width=&quot;850&quot; height=&quot;413&quot; src=&quot;/sites/default/files/styles/content_medium/public/uploads/2026-10/dashboard.png.webp?itok=yo1Bng8q&quot; alt=&quot;dashboard.thumb.png&quot; /&gt;



&lt;/a&gt;
    &lt;/figure&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Конечно, турагенты сообщили, что виджетами этого стола не пользуются совсем. Только ссылками, чтобы сразу прыгнуть в нужный раздел. А хотелось чтобы это был скорее быстрый доступ к важным разделам и информации. Чтобы некоторые вещи вообще можно было сделать, не уходя с дэшборда.  &lt;/p&gt;
&lt;p&gt;Вот этим мы с клод-дизайном и занялись. Переосмыслили содержимое дэшборда с целью сделать его удобным и используемым, а не просто местом для ссылок как рабочий стол в win95. И вышеприведенное «было» превратилось в новое «стало»:  &lt;/p&gt;&lt;/div&gt;
&lt;figure data-component-id=&quot;grakerru:figure&quot; class=&quot;figure figure--center figure--medium&quot;&gt;
      &lt;a href=&quot;/sites/default/files/uploads/2026-10/dashboard_3.png&quot; data-lightbox=&quot;node-2243&quot;&gt;
    &lt;img loading=&quot;lazy&quot; srcset=&quot;/sites/default/files/styles/content_medium/public/uploads/2026-10/dashboard_3.png.webp?itok=ORE5xe4w 850w, /sites/default/files/styles/content_medium_2x/public/uploads/2026-10/dashboard_3.png.webp?itok=f57DgDy- 1700w&quot; sizes=&quot;(min-width: 1200px) 850px, (min-width: 768px) 75vw, calc(100vw - 30px)&quot; width=&quot;850&quot; height=&quot;531&quot; src=&quot;/sites/default/files/styles/content_medium/public/uploads/2026-10/dashboard_3.png.webp?itok=ORE5xe4w&quot; alt=&quot;dashboard.thumb.png&quot; /&gt;



&lt;/a&gt;
    &lt;/figure&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Тут уже и показатели всякие, и главное лента с броньками более умная. Хочешь, смотри последние брони по дате, хочешь — требующие определённого внимания.  &lt;/p&gt;
&lt;p&gt;Сдерживать оформительские порывы Клода я не стал, поэтому в нагрузку получил сразу и новый стиль. Предыдущий стиль делался на теме color admin, которую я в 2018-м специально покупал. Тема, конечно, с тех пор несколько состарилась и подрастеряла актуальность.&lt;/p&gt;
&lt;p&gt;Так или иначе, когда есть новое оформление — остальные страницы оставлять в старом не хочется. И так, страничка за страничкой, компонент за компонентом мы сначала с Claude Design, а затем с Claude Code привели весь сервис к новым стилям. А поскольку просто так перерисовывать скучно, то заодно переосмыслили, доработали и переделали компоненты на страничках.&lt;/p&gt;
&lt;p&gt;Вот и получился PR на 610 файликов. Который я конечно умотался проверять и тестировать. И в целом тезисы моего &lt;a href=&quot;/news/2026/08/11/zeldevmeetup-talk-2026&quot;&gt;доклада&lt;/a&gt; на эту тему сохраняются. Надо тестировать, структурировать, декомпозировать. А вот не смотреть на нейрокод по заветам Роберта Мартина пока еще не получается: я проверял каждый экранчик — смотрел изменения, тесты, фронт, и в каждом находил что что-то было сделано не совсем так, или не работало, или влекло проблемы какие-то новые.&lt;/p&gt;
&lt;p&gt;Но в конечном итоге всё проверил, погонял руками и залил. Так что теперь у нас в Доктуристе не только новый, переосмысленный, современный дизайн, но и всякие юзабилити-мелочи, в том числе:&lt;/p&gt;
&lt;p&gt;— Доктурист запоминает и сразу показывает набор операторов, с которыми часто работает агент, не нужно каждый раз искать по автодополнению.&lt;br&gt;
— &lt;code&gt;/&lt;/code&gt; или &lt;code&gt;Ctrl+F&lt;/code&gt; немедленно включают поиск по всем данным (повторный Ctrl+F включает нативный поиск).&lt;br&gt;
— Документы по брони можно сгенерировать и подписать прямо из всплывашки с рабочего стола, необязательно в бронь проваливаться.&lt;br&gt;
— Улучшена работа календаря на мобильных устройствах (мобильный календарь просто сделан заново).&lt;br&gt;
— Страница профиля наконец-то разделена на 5 секций по соответствующим тематикам настроек.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Результатом доволен, теперь обновления снова можно выкатывать чаще, не проверяя такие большие PRы. В целом редизайн занял где-то полтора месяца. Теперь на очереди интеграция сервиса онлайн-касс (уже готова) и тёмная тема (уже тоже). Работаем!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://docturist.ru&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Доктурист — умный ежедневник турагента&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Wed, 07 Oct 2026 18:30:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2243 at https://graker.ru</guid>
    </item>
<item>
  <title>Нейросети и анализ кода</title>
  <link>https://graker.ru/news/2026/07/22/ai-code-analysis</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Вчера считал эстимейты на группу из ~40 тикетов. Все сделаны по отчету ИИ об анализе кода большого проекта на Drupal. Проекту около 10 лет, кодовая база развивалась все это время, 20 поддоменов, интеграции, апишки, синхронизация контента, в общем прикольный проект.&lt;/p&gt;
&lt;p&gt;Отчет структурированный, нейросеть проверяла всех четырёх всадников попокалипсиса в проекте: Уязвимости, Баги, Тормоза и Грязный код. Изначально из переданного отчета получалось гораздо больше задач, но процентов на 30% я сразу won&#039;t fix навесил. Там и глюки нашлись, и непонимание контекста. Но 40 тикетов тем не менее осталось.&lt;/p&gt;
&lt;p&gt;Среди них тоже в основном таски с минимальнейшим приоритетом, типа&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;в кастомном модуле не проставлена зависимость от чего-нибудь типа paragraphs;&lt;/li&gt;
&lt;li&gt;где-то в коде наглый программист вызвал \Drupal::service() вместо инъекции зависимостей;&lt;/li&gt;
&lt;li&gt;где-то deprecated-версии Друпала не убраны из поддерживаемых версий и тому подобное.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Нашлось и несколько более серьезных претензий:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;парочка проблем N+1;&lt;/li&gt;
&lt;li&gt;несколько XSS-уязвимостей (доступных только админам, но всё же);&lt;/li&gt;
&lt;li&gt;несколько мест, где отсутствуют проверки на наличие ключа в массиве (спамит в лог предупрежденими);&lt;/li&gt;
&lt;li&gt;и даже одна уязвимость типа timing oracle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Да, грязненький код — признак грязненьких мыслей :) Да, хорошо бы всё это почистить. Но за вычетом 3–4 претензий, это получается больше ста часов работы суммарно, а выхлоп — немножко более чистый код, причёсанное legacy, немножко меньше техдолга и warning/debug-записей в логе. Хорошо конечно, когда заказчик не против провести такую генеральную уборку. И честь и хвала аккаунтам, которые могут убедить заказчика в необходимости такой уборки при примерно нулевой ценности для конечного пользователя.&lt;/p&gt;
&lt;p&gt;А ощущения от таких отчетов по-прежнему странные. Вроде и находит что-то. Но суеты с этими отчетами пока куда больше, чем пользы.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Wed, 22 Jul 2026 09:15:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2227 at https://graker.ru</guid>
    </item>
<item>
  <title>Виртуализация локальной разработки, docker-compose и traefik</title>
  <link>https://graker.ru/news/2026/06/25/local-dev-virtualization-docker-compose-and-traefik</link>
  <description>&lt;p&gt;Когда-то давно описывал &lt;a href=&quot;/news/2019/03/26/virtual-local-projects-in-docker&quot;&gt;довольно простой способ виртуализации проектов&lt;/a&gt;, над которыми работаю, чтобы было удобно переключаться и они друг другу не мешали. Прошло уже 7 лет и способ конечно эволюционировал. Когда-то использовать отдельные контейнеры, запускаемые по `docker run` было быстрее и удобнее и поэтому я докерфайлы и docker-compose-файлы не писал. Но прогресс конечно добрался до меня в этом вопросе и победил. Теперь я для локальной разработки тоже использую docker compose.&lt;/p&gt;
&lt;blockquote&gt;Инструментами со всякими пресетами типа lando или ddev я, тем не менее, стараюсь не пользоваться. В основном потому что когда с ними сталкивался, они нормально работали — до тех пор пока не надо было что-то в них поменять или сделать нестандартно. После чего начинался вынос мозга, иногда такой, что проще было самому пересобрать сразу.&lt;br&gt;
Кроме того, если собирать «чистые» окружения, есть шанс лучше понять, как это всё работает, а если пользоваться lando, forge, ddev и прочими — наоборот.&lt;/blockquote&gt;
&lt;p&gt;Итак, чем docker compose лучше.&lt;/p&gt;</description>
  <pubDate>Thu, 25 Jun 2026 15:20:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2220 at https://graker.ru</guid>
    </item>
<item>
  <title>Изучаем C# и Unity</title>
  <link>https://graker.ru/news/2026/04/30/learn-csharp-and-unity</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Достаточно давно занимаюсь с сыном изучением C# через создание игр в Unity. До этого пробовали Scratch (слишком просто и немного скучно) и Lua с Роблоксом, тоже не зашло. Наверно, ввиду ограниченности применения.&lt;/p&gt;
&lt;p&gt;В общем, взялись за игры в Unity и, посмотрев пару-тройку видеоуроков, решили что лучше по учебнику. Купил «Unity и C# Геймдев от идеи до реализации» Джереми Гибсона Бонда. Быстренько прочитал сам и стали заниматься.&lt;/p&gt;
&lt;p&gt;Автор, как я понял, преподаёт геймдев в Калифорнийском универе, ну или что-то типа того, не вникал.&lt;/p&gt;
&lt;p&gt;Книжку можно разделить на три части:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Некоторая теория и философствования на тему геймдизайна. С точки зрения занятий с детьми часть не очень полезная, но в целом почитать интересно. Вероятно тем кто хочет стать геймдизайнером — может быть полезно.&lt;/li&gt;
&lt;li&gt;Теория по программированию на C#. Тут всё как обычно, разбор основных принципов программирования: hello world, переменные и типы данных, циклы, условия, классы и наследование. Учебные примеры, чтобы не заморачиваться, исполняются сразу в Unity.&lt;/li&gt;
&lt;li&gt;Разработка игр. Добрая половина книги — после теории — посвящена настоящей разработке настоящих игр. Каждая глава описывает пошагово разработку отдельного прототипа игры с рабочим играбельным результатом в конце. По учебнику можно создать 7 разных игр, в том числе скролл-шутер, пасьянс, клоны Angry Birds и даже старой The Legend of Zelda.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Автор дает как концепции кодинга под Unity, так и использования Unity Editor для создания префабов. Причем, в основном автор создает объекты, пользуясь возможностями самого редактора, а не загружает модельки откуда-то еще.&lt;/p&gt;
&lt;p&gt;Обычно основная проблема бумажной литературы о современных технологиях — ты еще не успел купить книжку, а данные в ней уже устарели. Но в данном случае примеры на удивление актуальны. Расхождения с текущей версией Unity есть конечно, в части текстовых лейблов на экране, в части работы с XML, но учитывая год издания (2021) их довольно мало: запускается сразу как в примерах почти всё.&lt;/p&gt;
&lt;p&gt;Некоторый матан в книжке (кватернионы, кривые Безье и т.д.) детям объяснить сходу не получится. Но основную суть ухватить они вполне могут. В любом случае, по книжке лучше конечно заниматься с взрослым, который немного шарит.&lt;/p&gt;
&lt;p&gt;Еще отмечу, что некоторые паттерны, применяемые автором, на взгляд программиста из другой отрасли могут показаться сомнительными. Но возможно это упрощение для учащихся. Ну или в настоящем геймдеве есть причины так делать — мало ли.&lt;/p&gt;
&lt;p&gt;В целом книжку рекомендую всем кто хотел бы попробовать овладеть базой создания игрушек под Юнити, или обучить детей программированию. В отличие от отдельных видеороликов, книжка подходит к вопросу более системно, охватывает более широкий спектр тем и дает направления для дальнейшего изучения.&lt;/p&gt;
&lt;p&gt;На первом приложенном видео — скролл-шутер, который мы написали по учебнику. На втором — результат упражнения по завершающей теоретическую часть главе. Это стая птиц, которая красиво летит за неким объектом, «роится», но при этом не сталкивается. Управлять ей нельзя, но можно регулировать параметры (скорость, количество птиц и т.д.) Это упражнение сын уже написал по книжке без меня.&lt;/p&gt;
&lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-md-6&quot;&gt;
        &lt;video class=&quot;center-block .img-responsive&quot; width=&quot;100%&quot; height=&quot;auto&quot; style=&quot;max-height: 480px;&quot; controls&gt;
          &lt;source src=&quot;/sites/default/files/media/space.mp4&quot; type=&quot;video/mp4&quot;&gt;
        Your browser does not support the video tag.
        &lt;/video&gt;
    &lt;/div&gt;

    &lt;div class=&quot;col-md-6&quot;&gt;
        &lt;video class=&quot;center-block .img-responsive&quot; width=&quot;100%&quot; height=&quot;auto&quot; style=&quot;max-height: 480px;&quot; controls&gt;
          &lt;source src=&quot;/sites/default/files/media/boyd.mp4&quot; type=&quot;video/mp4&quot;&gt;
        Your browser does not support the video tag.
        &lt;/video&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;
</description>
  <pubDate>Thu, 30 Apr 2026 17:45:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2210 at https://graker.ru</guid>
    </item>
<item>
  <title>Код пишут роботы, но отвечать за него нам</title>
  <link>https://graker.ru/news/2026/04/08/robots-code-we-take-responsibility</link>
  <description>&lt;p&gt;В последнее время все чаще и больше в разработке использую генеративные нейросети в агентском режиме, для простоты будем называть это как все, вайб-кодингом. Ну а чего? Сейчас каждый утюг и его бабушка вайб-кодят и рассказывают о том, как это стало здорово. И в плане доступа к разработке тех, кто раньше разрабатывать не умел, это, кстати, действительно здорово.&lt;/p&gt;
&lt;p&gt;Но кто и раньше умел разрабатывать сам, всё-таки смотрит на предмет немножко под другим углом. Поэтому решил немного растечься мыслями, поворчать, позанудствовать и поразмышлять не о том, как настроить Codex, MCP-сервер, или натравить Claude Code на KWork. А об эффектах, о неизбежных изменениях, которые внесли, вносят и будут вносить в нашу повседневную работу — в разработку программного обеспечения живыми человеческими людьми — нейросети.&lt;/p&gt;
&lt;blockquote&gt;Сначала коротко определим наше место в пространстве и времени относительно самого феномена нейросетей (здесь и далее — в разработке ПО). Обсуждать, нужны ли они, помогают ли они, следует ли их использовать — уже поздно. Этот вопрос больше не стоит. Если вдруг еще не начали, надо начать. Кот смотрит на часы и говорит — Пора!&lt;/blockquote&gt;</description>
  <pubDate>Wed, 08 Apr 2026 08:20:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2202 at https://graker.ru</guid>
    </item>
<item>
  <title>Снежный вайб-кодинг</title>
  <link>https://graker.ru/news/2026/02/26/snowy-vibe-coding</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Если вы живёте за городом, обязательно нужно вайб-кодить. Особенно зимой.  &lt;/p&gt;
&lt;p&gt;Я тут как-то завёл себе подписку на Claude Code, и он довольно здорово работает. Описал задание, выставил нужные разрешения, чтобы он без лишних вопросов работал, запустил. И всё, можно идти на улицу чистить снег. Если снега много, можно и сразу несколько заданий выставить.  &lt;/p&gt;
&lt;p&gt;Последнее время использую Клода в хвост и в гриву. Судя по регулярным сообщениям о превышении дневных и недельных лимитов — интенсивнее уже некуда.  &lt;/p&gt;
&lt;p&gt;Чтобы лимитов хватало чуточку побольше, пользуюсь таким простым методом.  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Сначала завожу проекту файлик CLAUDE.md, в котором описываю полезную для иишечки информацию о проекте. Какие технологии, методики, тесты, как почистить кэш и где найти нужные контейнеры. Этот файл принимается нейросетью к сведению при старте каждой новой сессии. В принципе, можно и Клода попросить составить этот файл командой /init, но он понимает сходу о проекте не всё.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;MD — это Markdown, удобный способ форматирования текста в обычных текстовых файлах. Удобный и роботам, и человекам.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Затем пишу отдельные md-файлы с задачами. Описываю цель задачи, детали, дополнительную инфу.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Затем перевожу Клода в режим планирования и говорю: прочитай файл с задачей и составь детальный план её реализации.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Читаю получившийся план, перещелкиваю в режим с авто-правками, запускаю и иду чистить снег.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Некоторые рекомендуют явно просить иичко записывать прогресс выполнения плана в отдельный файл, чтобы потом вернуться в случае сбоя. Но насколько я заметил, он под капотом и так всё в файлы пишет и проблем продолжить прерванную сессию не возникает.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Когда клод закончил и снег закончился, всё написанное нужно проверить вручную, отладить и закоммитить. Про эту часть напишу в следующий раз.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Как упомянул выше, дневные и недельные лимиты иссякают быстрее, чем хотелось бы. Чтобы немножко токенов сэкономить и чуть-чуть продлить беззаботный вайб-кодинг, рекомендую после пары-тройки выполненных задач посмотреть на лог сессий самому, или даже попросить агента порефлексировать. А именно: обновить по логам содержимое CLAUDE.md. Зачастую агент поначалу тупит и не сразу понимает, какой в точности командой правильно запустить тесты, или что не нужно лезть в контейнер, чтобы собрать фронт-энд. &lt;/p&gt;
&lt;p&gt;Вот эти команды надо скорректировать, записать в CLAUDE.md тот вариант, с которым агенту удалось справиться с задачей. Чтобы он в каждой новой сессии не перебирал варианты заново.&lt;/p&gt;
&lt;p&gt;Попользовался и консольным claude, и плагином в VS Code. Консольный поприкольнее, больше возможностей и команд всяких. К тому же его можно с отключенными проверками запустить — чтобы он не спрашивал, можно ли выполнить &lt;code&gt;rm -Rf *&lt;/code&gt;, а сразу делал. Но и плагин тоже ничего. Работает и там, и там иишечка на совесть, месячная подписка, я считаю, окупилась в первые 3 часа использования.&lt;/p&gt;
&lt;p&gt;В общем, хорошего вам снежного вайб-кодинга! Ну а летом достанем газонокосилку и займемся вайб-дебагом.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Thu, 26 Feb 2026 13:50:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2195 at https://graker.ru</guid>
    </item>
<item>
  <title>Laravel Reverb, броадкастинг и вебсокеты</title>
  <link>https://graker.ru/news/2026/01/20/laravel-reverb-broadcasting-and-websockets</link>
  <description>&lt;p&gt;В Ларавеле из коробки (ну, почти из коробки) есть поддержка отправки сообщений на вебсокетах, что бывает довольно полезно. Например, когда мы из фронта просим сервер выполнить длительную операцию, и не можем, или не хотим ждать её окончания. А вот узнать, когда она закончится — наоборот, очень хотим. Для чего нам нужно получить от сервера обратную связь. В эру палеолита для этого каждый клиент опрашивал сервер раз в секунду до получения ответа (или до полного изумления сервера). Но теперь у нас есть вебсокеты, с ними проще. Можно передать с сервера результат отложенной операции, можно сделать уведомления о действиях других юзеров, или просто чатик сделать даже. Почитать про это можно в документации на &lt;a href=&quot;https://laravel.com/docs/12.x/broadcasting&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Laravel Broadcasting&lt;/a&gt;. А далее мы рассмотрим нюансы первоначальной настройки Laravel Reverb для этого самого броадкастинга.&lt;/p&gt;</description>
  <pubDate>Tue, 20 Jan 2026 10:20:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2185 at https://graker.ru</guid>
    </item>
<item>
  <title>Ночные тесты и Laravel Scout</title>
  <link>https://graker.ru/news/2025/12/15/night-tests-and-laravel-scout</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Вчера перед сном решил — а ну-ка сейчас за 20 минут добью большую фичу. Долго делал, чуть-чуть осталось. Сел, открыл, и правда — через 20 минут фича была готова. Но чёрт меня дернул запустить после этого все тесты. Пока фичу делал — смысла не было запускать весь пакет. А тут, в ночи, решил запустить.&lt;/p&gt;
&lt;p&gt;И конечно как посыпались ошибки! Пару простых исправил, и оказалось, что все остальные — потому что сломался поиск. У меня в проекте используется Laravel Scout для быстрого поиска-автодополнения по нескольким типам моделей одновременно, чтобы было удобно искать что угодно. И вот он сломался сразу весь. Абсолютно все поиски возвращались пустыми.&lt;/p&gt;
&lt;p&gt;Посмотрел на проде — всё еще работает. Стал разбираться, чего такого я мог сломать. Отключил несколько установленных библиотек — вдруг конфликт у трейта &lt;code&gt;Searchable&lt;/code&gt; с чем-нибудь. Включил обратно ту, которую наоборот — стёр за ненадобностью. Не работает.&lt;/p&gt;
&lt;p&gt;Откатил контроль версий на точку до начала разработки фичи. Не работает! Подозрительно как-то. Накатил обратно. Обновил зависимости. Не работает. &lt;/p&gt;
&lt;p&gt;Поотлаживал классы Скаута — увидел, что почему-то драйвер поиска определяется как null (то есть никакой)! Полез смотреть, оказывается у меня внезапно в &lt;code&gt;.env&lt;/code&gt; прописано &lt;code&gt;SCOUT_DRIVER=null&lt;/code&gt;! Хотя я просто полагался на дефолтное значение из конфига &lt;code&gt;scout.php&lt;/code&gt; (который не менялся), и в &lt;code&gt;.env&lt;/code&gt; вообще драйвер не прописывал.&lt;/p&gt;
&lt;p&gt;В общем, непонятно, кто такое сделал-то — то ли один из устанавливаемых пакетов в ходе &lt;code&gt;vendor:publish&lt;/code&gt; проявил инициативу. То ли я зачем-то выставил, хотя никакой пользы от этого не припоминаю. То ли нейросеть, которую тем более об этом не просили. &lt;/p&gt;
&lt;p&gt;В общем, пока нашёл ошибку и вернул нормальный драйвер, прошло уже конечно в разы больше 20 минут. Зато в конце увидел все тесты зелёными. На чем и ушел спать, вот только&lt;/p&gt;&lt;/div&gt;
&lt;figure data-component-id=&quot;grakerru:figure&quot; class=&quot;figure figure--center figure--medium&quot;&gt;
      
    &lt;img loading=&quot;lazy&quot; srcset=&quot;/sites/default/files/styles/content_medium_2x/public/uploads/2025-12/6e5976e46e9131843002978c5dd20091.jpg.webp?itok=L5JhQUBr 500w&quot; sizes=&quot;(min-width: 1200px) 850px, (min-width: 768px) 75vw, calc(100vw - 30px)&quot; width=&quot;500&quot; height=&quot;332&quot; src=&quot;/sites/default/files/styles/content_medium/public/uploads/2025-12/6e5976e46e9131843002978c5dd20091.jpg.webp?itok=BuVGoljt&quot; alt=&quot;6e5976e46e9131843002978c5dd20091.jpg&quot; /&gt;




    &lt;/figure&gt;
</description>
  <pubDate>Mon, 15 Dec 2025 16:00:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2178 at https://graker.ru</guid>
    </item>
<item>
  <title>Сортировка по json-полю в таблицах Laravel Orchid</title>
  <link>https://graker.ru/news/2025/11/22/laravel-orchid-sort-table-by-json-field</link>
  <description>&lt;p&gt;Спешно прикручиваю к своей туристической CRMке нормальную админку (которая для админов). Раньше была самописная с фронтом на Vue, из-за этого добавление любой новой страницы или функции требовало слишком много времени. Собрался с мыслями, решил наконец заменить её на Laravel Orchid. Дело пошло значительно быстрее, и в целом могу констатировать очевидное: как бы ни было прикольно играться с фронтом на Vue, какая бы небольшая ни была админка — лучше конечно сразу брать готовую панельку. А с фронтом играться в пользовательской части.&lt;/p&gt;
&lt;p&gt;В процессе переноса столкнулся с неожиданной трудностью. В Orchid есть вывод моделей в таблицы, который довольно легко и удобно собирается, при этом столбцы таблицы можно сделать фильтруемыми и сортируемыми — тоже легко. Вот, например, объявили колонку «Название» с сортировкой и фильтром (по фрагменту текста)…&lt;/p&gt;</description>
  <pubDate>Fri, 21 Nov 2025 22:30:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2170 at https://graker.ru</guid>
    </item>
<item>
  <title>Почему не нужно писать тесты на визуал при разработке</title>
  <link>https://graker.ru/news/2025/11/11/why-we-should-not-test-visuals-in-development</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Вопрос касается не только TDD-разработки, но и написания качественных unit-тестов в целом.&lt;/p&gt;
&lt;p&gt;В &lt;a href=&quot;/news/2025/11/06/laravel-register-and-login-with-telegram-bots&quot;&gt;прошлой заметке&lt;/a&gt; был тест на проверку отправки юзеру в бот ссылки для входа на сайт. Вот код (я еще про &lt;code&gt;Argument::that()&lt;/code&gt; хотел отдельно написать):&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;/**
 * @test
 */
public function user_issues_login_command_and_gets_a_message_with_login_button(): void
{
    $user = User::factory()-&amp;gt;create([&amp;#039;telegram_username&amp;#039; =&amp;gt; &amp;#039;mr_phpunit&amp;#039;, &amp;#039;telegram_id&amp;#039; =&amp;gt; &amp;#039;123456789&amp;#039;]);
    $bot = Bot::factory()-&amp;gt;create([&amp;#039;user_id&amp;#039; =&amp;gt; $user-&amp;gt;id,]);
    $bot-&amp;gt;settings()-&amp;gt;create([&amp;#039;register&amp;#039; =&amp;gt; TRUE,]);
    $update = $this-&amp;gt;generateMessageUpdate(&amp;#039;mr_phpunit&amp;#039;, &amp;#039;&amp;#039;, &amp;#039;/login&amp;#039;);

    $webhooksService = resolve(TelegramBotWebhooksInterface::class);
    $webhooksService-&amp;gt;processUpdates($this-&amp;gt;api-&amp;gt;reveal(), $update); 

    // ожидаем что будет вызван метод sendMessage() где в тексте сообщения будет Please click the button below...
    // а ссылка в кнопке Login будет содержать роут быстрого логина
    $this-&amp;gt;api-&amp;gt;sendMessage(Argument::that(function ($params) use ($user) {
        return $params[&amp;#039;text&amp;#039;] === &amp;quot;Please click the button below to log in with your account. You will be automatically redirected to your dashboard.&amp;quot; &amp;amp;&amp;amp;
               strpos($params[&amp;#039;reply_markup&amp;#039;][&amp;#039;inline_keyboard&amp;#039;][0][0][&amp;#039;url&amp;#039;], route(&amp;#039;bot.quick-login&amp;#039;, [&amp;#039;user&amp;#039; =&amp;gt; $user-&amp;gt;id])) === 0;
    }))-&amp;gt;shouldHaveBeenCalled();
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Здесь мы проверяем, что пользователю в конце ушёл в виде сообщения определённый текст. Каковой текст и является визуалом, то есть &lt;em&gt;представлением&lt;/em&gt;. Это вывод текста и кнопки-ссылки в форме телеграм-сообщения. И этот текст тестировать не нужно.&lt;/p&gt;
&lt;p&gt;Почему? Потому что текст (представление) не является функциональной частью нашего решения. Мы можем написать какое угодно другое сообщение, но пока в нём содержится ссылка на логин, наша фича работает корректно. То есть конкретное содержимое текста совершенно не имеет значения.&lt;/p&gt;
&lt;p&gt;Почему ещё? Потому что в ходе развития проекта мы текст можем много раз улучшить и переписать. Что повлечёт необходимость менять соответствующие тесты. Безо всякой на то нужды, поскольку кнопку и роут входа мы не меняли.&lt;/p&gt;
&lt;p&gt;Иными словами, при написании тестов, будь то TDD, или просто тесты из общих соображений, мы тоже должны отделять бизнес-логику от представления. Тест — это не застывшее описание реализации, а спецификация поведения программы. А смена текста сообщения (представления) никак не меняет поведение (бизнес-логику). Поэтому тест не должен ломаться при смене текста.&lt;/p&gt;
&lt;p&gt;Текст был бы уместен, если бы кроме него никаких проверяемых результатов у нашей фичи бы не было. И то, тогда лучше проверить не наличие конкретных букв, а название строки из массива локализаций. Тогда проверку в упомянутом тесте можно было бы переписать так:&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;$this-&amp;gt;api-&amp;gt;sendMessage(Argument::that(function ($params) use ($user) {
    return $params[&amp;#039;text&amp;#039;] === __(&amp;#039;login_link.description&amp;#039;) &amp;amp;&amp;amp;
           strpos($params[&amp;#039;reply_markup&amp;#039;][&amp;#039;inline_keyboard&amp;#039;][0][0][&amp;#039;url&amp;#039;], route(&amp;#039;bot.quick-login&amp;#039;, [&amp;#039;user&amp;#039; =&amp;gt; $user-&amp;gt;id])) === 0;
}))-&amp;gt;shouldHaveBeenCalled();&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Возвращаясь к &lt;code&gt;Argument::that()&lt;/code&gt; — как вы уже могли заметить, этот статичный метод (из мок-библиотеки Prophecy) позволяет проверять в переданных аргументах только то, что действительно нужно проверить. А без него методы типа &lt;code&gt;shouldHaveBeenCalled()&lt;/code&gt; будут проверять все аргументы на точное совпадение. Что сделает наши тесты очень деревянными.&lt;/p&gt;
&lt;p&gt;Пример я взял из телеграм-бота просто потому что он был под рукой. Но абсолютно то же самое применимо и к веб-страницам. Не нужно, 10 раз не подумав, загонять в тесты конкретную верстку, или конкретные тексты. Нашим тестам от этого только вред: вывести фичу не поможет, а исправлять тесты потом придётся часто, причем безо всякой пользы для кода.&lt;/p&gt;
&lt;p&gt;А для тестирования визуала есть более подходящие способы: инструменты, сравнивающие референсные страницы с заранее сохраненными скринами попиксельно и поднимающие шухер, если вдруг что-то куда-то съехало. Ghost Inspector, например.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Tue, 11 Nov 2025 07:50:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2166 at https://graker.ru</guid>
    </item>
<item>
  <title>Регистрация и логин через telegram-ботов в Laravel</title>
  <link>https://graker.ru/news/2025/11/06/laravel-register-and-login-with-telegram-bots</link>
  <description>&lt;p&gt;Недавно прикрутил к своей платформе телеграм-ботов возможность регистрироваться и входить в пользовательскую панельку сайта (ну или личный кабинет, если хотите). То есть, у тех ботов, для которых пользователю нужны веб-функции в личном кабинете, появляются кнопки регистрации и логина. Ну а если у бота такой «админки» нет, то не появляются.&lt;/p&gt;
&lt;p&gt;Далее немного расскажу, как это технически реализовано на Laravel (на котором написан Botopotamus.Ru).&lt;/p&gt;
&lt;p&gt;У Телеграма есть и свой механизм авторизации, но он подразумевает ручную настройку каждого бота, который должен это уметь. А я в данном случае рассматриваю код, который работает для всех ботов разом и его не нужно через Телеграм настраивать. Пользователь просто жмёт «Зарегистрироваться» в боте, а потом жмёт «Войти» чтобы получить ссылку на автологин.&lt;/p&gt;
&lt;p&gt;Под катом примеры с кодом.&lt;/p&gt;</description>
  <pubDate>Wed, 05 Nov 2025 22:00:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2163 at https://graker.ru</guid>
    </item>
<item>
  <title>С Днём программиста!</title>
  <link>https://graker.ru/news/2025/09/13/happy-programmers-day</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;С Днём программиста, программисты!&lt;/p&gt;
&lt;p&gt;Сегодня можно купаться в торрентах и громить интернет-кафе!&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Sat, 13 Sep 2025 12:40:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2141 at https://graker.ru</guid>
    </item>
<item>
  <title>Экономичные паттерны разработки</title>
  <link>https://graker.ru/news/2025/09/10/economical-software-design-patterns</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;В продолжение предыдущего поста — да, было бы здорово, конечно. Но где бы тогда я находил вот такие экономичные паттерны разработки:&lt;/p&gt;
&lt;h4&gt;Экономим 2 килобайта&lt;/h4&gt;
&lt;p&gt;Если во фронт-энде нужна иконка, и она уже есть в каком-то из установленных модулей, плагинов, библиотек, или иных зависимостей — не нужно копировать иконку в свой фронт.
Нужно использовать ту, что в библиотеке. Не важно, что разработчик библиотеки её может заменить, удалить, или вся зависимость окажется больше не нужна.
Просто никогда ничего не обновляйте, и тогда иконка пребудет веки.&lt;/p&gt;
&lt;h4&gt;Экономим две минуты&lt;/h4&gt;
&lt;p&gt;Допустим у тебя есть модуль или плагин, который больше не нужен. Но в то же время есть задача в трекере, совершенно с модулем не связанная, но для неё нужно написать немного кода. Правильный порядок действий:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Сотри всё что происходило в ненужном больше модуле.&lt;/li&gt;
&lt;li&gt;Вставь туда новый функционал.&lt;/li&gt;
&lt;li&gt;Описание и название модуля не меняй. Все равно никто не читает.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Экономим… что-то экономим&lt;/h4&gt;
&lt;p&gt;Определенно, это жемчужина моей небольшой и беспорядочной коллекции.
Нам нужно аяксифицировать кнопочки в Drupal. Чтобы события не навешивались повторно, используется &lt;code&gt;once()&lt;/code&gt;, который добавляет элементу атрибут &lt;code&gt;data-once=&quot;ajax&quot;&lt;/code&gt;. Но чтобы враги ничего не поняли, сделаем так:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Кнопочки будем рендерить сразу с атрибутом &lt;code&gt;data-once=&quot;ajax&quot;&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;В коде JS первым делом удалим этот атрибут!!&lt;/li&gt;
&lt;li&gt;Скрестим пальцы и вознадеемся на правильный порядок исполнения и что вызов ajax-биндинга произойдет позже и не заметит удаленных атрибутов!!!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Возможно, таким образом пытались победить какие-то «гонки» в JS. Ведь, как известно, чтобы победить racing condition, нужно самому стать racing condition.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Wed, 10 Sep 2025 08:55:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2138 at https://graker.ru</guid>
    </item>
<item>
  <title>Как новичку попробовать в Test Driven Development</title>
  <link>https://graker.ru/news/2025/08/04/test-driven-development-tryout-for-newbies</link>
  <description>&lt;p&gt;Сегодня поговорим о Test Driven Development, то есть о разработке, движимой тестами. О том, с чего вообще она начинается, как начать писать код, и как продолжить. Для примеров будем использовать Laravel, в этом фреймворке многое заточено под тесты, примеры наглядные и лаконичные. Поехали.&lt;/p&gt;
&lt;p&gt;В литературе по тестированию и TDD в частности очень любят приводить в пример тест, что функция &lt;code&gt;sum(a, b)&lt;/code&gt; успешно складывает два числа. Сложно представить что-то более вредное для демонстрации методики. Этот пример:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;скучный — поскольку по сути ничего не проверяет и ничего не демонстрирует;&lt;/li&gt;
&lt;li&gt;практически бесполезный — поскольку изначально не нуждается в тестировании*;&lt;/li&gt;
&lt;li&gt;не представляет собой важную функцию в нашем проекте*.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;* если только мы не пишем реализацию математической библиотеки для какого-либо устройства, но там тесты будут совсем другие&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Попробуем сделать пример получше. Итак, чтобы удачно стартануть в проекте с TDD, нужно совершить очень важный первый шаг. Выбрать первую фичу, которую мы хотим реализовать, и написать…&lt;/p&gt;</description>
  <pubDate>Mon, 04 Aug 2025 07:45:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2131 at https://graker.ru</guid>
    </item>
<item>
  <title>Laravel Livewire — вход по имени пользователя или электронной почте</title>
  <link>https://graker.ru/news/2025/07/15/laravel-livewire-login-by-name-or-email</link>
  <description>&lt;p&gt;Если поставить Laravel Starter Kit с Livewire внутри, который мы в прошлый раз &lt;a href=&quot;/news/2025/06/15/add-more-volts-to-your-livewire&quot;&gt;немного поизучали&lt;/a&gt;, то у нас сразу, из коробки будет поддержка аутентификации. Но — только по электронной почте и паролю. А заказчики могут хотеть (и хотят) чтобы можно было входить с помощью логина, либо вместо почты, либо в качестве альтернативы. Причины могут быть разные, не будем зацикливаться. Вместо этого давайте посмотрим, как сделать, чтобы можно было использовать и логин, и почту в качестве идентификатора пользователя при входе.&lt;/p&gt;
&lt;p&gt;Начнём как положено, с тестов. В &lt;code&gt;tests/Feature/Auth&lt;/code&gt; у нас есть &lt;code&gt;AuthenticationTest.php&lt;/code&gt;, в котором уже находятся дефолтные тесты аутентификации. Выберем главный опорный тест, на базе которого проведем изменения...&lt;/p&gt;</description>
  <pubDate>Tue, 15 Jul 2025 07:05:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2126 at https://graker.ru</guid>
    </item>
<item>
  <title>Макрос getOrFail в Laravel</title>
  <link>https://graker.ru/news/2025/07/05/getorfail-macro-in-laravel</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;В Ларавеле есть удобный хелпер-метод: &lt;code&gt;firstOrFail()&lt;/code&gt;, позволяющий получить по заданному запросу из БД первую найденную модель, либо вывалиться в 404, если моделей не найдено. Удобство в том, что использование хелпера позволяет избавиться от необходимости отдельно проверять наличие результата.&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;$page = ContentPage::where(&amp;#039;slug&amp;#039;, $slug)-&amp;gt;firstOrFail();&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;вместо&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;$page = ContentPage::where(&amp;#039;slug&amp;#039;, $slug)-&amp;gt;take(1)-&amp;gt;get();

if ($page-&amp;gt;isEmpty()) abort(404);&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;Очевидно, первый вариант лаконичнее и читабельнее.&lt;/p&gt;
&lt;p&gt;Так вот, хотелось бы, чтобы то же самое можно было делать, когда мы хотим загрузить &lt;em&gt;несколько&lt;/em&gt; моделей, или уйти в 404, если не нашли ни одной. То есть чтобы был хелпер-метод &lt;code&gt;getOrFail()&lt;/code&gt;, который делает то же, что и firstOrFail, но возвращает несколько моделей.&lt;/p&gt;
&lt;p&gt;Для этого можно написать макрос. В Laravel есть такой трейт, Macroable, и классы, которые его используют, можно расширять своими макро-методами. Расширим класс &lt;code&gt;Illuminate\Database\Eloquent\Builder&lt;/code&gt;. Добавим в &lt;code&gt;AppServiceProvider&lt;/code&gt;:&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;public function boot(): void
{
    // ...

    Builder::macro(&amp;#039;getOrFail&amp;#039;, function () {
        return tap(
            $this-&amp;gt;get(), 
            fn ($results) =&amp;gt; abort_unless($results-&amp;gt;count(), 404)
        );
    });
}&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;теперь мы можем писать, например, так:&lt;/p&gt;&lt;/div&gt;
&lt;pre data-component-id=&quot;grakerru:code-block&quot; class=&quot;code-block language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;$contentPages = ContentPage::where(&amp;#039;slug&amp;#039;, $slug)-&amp;gt;getOrFail();&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;и получим либо коллекцию моделей ContentPage, либо ошибку 404, без необходимости отдельно проверять, что коллекция не пустая.&lt;/p&gt;
&lt;p&gt;P.S. Да, &lt;code&gt;slug&lt;/code&gt; в данном примере не уникальный, может быть несколько моделей с одинаковым &lt;code&gt;slug&lt;/code&gt;. Вместо этого у меня есть уникальный ключ &lt;code&gt;[&#039;slug&#039;, &#039;language&#039;]&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Sat, 05 Jul 2025 11:25:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2121 at https://graker.ru</guid>
    </item>
<item>
  <title>Вдарим вольтом по лайвваеру</title>
  <link>https://graker.ru/news/2025/06/15/add-more-volts-to-your-livewire</link>
  <description>&lt;p&gt;На днях начал работу над новым проектом, и выдался хороший случай попробовать Livewire и Volt с ним, с последней версией Laravel. Про Livewire в последних версиях Ларавела я раньше слышал и читал, но руки как-то не доходили. А теперь дошли и сейчас мы познакомимся с ним поближе.&lt;/p&gt;
&lt;h3&gt;Что такое Livewire&lt;/h3&gt;
&lt;p&gt;Что вообще такое Livewire? Это фреймворк, позволяющий разрабатывать динамичные интерфейсы прямо на PHP. Как гласит главная страница фреймворка:&lt;/p&gt;
&lt;blockquote&gt;Powerful, dynamic, front-end UIs without leaving PHP.&lt;/blockquote&gt;
&lt;p&gt;То есть «мощные, динамичные фронт-энд интерфейсы, не покидая PHP». Ничего не понятно, но очень интересно. Ну, я немного разобрался (прочитал документацию!) Этот фреймворк позволяет нам, путём вставки специальных директив типа &lt;code&gt;wire:model.live=&quot;filter&quot;&lt;/code&gt; прямо в blade-шаблон, в html какого-нибудь инпута, сделать этот инпут динамическим. Или, как раньше говорили, его аяксифицировать.&lt;/p&gt;
&lt;blockquote&gt;То есть заставить элемент отправлять запросы на сервер без перезагрузки страницы и обновлять соответствующий view по данным в ответе на запрос&lt;/blockquote&gt;
&lt;p&gt;И это — без необходимости писать JavaScript-код, вообще. И хотя мы в примере ниже немного JS-кода напишем, это, строго говоря, действительно необязательно.&lt;/p&gt;</description>
  <pubDate>Sun, 15 Jun 2025 13:30:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2112 at https://graker.ru</guid>
    </item>
<item>
  <title>Пример разработки feature-теста с помощью ИИ</title>
  <link>https://graker.ru/news/2025/03/06/ai-feature-testing-example</link>
  <description>&lt;p&gt;Недавно писал, что очень неплохо получается с помощью ИИ делать юнит- и фича-тесты. А в этой заметке решил разобрать подробнее, на примере, как это выглядит.&lt;/p&gt;

&lt;p&gt;Для определенности уточню, что использую я плагин Codeium для Visual Studio Code под Linux, тариф бесплатный. Никаких дополнительных настроек не применял, на сайте указано что плагином используются Chat GPT, Claude, DeepSeek и Gemini. Проект, с которым я работаю, написан на Laravel, в нём есть такая функция — на определенный route можно отправить post-запрос с сообщением, и это сообщение будет отправлено телеграм-ботом в соотвествующий чат.&lt;/p&gt;

&lt;p&gt;Эта функция уже написана, на неё есть тесты, и она работает. А в данном примере мы создадим feature-тест, проверяющий ограничение на количество сообщений в день в соответствии с тарифным планом пользователя. Такого функционала в проекте еще нет, я его хочу создать в соответствии с методикой TDD. То есть сначала написав тест, а затем последовательно запуская его и исправляя появившиеся ошибки.&lt;/p&gt;

&lt;p&gt;Вот для написания данного feature-теста я и применю ИИ. Открываем подходящий для теста файл, жмём Ctrl+I. Чат жопотэ, поехали!&lt;/p&gt;</description>
  <pubDate>Thu, 06 Mar 2025 10:30:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2091 at https://graker.ru</guid>
    </item>
<item>
  <title>ИИ или младший разработчик?</title>
  <link>https://graker.ru/news/2025/02/18/ai-vs-junior-dev</link>
  <description>&lt;div class=&quot;paragraph paragraph--text&quot;&gt;&lt;p&gt;В новостях все чаще появляются заголовки типа «Растратбанк уволил и больше не нанимает младших разработчиков». Внутри обычно намёк на повальное применение ИИ-ассистентов, дескать они легко заменяют младших разрабов (джунов) и экономят деньги. Ну с банками всё понятно, они не обеднеют. А что делать нам, маленьким студиям, скромным командам и &lt;a href=&quot;/news/2019/05/09/company-of-one&quot;&gt;компаниям-из-одного&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Если вы фанат отдачи строгих инструкций «Напиши класс A в котором есть вот этот список методов b(), c(), d(), e(), а также вот этот список тестов для них» и с пристрастием, до буквы проверяете результат, то только ИИ позволит сохранить остатки рассудка. Кодить надо строго одному, и желательно где-нибудь в глухом лесу.&lt;/p&gt;
&lt;p&gt;Если же вы уже научились делегировать задачи в более крупную клетку и проверять качество исполнения, а не буквоедствовать, джун точно лучше ИИ. Особенно в долгосрочной перспективе — ведь он не всегда джуном будет.&lt;/p&gt;
&lt;p&gt;Ну а на самом деле нужно и кодить с ИИ, и давать отдельные задачи джуну. Которому хотя бы на время стажировки лучше запретить самому включать ИИ. Чтобы тот не смущал неокрепший мозг своими электрическими овцами.&lt;/p&gt;&lt;/div&gt;
</description>
  <pubDate>Tue, 18 Feb 2025 08:45:00 +0000</pubDate>
    <dc:creator>graker</dc:creator>
    <guid isPermaLink="false">2087 at https://graker.ru</guid>
    </item>

  </channel>
</rss>
