🎩 Книга «Денди-код» о том, как сделать код аккуратным и понятным

Я проанализировал более 150 тысяч вакансий и понял, почему TIOBE бесполезен

True index

Когда я начинал изучать программирование, передо мной встал классический вопрос: какой язык выбрать? Открыл TIOBE, посмотрел на топ-20… и запутался окончательно. Perl в топ-15? Assembly? Fortran? Когда вы последний раз видел вакансию с требованием Fortran?

Тогда я решил проверить гипотезу: насколько популярные рейтинги технологий соответствуют реальному спросу на рынке труда? Результаты оказались показательными.

Проблемы существующих рейтингов

Начнём с того, как работает TIOBE. Его методология основана на подсчёте поисковых запросов в различных поисковых системах. Звучит логично, но есть нюанс: поисковый запрос “Python tutorial” может делать как практикующий разработчик, так и студент, выполняющий курсовую работу. Visual Basic держится в топе во многом благодаря тому, что миллионы офисных работников гуглят “как написать макрос в Excel”.

Более того, в топ-20 TIOBE регулярно попадают языки вроде Assembly, Fortran и Ada. Да, эти технологии используются в узкоспециализированных областях (встроенные системы, научные вычисления, аэрокосмическая отрасль), но их доля в общем объёме разработки минимальна.

И самое важное: западные рейтинги полностью игнорируют региональную специфику. Они не учитывают особенности рынка СНГ, где есть свои лидеры и свои тренды.

Методология исследования

Я решил построить рейтинг на основе реальных данных о спросе. Для этого был разработан парсер, который собирает данные с платформ по поиску работы, в первую очередь с hh.ru, career.habr.com и других российских площадок.

Что анализируется:

  • Количество вакансий с упоминанием конкретной технологии
  • Частота упоминаний в требованиях к кандидатам
  • Динамика изменений (месяц к месяцу)

Технические детали:

  • База данных содержит информацию о более чем 150 000 вакансий
  • Обновление происходит ежемесячно
  • Технологии разделены на 10 категорий: языки программирования, фреймворки, библиотеки, СУБД, CMS, DevOps-инструменты, облачные платформы, серверное ПО, инструменты тестирования, средства безопасности, AI/ML, дистрибутивы Linux

Для каждой технологии рассчитывается нормализованный индекс популярности на основе количества вакансий. В будущем планируется добавить дополнительные метрики: активность на GitHub (количество репозиториев, stars, commits), обсуждения на Stack Overflow, статистику загрузок пакетов из npm, PyPI, Composer и других репозиториев.

Результаты: что показывает реальный рынок

Вот топ языков программирования по количеству вакансий:

Место Технология Индекс Комментарий
1 SQL 47.86 Ожидаемо: работа с БД требуется практически везде
2 Python 38.00 Универсальность: от веб-разработки до ML
3 32.89 Специфика российского рынка
4 C 26.48 Системное программирование, embedded
5 JavaScript 25.22 Веб-разработка, фронтенд и бэкенд
6 Java 21.68 Enterprise-разработка
7 C++ 20.93 Высоконагруженные системы, gamedev
8 PHP 18.66 Веб-разработка

Самые интересные находки

1С на третьем месте. Это выше JavaScript, Java и C++. В TIOBE этого языка вообще нет, потому что он не используется за пределами СНГ. Но для российского рынка это огромный сегмент: тысячи компаний работают на платформе 1С, и спрос на специалистов стабильно высокий.

PHP держится в топ-10. В TIOBE он на 14-м месте, про него регулярно пишут статьи в духе “PHP умирает”. На практике же PHP находится на 8-м месте по количеству вакансий. Причина проста: существует огромное количество работающих проектов на PHP, они требуют поддержки и развития. Это классический пример расхождения между “что популярно в теории” и “что нужно на практике”.

Отсутствие экзотических языков. В топ-20 нет ни Fortran, ни Ada, ни Prolog. Они есть в TIOBE, но реальный спрос на них в разы меньше.

Практическое применение

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

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

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

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

Планы развития

Текущая версия использует только данные о вакансиях. В планах добавить:

  • 🐙 GitHub – активность репозиториев, звёзды, коммиты
  • 💬 Stack Overflow – вопросы и обсуждения
  • 📦 Статистику загрузок – библиотек (npm, PyPI и так далее)
  • 👥 Активность комьюнити – конфы, митапы, сообщества

