Как стать автором
Поиск
Написать публикацию
Обновить

Бэкенд

Сначала показывать
Порог рейтинга

Расширения и дочерние контейнеры в Joomla 5

Перевод с английского: Joomla! Programmers Documentation for Joomla 5.2

Всякий раз, когда Joomla загружает расширение, она создает дочерний Dependency Injection Container (далее контейнер), исключительно для использования этого расширения. Это показано на схеме ниже.

Child DIC
Child DIC

Дочерний контейнер содержит указатель на родительский контейнер и функционирует аналогично основному контейнеру, но с некоторыми отличиями:

  • При каждом вызове метода set() для этого дочернего контенера пара ключ-значение добавляется в дочерний контейнер;

  • При каждом вызове метода get() для этого дочернего контейнера ресурс извлекается из дочернего контейнера, но если он там не найден, то поиск выполняется также в родительском контейнере.

Начиная с версии Joomla 4, разработчики Joomla рекомендуют создателям расширений использовать внедрение зависимостей (dependency injection) для своих расширений, определяя файл services/provider.php. Загрузка расширения теперь выполняется в два этапа, которые обрабатываются внутри файла services/provider.php:

  1. Класс расширения регистрируется в дочернем контейнере;

  2. Класс расширения извлекается из дочернего контейнера, создавая экземпляр этого класса.

Давайте рассмотрим минимальный пример этого для компонента com_example с пространством имён Mycompany\Component\Example.

use Joomla\CMS\Extension\ComponentInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Mycompany\Component\Example\Administrator\Extension\ExampleComponent;
return new class implements ServiceProviderInterface
{
  public function register(Container $container): void
  {
    $container->set(
      ComponentInterface::class,
      function (Container $container)
      {
        $component = new ExampleComponent();
        return $component;
      }
    );
  }
};

Мы видим, что когда Joomla выполняет require этого PHP-файла, возвращается экземпляр класса.

$provider = require $path;  // $path points to the relevant services/provider.php file

Переменная $provider указывает на объект, который является экземпляром этого анонимного класса. Кроме того, класс реализует интерфейс Joomla\DI\ServiceProviderInterface, что, по сути, означает, что он содержит метод register с указанной выше сигнатурой.

Когда Joomla выполняет

if ($provider instanceof ServiceProviderInterface)
{
  $provider->register($container);

будет вызван метод register, который добавит запись в дочерний контейнер с

  • key - ComponentInterface::class – это сокращённый способ в PHP указать строку 'Joomla\CMS\Extension\ComponentInterface';

  • value - функция, которая возвращает новый экземпляр класса ExampleComponent (основного класса расширения компонента com_example).

$extension = $container->get($type);

Функция выше будет запущена и вернет новый экземпляр ExampleComponent.

Вы можете самостоятельно изучить код Joomla в файле libraries/src/Extension/ExtensionManagerTrait.php и убедиться, что описанный выше шаблон также применяется к модулям и плагинам.

Обратите также внимание на следующую строку в этом файле:

if ($extension instanceof BootableExtensionInterface)
{
  $extension->boot($container);
}

Таким образом, если класс расширения реализует интерфейс BootableExtensionInterface, Joomla немедленно вызовет метод boot() экземпляра расширения, как описано в документации по расширениям.

Теги:
Всего голосов 2: ↑2 и ↓0+3
Комментарии0

Поддержка должна быть бесплатной. Всегда!

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

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

Я основатель облака для простого деплоя проектов через Git push – Amvera Cloud. И вижу, что пользователи пишут нам в поддержку. И говоря честно – люди пишут только тогда, когда другие способы не помогли и они не знают, как решить их насущную проблему. А это значит мы не доработали и сделали что-то непонятно или неудобно. И это наша обязанность постараться им помочь. И я не вижу морального права просить за это с них деньги.

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

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

Поддержка должна быть бесплатной, всегда, и без всяких но! 

Теги:
Всего голосов 8: ↑7 и ↓1+6
Комментарии3

Почему не следует напрямую обращаться к глобальному контейнеру в Joomla 5

Что общего у нижеперечисленных методов?

  • Joomla\CMS\Factory::getCache()

  • Joomla\CMS\Factory::getDbo()

  • Joomla\CMS\Factory::getMailer()

  • Joomla\CMS\Application\AdministratorApplication::getRouter()

  • Joomla\CMS\Application\Administrator\ApiApplication::getRouter()

  • Joomla\CMS\Toolbar\Toolbar::getInstance()

Они объявлены устаревшими с Joomla 4.x и вместо них предлагается использовать Joomla\CMS\Factory::getContainer()->get('Соответствующий_интерфейс').

Например, вместо Joomla\CMS\Factory::getDbo()Factory::getContainer()->get(DatabaseInterface::class);

Но давайте посмотрим на описание метода Joomla\CMS\Factory::getContainer():

Возвращает глобальный контейнер сервисов, создавая его только в случае отсутствия.

Этот метод рекомендуется использовать только в коде, ответственном за создание новых сервисов и требующем разрешения зависимостей. Его следует применять только когда контейнер недоступен другими способами.

Допустимые сценарии использования:

  • Статический метод getInstance(), вызывающий сервис из контейнера (пример: Joomla\CMS\Toolbar\Toolbar::getInstance());

  • Фронт-контроллер приложения, загружающий и исполняющий класс Joomla (пример: файл cli/joomla.php);

  • Получение опциональных зависимостей конструктора во время переходного периода для сохранения обратной совместимости (в этом случае следует добавлять уведомление об устаревании).

Не рекомендуется использовать этот метод как прямую замену статическим вызовам, например заменять Factory::getDbo() на Factory::getContainer()->get(DatabaseInterface::class). Вместо этого код следует рефакторить для использования внедрения зависимостей.

В последнем абзаце видим явное противоречие и рекомендацию использовать зависимости.

Как же внедрять зависимости?

Рассмотрим как это сделано в плагине joomla группы content:

В сервис-провайдере плагина Root/plugins/content/joomla/services/provider.php используются методы setDatabase() и setUserFactory() для установки зависимостей.

$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));

