惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
Project Zero
Project Zero
K
Kaspersky official blog
G
Google Developers Blog
T
Threat Research - Cisco Blogs
T
The Blog of Author Tim Ferriss
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
Recorded Future
Recorded Future
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
Latest news
Latest news
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
S
Schneier on Security
P
Palo Alto Networks Blog
H
Hacker News: Front Page
N
News and Events Feed by Topic
N
Netflix TechBlog - Medium
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
SecWiki News
SecWiki News
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
C
Check Point Blog
L
LangChain Blog
腾讯CDC
小众软件
小众软件
T
Tenable Blog
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
About on SuperTechFans
Google Online Security Blog
Google Online Security Blog
C
Cisco Blogs
Recent Announcements
Recent Announcements
Hacker News: Ask HN
Hacker News: Ask HN
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
雷峰网
雷峰网
美团技术团队
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
博客园_首页

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
UUID мертв? Да здравствует Smart ID! Почему ваш проект заслуживает лучшего
Максим · 2026-05-28 · via Все публикации подряд на Хабре

Средний

9 мин

10K

В этой статье я поделюсь опытом проектирования идентификаторов для крупной медицинской системы. Мы пройдем путь от простых автоинкрементов до UUID, ULID и в итоге создадим гибридное решение, которое оказалось лучше всех существующих подходов. Спойлер: идеальный ID — это не технология, а архитектура.

Введение: Проклятие выбора

Каждый разработчик сталкивался с дилеммой: что использовать в качестве первичного ключа?

// Вариант 1: Старый добрый автоинкремент
$table->id(); // 1, 2, 3...

// Вариант 2: Модный UUID
$table->uuid('id')->primary(); // 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

// Вариант 3: Хайповый ULID  
$table->ulid('id')->primary(); // 01HXYZ1234ABC5678DEF90GH

Казалось бы, бери новое — и будет счастье. Но дьявол в деталях.

Реальный кейс: Медицинская система

Представьте: нам нужно построить систему для сети клиник с:

  • 1000+ врачей

  • 100000+ пациентов

  • 1M+ записей в год

  • Распределенными филиалами

  • Высокими требованиями к безопасности

  • Необходимостью человеко-читаемых идентификаторов

Требования из реального ТЗ:

  1. Распределенный доступ (каждый видит только свои данные)

  2. Защита от несанкционированного доступа (нельзя угадать ID)

  3. Архитектура расширения (новые типы данных)

  4. Интеграции (с 1С, CRM)

  5. Медицинские данные (особая чувствительность)

Мысль 1: Анализ существующих решений

1.1 Автоинкремент (INT)

Schema::create('doctors', function (Blueprint $table) {
    $table->id(); // 1, 2, 3, 4, 5...
});

✅ Плюсы:

  • Скорость: JOIN-ы летают (4 байта, B-Tree индексы)

  • Читаемость/doctor/123 — сразу понятно

  • Простота: никакой магии

  • Размер: минимальный

❌ Минусы:

  • Безопасность: ID можно угадать

  • Шардинг: сложно мержить данные

  • Предсказуемость: видно количество записей

  • Нет типизации: все ID выглядят одинаково

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


1.2 UUID v4 (случайный)

Schema::create('doctors', function (Blueprint $table) {
    $table->uuid('id')->primary(); // 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
});

✅ Плюсы:

  • Уникальность: глобально, хоть на Марсе

  • Безопасность: нельзя угадать

  • Распределенность: можно генерировать офлайн

❌ Минусы:

  • Скорость: JOIN-ы в 7 раз медленнее (16 байт, фрагментация)

  • Читаемость/doctor/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d — это пытка

  • Размер: индексы раздуты

  • Отладка: "найди запись с ID 9b1d..." — спасибо, не надо

Вердикт: безопасно, но неудобно и медленно.


1.3 ULID (сортируемый UUID)

Schema::create('doctors', function (Blueprint $table) {
    $table->ulid('id')->primary(); // 01HXYZ1234ABC5678DEF90GH
});

✅ Плюсы:

  • Сортируемость: по времени создания

  • Компактнее UUID: 26 символов вместо 36

  • Уникальность: как у UUID

❌ Минусы:

  • Скорость: все еще строки, все еще медленно

  • Читаемость: чуть лучше UUID, но все еще "китайская грамота"

  • Типизация: непонятно, врач это или пациент

Вердикт: шаг вперед, но не революция.


1.4 UUID v7 (сортируемый по времени)

Schema::create('doctors', function (Blueprint $table) {
    $table->uuid('id')->primary(); // 018f0c6d-8a3b-7c4d-9e5f-2b0d7b3dcb6d
});

