Обновить

Бэкенд

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

Если вы занимаетесь разработкой, не пропустите

У нас недавно выходили подборки полезных образовательных материалов для тех, кто хочет расти в ИТ. Заглядывайте:

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

Приглашаем на бесплатный вебинар «За кулисами Java: Секреты памяти, которые разгонят ваше приложение».

🕓 Когда: 25 декабря, 16:00–17:00 (Мск)

👨‍🎓 Спикер: Прощаев Сергей — эксперт в области Java.

Содержание:

✔️ Архитектура памяти в JVM: тонкости работы стека и кучи (Java 8+).

✔️ Фундаментальные проблемы параллелизма: видимость, упорядоченность, атомарность.

✔️ Сравнительный анализ инструментов синхронизации: synchronized, volatile, атомарные классы из java.util.concurrent.atomic.

✔️ Практические рекомендации по выбору инструментов для оптимальной производительности и надёжности.

Вы узнаете:

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

➕ Как избегать распространённых ошибок, связанных с управлением памятью.

➕ Какие best practices применяют в отраслях с жёсткими требованиями к отказоустойчивости.

Для участия желательны базовые знания Java на уровне Middle и понимание основ многопоточности.

👉 Записаться

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

Выкладываем все карты на стол —

Запустили IT Poker с K2 Cloud. Шоу, в котором сильнейшие девелоперы и техлиды показывают, на что способен их скиллсет.

Собрали 12 айтишников из ведущих компаний за столом для покера, но вместо обычной колоды приготовили технологии, сервисы и архитектурные решения. Представьте: в одной руке у игрока — API Gateway, в другой — брокер сообщений, а на флоп внезапно ложится Load Balancer.

Кто дойдёт до конца и сорвёт банк? Справятся ли инженеры без ИИ и техдоков?

Смотреть первые выпуски и болеть за своих уже можно в VK Видео и на YouTube.

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

Как написать свой линтер на Go?

Бэкенд-инженер AvitoTech Вячеслав Овчинников на стриме Go live-Coding разобрал механику линтеров и то, как работать с AST Go-проектов. Слава показал, что создание собственного правила — это не магия, а понятный и довольно увлекательный процесс. На стриме он:

  • написал простой, но полноценный линтер;

  • показал, как парсить AST и анализировать типы;

  • добавил своё правило и нашел проблемные конструкции в коде;

  • подключил линтер к golangci-lint.

Специально для вас мы сделали запись стрима, рекомендуем к просмотру всем, кому интересна тема линтеров на Go.

Запись стрима также есть на YouTube.

В ноябре Александр Кувакин, backend-инженер в команде Engineering Excellence AvitoTech, рассказывал в статье на Хабре о том, как backend-разработчикам выстраивать систему тестов на бэкенде. В тексте Саша разобрал основные проблемы и тесты, которые проверяют бизнес-логику. Почитать можно вот по этой ссылке.

А вот здесь вы найдете еще больше материалов по Go — статьи, видео, подкасты.

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

Где учиться DevOps?

На Хабр Карьере мы собрали все полезные курсы в одном месте, чтобы вам не пришлось тратить свое время на поиски и сравнения.

А сегодня — подборка по одному из самых востребованных направлений в IT. Если хотите разобраться в DevOps с нуля или системно прокачать навыки — поглядите курсы по основным инструментам:

— Kubernetes. Оркестрация контейнеров, масштабирование сервисов и управление сложной инфраструктурой.

— Docker. Упаковка приложений в контейнеры для удобного запуска и переноса между средами.

— CI/CD. Автоматизация сборки, тестирования и доставки кода в продакшн.

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

— Linux. Основа серверной среды и ключевой навык для работы с инфраструктурой.

→ А еще у нас есть курсы на любой вкус и кошелек — посмотрите

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

Метод registerListeners() в CMSPlugin в плагинах планируется удалить в Joomla 7.0.

Этот метод регистрирует устаревшие слушатели событий в диспетчере, имитируя работу плагинов Joomla! 3.x и ниже для Joomla 4+. По умолчанию этот метод ищет все общедоступные методы, название которых начинается с on. Он регистрирует лямбда-функции (замыкания), которые пытаются преобразовать аргументы отправленного события в аргументы вызова метода и вызвать ваш метод on<Нечто>. Результат передаётся обратно событию в его аргумент result.