А в классе расширения плагина plugins/content/joomla/src/Extension/Joomla.php используются методы getDatabase() и getUserFactory(). Аналогично в компонентах.

Мой пример использования:

В компоненте обновления цен для JoomShopping, в моделях работающих с товарами я заменил драйвер базы данных на свой, соединяющийся с базой другого сайта. Код самих моделей при этом изменять не потребовалось.

Выводы:

  • Сервис-провайдер расширения — единая точка установки зависимостей для своего расширения.

  • Событие onAfterExtensionBoot - точка для замены зависимости в любом расширении.

  • Если бы расширения напрямую брали зависимости из глобального контейнера, такая замена была бы невозможна.

Материалы по теме:

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Есть такая мантра в гошке - "всегда обрабатывать ошибки"

А ведь так хочется чтобы они сами наверх прокидывались...

Недавно работал с либой валидатора, и нашел функцию у которой можно не проверять ошибку так как если она не отработает то приложение не запустится в любом случае

То есть ошибка равна панике

validator.Register("", func any)
if err := validator.Register("", func(
  
); err != nil {
  return err
}

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

Теги:
Всего голосов 5: ↑3 и ↓2+3
Комментарии2

Обновления Dockhost: апрель 2025

Апрель подошел к концу, и мы знакомим вас с обновлениями на платформе, которые произошли за прошедший месяц.

Функционал передачи проекта другому пользователю.

Теперь вы можете передать свой проект другому пользователю, имеющему аккаунт на платформе (для этого пользователю заранее нужно предоставить доступ к проекту). Новая фича доступна в проекте в разделе "Настройки/Пользователи".

Функционал будет полезен студиям, фрилансерам и всем тем, кто занимается заказной разработкой. Важная особенность: после передачи проекта на баланс заказчику, вы можете (опционально) оставить доступ к проекту для осуществления поддержки.

Дополнения и доработки:

  • Исправлена ошибка, которая могла приводить к зависанию статуса контейнер

  • Для «Сетевых дисков» добавлена поддержка subPath, что позволяет подключать отдельные папки «Сетевого диска» к контейнеру.

  • Исправлена ошибка, которая могла приводить к разрыву соединения через «Сетевой сервис».

  • Исправлена ошибка, которая приводила к излишней буферизации в «Сетевые сервисы / Маршруты».

  • Исправлена ошибка веб-интерфейса, в результате которой общее количество ресурсов не обновлялось при удаление из проекта контейнера или сетевого диска

  • Максимальное значение для переменных было увеличено до 1024 символов.

Продолжаем развивать наш каталог и в апреле добавили 3 новых приложения:

Совместно с Российской платформой NextBox реализовали интеграцию в каталог приложений цифровой платформы для хранения и обработки данных.

NextBox помогает компаниям безопасно хранить и обмениваться корпоративными файлами, совместно работать с документами любых форматов в едином пространстве.

Также добавили 2 новых self-hosted приложения:

Redash - открытая платформа для визуализации данных и бизнес-аналитики, которая предоставляет простой интерфейс для создания дашбордов, запросов и отчетов. Сервис позволяет работать с различными источниками данных, включая базы данных, API и файлы, а также поддерживает создание пользовательских SQL-запросов для глубокого анализа информации.

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

Dockhost — облачная платформа для хостинга приложений на основе Docker‑контейнеров (боты, сайты, базы данных и т. д.), которая позволяет запускать и масштабировать как простые проекты, так и сложные микросервисные приложения без необходимости настраивать и контролировать инфраструктуру.

Теги:
Всего голосов 4: ↑3 и ↓1+3
Комментарии0

Нейронные сети в руках хакеров

Как вам такой сценарий. Некоторая группа специалистов по информационной безопасности (в плохом смысле) создаёт публичный сайт-прокси который рекламируется как бесплатное решение всех проблем программиста.

Когда программист делает запрос на генерацию кода скажем бекенда для веб сервера его запрос проксируется в ChatGPT, а потом модифицируется скриптом, который добавляет небезопасный код.

Попутно сайт собирает информацию о самом программисте, например, IP адрес, а в случае регистрации - email работодателя.

Информация сохраняется для разработки, через полгода-год когда код гарантировано попадает на прод происходит кибератака.

Теги:
Рейтинг0
Комментарии3

Читаемость Си-кода: грустный ликбез, чтобы жить стало веселее

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

И всему виной (ожидаемо) выражения препроцессора и, как следствие, макросы. Да, вы правильно подумали. Именно те части кода, в которых вызываются такие легенды как:

Последние два очень легко спутать, если читать код невнимательно. Вместо них иногда рекомендуют использовать

#if defined // вместо #ifdef
#if !defined // вместо #ifndef

Но если же в компании/проекте/отделе нет определенного код-стайла, или он не предполагает написание длинного варианта, то, естественно, разрабы пишут короткую форму (я, честно признаться, тоже).

Чего далеко ходить - все open source проекты пестрят именно сокращенными вариантами этих выражений и с этим уже ничего не поделаешь.

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

Конечно же выражения препроцессора - это очень гибкий и полезный инструмент, позволяющий делать всё:

  • условную компиляцию;

  • выравнивание структур;

  • предотвращать повторные включения файла;

  • работать со строками;

  • грамотно оборачивать повторяющийся код и т.д. и т.п.

Но бывают случаи, когда упрощение кода с точки зрения алгоритма делает его слабо читаемым для того самого бедного программиста, пытающегося прочесть этот шедевр машинописного текста:

struct {
  const char *name;
  const char *value;
#define _SPECIAL(x) { .name = #x, .value = b->x, }
} specials[] = {
  { .name = "object", .value = b->object_string, },
  _SPECIAL(host),
  _SPECIAL(endpoint),
#undef _SPECIAL
};

*ну все, можно начинать грустить*

Чтобы разобраться, давайте очистим код от макросов, но сохраним суть:

struct {
  const char *name;
  const char *value;
} specials[] = {
  { .name = "object", .value = b->object_string, },
  { .name = "host", .value = host, },
  { .name = "endpoint", .value = endpoint, },
};

Что понятно из очищенного варианта:

  • инициализируется массив specials[];

  • типом данных этого массива является структура с полями *name и *value;

  • поля элементов массива задаются вручную.

Но как можно этот процесс немного автоматизировать и не прописывать вручную одинаковые строки?

Правильно, с помощью макроса:

#define _SPECIAL(x) { .name = #x, .value = b->x, }

который определяется после объявления полей структуры.

Как обрабатывается аргумент x:

  • имя аргумента преобразуется в строку с помощью макроса "#x" и присваивается полю *name;

  • полю *value присваивается значение поля структуры b с названием аргумента x (тут нужно убедиться, что поле с именем x действительно существует в структуре b).

То есть чтобы при заполнении массива не писать каждый раз одинаковые строчки:

{ .name = "host", .value = host, },
{ .name = "endpoint", .value = endpoint, }

можно вызвать выражение _SPECIALS:

_SPECIAL(host),
_SPECIAL(endpoint),

Ну и в самом конце вызываем удаление созданного макроса, чтобы оно не было использовано в коде в дальнейшем:

#undef _SPECIAL

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

А какие выражения и макросы в Си видели вы?

Теги:
Всего голосов 7: ↑7 и ↓0+10
Комментарии2

🗯️ Про метрики на отдельном порту.

Далее про то как сделать выделенный порт и http-пулл для promitheus-метрик, так вот докладываю👇

Мы используем embedded tomcat как и великое множество других Java-проектов(остальным сил и терпения), по этому этот пост применительно к нему.

📍Для создания выделенного порта достаточно создать отдельный коннектор спринговой java-конфигурацией и проинициализировать его через TomcatServletWebServerFactory.

❕Стоит обратить внимание что на данном порту будут доступны вообще все сервлеты доступные и на стандартном порту, но при наличии разграничения доступа обычно это не является проблемой.

P.S. Не хочу быть злом по этому в комменты в свою телегу выложу класс в текстовом варианте😁

Теги:
Всего голосов 3: ↑1 и ↓2+1
Комментарии2

Опасности Apache POI 📍

Наверняка многие из вас юзают Apache POI. Для тех, кто не знает: это джаванская либа для работы с файлами Microsoft Office и OOXML — всякие Excel, Word и прочее.

А в чём опасность?

При генерации Excel-файла эта библиотека позволяет включить отслеживание ширины данных в колонках и автоподгонку ширины столбцов под содержимое (чтобы данные не скрывались из-за маленькой ширины столбца по умолчанию).

Включается это так:
// Отслеживаем ширину для автосайзинга
sheet.trackAllColumnsForAutoSizing();
// ... генерируем строки Excel-файла
// Автосайзим столбцы
sheet.autoSizeColumn(columnIndex);

Проблема: эта тема крайне ресурсоёмкая на больших объёмах данных. На тесте с 100 строками — всё быстро. На проде с 600К строк — 20 минут превращаются в 4 часа. 4 часа, Карл! Чего оно там делает вообще?!)