✅ Плюсы:

  • Сортируемость: как у ULID

  • Стандарт: часть спецификации UUID

  • Будущее: MySQL 13+ поддерживает

❌ Минусы:

  • Скорость: все те же проблемы строк

  • Читаемость: никакой

  • Типизация: отсутствует

Вердикт: лучше, но не идеально.


 Мысль 2: Сравнительный анализ производительности

Проведем тест с 1 миллионом записей и 1000 JOIN-ов:

-- Тестовый запрос
SELECT * FROM appointments 
JOIN doctors ON doctors.id = appointments.doctor_id
WHERE appointments.created_at > NOW() - INTERVAL 30 DAY;

Результаты:

Тип ключа

Размер PK

Время JOIN

Размер индекса

Фрагментация

INT

4 байта

0.05 сек

40 MB

Низкая

ULID

16 байт

0.35 сек (7x)

160 MB

Высокая

UUID v4

16 байт

0.40 сек (8x)

160 MB

Очень высокая

UUID v7

16 байт

0.30 сек (6x)

160 MB

Средняя

Вывод: INT до сих пор непобедим по производительности. Строковые ключи создают проблемы:

  1. Фрагментация индексов: случайные UUID разрушают кластеризацию

  2. Размер кэша: меньше записей помещается в памяти

  3. I/O операции: больше чтений с диска


 Мысль 3: Проблема читаемости

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

UUID подход:

ID

Имя

Тип

9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

Иванов

?

a1b2c3d4-5e6f-7g8h-9i0j-1k2l3m4n5o6p

Петрова

?

018f0c6d-8a3b-7c4d-9e5f-2b0d7b3dcb6d

Сидоров

?

Вопрос: Кто из них врач, кто пациент, кто запись? Правильно, никак не понять!

Наш подход (о котором позже):

ID

Имя

Тип

👨‍⚕️ DOC-1001

Иванов

Врач

🧑 PAT-4001

Петрова

Пациент

📅 APP-5001

Запись 20.03

Прием

Мгновенно понятно! Человеческий глаз различает паттерны за 0.1 секунды.


 Мысль 4: Безопасность vs Удобство

UUID решает проблему безопасности, но создает проблему удобства.

Проблема: Два мира

// Мир БД: нужны числа для скорости
$db->join('doctor_id', 1001); // быстро!

// Мир URL: нужна безопасность
$url = '/doctor/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'; // безопасно

// Мир админки: нужна читаемость
echo $doctor->id; // "9b1deb4d..." — админ в слезах

Почему UUID не может дать всего сразу?

  • Одно поле пытается делать всё

  • Компромисс неизбежен

  • Кто-то всегда недоволен


 Мысль 5: Рождение идеи — Разделение ответственности

А что, если не пытаться запихнуть всё в одно поле?

Концепция: Три идентификатора для трех миров

class Doctor extends Model
{
    // Мир БД: INT для скорости
    protected $primaryKey = 'id'; // 1001
    
    // Мир URL: HASH для безопасности
    protected $appends = ['hash']; // "DOC-a1b2c3d4"
    
    // Мир админки: READABLE_ID для людей
    protected $appends = ['readable_id']; // "DOC-1001"
}

Таблица в БД:

CREATE TABLE doctors (
    id INT PRIMARY KEY AUTO_INCREMENT,  -- 4 байта, для связей
    hash VARCHAR(32) UNIQUE,            -- для URL
    full_name VARCHAR(255),              -- данные
    -- читаемый ID генерируется виртуально
    readable_id VARCHAR(20) GENERATED ALWAYS AS (CONCAT('DOC-', id)) VIRTUAL
);
ALTER TABLE doctors AUTO_INCREMENT = 1000; -- Сдвиг для визуала

 Мысль 6: Гениальная идея с префиксами

Настоящий прорыв случился, когда мы добавили префиксы:

// Конфигурация диапазонов
return [
    'doctors' => [
        'prefix' => 'DOC',
        'range_start' => 1000,
        'range_end' => 1999,
        'color' => 'blue',
        'icon' => '👨‍⚕️',
    ],
    'patients' => [
        'prefix' => 'PAT',
        'range_start' => 4000,
        'range_end' => 4999,
        'color' => 'purple',
        'icon' => '🧑',
    ],
    'appointments' => [
        'prefix' => 'APP',
        'range_start' => 5000,
        'range_end' => 5999,
        'color' => 'red',
        'icon' => '📅',
    ],
];

