Всё о назначении и применимости Наблюдателя и Цепочки Обязанностей
Это десятая серия курса «Паттерны и практики написания кода»: вместе с бэкенд-инженером Юрой Афанасьевым продолжаем изучать тему Поведенческих паттернов. В новом эпизоде разбираем два подхода, связанных с отправкой и обработкой событий: Наблюдатель и Цепочка Обязанностей.
Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.
Это большая тема, о которой можно говорить очень много. Самое главное, что возможности применения ограничиваются только вашей больной фантазией. Вы строите интерфейс своего модуля или плагина и вам нужно подтянуть данные из сторонней системы (список чего-нибудь по какому-нибудь API), чтобы сохранить выбранный id в Joomla. Или сделать какую-то проверку и в зависимости от неё показать то или иное сообщение пользователю. Для этого подойдут свои пользовательские типы полей.
Интерфейс Joomla по большей части описан в XML-файлах. У каждого из них свои параметры. Некоторые не описаны в документации (manual.joomla.org), поэтому самым любопытным будет полезно заглянуть в собственно файлы фреймворка по пути libraries/src/Form/FormField.php, а так же в libraries/src/Form/Fields. У каждого класса поля перечислены его специфические свойства, которые можно описывать в XML. А в своём типе поля вы можете устанавливать эти значения программно.
В моём модуле WT Quick links под капотом происходят изменения. Теперь для работы (в админке) ему нужен вспомогательный плагин. А в самом модуле нам бы проверить, а не выключен ли он?
В Joomla есть тип поля Note - заметка. Его можно использовать для вывода примечаний.
<field type="note"
name="your_note_for_user"
label="Заголовок примечания"
title="Альтернативный способ для заголовка"
description="Текст примечания"
class="col-12 alert alert-info"
heading="h1"
close="true"
/>
heading- указывать уровень заголовка. close - позволяет закрыть это примечание.
В классе поля libraries/src/Form/Field/NoteField.php описана логика вывода. И в принципе оно нам подходит для нашей задачи. Но оно будет выводить сообщение всегда, а нам нужно только тогда, когда плагин отключён.
Поэтому берём и создаём свой класс поля, который мы унаследуем от NoteField. Это значит, что у нас в руках будет весь инструментарий стандартного поля Note + то, что мы сами добавим.
addfieldprefix - указываем namespace к нашему классу, может быть любой нам нужный
name - нельзя полю без имени...
Это означает, что Joomla будет использовать класс поля из файла modules/mod_wt_quick_links/src/Fields/SystempluginstatusField.php. А в классе поля будет написано следующее:
<?php
// namespace для атрибута addfieldprefix
namespace Joomla\Module\Wtquicklinks\Site\Fields;
// нельзя напрямую обращаться к этому файлу
defined('_JEXEC') or die;
// подключаем родительский класс для переопределения
use Joomla\CMS\Form\Field\NoteField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
// имя класса и имя файла точь-в-точь
class SystempluginstatusField extends NoteField
{
protected $type = 'Systempluginstatus'; // тип поля без "Field" в конце
protected function getLabel()
{
// если плагин не включён
if(PluginHelper::isEnabled('system','wtquicklinks')) {
// меняем свойства родительского класса поля
$this->class = 'alert alert-danger w-100';
$this->element['label'] = '⚠️ А-а-а-а!';
$this->element['description'] = 'Плагин не включён!!';
// и просто рендерим его с нашими свойствами
return parent::getLabel();
}
// А иначе всё хорошо, скрываем поле из виду.
$this->parentclass = 'd-none';
return '';
}
}
Просто и удобно. И людям приятно, что о них позаботились и рассказали почему что-то не работает.
В новом эпизоде курса «Паттерны и практики написания кода» вместе с бэкенд-инженером Юрой Афанасьевым продолжаем тему Поведенческих паттернов. На рассмотрении следующие два подхода: Команда и Посредник — разберёмся, какие задачи они решают, как выглядят соответствующие UML-диаграммы, а также какие особенности следует учитывать при реализации в коде.
Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.
Это восьмая серия курса «Паттерны и практики написания кода», где вместе с бэкенд-инженером Юрой Афанасьевым открываем новую тему — Поведенческие паттерны. Данная группа самая обширная из всех изученных, поэтому в новом эпизоде постепенно разберём первые два подхода: Стратегия и Состояние.
Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.
В развитие темы Bare Metal VM, над которой я время от времени размышляю начиная аж с 2010 года, предлагаю ознакомиться с интересным и, на мой взгляд, перспективным проектом OSv.
Ещё в 10-м году я подумывал над тем, что имея сервера приложений наподобие Томката и серьёзную взрослую изоляцию на уровне загрузчика классов - можно выкинуть подлежащую ОС со всеми её ненужными сервисами из нашего стека, оставив сервер приложений на голом железе. Тогда же выяснилось, что не я один так думаю, было коммерческое предложение Oracle JRockitVE. Судя по всему, наследница вот этого приобретения Bea.
Ранее я уже писал статью об этой идее на Хабре и пытался защищать в дискуссии.
Можно попробовать снова.
Ещё можно смотреть на развитие ОС на базе грааля. Или вспомнить про JaOS.
К современным ОС типа Линукса у меня есть много претензий, и есть несколько идей, которые можно было бы реализовать для их улучшения. Некоторые из них описаны в указанном проекте. Некоторые в том или ином виде наличествуют в специализированных коммерческих предложениях (Юникс) крупных вендоров типа АйбиЭм или того же Оракла. Это касается, например,
файлово-дискового стека,
оптимизации сети,
использования ГПУ в неожиданных местах,
гибкости в использовании СУБД при разработке с контейнером.
В каждой компании, где я работал, были свои правила формализации и постановки обнаруженных багов. Чаще всего - никаких правил. Что нашел тестировщик, то отписал в комментарии к задаче (и это еще хорошо!), а иногда просто на созвоне обсудил с разрабом, тот быстро пофиксил и факт найденного бага остался между ними. Для мелких студий так работать, может, и допустимо, но рано или поздно отсутствие элементарного порядка начинает надоедать. И тут появляются вопросы:
Как оформить баг? Комментарий к задаче? Отдельная задача? Чек-лист в описании задачи?
Как отметить баг выполненным? Проверенным? Повторно проявившимся?
Какая система багтрекинга вам показалась наиболее удобной? Jira? Youtrack? Яндекс.Трекер? Битрикс24? Что-то из новомодного импортозамещения?
Какие шаблоны описания бага приняты в вашей компании? Нет правил? Шаг 1 - шаг 2 - шаг 3 - ожидание - реальность? Скриншот со стрелочками? Видеозапись с экрана?
Есть ли какая-то классификация багов? Минор / мажор? Бэк / фронт? Бэклог / критикал?
Очень интересует ваш опыт в данной теме. Буду очень признателен, если поделитесь своими знаниями в комментариях.
Какую тему для книги можно выбрать в 2025? Современный мир — насыщенный мир. Книг выходит очень много. Как, интересно, можно выбрать тему для книги? От этого зависит конечная аудитория книги всё-таки. Микросервисы? Внедрение зависимостей? Ещё что-нибудь? Я в смятении. А выбирать пора уже. Полгода как прошлая книга вышла...
Не успели начать июнь с грандиозных планов? У нас есть отличный способ встряхнуться и достичь своей цели — 5-дневный IT-челлендж с 16 по 20 июня.
Пять дней, пять тем: Linux, сети, Docker, SQL, безопасность. Вас ждут вопросы и практические задания в формате Google Форм. А чтобы в будничной суете не забыть об испытаниях, Telegram-бот напомнит о челлендже и поведёт вас по шагам.
Победители получат ценные призы, среди которых:
🔥 Подписка на курсы Слёрма
🔥 Курс «Администрирование Linux»
🔥 Курс «Ansible: Infrastructure as Code»
Для самых стойких участников, дошедших до конца — скидка 30% на все курсы.
В cедьмой серии курса «Паттерны и практики написания кода» разберем три последних подхода в теме Структурных Паттернов: Мост, Заместитель и Приспособленец. Вместе с бэкенд-инженером Юрой Афанасьевым посмотрим, как паттерны реализуются в коде и в чём состоит их ключевое назначение.
Подписывайтесь на канал AvitoTech в Telegram, там мы рассказываем больше о профессиональном опыте наших инженеров, проектах и работе в Авито, а также анонсируем митапы и статьи.
Обновляем платформу SourceCraft и открываем доступ к ней для всех разработчиков
Сегодня Yandex B2B Tech открыла публичный доступ к платформе для разработки SourceCraft и представила её новые возможности. В платформу интегрированы инструменты безопасности, которые обеспечат защищённую разработку программных продуктов. А в ИИ‑помощнике SourceCraft Code Assistant появился чат‑режим, что увеличит скорость и эффективность разработки.
Удобство командной работы повысится за счёт бранч‑ и ревью‑политик, встроенных в интерфейс, а также аутентификации через SSO. Также появляется возможность зеркалирования репозиториев с GitHub и публичный API.
Инструменты безопасности
На платформе стали доступны инструменты безопасной разработки: сканер секретов в коде и анализ зависимостей в кодовой базе.
По данным исследования аналитиков Forrester интеграция инструментов безопасности в разработку на 81% снижает трудозатраты на ИБ‑поддержку всего проекта.
Чат‑режим в SourceCraft Code Assistant
ИИ‑помощником SourceCraft Code Assistant пользуются десятки тысяч разработчиков. Теперь в нём доступен чат‑режим, интегрированный непосредственно в среду разработки. В диалоговом режиме на естественном языке можно задать вопрос ИИ‑ассистенту, сгенерировать код, юнит‑тесты, документацию. Это ускорит поиск необходимой информации и оценку предлагаемых решений. Функциональность доступна в плагинах для VSCode и IDE от JetBrains.
Зеркалирование и бесшовная миграция
Миграция проектов с GitHub становится бесшовной — кроме кода переносятся Issues, PRs, Labels, Milestones, Comments. Также можно выбрать ветки для зеркалирования — непрерывной синхронизации кода.
Также появился федеративный доступ к платформе для компаний — авторизация через SSO.
Публичный API
Благодаря появлению публичного API платформа становится расширяемой. Пользователь сможет взаимодействовать с SourceCraft и обеспечивать автоматизацию и интеграцию с другими приложениями. Первая версия публичного API доступна для управления задачами, список будет пополняться.
Правила работы с ИТ‑проектами
В интерфейсе платформы появились бранч‑ и ревью‑политики — правила работы с ветками и проверками кода, которые интегрируются в систему контроля версий и процессы CI/CD.
Опенсорс
Появился анонимный доступ к публичным репозиториям платформы.Пользователи SourceCraft смогут создавать независимые копии репозиториев (forks) опенсорс‑проектов. Это позволит вносить персональные изменения, не затрагивая напрямую исходную кодовую базу. При этом копия сохраняет связь с оригиналом для получения обновлений.
Удобство работы с кодом
Интерфейс платформы теперь позволяет просматривать структуру файлов для шести языков программирования: Python, C++, Java, Go, TypeScript и JavaScript. Функциональность навигации по коду стала умнее и аналогично теперь поддерживает 6 языков.
Автоматизация CI/CD‑процессов
Среди обновлений, связанных со сборкой и развертыванием кода, появились self‑hosted runners — теперь можно запускать задачи как на виртуальных машинах Yandex Cloud, так и в своём окружении. Также появились flavours — теги для пользовательских задач, за счёт которых можно выбирать, где запускать задачу. Помимо этого в интерфейсе платформы появилась возможность не только разрабатывать, но сразу публиковать мобильные приложения в App Store, Google Play, RuStore, Huawei AppGalery.
Packages
Появилась возможность создавать и использовать собственные программные пакеты популярных форматов: наборы кода, библиотек, модулей или компонентов. Разработчик сможет хранить их в персональном облаке, привязанном к организации SourceCraft, и использовать в своих проектах. Packages также интегрированы с CI/CD платформы.
Вход в SourceCraft реализован через Яндекс ID аккаунт. Зайти на обновлённую платформу можно на сайте SourceCraft.
На днях в офисе я столкнулась с коллегами из направления системного программирования в «Криптоните». Они пишут на С++ — а ошибки на этом языке у нас ещё не было!
Поэтому я попросила их придумать код с ошибкой специально для Хабра — и вот что получилось!
Итак, есть ли в этом коде проблема кроме narrowing conversion? Ждём ваши варианты в комментариях.
#include <cstdint>
#include <vector>
struct Type
{
Type(uint16_t, uint32_t = {})
{}
};
int main()
{
std::vector<Type> vector;
std::uint32_t object_id{};
// Есть предупреждение о narrowing conversion
vector.insert(vector.begin(), {0, object_id});
// Нет narrowing conversion
vector.push_back({0, object_id});
// Нет narrowing conversion
vector.insert(vector.begin(), Type{0, object_id});
}
АККУРАТНО, ДАЛЬШЕ СПОЙЛЕР!
Проблема в том, что в строке
vector.insert(vector.begin(), {0, object_id});
в вектор вставляется 2 элемента типа Type, а не один, как ожидает программист.
Причина в том, что метод insert у вектора имеет перегрузку (номер 5), которая вторым параметром принимает std::initializer_list. А компилятор, видя фигурные скобки в коде, в первую очередь пытается создать объект такого типа.
И тут ему это удается, потому что у конструктора Type второй параметр имеет значение по умолчанию, следовательно, Type умеет создаваться, если в конструктор передали только один аргумент. В итоге компилятор успешно создает std::initializer_list с двумя элементами типа Type.
Так как создание std::initializer_list выполняется с использованием uniform initialization, то компилятор следит за корректностью преобразований. В примере объект типа std::uint32_t передается в конструктор Type, который принимает первым параметром std::uint16_t. То есть, возникает риск потери точности (32 бита не могут поместиться в 16 бит).
Об этом компилятор и предупреждает. Вот упрощенный пример, где видим то же самое предупреждение.
Может возникнуть вопрос, почему создание Type от 0 не вызывает предупреждение, ведь 0 - это int, а он, скорее всего 32 бита и тоже не помещается в 16 бит. Но тут литерал. Компилятор видит, что 0 вмещается в 16 бит и не предупреждает. Но если поместить int в переменную, то также возникает предупреждение.
Positive Technologies представляет новую версию PT NAD 12.3.
Главное в продукте: повышение производительности, плейбуки и возможность хранения метаданных в облаке.
🗓️ 5 июня на онлайн-запуске PT NAD 12.3 вы сможете узнать, как команда продукта трансформирует подход к обнаружению сетевых атак за счет централизованного управления, опции хранения метаданных в облаке и плейбуков.
📌 Добавляйте слот в календарь: 5 июня, 14:00.
В программе:
🔻 Экспертиза: обновленные модули, репутационные списки и плейбуки — чтобы ваша команда могла быстрее реагировать на угрозы;
🔻 Центральная консоль: как сократить затраты на команду мониторинга и контролировать атаки во всех филиалах из единой точки;
🔻 «Облако» vs локальные хранилища: гибкое хранение метаданных для экономии денег без потери скорости;
🔻 Скорость: оптимизация производительности для ускорения анализа угроз и обработки трафика даже в крупных сетях.
✍️ Регистрируйтесь на онлайн-запуск PT NAD 12.3 по ссылке.
Что обсудили: — рабочий день техлида, — горизонтальное vs вертикальное развитие: что выбрать, — сложности руководства командой, — опыт работы в Германии и возвращения, — почему Юрий выбрал МойОфис, и как у нас устроена инженерная культура, — как развиваться самому и развивать продукт.
Хотите стать техлидом или просто узнать, что значит вести команду? В этом выпуске — кейсы и честные истории про задачи и людей.
За 5 лет, что я проектирую API, вывела для себя шесть базовых принципов, которых стараюсь придерживаться:
Проектировать для потребителя
Ориентироваться на потребности клиентов API, а не на простоту реализации или устройство базы данных. Об этом, кстати, подробно написано в отличной книге Лоре Арно “Проектирование веб-API”.
Учитывать интересы всех клиентов. Не забывать, что могут появиться новые клиенты.
Сложную логику реализовывать на сервере. Искать баланс между универсальностью API и нагрузкой на клиента, исходя из реалий проекта.
Проектировать понятные API-схемы
Наименования и структуры должны быть максимально прозрачными, ясными и лаконичными.
Избегать обобщающих наименований, типа “flag”. Описывать в названии, какой бизнес-смысл несет этот параметр или метод. Например, флаг с признаком пустой упаковки можно назвать “isEmpty”.
Человек при прочтении схемы должен без дополнительной документации понять, зачем нужен этот API и что он делает.
Отдавать адекватные текстовые коды ошибок, из которых будет однозначно понятно, что поправить в запросе для успешного его выполнения. Например, отдавать не 400 BAD_REQUEST, а 400 PRODUCT_NOT_FOUND.
Принять конвенции и придерживаться их
Использовать везде либо snake_case, либо camelCase, либо kebab-case, не менять правила от метода к методу.
Стандартизировать формат ошибок - во всех методах отдавать их в одинаковой структуре.
Если это HTTP, то зафиксировать, в каких случаях какие коды ответов будут возвращаться. Например, иногда возвращается всегда 200, а потребители ориентируются только на тело ответа.
Договориться о формате версионирования API.
Стандартизировать типы данных: формат дат, UUID и пр.
Думать о безопасности, производительности и надежности
Использовать аутентификацию, авторизацию и ACL. Разграничивать доступ на уровне конкретных методов и даже параметров.
Сначала писать документацию, а только потом разрабатывать. Такой подход минимизирует количество ошибок и проблем с API.
Помечать изменения тегами задач и, при необходимости, цветом.
Описывать логику работы методов/топиков/очередей. При необходимости добавлять диаграммы последовательности и маппинги данных.
Мониторить и анализировать
Понимать, какие методы как часто вызываются и как быстро работают. Как быстро обрабатываются сообщения в очередях и топиках, какое их количество и размеры. Это важно для принятия решений о дальнейших доработках API.
Смотреть в консоли разработчика на проде, как быстро отрабатывают те или иные запросы и т.д.
По возможности настраивать системы мониторинга и алертинга. Это помогает прогнозировать рост нагрузки и отслеживать эффективность системы.
У каждого API‑проектировщика со временем появляется свой набор правил. Было бы интересно сравнить — добавляйте свои пункты в комментариях.
Другие мои материалы можно почитать в телеграм-канале breakfront.
Выбор облачной архитектуры — это не только про экономию, но и про грамотное распределение ресурсов.
Поговорим об этом на бесплатном вебинаре в рамках нового проекта FinOps.
11 июня, в 17:00 по МСК встречаемся с технологическим евангелистом VK Cloud Станиславом Погоржельским и будем обсуждать облачные решения: как снизить затраты и повысить эффективность.
Вместе:
разберём частые ошибки компании при использовании облачных технологий;
оценим важность сетевых сервисов;
посмотрим на примере ПО, как неверный выбор ресурсов для приложения может привести к непредсказуемым последствиям;
обсудим резервное копирование и как его игнор может поставить под угрозу весь бизнес.
Устройство компилятора (кратко) на LLVM Компилятор - инструмент конвертации исходного кода, написанного на высокоуровневом языке программирования в машинный код, который может исполнять компьютер.
Компилятор делится на 3 этапа:
FRONTEND - анализирует текст исходного кода и преобразует его в IR.
MIDDLE - анализирует и оптимизирует этот сгенерированный код IR.
BACKEND - преобразует IR в машинный код.
Сам компилятор, и собственно язык программирования состоит из нескольких частей.
Lexer - лексер
Лексер сканирует и превращает сырой текст в токены. То есть сам исходный код разбиваеты на набор токенов (такие как литералы, идентификаторы, ключевые слова, операторы, разделители) Лексер читает исходный код символ за символом и идентифицирует последовательности символов, соответствующие определённым правилам языка.
Парсинг
Парсинг немного сложнее чем лексический анализ. Существует множество паресров и парсеров-генераторов.
Парсеры в компиляторах обычно принимают входные данные в форме токенов и строят определенное дерево - AST или дерево парсинга.
Обычно компиляторы строятся из множества маленьких компонентов, которые берут входные данные, меняют их или преобразуют их в различные выходные данные. Это одна из причин, по которым функциональные языки хорошо подходят для создания компиляторов. Другие причины — прекрасное сопоставление с эталоном и довольно обширные стандартные библиотеки. Прикольный факт: первая реализация компилятора Rust была на Ocaml.
Советую держать эти компоненты как можно более простыми и автономными — модульность сильно облегчит процесс. По-моему, то же можно сказать и о многих других аспектах разработки ПО.
AST
AST - абстрактное синтаксическое дерево. Это структурированное представление исходного кода программы в виде дерева, где каждый узел дерева представляет собой синтаксическую конструк языка программирования. Это дерево предоставляет абстракцию, которая позволяет анализировать и манипулировать программным кодом на высоком уровне.
IR
Эта часть занимается созданием [[1.2 IR]]. Через примитивы LLVM мы можем сгенерировать промежуточное представление. Каждому типу в AST дается метод, называемый codegen, который всегда возвращает объект значение LLVM, используемый для представления одного регистра присваивания (single assignment register), который является переменной для компилятора, которая может быть назначена только один раз. Интересно, что в этих примитивах IR то, что в отличии от ассемблера, они не зависят от какой-либо конкретной архитектуры машины, и это значительно упрощает работу для разработчиков языков, которым больше не нужно сопоставлять вывод в набор инструкций процессора. Теперь, когда фронтенд может генерировать IR, инструмент LLVM Optimizer используется для анализа и оптимизации сгенерированного кода. Он выполняет несколько проходов по IR и выполняет такие действия как устранение мертвого кода и скалярная замена агрегатов, и, наконец, это приводит нас к бекенду, где мы пишем модуль, который принимает IR в качестве входных данных, который выдает объектный код, который может работать на любой архитектуре.