У нас такое не раз уезжало в прод и штука эта совсем неприятная я вам скажу:

  • Отчёт не собирается вовремя;

  • Заказчик негодует;

  • Паника, крики — в общем, ну его этот трекинг! 😅

Что делать?

В 99% случаев: достаточно автосайзинга только для заголовков:

// Включаем автосайзинг
sheet.trackAllColumnsForAutoSizing();
// Генерируем заголовки
//...
// Автосайзим колонки
sheet.autoSizeColumn(columnIndex);
// Выключаем трекинг
sheet.untrackAllColumnsForAutoSizing();
//... продолжаем генерацию

В 1% случаев: нужно отавтосайзить 1-2 столбца из сотен. Тогда делаем точечный трекинг:

// Трекинг только нужных колонок
sheet.trackColumnForAutoSizing(columnIndex);
// ... генерация данных
// Автосайзим
sheet.autoSizeColumn(columnIndex);

Ну и можно конечно вручную задавать ширину столбцов, но это не всегда удобно.

P.S. Метод autoSizeColumn() очень тяжёлый. Выдержка из джавадоки:

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

P.S.S. Еще кстати поя умеют не буферизовать весь excel’ник в память при генерации, надеюсь вы все этим пользуетесь ибо обратное дико некармическая тема)) Знаете ж как?