Теперь этот слой совместимости с устаревшей Joomla 3 помечен к удалению в Joomla 7.0, которая должна выйти осенью 2027 года. Это означает, что те уникальные расширения от Joomla 2.5 / Joomla 3, которые ещё работали на Joomla 4-6 скорее всего окончательно перестанут работать на Joomla 7. Предполагается, что активные разработчики планомерно и постепенно избавляются от технического долга и обновляют свои расширения 😎

Чат русскоязычного Joomla-сообщества.

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

Усыпальница Java

Java обычно воспринимают как "тихую гавань" стабильности и обратной совместимости. Но на самом деле внутри неё постоянно кипит жизнь: язык и платформа меняются, обрастают новыми API и возможностями, а старые решения постепенно отправляются на покой в виртуальную усыпальницу.

В новой статье мы разберёмся, чем именно наполняется эта усыпальница и почему. Поговорим о legacy-коллекциях Java, финализаторах, Nashorn, SecurityManager и легендарном Unsafe. Какие задачи они решали? Какие архитектурные и эксплуатационные проблемы породили? И, конечно, разберём, какие современные альтернативы пришли им на смену.

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

Где учить английский язык?

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

Мы понимаем, что цели у всех разные: одни хотят прокачать разговорную речь, другие — освоить профессиональную лексику. Подумали и собрали подборку курсов по самым разным направлениям в изучении языка. Ловите:

• Разговорный английский. Говорим уверенно без языкового барьера.

• Письменный английский. Письма, сообщения, документы и четкие формулировки.

• Английский с носителем языка. Практикуем свободную речь и произношение.

• Деловой английский. Для встреч, переговоров, презентаций и рабочей переписки.

• Английский для IT. Профильная лексика и упор на деловое общение.

→ На Хабр Карьере есть курсы под разные цели и уровни — заглядывайте к нам на витрину.

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

Баги на всех языках мира. Проверка LanguageTool

Всем привет! Hello, everyone! Hallo zusammen! Hola a tothom! مرحباً بالجميع!

В нашем блоге мы часто говорим про статический анализ, линтеры и подобные инструменты. Но на этот раз мы нашли их довольно интересного представителя! LanguageTool — это многоязычная программа проверки орфографии, стилистики и грамматики, которая помогает исправлять и перефразировать тексты.

В новой статье заглянем в её код и посмотрим на интересные вещи, которые нашёл в нём статический анализатор кода PVS-Studio: от утечек ресурсов и логических противоречий в условиях до дублирующихся ключей в хеш-таблицах, избыточных проверок и мёртвого кода.

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

Ожидается до минус 30...

... процентов скидки на IT-курсы от практикующих экспертов!

Условия простые:

➖ 1 курс: скидка 15% до 21.12 включительно, далее скидка будет уменьшаться
➖ 2 курса: -25%
➖ 3 курса: -30%
➖ Годовая подписка: -20%

Несколько советов, как правильно выбрать курс:

1) Выбирайте курс, после которого останется что‑то на руках.
Полезные и применимые на практике артефакты: репозиторий, проект, пайплайн, дашборды, шаблоны, чек‑листы. Если на выходе только конспекты и общие слова — это скорее лекции, которые вряд ли принесут карьерный рост.

2) Контент — вторично. Важнее обратная связь.
Узнайте заранее: кто и как проверяет домашки, есть ли ревью, разбор ошибок, можно ли задать вопрос и получить ответ. Без этого курс превращается в просмотр видео «для вдохновения».

3) Сопоставьте программу с требованиями рынка и карьерной целью.
Посмотрите 20–30 вакансий на нужный грейд и выпишите, что там реально требуют. Потом сравните с программой: покрывает ли она скиллы, за которые платят, или уводит в редкую экзотику.

Выбрать своё

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

36 бесплатных IT-уроков недели от практиков

Привет, Хабр. Делимся подборкой бесплатных открытых уроков, которые пройдут на этой неделе в Otus. Опытные практики проведут занятия онлайн — сможете узнать больше о формате обучения и задать вопросы экспертам. Занятия проходят по вечерам, в 19 или 20:00 по мск. Выбирайте свою тему и присоединяйтесь!

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

🐧 Linux для начинающих. Подробнее