Все метрики будут нормализованы и объединены в единый индекс с весовыми коэффициентами для каждого параметра.

Результаты

Актуальный рейтинг доступен на trueindex.ru. Проект обновляется ежемесячно, данные находятся в открытом доступе.

Если интересно обсудить методологию, предложить улучшения или добавить новые технологии в отслеживание – пишите в комментариях или в Telegram @ihxnnxs.

Популярные рейтинги технологий часто оторваны от реальности рынка труда. TIOBE, основанный на поисковых запросах, показывает одну картину, а реальный спрос работодателей – совершенно другую.

Анализ более 150 000 вакансий показал:

  • Региональная специфика имеет огромное значение (1С в топ-3 для СНГ)
  • “Умирающие” технологии вроде PHP продолжают активно использоваться
  • Экзотические языки из топа академических рейтингов практически не встречаются в вакансиях

Для принятия решений о выборе технологий стоит опираться на данные реального рынка, а не на абстрактные индексы популярности.

P.S. Специально для laravel.su (и, возможно, для других сайтов, посвящённых статьям про PHP). Сам проект реализован на Laravel – если вам интересно, могу написать отдельную статью специально для вас, с конкретным стеком или с рассказом о проблемах и т. п. только дайте знать в комментах :)

2

Автоматизация в Laravel: как ускорить и упростить процесс разработки

Автоматизация в Laravel

Работа над проектом на Laravel становится заметно эффективнее, если автоматизировать как можно больше этапов — от конфигурации окружения до проверки кода и тестирования. В этом материале я расскажу, как сделать рабочий процесс надёжным, уменьшить ручную рутину и поддерживать качество кода на высоком уровне.

Материал рассчитан на тех, кто уже знаком с Laravel и хочет внедрить в проект автоматические проверки, единый стиль кода, статику и готовую Docker-инфраструктуру. Я поделюсь используемыми инструментами, примерами конфигураций и реалистичными скриптами.

Docker-Compose как основа окружения

Я всегда начинаю проект с продуманной конфигурации Docker Compose — это дает сразу готовое изолированное окружение, минимизирует конфликты зависимостей и ускоряет старт работы. Обычно в моём составе используются следующие сервисы:

  • php-fpm – выполнение PHP-кода приложения
  • PostgreSQL – реляционная база данных
  • Grafana + Loki – визуализация метрик и логов
  • pgAdmin – веб-интерфейс для управления БД
  • Redis – Кэш и очереди Laravel
  • Insight – визуализация данных Redis
  • Queue – выполнение фоновых задач
services:
    app:
        build: .
        container_name: pet
        user: root
        depends_on:
            - pgdb
            - redis
            - loki
        env_file:
            - .env
        working_dir: /var/www/
        volumes:
            - .:/var/www
        networks:
            - pet
        dns:
            - 8.8.8.8
            - 1.1.1.1

    pgdb:
        container_name: pgdb
        image: postgres
        tty: true
        restart: always
        environment:
            - POSTGRES_DB=${DB_DATABASE}
            - POSTGRES_USER=${DB_USERNAME}
            - POSTGRES_PASSWORD=${DB_PASSWORD}
        ports:
            - ${PGDB_PORT}
        volumes:
            - ./docker/postgres:/var/lib/postgresql/data
        networks:
            - pet

    nginx:
        image: nginx:latest
        container_name: nginx
        restart: unless-stopped
        ports:
            - ${NGINX_PORT}
            - "443:443"
        volumes:
            - .:/var/www
            - ./docker/nginx:/etc/nginx/conf.d
            - /etc/letsencrypt:/etc/letsencrypt:ro
        environment:
            - TZ=${SYSTEM_TIMEZONE}
        depends_on:
            - pgdb
            - app
            - pgadmin
        networks:
            - pet

    pgadmin:
        image: dpage/pgadmin4:latest
        restart: always
        depends_on:
            - pgdb
        environment:
            - PGADMIN_DEFAULT_EMAIL=${PGADMIN_EMAIL}
            - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PASSWORD}
        ports:
            - ${PGADMIN_PORT}
        networks:
            - pet

    redis:
        image: redis:latest
        container_name: redis
        restart: always
        ports:
            - ${REDIS_PORT}
        environment:
            - REDIS_PASSWORD=${REDIS_PASSWORD}
        command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
        networks:
            - pet

    redisinsight:
        image: redislabs/redisinsight:latest
        container_name: redisinsight
        ports:
            - ${REDISINSIGHT_PORT}
        volumes:
            - ./docker/redisinsight:/db
        restart: always
        networks:
            - pet

    grafana:
        image: grafana/grafana:latest
        container_name: grafana
        user: "472"
        ports:
            - ${GRAFANA_PORT}
        environment:
            - GF_SECURITY_ADMIN_USER=${GRAFANA_USER}
            - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
        volumes:
            - ./docker/grafana:/var/lib/grafana
        depends_on:
            - loki
        networks:
            - pet

    queue:
        build: .
        image: docker_template:latest
        container_name: laravel_queue
        restart: always
        depends_on:
            - app
            - redis
        env_file:
            - .env
        working_dir: /var/www
        volumes:
            - .:/var/www
        command: php artisan queue:work --sleep=3 --tries=3 --timeout=90
        networks:
            - pet
        dns:
            - 8.8.8.8
            - 1.1.1.1

    loki:
        image: grafana/loki:latest
        container_name: loki
        ports:
            - ${LOKI_PORT}
        networks:
            - pet