Приходите к телегу, там обсуждаем наши кровавые энтерпрайзы: https://t.me/umenyarabotaet

Теги:
Всего голосов 3: ↑2 и ↓1+2
Комментарии5

В 2ГИС мы пишем на Go и помогаем инженерам перейти на него с других языков. Знакомство с Go открывает возможность контрибьютить в одну из самых востребованных технологий современности. На Go написаны проекты, без которых сложно представить мир распределённых систем: K8s, CockroachDB, Badger, Prometheus, VictoriaMetrics, Jaeger, NATS, Temporal. 

Переход на Go — реальность! В карточках рассказываем, как это получилось у Саши

Хочешь так же? Прямо сейчас ищем ребят с Java и C#.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии8

Доброго дня. В этом посте хочу описать способ развертывания приложений в Docker на Linux сервере без использования реестра. Для этого нужно:

  1. Сохранение образа docker save -o myimage.tar myimagename

  2. Передача файл myimage.tar на сервер по FTP или любым другим способом

  3. Загрузка образа docker load -i myimage.tar или podman load -i myimage.tar

Такой способ позволяет разворачивать Docker‑образы без использования реестра — просто, удобно и быстро. Если у вас по любой причине нет реестра, но хочется использовать Docker, вы можете найти это полезным. Надеюсь, кому‑то пригодится в реальной практике. Если вы используете другие подходы или автоматизируете процесс — поделитесь в комментариях. Спасибо за внимание!