📊 Основы SQL. Подробнее

🔀 Основы Git. Подробнее

🧑‍🎓 Выбор профессии в IT. Подробнее

15 декабря, понедельник

16 декабря, вторник

17 декабря, среда

18 декабря, четверг

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

📊 Multi-LLM Orchestrator v0.7.0: подсчёт токенов и мониторинг через Prometheus

На этой неделе вышел релиз v0.7.0 — завершена фаза observability. Теперь библиотека автоматически считает токены, оценивает стоимость запросов и экспортирует метрики в Prometheus. Всё работает из коробки.

Предыдущие релизы:

🔢 Автоматический подсчёт токенов

Библиотека автоматически считает токены для каждого запроса — и для prompt, и для completion. Используется tiktoken с fallback на оценку по словам.

from orchestrator import Router
from orchestrator.providers import GigaChatProvider, ProviderConfig

router = Router()
router.add_provider(GigaChatProvider(ProviderConfig(
    name="gigachat",
    api_key="your_key",
    model="GigaChat",
    verify_ssl=False
)))

# Токены считаются автоматически
response = await router.route("Напиши стихотворение про Python")

# Получаем статистику
metrics = router.get_metrics()
print(f"Total tokens: {metrics['gigachat'].total_tokens}")
print(f"  Prompt: {metrics['gigachat'].total_prompt_tokens}")
print(f"  Completion: {metrics['gigachat'].total_completion_tokens}")

Результат:

Total tokens: 75
  Prompt: 20
  Completion: 55

💰 Оценка стоимости запросов

Расчёт стоимости в реальном времени. Цены настраиваются в pricing.py (фиксированные значения для демонстрации — для production рекомендуется настроить под свои тарифы).

Результаты тестов с реальными провайдерами:

  • GigaChat: 75 tokens → ₽0.0750

  • YandexGPT: 105 tokens → ₽0.1575

  • Streaming: 342 tokens → ₽0.3420

📈 Интеграция с Prometheus

HTTP-эндпоинт /metrics в формате Prometheus. Метрики обновляются в реальном времени и готовы для scraping.

# Запускаем metrics server
await router.start_metrics_server(port=9090)

# Делаем запросы
await router.route("Привет!")

# Метрики доступны: http://localhost:9090/metrics

Экспортируемые метрики:

  • llm_requests_total — количество запросов

  • llm_request_latency_seconds — histogram латентности

  • llm_tokens_total — токены (prompt/completion)

  • llm_cost_total — стоимость в RUB

  • llm_provider_health — health status (0-1)

Готово для визуализации с Grafana.

🏗️ Архитектура

Router → Metrics Engine → Prometheus Exporter → Grafana.
Router → Metrics Engine → Prometheus Exporter → Grafana.

✅ Тестирование на реальных провайдерах

Все функции протестированы с production API и реальными ключами:

Подсчёт токенов:

  • ✅ GigaChat — 75 токенов, ₽0.0750 (стихотворение про Python)

  • ✅ YandexGPT — 105 токенов, ₽0.1575 (объяснение ML концепции)

Streaming-режим:

  • ✅ GigaChat — 342 токена, ₽0.3420 (генерация длинного текста)

Prometheus endpoint:

  • ✅ HTTP /metrics — корректный формат, все метрики экспортируются

Качество кода: 203 теста • 81% покрытие • mypy strict без ошибок


📦 Установка

pip install multi-llm-orchestrator==0.7.0

Новые зависимости: prometheus-client, tiktoken, aiohttp

🎯 Планы на v0.8.0

В следующей версии планируется добавить:

  • Динамическое обновление цен — автоматическое получение актуальных тарифов через API провайдеров

  • Provider-specific tokenizers — нативные токенизаторы для GigaChat и YandexGPT (вместо универсального tiktoken)

  • Расширенная аналитика латентности — percentiles p50, p95, p99 для детального анализа производительности

  • Cost analytics — уведомления о превышении бюджета, детальная разбивка расходов по моделям

  • Prometheus Pushgateway — поддержка push-модели для serverless окружений

Если используете библиотеку — пишите в комментариях, какие функции нужны вам!

🔗 Ссылки

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

Required или нет?