volumes:
    pgdata:
networks:
    pet:
        driver: bridge

Каждый из этих сервисов разворачивается в отдельном контейнере. Такой подход даёт преимущества:

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

Совет: можно использовать готовый шаблон docker-compose.yml, который сразу поднимает все сервисы и настраивает базовые параметры Laravel.

Поддержание единого стиля кода с Laravel Pint

Для автоматического форматирования и приведения к единому стилю я использую laravel/pint. Он позволяет:

  • автоматически исправлять стиль кода при запуске;
  • интегрироваться в CI или докерные сценарии;
  • соблюдать стандарт PSR-12 без ручных усилий.

Пример конфигурации pint.json:

{
    "preset": "psr12",
    "exclude": [
        "vendor",
        "storage",
        "node_modules",
        "bootstrap/cache"
    ],
    "rules": {
        "array_syntax": {
            "syntax": "short"
        },
        "binary_operator_spaces": {
            "default": "single_space"
        },
        "braces": true,
        "class_attributes_separation": {
            "elements": {
                "const": "one",
                "method": "one",
                "property": "one"
            }
        },
        "no_unused_imports": true,
        "ordered_imports": true,
        "phpdoc_separation": true,
        "phpdoc_align": true,
        "single_quote": true,
        "ternary_to_null_coalescing": true,
        "trailing_comma_in_multiline": {
            "after_heredoc": true
        },
        "types_spaces": {
            "space": "none"
        },
        "phpdoc_no_empty_return": false,
        "no_superfluous_phpdoc_tags": false,
        "concat_space": {
            "spacing": "one"
        }
    }
}

Такая конфигурация помогает стандартизировать стиль: синтаксис массивов, расположение операторов, форматирование импортов и PHPDoc.

Запуск Pint перед коммитом — хорошая практика, она поддерживает чистоту кода автоматически.

Статический анализ: PHPStan + Larastan

Чтобы ловить ошибки и потенциальные проблемы ещё на этапе разработки, я применяю комбинацию phpstan/phpstan и nunomaduro/larastan. Эти инструменты позволяют:

  • находить некорректное использование типов;
  • выявлять отсутствие проверок;
  • предупреждать баги до запуска приложения.

Пример конфигурации phpstan.neon:

parameters:
    level: 6
    paths:
        - app
        - routes
    excludePaths:
        - vendor
        - storage
        - bootstrap

    errorFormat: table
    checkMissingVarTagTypehint: false
    inferPrivatePropertyTypeFromConstructor: true

    ignoreErrors:
        - identifier: missingType.iterableValue
        - identifier: missingType.generics
        - '#referenced with incorrect case#'

includes:
    - vendor/phpstan/phpstan/conf/bleedingEdge.neon

Основные преимущества такого подхода:

  • ошибки фиксируются ещё до запуска функционала;
  • повышается надёжность и стабильность кода;
  • анализ становится частью процесса разработки.

Автоматические проверки через Git Hooks и shell-скрипты

Чтобы гарантировать, что все коммиты соответствуют стандартам, я применяю Git Hooks + shell-скрипты:

Основные идеи:

Pre-commit: проверка изменённых файлов обрабатываются только изменённые файлы (для скорости); запускаются Pint и PHPStan на этих файлах; при ошибках коммит блокируется до исправления.

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

Проверка наличия тестов Скрипт проверяет, что для любого нового или изменённого класса создан соответствующий тест в директории tests. Например, если добавлен класс app/Services/UserService.php, ожидается файл tests/Unit/Services/UserServiceTest.php.

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

Примеры скриптов

Скрипт для проверки с PHPStan (pre-commit / push)

Скрипт для проверки с PHPStan

#!/bin/bash
COMMAND="$1"  # commit или push

if [ "$COMMAND" = "commit" ]; then
  NEW_FILES=$(git diff --cached --name-only --diff-filter=A | grep '\.php$')
  if [ -n "$NEW_FILES" ]; then
    vendor/bin/phpstan analyse --no-progress --error-format=table $NEW_FILES || exit 1
  fi
fi

BASELINE_FILE=".phpstan-error-count.json"
[ ! -f "$BASELINE_FILE" ] && echo "{}" > "$BASELINE_FILE"

if [ "$COMMAND" = "commit" ]; then
  ALL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' || true)
elif [ "$COMMAND" = "push" ]; then
  BRANCH=$(git rev-parse --abbrev-ref HEAD)
  ALL_FILES=$(git diff --name-only origin/$BRANCH --diff-filter=ACM | grep '\.php$' || true)
fi

if [ -n "$ALL_FILES" ]; then
  for FILE in $ALL_FILES; do
    ERR_NEW=$(vendor/bin/phpstan analyse --error-format=raw --no-progress "$FILE" 2>/dev/null | grep -c '^')
    ERR_OLD=$(jq -r --arg file "$FILE" '.[$file] // empty' "$BASELINE_FILE")
    [ -z "$ERR_OLD" ] && ERR_OLD=$ERR_NEW

    TARGET=$((ERR_OLD - 1))
    [ "$TARGET" -lt 0 ] && TARGET=0

    if [ "$ERR_NEW" -le "$TARGET" ]; then
      jq --arg file "$FILE" --argjson errors "$ERR_NEW" '.[$file] = $errors' "$BASELINE_FILE" > tmp && mv tmp "$BASELINE_FILE"
    else
      echo "Ошибка статического анализа в $FILE: $ERR_NEW (допустимо ≤ $TARGET)"
      vendor/bin/phpstan analyse --error-format=table "$FILE"
      exit 1
    fi
  done
fi

exit 0

Скрипт для проверки Pint стиля

Скрипт для проверки Pint стиля

#!/bin/bash
COMMAND="$1"

if [ "$COMMAND" = "commit" ]; then
  ALL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$' || true)
elif [ "$COMMAND" = "push" ]; then
  BRANCH=$(git rev-parse --abbrev-ref HEAD)
  ALL_FILES=$(git diff --name-only origin/$BRANCH --diff-filter=ACM | grep '\.php$' || true)
fi

if [ -n "$ALL_FILES" ]; then
  vendor/bin/pint --test $ALL_FILES
  if [ $? -ne 0 ]; then
    vendor/bin/pint $ALL_FILES
    echo "$ALL_FILES" | xargs git add
    exit 1
  fi
fi

exit 0

Проверка наличия тестов для классов

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

Скрипт получает список изменённых и добавленных PHP-файлов и ищет соответствующий тестовый файл в директории tests.

Например, если в проекте есть класс app/Services/UserService.php, скрипт потребует создать файл теста tests/Unit/Services/UserServiceTest.php. Таким образом, любой новый или изменённый класс обязательно должен иметь соответствующий тест, что помогает поддерживать качество и надёжность кода.

Это скрипт, который постоянно дополняется, поэтому актуальную версию вы можете посмотреть здесь – https://github.com/prog-time/git-hooks

Скрипт для проверки Pint стиля

Проверка работы Docker сборки

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

Скрипт может автоматически останавливать текущие контейнеры, заново собирать их и запускать в фоне. После запуска выполняется проверка состояния через docker ps или docker compose ps, чтобы убедиться, что все контейнеры находятся в статусе healthy или up.

#!/bin/bash