Теги:
Рейтинг0
Комментарии1

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

29 апреля, вторник:

30 апреля, среда:

5 мая, понедельник:

6 мая, вторник:

Список всех открытых уроков по всем ИТ-направлениям можно посмотреть в календаре.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

PEP 750: t-строки в 3.14

Недавно ревьюил один интересный PR в CPython: в питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций. Расскажу: как и зачем.

Основная причина: использовать f строки удобно, но нет никакого АПИ для перехвата момента "вставки" или интерполяции значений. Например, при форматировании html или sql – требуется специальным образом делать escape для значений. И раньше код вида f"{template}" представлял собой дыру в безопасности и потенциальное место для XSS.

string.templatelib.Template

Новый префикс t не будет создавать объект str, он будет создавать объект класса string.templatelib.Template:

>>> user = 'sobolevn'
>>> template = t"Hi, {user}"
>>> template
Template(strings=('Hi, ', ''), interpolations=(Interpolation('sobolevn', 'user', None, ''),))

>>> from string.templatelib import Template
>>> isinstance(template, Template)
True

Обратите внимание, что при создании template – у нас не произошло форматирование сразу. Мы создали объект, у которого есть свойства strings и interpolations, из которых можно собрать финальную отформатированную строку.

Давайте посмотрим на примере. Допустим, мы хотим формировать URL из наших данных:

>>> domain = 'example.com'
>>> query = 'python string formatting is too complex'
>>> template = t'https://{domain}?q={query}'

И сам код логики форматирования, где мы будем вставлять значения разным способом. Если у нас шаблон query, то мы будем использовать quote_plus для его форматирования. Остальные значения – будем вставлять как есть:

>>> from string.templatelib import Template, Interpolation
>>> from urllib.parse import quote_plus

>>> def format_url(template: Template) -> str:
...     parts = []
...     for part in template:
...         match part:
...             case str() as s:  # regular string
...                 parts.append(s)
...             case Interpolation(value, expression='query'):
...                 parts.append(quote_plus(value))
...             case Interpolation(value):
...                 parts.append(value)
...     return ''.join(parts)

И вот результат:

>>> format_url(template)
'https://example.com?q=python+string+formatting+is+too+complex'

Только теперь наш Template был отформатирован. Нами. Ручками.
У нас есть полный контроль за процессом форматирования. Вот в чем суть данного ПЕПа.

Фичи одной строкой

  • Работает = как обычно в f строках: t'{user=}'

  • Есть привычные определители формата: !r, !s, .2f, тд

  • t строки можно конкатенировать: t'Hello' + t' , world!' и t'Hello, ' + 'world'

  • Поддерживается режим raw строк: rt"Hi \n!"

Как устроено внутри?

Интересные места имплементации:

>>> import dis
>>> user = 'sobolevn'
>>> dis.dis('t"Hi, {user}"')
  0           RESUME                   0

  1           LOAD_CONST               2 (('Hi, ', ''))
              LOAD_NAME                0 (user)
              LOAD_CONST               1 ('user')
              BUILD_INTERPOLATION      2
              BUILD_TUPLE              1
              BUILD_TEMPLATE
              RETURN_VALUE

Обсуждение: как вам еще один способ форматирования строк?

Если понравилось – заходи в тг, где я рассказываю, как я делаю CPython.

Теги:
Всего голосов 10: ↑10 и ↓0+13
Комментарии7

Ближайшие события

Для себя я определил архитектуру так:

Архитектура программной системы - это набор ограничений, которые формируют и направляют реализацию системы в сторону максимизации её ценности

Архитектура - это набор ограничений
Архитектура - это набор ограничений
  • Это набор ограничений: архитектура задаёт рамки/правила по которым должна строиться система

  • Архитектура формирует и направляет реализацию: у разработчиков должна быть свобода в реализации, но архитектура задаёт для них ограничения

  • Архитектура максимизирует ценность: ограничения поставлены так, чтобы вписываясь в них система принесла больше ценности. Именно архитектура определяет: какими паттернами реализовывать бизнес-логику, как связываться со сторонними сервисами, из каких категорий будет состоять программный код