Работая над одним из проектов, который недавно переехал из Framework 4.8 на Core 9, обнаружил множество самых разных вариантов использования модификатора required и атрибута Required, примерно каждый второй из которых был использован неправильно. Я написал это коллегам и хочу поделиться этим здесь. Это не обязательные правила, но сильно упрощают работу с кодом.

Небольшое пояснение

Атрибут Required нужен для проверки входящих преимущественно строковых данных в эндпоинтах. Возвращает ошибку, если значение null или пустая строка для строк (если не отключено параметром AllowEmptyStrings). Работает в Runtime. Также применяется в Entity Framework в подходе code-first но с включением опции <Nullable> в csproj про эти случаи можно забыть, сделав код чище.

Модификатор required нужен для обязательного указания значений полей при создании класса. Работает в Compile-time.

Примеры использования

// имеем класс с required полем
public class Example
{
    public required string Name { get; set; }
}

// пытаемся создать экземпляр в коде
var example1 = new Example();  // будет ошибка при попытке сборки проекта
var example2 = new Example { Name = string.Empty };  // тут ошибки не будет

// Вывод: модификатор required нужен для разработчика
// имеем класс с полем, у которого атрибут Required
public class Example
{
    [Required]
    public string Name { get; set; }
}

// пытаемся создать экземпляр в коде
var example = new Example();  // проект спокойно собирается

// имеем эндпоинт в контроллере
public IActionResult PostMethod([FromBody] Example model) => Ok();

/* передаём в теле запроса:
{}
или
{"Name": null}
или
{"Name": ""}
или
{"Name": "   "}
Получаем BadRequest с текстом ошибки. */

// передаём в теле запроса: {"Name": "name"}. Получаем OK.

// Вывод: атрибут Required нужен для пользователя

Как стоит и не стоит использовать.

public class BadExample
{
    public required string Field1 { get; set; } // 1
    
    public required string? Field2 { get; set; } // 2
    
    [Required]
    public required string Field3 { get; set; } // 3

    [Required]
    public string? Field4 { get; set; } // 4

    [Required]
    public int Field5 { get; set; } // 5

    public required int Field6 { get; set; } = 10; // 6
      
    public required List<int> Field7 { get; set; } // 7
}
  1. Ошибка, если класс используется как входящий параметр в эндпоинте. Соответственно, не стоит использовать, если десериализуем в него.

  2. Либо required, либо nullable.

  3. Надо выбрать одно из двух в зависимости от места использования.

  4. Либо Required, либо nullable. Тут даже AllowEmptyStrings = true не поможет.

  5. Required используется для строк. Но есть нюанс (*).

  6. Не нужно использовать required со значением по умолчанию.

  7. Не стоит усложнять жизнь, если поле можно проинициализировать при создании класса.

public class GoodExample
{
    public required string Field1 { get; set; } // 1
    
    [Required]
    public string Field2 { get; set; } = null!; // 2
    
    public string? Field3 { get; set; } // 3

    public int Field4 { get; set; } // 4

    public List<string> Field5 { get; set; } = []; // 5
}
  1. Хорошо где угодно за пределами эндпоинтов и десериализации, а значение не может принимать null.

  2. То что нужно для эндпоинта.

  3. Поле nullable. Поэтому никаких required.

  4. Не используем атрибут Required с не строками. Но есть нюанс (*).

  5. Избегаем использование required, проинициализировав коллекцию.

* - если передаётся json, в котором явно указано значение null ({"Field4": null}), то использование атрибута Required вернёт BadRequest.
Если же в json поле было опущено, то будет присвоено значение по умолчанию.

Надеюсь, это поможет сделать код чище и избежать неоднозначностей.

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

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

Компьютерное зрение для кода: что PVS-Studio разглядел в OpenCV

Что общего у компьютерного зрения и статического анализа? Оба ищут смысл в данных. OpenCV находит образы среди миллионов пикселей, а PVS-Studio — ошибки среди тысяч строк кода. Изучим же исходники крупнейшей библиотеки компьютерного зрения.

На примере 14 фрагментов кода из OpenCV предлагаю посмотреть, как статический анализ помогает избежать попадания багов в релиз и облегчить жизнь разработчикам.

Давайте посмотрим на кусок кода из проекта:

template<typename T>
struct Ptr : public std::shared_ptr<T>;
// ....
Ptr<FlannNeighborhoodGraph> FlannNeighborhoodGraph::create(....) 
{           
    return makePtr<FlannNeighborhoodGraphImpl>(....);
}

void Utils::densitySort (const Mat &points, int knn, 
                         Mat &sorted_points, std::vector<int> &sorted_mask) 
{
  // ....
  FlannNeighborhoodGraph &graph =                                      // <=
                         *FlannNeighborhoodGraph::create(....);

  std::vector<double> sum_knn_distances (points_size, 0);
  for (int p = 0; p < points_size; p++) {
    const std::vector<double> &dists = graph.getNeighborsDistances(p);
    for (int k = 0; k < knn; k++)
      sum_knn_distances[p] += dists[k];
  }
  // ....
}

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

  1. Функция create создаёт и возвращает умный указатель на тип FlannNeighborhoodGraphImpl, и его счётчик ссылок на объект равен единице;

  2. Создаётся ссылка graph на значение этого умного указателя, при этом счётчик ссылок на объект не изменяется;

  3. Указатель является временным объектом, и поэтому после завершения инициализации счётчик ссылок уменьшится до нуля, что приведёт к освобождению управляемого объекта. Теперь ссылка указывает на разрушенный объект;

  4. В цикле for происходит обращение к невалидной ссылке.

В итоге код, который казался правильным, приводит к неопределённому поведению. Кроме того, эту проблему находит не только PVS-Studio, но и санитайзер. Пруф.

Для исправления необходимо сохранить умный указатель, тогда объект типа FlannNeighborhoodGraph будет жить до конца блока. Можно сделать так:

std::vector<double> sum_knn_distances (points_size, 0);

{
  // get neighbors
  auto graph = FlannNeighborhoodGraph::create(....);

  for (int p = 0; p < points_size; p++) {
    const std::vector<double> &dists = graph->getNeighborsDistances(p);
    for (int k = 0; k < knn; k++) 
      sum_knn_distances[p] += dists[k];
  }
}

Дополнительно ограничили область видимости graph, чтобы ресурс освободился после выполнения циклов.

Хотите узнать больше?

Статический анализ выявляет скрытые дефекты даже в больших работающих проектах. Какие ещё опасные фрагменты кода мы нашли в коде OpenCV? Полный разбор можно найти в отдельной статье.

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

20 демо-уроков, которые нельзя пропустить бэкенд-разработчикам

Привет, Хабр. Сегодня делимся подборкой открытых уроков, которые пройдут в Otus в декабре. Уроки проводят преподаватели курсов в формате живых вебинаров — это шанс не только получить нужные знания, но и задать свои вопросы экспертам. Участие бесплатное (нужно только зарегистрироваться). Присоединяйтесь!

Полное расписание бесплатных демо-уроков смотрите в календаре.

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

Слои валидации

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

Валидация на клиенте (если он есть)

Сюда входит формат данных, обязательность полей и так далее. Чуть сложнее, когда надо проверять, например, уникальность имени пользователя или емейла, в этом случае придется ждать отправки или делать запросы на бекенд во время заполнения. Главное что надо знать про эту валидацию, то что она вспомогательная. Клиент всегда можно обойти и сделать запрос напрямую. Дублирование как ни крути, хотя и важно для UX.

Структурная валидация

Это валидация, которая, обычно, происходит на уровне самого фреймворка или в самом начале цикла обработки запроса. Для этого данные прогоняются через валидаторы json схемы, которая в идеале генерируется из openapi спеки. В самых деревянных случаях ручками (так делать не надо). Что важно понимать, это не доменная валидация (бизнес правила). Да тут можно проверить формат, наличие/отсутствие, но нельзя и не правильно пытаться проверять уникальность, выполнение каких-то условий, например количества денег на счету и тому подобное.

Кстати с точки зрения кодов ответа, на этом уровне несовпадение со схемой воспринимается не как ошибка валидации, а как неверный запрос с неверной структурой, а это код ответа 400.

Доменная валидация

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

Доменные проверки, как и клиентские могут дублироваться, если завязаны на консистентность базы данных. Например во многих фреймворках (с orm) есть валидация на уникальность, которая делает sql-запрос, но в документации у этого валидатора всегда написано, что это не надежно (из-за конкурентности) и в таких ситуациях обязательно делать индексы в базе данных.

