История IT-технологий сегодня — 23 ноября
ℹ️ Кто родился в этот день
Абхай Бхушан ( произношение на хинди: [əbʰəj bʰuːʂəɳː] ; родился 23 ноября 1944 г.) — индийский компьютерный учёный; автор оригинальной спецификации FTP и ряда ранних RFC для ARPANET/Интернета.
Магнус Даниэль Стенберг (23 ноября 1970) — шведский разработчик; создатель и ведущий разработчик проекта cURL, инструмента для работы с сетевыми протоколами, широко используемого в инфраструктуре.
🌐 Знаковые события
1924 — состоялась первая широковещательная передача Московского радио. Начало регулярного радиовещания в СССР.
Комментарий: Всего 100 лет назад... Только появилось радио, а теперь роботы, космос и интернет... Что будет еще через 100 лет?
#Biography #Birth_Date #Events #23Ноября
Абхай Бхушан ( произношение на хинди: [əbʰəj bʰuːʂəɳː] ; родился 23 ноября 1944 г.) — индийский компьютерный учёный; автор оригинальной спецификации FTP и ряда ранних RFC для ARPANET/Интернета.
Магнус Даниэль Стенберг (23 ноября 1970) — шведский разработчик; создатель и ведущий разработчик проекта cURL, инструмента для работы с сетевыми протоколами, широко используемого в инфраструктуре.
1924 — состоялась первая широковещательная передача Московского радио. Начало регулярного радиовещания в СССР.
Комментарий: Всего 100 лет назад... Только появилось радио, а теперь роботы, космос и интернет... Что будет еще через 100 лет?
#Biography #Birth_Date #Events #23Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Кем ты видишь себя в будущем в IT?
Сегодня в IT идёт каждый второй.
Кто-то по моде.
Кто-то за деньгами.
Но вот о чём почти никто не думает:
Кем ты хочешь стать через 5–10 лет?
И хочешь ли ты этого вообще?
Давайте об этом сегодня и поразмышляем.
Разработчик - это фундамент
Как бы банально ни звучало: разработчик - это основа IT.
Если убрать программистов, то рухнет всё: сервисы, приложения, бэкенды, интерфейсы - всё.
Но спустя годы работы некоторым становится тесно.
Кто-то устает просто решать таски.
Кому-то хочется больше влияния, кому-то — меньше рутины, кому-то — новых вызовов.
Куда можно расти дальше
1. Individual Contributor (IC): разработчик
Джун → мидл → сеньор → ведущий.
Ты пишешь код, решаешь сложные задачи, драйвишь качество.
Глубина и ширина.
Это путь для тех, кто любит и хочет продолжать создавать что-то своими руками.
2. Архитектор / системный инженер
От решения отдельных модулей - к проектированию больших систем.
Минимум строчек кода, больше схем, интеграций, рисков, компромиссов.
Тут ты уже не пишешь программу.
Ты формируешь её скелет, основу, генерируешь понимание как все это будет работать в связке, давая свою компетенцию и гарантии.
3. Тимлид (People Manager)
Тут код - уже не главное.
Главное - люди, процессы, сроки, коммуникация.
Мотивировать.
Помогать расти.
Разруливать конфликты.
Закрывать найм.
Ты превращаешься из разработчика в того, кто рулит и организует процесс разработки.
4. Техлид / Tech Lead
Эта позиция позволяет сохранить контроль над кодом, при этом руководя его написанием.
Ты остаёшься технически сильным, но получаешь влияние на команду.
Твоя зона: архитектура, ревью, стандарты, координация технического направления.
Без HR-функций, но с высокой ответственностью за качество.
5. Продуктовый путь (PM, Product Engineer)
Переход, от как запрограммировать - к а зачем это вообще нужно?
Пользовательские кейсы, метрики, ценность, гипотезы.
Ты становишься человеком, который превращает код в продукт, а не в набор функций.
А надо ли тебе это?
Когда приходит возможность выбирать - этот вопрос основной.
С одной стороны:
спокойная работа разработчиком, задачи, PR-ы, ревью, новые фреймворки и старое доброе легаси.
С другой:
рост, новые роли, новые риски, новые деньги.
Не каждому хочется руководить людьми.
Не каждый хочет отвечать за архитектуру.
Не всем нужен стресс, планирование, ответственность.
Кому-то достаточно закрывать таски и вечером залипать в сериалы 😂
И это тоже нормально.
Выбор есть у каждого.
Но решать придётся самому — трезво взвесив, чего ты реально хочешь.
Если статья зашла — поделись с другом и позови его на канал.
А мне — плюсик к карме 🤝😎
😎
#motivation
Сегодня в IT идёт каждый второй.
Кто-то по моде.
Кто-то за деньгами.
Но вот о чём почти никто не думает:
Кем ты хочешь стать через 5–10 лет?
И хочешь ли ты этого вообще?
Давайте об этом сегодня и поразмышляем.
Разработчик - это фундамент
Как бы банально ни звучало: разработчик - это основа IT.
Если убрать программистов, то рухнет всё: сервисы, приложения, бэкенды, интерфейсы - всё.
Но спустя годы работы некоторым становится тесно.
Кто-то устает просто решать таски.
Кому-то хочется больше влияния, кому-то — меньше рутины, кому-то — новых вызовов.
Куда можно расти дальше
1. Individual Contributor (IC): разработчик
Джун → мидл → сеньор → ведущий.
Ты пишешь код, решаешь сложные задачи, драйвишь качество.
Глубина и ширина.
Это путь для тех, кто любит и хочет продолжать создавать что-то своими руками.
2. Архитектор / системный инженер
От решения отдельных модулей - к проектированию больших систем.
Минимум строчек кода, больше схем, интеграций, рисков, компромиссов.
Тут ты уже не пишешь программу.
Ты формируешь её скелет, основу, генерируешь понимание как все это будет работать в связке, давая свою компетенцию и гарантии.
3. Тимлид (People Manager)
Тут код - уже не главное.
Главное - люди, процессы, сроки, коммуникация.
Мотивировать.
Помогать расти.
Разруливать конфликты.
Закрывать найм.
Ты превращаешься из разработчика в того, кто рулит и организует процесс разработки.
4. Техлид / Tech Lead
Эта позиция позволяет сохранить контроль над кодом, при этом руководя его написанием.
Ты остаёшься технически сильным, но получаешь влияние на команду.
Твоя зона: архитектура, ревью, стандарты, координация технического направления.
Без HR-функций, но с высокой ответственностью за качество.
5. Продуктовый путь (PM, Product Engineer)
Переход, от как запрограммировать - к а зачем это вообще нужно?
Пользовательские кейсы, метрики, ценность, гипотезы.
Ты становишься человеком, который превращает код в продукт, а не в набор функций.
А надо ли тебе это?
Когда приходит возможность выбирать - этот вопрос основной.
С одной стороны:
спокойная работа разработчиком, задачи, PR-ы, ревью, новые фреймворки и старое доброе легаси.
С другой:
рост, новые роли, новые риски, новые деньги.
Не каждому хочется руководить людьми.
Не каждый хочет отвечать за архитектуру.
Не всем нужен стресс, планирование, ответственность.
Кому-то достаточно закрывать таски и вечером залипать в сериалы 😂
И это тоже нормально.
Выбор есть у каждого.
Но решать придётся самому — трезво взвесив, чего ты реально хочешь.
Если статья зашла — поделись с другом и позови его на канал.
А мне — плюсик к карме 🤝😎
#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
История IT-технологий сегодня — 24 ноября
ℹ️ Кто родился в этот день
Сельмер Брингсйорд (родился 24 ноября 1958 года) — американский исследователь в ИИ и когнитивных науках; известен работами по автоматическому рассуждению и философии машинного интеллекта.
🌐 Знаковые события
Не нашел((
#Biography #Birth_Date #Events #24Ноября
Сельмер Брингсйорд (родился 24 ноября 1958 года) — американский исследователь в ИИ и когнитивных науках; известен работами по автоматическому рассуждению и философии машинного интеллекта.
Не нашел((
#Biography #Birth_Date #Events #24Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Глава 2. List — списки в Java
Реализации: ArrayList и LinkedList. Сравнение производительности
ArrayList: динамический массив под капотом
Самая популярная и часто используемая реализация List. Её название раскрывает всю суть: ArrayList — это список, реализованный на основе массива.
Внутреннее устройство:
Массив как основа. Когда вы создаете ArrayList, внутри него создается обычный массив типа Object[] (или E[] после дженериков). Изначально этот массив имеет некоторый начальный размер (емкость, capacity), часто по умолчанию это 10 элементов.
Динамическое расширение.
Когда вы добавляете новый элемент с помощью add(), ArrayList проверяет, осталось ли место во внутреннем массиве.
Если место есть, элемент просто помещается в первую свободную ячейку elementData[size], и значение size увеличивается на 1. Это очень быстрая операция, comparable с работой с массивом.
Если массив полон, происходит следующее:
Создается новый массив большего размера. Стандартная логика увеличения — (старый_размер * 1.5) + 1.
Все элементы из старого массива копируются в новый.
Старый массив удаляется сборщиком мусора, а ссылка elementData начинает указывать на новый массив.
Только после этого новый элемент добавляется в конец.
Этот процесс пересоздания и копирования массива является относительно медленным, поэтому, если вы заранее знаете примерное количество элементов, лучше создать ArrayList с нужной начальной емкостью через конструктор new ArrayList<>(1000). Это позволит избежать или минимизировать количество операций расширения.
LinkedList: цепочка связанных элементов
LinkedList подходит к задаче иначе. Его название также прямо говорит о структуре: LinkedList — это связный список.
Внутреннее устройство:
Узлы (Node). LinkedList не использует массив. Вместо этого он построен на основе узлов.
Каждый узел — это самостоятельный объект, который хранит три вещи:
Сам элемент (например, строку или число).
Ссылку на следующий узел (next).
Ссылку на предыдущий узел (prev).
Двусвязность. LinkedList в Java является двусвязным списком. Это означает, что он хранит ссылки как на следующий, так и на предыдущий элемент. Благодаря этому можно легко перемещаться по списку как от начала к концу, так и от конца к началу.
Отсутствие массива. Элементы не хранятся в непрерывной области памяти. Они разбросаны по куче (Heap), а связаны между собой лишь этими ссылками-«ниточками». Голова списка — это поле first, а хвост — last.
#Java #для_новичков #beginner #List #ArrayList #LinkedList
Реализации: ArrayList и LinkedList. Сравнение производительности
ArrayList: динамический массив под капотом
Самая популярная и часто используемая реализация List. Её название раскрывает всю суть: ArrayList — это список, реализованный на основе массива.
Внутреннее устройство:
Массив как основа. Когда вы создаете ArrayList, внутри него создается обычный массив типа Object[] (или E[] после дженериков). Изначально этот массив имеет некоторый начальный размер (емкость, capacity), часто по умолчанию это 10 элементов.
// Примерно так выглядит внутри ArrayList
public class ArrayList<E> {
private Object[] elementData; // Внутренний массив
private int size; // Текущее количество реальных элементов
// ...
}
Динамическое расширение.
Когда вы добавляете новый элемент с помощью add(), ArrayList проверяет, осталось ли место во внутреннем массиве.
Если место есть, элемент просто помещается в первую свободную ячейку elementData[size], и значение size увеличивается на 1. Это очень быстрая операция, comparable с работой с массивом.
Если массив полон, происходит следующее:
Создается новый массив большего размера. Стандартная логика увеличения — (старый_размер * 1.5) + 1.
Все элементы из старого массива копируются в новый.
Старый массив удаляется сборщиком мусора, а ссылка elementData начинает указывать на новый массив.
Только после этого новый элемент добавляется в конец.
Этот процесс пересоздания и копирования массива является относительно медленным, поэтому, если вы заранее знаете примерное количество элементов, лучше создать ArrayList с нужной начальной емкостью через конструктор new ArrayList<>(1000). Это позволит избежать или минимизировать количество операций расширения.
LinkedList: цепочка связанных элементов
LinkedList подходит к задаче иначе. Его название также прямо говорит о структуре: LinkedList — это связный список.
Внутреннее устройство:
Узлы (Node). LinkedList не использует массив. Вместо этого он построен на основе узлов.
Каждый узел — это самостоятельный объект, который хранит три вещи:
Сам элемент (например, строку или число).
Ссылку на следующий узел (next).
Ссылку на предыдущий узел (prev).
// Примерная структура узла
private static class Node<E> {
E item; // Данные
Node<E> next; // Ссылка на следующий узел
Node<E> prev; // Ссылка на предыдущий узел
// ...
}
Двусвязность. LinkedList в Java является двусвязным списком. Это означает, что он хранит ссылки как на следующий, так и на предыдущий элемент. Благодаря этому можно легко перемещаться по списку как от начала к концу, так и от конца к началу.
Отсутствие массива. Элементы не хранятся в непрерывной области памяти. Они разбросаны по куче (Heap), а связаны между собой лишь этими ссылками-«ниточками». Голова списка — это поле first, а хвост — last.
#Java #для_новичков #beginner #List #ArrayList #LinkedList
👍2
Сравнение производительности
Время выполнения операций принято описывать в нотации "Big O", которая показывает, как время работы растет с увеличением объема данных (n).
1. Доступ к элементу по индексу (get(index))
ArrayList: O(1) — константное время.
Это его сильнейшая сторона. Поскольку внутри обычный массив, чтобы получить элемент по индексу 5, система просто делает одну операцию: берет начальный адрес массива и смещается на 5 ячеек в памяти. Это происходит мгновенно, независимо от размера списка.
LinkedList: O(n) — линейное время.
Это его главный недостаток для данной операции. У списка нет индексов в памяти. Чтобы найти элемент с индексом 5, ему приходится начинать с начала (или с конца, если индекс ближе к нему) и последовательно переходить по ссылкам next (или prev).
Для доступа к первому или последнему элементу (get(0) или get(last)) скорость будет высокой O(1), так как есть прямые ссылки first и last. Но для элемента в середине — очень низкой.
2. Вставка элемента (add(element)) и удаление с конца
ArrayList: В среднем O(1), но в худшем случае O(n).
Добавление в конец (add(element)) обычно очень быстрое (O(1)), так как это запись в свободную ячейку. Однако, если массив полон, требуется дорогостоящая операция копирования всего массива (O(n)).
LinkedList: O(1) — константное время.
Добавление в конец всегда выполняется за константное время. Для этого нужно просто создать новый узел, сделать его prev ссылку на старый последний узел, и обновить ссылку last. Это несколько операций, но их количество не зависит от размера списка.
3. Вставка/удаление в произвольной позиции (add(index, element), remove(index))
ArrayList: O(n) — линейное время.
Это его слабое место. Представьте, что вы вставляете элемент в начало списка (индекс 0). ArrayList вынужден сдвинуть все существующие элементы на одну позицию вправо, чтобы освободить место для нового.
Эта операция arraycopy требует времени, пропорционального количеству сдвигаемых элементов (n). Удаление из начала/середины имеет ту же проблему, так как требует сдвига всех последующих элементов влево.
LinkedList: В среднем O(n), но само изменение ссылок — O(1).
Время операции здесь определяется не самим добавлением/удалением, а поиском нужной позиции. Как мы помним, поиск по индексу в LinkedList занимает O(n). Однако, как только узел найден, вставка или удаление выполняются очень быстро: нужно всего лишь поменять несколько ссылок у соседних узлов. Не нужно перемещать половину списка!
Поэтому, если у вас уже есть ссылка на узел (например, вы находитесь в середине итерации), вставка и удаление рядом с этим узлом будут исключительно быстрыми (O(1)).
Когда использовать ArrayList (в 95% случаев):
Когда преобладают операции чтения и получения элементов по индексу.
Когда вы в основном добавляете элементы в конец.
Когда память несколько критична, и вы хотите минимизировать overhead.
Когда использовать LinkedList:
Когда преобладают операции вставки и удаления в начале или середине списка, и при этом у вас нет частой необходимости в быстром доступе по индексу.
Когда вы активно используете структуры типа "стек" (LIFO) или "очередь" (FIFO) (хогда для этого есть более специализированные классы, как ArrayDeque).
#Java #для_новичков #beginner #List #ArrayList #LinkedList
Время выполнения операций принято описывать в нотации "Big O", которая показывает, как время работы растет с увеличением объема данных (n).
1. Доступ к элементу по индексу (get(index))
ArrayList: O(1) — константное время.
Это его сильнейшая сторона. Поскольку внутри обычный массив, чтобы получить элемент по индексу 5, система просто делает одну операцию: берет начальный адрес массива и смещается на 5 ячеек в памяти. Это происходит мгновенно, независимо от размера списка.
// Внутренняя логика ArrayList.get(index)
public E get(int index) {
// ... проверка индекса ...
return (E) elementData[index]; // Прямое обращение по индексу массива
}
LinkedList: O(n) — линейное время.
Это его главный недостаток для данной операции. У списка нет индексов в памяти. Чтобы найти элемент с индексом 5, ему приходится начинать с начала (или с конца, если индекс ближе к нему) и последовательно переходить по ссылкам next (или prev).
// Примерная логика (упрощенно). Чтобы найти узел с индексом 5:
Node<E> x = first;
for (int i = 0; i < 5; i++) { // Нужно сделать 5 итераций
x = x.next;
}
return x.item;
Для доступа к первому или последнему элементу (get(0) или get(last)) скорость будет высокой O(1), так как есть прямые ссылки first и last. Но для элемента в середине — очень низкой.
2. Вставка элемента (add(element)) и удаление с конца
ArrayList: В среднем O(1), но в худшем случае O(n).
Добавление в конец (add(element)) обычно очень быстрое (O(1)), так как это запись в свободную ячейку. Однако, если массив полон, требуется дорогостоящая операция копирования всего массива (O(n)).
LinkedList: O(1) — константное время.
Добавление в конец всегда выполняется за константное время. Для этого нужно просто создать новый узел, сделать его prev ссылку на старый последний узел, и обновить ссылку last. Это несколько операций, но их количество не зависит от размера списка.
3. Вставка/удаление в произвольной позиции (add(index, element), remove(index))
ArrayList: O(n) — линейное время.
Это его слабое место. Представьте, что вы вставляете элемент в начало списка (индекс 0). ArrayList вынужден сдвинуть все существующие элементы на одну позицию вправо, чтобы освободить место для нового.
// При вставке в середину/начало в ArrayList
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = newElement;
size++;
Эта операция arraycopy требует времени, пропорционального количеству сдвигаемых элементов (n). Удаление из начала/середины имеет ту же проблему, так как требует сдвига всех последующих элементов влево.
LinkedList: В среднем O(n), но само изменение ссылок — O(1).
Время операции здесь определяется не самим добавлением/удалением, а поиском нужной позиции. Как мы помним, поиск по индексу в LinkedList занимает O(n). Однако, как только узел найден, вставка или удаление выполняются очень быстро: нужно всего лишь поменять несколько ссылок у соседних узлов. Не нужно перемещать половину списка!
// Вставка `newNode` между `prevNode` и `currentNode`
newNode.prev = prevNode;
newNode.next = currentNode;
prevNode.next = newNode;
currentNode.prev = newNode;
Поэтому, если у вас уже есть ссылка на узел (например, вы находитесь в середине итерации), вставка и удаление рядом с этим узлом будут исключительно быстрыми (O(1)).
Когда использовать ArrayList (в 95% случаев):
Когда преобладают операции чтения и получения элементов по индексу.
Когда вы в основном добавляете элементы в конец.
Когда память несколько критична, и вы хотите минимизировать overhead.
Когда использовать LinkedList:
Когда преобладают операции вставки и удаления в начале или середине списка, и при этом у вас нет частой необходимости в быстром доступе по индексу.
Когда вы активно используете структуры типа "стек" (LIFO) или "очередь" (FIFO) (хогда для этого есть более специализированные классы, как ArrayDeque).
#Java #для_новичков #beginner #List #ArrayList #LinkedList
👍2
Что выведет код?
#Tasks
import java.util.LinkedList;
import static java.lang.Integer.valueOf;
public class Task241125 {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
list.add(3);
list.remove(1);
list.remove(valueOf(2));
System.out.println(list.size());
System.out.println(list.getFirst());
}
}
#Tasks
👍1
😱1
Вопрос с собеседований
Как работает CopyOnWriteArrayList?🤓
Ответ:
Каждая модификация создает новую копию массива, что делает чтение полностью безопасным без блокировок.
Подходит для сценариев с большим количеством чтений и редкими записями.
Минус — высокая стоимость модификаций и расход памяти при частых изменениях.
#собеседование
Как работает CopyOnWriteArrayList?
Ответ:
Подходит для сценариев с большим количеством чтений и редкими записями.
Минус — высокая стоимость модификаций и расход памяти при частых изменениях.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История IT-технологий сегодня — 25 ноября
ℹ️ Кто родился в этот день
Хиронобу Сакагути (яп. 坂口 博信 Сакагути Хиронобу, род. 25 ноября 1962) — японский геймдизайнер и программист; создатель серии Final Fantasy, повлиявшей на развитие игровых технологий и интерактивного дизайна.
🌐 Знаковые события
Не нашел((
#Biography #Birth_Date #Events #25Ноября
Хиронобу Сакагути (яп. 坂口 博信 Сакагути Хиронобу, род. 25 ноября 1962) — японский геймдизайнер и программист; создатель серии Final Fantasy, повлиявшей на развитие игровых технологий и интерактивного дизайна.
Не нашел((
#Biography #Birth_Date #Events #25Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Реализация GraphQL на сервере
1. Как сервер “понимает” запросы
GraphQL — это не просто формат данных. Это полноценный язык запросов, который сервер интерпретирует строжайшим образом.
На сервере присутствуют три ключевых компонента:
Схема (Schema) — декларативное описание типов, запросов, мутаций и подписок.
Исполнитель (Executor) — механизм, который умеет разбирать, валидировать и выполнять запросы.
Резолверы (resolvers) — функции, которые реально достают данные.
Процесс обработки запроса выглядит так:
Шаг 1. Парсинг
Запрос, полученный в виде строки, разбирается в AST (абстрактное синтаксическое дерево).
GraphQL понимает только корректный язык запросов, поэтому на этом этапе запрос может быть отклонён.
Шаг 2. Валидация
AST сравнивается со схемой.
Сервер проверяет:
существуют ли указанные поля;
правильно ли переданы аргументы;
корректны ли типы;
не запрошены ли деприкейтнутые или отсутствующие типы.
Если запрос не соответствует схеме, сервер вообще не перейдёт к резолверам.
Шаг 3. Выполнение
GraphQL выполняет запрос сверху вниз, проходя по полям и вызывая резолверы там, где они определены.
GraphQL никогда не “догадывается”, где лежат данные.
Он лишь исполняет дерево запроса, вызывая привязанные функции.
2. Роль резолверов (resolvers)
Резолвер — это функция, которая отвечает на вопрос:
“Как получить данные для этого конкретного поля?”
В GraphQL у каждого поля может быть свой резолвер, хотя обычно определяют резолверы для корневых типов: Query, Mutation, Subscription.
Резолвер принимает три основных аргумента:
parent — результат предыдущего резолвера (нужен для вложенных структур);
args — аргументы, которые указал клиент;
context — общий контекст запроса (авторизация, транзакция, соединения с БД).
Пример простого резолвера на Java (Spring Boot + graphql-java-tools):
Резолвер выполняет ровно одну задачу: достать данные.
GraphQL не хранит состояние, не кэширует данные, не соединяется с БД — всё это делает твой код через резолверы.
3. Маппинг схемы на реальные источники данных
GraphQL — это уровень между клиентом и данными.
Источники могут быть любыми:
реляционная БД (PostgreSQL);
документоориентированная БД (MongoDB);
REST API других микросервисов;
gRPC сервисы;
сообщения из Kafka;
кэш Redis.
GraphQL не диктует, где должны лежать данные. Он просто обеспечивает единый интерфейс запросов.
Пример маппинга:
Резолверы:
Отсюда следует ключевой принцип:
сервер выполняет только то, что клиент запросил — ни больше, ни меньше.
#Java #middle #GraphQL
1. Как сервер “понимает” запросы
GraphQL — это не просто формат данных. Это полноценный язык запросов, который сервер интерпретирует строжайшим образом.
На сервере присутствуют три ключевых компонента:
Схема (Schema) — декларативное описание типов, запросов, мутаций и подписок.
Исполнитель (Executor) — механизм, который умеет разбирать, валидировать и выполнять запросы.
Резолверы (resolvers) — функции, которые реально достают данные.
Процесс обработки запроса выглядит так:
Шаг 1. Парсинг
Запрос, полученный в виде строки, разбирается в AST (абстрактное синтаксическое дерево).
GraphQL понимает только корректный язык запросов, поэтому на этом этапе запрос может быть отклонён.
Шаг 2. Валидация
AST сравнивается со схемой.
Сервер проверяет:
существуют ли указанные поля;
правильно ли переданы аргументы;
корректны ли типы;
не запрошены ли деприкейтнутые или отсутствующие типы.
Если запрос не соответствует схеме, сервер вообще не перейдёт к резолверам.
Шаг 3. Выполнение
GraphQL выполняет запрос сверху вниз, проходя по полям и вызывая резолверы там, где они определены.
GraphQL никогда не “догадывается”, где лежат данные.
Он лишь исполняет дерево запроса, вызывая привязанные функции.
2. Роль резолверов (resolvers)
Резолвер — это функция, которая отвечает на вопрос:
“Как получить данные для этого конкретного поля?”
В GraphQL у каждого поля может быть свой резолвер, хотя обычно определяют резолверы для корневых типов: Query, Mutation, Subscription.
Резолвер принимает три основных аргумента:
parent — результат предыдущего резолвера (нужен для вложенных структур);
args — аргументы, которые указал клиент;
context — общий контекст запроса (авторизация, транзакция, соединения с БД).
Пример простого резолвера на Java (Spring Boot + graphql-java-tools):
@Component
public class UserQueryResolver implements GraphQLQueryResolver {
private final UserService service;
public UserQueryResolver(UserService service) {
this.service = service;
}
public User userById(Long id) {
return service.findById(id);
}
}
Резолвер выполняет ровно одну задачу: достать данные.
GraphQL не хранит состояние, не кэширует данные, не соединяется с БД — всё это делает твой код через резолверы.
3. Маппинг схемы на реальные источники данных
GraphQL — это уровень между клиентом и данными.
Источники могут быть любыми:
реляционная БД (PostgreSQL);
документоориентированная БД (MongoDB);
REST API других микросервисов;
gRPC сервисы;
сообщения из Kafka;
кэш Redis.
GraphQL не диктует, где должны лежать данные. Он просто обеспечивает единый интерфейс запросов.
Пример маппинга:
type Query {
user(id: ID!): User
}
type User {
id: ID!
name: String!
posts: [Post!]!
}Резолверы:
@Component
public class UserResolver implements GraphQLResolver<User> {
private final PostService postService;
public UserResolver(PostService postService) {
this.postService = postService;
}
public List<Post> posts(User user) {
return postService.findByUserId(user.getId());
}
}
GraphQL вызывает posts() только если клиент запросит поле posts.
Если клиент запросит только user { id name }, резолвер posts не будет вызван вообще.
Отсюда следует ключевой принцип:
сервер выполняет только то, что клиент запросил — ни больше, ни меньше.
#Java #middle #GraphQL
👍1
4. Типичная архитектура GraphQL-сервера (Spring Boot)
Структура проекта в Java обычно такая:
Описание этапов:
Схема
Файл .graphqls описывает типы и операции.
Резолверы
Связывают поля схемы с Java-методами.
Сервисы
Логика бизнес-операций.
Репозитории
SQL/NoSQL/REST/gRPC слой, через который сервер реально получает данные.
Context
Сюда кладут:
JWT токен
объект пользователя
транзакции
общие ресурсы
5. Пример полного цикла запроса
Клиент отправляет запрос:
Что делает сервер:
Парсит запрос → AST
Проверяет типы по схеме
Вызывает QueryResolver.user(id=10)
Получает объект User
Чтобы отдать поле posts, вызывает UserResolver.posts(user)
Формирует объект ответа, возвращает клиенту JSON
Клиент всегда получает именно ту форму данных, которую указал.
Сервер не отдаёт лишних полей.
6. Почему GraphQL — это слой поверх данных, а не база данных
GraphQL:
не знает SQL;
не оптимизирует запросы;
не управляет транзакциями;
не индексирует данные;
не проверяет связи между таблицами.
GraphQL — это универсальный контракт между клиентом и сервером, а не способ хранения данных.
Он лишь обеспечивает:
строгую структуру данных (схему)
гибкие запросы от клиента
единый интерфейс ко множеству источников
оптимизацию на уровне поля (через резолверы)
Всё остальное — на стороне backend-логики.
#Java #middle #GraphQL
Структура проекта в Java обычно такая:
/graphql
/schema
schema.graphqls
/resolvers
QueryResolver.java
MutationResolver.java
UserResolver.java
PostResolver.java
/services
UserService.java
PostService.java
/repositories
UserRepository.java
PostRepository.java
Описание этапов:
Схема
Файл .graphqls описывает типы и операции.
Резолверы
Связывают поля схемы с Java-методами.
Сервисы
Логика бизнес-операций.
Репозитории
SQL/NoSQL/REST/gRPC слой, через который сервер реально получает данные.
Context
Сюда кладут:
JWT токен
объект пользователя
транзакции
общие ресурсы
5. Пример полного цикла запроса
Клиент отправляет запрос:
query {
user(id: 10) {
id
name
posts {
id
title
}
}
}Что делает сервер:
Парсит запрос → AST
Проверяет типы по схеме
Вызывает QueryResolver.user(id=10)
Получает объект User
Чтобы отдать поле posts, вызывает UserResolver.posts(user)
Формирует объект ответа, возвращает клиенту JSON
Клиент всегда получает именно ту форму данных, которую указал.
Сервер не отдаёт лишних полей.
6. Почему GraphQL — это слой поверх данных, а не база данных
GraphQL:
не знает SQL;
не оптимизирует запросы;
не управляет транзакциями;
не индексирует данные;
не проверяет связи между таблицами.
GraphQL — это универсальный контракт между клиентом и сервером, а не способ хранения данных.
Он лишь обеспечивает:
строгую структуру данных (схему)
гибкие запросы от клиента
единый интерфейс ко множеству источников
оптимизацию на уровне поля (через резолверы)
Всё остальное — на стороне backend-логики.
#Java #middle #GraphQL
👍3
Что выведет код?
#Tasks
import java.util.List;
public class Task251125 {
public static void main(String[] args) {
var list = List.of(1, 2, 3);
var number = 10;
var result = process(list, number);
System.out.println(result);
}
static var process(List<Integer> list, int n) {
var sum = 0;
for (var item : list) {
sum += item;
}
return sum * n;
}
}
#Tasks
👍2
Вопрос с собеседований
Разница между deep copy и shallow copy?🤓
Ответ:
Shallow copy копирует только верхний уровень объекта, оставляя вложенные ссылки общими.
Deep copy создает полную независимую структуру.
Первый быстрее, второй безопаснее, если требуется изоляция состояния. Выбор зависит от структуры данных и логики приложения.
#собеседование
Разница между deep copy и shallow copy?
Ответ:
Deep copy создает полную независимую структуру.
Первый быстрее, второй безопаснее, если требуется изоляция состояния. Выбор зависит от структуры данных и логики приложения.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2