И я придумал для этого метафору. Представьте, что мы строим дом. Тогда:

Системный архитектор:
Нарисует чертежи всего дома (фасада, этажей). Задаст форму квартирам: сколько в квартире комнат, куда проведены трубы и электричество. Исходя из этого, сан-узел можно будет поставить только в одной комнате (куда проведены вода и канализация), а кухню только в другой (куда проведена вода и газ). Системный архитектор наложил на весь дом и на каждую квартиру верхне-уровневые ограничения: структурные (сколько в каждой квартире комнат, где сан-узел, где кухня, а где жилые комнаты) и поведенческие (это жилое помещение, а не склад или магазин). Но в какой комнате будет детская, а в какой рабочий кабинет - решать не ему.

Системный дизайнер:
Он как дизайнер интерьеров. Определяет назначение каждой комнаты, учитывая уже наложенные архитектурные ограничения. Где будет гостиная, где спальня, где рабочий кабинет и т.п. И расставляет мебель (структурные ограничения), руководствуясь назначением каждой комнаты (поведенческие ограничения). И всё это так, чтобы живущим в квартире людям было удобно.

Программист:
Это рабочий, который по чертежам дизайнера положит паркет, подключит фурнитуру и соберёт мебель.

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

  • Системный архитектор - senior (опытный программист, способный спроектировать кластер контейнеров)

  • Системный дизайнер - middle (программист, способный спроектировать один контейнер)

  • Программист - junior (любой программист, способный работать внутри контейнера по готовым ограничениям)

Теги:
Всего голосов 4: ↑3 и ↓1+2
Комментарии0

Работаем в лоб: Прямое редактирование XML форм Joomla

Используя событие onContentPrepareForm можно изменять почти любую форму Joomla, но методов класса Joomla\CMS\Form\Form обычно не хватает для работы со сложными формами (например с полями типа subform).

Но есть простое решение - работать с формой как c экземпляром SimpleXMLElement.

Получаем XML формы.

echo $form->getXml()->asXMl();
die;

Отправляем его в ChatGPT с описанием что и как надо изменить в форме, и просим написать PHP-код.

Например у меня такая форма:

<?xml version="1.0"?>
<form>
	<config>
		<fieldset label="PLG_CONTENT_WISHBOXRADICALMARTCDEKORDERREGISTRATOR_FIELDSET_LABEL" name="wishboxradicalmartcdekorderregistrator"
                  addfieldprefix="Joomla\Component\Wishboxradicalmartcdek\Administrator\Field">
			<field name="wishboxradicalmartcdekorderregistrator" type="subform"
                   label="PLG_CONTENT_WISHBOXRADICALMARTCDEKORDERREGISTRATOR_FIELD_REGISTRATOR_LABEL"
                   buttons="add,remove,move"
                   multiple="false"
                   hiddenLabel="true">
				<form>
					<fieldset>
						<field name="order_number_prefix" type="text"
                               label="COM_WISHBOXRADICALMARTCDEK_FIELD_ORDER_NUMBER_PREFIX_LABEL"
                               default="test_" />
					</fieldset>
				</form>
			</field>
		</fieldset>
	</config>
</form>

И для изменения атрибута default поля order_number_prefix получаем следующий код:

$fields = $xml->xpath('//field[@name="wishboxradicalmartcdekorderregistrator"]/form/fieldset/field[@name="order_number_prefix"]');

$fields[0]['default'] = 'Test ';

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

Теги:
Рейтинг0
Комментарии0

Coding Game. Mad Pod Racing. Игра для программистов.

Coding Game — это онлайн-платформа, которая помогает изучать программирование. В ней вы будете решать различные задачи и головоломки и игры, используя разные языки программирования. Игра доступна бесплатно и подходит для начинающих программистов.

Mad Pod Racing

Mad Pod Racing - это многопользовательская игра (соревнование) для программистов.

Ваша задача запрограммировать бота для победы в гонке на космическом корабле.

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

Теги:
Всего голосов 1: ↑1 и ↓0+2
Комментарии1

Что такое чистая архитектура: основные особенности

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

Как, по сути, работает чистая архитектура
Как, по сути, работает чистая архитектура

