День 2615. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
28. Методы оценки
«Можете ли вы описать методы оценки, которые вы использовали в своих проектах, и объяснить, как они помогли вам обеспечить выполнение проектов в установленные сроки?»
Хороший ответ
В моём опыте управления проектами .NET я использовал комбинацию методов оценки для обеспечения точного прогнозирования и эффективного управления проектом. Среди них экспертная оценка (Expert Judgment), покер планирования (Planning Poker) и анализ точек использования (Case Point Analysis).
1. Экспертная оценка предполагает консультации с опытными членами команды для получения оценок на основе их прошлого опыта. Например, при работе над веб-сервисом, включающим ASP.NET Core и Entity Framework Core, я обсуждал задачи со старшими разработчиками, имеющими аналогичный опыт работы над проектами, чтобы получить реалистичное представление о трудозатратах и сроках.
2. Покер планирования - метод оценки в Agile, использующий консенсус для оценки задач. Каждый член команды предоставляет оценку, используя пронумерованные карточки, и затем следуют обсуждения, пока команда не достигнет консенсуса. Этот метод особенно полезен для вовлечения всей команды в процесс оценки, что повышает вовлечённость и точность оценок. Суть метода:
- Каждый разработчик получает карточки с номерами, представляющими собой стори-пойнты.
- Владелец продукта описывает функцию.
- Разработчики выбирают карточку, представляющую их оценку, не раскрывая её.
- Все карточки раскрываются одновременно, и разногласия обсуждаются до достижения консенсуса.
3. Анализ вариантов использования - адаптирован для оценки трудозатрат, необходимых для пользовательских историй, включающих взаимодействие с пользователями. Он учитывает сложность вариантов использования и корректирует её с учётом технических и организационных факторов.
Суть метода в том, что каждый вариант использования классифицируется как простой, средний или сложный, а затем присваивается вес на основе этих категорий. Это особенно эффективно для проектов с чёткими функциональными требованиями, таких как веб-сервис с несколькими конечными точками.
Комбинация этих методов позволяет предоставить более надёжные оценки, учитывающие неопределённости и позволяющие лучше планировать и управлять рисками. Такой подход помогает гарантировать, что проекты будут реализованы в срок и в рамках заданного объёма, даже при возникновении непредвиденных сложностей.
Часто встречающийся плохой ответ
«Я примерно по опыту оцениваю время, которое потребуется на написание кода и добавляю к нему некоторый процент на непредвиденные проблемы. Обычно этого достаточно.»
Почему это неправильно
- Чрезмерное упрощение: Этот подход чрезмерно упрощён и не учитывает детальные аспекты выполняемых задач. Оценка — это не просто завышение необходимого времени, а понимание сложности и связанных с этим рисков.
- Неточность и неэффективность: Простое увеличение предполагаемого времени кодирования неточно отражает реальные необходимые усилия, особенно для задач, сложность или трудозатраты которых могут быть нелинейными. Этот метод может привести к неэффективному распределению ресурсов и либо к переоценке, либо к недооценке фактического необходимого времени.
- Отсутствие вовлечения заинтересованных сторон: Этот метод не предполагает вовлечения других членов команды и заинтересованных сторон, которые могут предложить ценные идеи для процесса оценки. Он не использует коллективный опыт и знания команды, что может привести к нарушению сроков проекта.
Эта ошибка часто возникает из-за недостатка опыта работы с формальными методами оценки или из-за работы в условиях, где детальное планирование не было приоритетом. Это подчёркивает необходимость структурированного подхода к оценке в управлении проектами разработки ПО, особенно для крупных или сложных проектов.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
28. Методы оценки
«Можете ли вы описать методы оценки, которые вы использовали в своих проектах, и объяснить, как они помогли вам обеспечить выполнение проектов в установленные сроки?»
Хороший ответ
В моём опыте управления проектами .NET я использовал комбинацию методов оценки для обеспечения точного прогнозирования и эффективного управления проектом. Среди них экспертная оценка (Expert Judgment), покер планирования (Planning Poker) и анализ точек использования (Case Point Analysis).
1. Экспертная оценка предполагает консультации с опытными членами команды для получения оценок на основе их прошлого опыта. Например, при работе над веб-сервисом, включающим ASP.NET Core и Entity Framework Core, я обсуждал задачи со старшими разработчиками, имеющими аналогичный опыт работы над проектами, чтобы получить реалистичное представление о трудозатратах и сроках.
2. Покер планирования - метод оценки в Agile, использующий консенсус для оценки задач. Каждый член команды предоставляет оценку, используя пронумерованные карточки, и затем следуют обсуждения, пока команда не достигнет консенсуса. Этот метод особенно полезен для вовлечения всей команды в процесс оценки, что повышает вовлечённость и точность оценок. Суть метода:
- Каждый разработчик получает карточки с номерами, представляющими собой стори-пойнты.
- Владелец продукта описывает функцию.
- Разработчики выбирают карточку, представляющую их оценку, не раскрывая её.
- Все карточки раскрываются одновременно, и разногласия обсуждаются до достижения консенсуса.
3. Анализ вариантов использования - адаптирован для оценки трудозатрат, необходимых для пользовательских историй, включающих взаимодействие с пользователями. Он учитывает сложность вариантов использования и корректирует её с учётом технических и организационных факторов.
Суть метода в том, что каждый вариант использования классифицируется как простой, средний или сложный, а затем присваивается вес на основе этих категорий. Это особенно эффективно для проектов с чёткими функциональными требованиями, таких как веб-сервис с несколькими конечными точками.
Комбинация этих методов позволяет предоставить более надёжные оценки, учитывающие неопределённости и позволяющие лучше планировать и управлять рисками. Такой подход помогает гарантировать, что проекты будут реализованы в срок и в рамках заданного объёма, даже при возникновении непредвиденных сложностей.
Часто встречающийся плохой ответ
«Я примерно по опыту оцениваю время, которое потребуется на написание кода и добавляю к нему некоторый процент на непредвиденные проблемы. Обычно этого достаточно.»
Почему это неправильно
- Чрезмерное упрощение: Этот подход чрезмерно упрощён и не учитывает детальные аспекты выполняемых задач. Оценка — это не просто завышение необходимого времени, а понимание сложности и связанных с этим рисков.
- Неточность и неэффективность: Простое увеличение предполагаемого времени кодирования неточно отражает реальные необходимые усилия, особенно для задач, сложность или трудозатраты которых могут быть нелинейными. Этот метод может привести к неэффективному распределению ресурсов и либо к переоценке, либо к недооценке фактического необходимого времени.
- Отсутствие вовлечения заинтересованных сторон: Этот метод не предполагает вовлечения других членов команды и заинтересованных сторон, которые могут предложить ценные идеи для процесса оценки. Он не использует коллективный опыт и знания команды, что может привести к нарушению сроков проекта.
Эта ошибка часто возникает из-за недостатка опыта работы с формальными методами оценки или из-за работы в условиях, где детальное планирование не было приоритетом. Это подчёркивает необходимость структурированного подхода к оценке в управлении проектами разработки ПО, особенно для крупных или сложных проектов.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👍3
День 2616. #SQLServer
SQL Server Незаметно Переименовывает Пользователя
Автор оригинала: Bart Wullems
Учитывая кучу существующих ИИ-помощников, можно было бы ожидать, что мы больше не будем тратить время на глупые проблемы. К сожалению, до этого ещё далеко. Сегодня я потерял немало времени из-за поведения SQL Server, которое кажется очевидным, если вы об этом знаете, а если не знаете —ужасно раздражает.
У меня был скрипт, который должен был быть идемпотентным: создать пользователя БД, если его не существует, или обновить его, если существует. Стандартная процедура. Вот упрощённая версия:
Выглядит нормально. Запустил один раз — работает. Запустил второй раз, и SQL Server выдаёт ошибку, что не может найти пользователя
Что происходит на самом деле?
Когда вы запускаете
Таким образом, после первого запуска пользователя
Это одно из тех явлений, которое становится понятным, как только вы разберётесь в модели данных, но никаким образом не сообщает вам, что так происходит.
Решение
Явно укажите SQL Server сохранить имя пользователя как есть, добавив
Добавление
Почему SQL Server так делает?
SQL Server различает логины (субъекты уровня сервера) и пользователей (субъекты уровня БД). Когда вы связываете пользователя с логином с помощью команды
Источник: https://bartwullems.blogspot.com/2026/03/sql-server-silently-renames-your-user.html
SQL Server Незаметно Переименовывает Пользователя
Автор оригинала: Bart Wullems
Учитывая кучу существующих ИИ-помощников, можно было бы ожидать, что мы больше не будем тратить время на глупые проблемы. К сожалению, до этого ещё далеко. Сегодня я потерял немало времени из-за поведения SQL Server, которое кажется очевидным, если вы об этом знаете, а если не знаете —ужасно раздражает.
У меня был скрипт, который должен был быть идемпотентным: создать пользователя БД, если его не существует, или обновить его, если существует. Стандартная процедура. Вот упрощённая версия:
USE [ONT_SampleDB];
GO
IF EXISTS (SELECT * FROM sys.database_principals WHERE name = N'usr_DB_reader')
BEGIN
ALTER USER [usr_DB_reader] WITH LOGIN = [lg_DB_dev_reader];
END
ELSE
BEGIN
CREATE USER [usr_DB_reader] FOR LOGIN [lg_DB_dev_reader];
END
GO
ALTER ROLE [db_datareader] ADD MEMBER [usr_DB_reader];
GO
Выглядит нормально. Запустил один раз — работает. Запустил второй раз, и SQL Server выдаёт ошибку, что не может найти пользователя
usr_DB_reader. Пользователя, которого мы только что создали. В той же базе данных. Этим же скриптом.Что происходит на самом деле?
Когда вы запускаете
ALTER USER […] WITH LOGIN = […], SQL Server переименовывает пользователя в соответствии с логином — по умолчанию, без предупреждений.Таким образом, после первого запуска пользователя
usr_DB_reader больше не существует. Он переименован в lg_DB_dev_reader, чтобы соответствовать логину. При втором запуске проверка IF EXISTS ищет usr_DB_reader, ничего не находит и переходит в ELSE — где CREATE USER завершается с ошибкой, потому что такой логин уже сопоставлен с пользователем c другим именем.Это одно из тех явлений, которое становится понятным, как только вы разберётесь в модели данных, но никаким образом не сообщает вам, что так происходит.
Решение
Явно укажите SQL Server сохранить имя пользователя как есть, добавив
NAME = к оператору ALTER USER:ALTER USER [usr_DB_reader]
WITH NAME = [usr_DB_reader],
LOGIN = [VLM\lg_DB_dev_reader];
Добавление
WITH NAME = [usr_DB_reader] говорит SQL Server: да, измени логин, но не трогай имя пользователя. Теперь скрипт действительно идемпотентный.Почему SQL Server так делает?
SQL Server различает логины (субъекты уровня сервера) и пользователей (субъекты уровня БД). Когда вы связываете пользователя с логином с помощью команды
ALTER USER … WITH LOGIN, не указывая имя, SQL Server предполагает, что вы хотите синхронизировать их — поэтому он переименовывает пользователя в соответствии с логином. Это следует соглашениям, но это не то, чего вы ожидаете, если привыкли рассматривать имена пользователей как стабильные идентификаторы.Источник: https://bartwullems.blogspot.com/2026/03/sql-server-silently-renames-your-user.html
👍4
День 2617. #Шпаргалка
Виды Классов в C#
Сегодня рассмотрим различные виды классов в C# и как они работают.
Абстрактный
Базовый класс, экземпляр которого нельзя создать. Он может содержать абстрактные и неабстрактные члены и предназначен для наследования от него.
Создать экземпляр класса Vehicle нельзя, поэтому унаследуем от него. При этом класс-наследник обязан переопределить абстрактные члены:
Запечатанный (sealed)
Специальный тип класса, который ограничивает иерархию наследования. Это предотвращает создание производных типов, что повышает безопасность кода и позволяет компилятору применять оптимизации производительности.
Статический
Экземпляр статического класса нельзя создать, и от статического класса нельзя унаследовать. Все члены должны быть помечены статическими.
Частичный
В одном и том же пространстве имён нельзя создавать несколько классов с одним именем. Частичный класс позволяет разделить объявление класса на несколько файлов. При компиляции объявления объединяются в один класс. Нельзя дублировать члены с одной сигнатурой в разных объявлениях частичного класса:
Небезопасный
Небезопасный класс позволяет использовать код с указателями:
Если вам необходимо работать с указателями, нужно включить небезопасный код в файле .csproj, установив параметр AllowUnsafeBlocks в значение true.
Запись
Запись — ссылочный тип, предназначенный для данных, а не для поведения, и по умолчанию является неизменяемой:
См. подробнее про записи.
Модификаторы доступа
-
-
-
-
-
Источник: https://www.roundthecode.com/dotnet-tutorials/c-sharp-class-types-explained-examples
Виды Классов в C#
Сегодня рассмотрим различные виды классов в C# и как они работают.
Абстрактный
Базовый класс, экземпляр которого нельзя создать. Он может содержать абстрактные и неабстрактные члены и предназначен для наследования от него.
public abstract class Vehicle
{
public abstract int Wheels { get; }
public abstract void TurnOn();
public bool Started { get; protected set; }
}
Создать экземпляр класса Vehicle нельзя, поэтому унаследуем от него. При этом класс-наследник обязан переопределить абстрактные члены:
public class Car : Vehicle
{
public override int Wheels => 4;
public override void TurnOn()
=> Started = true;
}
Запечатанный (sealed)
Специальный тип класса, который ограничивает иерархию наследования. Это предотвращает создание производных типов, что повышает безопасность кода и позволяет компилятору применять оптимизации производительности.
public sealed class Vehicle
{
}
Статический
Экземпляр статического класса нельзя создать, и от статического класса нельзя унаследовать. Все члены должны быть помечены статическими.
public static class SpeedConverter
{
public static decimal ToMph(decimal kph)
=> return kph / 1.6093m;
}
Частичный
В одном и том же пространстве имён нельзя создавать несколько классов с одним именем. Частичный класс позволяет разделить объявление класса на несколько файлов. При компиляции объявления объединяются в один класс. Нельзя дублировать члены с одной сигнатурой в разных объявлениях частичного класса:
public partial class Team
{
public Team() { }
public string Name { get; set; }
}
public partial class Team
{
public int Players { get; set; }
}
Небезопасный
Небезопасный класс позволяет использовать код с указателями:
public unsafe class MemoryReader
{
public void Read(int* value)
{
Console.WriteLine(*value);
}
}
Если вам необходимо работать с указателями, нужно включить небезопасный код в файле .csproj, установив параметр AllowUnsafeBlocks в значение true.
Запись
Запись — ссылочный тип, предназначенный для данных, а не для поведения, и по умолчанию является неизменяемой:
public record class Team(string Name, int Players);
См. подробнее про записи.
Модификаторы доступа
-
public – доступен отовсюду;-
internal – доступен внутри сборки;-
private – доступен только внутри включающего его типа;-
protected – доступен внутри включающего его типа и всех его наследников;-
file – доступен только внутри содержащего его файла исходного кода.Источник: https://www.roundthecode.com/dotnet-tutorials/c-sharp-class-types-explained-examples
👍15👎5
День 2618. #МоиИнструменты #PG
Инструменты Оптимизации Запросов в PostgreSQL. Часть 5
5. EXPLAIN ANALYZE (для всех SQL баз данных)
Что даёт: точное понимание, как БД выполняет запрос.
Тип: встроенная команда (для всех основных БД)
Зачем: показывает план выполнения запроса — как БД фактически обрабатывает SQL-запрос. Без этого оптимизация — это гадание.
Использование в разных базах данных:
Вывод (пример Postgres):
Что это значит:
- "Seq Scan" – полное сканирование таблицы (ПЛОХО – не используется индекс)
- "Rows Removed by Filter: 9847234" - Просканировано 9.8млн строк, возвращено 247
- "Execution Time: 2341ms" - 2.3 секунды
Решение – добавить индекс на поля customer_id и order_date:
После:
Что это значит:
- "Index Scan" – Используется индекс (ХОРОШО)
- "Buffers: shared hit=5" – только 5 блоков прочитано (против 185234 в предыдущем случае)
- "Execution Time: 0.112ms" – в 20000 раз быстрее
Основные шаги оптимизации запросов
1. Выполнить EXPLAIN ANALYZE
2. Обнаружить узкое место (seq scan, дорогой join или сортировку и т.п.)
3. Исправить (добавить индекс, переписать запрос, изменить порядок объединения)
4. Ещё раз выполнить EXPLAIN ANALYZE для проверки
Когда использовать
- Анализ любого медленного запроса;
- Перед написанием сложных запросов (прогноз производительности);
- После изменений схемы (проверка влияния);
- При добавлении индексов (обоснование использования).
Когда отказаться
Особых причин не использовать нет.
Скрытая функция
Сравнение планов запросов
1. Сохранить в файл
2. Сделать изменения
3. Сохранить новый план
4. Использовать утилиту визуализации плана:
- https://explain.dalibo.com/
- https://explain.depesz.com/
5. Использовать утилиту визуального сравнения (например, https://winmerge.org/)
С осторожностью
EXPLAIN с параметром ANALYZE на самом деле выполняет запрос.
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
Инструменты Оптимизации Запросов в PostgreSQL. Часть 5
5. EXPLAIN ANALYZE (для всех SQL баз данных)
Что даёт: точное понимание, как БД выполняет запрос.
Тип: встроенная команда (для всех основных БД)
Зачем: показывает план выполнения запроса — как БД фактически обрабатывает SQL-запрос. Без этого оптимизация — это гадание.
Использование в разных базах данных:
-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT … FROM orders WHERE …;
-- MySQL
EXPLAIN ANALYZE
SELECT … FROM orders WHERE …;
-- SQL Server
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT … FROM orders WHERE …;
Вывод (пример Postgres):
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders
WHERE customer_id = 12345
AND order_date >= '2024-01-01';
Seq Scan on orders (cost=0.00..185234.25 rows=1 width=120)
(actual time=0.045..2341.234 rows=247 loops=1)
Filter: ((customer_id = 12345) AND (order_date >= '2024-01-01'::date))
Rows Removed by Filter: 9847234
Buffers: shared hit=47234 read=138000
Planning Time: 0.234 ms
Execution Time: 2341.567 ms
Что это значит:
- "Seq Scan" – полное сканирование таблицы (ПЛОХО – не используется индекс)
- "Rows Removed by Filter: 9847234" - Просканировано 9.8млн строк, возвращено 247
- "Execution Time: 2341ms" - 2.3 секунды
Решение – добавить индекс на поля customer_id и order_date:
CREATE INDEX idx_orders_customer_date ON orders(customer_id, order_date);
После:
Index Scan using idx_orders_customer_date on orders
(cost=0.43..8.45 rows=1 width=120)
(actual time=0.023..0.087 rows=247 loops=1)
Index Cond: ((customer_id = 12345) AND (order_date >= '2024-01-01'::date))
Buffers: shared hit=5
Planning Time: 0.123 ms
Execution Time: 0.112 ms
Что это значит:
- "Index Scan" – Используется индекс (ХОРОШО)
- "Buffers: shared hit=5" – только 5 блоков прочитано (против 185234 в предыдущем случае)
- "Execution Time: 0.112ms" – в 20000 раз быстрее
Основные шаги оптимизации запросов
1. Выполнить EXPLAIN ANALYZE
2. Обнаружить узкое место (seq scan, дорогой join или сортировку и т.п.)
3. Исправить (добавить индекс, переписать запрос, изменить порядок объединения)
4. Ещё раз выполнить EXPLAIN ANALYZE для проверки
Когда использовать
- Анализ любого медленного запроса;
- Перед написанием сложных запросов (прогноз производительности);
- После изменений схемы (проверка влияния);
- При добавлении индексов (обоснование использования).
Когда отказаться
Особых причин не использовать нет.
Скрытая функция
Сравнение планов запросов
1. Сохранить в файл
psql -c "EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT …" > plan_before.json
2. Сделать изменения
3. Сохранить новый план
psql -c "EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT …" > plan_after.json
4. Использовать утилиту визуализации плана:
- https://explain.dalibo.com/
- https://explain.depesz.com/
5. Использовать утилиту визуального сравнения (например, https://winmerge.org/)
С осторожностью
EXPLAIN с параметром ANALYZE на самом деле выполняет запрос.
-- Удалит данные!!!
EXPLAIN ANALYZE DELETE FROM orders WHERE …;
-- Безопасное тестирование
BEGIN;
EXPLAIN ANALYZE DELETE FROM orders WHERE …;
ROLLBACK;
END;
-- Либо без ANALYZE (только оценка)
EXPLAIN DELETE FROM orders WHERE …;
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
👍17
День 2619. #ЗаметкиНаПолях
Паттерн Адаптер: Упрощаем Интеграцию со Сторонними Сервисами. Начало
Интеграция сторонних сервисов в ваше приложение может быстро стать сложной задачей. Разные API имеют разные форматы запросов, механизмы аутентификации и структуры ответов. Со временем это приводит к тесно связанному коду, который трудно поддерживать, тестировать и расширять. Именно здесь проявляется преимущество паттерна Адаптер.
Паттерн Адаптер позволяет несовместимым интерфейсам работать вместе. Он выступает в качестве моста между вашим приложением и внешней системой, преобразуя один интерфейс в другой, ожидаемый вашим приложением, что позволяет:
- отделить вашу бизнес-логику от внешних систем;
- легко переключаться между провайдерами;
- улучшить тестируемость;
- сократить количество критических изменений.
Сценарий
Есть приложение, использующее следующий интерфейс:
Всё приложение использует эту абстракцию. Однако, есть существующий сервис, производящий оплату:
Проблемы:
- сигнатуры методов отличаются;
- типы параметров отличаются;
- изменить существующий сервис невозможно.
Решение
1. Создаём адаптер
Адаптер:
- реализует интерфейс приложения (IPaymentProcessor);
- преобразует десятичное число в строку;
- делегирует вызов устаревшему сервису.
Приложение остаётся чистым и не знает об устаревшей реализации.
2. Используем адаптер
Результат:
- Приложение использует только IPaymentProcessor;
- Адаптер обрабатывает все преобразования;
- Устаревшая система полностью изолирована.
Окончание следует…
Источник: https://thecodeman.net/posts/simplifying-integration-with-adapter-pattern
Паттерн Адаптер: Упрощаем Интеграцию со Сторонними Сервисами. Начало
Интеграция сторонних сервисов в ваше приложение может быстро стать сложной задачей. Разные API имеют разные форматы запросов, механизмы аутентификации и структуры ответов. Со временем это приводит к тесно связанному коду, который трудно поддерживать, тестировать и расширять. Именно здесь проявляется преимущество паттерна Адаптер.
Паттерн Адаптер позволяет несовместимым интерфейсам работать вместе. Он выступает в качестве моста между вашим приложением и внешней системой, преобразуя один интерфейс в другой, ожидаемый вашим приложением, что позволяет:
- отделить вашу бизнес-логику от внешних систем;
- легко переключаться между провайдерами;
- улучшить тестируемость;
- сократить количество критических изменений.
Сценарий
Есть приложение, использующее следующий интерфейс:
public interface IPaymentProcessor
{
void ProcessPayment(decimal amount);
}
Всё приложение использует эту абстракцию. Однако, есть существующий сервис, производящий оплату:
public class LegacyPaymentService
{
public void MakePayment(string amount)
{
// обработка оплаты
}
}
Проблемы:
- сигнатуры методов отличаются;
- типы параметров отличаются;
- изменить существующий сервис невозможно.
Решение
1. Создаём адаптер
public class PaymentAdapter(
LegacyPaymentService legacyService) :
IPaymentProcessor
{
public void ProcessPayment(decimal amount)
{
var amntStr = amount.ToString("F2");
legacyService.MakePayment(amntStr);
}
}
Адаптер:
- реализует интерфейс приложения (IPaymentProcessor);
- преобразует десятичное число в строку;
- делегирует вызов устаревшему сервису.
Приложение остаётся чистым и не знает об устаревшей реализации.
2. Используем адаптер
LegacyPaymentService legacySvc = new();
IPaymentProcessor processor =
new PaymentAdapter(legacySvc);
processor.ProcessPayment(123.4567868m);
Результат:
- Приложение использует только IPaymentProcessor;
- Адаптер обрабатывает все преобразования;
- Устаревшая система полностью изолирована.
Окончание следует…
Источник: https://thecodeman.net/posts/simplifying-integration-with-adapter-pattern
👍18
День 2620. #ЗаметкиНаПолях
Паттерн Адаптер: Упрощаем Интеграцию со Сторонними Сервисами. Окончание
Начало
Пример из реальной жизни: интеграция с облачным хранилищем
Представьте себе систему, поддерживающую несколько облачных провайдеров:
- Amazon S3
- Azure Blob Storage
- Google Cloud Storage
У каждого провайдера свои SDK и API. Без адаптера код становится тесно связанным с конкретной реализацией.
1. Определение общего интерфейса
Интерфейс представляет контракт вашей системы и стабильную абстракцию. Ваше приложение должно зависеть только от него.
2. Реализуем адаптер (пример для Google Cloud)
Адаптер:
- оборачивает SDK от Google,
- приводит вызовы к вашему интерфейсу,
- скрывает детали реализации.
3. Настройка внедрения зависимостей
Пояснение
- адаптер выбирается динамически,
- обеспечивается гибкость системы,
- есть возможность переключаться во время выполнения.
Когда использовать Адаптер
- интеграция сторонних API,
- работа с устаревшими системами,
- стандартизация нескольких провайдеров,
- переключение реализаций.
Когда не использовать
- интерфейсы уже совместимы,
- преобразование тривиально,
- производительность крайне важна,
- абстракция добавляет ненужную сложность.
Источник: https://thecodeman.net/posts/simplifying-integration-with-adapter-pattern
Паттерн Адаптер: Упрощаем Интеграцию со Сторонними Сервисами. Окончание
Начало
Пример из реальной жизни: интеграция с облачным хранилищем
Представьте себе систему, поддерживающую несколько облачных провайдеров:
- Amazon S3
- Azure Blob Storage
- Google Cloud Storage
У каждого провайдера свои SDK и API. Без адаптера код становится тесно связанным с конкретной реализацией.
1. Определение общего интерфейса
public interface ICloudStorage
{
Task UploadAsync(string container,
string file, Stream stream);
Task<Stream> DownloadAsync(
string container, string file);
Task DeleteAsync(string container,
string file);
}
Интерфейс представляет контракт вашей системы и стабильную абстракцию. Ваше приложение должно зависеть только от него.
2. Реализуем адаптер (пример для Google Cloud)
public class GoogleCloudStorageAdapter
: ICloudStorage
{
private readonly StorageClient _client;
public GoogleCloudStorageAdapter(
StorageClient client)
{
_client = client;
}
public async Task UploadAsync(
string container, string file, Stream stream)
{
await _client.UploadObjectAsync(
container, file, null, stream);
}
public async Task<Stream> DownloadAsync(
string container, string file)
{
MemoryStream stream = new();
await _client.DownloadObjectAsync(
container, file, stream);
stream.Position = 0;
return stream;
}
public async Task DeleteAsync(
string container, string file)
{
await _client.DeleteObjectAsync(container, file);
}
}
Адаптер:
- оборачивает SDK от Google,
- приводит вызовы к вашему интерфейсу,
- скрывает детали реализации.
3. Настройка внедрения зависимостей
builder.Services
.AddTransient<Func<string, ICloudStorage>>(
sp => provider =>
{
return provider switch
{
"Azure" => sp.GetRequiredService<AzureBlobStorageAdapter>(),
"Google" => sp.GetRequiredService<GoogleCloudStorageAdapter>(),
"AWS" => sp.GetRequiredService<S3StorageAdapter>(),
_ => throw new ArgumentException("Неподдерживаемый провайдер")
};
});
Пояснение
- адаптер выбирается динамически,
- обеспечивается гибкость системы,
- есть возможность переключаться во время выполнения.
Когда использовать Адаптер
- интеграция сторонних API,
- работа с устаревшими системами,
- стандартизация нескольких провайдеров,
- переключение реализаций.
Когда не использовать
- интерфейсы уже совместимы,
- преобразование тривиально,
- производительность крайне важна,
- абстракция добавляет ненужную сложность.
Источник: https://thecodeman.net/posts/simplifying-integration-with-adapter-pattern
👍11
День 2621. #ЧтоНовенького #МоиИнструменты
Bookmark Studio Закладки на Стеройдах в Visual Studio
Закладки в Visual Studio всегда были простой и надёжной функцией. Многие разработчики регулярно ими пользуются. Он полезны, но имеют несколько недостатков, которые мешали им быть настолько эффективными и актуальными, насколько они могли бы быть.
Навигация - одна из самых больших проблем. Можно было перемещаться между закладками, но не было простого способа перейти непосредственно к конкретной закладке с помощью клавиатуры. Это неудобно, когда закладок больше нескольких штук. Ещё один распространённый запрос пользователей – возможность делиться закладками с коллегами или повторно использовать их в разных репозиториях, ветках или пул-реквестах.
Bookmark Studio - новое экспериментальное расширение Visual Studio от Мэдса Кристенсена, которое развивает существующий опыт работы с закладками. Вот его основные функции.
1. Навигация по слотам. Закладки можно назначать слотам с 1 по 9 и переходить к ним напрямую с помощью простых сочетаний клавиш, таких как
2. Менеджер закладок (см. картинку). Отображает все закладки в одном месте и упрощает просмотр, поиск и навигацию между ними. Вы можете фильтровать по имени, файлу, местоположению, цвету или слоту и переходить непосредственно к закладке двойным щелчком или навигацией с помощью клавиатуры. Он разработан для того, чтобы упростить повторное обращение к закладкам, особенно при переключении контекста или возвращении к коду позже.
3. Метки, цвета и папки для закладок. Ничего из этого не требуется, и вы можете продолжать использовать закладки по-прежнему. Но когда вы отлаживаете, рефакторите, проверяете код или исследуете незнакомые области кодовой базы, этот дополнительный контекст поможет сделать закладки более полезными и упростить понимание их работы. Все метаданные закладок хранятся для каждого решения, поэтому они остаются с вашей работой между сессиями.
4. Экспорт. Закладки часто наиболее ценны, когда они отражают намерение, а не просто местоположение. Bookmark Studio позволяет легко экспортировать закладки в виде обычного текста, Markdown или CSV. Т.е. вы можете включать закладки в пул-реквесты, делиться с коллегами или перемещать полезные наборы закладок между репозиториями.
5. Отслеживание. Bookmark Studio отслеживает закладки по мере перемещения текста во время редактирования, поэтому они остаются прикрепленными к соответствующему коду, а не смещаются на неправильную строку.
Итого
Если вы уже используете закладки в Visual Studio, Bookmark Studio покажется вам знакомым за считанные минуты. А если вы когда-либо хотели, чтобы закладки могли делать немного больше, это расширение стоит посмотреть.
Источник: https://devblogs.microsoft.com/visualstudio/bookmark-studio-evolving-bookmarks-in-visual-studio/
Bookmark Studio Закладки на Стеройдах в Visual Studio
Закладки в Visual Studio всегда были простой и надёжной функцией. Многие разработчики регулярно ими пользуются. Он полезны, но имеют несколько недостатков, которые мешали им быть настолько эффективными и актуальными, насколько они могли бы быть.
Навигация - одна из самых больших проблем. Можно было перемещаться между закладками, но не было простого способа перейти непосредственно к конкретной закладке с помощью клавиатуры. Это неудобно, когда закладок больше нескольких штук. Ещё один распространённый запрос пользователей – возможность делиться закладками с коллегами или повторно использовать их в разных репозиториях, ветках или пул-реквестах.
Bookmark Studio - новое экспериментальное расширение Visual Studio от Мэдса Кристенсена, которое развивает существующий опыт работы с закладками. Вот его основные функции.
1. Навигация по слотам. Закладки можно назначать слотам с 1 по 9 и переходить к ним напрямую с помощью простых сочетаний клавиш, таких как
Alt+Shift+1 – Alt+Shift+9. Это делает закладки более продуманными и удобными для быстрого доступа к нескольким важным разделам. Новые закладки автоматически назначаются следующему доступному слоту, если это возможно, поэтому быстрая навигация часто работает без дополнительной настройки. Bookmark Studio также интегрируется с существующими командами закладок Visual Studio, т.е. текущие сочетания клавиш продолжат работать.2. Менеджер закладок (см. картинку). Отображает все закладки в одном месте и упрощает просмотр, поиск и навигацию между ними. Вы можете фильтровать по имени, файлу, местоположению, цвету или слоту и переходить непосредственно к закладке двойным щелчком или навигацией с помощью клавиатуры. Он разработан для того, чтобы упростить повторное обращение к закладкам, особенно при переключении контекста или возвращении к коду позже.
3. Метки, цвета и папки для закладок. Ничего из этого не требуется, и вы можете продолжать использовать закладки по-прежнему. Но когда вы отлаживаете, рефакторите, проверяете код или исследуете незнакомые области кодовой базы, этот дополнительный контекст поможет сделать закладки более полезными и упростить понимание их работы. Все метаданные закладок хранятся для каждого решения, поэтому они остаются с вашей работой между сессиями.
4. Экспорт. Закладки часто наиболее ценны, когда они отражают намерение, а не просто местоположение. Bookmark Studio позволяет легко экспортировать закладки в виде обычного текста, Markdown или CSV. Т.е. вы можете включать закладки в пул-реквесты, делиться с коллегами или перемещать полезные наборы закладок между репозиториями.
5. Отслеживание. Bookmark Studio отслеживает закладки по мере перемещения текста во время редактирования, поэтому они остаются прикрепленными к соответствующему коду, а не смещаются на неправильную строку.
Итого
Если вы уже используете закладки в Visual Studio, Bookmark Studio покажется вам знакомым за считанные минуты. А если вы когда-либо хотели, чтобы закладки могли делать немного больше, это расширение стоит посмотреть.
Источник: https://devblogs.microsoft.com/visualstudio/bookmark-studio-evolving-bookmarks-in-visual-studio/
👍8
День 2622. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
29. Командная работа
«Расскажите, как вы развивали командную работу в ваших проектах? Какие стратегии и инструменты вы использовали для обеспечения эффективной коммуникации и интеграции между членами команды?»
Хороший ответ
По моему опыту, эффективное командное взаимодействие в проектах разработки включает в себя сочетание чёткой коммуникации, общности целей и стратегического использования инструментов для совместной работы. Вот некоторые важные аспекты.
- Регулярная коммуникация: я выступаю за ежедневные совещания или встречи в виртуальном формате. Эти встречи помогают всем быть в курсе прогресса проекта и любых препятствий, которые могут потребовать решения. Например, во время недавнего проекта мы использовали Microsoft Teams для ежедневных митингов, что поддерживало вовлечённость и информированность удалённых членов команды.
- Проверки кода: внедрение надёжного процесса проверки кода имеет жизненно важное значение. Мы используем пул-реквесты, которые не только облегчают коллегиальную проверку, но и интегрируют проверки в конвейер CI/CD, где код автоматически собирается и запускаются тесты. Этот процесс гарантирует, что код соответствует стандартам качества до слияния, и способствует обмену знаниями и наставничеству внутри команды.
- Инструменты для совместной работы: использование таких инструментов, как Git, для контроля версий и ветвления функций позволяет нам работать над различными аспектами проекта, не мешая друг другу. Мы регулярно интегрируем наши ветки, чтобы уменьшить проблемы интеграции.
- Общая документация: мы храним документацию по проекту в централизованном ресурсе, что помогает новым членам команды быстрее адаптироваться и служит справочным материалом для всей команды.
- Обратная связь: регулярные ретроспективы позволяют команде анализировать, что работало хорошо, а что нет. Эта непрерывная обратная связь помогает улучшать процессы и взаимодействие, обеспечивая более эффективное сотрудничество в будущих спринтах.
Сочетание этих стратегий и инструментов помогает делать команды продуктивными, сплочёнными и способными эффективно решать сложные проекты.
Часто встречающийся плохой ответ
«Пока каждый выполняет свою работу и соблюдает сроки, нет особой необходимости в дополнительном сотрудничестве или частых встречах. Мы просто отправляем дневные отчёты через e-mail или общаемся в чатах, чтобы держать всех в курсе».
Почему это неправильно:
- Отсутствие активного участия: ответ демонстрирует пассивный подход к сотрудничеству, полагающийся на индивидуальные усилия и минимальное взаимодействие. Эффективное командное сотрудничество требует более активных стратегий вовлечения для управления зависимостями и эффективной интеграции работы.
- Недооценка ценности взаимодействия: утверждение, что достаточно отчётов о проделанной работе по e-mail, игнорирует преимущества общения в режиме реального времени и интерактивных обсуждений, которые имеют решающее значение для быстрого и эффективного решения сложных проблем.
- Игнорирование командной динамики: такой подход не способствует формированию командной культуры, которая поощряет общую ответственность и коллективное решение проблем. Он может привести к изоляции среди членов команды и потенциально затруднить эффективное реагирование команды на изменения и вызовы.
Эта ошибка часто возникает из-за недостаточного понимания важности акцента на командной динамике и коммуникации. Она также может быть вызвана предыдущим опытом работы в средах, где приоритет отдавался индивидуальному вкладу, а не командному сотрудничеству, либо в небольших проектах, что менее эффективно в более крупных или сложных проектах.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
29. Командная работа
«Расскажите, как вы развивали командную работу в ваших проектах? Какие стратегии и инструменты вы использовали для обеспечения эффективной коммуникации и интеграции между членами команды?»
Хороший ответ
По моему опыту, эффективное командное взаимодействие в проектах разработки включает в себя сочетание чёткой коммуникации, общности целей и стратегического использования инструментов для совместной работы. Вот некоторые важные аспекты.
- Регулярная коммуникация: я выступаю за ежедневные совещания или встречи в виртуальном формате. Эти встречи помогают всем быть в курсе прогресса проекта и любых препятствий, которые могут потребовать решения. Например, во время недавнего проекта мы использовали Microsoft Teams для ежедневных митингов, что поддерживало вовлечённость и информированность удалённых членов команды.
- Проверки кода: внедрение надёжного процесса проверки кода имеет жизненно важное значение. Мы используем пул-реквесты, которые не только облегчают коллегиальную проверку, но и интегрируют проверки в конвейер CI/CD, где код автоматически собирается и запускаются тесты. Этот процесс гарантирует, что код соответствует стандартам качества до слияния, и способствует обмену знаниями и наставничеству внутри команды.
- Инструменты для совместной работы: использование таких инструментов, как Git, для контроля версий и ветвления функций позволяет нам работать над различными аспектами проекта, не мешая друг другу. Мы регулярно интегрируем наши ветки, чтобы уменьшить проблемы интеграции.
- Общая документация: мы храним документацию по проекту в централизованном ресурсе, что помогает новым членам команды быстрее адаптироваться и служит справочным материалом для всей команды.
- Обратная связь: регулярные ретроспективы позволяют команде анализировать, что работало хорошо, а что нет. Эта непрерывная обратная связь помогает улучшать процессы и взаимодействие, обеспечивая более эффективное сотрудничество в будущих спринтах.
Сочетание этих стратегий и инструментов помогает делать команды продуктивными, сплочёнными и способными эффективно решать сложные проекты.
Часто встречающийся плохой ответ
«Пока каждый выполняет свою работу и соблюдает сроки, нет особой необходимости в дополнительном сотрудничестве или частых встречах. Мы просто отправляем дневные отчёты через e-mail или общаемся в чатах, чтобы держать всех в курсе».
Почему это неправильно:
- Отсутствие активного участия: ответ демонстрирует пассивный подход к сотрудничеству, полагающийся на индивидуальные усилия и минимальное взаимодействие. Эффективное командное сотрудничество требует более активных стратегий вовлечения для управления зависимостями и эффективной интеграции работы.
- Недооценка ценности взаимодействия: утверждение, что достаточно отчётов о проделанной работе по e-mail, игнорирует преимущества общения в режиме реального времени и интерактивных обсуждений, которые имеют решающее значение для быстрого и эффективного решения сложных проблем.
- Игнорирование командной динамики: такой подход не способствует формированию командной культуры, которая поощряет общую ответственность и коллективное решение проблем. Он может привести к изоляции среди членов команды и потенциально затруднить эффективное реагирование команды на изменения и вызовы.
Эта ошибка часто возникает из-за недостаточного понимания важности акцента на командной динамике и коммуникации. Она также может быть вызвана предыдущим опытом работы в средах, где приоритет отдавался индивидуальному вкладу, а не командному сотрудничеству, либо в небольших проектах, что менее эффективно в более крупных или сложных проектах.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
День 2623. #Карьера #SystemDesign
Как я Освоил Системное Проектирование. Начало
Путь от провала на собеседовании до проектирования масштабируемых производственных систем.
Автор оригинала: Soma Sharma
Собеседование, которое изменило всё
Google. Второй раунд. Собеседование по системному проектированию: «Спроектируйте ленту Instagram для 2 миллиардов пользователей». У меня в голове всё помутнело. Я начал мямлить что-то о REST API. Упомянул MySQL. Поговорил о кэшировании… А потом тишина. Я понятия не имел, как это делать.
Шесть месяцев спустя я успешно прошёл собеседования по проектированию систем в Meta, Amazon и Netflix. Вот путь от полной растерянности до уверенного в себе системного проектировщика.
1. Я признал, что ничего не знал (и это нормально)
Годами я избегал проектирования систем. Я видел видео под названием «Разрабатываем Твиттер» и думал: «Это для архитекторов, а не для разработчиков, как я». Нет. Проектирование систем — это для всех, кто хочет понять, как ПО работает в масштабе. Я перестал спрашивать: «Достаточно ли я умён для этого?» и начал спрашивать: «Что нужно изучить в первую очередь?»
Проектирование систем — это набор концепций:
1) Инфраструктура:
- Как запросы проходят через интернет;
- Что происходит, когда вы вводите URL-адрес;
- DNS, балансировщики нагрузки, CDN.
2) Данные:
- Где хранить различные типы данных;
- Как сделать БД быстрыми;
- Когда использовать SQL, а когда NoSQL.
3) Масштабирование:
- Обработка 1 тыс пользователей против 1 млн;
- Стратегии кэширования;
- Горизонтальное и вертикальное масштабирование.
4) Надёжность:
- Что происходит при сбоях серверов;
- Как избежать единой точки отказа;
- Стратегии резервного копирования и восстановления.
2. Я разбил «проектирование систем» на части
1) Основы (недели 1–2)
Что происходит, когда вы набираете google.com?
- Поиск DNS (домен → IP-адрес);
- Установление TCP-соединения;
- Отправка HTTP-запроса;
- Обработка запроса сервером;
- Отправка ответа;
- Отображение страницы браузером.
Изученные концепции:
- DNS (телефонная книга интернета);
- Балансировка нагрузки (распределение трафика);
- CDN (сети доставки контента);
- Протоколы HTTP/HTTPS.
2) Данные и хранилища (недели 3–4)
SQL или NoSQL — когда что использовать?
Изученные концепции:
- SQL: структурированные данные, связи, ACID-транзакции;
- NoSQL: гибкая схема, горизонтальное масштабирование, итоговая согласованность;
- Индексирование: ускорение запросов в 100 раз;
- Репликация: копирование данных для повышения надёжности;
- Шардинг: разделение данных между несколькими БД.
Вывод: нет «лучшей» БД, есть подходящая для конкретного случая.
3) Методы масштабирования (недели 5–6)
Как системы обрабатывают миллионы пользователей?
- Вертикальное масштабирование: большие серверы (ограниченно, дорого);
- Горизонтальное масштабирование: больше серверов (неограниченно, сложно).
Кэширование:
- Хранение часто используемых данных в памяти (Redis, Memcached);
- 90% запросов попадают в кэш, а не в БД;
- Ускоряет работу систем в 100 раз.
Балансировка нагрузки:
- Распределение запросов между несколькими серверами: по очереди, по наименьшему количеству соединений, по хэшу IP;
- Предотвращает перегрузку какого-либо отдельного сервера.
Очереди сообщений:
- Разделение сервисов;
- Обработка пиковых нагрузок;
- Асинхронная обработка задач.
4) Архитектурные шаблоны (недели 7–8)
Монолитная архитектура:
✅ Простота разработки и развёртывания;
✅ Лёгкость понимания;
❌ Сложность масштабирования отдельных частей независимо друг от друга;
❌ Сбой в одном месте ведёт к сбою всей системы.
Микросервисы:
✅ Независимое масштабирование компонентов;
✅ Разные команды отвечают за разные сервисы;
❌ Сложное развёртывание;
❌ Проблемы распределённых систем.
Архитектура, управляемая событиями:
- Сервисы взаимодействуют посредством событий;
- Слабая связанность;
- Kafka, RabbitMQ для передачи сообщений.
Архитектура — это не вопрос «что лучше», а вопрос «что подходит для вашего масштаба и команды».
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
Как я Освоил Системное Проектирование. Начало
Путь от провала на собеседовании до проектирования масштабируемых производственных систем.
Автор оригинала: Soma Sharma
Собеседование, которое изменило всё
Google. Второй раунд. Собеседование по системному проектированию: «Спроектируйте ленту Instagram для 2 миллиардов пользователей». У меня в голове всё помутнело. Я начал мямлить что-то о REST API. Упомянул MySQL. Поговорил о кэшировании… А потом тишина. Я понятия не имел, как это делать.
Шесть месяцев спустя я успешно прошёл собеседования по проектированию систем в Meta, Amazon и Netflix. Вот путь от полной растерянности до уверенного в себе системного проектировщика.
1. Я признал, что ничего не знал (и это нормально)
Годами я избегал проектирования систем. Я видел видео под названием «Разрабатываем Твиттер» и думал: «Это для архитекторов, а не для разработчиков, как я». Нет. Проектирование систем — это для всех, кто хочет понять, как ПО работает в масштабе. Я перестал спрашивать: «Достаточно ли я умён для этого?» и начал спрашивать: «Что нужно изучить в первую очередь?»
Проектирование систем — это набор концепций:
1) Инфраструктура:
- Как запросы проходят через интернет;
- Что происходит, когда вы вводите URL-адрес;
- DNS, балансировщики нагрузки, CDN.
2) Данные:
- Где хранить различные типы данных;
- Как сделать БД быстрыми;
- Когда использовать SQL, а когда NoSQL.
3) Масштабирование:
- Обработка 1 тыс пользователей против 1 млн;
- Стратегии кэширования;
- Горизонтальное и вертикальное масштабирование.
4) Надёжность:
- Что происходит при сбоях серверов;
- Как избежать единой точки отказа;
- Стратегии резервного копирования и восстановления.
2. Я разбил «проектирование систем» на части
1) Основы (недели 1–2)
Что происходит, когда вы набираете google.com?
- Поиск DNS (домен → IP-адрес);
- Установление TCP-соединения;
- Отправка HTTP-запроса;
- Обработка запроса сервером;
- Отправка ответа;
- Отображение страницы браузером.
Изученные концепции:
- DNS (телефонная книга интернета);
- Балансировка нагрузки (распределение трафика);
- CDN (сети доставки контента);
- Протоколы HTTP/HTTPS.
2) Данные и хранилища (недели 3–4)
SQL или NoSQL — когда что использовать?
Изученные концепции:
- SQL: структурированные данные, связи, ACID-транзакции;
- NoSQL: гибкая схема, горизонтальное масштабирование, итоговая согласованность;
- Индексирование: ускорение запросов в 100 раз;
- Репликация: копирование данных для повышения надёжности;
- Шардинг: разделение данных между несколькими БД.
Вывод: нет «лучшей» БД, есть подходящая для конкретного случая.
3) Методы масштабирования (недели 5–6)
Как системы обрабатывают миллионы пользователей?
- Вертикальное масштабирование: большие серверы (ограниченно, дорого);
- Горизонтальное масштабирование: больше серверов (неограниченно, сложно).
Кэширование:
- Хранение часто используемых данных в памяти (Redis, Memcached);
- 90% запросов попадают в кэш, а не в БД;
- Ускоряет работу систем в 100 раз.
Балансировка нагрузки:
- Распределение запросов между несколькими серверами: по очереди, по наименьшему количеству соединений, по хэшу IP;
- Предотвращает перегрузку какого-либо отдельного сервера.
Очереди сообщений:
- Разделение сервисов;
- Обработка пиковых нагрузок;
- Асинхронная обработка задач.
4) Архитектурные шаблоны (недели 7–8)
Монолитная архитектура:
✅ Простота разработки и развёртывания;
✅ Лёгкость понимания;
❌ Сложность масштабирования отдельных частей независимо друг от друга;
❌ Сбой в одном месте ведёт к сбою всей системы.
Микросервисы:
✅ Независимое масштабирование компонентов;
✅ Разные команды отвечают за разные сервисы;
❌ Сложное развёртывание;
❌ Проблемы распределённых систем.
Архитектура, управляемая событиями:
- Сервисы взаимодействуют посредством событий;
- Слабая связанность;
- Kafka, RabbitMQ для передачи сообщений.
Архитектура — это не вопрос «что лучше», а вопрос «что подходит для вашего масштаба и команды».
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
👍16
День 2624. #Карьера #SystemDesign
Как я Освоил Системное Проектирование. Продолжение
Начало
3. Я перестал смотреть обучающие видео и начал смотреть, как люди думают
Переломный момент: пробные собеседования. Вместо того чтобы смотреть, как кто-то объясняет концепции, я смотрел, как люди решают задачи в реальном времени.
Обучающие видео учат вас, что делать. Пробные собеседования учат, как думать. Кандидаты на пробных собеседованиях:
- Задавали уточняющие вопросы;
- Совершали ошибки и исправляли их;
- Обсуждали компромиссы;
- Меняли подходы в процессе проектирования.
Я научился процессу, а не только ответам.
Что я узнал, наблюдая?
1) Всегда задавайте уточняющие вопросы
- Каков масштаб? (1000 пользователей? 1 миллиард?)
- Каковы основные функции?
- Что важнее: скорость или стабильность?
- Для чего мы оптимизируем (время или размер)?
2) Чётко определите требования
Функциональные:
- Публикация фото;
- Подписка на других;
- Просмотр ленты.
Нефункциональные:
- 100 миллионов активных пользователей в день;
- Загрузка ленты менее чем за 200 мс;
- 99,9% времени безотказной работы;
- 10 миллионов фотографий загружается ежедневно.
3) Всегда обсуждайте компромиссы
Никогда не говорите: «Мы будем использовать Redis для кэширования».
Говорите: «Мы будем использовать Redis для кэширования, потому что он работает в оперативной памяти (быстро), но нам понадобится стратегия резервного копирования, поскольку данные изменчивы».
4. Я начал рисовать (хотя не умею)
Неожиданное открытие: эскизы помогли во всём разобраться.
Я не художник. Мои диаграммы — это просто прямоугольники и стрелки. Но рисунок «клиент → балансировщик нагрузки → серверы приложений → база данных» позволяет наглядно представить абстрактные понятия.
1) Поток запроса стал реальным
Когда я нарисовал путь запроса пользователя, стало:
- Видно, где возникают узкие места;
- Понятно, почему помогает кэширование;
- Очевидны точки отказа.
2) Компоненты обрели смысл
Рисование поможет понять:
- Зачем размещать кэш между приложением и БД;
- Где разместить очередь сообщений;
- Когда следует разделять на микросервисы.
3) Компромиссы стали очевидны
Рисование двух подходов рядом покажет:
- Какой дизайн проще;
- Какой масштабируется лучше;
- Какой стоит дороже.
Процесс рисования
1) Нарисуйте счастливый сценарий (всё работает);
2) Добавьте сценарии сбоев (что ломается?);
3) Добавьте решения (кэширование, репликация, балансировка нагрузки);
4) Оцените показатели (запросы в секунду, хранилище, пропускная способность).
Даже сегодня, когда я застреваю, я беру бумагу и ручку. 5-минутный набросок часто даст больше ясности, чем 2 часа чтения.
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
Как я Освоил Системное Проектирование. Продолжение
Начало
3. Я перестал смотреть обучающие видео и начал смотреть, как люди думают
Переломный момент: пробные собеседования. Вместо того чтобы смотреть, как кто-то объясняет концепции, я смотрел, как люди решают задачи в реальном времени.
Обучающие видео учат вас, что делать. Пробные собеседования учат, как думать. Кандидаты на пробных собеседованиях:
- Задавали уточняющие вопросы;
- Совершали ошибки и исправляли их;
- Обсуждали компромиссы;
- Меняли подходы в процессе проектирования.
Я научился процессу, а не только ответам.
Что я узнал, наблюдая?
1) Всегда задавайте уточняющие вопросы
- Каков масштаб? (1000 пользователей? 1 миллиард?)
- Каковы основные функции?
- Что важнее: скорость или стабильность?
- Для чего мы оптимизируем (время или размер)?
2) Чётко определите требования
Функциональные:
- Публикация фото;
- Подписка на других;
- Просмотр ленты.
Нефункциональные:
- 100 миллионов активных пользователей в день;
- Загрузка ленты менее чем за 200 мс;
- 99,9% времени безотказной работы;
- 10 миллионов фотографий загружается ежедневно.
3) Всегда обсуждайте компромиссы
Никогда не говорите: «Мы будем использовать Redis для кэширования».
Говорите: «Мы будем использовать Redis для кэширования, потому что он работает в оперативной памяти (быстро), но нам понадобится стратегия резервного копирования, поскольку данные изменчивы».
4. Я начал рисовать (хотя не умею)
Неожиданное открытие: эскизы помогли во всём разобраться.
Я не художник. Мои диаграммы — это просто прямоугольники и стрелки. Но рисунок «клиент → балансировщик нагрузки → серверы приложений → база данных» позволяет наглядно представить абстрактные понятия.
1) Поток запроса стал реальным
Когда я нарисовал путь запроса пользователя, стало:
- Видно, где возникают узкие места;
- Понятно, почему помогает кэширование;
- Очевидны точки отказа.
2) Компоненты обрели смысл
Рисование поможет понять:
- Зачем размещать кэш между приложением и БД;
- Где разместить очередь сообщений;
- Когда следует разделять на микросервисы.
3) Компромиссы стали очевидны
Рисование двух подходов рядом покажет:
- Какой дизайн проще;
- Какой масштабируется лучше;
- Какой стоит дороже.
Процесс рисования
1) Нарисуйте счастливый сценарий (всё работает);
2) Добавьте сценарии сбоев (что ломается?);
3) Добавьте решения (кэширование, репликация, балансировка нагрузки);
4) Оцените показатели (запросы в секунду, хранилище, пропускная способность).
Даже сегодня, когда я застреваю, я беру бумагу и ручку. 5-минутный набросок часто даст больше ясности, чем 2 часа чтения.
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
👍9
День 2625. #Карьера #SystemDesign
Как я Освоил Системное Проектирование. Продолжение
Начало
Продолжение
5. Я проектировал реальные системы (на бумаге, а затем в коде)
Теория без практики бесполезна. Освоив основы, я перестал просто наблюдать. Я начал проектировать системы. Каждое воскресенье я выбирал реальную систему: WhatsApp, YouTube, Uber, Instagram, TinyURL, Netflix, Twitter, Dropbox.
Шаблон разработки системы
1) Функциональные требования (Что нужно делать?)
Пример (Twitter):
- Публиковать твиты (280 символов);
- Подписываться на пользователей;
- Просматривать ленту (твиты от людей, на которых вы подписаны);
- Лайки/ретвиты.
2) Нефункциональные требования (Масштабируемость, производительность, доступность)
- 300 млн активных пользователей;
- 500 млн твитов в день;
- Загрузка ленты <300 мс;
- 99,95% времени безотказной работы.
3) Оценка (приблизительные расчёты)
Хранилище:
- 500 млн твитов в день × 280 символов × 365 дней = 51 ТБ/год (только текст);
- Фотографии: 200 млн/день × 200 КБ = 40 ТБ/день;
- Видео: отдельный расчёт.
Трафик:
500 млн твитов/день ÷ 86400 секунд = ~5800 твитов/секунду.
Пик: 5x среднее значение = 29000 твитов/секунду
4) Высокоуровневый дизайн (нарисуйте архитектуру)
Клиент (веб/мобильное приложение) -> Балансировщик нагрузки -> API-серверы (сервис твитов, сервис ленты, сервис пользователей) -> Кэш (Redis) + БД (PostgreSQL, Cassandra) -> Объектное хранилище (S3 для медиафайлов).
5) Детальный дизайн (подробный анализ компонентов)
Как сгенерировать ленту?
- Подход 1: Пул-модель (интенсивное чтение)
Когда пользователь открывает приложение, запросить все подписки, получить последние твиты, объединить и отсортировать по времени.
Проблема: медленно для пользователей, подписанных на тысячи человек.
- Подход 2: Пуш-модель (интенсивная запись)
Когда кто-то публикует твит, отправить его во все ленты подписчиков. Быстрое чтение (предварительно вычислено).
Проблема: дорого для знаменитостей (миллионы подписчиков).
- Подход 3: Гибридный
Пул для твитов знаменитостей. Пуш для обычных пользователей.
6) Масштабирование и оптимизация
- Добавить кэширование (Redis);
- Шардирование базы данных (по user_id);
- Асинхронная обработка (очереди сообщений);
- CDN для медиафайлов.
7) Обработка сбоев
- Что если БД выйдет из строя? (Репликация)
- Что если сервер приложения выйдет из строя? (Проверки работоспособности балансировщика нагрузки)
- Что если кэш выйдет из строя? (стратегия Cache-aside).
Я проектировал по одной системе в неделю в течение 12 недель. К 5й системе я перестал гуглить решения, а стал мыслить самостоятельно. К 10й я смог сравнивать различные подходы и обосновывать свой выбор. В этом разница между запоминанием и пониманием. Я также читал решения распространённых задач проектирования систем, чтобы выявить недостатки своего решения и улучшить его.
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
Как я Освоил Системное Проектирование. Продолжение
Начало
Продолжение
5. Я проектировал реальные системы (на бумаге, а затем в коде)
Теория без практики бесполезна. Освоив основы, я перестал просто наблюдать. Я начал проектировать системы. Каждое воскресенье я выбирал реальную систему: WhatsApp, YouTube, Uber, Instagram, TinyURL, Netflix, Twitter, Dropbox.
Шаблон разработки системы
1) Функциональные требования (Что нужно делать?)
Пример (Twitter):
- Публиковать твиты (280 символов);
- Подписываться на пользователей;
- Просматривать ленту (твиты от людей, на которых вы подписаны);
- Лайки/ретвиты.
2) Нефункциональные требования (Масштабируемость, производительность, доступность)
- 300 млн активных пользователей;
- 500 млн твитов в день;
- Загрузка ленты <300 мс;
- 99,95% времени безотказной работы.
3) Оценка (приблизительные расчёты)
Хранилище:
- 500 млн твитов в день × 280 символов × 365 дней = 51 ТБ/год (только текст);
- Фотографии: 200 млн/день × 200 КБ = 40 ТБ/день;
- Видео: отдельный расчёт.
Трафик:
500 млн твитов/день ÷ 86400 секунд = ~5800 твитов/секунду.
Пик: 5x среднее значение = 29000 твитов/секунду
4) Высокоуровневый дизайн (нарисуйте архитектуру)
Клиент (веб/мобильное приложение) -> Балансировщик нагрузки -> API-серверы (сервис твитов, сервис ленты, сервис пользователей) -> Кэш (Redis) + БД (PostgreSQL, Cassandra) -> Объектное хранилище (S3 для медиафайлов).
5) Детальный дизайн (подробный анализ компонентов)
Как сгенерировать ленту?
- Подход 1: Пул-модель (интенсивное чтение)
Когда пользователь открывает приложение, запросить все подписки, получить последние твиты, объединить и отсортировать по времени.
Проблема: медленно для пользователей, подписанных на тысячи человек.
- Подход 2: Пуш-модель (интенсивная запись)
Когда кто-то публикует твит, отправить его во все ленты подписчиков. Быстрое чтение (предварительно вычислено).
Проблема: дорого для знаменитостей (миллионы подписчиков).
- Подход 3: Гибридный
Пул для твитов знаменитостей. Пуш для обычных пользователей.
6) Масштабирование и оптимизация
- Добавить кэширование (Redis);
- Шардирование базы данных (по user_id);
- Асинхронная обработка (очереди сообщений);
- CDN для медиафайлов.
7) Обработка сбоев
- Что если БД выйдет из строя? (Репликация)
- Что если сервер приложения выйдет из строя? (Проверки работоспособности балансировщика нагрузки)
- Что если кэш выйдет из строя? (стратегия Cache-aside).
Я проектировал по одной системе в неделю в течение 12 недель. К 5й системе я перестал гуглить решения, а стал мыслить самостоятельно. К 10й я смог сравнивать различные подходы и обосновывать свой выбор. В этом разница между запоминанием и пониманием. Я также читал решения распространённых задач проектирования систем, чтобы выявить недостатки своего решения и улучшить его.
Продолжение следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
👍21
День 2626. #Карьера #SystemDesign
Как я Освоил Системное Проектирование. Продолжение
Часть 1
Часть 2
Часть 3
6. Применение в работе (реальные системы и ограничения)
Теория бесполезна, пока вы не создадите что-то реальное. На работе я был в команде, разрабатывавшей систему обработки платежей:
- Большой объём транзакций;
- Требуется строгая согласованность данных;
- Нулевая терпимость к потере данных;
- Сложная бизнес-логика.
Что я применил
1) Архитектурное решение - разделить монолит на сервисы:
- платежи;
- уведомления;
- бухгалтерия;
- обнаружение мошенничества.
Почему: Каждый сервис имеет разные потребности в масштабировании.
2) Стратегия коммуникаций:
- Синхронная: REST API для операций, ориентированных на пользователя.
- Асинхронная: Kafka для внутренних событий:
Платеж обработан
→ Уведомить пользователя;
→ Обновить учётную запись;
→ Провести проверку на мошенничество.
3) Согласованность данных:
Проблема: деньги не могут быть дублированы или потеряны.
Решение:
- Ключи идемпотентности (предотвращение дублирования транзакций);
- Паттерн Saga для распределённых транзакций;
- Паттерн Источники Событий для аудита.
4) Надёжность:
- Прерыватели цепи (предотвращение каскадных сбоев)
- Повторные попытки с экспоненциальной задержкой;
- Очереди недоставленных сообщений.
5) Мониторинг:
- Отслеживание задержек (P50, P95, P99);
- Оповещения об уровне ошибок;
- Уровень успешности транзакций;
- Панель мониторинга в реальном времени.
Создание реальных систем научило меня:
1) Идеальных проектов не существует
- Каждый выбор — это компромисс;
- Бизнес-ограничения имеют значение;
- Технический долг неизбежен.
2) Эксплуатация важнее проектирования
- Мониторинг и оповещения критически важны;
- Отладка распределённых систем сложна;
- Необходимо планирование отката.
3) Важна команда
- Самый лучший проект ничего не значит, если команда не может его поддерживать;
- Документация имеет решающее значение;
- Привлечение новых инженеров занимает время.
Этот реальный опыт сделал меня в 10 раз лучше на собеседованиях по проектированию систем. Я перестал давать шаблонные ответы. Я начал обсуждать реальные компромиссы, основанные на реальном опыте.
7. Я обучал других (лучший способ учиться)
Обучение выявляет пробелы в понимании.
Что я начал делать
1) Наставлял младших инженеров:
- Объяснял кэширование, базы данных, масштабирование;
- Разбирал реальные системные проекты;
- Отвечал на их вопросы «почему».
2) Проводил внутренние технические презентации:
- «Как работает наша платежная система»;
- «Введение в очереди сообщений»;
- «Базы данных: когда что использовать».
3) Писал посты в блоге с диаграммами:
- Помогает систематизировать мысли;
- Приходится ясно объяснять;
- Появляется обратная связь от читателей.
4) Проводил пробные собеседования с коллегами:
- Практика в формулировании мыслей;
- Умение справляться с трудностями;
- Разные подходы к решению.
Почему обучение сработало?
Если вы не можете объяснить что-то просто, значит, вы недостаточно хорошо это понимаете.
Каждый раз, когда я обучал кого-то:
- Я прояснял собственное мышление;
- Я обнаруживал пробелы в своих знаниях;
- Я учился на вопросах, на которые не мог ответить.
Преподавание превращает понимание в мастерство.
Окончание следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
Как я Освоил Системное Проектирование. Продолжение
Часть 1
Часть 2
Часть 3
6. Применение в работе (реальные системы и ограничения)
Теория бесполезна, пока вы не создадите что-то реальное. На работе я был в команде, разрабатывавшей систему обработки платежей:
- Большой объём транзакций;
- Требуется строгая согласованность данных;
- Нулевая терпимость к потере данных;
- Сложная бизнес-логика.
Что я применил
1) Архитектурное решение - разделить монолит на сервисы:
- платежи;
- уведомления;
- бухгалтерия;
- обнаружение мошенничества.
Почему: Каждый сервис имеет разные потребности в масштабировании.
2) Стратегия коммуникаций:
- Синхронная: REST API для операций, ориентированных на пользователя.
- Асинхронная: Kafka для внутренних событий:
Платеж обработан
→ Уведомить пользователя;
→ Обновить учётную запись;
→ Провести проверку на мошенничество.
3) Согласованность данных:
Проблема: деньги не могут быть дублированы или потеряны.
Решение:
- Ключи идемпотентности (предотвращение дублирования транзакций);
- Паттерн Saga для распределённых транзакций;
- Паттерн Источники Событий для аудита.
4) Надёжность:
- Прерыватели цепи (предотвращение каскадных сбоев)
- Повторные попытки с экспоненциальной задержкой;
- Очереди недоставленных сообщений.
5) Мониторинг:
- Отслеживание задержек (P50, P95, P99);
- Оповещения об уровне ошибок;
- Уровень успешности транзакций;
- Панель мониторинга в реальном времени.
Создание реальных систем научило меня:
1) Идеальных проектов не существует
- Каждый выбор — это компромисс;
- Бизнес-ограничения имеют значение;
- Технический долг неизбежен.
2) Эксплуатация важнее проектирования
- Мониторинг и оповещения критически важны;
- Отладка распределённых систем сложна;
- Необходимо планирование отката.
3) Важна команда
- Самый лучший проект ничего не значит, если команда не может его поддерживать;
- Документация имеет решающее значение;
- Привлечение новых инженеров занимает время.
Этот реальный опыт сделал меня в 10 раз лучше на собеседованиях по проектированию систем. Я перестал давать шаблонные ответы. Я начал обсуждать реальные компромиссы, основанные на реальном опыте.
7. Я обучал других (лучший способ учиться)
Обучение выявляет пробелы в понимании.
Что я начал делать
1) Наставлял младших инженеров:
- Объяснял кэширование, базы данных, масштабирование;
- Разбирал реальные системные проекты;
- Отвечал на их вопросы «почему».
2) Проводил внутренние технические презентации:
- «Как работает наша платежная система»;
- «Введение в очереди сообщений»;
- «Базы данных: когда что использовать».
3) Писал посты в блоге с диаграммами:
- Помогает систематизировать мысли;
- Приходится ясно объяснять;
- Появляется обратная связь от читателей.
4) Проводил пробные собеседования с коллегами:
- Практика в формулировании мыслей;
- Умение справляться с трудностями;
- Разные подходы к решению.
Почему обучение сработало?
Если вы не можете объяснить что-то просто, значит, вы недостаточно хорошо это понимаете.
Каждый раз, когда я обучал кого-то:
- Я прояснял собственное мышление;
- Я обнаруживал пробелы в своих знаниях;
- Я учился на вопросах, на которые не мог ответить.
Преподавание превращает понимание в мастерство.
Окончание следует…
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
👍8
День 2627. #Карьера #SystemDesign
Как я Освоил Системное Проектирование. Окончание
Часть 1
Часть 2
Часть 3
Часть 4
Ресурсы
Существует множество видео, курсов и книг по теме. Платные курсы рекламировать не буду, решайте сами, стоят ли они того.
Книги:
1) «System Design. Подготовка к сложному интервью» Сюй А.
- Красивые диаграммы;
- Более 15 вариантов системного проектирования.
2) «Высоконагруженные приложения. Программирование, масштабирование, поддержка» Клеппман М.
- Глубокий технический анализ;
- Читать после изучения основ;
- Отличный справочник.
Сдвиг мышления, который изменил всё
Перед изучением системного проектирования.
Синдром самозванца:
- «Я недостаточно опытен»
- «Это слишком сложно»
- «Я никогда не пойму распределённые системы»
Тревога перед собеседованием:
- Надеюсь, я сталкивался с этой проблемой;
- Паника, когда застреваю;
- Заучивание решений.
Карьерный застой:
- Ограничен задачами по программированию;
- Неучастие в принятии архитектурных решений;
- Мимо руководящих должностей.
После освоения системного проектирования
Уверенность:
- Возможность обсуждать архитектуру с кем угодно;
- Понимание компромиссов;
- Мышление в масштабе.
Успех на собеседованиях:
- Возможность ответить на любой вопрос по проектированию;
- Сосредоточенность на размышлении, а не на запоминании.
На собеседованиях по системному проектированию (и в реальной работе):
Плохой ответ: «Мы будем использовать микросервисы и Kafka».
Хороший ответ: «Мы могли бы использовать микросервисы для независимого масштабирования, но, учитывая размер нашей команды (5 инженеров) и текущий масштаб (10 000 пользователей), хорошо структурированный монолит с чёткими границами модулей будет проще в обслуживании. Мы можем выделить сервисы позже, когда достигнем 100 тыс пользователей или нам потребуется независимое развёртывание».
Что изменилось:
- Продемонстрировал понимание компромиссов;
- Учел команду и масштаб;
- Предоставил обоснование;
- Обсудил эволюцию.
Интервьюерам не нужны идеальные проекты. Им нужно увидеть, как вы мыслите.
Итого
Проектирование систем — это навык, а не талант.
Вам не нужны:
- 10 лет опыта;
- Степень в области компьютерных наук;
- Фотографическая память;
- Природный талант.
Нужно только:
- Любопытство изучать, как всё работает;
- Готовность к систематическому обучению;
- Практика проектирования реальных систем;
- Терпение.
Проектирование систем — это не магия. Это навык, которому можно научиться, как приготовление пищи, вождение или игра на гитаре. Начните с основ. Практикуйтесь постоянно. Развивайте свои знания. Помните: каждый архитектор, каждый сеньор, каждый системный проектировщик начинал с того места, где вы сейчас.
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
Как я Освоил Системное Проектирование. Окончание
Часть 1
Часть 2
Часть 3
Часть 4
Ресурсы
Существует множество видео, курсов и книг по теме. Платные курсы рекламировать не буду, решайте сами, стоят ли они того.
Книги:
1) «System Design. Подготовка к сложному интервью» Сюй А.
- Красивые диаграммы;
- Более 15 вариантов системного проектирования.
2) «Высоконагруженные приложения. Программирование, масштабирование, поддержка» Клеппман М.
- Глубокий технический анализ;
- Читать после изучения основ;
- Отличный справочник.
Сдвиг мышления, который изменил всё
Перед изучением системного проектирования.
Синдром самозванца:
- «Я недостаточно опытен»
- «Это слишком сложно»
- «Я никогда не пойму распределённые системы»
Тревога перед собеседованием:
- Надеюсь, я сталкивался с этой проблемой;
- Паника, когда застреваю;
- Заучивание решений.
Карьерный застой:
- Ограничен задачами по программированию;
- Неучастие в принятии архитектурных решений;
- Мимо руководящих должностей.
После освоения системного проектирования
Уверенность:
- Возможность обсуждать архитектуру с кем угодно;
- Понимание компромиссов;
- Мышление в масштабе.
Успех на собеседованиях:
- Возможность ответить на любой вопрос по проектированию;
- Сосредоточенность на размышлении, а не на запоминании.
На собеседованиях по системному проектированию (и в реальной работе):
Плохой ответ: «Мы будем использовать микросервисы и Kafka».
Хороший ответ: «Мы могли бы использовать микросервисы для независимого масштабирования, но, учитывая размер нашей команды (5 инженеров) и текущий масштаб (10 000 пользователей), хорошо структурированный монолит с чёткими границами модулей будет проще в обслуживании. Мы можем выделить сервисы позже, когда достигнем 100 тыс пользователей или нам потребуется независимое развёртывание».
Что изменилось:
- Продемонстрировал понимание компромиссов;
- Учел команду и масштаб;
- Предоставил обоснование;
- Обсудил эволюцию.
Интервьюерам не нужны идеальные проекты. Им нужно увидеть, как вы мыслите.
Итого
Проектирование систем — это навык, а не талант.
Вам не нужны:
- 10 лет опыта;
- Степень в области компьютерных наук;
- Фотографическая память;
- Природный талант.
Нужно только:
- Любопытство изучать, как всё работает;
- Готовность к систематическому обучению;
- Практика проектирования реальных систем;
- Терпение.
Проектирование систем — это не магия. Это навык, которому можно научиться, как приготовление пищи, вождение или игра на гитаре. Начните с основ. Практикуйтесь постоянно. Развивайте свои знания. Помните: каждый архитектор, каждый сеньор, каждый системный проектировщик начинал с того места, где вы сейчас.
Источник: https://medium.com/javarevisited/how-i-learned-system-design-861efe86f173
👍15
День 2628. #SystemDesign101
Что Происходит, Когда вы Вводите google.com в Браузере?
1. Вы вводите адрес веб-сайта в адресную строку браузера.
2. Браузер сначала проверяет свой кэш. Если адрес не найден в кэше, он должен найти IP-адрес.
3. Начинается поиск DNS (представьте, что вы ищете номер телефона). Запрос проходит через различные DNS-серверы (корневой, TLD - сервер имен доменов верхнего уровня - и авторитативный). Наконец, извлекается IP-адрес.
4. Браузер инициирует TCP-соединение, начиная с рукопожатия. Например, в случае HTTP 1.1 клиент и сервер выполняют трёхстороннее TCP-рукопожатие с сообщениями SYN, SYN-ACK и ACK.
5. Браузер отправляет HTTP-запрос на сервер, и сервер отвечает файлами HTML, CSS и JS.
6. Браузер обрабатывает ответ. Он анализирует HTML-документ и создаёт деревья DOM и CSSOM.
7. Браузер выполняет код JavaScript и отображает страницу, проходя через различные этапы (токенизатор, парсер, дерево рендеринга, компоновка и отрисовка).
8. Веб-страница появляется на экране.
Источник: https://bytebytego.com/guides/what-happens-when-you-type-google/
Что Происходит, Когда вы Вводите google.com в Браузере?
1. Вы вводите адрес веб-сайта в адресную строку браузера.
2. Браузер сначала проверяет свой кэш. Если адрес не найден в кэше, он должен найти IP-адрес.
3. Начинается поиск DNS (представьте, что вы ищете номер телефона). Запрос проходит через различные DNS-серверы (корневой, TLD - сервер имен доменов верхнего уровня - и авторитативный). Наконец, извлекается IP-адрес.
4. Браузер инициирует TCP-соединение, начиная с рукопожатия. Например, в случае HTTP 1.1 клиент и сервер выполняют трёхстороннее TCP-рукопожатие с сообщениями SYN, SYN-ACK и ACK.
5. Браузер отправляет HTTP-запрос на сервер, и сервер отвечает файлами HTML, CSS и JS.
6. Браузер обрабатывает ответ. Он анализирует HTML-документ и создаёт деревья DOM и CSSOM.
7. Браузер выполняет код JavaScript и отображает страницу, проходя через различные этапы (токенизатор, парсер, дерево рендеринга, компоновка и отрисовка).
8. Веб-страница появляется на экране.
Источник: https://bytebytego.com/guides/what-happens-when-you-type-google/
👍27
День 2629. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
30. Лидерство и наставничество
«Можете ли вы рассказать о своем подходе к лидерству и наставничеству в команде разработчиков? Как вы обеспечиваете положительное влияние вашего лидерства на результаты проекта и на развитие членов команды?»
Хороший ответ
Мой подход к лидерству и наставничеству в команде разработчиков основан на личном примере, развитии открытой коммуникации и активной поддержке профессионального роста членов команды. Вот как я реализую эти принципы.
- Лидерство личным примером: Я верю в демонстрацию поведения и практик, которые ожидаю от своей команды. Это включает в себя соблюдение лучших практик кодирования, поддержание высокого стандарта качества кода и демонстрацию приверженности целям проекта. Например, я обязательно участвую в проверках кода, вношу свой вклад в задачи кодирования и остаюсь в курсе последних технологий .NET, чтобы эффективно руководить командой.
- Развитие открытой коммуникации: Я поощряю регулярные командные встречи и индивидуальные консультации, чтобы обеспечить постоянную открытость каналов связи. Это помогает решать любые проблемы на ранних этапах, обмениваться идеями и совместно находить решения проблем.
- Профессиональный рост и наставничество: Я привержен профессиональному развитию членов своей команды. Это включает в себя регулярные сессии наставничества, поощрение посещения семинаров и конференций, а также предоставление членам команды возможностей принимать новые вызовы. Начинающих разработчиков я часто объединяю в пары с более опытными коллегами и чередую обязанности в проектах, чтобы расширить их кругозор и навыки.
- Обратная связь и признание: Я стараюсь предоставлять конструктивную обратную связь и отмечать достижения. Позитивное подкрепление и конструктивная критика помогают укрепить уверенность и улучшить навыки, что, в свою очередь, повышает производительность команды и моральный дух.
Внедряя эти стратегии, я стремлюсь создать благоприятную среду, которая не только способствует успеху проекта, но и развитию каждого члена команды.
Часто встречающийся неправильный ответ
«Как лидер, я принимаю все ключевые решения и определяю направление проекта. Я ожидаю, что моя команда будет следовать моему руководству и сосредоточится на своих задачах, чтобы проект был завершен вовремя».
Почему это неправильно
- Авторитарный подход: Этот ответ указывает на нисходящий, командно-административный подход к лидерству, который может подавлять творчество и снижать вовлеченность команды. Современное лидерство в разработке программного обеспечения часто требует инклюзивности и сотрудничества.
- Отсутствие делегирования: Не вовлекая команду в процесс принятия решений, лидер упускает ценные идеи и лишает членов команды возможности расти, преодолевая трудности и принимая решения.
- Пренебрежение наставничеством: Ответ не затрагивает ни один аспект наставничества или личностного развития членов команды, которые имеют решающее значение для поддержания мотивированной и квалифицированной команды.
Эта ошибка обычно проистекает из традиционного взгляда на лидерство, который может не соответствовать коллаборативной и динамичной природе современных команд разработчиков программного обеспечения, особенно в средах, поощряющих инновации и непрерывное обучение.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
30. Лидерство и наставничество
«Можете ли вы рассказать о своем подходе к лидерству и наставничеству в команде разработчиков? Как вы обеспечиваете положительное влияние вашего лидерства на результаты проекта и на развитие членов команды?»
Хороший ответ
Мой подход к лидерству и наставничеству в команде разработчиков основан на личном примере, развитии открытой коммуникации и активной поддержке профессионального роста членов команды. Вот как я реализую эти принципы.
- Лидерство личным примером: Я верю в демонстрацию поведения и практик, которые ожидаю от своей команды. Это включает в себя соблюдение лучших практик кодирования, поддержание высокого стандарта качества кода и демонстрацию приверженности целям проекта. Например, я обязательно участвую в проверках кода, вношу свой вклад в задачи кодирования и остаюсь в курсе последних технологий .NET, чтобы эффективно руководить командой.
- Развитие открытой коммуникации: Я поощряю регулярные командные встречи и индивидуальные консультации, чтобы обеспечить постоянную открытость каналов связи. Это помогает решать любые проблемы на ранних этапах, обмениваться идеями и совместно находить решения проблем.
- Профессиональный рост и наставничество: Я привержен профессиональному развитию членов своей команды. Это включает в себя регулярные сессии наставничества, поощрение посещения семинаров и конференций, а также предоставление членам команды возможностей принимать новые вызовы. Начинающих разработчиков я часто объединяю в пары с более опытными коллегами и чередую обязанности в проектах, чтобы расширить их кругозор и навыки.
- Обратная связь и признание: Я стараюсь предоставлять конструктивную обратную связь и отмечать достижения. Позитивное подкрепление и конструктивная критика помогают укрепить уверенность и улучшить навыки, что, в свою очередь, повышает производительность команды и моральный дух.
Внедряя эти стратегии, я стремлюсь создать благоприятную среду, которая не только способствует успеху проекта, но и развитию каждого члена команды.
Часто встречающийся неправильный ответ
«Как лидер, я принимаю все ключевые решения и определяю направление проекта. Я ожидаю, что моя команда будет следовать моему руководству и сосредоточится на своих задачах, чтобы проект был завершен вовремя».
Почему это неправильно
- Авторитарный подход: Этот ответ указывает на нисходящий, командно-административный подход к лидерству, который может подавлять творчество и снижать вовлеченность команды. Современное лидерство в разработке программного обеспечения часто требует инклюзивности и сотрудничества.
- Отсутствие делегирования: Не вовлекая команду в процесс принятия решений, лидер упускает ценные идеи и лишает членов команды возможности расти, преодолевая трудности и принимая решения.
- Пренебрежение наставничеством: Ответ не затрагивает ни один аспект наставничества или личностного развития членов команды, которые имеют решающее значение для поддержания мотивированной и квалифицированной команды.
Эта ошибка обычно проистекает из традиционного взгляда на лидерство, который может не соответствовать коллаборативной и динамичной природе современных команд разработчиков программного обеспечения, особенно в средах, поощряющих инновации и непрерывное обучение.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👎4👍2
День 2630. #ЗаметкиНаПолях
Проверяем Конфигурацию при Запуске. Начало
.NET-приложения со строго типизированной конфигурацией IOptions<T> и его вариантами предоставляют удобный способ привязки разделов appsettings.json к классам C#. Но привязка — это не то же самое, что проверка: отсутствие обязательного значения или число, выходящее за пределы допустимого диапазона, без проблем привяжутся и незаметно сломают приложение во время выполнения. IValidateOptions<T> — механизм, предоставляемый .NET для решения этой проблемы.
Рассмотрим типичный класс параметров:
Если в файле appsettings.json отсутствует Host, приложение запустится нормально. Ошибка проявится только при отправке email. Аннотации данных (
1. Они используют рефлексию, что приводит к:
- Затратам на производительность, что важно в сценариях с высокой нагрузкой и требованиям к быстрому запуску.
- Несовместимости с AOT и агрессивным триммингом (
Это можно исправить, используя генератор кода в .NET8+. Для активации генератора для конкретного класса валидатора параметров потребуется:
- Класс параметров, помеченный атрибутами Data Annotation.
- Частичный класс, реализующий IValidateOptions<T> и помеченный
Генератор заполнит тело класса при сборке.
2. Но иногда аннотация данных вовсе недостаточно, когда необходимы:
- Проверка нескольких свойств объекта конфигурации;
- Асинхронные или основанные на данных из БД проверки;
- Условная логика в зависимости от среды;
- Многократно используемые валидаторы, общие для нескольких типов конфигурации.
Здесь пригодится реализовать IValidateOptions<T>. Это интерфейс в Microsoft.Extensions.Options с единственным методом:
Вы реализуете этот интерфейс, регистрируете его в DI-контейнере, и инфраструктура Options вызывает его автоматически:
- лениво (при первом обращении),
- немедленно при запуске, если используется ValidateOnStart().
Вот простой валидатор для класса, описанного выше:
Регистрируем в Program.cs:
Если проверка не проходит, во время выполнения
Окончание следует…
Источник: https://bartwullems.blogspot.com/2026/03/validating-configuration-at-startup.html
Проверяем Конфигурацию при Запуске. Начало
.NET-приложения со строго типизированной конфигурацией IOptions<T> и его вариантами предоставляют удобный способ привязки разделов appsettings.json к классам C#. Но привязка — это не то же самое, что проверка: отсутствие обязательного значения или число, выходящее за пределы допустимого диапазона, без проблем привяжутся и незаметно сломают приложение во время выполнения. IValidateOptions<T> — механизм, предоставляемый .NET для решения этой проблемы.
Рассмотрим типичный класс параметров:
public class SmtpOptions
{
public string Host { get; set; } = "";
public int Port { get; set; }
public string FromAddress { get; set; } = "";
}
Если в файле appsettings.json отсутствует Host, приложение запустится нормально. Ошибка проявится только при отправке email. Аннотации данных (
[Required], [Range] и т.п.) в сочетании с вызовом ValidateDataAnnotations() помогают, но с ними есть 2 проблемы.1. Они используют рефлексию, что приводит к:
- Затратам на производительность, что важно в сценариях с высокой нагрузкой и требованиям к быстрому запуску.
- Несовместимости с AOT и агрессивным триммингом (
<PublishTrimmed>true</PublishTrimmed>). Могут быть исключены метаданные, от которых зависит рефлексия, что приводит к предупреждениям IL2026/IL3050 или к сбоям во время выполнения.Это можно исправить, используя генератор кода в .NET8+. Для активации генератора для конкретного класса валидатора параметров потребуется:
- Класс параметров, помеченный атрибутами Data Annotation.
- Частичный класс, реализующий IValidateOptions<T> и помеченный
[OptionsValidator], с пустым телом:using Microsoft.Extensions.Options;
[OptionsValidator]
public partial class ValidateSmtpOptions
: IValidateOptions<SmtpOptions>
{
}
Генератор заполнит тело класса при сборке.
2. Но иногда аннотация данных вовсе недостаточно, когда необходимы:
- Проверка нескольких свойств объекта конфигурации;
- Асинхронные или основанные на данных из БД проверки;
- Условная логика в зависимости от среды;
- Многократно используемые валидаторы, общие для нескольких типов конфигурации.
Здесь пригодится реализовать IValidateOptions<T>. Это интерфейс в Microsoft.Extensions.Options с единственным методом:
public interface IValidateOptions<TOptions>
where TOptions : class
{
ValidateOptionsResult Validate(
string? name, TOptions options);
}
Вы реализуете этот интерфейс, регистрируете его в DI-контейнере, и инфраструктура Options вызывает его автоматически:
- лениво (при первом обращении),
- немедленно при запуске, если используется ValidateOnStart().
Вот простой валидатор для класса, описанного выше:
public class SmtpOptionsValidator
: IValidateOptions<SmtpOptions>
{
public ValidateOptionsResult Validate(
string? name, SmtpOptions opts)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(opts.Host))
errors.Add("Требуется Host");
if (opts.Port is < 1 or > 65535)
errors.Add($"Port должен быть от 1 до 65535");
if (string.IsNullOrWhiteSpace(opts.FromAddress))
errors.Add("Требуется FromAddress");
return errors.Count > 0
? ValidateOptionsResult.Fail(errors)
: ValidateOptionsResult.Success;
}
}
Регистрируем в Program.cs:
builder.Services
.Configure<SmtpOptions>(
builder.Configuration.GetSection("Smtp"))
.AddSingleton<IValidateOptions<SmtpOptions>, SmtpOptionsValidator>()
.AddOptions<SmtpOptions>()
.ValidateOnStart();
Если проверка не проходит, во время выполнения
app.Run() генерируется исключение OptionsValidationException, поэтому сервис никогда не запустится с некорректной конфигурацией. Этот вариант «быстрого сбоя» обычно предпочтительнее, чем исключение NullReferenceException во время выполнения, возникающее где-то в глубинах бизнес-логики.Окончание следует…
Источник: https://bartwullems.blogspot.com/2026/03/validating-configuration-at-startup.html
👍24
День 2631. #ЗаметкиНаПолях
Проверяем Конфигурацию при Запуске. Окончание
Начало
Доступ к другим сервисам внутри валидатора
Поскольку валидатор является обычным классом, зарегистрированным в DI, вы можете внедрять зависимости. Это одно из ключевых преимуществ по сравнению с аннотациями данных. Кроме того, аннотации данных не могут выражать зависимости между свойствами. В валидаторе вы можете добавить любую логику.
Именованные конфигурации
IValidateOptions<T> поддерживает именованные конфигурации через параметр name. Это важно при регистрации нескольких экземпляров одного типа конфигурации — например, двух разных клиентов API:
Регистрация именованных настроек:
Использование в сочетании с OptionsBuilder<T>
API OptionsBuilder<T> (возвращаемый функцией AddOptions<T>()) имеет перегрузку метода .Validate(), которая принимает делегат. Это подходит для простых случаев. Для чего-либо более сложного предпочтительнее использовать реализацию IValidateOptions<T> — она позволяет тестировать логику проверки и не размещать её в Program.cs:
Вы можете объединить оба варианта в одном типе параметров — фреймворк запускает все зарегистрированные валидаторы и агрегирует ошибки.
Источник: https://bartwullems.blogspot.com/2026/03/validating-configuration-at-startup.html
Проверяем Конфигурацию при Запуске. Окончание
Начало
Доступ к другим сервисам внутри валидатора
Поскольку валидатор является обычным классом, зарегистрированным в DI, вы можете внедрять зависимости. Это одно из ключевых преимуществ по сравнению с аннотациями данных. Кроме того, аннотации данных не могут выражать зависимости между свойствами. В валидаторе вы можете добавить любую логику.
public class DatabaseOptionsValidator
: IValidateOptions<DatabaseOptions>
{
private readonly IHostEnvironment _env;
public DatabaseOptionsValidator(IHostEnvironment env)
=> _env = env;
public ValidateOptionsResult Validate(
string? name, DatabaseOptions opts)
{
var errors = new List<string>();
// Более строгие правила вне среды разработки
if (!_env.IsDevelopment())
{
…
}
…
}
}
Именованные конфигурации
IValidateOptions<T> поддерживает именованные конфигурации через параметр name. Это важно при регистрации нескольких экземпляров одного типа конфигурации — например, двух разных клиентов API:
public class ApiClientOptionsValidator
: IValidateOptions<ApiClientOptions>
{
public ValidateOptionsResult Validate(
string? name, ApiClientOptions opts)
{
…
// … Валидация общих свойств …
// Более строгие правила для API Payments
if (name == "Payments"
&& opts.Timeout > 30)
errors.Add($"Таймаут клиента [{name}] не должен превышать 30 сек.");
…
}
}
Регистрация именованных настроек:
builder.Services
.AddSingleton<IValidateOptions<ApiClientOptions>, ApiClientOptionsValidator>();
builder.Services
.AddOptions<ApiClientOptions>("Payments")
.BindConfiguration("ApiClients:Payments")
.ValidateOnStart();
builder.Services
.AddOptions<ApiClientOptions>("Shipping")
.BindConfiguration("ApiClients:Shipping")
.ValidateOnStart();
Использование в сочетании с OptionsBuilder<T>
API OptionsBuilder<T> (возвращаемый функцией AddOptions<T>()) имеет перегрузку метода .Validate(), которая принимает делегат. Это подходит для простых случаев. Для чего-либо более сложного предпочтительнее использовать реализацию IValidateOptions<T> — она позволяет тестировать логику проверки и не размещать её в Program.cs:
// Делегат — для простых проверок
builder.Services
.AddOptions<FeatureFlagOptions>()
.BindConfiguration("FeatureFlags")
.Validate(opts => opts.Percentage is >= 0 and <= 100,
"Percentage должен быть от 0 до 100")
.ValidateOnStart();
// Класс – для сложных проверок
builder.Services
.AddSingleton<IValidateOptions<SmtpOptions>, SmtpOptionsValidator>()
.AddOptions<SmtpOptions>()
.BindConfiguration("Smtp")
.ValidateOnStart();
Вы можете объединить оба варианта в одном типе параметров — фреймворк запускает все зарегистрированные валидаторы и агрегирует ошибки.
Источник: https://bartwullems.blogspot.com/2026/03/validating-configuration-at-startup.html
👍9
День 2632. #МоиИнструменты #PG
Инструменты Оптимизации Запросов в PostgreSQL. Часть 6
6. SQLFluff (SQL-линтер для производительности)
Что даёт: выявляет антипаттерны производительности до того, как запросы попадут в прод.
Зачем нужен: Большинство проблем с производительностью SQL возникают из-за распространённых ошибок: SELECT *, ненужные DISTINCT, отсутствие WHERE, неэффективные соединения. SQLFluff выявляет их на этапе разработки, до того, как они вызовут проблемы в продакшене.
Установка:
Использование
1. Линтинг SQL-файлов:
Пример вывода:
2. Автоматические исправления:
До SQLFluff:
Проблемы:
1. SELECT * (возвращает ненужные поля);
2. Неявное объединение (неясное намерение);
3. Сравнение даты без явного приведения типа.
После SQLFluff:
Когда использовать
- dbt-проекты (отлично интегрируется);
- Несколько инженеров, пишущих SQL-запросы (обеспечение согласованности);
- Предотвращение распространённых ошибок;
- Конвейер CI/CD для SQL.
Когда отказаться
- Разработчик-одиночка (меньшая ценность);
- ad-hoc запросы (избыточно);
- Нестандартный диалект SQL (ограниченная поддержка).
Скрытая функция
Пользовательские правила для антипаттернов в вашей команде:
Добавить в .sqlfluff.
С осторожностью
Слишком агрессивный линтинг убивает продуктивность:
Постепенно добавляйте правила со временем. Соблюдайте баланс между отловом проблем и сопротивлением разработчиков.
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
Инструменты Оптимизации Запросов в PostgreSQL. Часть 6
6. SQLFluff (SQL-линтер для производительности)
Что даёт: выявляет антипаттерны производительности до того, как запросы попадут в прод.
Зачем нужен: Большинство проблем с производительностью SQL возникают из-за распространённых ошибок: SELECT *, ненужные DISTINCT, отсутствие WHERE, неэффективные соединения. SQLFluff выявляет их на этапе разработки, до того, как они вызовут проблемы в продакшене.
Установка:
pip install sqlfluff
# Создаём конфиг
cat > .sqlfluff <<EOF
[sqlfluff]
dialect = postgres
templater = dbt
[sqlfluff:rules:L042]
# Запрет SELECT * в проде
select_
_targets = qualified
[sqlfluff:rules:L045]
# Обязательные алиасы полей
aliasing = explicit
[sqlfluff:rules:L052]
# Требование явных объединений
join_types = explicit
EOF
Использование
1. Линтинг SQL-файлов:
sqlfluff lint models/*.sql
Пример вывода:
== [models/orders.sql] FAIL
L: 5 | P: 8 | L042 | SELECT * is not allowed in production.
L: 12 | P: 15 | L031 | Avoid DISTINCT where possible (use GROUP BY).
L: 18 | P: 1 | L044 | Query is missing WHERE clause (full table scan).
L: 23 | P: 22 | L052 | JOIN should specify type (INNER, LEFT, etc.).
2. Автоматические исправления:
sqlfluff fix models/*.sql
До SQLFluff:
SELECT * FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE order_date > '2024-01-01';
Проблемы:
1. SELECT * (возвращает ненужные поля);
2. Неявное объединение (неясное намерение);
3. Сравнение даты без явного приведения типа.
После SQLFluff:
SELECT
o.order_id,
o.order_date,
o.total,
c.customer_name
FROM orders AS o
INNER JOIN customers AS c
ON o.customer_id = c.id
WHERE o.order_date > CAST('2024-01-01' AS DATE);
Когда использовать
- dbt-проекты (отлично интегрируется);
- Несколько инженеров, пишущих SQL-запросы (обеспечение согласованности);
- Предотвращение распространённых ошибок;
- Конвейер CI/CD для SQL.
Когда отказаться
- Разработчик-одиночка (меньшая ценность);
- ad-hoc запросы (избыточно);
- Нестандартный диалект SQL (ограниченная поддержка).
Скрытая функция
Пользовательские правила для антипаттернов в вашей команде:
# custom_rules/no_cross_joins.py
from sqlfluff.core.rules import BaseRule, LintResult
class Rule_Custom_NoCrossJoin(BaseRule):
"""Запрет CROSS JOIN (почти всегда необязательны)."""
def _eval(self, segment, **kwargs):
if segment.is_type("join_clause"):
if "CROSS" in segment.raw_upper:
return LintResult(
anchor=segment,
description="Найден CROSS JOIN. Почти всегда необязателен.",
fixes=[...] # Опционально: предложение исправления
)
Добавить в .sqlfluff.
С осторожностью
Слишком агрессивный линтинг убивает продуктивность:
# Слишком строго (инженеры возненавидят)
sqlfluff lint --rules all
# Лучше начать с критических правил
sqlfluff lint --rules L042,L044,L052
Постепенно добавляйте правила со временем. Соблюдайте баланс между отловом проблем и сопротивлением разработчиков.
Источник: https://medium.com/@reliabledataengineering/15-sql-optimization-tools-that-make-queries-10x-faster-8629ac451d97
👍3
День 2633. #TipsAndTricks
Вызываем Файлы из Репозитория Действий в GitHub Actions
GitHub Actions позволяет создавать многократно используемые действия. Один из самых простых способов сделать это — использовать составные действия (Composite Actions), которые позволяют объединять несколько шагов в одно действие. Это уменьшает дублирование кода в ваших рабочих процессах.
При создании составного действия вам может потребоваться сослаться на файлы, хранящиеся в репозитории действий, например, на скрипт PowerShell или Bash.
По умолчанию, когда выполняется действие, рабочий каталог — это корень репозитория, использующего действие. Это означает, что относительные пути разрешаются в репозиторий вызывающего объекта, а не в репозиторий действия.
Для доступа к файлам из репозитория действий используйте контекстную переменную github.action_path, которая содержит путь к каталогу, где находится ваше действие.
Вот пример того, как использовать её в файле
В этом примере файл
Дополнительные ресурсы:
- Контексты GitHub - github.action_path
- Создание составного действия
Источник: https://www.meziantou.net/accessing-files-from-the-action-repository-in-a-github-composite-action.htm
Вызываем Файлы из Репозитория Действий в GitHub Actions
GitHub Actions позволяет создавать многократно используемые действия. Один из самых простых способов сделать это — использовать составные действия (Composite Actions), которые позволяют объединять несколько шагов в одно действие. Это уменьшает дублирование кода в ваших рабочих процессах.
При создании составного действия вам может потребоваться сослаться на файлы, хранящиеся в репозитории действий, например, на скрипт PowerShell или Bash.
По умолчанию, когда выполняется действие, рабочий каталог — это корень репозитория, использующего действие. Это означает, что относительные пути разрешаются в репозиторий вызывающего объекта, а не в репозиторий действия.
Для доступа к файлам из репозитория действий используйте контекстную переменную github.action_path, которая содержит путь к каталогу, где находится ваше действие.
Вот пример того, как использовать её в файле
action.yml:name: 'My Composite Action'
description: 'An example'
runs:
using: "composite"
steps:
- name: Run script
run: ${{ github.action_path }}/script.sh
shell: bash
В этом примере файл
script.sh находится в корневом каталоге репозитория действий. Использование ${{ github.action_path }}/script.sh гарантирует, что исполнитель выполнит скрипт из правильного места.Дополнительные ресурсы:
- Контексты GitHub - github.action_path
- Создание составного действия
Источник: https://www.meziantou.net/accessing-files-from-the-action-repository-in-a-github-composite-action.htm
👍1
День 2634. #TipsAndTricks #Git
Команды Git, Которые Я Запускаю Перед Чтением Кода
Автор оригинала: Ally Piechowski
Я занимаюсь аудитом кодовых баз моих клиентов. Первое, что я обычно делаю, когда берусь за новую кодовую базу, открываю терминал и запускаю несколько команд Git. Я хочу понять, кто основные авторы, где сосредоточены проблемы, уверенно ли команда выпускает продукт или ходит по минному полю.
1. Что меняется чаще всего
20 самых часто изменяемых файлов за последний год. Файл, находящийся вверху списка, почти всегда тот, о котором говорят: «К нему все боятся прикасаться».
Высокая активность в файле - иногда это просто активная разработка. Но если авторов много — это явный признак проблемы. Это файл, где каждое изменение — это исправление исправления. Я беру 5 файлов из этого списка и сопоставляю их с командой поиска ошибок (см. п. 3). Файл с высокой активностью и большим количеством ошибок — это основной источник риска.
2. Кто авторы
Авторы по количеству коммитов. Если на одного человека приходится 60%+, это ваш «автобусный фактор». Если он ушёл полгода назад, это кризис. Если ведущий автор из списка не появляется в течение 6 месяцев (
Я также смотрю на хвост. 30 авторов, но только 3 были активны в течение последнего года. Т.е. люди, которые создали эту систему, не те, кто её поддерживает.
Замечание: рабочие процессы объединения коммитов сжимают информацию об авторстве. Если команда объединяет каждый пул-реквест в один коммит, этот результат отражает, кто объединил, а не кто написал. Стоит уточнить стратегию объединения, прежде чем делать выводы.
3. Места ошибок
Та же структура, что и у 1й команды, но отфильтрована по коммитам с ключевыми словами, связанными с ошибками. Файлы, которые появляются в обоих списках, — это код с самым высоким риском: они постоянно ломаются и постоянно исправляются, но никогда не исправляются должным образом.
Это зависит от дисциплины в сообщениях коммитов. Если команда пишет случайные сообщения коммитов, вы ничего не получите. Но даже приблизительная карта плотности ошибок лучше, чем её отсутствие.
4. Проект ускоряется или умирает?
Количество коммитов по месяцам. Стабильный ритм — это хорошо. Но что, если количество коммитов падает в 2 раза за месяц? Обычно - кто-то ушёл. Снижение в течение 6-12 месяцев говорит о том, что команда теряет темп. Периодические всплески, за которыми следуют спокойные месяцы, означают, что команда работает над релизами партиями, а не выпускает их непрерывно.
5. Как часто «тушат пожары»?
Частота откатов и хотфиксов. Несколько откатов за год нормально. Каждые пару недель - команда не доверяет своему процессу развёртывания. Это свидетельство более глубокой проблемы: ненадёжные тесты, отсутствие приёмочных тестов или конвейер развертывания, который усложняет откаты. Отсутствие результатов – сигнал, что либо команда стабильна, либо никто не пишет подробные сообщения о коммитах.
Итого
Выполнение этих команд займет пару минут. Они не покажут вам всего. Но вы будете знать, какой код читать в первую очередь и что искать, когда дойдёте до него. В этом разница между методичным изучением кодовой базы с первого дня и бесцельным блужданием по коду.
Источник: https://piechowski.io/post/git-commands-before-reading-code/
Команды Git, Которые Я Запускаю Перед Чтением Кода
Автор оригинала: Ally Piechowski
Я занимаюсь аудитом кодовых баз моих клиентов. Первое, что я обычно делаю, когда берусь за новую кодовую базу, открываю терминал и запускаю несколько команд Git. Я хочу понять, кто основные авторы, где сосредоточены проблемы, уверенно ли команда выпускает продукт или ходит по минному полю.
1. Что меняется чаще всего
git log --format=format: --name-only --since="1 year ago" | sort | uniq -c | sort -nr | head -20
20 самых часто изменяемых файлов за последний год. Файл, находящийся вверху списка, почти всегда тот, о котором говорят: «К нему все боятся прикасаться».
Высокая активность в файле - иногда это просто активная разработка. Но если авторов много — это явный признак проблемы. Это файл, где каждое изменение — это исправление исправления. Я беру 5 файлов из этого списка и сопоставляю их с командой поиска ошибок (см. п. 3). Файл с высокой активностью и большим количеством ошибок — это основной источник риска.
2. Кто авторы
git shortlog -sn --no-merges
Авторы по количеству коммитов. Если на одного человека приходится 60%+, это ваш «автобусный фактор». Если он ушёл полгода назад, это кризис. Если ведущий автор из списка не появляется в течение 6 месяцев (
git shortlog -sn --no-merges --since="6 months ago"), я немедленно сообщаю об этом клиенту.Я также смотрю на хвост. 30 авторов, но только 3 были активны в течение последнего года. Т.е. люди, которые создали эту систему, не те, кто её поддерживает.
Замечание: рабочие процессы объединения коммитов сжимают информацию об авторстве. Если команда объединяет каждый пул-реквест в один коммит, этот результат отражает, кто объединил, а не кто написал. Стоит уточнить стратегию объединения, прежде чем делать выводы.
3. Места ошибок
git log -i -E --grep="fix|bug|broken" --name-only --format='' | sort | uniq -c | sort -nr | head -20
Та же структура, что и у 1й команды, но отфильтрована по коммитам с ключевыми словами, связанными с ошибками. Файлы, которые появляются в обоих списках, — это код с самым высоким риском: они постоянно ломаются и постоянно исправляются, но никогда не исправляются должным образом.
Это зависит от дисциплины в сообщениях коммитов. Если команда пишет случайные сообщения коммитов, вы ничего не получите. Но даже приблизительная карта плотности ошибок лучше, чем её отсутствие.
4. Проект ускоряется или умирает?
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c
Количество коммитов по месяцам. Стабильный ритм — это хорошо. Но что, если количество коммитов падает в 2 раза за месяц? Обычно - кто-то ушёл. Снижение в течение 6-12 месяцев говорит о том, что команда теряет темп. Периодические всплески, за которыми следуют спокойные месяцы, означают, что команда работает над релизами партиями, а не выпускает их непрерывно.
5. Как часто «тушат пожары»?
git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback'
Частота откатов и хотфиксов. Несколько откатов за год нормально. Каждые пару недель - команда не доверяет своему процессу развёртывания. Это свидетельство более глубокой проблемы: ненадёжные тесты, отсутствие приёмочных тестов или конвейер развертывания, который усложняет откаты. Отсутствие результатов – сигнал, что либо команда стабильна, либо никто не пишет подробные сообщения о коммитах.
Итого
Выполнение этих команд займет пару минут. Они не покажут вам всего. Но вы будете знать, какой код читать в первую очередь и что искать, когда дойдёте до него. В этом разница между методичным изучением кодовой базы с первого дня и бесцельным блужданием по коду.
Источник: https://piechowski.io/post/git-commands-before-reading-code/
👍30