В случае провала такой валидации, в api принято возвращать код 422

Валидация на уровне базы данных

Все предыдущие уровни не могут дать 100% гарантий, особенно учитывая, что данные в базе обновляются далеко не только по запросам снаружи. Поэтому есть вещи, которые обязательно делать на уровне базы данных. Сюда относятся уникальные индексы, внешние ключи (если делаете их), nullable, ограничение по длине и т.д. Технически многие базы данных позволяют писать кастомные валидации, которые соблазнительно использовать как доменную валидацию. Не надо этого делать :)

Проверка корректности данных

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

Подобные проверки делают в первую очередь на клиенте (и на этом можно было бы остановиться). Внутри бека их располагают в слое форм (есть далеко не во всех фреймворках), либо некоторые фреймворки типа rails для простоты пихают такой валидатор в модели, хотя семантически это неверно.

Больше про разработку в моем телеграм-канале Организованное программирование

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

Где учиться кибербезопасности?

На Хабр Карьере мы собираем для вас лучшие и самые актуальные курсы, чтобы обучение было максимально полезным.

Сегодня мы решили собрать для вас подборку курсов по кибербезопасности — одному из самых востребованных сейчас направлений в IT. Взгляните:

Защита информации. Шифрование, резервное копирование и защита от утечек данных.

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

Анализ вредоносных программ. Анализ вредоносного ПО (вирусы, трояны, программы-вымогатели) и разработка защиты.

Кибербезопасность. Общее направление: защищаем сети, системы и приложения от атак.

Системное администрирование. Администрирование серверов, сетей, IT-инфраструктуры, настройка прав и обеспечение стабильности работы систем.

Мониторинг сетей. Мониторинг сетевой активности, выявление аномалий и угроз, настройка систем обнаружения вторжений и анализ трафика.

→ Еще больше полезных курсов на нашей витрине

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

Совет по Joomla: использовать выключенное состояние для кнопок в списках элементов админки - listCheck().

Мы добавляем в тулбар панели администратора Joomla некую кнопку, которая что-то делает со списком id выделенных элементов и ajax-запросом отсылаем их в свой плагин. Но нам надо предупредить нажатия на кнопку в тех случаях, когда ни один элемент не был выбран. Для этого можно написать свою проверку на js. А можно воспользоваться встроенной в Joomla.

Добавить кнопку в тулбар Joomla 6.

use Joomla\CMS\Toolbar\Button\BasicButton;
use Joomla\CMS\Language\Text;

// ниже по коду, где-нибудь в плагине на onAfterDispatch()
// Предварительно проверяем в каком компоненте мы находимся по option из $app->getInput()
// пример из плагина, поэтому $this->getApplication()
$app = $this->getApplication();
// Берём текущий тулбар
$toolbar = $app->getDocument()->getToolbar('toolbar');

// Создаём кнопку
$button = (new BasicButton('send-to-indexnow'))
    ->text(Text::_('PLG_WTINDEXNOWSWJPROJECTS_BUTTON_LABEL'))
    ->icon('fa-solid fa-arrow-up-right-dots')
    ->onclick("window.wtindexnowswjprojects()");

// Добавляем кнопку в тулбар
$toolbar->appendButton($button);

Заблокировать кнопку тулбара Joomla, если не выбраны элементы списка.

Теперь нам надо проверить находимся ли мы в списке. Делаем это по view из $app->getInput().

if(in_array($app->getApplication()->getInput()->get('view'),
            ['categories','documentation','projects','versions'])
  ) {
        $button->listCheck(true);
}

И если мы в списке - используем метод $button->listCheck(true), который сделает проверку за нас. Если ни один элемент не выбран - кнопка в тулбаре Joomla будет заблокирована и JS-обработчик не будет вызван. Этот метод есть у всех классов кнопок, наследующих класс \Joomla\CMS\Toolbar\ToolbarButton.

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

Хочу немного поплакаться о поиске работы в IT…

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

Я — .NET backend-разработчик с опытом 6+ лет. Казалось бы, с таким бэкграундом я должен быть для HR вполне «лакомым кусочком». Но реальность оказалась совсем другой.