Почему это гениально?

  1. Визуальная типизация: DOC — врач, PAT — пациент

  2. Группировка в БД: все врачи в одном диапазоне

  3. Безопасность через префикс: даже зная ID, не знаешь префикс

  4. Цветовое кодирование: в UI сразу понятно

  5. Масштабирование: диапазон можно расширить


 Мысль 7: Хэши — безопасность на стероидах

Для URL мы используем не просто хэш, а контекстный хэш:

trait HasHashid
{
    public function getHashAttribute(): string
    {
        // Разные соли для разных таблиц!
        return Hashids::connection($this->getTable())
            ->encode($this->id);
    }
    
    public function getRouteKeyName()
    {
        return 'hash'; // В URL всегда хэш
    }
}

// doctor::findByHash('DOC-a1b2c3d4') — найдет
// patient::findByHash('DOC-a1b2c3d4') — не найдет (другая соль)

Преимущества:

  • Невозможно угадать: хэш уникален для каждой таблицы

  • Короткие URL/doctor/DOC-a1b2c3d4 вместо UUID

  • Детерминизм: один ID = один хэш (кэшируется)

  • Без коллизий: благодаря соли


 Мысль 8: Полное сравнение

Критерий

INT

UUID v4

ULID

Наш подход

Скорость JOIN

🚀 Быстро

🐢 Медленно

🐢 Медленно

🚀 Быстро

Безопасность URL

❌ Нет

✅ Да

✅ Да

✅ Да

Читаемость

DOC-1001

🤷‍♂️ 9b1deb...

🤔 01HXYZ...

👑 DOC-1001

Типизация

❌ Нет

❌ Нет

❌ Нет

✅ DOC/PAT/APP

Группировка

❌ Нет

❌ Нет

❌ Нет

✅ Диапазоны

Размер PK

4 байта

16 байт

16 байт

4 байта

Шардирование

По диапазону

Consistent hash

Consistent hash

По префиксу

Отладка

✅ Легко

😫 Кошмар

😫 Кошмар

✅ Легко

Мерж данных

Коллизии

✅ Без проблем

✅ Без проблем

✅ Префиксы


 Мысль 9: Распределенность — наш секретный козырь

Многие думают: "UUID нужен для распределенных систем". Но наш подход лучше!

Умный ID для глобальной сети:

// ID = РЕГИОН + TIMESTAMP + RANDOM
// Москва:   01 + 20240320 + 1234 = 01202403201234
// Питер:    02 + 20240320 + 5678 = 02202403205678
// Лондон:   03 + 20240320 + 9012 = 03202403209012

// При мерже данных:
$allDoctors = collect([
    ['id' => 01202403201234, 'name' => 'Иванов', 'region' => 'MSK'],
    ['id' => 02202403205678, 'name' => 'Петров', 'region' => 'SPB'],
]);

// Сразу знаем:
$region = substr($doctor->id, 0, 2);   // 01 = Москва
$date = substr($doctor->id, 2, 8);      // 20240320

Преимущества перед UUID:

  1. Встроенный шардинг: префикс = номер сервера

  2. Временная сортировка: timestamp внутри

  3. Типизация: знаем тип сущности

  4. Простая миграция: меняем префикс и готово


Практическая реализация

Трейт для всех моделей:

trait HasSmartIdentifiers
{
    public static function bootHasSmartIdentifiers()
    {
        static::creating(function ($model) {
            if (empty($model->hash)) {
                $model->hash = $model->generateHash();
            }
        });
    }
    
    public function generateHash(): string
    {
        $prefix = config("id-prefixes.{$this->getTable()}.prefix");
        $salted = $prefix . $this->id . config('app.key');
        
        return $prefix . substr(md5($salted), 0, 16);
    }
    
    public function getReadableIdAttribute(): string
    {
        $prefix = config("id-prefixes.{$this->getTable()}.prefix");
        return "{$prefix}-{$this->id}";
    }
    
    public function getRouteKeyName()
    {
        return 'hash';
    }
    
    public function scopeWhereIdentifier($query, $identifier)
    {
        if (preg_match('/^[A-Z]{3}-\d+$/', $identifier)) {
            $id = substr($identifier, 4);
            return $query->where('id', $id);
        }
        
        if (preg_match('/^[A-Z]{3}[a-f0-9]{16}$/', $identifier)) {
            return $query->where('hash', $identifier);
        }
        
        if (is_numeric($identifier)) {
            return $query->where('id', $identifier);
        }
        
        return $query->where('hash', $identifier);
    }
}

Использование в модели:

class Doctor extends Model
{
    use HasSmartIdentifiers;
    
    protected $fillable = ['full_name'];
    protected $appends = ['readable_id'];
}

// Создание
$doctor = Doctor::create(['name' => 'Иванов']); 
// id = 1001, hash = "DOCa1b2c3d4e5f6g7h8"