echo "=== Остановка всех контейнеров ==="
docker-compose down

echo "=== Сборка контейнеров ==="
docker-compose build

echo "=== Запуск контейнеров в фоне ==="
docker-compose up -d

# Пауза для запуска сервисов
echo "=== Ждем 5 секунд для старта сервисов ==="
sleep 5

echo "=== Проверка состояния контейнеров ==="
# Получаем статус всех контейнеров
STATUS=$(docker-compose ps --services --filter "status=running")

if [ -z "$STATUS" ]; then
  echo "Ошибка: ни один контейнер не запущен!"
  exit 1
else
  echo "Запущенные контейнеры:"
  docker-compose ps
fi

# Дополнительно можно проверять HEALTHCHECK каждого контейнера
echo "=== Проверка состояния HEALTH ==="
docker ps --filter "health=unhealthy" --format "table {{.Names}}\t{{.Status}}"

echo "=== Скрипт завершен ==="

exit 0

Вывод

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

Основные принципы:

  • использование Docker Compose для стандартизированного и устойчивого окружения;
  • автоматическое форматирование кода (Pint) для единого стиля;
  • статический анализ (PHPStan + Larastan) для раннего обнаружения ошибок;
  • Git Hooks и скрипты, проверяющие файлы, тесты и работоспособность окружения.

Если вы внедрите эти практики, вы:

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

Автоматизируйте рутинные задачи — и команда сможет сфокусироваться на настоящей ценности: создании функционала и развитии продукта.

7

UmbraUI — как я устал писать одни и те же компоненты и создал свой первый пакет для Laravel

Привет!

Меня всегда бесило в веб-разработке то, что каждый новый проект — это создание компонентов с нуля. Кнопочка, инпут, модалка, уведомления… И так бесконечно.

После очередного проекта, где я в тысячный раз писал <button class="px-4 py-2 bg-neutral-500...">, понял — хватит! Пора сделать что-то, что избавит меня (и вас) от этой рутины.

Так родился UmbraUI — мой первый пакет в принципе и по совместительству пакет UI компонентов для Laravel.

Почему именно так?

Просто устал каждый раз гуглить “accessibility для чекбоксов” и “почему у меня модалка не закрывается по Escape”…

Хотелось сделать библиотеку, которую я сам буду использовать в своих проектах. Без десятка зависимостей, без необходимости изучать новый фреймворк. Просто — поставил, написал <x-button>, и оно работает как надо.

Что получилось?

🎯 Только то, что реально нужно

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

🎨 Красиво из коробки

Всё на Tailwind CSS, вдохновлялся shadcn/ui и другими крутыми библиотеками. Но адаптировал под реалии Laravel-разработки.

🏠 Laravel-native подход

Никаких дополнительных зависимостей, сложных сборок или конфликтов. Чистые Blade компоненты, которые работают как родные Laravel элементы.

🌙 Тёмная тема

Потому что в 2025 году не поддерживать dark mode — это как не поддерживать мобильные устройства.

Что уже есть?

20+ компонентов, которые покрывают 95% потребностей:

Формы: Button, Input, Textarea, Select, Checkbox, Radio, Switch, Slider, Date Picker, Label, Field (с валидацией) и т. п.

UI элементы: Alert, Badge, Avatar, Card, Tabs, Accordion, Modal, Dropdown, Link и т. п.

Специальное: Table (с сортировкой), Toast (система уведомлений), Progress

Иконки: 5000 кастомизируемых иконок от Tabler icons

Как попробовать?

composer require ihxnnxs/umbra-ui

Для JS-функций (toast’ы и т. д.):

php artisan vendor:publish --tag=umbra-ui-assets

Мои планы

Сейчас пакет в активной разработке, но уже вполне рабочий. Планирую добавить:

  • Сайт для пакета
  • Chart
  • Modal
  • Header/sidebar
  • и многое другое

А самое главное — после стабильного релиза перепишу свои сайты на UmbraUI. Я считаю, что это будет лучшей проверкой того, насколько пакет действительно удобен в реальной работе. Если я сам не буду им пользоваться — значит, что-то делаю не так.

Попробуйте!

Пакет на GitHub: https://github.com/ihxnnxs/UmbraUI

Если пакет зайдёт — ставьте звёздочку на GitHub ⭐ Это реально мотивирует продолжать развитие проекта.

11