Какие еще свойства чистой архитектуры важны:

  1. Тестируемость. Это значит, что бизнес-правила могут быть протестированы без UI, без баз данных, без веб-сервера и без любого другого внешнего компонента. Например, у нас может быть фронтенд на React и мобилка на Flutter — и мы при этом всё равно можем менять контракты, не меняя бизнес-правила.

  2. Чистая архитектура независима от информационных хранилищ. Можно поменять PostgreSQL на MongoDB или на любую другую СУБД. При этом работа бизнес-правил не изменится. 

  3. Чистая архитектура — это независимость от внешнего сервиса. По факту слой use-кейсов изолирован от внешнего мира, ничего о нем не знает. А знает только о том, как работать в рамках бизнес-системы.

Большой материал о том, на каком проекте была внедрен этот подход и почему выбрали именно его, читайте в блоге.

Теги:
Всего голосов 2: ↑1 и ↓1+2
Комментарии2

Когда нельзя доверять даже себе

Экосистема JavaScript — обширная, гибкая и насыщенная готовыми решениями. Она позволяет без особых усилий подключать сторонние пакеты — как в браузере, так и на сервере. Но у этой открытости есть и обратная сторона: сторонний код может вмешиваться в ваш собственный. Хорошо, если это происходит явно. Но бывает иначе: кто-то оборачивает ваши функции, переопределяет методы, расширяет прототипы — и тихо выполняет свою «чёрную работу».

В такой среде доверие к собственному коду становится условным. Разработчик ещё способен более-менее контролировать точку входа — HTML-страницу или Node.js-скрипт. Он может доверять тому, что написал сам и вызывает сам. До тех пор, пока не подключит стороннюю библиотеку. А дальше — возможны любые сценарии.

Чтобы можно было доверять своему коду хоть немного больше, я пошёл на эксперимент и по умолчанию встроил "заморозку" всех объектов, создаваемых моим DI-контейнером:

let res = await _composer.create(key, module, stack, this);
if (canBeFrozen(res)) Object.freeze(res);

При запуске node-приложения (или при загрузке кода на веб-страницу) я создаю контейнер и через него получаю нужный объект со всеми зависимостями:

import Container from '@teqfw/di';

const container = new Container();
const resolver = container.getResolver();
resolver.addNamespaceRoot('App_', '/home/user/project/src');
const app = await container.get('App_Main');
app.run();

Поскольку все объекты, получаемые из контейнера, автоматически замораживаются, сторонний код не может изменить поведение уже созданной зависимости — даже если получит к ней доступ.

Разумеется, такой подход не делает JS-среду абсолютно безопасной. Но он позволяет немного повысить уровень доверия к тому, что происходит внутри.

Эта идея родилась после прений с коллегой @nin-jin — так что спасибо ему за подброшенную мысль ;) Я реализовал её в коде, опробовал на своих приложениях и вот теперь делюсь результатом.

Теги:
Всего голосов 3: ↑2 и ↓1+2
Комментарии7

Хотите разобраться, как работает Docker и зачем он нужен?

Тогда новый бесплатный курс — для вас!

Docker — это open source-платформа для создания контейнеров — окружений, где приложения работают независимо от ОС или среды. Технология упрощает перенос приложений между окружениями и ускоряет разработку.

В новом бесплатном курсе мы расскажем, с чего начать: как установить Docker, собрать образ, создать и запустить контейнер. Также познакомимся с Docker Compose и обсудим, чем Kubernetes отличается от Docker Swarm.

Несколько материалов для начала

Приступить к изучению курса →

Теги:
Всего голосов 5: ↑4 и ↓1+4
Комментарии0

Поздравляем с 0x8 марта девушек в IT!

В этом году мы решили не просто на словах поздравить девушек с праздником. Мы сделали видео с девушками и о девушках в IT. На то есть несколько причин:

  • Мы хотим сказать: коллеги, мы вам благодарны за ваш труд! Мы гордимся вами!

  • Мы хотим показать вам реальных людей из разных сфер IT, а не просто цифры в статистике.

  • Надеемся, примеры участниц покажут, что IT — это не для избранных. Здесь есть место каждой, если ей интересно и она этого захочет.

Смотрите видео по ссылкам:

Вдохновляйтесь, делитесь своими историями и отправляйте своим друзьям, коллегам, знакомым и всем, кто имеет отношение к IT!

А мы желаем всем айтишницам счастливого праздника, безопасности и простого человеческого счастья!

Теги:
Всего голосов 4: ↑4 и ↓0+6
Комментарии1