Постоянные отказы без объяснений. При том что резюме — нормальное, вычитанное, со смыслом. Все, кому я его показывал, говорили то же самое. И это, разумеется, бьёт по самооценке: появляется ощущение, что никому не нужен.

Складывается впечатление, что компании ищут кандидатов, которые совпадают с их стеком на 100%, и им плевать, что ту или иную технологию можно подтянуть за пару вечеров. Иначе я не могу объяснить, почему в вакансиях требуют конкретные библиотеки вроде Dapper или Autofac, которые изучаются буквально за вечер.

Есть ChatGPT и Gemini — хочешь, они разжуют любую тему. Но если в резюме не указал какую-то библиотеку — красный флаг. Отказ.
«Мы лучше ещё пару месяцев поищем кандидата, который совпадает на 100%, чем возьмём тебя». Примерно так это и выглядит.

А собеседования — отдельная песня.
По три этапа, каждый по часу. И ладно бы их можно было пройти за неделю, так нет — между этапами неделя перерыва. За это время уже как-то всё равно становится, возьмут тебя или нет. А когда после третьего этапа тебе в итоге не дают оффер — ощущение, что просто выкинул время в мусорку.

Про технические интервью я вообще молчу. Иногда спрашивают такую дичь, которая в реальной работе не нужна от слова «совсем». Например, у меня спросили разницу между структурой и классом. Я ответил по классике: копирование, расположение в памяти, наследование. Но от меня ожидали услышать ещё про блок синхронизации в объекте и почему структуры нельзя использовать в lock.
Может, я и читал это когда-то у Шилдта или Троелсена, но в реальной работе это знание ни разу не пригодилось.

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

И вот главный вопрос: зачем столько этапов?
Человек с каждым собеседованием становится опытнее, у него подвешивается язык, он понимает, что сейчас в моде спрашивать. Если где-то не ответил — проработает и на следующем собесе уже ответит. Так зачем превращать процесс в марафон длиной в месяц?

Да и честно говоря, всё равно все на собеседованиях врут. Потому что попробуй скажи правду — например:
«Мне надоело бесконечно ковыряться в легаси, поэтому я решил уйти».
Мгновенно получишь красный флаг.

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

А ещё последнее время любят оправдывать весь этот цирк «защитой от вкатунов с курсов».
Только проблема в том, что эта защита вообще не работает.

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

В итоге фильтруют не тех, кого нужно, а просто создают лишние барьеры.

Хотите проверить, что кандидат — не выпускник трёхнедельного курса? Попросите показать трудовую книжку. Я покажу без проблем — подтвердить реальные годы опыта для меня не проблема.

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

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

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

API First и Богатая доменная модель не являются взаимоисключающими понятиями, если правильно выстроить процесс и архитектуру.

Главная проблема: API First фокусируется на контрактах внешнего мира, что часто приводит к созданию DTO/Model классов, которые являются чистыми структурами данных без поведения (анемичная модель).

API First — это про контракты, а не про реализацию. Не позволяйте инструментам кодогенерации диктовать структуру вашей доменной модели!

Правильный workflow:

1. API Design First: Создайте/обновите OpenAPI спецификацию.

2. Генерация DTO: Сгенерируйте или создайте классы для API‑контрактов.

3. Projection First: Спроектируйте доменную модель независимо от DTO, фокусируясь на поведении и инвариантах.

4. Создание Mapping Layer: Напишите преобразователи между DTO и Domain Objects.

5. Реализация Application Service: Тонкий слой, который координирует работу домена.

Стек технологий, который помогает:

— MapStruct: Для автоматизации маппинга между DTO и Domain
— JUnit 5: Для тестирования доменной логики
— OpenAPI Generator: Для автоматической генерации DTO из спецификации
— ArchUnit: Для проверки архитектурных правил (например, запрет на анемичные модели)

// ArchUnit тест, проверяющий, что в доменных классах есть поведение
@ArchTest
static final ArchRule domain_models_should_have_business_methods = 
    classes()
        .that().resideInPackage("..domain..")
        .and().areAnnotatedWith(Entity.class)
        .should().containAnyMethodsThat(
            DescribedPredicate.describe(
                "have business methods", 
                method -> !method.getName().startsWith("get") && 
                         !method.getName().startsWith("set")
            )
        );
Теги:
Всего голосов 1: ↑0 и ↓1-1
Комментарии0