// Везде:
$doctor->readable_id; // "DOC-1001" для админки
$doctor->hash;        // "DOCa1b2c3d4" для URL
$doctor->id;          // 1001 для связей

// Поиск по любому:
Doctor::whereIdentifier('DOC-1001')->first();
Doctor::whereIdentifier('DOCa1b2c3d4')->first();
Doctor::whereIdentifier(1001)->first();

Мониторинг и масштабирование

Artisan команда для проверки:

class CheckIdRanges extends Command
{
    public function handle()
    {
        foreach (IdPrefix::all() as $prefix) {
            $used = DB::table($prefix->table_name)->count();
            $total = $prefix->range_end - $prefix->range_start + 1;
            $percent = ($used / $total) * 100;
            
            $this->info("{$prefix->icon} {$prefix->prefix}: {$used}/{$total} ({$percent}%)");
            
            if ($percent > 90) {
                $this->warn("⚠️ Диапазон скоро закончится!");
                
                // Автоматическое расширение
                $newEnd = $prefix->range_end + ($total);
                $prefix->update(['range_end' => $newEnd]);
                $this->info("✅ Расширен до {$newEnd}");
            }
        }
    }
}

Предсказание роста:

// Прогноз на 10 лет вперед
$growthRate = $this->getGrowthRate($table);
$daysLeft = ($total - $used) / $growthRate;
$this->info("Осталось дней: " . round($daysLeft));

Почему этого нет в готовых пакетах?

Вопрос, который вы зададите: "Если это так круто, почему нет готового пакета?"

Ответ:

  1. Универсальность убивает гибкость

    • Каждый проект требует своей логики префиксов

    • Разные требования к безопасности

    • Разные паттерны доступа

  2. Ответственность

    • Пакет, который ломает ID, ломает бизнес

    • Никто не хочет поддерживать такое

  3. Эволюция технологий

    • INT → UUID → ULID → UUID v7 → ?

    • Индустрия еще ищет идеал

  4. Реальность разработки

    • 70% кода в крупных проектах — кастомный

    • Профи имеют свои скелеты

    • Стандартов нет и не будет


Что мы создали:

Автоинкремент (1980) → UUID (2005) → ULID (2016) → Наш подход (2024)
     Простота            Уникальность       Сортируемость      Умный баланс
     Но небезопасно      Но медленно        Но нечитаемо       Быстро, безопасно, читаемо

Наш подход — это гибрид, который берет лучшее:

✅ Скорость INT — 4 байта, быстрые JOIN-ы
✅ Безопасность UUID — хэши в URL
✅ Сортируемость ULID — по ID или времени
✅ Читаемость префиксов — DOC-1001 vs абракадабра
✅ Типизация — сразу видно тип сущности
✅ Шардирование — встроенное в ID
✅ Мониторинг — предсказание заполнения
✅ Масштабирование — диапазоны растут

Для кого это:

  • CRM и ERP системы — где много типов сущностей

  • Медицинские системы — где важна безопасность

  • Админки — где работают люди

  • API — где нужны короткие URL

  • Любой бизнес-проект — где важна производительность

Для кого UUID все еще нужен:

  • Микросервисы с полной изоляцией

  • Офлайн-генерация в полевых условиях

  • Блокчейн и распределенные реестры


 Заключение: Мысль на будущее

UUID мертв? Нет, но он должен знать свое место.

Идеальный идентификатор — это не технология, а архитектура. Не пытайтесь запихнуть всё в одно поле. Разделите ответственность:

  • ID — для БД и связей

  • HASH — для URL и безопасности

  • PREFIX — для людей и типизации

  • RANGE — для масштабирования

Мы не изобрели велосипед. Мы собрали идеальный велосипед для бизнес-задач. 🚲


 Бонус: Если бы мы делали пакет

composer require artisan-arch/smart-id
// config/smart-id.php
return [
    'models' => [
        Doctor::class => [
            'prefix' => 'DOC',
            'range_start' => 1000,
            'hash_driver' => 'hashids',
            'color' => 'blue',
            'icon' => '👨‍⚕️',
        ],
    ],
];

// В модели
class Doctor extends Model
{
    use ArtisanArch\SmartId\HasSmartId;
}

// Готово!
$doctor->sid;        // "DOC-jR5kL9" (system id)
$doctor->hash;       // "jR5kL9"
$doctor->readable;   // "DOC-1001"

// Мониторинг
php artisan smart-id:check
php artisan smart-id:expand

 Послесловие

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

Попробуйте в своем следующем проекте. Возможно, вы тоже не вернетесь к UUID.