День 2172. #ЗаметкиНаПолях
Функции Пригодности в Архитектуре ПО
Нефункциональные требования важны, но мы часто забываем их проверять. Вы можете измерить их, настроив функции пригодности. Достаточно ли быстра ваша система? Проходит ли она все проверки безопасности? А как насчёт тестируемости, ремонтопригодности и других качеств?
Функции пригодности — это компоненты архитектуры, которые не выполняют функциональные операции, но, используя набор тестов и измерений, позволяют вам проверить, что система соблюдает все предварительно определённые нефункциональные требования.
Если у нас нет четкого понимания нефункциональных требований, то их невозможно измерить. И как только мы определили способ их измерения, как мы можем гарантировать, что мы оправдываем ожидания? Вот где пригодятся функции пригодности.
Будучи связанными с конкретными и измеримыми метриками, функции пригодности предоставляют способ оценки качества и производительности архитектуры, снижая зависимость от субъективных мнений с помощью объективных измерений. Метрика может быть простым числом (например, «максимальное количество запросов в секунду»), процентным значением (например, «процент кода, покрытого тестами») или другими измеримыми значениями.
Знание того, как система ведёт себя в отношении этих показателей, позволяет архитекторам работать над постоянным совершенствованием системы: команды могут определять области для улучшения и принимать решения, основанные не на личном мнении, а на фактических данных, для улучшения системы.
Наличие централизованного места для просмотра исторических значений показателя помогает понять, достигли ли вы прогресса или со временем качество ухудшилось. А чёткое понимание текущего статуса таких показателей может помочь в выявлении потенциальных проблем на ранних этапах процесса разработки, позволяя командам решать их до того, как они станут критическими проблемами.
Например, используя функции пригодности, вы можете гарантировать, что система сможет обрабатывать определённое количество пользователей в секунду: имея надлежащие измерения, вы можете определить, какие функции менее производительны и, в случае высокого трафика, могут привести к падению всей системы.
Скорее всего, вы уже используете функции пригодности, не зная об этом (или хотя бы слышали о них).
Такие инструменты, как SonarQube и NDepend, используют функции пригодности для оценки качества кода на основе метрик, вроде сложности кода, дублирования и соответствия стандартам кодирования. Метрики рассчитываются на основе статического анализа кода, и команды могут определять пороговые значения, при которых система может подвергаться риску потери возможности обслуживания. Примером метрики, связанной с качеством кода, является процент покрытия тестами.
Инструменты, типа JMeter или K6, помогают измерять производительность системы в различных условиях. Наличие истории результатов нагрузочного тестирования может помочь гарантировать, что при добавлении новых функций в систему производительность некоторых конкретных модулей не снизится.
В целом, большинство функций пригодности можно настроить как часть конвейера CI/CD. Например, можно настроить конвейер CD так, чтобы он блокировал развёртывание кода, если результаты нагрузочного тестирования нового кода хуже, чем в предыдущей версии. Или блокировал пул-реквест, если процент покрытия кода снижается.
Вы можете создать свои собственные функции пригодности на основе всего, что вы можете (и должны) измерить: от времени средней загрузки страницы до оценки удовлетворенности клиентов. В сочетании с понятной панелью управления вы можете иметь чёткое представление истории таких показателей.
Источник: https://www.code4it.dev/architecture-notes/fitness-functions/
Функции Пригодности в Архитектуре ПО
Нефункциональные требования важны, но мы часто забываем их проверять. Вы можете измерить их, настроив функции пригодности. Достаточно ли быстра ваша система? Проходит ли она все проверки безопасности? А как насчёт тестируемости, ремонтопригодности и других качеств?
Функции пригодности — это компоненты архитектуры, которые не выполняют функциональные операции, но, используя набор тестов и измерений, позволяют вам проверить, что система соблюдает все предварительно определённые нефункциональные требования.
Если у нас нет четкого понимания нефункциональных требований, то их невозможно измерить. И как только мы определили способ их измерения, как мы можем гарантировать, что мы оправдываем ожидания? Вот где пригодятся функции пригодности.
Будучи связанными с конкретными и измеримыми метриками, функции пригодности предоставляют способ оценки качества и производительности архитектуры, снижая зависимость от субъективных мнений с помощью объективных измерений. Метрика может быть простым числом (например, «максимальное количество запросов в секунду»), процентным значением (например, «процент кода, покрытого тестами») или другими измеримыми значениями.
Знание того, как система ведёт себя в отношении этих показателей, позволяет архитекторам работать над постоянным совершенствованием системы: команды могут определять области для улучшения и принимать решения, основанные не на личном мнении, а на фактических данных, для улучшения системы.
Наличие централизованного места для просмотра исторических значений показателя помогает понять, достигли ли вы прогресса или со временем качество ухудшилось. А чёткое понимание текущего статуса таких показателей может помочь в выявлении потенциальных проблем на ранних этапах процесса разработки, позволяя командам решать их до того, как они станут критическими проблемами.
Например, используя функции пригодности, вы можете гарантировать, что система сможет обрабатывать определённое количество пользователей в секунду: имея надлежащие измерения, вы можете определить, какие функции менее производительны и, в случае высокого трафика, могут привести к падению всей системы.
Скорее всего, вы уже используете функции пригодности, не зная об этом (или хотя бы слышали о них).
Такие инструменты, как SonarQube и NDepend, используют функции пригодности для оценки качества кода на основе метрик, вроде сложности кода, дублирования и соответствия стандартам кодирования. Метрики рассчитываются на основе статического анализа кода, и команды могут определять пороговые значения, при которых система может подвергаться риску потери возможности обслуживания. Примером метрики, связанной с качеством кода, является процент покрытия тестами.
Инструменты, типа JMeter или K6, помогают измерять производительность системы в различных условиях. Наличие истории результатов нагрузочного тестирования может помочь гарантировать, что при добавлении новых функций в систему производительность некоторых конкретных модулей не снизится.
В целом, большинство функций пригодности можно настроить как часть конвейера CI/CD. Например, можно настроить конвейер CD так, чтобы он блокировал развёртывание кода, если результаты нагрузочного тестирования нового кода хуже, чем в предыдущей версии. Или блокировал пул-реквест, если процент покрытия кода снижается.
Вы можете создать свои собственные функции пригодности на основе всего, что вы можете (и должны) измерить: от времени средней загрузки страницы до оценки удовлетворенности клиентов. В сочетании с понятной панелью управления вы можете иметь чёткое представление истории таких показателей.
Источник: https://www.code4it.dev/architecture-notes/fitness-functions/
👍5
День 2173. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 38. Люди много говорят о своих правах, но права подразумевают ответственность
В жизни мы имеем не только права, но и обязанности. Вы имеете право владеть автомобилем, но также должны его зарегистрировать и застраховать. Наряду с правом на покупку недвижимости возникает обязанность платить налог за неё. Сочетание прав и обязанностей определяет отношения людей с обществом.
Люди, работающие над программными проектами, тоже имеют права и обязанности. Наши права в этом случае можно представить как наши ожидания по отношению к другим, а обязанности — как ответственность перед ними. Каждый имеет такие права/обязанности перед своими коллегами, клиентами, руководителями, поставщиками и широкой общественностью.
Помимо конкретных обязательств, которые мы берём на себя перед другими, все специалисты по ПО несут ответственность за соблюдение профессиональной этики: действовать в интересах общества, сохранять конфиденциальность, уважать право интеллектуальной собственности, стремиться к высокому качеству и т.д.
Между правами и обязанностями специалистов по ПО существует определённая симметрия. Если члены команды А имеют право рассчитывать на некие услуги или действия членов команды Б, то верно и обратное.
Вот несколько примеров прав и обязанностей команд, участвующих в разработке ПО. Если вас не устраивает формализм записи прав и обязанностей, то можно сформулировать их в виде: «Для меня резонно ожидать от вас Х, а для вас резонно ожидать от меня Y».
Клиенты
- Право ожидать, что бизнес-аналитик будет использовать информацию о вашем бизнесе исключительно для вашего блага. Вы обязаны дать бизнес-аналитикам и разработчикам всю интересующую их информацию о своем бизнесе.
- Право получить систему, отвечающую потребностям и ожиданиям в отношении качества. Вы обязаны выделить время, необходимое для предоставления и уточнения требований.
- Право изменить свои требования. Вы обязаны оперативно сообщить об изменениях требований команде разработчиков.
Разработчики
- Право на признание и уважение вашей интеллектуальной собственности другими. Вы обязаны уважать право интеллектуальной собственности других лиц, повторно используя плоды их труда только с их разрешения.
- Право знать приоритет каждого требования. Вы обязаны информировать заказчика о влиянии на график новых требований и изменений в приоритетах требований.
- Право оценивать и переоценивать свою работу. Вы обязаны делать свои оценки как можно более точными и как можно быстрее корректировать графики работ, приближая их к реальности.
Руководители или спонсоры проекта
- Право ожидать от разработчиков высококачественного ПО. Вы обязаны предоставить среду, ресурсы и время, чтобы разработчики могли создавать высококачественное ПО.
- Право определять цели проекта и устанавливать графики их реализации. Вы обязаны уважать оценки разработчиков и не принуждать их выполнять работы в нереалистичные сроки.
Вы можете думать, что вам полагаются определённые права, присущие какому-то другому сообществу, но порой они не могут или не хотят оправдывать ваши ожидания. Всякий раз, сталкиваясь с подобным несоответствием, стороны должны научиться работать вместе конструктивно и без раздражения. Стоит потратить время, чтобы обсудить взаимные права и обязанности, и, может быть, даже записать их, чтобы избежать недоразумений. Достижение общего понимания прав и обязанностей помогает избежать неприятных межличностных кризисов.
Наша главная обязанность — справедливое и уважительное отношение к коллегам по профессии. Мы все должны быть в состоянии сделать это.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
Уроки 50 Лет Разработки ПО
Урок 38. Люди много говорят о своих правах, но права подразумевают ответственность
В жизни мы имеем не только права, но и обязанности. Вы имеете право владеть автомобилем, но также должны его зарегистрировать и застраховать. Наряду с правом на покупку недвижимости возникает обязанность платить налог за неё. Сочетание прав и обязанностей определяет отношения людей с обществом.
Люди, работающие над программными проектами, тоже имеют права и обязанности. Наши права в этом случае можно представить как наши ожидания по отношению к другим, а обязанности — как ответственность перед ними. Каждый имеет такие права/обязанности перед своими коллегами, клиентами, руководителями, поставщиками и широкой общественностью.
Помимо конкретных обязательств, которые мы берём на себя перед другими, все специалисты по ПО несут ответственность за соблюдение профессиональной этики: действовать в интересах общества, сохранять конфиденциальность, уважать право интеллектуальной собственности, стремиться к высокому качеству и т.д.
Между правами и обязанностями специалистов по ПО существует определённая симметрия. Если члены команды А имеют право рассчитывать на некие услуги или действия членов команды Б, то верно и обратное.
Вот несколько примеров прав и обязанностей команд, участвующих в разработке ПО. Если вас не устраивает формализм записи прав и обязанностей, то можно сформулировать их в виде: «Для меня резонно ожидать от вас Х, а для вас резонно ожидать от меня Y».
Клиенты
- Право ожидать, что бизнес-аналитик будет использовать информацию о вашем бизнесе исключительно для вашего блага. Вы обязаны дать бизнес-аналитикам и разработчикам всю интересующую их информацию о своем бизнесе.
- Право получить систему, отвечающую потребностям и ожиданиям в отношении качества. Вы обязаны выделить время, необходимое для предоставления и уточнения требований.
- Право изменить свои требования. Вы обязаны оперативно сообщить об изменениях требований команде разработчиков.
Разработчики
- Право на признание и уважение вашей интеллектуальной собственности другими. Вы обязаны уважать право интеллектуальной собственности других лиц, повторно используя плоды их труда только с их разрешения.
- Право знать приоритет каждого требования. Вы обязаны информировать заказчика о влиянии на график новых требований и изменений в приоритетах требований.
- Право оценивать и переоценивать свою работу. Вы обязаны делать свои оценки как можно более точными и как можно быстрее корректировать графики работ, приближая их к реальности.
Руководители или спонсоры проекта
- Право ожидать от разработчиков высококачественного ПО. Вы обязаны предоставить среду, ресурсы и время, чтобы разработчики могли создавать высококачественное ПО.
- Право определять цели проекта и устанавливать графики их реализации. Вы обязаны уважать оценки разработчиков и не принуждать их выполнять работы в нереалистичные сроки.
Вы можете думать, что вам полагаются определённые права, присущие какому-то другому сообществу, но порой они не могут или не хотят оправдывать ваши ожидания. Всякий раз, сталкиваясь с подобным несоответствием, стороны должны научиться работать вместе конструктивно и без раздражения. Стоит потратить время, чтобы обсудить взаимные права и обязанности, и, может быть, даже записать их, чтобы избежать недоразумений. Достижение общего понимания прав и обязанностей помогает избежать неприятных межличностных кризисов.
Наша главная обязанность — справедливое и уважительное отношение к коллегам по профессии. Мы все должны быть в состоянии сделать это.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
👍9
День 2174. #ЗаметкиНаПолях
Изучаем CollectionsMarshal на Примере Словарей
Небезопасный класс CollectionsMarshal предоставляет набор методов для эффективного доступа к базовым представлениям данных коллекций. Обратите внимание на слово «небезопасный». Хотя представленные методы и эффективны, неосторожное обращение может нарушить целостность данных. Сегодня рассмотрим, как использовать CollectionsMarshal для эффективной работы со словарями.
В отличие от ConcurrentDictionary, Dictionary не имеет метода GetOrAdd. Этот метод полезен, когда вы хотите добавить пару ключ-значение в словарь, если ключ не существует, или вернуть значение, если ключ уже существует. Наивная реализация:
Проблема в том, что к словарю обращаются дважды: один раз для проверки существования ключа и один раз для добавления пары ключ-значение. Это означает, что вы дважды вычисляете хэш ключа и вызываете метод Equals как минимум дважды, что неэффективно.
Метод CollectionsMarshal.GetValueRefOrAddDefault возвращает ссылку на значение, связанное с ключом, и логическое значение, указывающее, существует ли ключ. Поскольку метод возвращает ссылку, вы можете обновить значение:
Другой полезны метод, GetValueRefOrNullRef, позволяет, например, обновлять значение по ключу, если оно существует:
Источник: https://www.meziantou.net/exploring-collectionsmarshal-for-dictionary.htm
Изучаем CollectionsMarshal на Примере Словарей
Небезопасный класс CollectionsMarshal предоставляет набор методов для эффективного доступа к базовым представлениям данных коллекций. Обратите внимание на слово «небезопасный». Хотя представленные методы и эффективны, неосторожное обращение может нарушить целостность данных. Сегодня рассмотрим, как использовать CollectionsMarshal для эффективной работы со словарями.
В отличие от ConcurrentDictionary, Dictionary не имеет метода GetOrAdd. Этот метод полезен, когда вы хотите добавить пару ключ-значение в словарь, если ключ не существует, или вернуть значение, если ключ уже существует. Наивная реализация:
public static TValue GetOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dict,
TKey key,
TValue value)
where TKey : notnull
{
if (dict.TryGetValue(key, out var result))
return result;
dict[key] = value;
return value;
}
Проблема в том, что к словарю обращаются дважды: один раз для проверки существования ключа и один раз для добавления пары ключ-значение. Это означает, что вы дважды вычисляете хэш ключа и вызываете метод Equals как минимум дважды, что неэффективно.
Метод CollectionsMarshal.GetValueRefOrAddDefault возвращает ссылку на значение, связанное с ключом, и логическое значение, указывающее, существует ли ключ. Поскольку метод возвращает ссылку, вы можете обновить значение:
public static TValue GetOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dict,
TKey key,
TValue value)
where TKey : notnull
{
ref var dictVal = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out var exists);
if (exists)
return dictVal;
dictVal = value;
return value;
}
Другой полезны метод, GetValueRefOrNullRef, позволяет, например, обновлять значение по ключу, если оно существует:
public static bool TryUpdate<TKey, TValue>(
this Dictionary<TKey, TValue> dict,
TKey key,
TValue value)
where TKey : notnull
{
ref var dictVal = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key);
if (!Unsafe.IsNullRef(ref dictVal))
{
dictVal = value;
return true;
}
return false;
}
Источник: https://www.meziantou.net/exploring-collectionsmarshal-for-dictionary.htm
👍28
День 2175. #AI
Работа с LLM в .NET. Начало
Большие языковые модели (LLM) произвели революцию в подходе к приложениям на базе ИИ. Хотя многие разработчики знакомы с облачными решениями, такими как модели GPT от OpenAI, локальный запуск LLM становится всё более доступным благодаря таким проектам, как Ollama. Рассмотрим, как использовать LLM в приложениях .NET с Microsoft.Extensions.AI.
LLM — модели глубокого обучения, построенные на огромных объемах данных, способные понимать и генерировать текст, похожий на человеческий. Они могут выполнять различные задачи, вроде завершения текста, резюмирования, классификации или поддержания разговора.
Ollama — проект с открытым кодом, который упрощает запуск LLM локально. Он предоставляет контейнер Docker, который может запускать различные модели с открытым кодом, такие как Llama, что упрощает эксперименты с ИИ без зависимости от облачных сервисов. Ollama занимается управлением и оптимизацией моделей и предоставляет простой API для взаимодействия.
Microsoft.Extensions.AI — библиотека, которая предоставляет унифицированный интерфейс для работы с LLM в приложениях .NET. Созданная на основе семантического ядра Microsoft, она абстрагируется от сложности различных реализаций LLM, позволяя разработчикам переключаться между поставщиками (такими как Ollama, Azure или OpenAI) без изменения кода приложения.
Подготовка
Замечание: сразу оговорюсь, я стараюсь проверять весь код, который выкладываю на канале, но этот пример проверить не было возможности, поэтому доверюсь автору оригинальной статьи. Если вы попробуете это воспроизвести, и у вас возникнут проблемы, пожалуйста, напишите в комментариях.
Для начала надо запустить LLM локально:
1) Запустите Docker
2) Запустите контейнер Ollama с моделью llama3:
3) Добавьте несколько NuGet-пакетов (эти для .NET 9):
Простой чат
Для начала создадим простой чат с ИИ. Вот минимальный код:
Мы настраиваем внедрение зависимости и задаём простой вопрос. Метод расширения AddChatClient регистрирует клиент чата в контейнере DI. Это позволяет внедрять IChatClient в сервисы и взаимодействовать с LLM с помощью простого API. Реализация использует OllamaChatClient для связи с контейнером Ollama, запущенным локально.
Чат с историей
Основываясь на предыдущем примере, создадим интерактивный чат, который сохраняет историю разговоров. Всё, что нам нужно - хранить историю чата:
Здесь мы получаем потоковый ответ — постепенный текстовый вывод, как в ChatGPT. Мы также сохраняем историю чата, что позволяет модели понимать контекст из предыдущих сообщений, делая разговоры более естественными.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/working-with-llms-in-dotnet-using-microsoft-extensions-ai
Работа с LLM в .NET. Начало
Большие языковые модели (LLM) произвели революцию в подходе к приложениям на базе ИИ. Хотя многие разработчики знакомы с облачными решениями, такими как модели GPT от OpenAI, локальный запуск LLM становится всё более доступным благодаря таким проектам, как Ollama. Рассмотрим, как использовать LLM в приложениях .NET с Microsoft.Extensions.AI.
LLM — модели глубокого обучения, построенные на огромных объемах данных, способные понимать и генерировать текст, похожий на человеческий. Они могут выполнять различные задачи, вроде завершения текста, резюмирования, классификации или поддержания разговора.
Ollama — проект с открытым кодом, который упрощает запуск LLM локально. Он предоставляет контейнер Docker, который может запускать различные модели с открытым кодом, такие как Llama, что упрощает эксперименты с ИИ без зависимости от облачных сервисов. Ollama занимается управлением и оптимизацией моделей и предоставляет простой API для взаимодействия.
Microsoft.Extensions.AI — библиотека, которая предоставляет унифицированный интерфейс для работы с LLM в приложениях .NET. Созданная на основе семантического ядра Microsoft, она абстрагируется от сложности различных реализаций LLM, позволяя разработчикам переключаться между поставщиками (такими как Ollama, Azure или OpenAI) без изменения кода приложения.
Подготовка
Замечание: сразу оговорюсь, я стараюсь проверять весь код, который выкладываю на канале, но этот пример проверить не было возможности, поэтому доверюсь автору оригинальной статьи. Если вы попробуете это воспроизвести, и у вас возникнут проблемы, пожалуйста, напишите в комментариях.
Для начала надо запустить LLM локально:
1) Запустите Docker
2) Запустите контейнер Ollama с моделью llama3:
# Получаем контейнер Ollama
docker run --gpus all -d -v ollama_data:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
# Получаем модель llama3
docker exec -it ollama ollama pull llama3
3) Добавьте несколько NuGet-пакетов (эти для .NET 9):
Install-Package Microsoft.Extensions.AI
Install-Package Microsoft.Extensions.AI.Ollama
Install-Package Microsoft.Extensions.Hosting
Простой чат
Для начала создадим простой чат с ИИ. Вот минимальный код:
var builder = Host.CreateApplicationBuilder();
builder.Services.AddChatClient(
new OllamaChatClient(
new Uri("https://localhost:11434"),
"llama3")
);
var app = builder.Build();
var client = app.Services
.GetRequiredService<IChatClient>();
var response =
await client.CompleteAsync(
"What is .NET? Reply in 50 words max.");
Console.WriteLine(response.Message.Text);
Мы настраиваем внедрение зависимости и задаём простой вопрос. Метод расширения AddChatClient регистрирует клиент чата в контейнере DI. Это позволяет внедрять IChatClient в сервисы и взаимодействовать с LLM с помощью простого API. Реализация использует OllamaChatClient для связи с контейнером Ollama, запущенным локально.
Чат с историей
Основываясь на предыдущем примере, создадим интерактивный чат, который сохраняет историю разговоров. Всё, что нам нужно - хранить историю чата:
var history = new List<ChatMessage>();
while (true)
{
Console.WriteLine("Enter prompt:");
var prompt = Console.ReadLine();
history.Add(
new ChatMessage(ChatRole.User, prompt));
Console.WriteLine("Response:");
var response = "";
await foreach (var item in
client.CompleteStreamingAsync(history))
{
Console.Write(item.Text);
response += item.Text;
}
history.Add(new ChatMessage(
ChatRole.Assistant, response));
Console.WriteLine();
}
Здесь мы получаем потоковый ответ — постепенный текстовый вывод, как в ChatGPT. Мы также сохраняем историю чата, что позволяет модели понимать контекст из предыдущих сообщений, делая разговоры более естественными.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/working-with-llms-in-dotnet-using-microsoft-extensions-ai
👍27
День 2176. #AI
Работа с LLM в .NET. Окончание
Начало
Резюмирование статьи
Попробуем что-то более полезное — выделение главной мысли (резюмирование) текста:
Совет: конкретизация выходного формата (например, запрос JSON, соответствующего RFC8259) помогает получать согласованные результаты.
Интеллектуальная категоризация
Мы можем получать строго типизированные ответы напрямую от LLM:
Строго типизированный подход обеспечивает безопасность во время компиляции и лучшую поддержку IDE, что упрощает поддержку и рефакторинг кода, взаимодействующего с ответами LLM.
Использование различных поставщиков LLM
Одним из ключевых преимуществ Microsoft.Extensions.AI является поддержка различных поставщиков. Хотя в наших примерах используется Ollama, вы можете легко переключиться на других поставщиков:
Это позволяет:
- Начать разработку с локальных моделей
- Развернуть приложение с облачными поставщиками
- Переключаться между поставщиками без изменения кода приложения
- Смешивать разных поставщиков для разных вариантов использования (категоризирование, распознавание изображений и т. д.)
Источник: https://www.milanjovanovic.tech/blog/working-with-llms-in-dotnet-using-microsoft-extensions-ai
Работа с LLM в .NET. Окончание
Начало
Резюмирование статьи
Попробуем что-то более полезное — выделение главной мысли (резюмирование) текста:
var posts = Directory.GetFiles("posts")
.Take(5).ToArray();
foreach (var post in posts)
{
var prompt = $$"""
You will receive an input text and the desired output format.
You need to analyze the text and produce the desired output format.
You are not allowed to change code, text, or other references.
# Desired response
Only provide a RFC8259 compliant JSON response following this format without deviation.
{
"title": "Title pulled from the front matter section",
"summary": "Summarize the article in no more than 100 words"
}
# Article content:
{{File.ReadAllText(post)}}
""";
var response =
await client.CompleteAsync(prompt);
Console.WriteLine(response.Message.Text);
Console.WriteLine(Environment.NewLine);
}
Совет: конкретизация выходного формата (например, запрос JSON, соответствующего RFC8259) помогает получать согласованные результаты.
Интеллектуальная категоризация
Мы можем получать строго типизированные ответы напрямую от LLM:
class PostCategory
{
public string Title { get; set; } = string.Empty;
public string[] Tags { get; set; } = [];
}
var posts = Directory.GetFiles("posts").Take(5).ToArray();
foreach (var post in posts)
{
//Такой же запрос, что и в предыдущем примере, только изменим формат JSON-ответа
var prompt = $$"""
…
{
"title": "Title pulled from the front matter section",
"tags": "Array of tags based on analyzing the article content. Tags should be lowercase."
}
…
""";
var response = await
client.CompleteAsync<PostCategory>(prompt);
Console.WriteLine(
$"{response.Result.Title}. Tags: {string.Join(",",response.Result.Tags)}");
}
Строго типизированный подход обеспечивает безопасность во время компиляции и лучшую поддержку IDE, что упрощает поддержку и рефакторинг кода, взаимодействующего с ответами LLM.
Использование различных поставщиков LLM
Одним из ключевых преимуществ Microsoft.Extensions.AI является поддержка различных поставщиков. Хотя в наших примерах используется Ollama, вы можете легко переключиться на других поставщиков:
// Azure OpenAI
builder.Services.AddChatClient(
new AzureOpenAIClient(
new Uri("AZURE_OPENAI_ENDPOINT"),
new DefaultAzureCredential())
.AsChatClient());
// Using OpenAI
builder.Services.AddChatClient(
new OpenAIClient("OPENAI_API_KEY")
.AsChatClient());
Это позволяет:
- Начать разработку с локальных моделей
- Развернуть приложение с облачными поставщиками
- Переключаться между поставщиками без изменения кода приложения
- Смешивать разных поставщиков для разных вариантов использования (категоризирование, распознавание изображений и т. д.)
Источник: https://www.milanjovanovic.tech/blog/working-with-llms-in-dotnet-using-microsoft-extensions-ai
👍11
День 2177. #ЗаметкиНаПолях
Быстрое и Безопасное Восстановление NuGet-пакетов
Некоторые параметры могут помочь повысить производительность и безопасность при восстановлении NuGet-пакетов.
Файлы блокировки
При восстановлении пакетов NuGet создает граф зависимостей, включающий все объявленные и транзитивные пакеты. Затем этот граф используется для определения того, какие пакеты следует загрузить и установить. Файл блокировки позволяет хранить граф зависимостей и повторно использовать его при восстановлении пакета. Это гарантирует, что разрешение всегда восстанавливает те же пакеты.
Преимущества:
- Безопасность: файл содержит хэш пакета. Если вы загружаете поврежденный или вредоносный пакет, NuGet может обнаружить его и отменить установку.
- Детерминированное восстановление: есть некоторые случаи, когда вычисление графа зависимостей не является детерминированным (разная конфигурация NuGet, плавающие версии, пакет удален на сервере и т. д.). Использование файла блокировки позволяет восстанавливать те же пакеты независимо от конфигурации.
- Производительность: не нужно снова вычислять график зависимости при восстановлении пакетов.
- Надёжность: при использовании сервера NuGet с поддержкой вышестоящего уровня, например Azure Artifacts или Artifactory, серверу не нужно связываться с вышестоящим сервером для вычисления графика зависимости. Таким образом, если nuget.org не работает, вы все равно можете восстановить пакеты, если они уже есть в кэше сервера.
Недостатки:
- Вы можете получить больше конфликтов слияния из-за файла блокировки.
- Некоторые инструменты, такие как Dependabot, не обновляют файл блокировки (на момент написания поста).
Чтобы включить файл блокировки, нужно добавить следующую строку в файл .csproj:
Сопоставление источников пакетов
Если у вас несколько источников NuGet для восстановления пакетов, может потребоваться включить сопоставление источников пакетов. NuGet пытается загрузить пакеты из всех источников параллельно и получить результат из первого, кто ответит. Сопоставление источников пакетов позволяет указать, какой источник следует использовать для восстановления пакета.
Преимущества
- Детерминированное восстановление/безопасность: если несколько серверов содержат один и тот же пакет, его можно восстановить с любого из них. Но если пакеты отличаются, вы можете получить несогласованное восстановление.
- Производительность: NuGet не будет тратить время на запросы к нескольким серверам, поэтому вы сокращаете количество сетевых запросов на восстановление пакетов.
Чтобы использовать сопоставление источников пакетов, вам необходимо создать файл nuget.config в корне репозитория и адаптировать конфигурацию для каждого пакета:
См. также документацию по сопоставлению источников пакетов.
Источник: https://www.meziantou.net/faster-and-safer-nuget-restore-using-source-mapping-and-lock-files.htm
Быстрое и Безопасное Восстановление NuGet-пакетов
Некоторые параметры могут помочь повысить производительность и безопасность при восстановлении NuGet-пакетов.
Файлы блокировки
При восстановлении пакетов NuGet создает граф зависимостей, включающий все объявленные и транзитивные пакеты. Затем этот граф используется для определения того, какие пакеты следует загрузить и установить. Файл блокировки позволяет хранить граф зависимостей и повторно использовать его при восстановлении пакета. Это гарантирует, что разрешение всегда восстанавливает те же пакеты.
Преимущества:
- Безопасность: файл содержит хэш пакета. Если вы загружаете поврежденный или вредоносный пакет, NuGet может обнаружить его и отменить установку.
- Детерминированное восстановление: есть некоторые случаи, когда вычисление графа зависимостей не является детерминированным (разная конфигурация NuGet, плавающие версии, пакет удален на сервере и т. д.). Использование файла блокировки позволяет восстанавливать те же пакеты независимо от конфигурации.
- Производительность: не нужно снова вычислять график зависимости при восстановлении пакетов.
- Надёжность: при использовании сервера NuGet с поддержкой вышестоящего уровня, например Azure Artifacts или Artifactory, серверу не нужно связываться с вышестоящим сервером для вычисления графика зависимости. Таким образом, если nuget.org не работает, вы все равно можете восстановить пакеты, если они уже есть в кэше сервера.
Недостатки:
- Вы можете получить больше конфликтов слияния из-за файла блокировки.
- Некоторые инструменты, такие как Dependabot, не обновляют файл блокировки (на момент написания поста).
Чтобы включить файл блокировки, нужно добавить следующую строку в файл .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--Генерация lock-файла -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<!-- Восстановление пакетов только из lock-файла -->
<RestoreLockedMode Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="…" Version="…" />
</ItemGroup>
</Project>
Сопоставление источников пакетов
Если у вас несколько источников NuGet для восстановления пакетов, может потребоваться включить сопоставление источников пакетов. NuGet пытается загрузить пакеты из всех источников параллельно и получить результат из первого, кто ответит. Сопоставление источников пакетов позволяет указать, какой источник следует использовать для восстановления пакета.
Преимущества
- Детерминированное восстановление/безопасность: если несколько серверов содержат один и тот же пакет, его можно восстановить с любого из них. Но если пакеты отличаются, вы можете получить несогласованное восстановление.
- Производительность: NuGet не будет тратить время на запросы к нескольким серверам, поэтому вы сокращаете количество сетевых запросов на восстановление пакетов.
Чтобы использовать сопоставление источников пакетов, вам необходимо создать файл nuget.config в корне репозитория и адаптировать конфигурацию для каждого пакета:
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="mycompany.org" value="https://mycompany.org/nuget/" />
</packageSources>
<packageSourceMapping>
<!-- key должен соответствовать <packageSources> -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="mycompany.org">
<package pattern="MyCompany.*" />
<package pattern="MyCompanySpecificPackage" />
</packageSource>
</packageSourceMapping>
См. также документацию по сопоставлению источников пакетов.
Источник: https://www.meziantou.net/faster-and-safer-nuget-restore-using-source-mapping-and-lock-files.htm
👍5
День 2178. #Оффтоп
Почему Открытый Код Важен и Бесплатный ли он? Начало
Какие из продуктов вы используете в своей личной или профессиональной работе: Serilog, Polly, PostgreSQL, Git, Curl, Jenkins, Blazor?
Скорее всего вы используете хотя бы один. Большинство ПО в той или иной степени построено на продуктах или библиотеках с открытым кодом. И часто они не поддерживаются большой компанией. Например, Log4J - самая известная библиотека логирования в экосистеме Java. Основная работа выполняется горсткой разработчиков без какой-либо финансовой поддержки. А она использовалась в Apple, Amazon, Steam, Alibaba и т.п.
Log4J / Log4Shell
Коротко напомню: специальный пользовательский ввод может привести к удалённому выполнению кода через сервер LDAP в контексте приложения. А удалённое выполнение кода – это большой красный флаг в сфере ПО. Проблема в том, как это было воспринято теми самыми компаниями, использовавшими Log4J. Согласно этой статье, мейнтейнеры библиотеки получили такое сообщение: «Мы обещаем сохранить это в тайне, пока не выйдет ваш официальный патч. Пожалуйста, поторопитесь.»
Понятно, что из-за такой уязвимости, возможно, придётся отключить затронутые сервисы. А для Amazon или Alibaba это может стоить миллионов и миллиардов дохода за очень короткое время. Мейнтейнеры написали в Твиттере о ситуации: «Сотрудники Log4j не покладая рук трудятся над мерами по смягчению последствий: исправлениями, документацией, CVE, ответами на запросы и т.д. Однако ничто не мешает людям критиковать нас за работу, за которую нам не платят, за функцию, которая нам всем не нравится, но которую необходимо сохранить из-за проблем с обратной совместимостью.»
Другие инциденты
LeftPad был пакетом NPM, который был удалён из-за спора между ментейнером, NPM и компанией. Суть: у мейнтейнера Azer был пакет под названием "kik". Также была компания "kik", которая хотела зарезервировать это имя для себя. Поскольку Azer уже занял это имя, были привлечены юристы. И NPM отдал имя компании. После этого Azer просто удалил свою наиболее используемую библиотеку "leftpad" (да, вы могли просто удалить пакеты из NPM). Конечно, если вы использовали "leftpad" напрямую или транзитивно, ваша сборка ломалась!
Moq — одна из самых известных библиотек в экосистеме dotnet. Создатель Дэниел Каццулино (более известный как kzu) попробовал альтернативный подход к монетизации: он разработал SponsorLink. По сути, в то время он проверял, сделал ли пользователь пожертвование на библиотеку, в которой используется SponsorLink. Он делал это, выполняя HTTP-запрос на какой-то сервер. Я описывал эту ситуацию подробно в этом посте.
Fluent Assertions — одна из популярнейших библиотек для утверждений в юнит-тестах начиная с версии 8 стала платной.
Эти инциденты вызвали довольно много негативной реакции, но все они показывают некоторые фундаментальные недостатки открытого кода:
- Проекты с открытым кодом считаются бесплатными.
- Монетизация — это сложно!
- Требуется поддержка проекта в рабочем состоянии в течение длительного периода
времени.
Продолжение следует…
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
Почему Открытый Код Важен и Бесплатный ли он? Начало
Какие из продуктов вы используете в своей личной или профессиональной работе: Serilog, Polly, PostgreSQL, Git, Curl, Jenkins, Blazor?
Скорее всего вы используете хотя бы один. Большинство ПО в той или иной степени построено на продуктах или библиотеках с открытым кодом. И часто они не поддерживаются большой компанией. Например, Log4J - самая известная библиотека логирования в экосистеме Java. Основная работа выполняется горсткой разработчиков без какой-либо финансовой поддержки. А она использовалась в Apple, Amazon, Steam, Alibaba и т.п.
Log4J / Log4Shell
Коротко напомню: специальный пользовательский ввод может привести к удалённому выполнению кода через сервер LDAP в контексте приложения. А удалённое выполнение кода – это большой красный флаг в сфере ПО. Проблема в том, как это было воспринято теми самыми компаниями, использовавшими Log4J. Согласно этой статье, мейнтейнеры библиотеки получили такое сообщение: «Мы обещаем сохранить это в тайне, пока не выйдет ваш официальный патч. Пожалуйста, поторопитесь.»
Понятно, что из-за такой уязвимости, возможно, придётся отключить затронутые сервисы. А для Amazon или Alibaba это может стоить миллионов и миллиардов дохода за очень короткое время. Мейнтейнеры написали в Твиттере о ситуации: «Сотрудники Log4j не покладая рук трудятся над мерами по смягчению последствий: исправлениями, документацией, CVE, ответами на запросы и т.д. Однако ничто не мешает людям критиковать нас за работу, за которую нам не платят, за функцию, которая нам всем не нравится, но которую необходимо сохранить из-за проблем с обратной совместимостью.»
Другие инциденты
LeftPad был пакетом NPM, который был удалён из-за спора между ментейнером, NPM и компанией. Суть: у мейнтейнера Azer был пакет под названием "kik". Также была компания "kik", которая хотела зарезервировать это имя для себя. Поскольку Azer уже занял это имя, были привлечены юристы. И NPM отдал имя компании. После этого Azer просто удалил свою наиболее используемую библиотеку "leftpad" (да, вы могли просто удалить пакеты из NPM). Конечно, если вы использовали "leftpad" напрямую или транзитивно, ваша сборка ломалась!
Moq — одна из самых известных библиотек в экосистеме dotnet. Создатель Дэниел Каццулино (более известный как kzu) попробовал альтернативный подход к монетизации: он разработал SponsorLink. По сути, в то время он проверял, сделал ли пользователь пожертвование на библиотеку, в которой используется SponsorLink. Он делал это, выполняя HTTP-запрос на какой-то сервер. Я описывал эту ситуацию подробно в этом посте.
Fluent Assertions — одна из популярнейших библиотек для утверждений в юнит-тестах начиная с версии 8 стала платной.
Эти инциденты вызвали довольно много негативной реакции, но все они показывают некоторые фундаментальные недостатки открытого кода:
- Проекты с открытым кодом считаются бесплатными.
- Монетизация — это сложно!
- Требуется поддержка проекта в рабочем состоянии в течение длительного периода
времени.
Продолжение следует…
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
👍19👎1
День 2179. #Оффтоп
Почему Открытый Код Важен? И Бесплатный ли он? Продолжение
Начало
Открытый код бесплатный?
Простой ответ: Да. Можно же просто скачать любой пакет и использовать его? Ну… и да, и нет. Конечно, это «бесплатно». В том смысле, что вы не платите за труд по написанию кода, но есть другие затраты: обслуживание и зависимости. Это звучит странно. Разве не поэтому люди используют библиотеки других людей - чтобы меньше обслуживать код?
Плата за обслуживание
Когда вы используете открытый код, вы наследуете не только его функции, но и его жизненный цикл. Библиотеки с открытым кодом со временем развиваются. У них могут быть критические проблемы, из-за которых вам придётся обновлять пакет. Критические изменения или другие вещи, из-за которых придётся проверять, всё ли ваше ПО по-прежнему делает то, что оно должно делать.
Некоторые проекты с открытым кодом со временем теряют активных мейнтейнеров. Если вы полагаетесь на такую библиотеку, у вас остаётся три варианта:
- Продолжить использовать устаревшую версию (риск безопасности).
- Перейти на альтернативу (может потребовать много усилий, не предоставив прямой ценности).
- Взять на себя обслуживание (сделать форк). Это затраты на обслуживания кода, который вам нужен, а может и не нужен или нужен не весь. Иногда библиотека, от которой вы зависите, не соответствует вашим потребностям, поэтому вам, возможно, придется её форкнуть. Теперь вы также «владеете» кодом со всеми его затратами, зависимостями и последствиями.
Во всех этих случаях вы платите, тратите время и деньги. Каждая зависимость, которую вы создаёте, будет иметь цену. Вам нужно взвесить, оправдана ли она. И эти затраты будут возникать время от времени, а не один раз за весь срок существования проекта. Это особенно важно, если вы используете много микробиблиотек, вроде Left Pad, которые чаще всего содержат не более 10 строк кода и выполняют элементарные функции. Еще один отличный пример: is-even и is-odd. У обеих до сих пор 200000 (да, двести тысяч) загрузок в неделю.
Так что нет, открытый код не бесплатный. Он бесплатный в том смысле, что не стоит денег, но почти всё имеет свою цену! Конечно, то же самое относится и к библиотекам с закрытым кодом, которые вы можете использовать. Они также стоят денег, но они стоят вам большую часть времени денег сверху, и вы не можете наблюдать за процессом разработки открыто.
Все инциденты, описанные ранее, известны и были быстро устранены, потому что всё происходило открыто и прозрачно. Это хорошо. Этим открытый код и прекрасен. И в заключении мы поговорим о другой стороне – мейнтейнерах.
Окончание следует…
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
Почему Открытый Код Важен? И Бесплатный ли он? Продолжение
Начало
Открытый код бесплатный?
Простой ответ: Да. Можно же просто скачать любой пакет и использовать его? Ну… и да, и нет. Конечно, это «бесплатно». В том смысле, что вы не платите за труд по написанию кода, но есть другие затраты: обслуживание и зависимости. Это звучит странно. Разве не поэтому люди используют библиотеки других людей - чтобы меньше обслуживать код?
Плата за обслуживание
Когда вы используете открытый код, вы наследуете не только его функции, но и его жизненный цикл. Библиотеки с открытым кодом со временем развиваются. У них могут быть критические проблемы, из-за которых вам придётся обновлять пакет. Критические изменения или другие вещи, из-за которых придётся проверять, всё ли ваше ПО по-прежнему делает то, что оно должно делать.
Некоторые проекты с открытым кодом со временем теряют активных мейнтейнеров. Если вы полагаетесь на такую библиотеку, у вас остаётся три варианта:
- Продолжить использовать устаревшую версию (риск безопасности).
- Перейти на альтернативу (может потребовать много усилий, не предоставив прямой ценности).
- Взять на себя обслуживание (сделать форк). Это затраты на обслуживания кода, который вам нужен, а может и не нужен или нужен не весь. Иногда библиотека, от которой вы зависите, не соответствует вашим потребностям, поэтому вам, возможно, придется её форкнуть. Теперь вы также «владеете» кодом со всеми его затратами, зависимостями и последствиями.
Во всех этих случаях вы платите, тратите время и деньги. Каждая зависимость, которую вы создаёте, будет иметь цену. Вам нужно взвесить, оправдана ли она. И эти затраты будут возникать время от времени, а не один раз за весь срок существования проекта. Это особенно важно, если вы используете много микробиблиотек, вроде Left Pad, которые чаще всего содержат не более 10 строк кода и выполняют элементарные функции. Еще один отличный пример: is-even и is-odd. У обеих до сих пор 200000 (да, двести тысяч) загрузок в неделю.
Так что нет, открытый код не бесплатный. Он бесплатный в том смысле, что не стоит денег, но почти всё имеет свою цену! Конечно, то же самое относится и к библиотекам с закрытым кодом, которые вы можете использовать. Они также стоят денег, но они стоят вам большую часть времени денег сверху, и вы не можете наблюдать за процессом разработки открыто.
Все инциденты, описанные ранее, известны и были быстро устранены, потому что всё происходило открыто и прозрачно. Это хорошо. Этим открытый код и прекрасен. И в заключении мы поговорим о другой стороне – мейнтейнерах.
Окончание следует…
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
👍7
Если у вас стандартный 8-часовой рабочий день, сколько в среднем времени вы реально занимаетесь рабочими задачами?
Anonymous Poll
23%
не больше 4 часов
29%
4-5 часов
20%
5-6 часов
13%
6-7 часов
7%
больше 7 часов
9%
больше 8 часов (постоянно перерабатываю)
👍5
День 2180. #Оффтоп
Почему Открытый Код Важен? И Бесплатный ли он? Окончание
Начало
Продолжение
Нужно ли платить мейнтейнерам?
Не существует универсального решения. Это зависит от обстоятельств и индивидуальных целей в проекте. Как оправдать эти затраты? Должны ли вы лично донатить? Должна ли компания делать это?
С другой стороны, есть ли ожидания, связанные с этими деньгами? Представьте, что вы получаете $100 доната, и тот же человек лицо/компания открывает тикет или запрос функции, который вы считаете не очень важным. Заставит ли донат вас это реализовывать? Есть мейнтейнеры, которые не берут деньги именно по этой причине.
Не следует ожидать денег от создания ПО с открытым кодом (но получать их, конечно, приятно). По крайней мере, не за тот код, который вы публикуете. Есть компании, как UNO Platform, которые открыли код всех своих продуктов, но вы можете заплатить за контракт на корпоративное обслуживание. Так что, если вам понадобится помощь или функция, они вам помогут.
Приятно иметь стабильный доход от вашего вклада в открытый код, но для большинства проектов этого не будет. Пожертвования хороши, так как сопровождающие, по крайней мере, не терпят убытков в финансовом плане. Они могут нести расходы на серверы, сертификаты и т.д. Если вы цените проект, не стесняйтесь донатить.
Также важно отметить: со стороны мейнтейнеров нет никаких обязательств или гарантий предоставлять поддержку, обновления или определённую функциональность. Они часто работают над проектами в свободное время, движимые страстью или желанием отплатить сообществу. Использование ПО с открытым кодом подразумевает, что между разработчиком и пользователем нет формального контракта. ПО предоставляется «как есть» без гарантий надёжности или пригодности для какой-либо конкретной цели. Это часть стоимости, которую вы платите, если используете какую-либо зависимость.
Зачем вам поддерживать открытый код?
Главное: нет альтернативы, которая была бы лучше в большинстве случаев. У нас нет другой системы, которая бы приносила столько преимуществ по сравнению с недостатками.
Как поддержать открытый код и что я получу?
Самое простое решение (как и со многими проблемами в нашем мире): деньгами. Но это не единственный способ. Тот, кто тратит своё личное время и ресурсы, чтобы улучшить что-то общедоступное - лучше! Если вы создаёте библиотеку, и кто-то пишет вам либо отчёт об ошибке, либо запрос на функцию, либо подаёт пул-реквест, это часто одна из самых высоких наград, которые вы можете получить. Это значит, что кто-то может идентифицировать себя с тем, что вы создали. Мейнтейнеру открытого кода трудно найти кого-то, кто потратит своё время вместе с ним, поэтому время — самый ценный ресурс, который вы можете дать!
Если вы не знаете, как начать, лучше поддерживать небольшие библиотеки, поскольку когнитивная нагрузка для этого меньше. Есть даже целые сайты, такие как https://goodfirstissue.dev/, где вы можете поискать среди репозиториев, кого поддержать.
Что вы получите?
- Знания: изучение чужого кода и шаблонов мышления может помочь вам укрепить ваши собственные хард- и софт-скилы. И, возможно, это даже поможет вам найти работу.
- Нетворкинг: вы познакомитесь с замечательными людьми по всему миру только благодаря вкладам в открытый код.
- Альтруизм: вы делаете добро миру. Ваш код может прямо или косвенно помочь создавать замечательные вещи!
Но, возможно, самое важное. Если вы вносите свой вклад в любой проект с открытым кодом: будьте вежливы и постарайтесь не грубить. Человеческое сотрудничество — это не игра с нулевой суммой! Это совместный вклад в общий успех!
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
Почему Открытый Код Важен? И Бесплатный ли он? Окончание
Начало
Продолжение
Нужно ли платить мейнтейнерам?
Не существует универсального решения. Это зависит от обстоятельств и индивидуальных целей в проекте. Как оправдать эти затраты? Должны ли вы лично донатить? Должна ли компания делать это?
С другой стороны, есть ли ожидания, связанные с этими деньгами? Представьте, что вы получаете $100 доната, и тот же человек лицо/компания открывает тикет или запрос функции, который вы считаете не очень важным. Заставит ли донат вас это реализовывать? Есть мейнтейнеры, которые не берут деньги именно по этой причине.
Не следует ожидать денег от создания ПО с открытым кодом (но получать их, конечно, приятно). По крайней мере, не за тот код, который вы публикуете. Есть компании, как UNO Platform, которые открыли код всех своих продуктов, но вы можете заплатить за контракт на корпоративное обслуживание. Так что, если вам понадобится помощь или функция, они вам помогут.
Приятно иметь стабильный доход от вашего вклада в открытый код, но для большинства проектов этого не будет. Пожертвования хороши, так как сопровождающие, по крайней мере, не терпят убытков в финансовом плане. Они могут нести расходы на серверы, сертификаты и т.д. Если вы цените проект, не стесняйтесь донатить.
Также важно отметить: со стороны мейнтейнеров нет никаких обязательств или гарантий предоставлять поддержку, обновления или определённую функциональность. Они часто работают над проектами в свободное время, движимые страстью или желанием отплатить сообществу. Использование ПО с открытым кодом подразумевает, что между разработчиком и пользователем нет формального контракта. ПО предоставляется «как есть» без гарантий надёжности или пригодности для какой-либо конкретной цели. Это часть стоимости, которую вы платите, если используете какую-либо зависимость.
Зачем вам поддерживать открытый код?
Главное: нет альтернативы, которая была бы лучше в большинстве случаев. У нас нет другой системы, которая бы приносила столько преимуществ по сравнению с недостатками.
Как поддержать открытый код и что я получу?
Самое простое решение (как и со многими проблемами в нашем мире): деньгами. Но это не единственный способ. Тот, кто тратит своё личное время и ресурсы, чтобы улучшить что-то общедоступное - лучше! Если вы создаёте библиотеку, и кто-то пишет вам либо отчёт об ошибке, либо запрос на функцию, либо подаёт пул-реквест, это часто одна из самых высоких наград, которые вы можете получить. Это значит, что кто-то может идентифицировать себя с тем, что вы создали. Мейнтейнеру открытого кода трудно найти кого-то, кто потратит своё время вместе с ним, поэтому время — самый ценный ресурс, который вы можете дать!
Если вы не знаете, как начать, лучше поддерживать небольшие библиотеки, поскольку когнитивная нагрузка для этого меньше. Есть даже целые сайты, такие как https://goodfirstissue.dev/, где вы можете поискать среди репозиториев, кого поддержать.
Что вы получите?
- Знания: изучение чужого кода и шаблонов мышления может помочь вам укрепить ваши собственные хард- и софт-скилы. И, возможно, это даже поможет вам найти работу.
- Нетворкинг: вы познакомитесь с замечательными людьми по всему миру только благодаря вкладам в открытый код.
- Альтруизм: вы делаете добро миру. Ваш код может прямо или косвенно помочь создавать замечательные вещи!
Но, возможно, самое важное. Если вы вносите свой вклад в любой проект с открытым кодом: будьте вежливы и постарайтесь не грубить. Человеческое сотрудничество — это не игра с нулевой суммой! Это совместный вклад в общий успех!
Источник: https://steven-giesel.com/blogPost/591f2354-a205-4507-bbb2-7d88781e0563/why-is-open-source-important-and-is-it-free
👍13
День 2181. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 39. Даже небольшие физические расстояния препятствуют общению и совместной работе
Совместная работа наиболее эффективна, когда коллеги находятся рядом и могут общаться беспрепятственно. Даже если ваш коллега находится в другом кабинете, до которого нужно дойти, либо использовать телефон, коммуникация уже усложняется. Тем более, если вы разделены географически.
Чем больше часовых поясов разделяют общающихся, тем серьёзнее проблема со связью и тем меньше количество рабочих часов, в течение которых люди могут взаимодействовать. В одном проекте участвовали люди из нескольких стран, находящихся в 12 часовых поясах. Какое бы время они ни выбрали для созвонов, оно было для кого-то неудобным. Время постоянно менялось, чтобы неудобства причинялись всем примерно в равной степени. Эта любезность демонстрировала уважение к каждому и давала важный культурный сигнал, указывающий, что все люди независимо от их места работы одинаково важны для проекта.
Организация офисных помещений так, чтобы внутренняя обстановка способствовала совместной работе и при этом сохранялась приватность, позволяющая сотрудникам быть сосредоточенными на работе, — тонкое искусство. Работники умственного труда наиболее продуктивны, когда входят в состояние потока, глубоко погружаясь в задачу. Поддержание состояния потока требует отсутствия отвлекающих факторов. Т.е. люди должны быть достаточно близко друг к другу, чтобы легко взаимодействовать, но им также необходимо личное пространство для сосредоточения внимания.
Виртуальные команды: максимальное разделение
Все больше IT-специалистов работают удалённо. Однако возникновение виртуальных команд порождает новый набор сложностей с организацией культуры сотрудничества. Трудно узнать и понять коллег, которых вы никогда не встречали лично, не говоря уже о том, чтобы выстроить общую культуру ценностей и практик или интегрироваться в неё.
Гугл по запросу «сложности виртуальных команд разработчиков ПО» выдаёт множество статей, посвященных соответствующим проблемам. Если вы работаете удалённо, стоит потратить время, чтобы изучить основные сложности и подумать, как добиться успеха.
Дверь, дверь, королевство за дверь!
Закрытая дверь — барьер для общения. В зависимости от того, по какую сторону двери вы находитесь, она может быть преимуществом или неудобством. Если двери нет, то это способствует общению, с другой стороны, как сообщить коллегам, что вы заняты? Можно использовать табличку с надписью «Свободен» с одной стороны и «Занят» с другой. Либо какой-то другой похожий сигнал. Но надо договориться об этом с коллегами, потому что далеко не все понимают намёки. В некоторых компаниях эксперты, оказывающие консультативные услуги, устанавливают рабочие часы, в течение которых к ним можно прийти для обсуждения назревших вопросов.
К работе в популярных среди компаний по разработке ПО опенспейсах тоже нужно привыкнуть, и далеко не у всех это получается. Многие испытывают сильный стресс, пока не адаптируются к шумной среде.
Не существует идеального решения для организации рабочих пространств, которые могли бы удовлетворить противоречивые потребности в приватности, свободе от отвлекающих факторов, близости к коллегам в целях быстрого взаимодействия и общем пространстве для совещаний по проекту. Географическое разделение вызывает проблемы, а культурные различия значительно усложняют эффективное сотрудничество. Инструменты для совместной работы помогают сотрудничать людям, разделённым большими расстояниями, но не могут полностью заменить личное взаимодействие в реальном времени. По мере возможности руководители должны позволять членам команды самим организовывать их рабочие места, чтобы наилучшим образом сбалансировать эти противоречивые цели. А если это невозможно, есть наушники или беруши.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
Уроки 50 Лет Разработки ПО
Урок 39. Даже небольшие физические расстояния препятствуют общению и совместной работе
Совместная работа наиболее эффективна, когда коллеги находятся рядом и могут общаться беспрепятственно. Даже если ваш коллега находится в другом кабинете, до которого нужно дойти, либо использовать телефон, коммуникация уже усложняется. Тем более, если вы разделены географически.
Чем больше часовых поясов разделяют общающихся, тем серьёзнее проблема со связью и тем меньше количество рабочих часов, в течение которых люди могут взаимодействовать. В одном проекте участвовали люди из нескольких стран, находящихся в 12 часовых поясах. Какое бы время они ни выбрали для созвонов, оно было для кого-то неудобным. Время постоянно менялось, чтобы неудобства причинялись всем примерно в равной степени. Эта любезность демонстрировала уважение к каждому и давала важный культурный сигнал, указывающий, что все люди независимо от их места работы одинаково важны для проекта.
Организация офисных помещений так, чтобы внутренняя обстановка способствовала совместной работе и при этом сохранялась приватность, позволяющая сотрудникам быть сосредоточенными на работе, — тонкое искусство. Работники умственного труда наиболее продуктивны, когда входят в состояние потока, глубоко погружаясь в задачу. Поддержание состояния потока требует отсутствия отвлекающих факторов. Т.е. люди должны быть достаточно близко друг к другу, чтобы легко взаимодействовать, но им также необходимо личное пространство для сосредоточения внимания.
Виртуальные команды: максимальное разделение
Все больше IT-специалистов работают удалённо. Однако возникновение виртуальных команд порождает новый набор сложностей с организацией культуры сотрудничества. Трудно узнать и понять коллег, которых вы никогда не встречали лично, не говоря уже о том, чтобы выстроить общую культуру ценностей и практик или интегрироваться в неё.
Гугл по запросу «сложности виртуальных команд разработчиков ПО» выдаёт множество статей, посвященных соответствующим проблемам. Если вы работаете удалённо, стоит потратить время, чтобы изучить основные сложности и подумать, как добиться успеха.
Дверь, дверь, королевство за дверь!
Закрытая дверь — барьер для общения. В зависимости от того, по какую сторону двери вы находитесь, она может быть преимуществом или неудобством. Если двери нет, то это способствует общению, с другой стороны, как сообщить коллегам, что вы заняты? Можно использовать табличку с надписью «Свободен» с одной стороны и «Занят» с другой. Либо какой-то другой похожий сигнал. Но надо договориться об этом с коллегами, потому что далеко не все понимают намёки. В некоторых компаниях эксперты, оказывающие консультативные услуги, устанавливают рабочие часы, в течение которых к ним можно прийти для обсуждения назревших вопросов.
К работе в популярных среди компаний по разработке ПО опенспейсах тоже нужно привыкнуть, и далеко не у всех это получается. Многие испытывают сильный стресс, пока не адаптируются к шумной среде.
Не существует идеального решения для организации рабочих пространств, которые могли бы удовлетворить противоречивые потребности в приватности, свободе от отвлекающих факторов, близости к коллегам в целях быстрого взаимодействия и общем пространстве для совещаний по проекту. Географическое разделение вызывает проблемы, а культурные различия значительно усложняют эффективное сотрудничество. Инструменты для совместной работы помогают сотрудничать людям, разделённым большими расстояниями, но не могут полностью заменить личное взаимодействие в реальном времени. По мере возможности руководители должны позволять членам команды самим организовывать их рабочие места, чтобы наилучшим образом сбалансировать эти противоречивые цели. А если это невозможно, есть наушники или беруши.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
👍12👎9
День 2182. #МоиИнструменты
SQL-запросы к Логам и Другим Текстовым Данным
Сразу оговорюсь, что этот инструмент древний как мамонты, и в эпоху структурированных логов, Seq и прочих мощных визуализаторов, он, возможно, мало кому будет интересен, но вдруг. Я обнаружил его только недавно по необходимости.
Попросил меня коллега выбрать из логов IIS айпишники клиентов, которые обращались к определённому URL. Логи IIS – это текстовые файлы вот такого формата:
И дальше ещё много таких строчек (в моём случае было 2 файла по 1Гб+).
Так вот, у Microsoft есть утилита Log Parser которая обеспечивает универсальный доступ через SQL-запросы к текстовым данным, таким как файлы логов, XML-файлы и CSV-файлы, а также к источникам данных в операционной системе Windows, таким как журнал событий, реестр, файловая система и Active Directory.
Но это утилита для командной строки, а для любителей GUI, есть Log Parser Studio (скачать можно здесь), которая работает поверх Log Parser. На картинке выше пример результата запроса к логам IIS. Кроме того, Log Parser Studio позволяет выполнять разные запросы на нескольких вкладках, экспортировать результаты, сгенерировать скрипт для PowerShell, чтобы выполнять его на любой машине, где установлен Log Parser, а также содержит десятки шаблонов популярных запросов.
В общем, небольшая, но полезная в отдельных случаях утилитка.
Источник: https://techcommunity.microsoft.com/blog/exchange/log-parser-studio-2-0-is-now-available/593266
SQL-запросы к Логам и Другим Текстовым Данным
Сразу оговорюсь, что этот инструмент древний как мамонты, и в эпоху структурированных логов, Seq и прочих мощных визуализаторов, он, возможно, мало кому будет интересен, но вдруг. Я обнаружил его только недавно по необходимости.
Попросил меня коллега выбрать из логов IIS айпишники клиентов, которые обращались к определённому URL. Логи IIS – это текстовые файлы вот такого формата:
#Fields: date time s-sitename s-computername s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs-version cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2025-01-15 00:00:00 W3SVC7 WWW-VM-B 127.0.0.1 GET /page.html - 443 - 8.8.8.8 HTTP/1.1 Mozilla/5.0+… - 200 0 0 103
…
И дальше ещё много таких строчек (в моём случае было 2 файла по 1Гб+).
Так вот, у Microsoft есть утилита Log Parser которая обеспечивает универсальный доступ через SQL-запросы к текстовым данным, таким как файлы логов, XML-файлы и CSV-файлы, а также к источникам данных в операционной системе Windows, таким как журнал событий, реестр, файловая система и Active Directory.
Но это утилита для командной строки, а для любителей GUI, есть Log Parser Studio (скачать можно здесь), которая работает поверх Log Parser. На картинке выше пример результата запроса к логам IIS. Кроме того, Log Parser Studio позволяет выполнять разные запросы на нескольких вкладках, экспортировать результаты, сгенерировать скрипт для PowerShell, чтобы выполнять его на любой машине, где установлен Log Parser, а также содержит десятки шаблонов популярных запросов.
В общем, небольшая, но полезная в отдельных случаях утилитка.
Источник: https://techcommunity.microsoft.com/blog/exchange/log-parser-studio-2-0-is-now-available/593266
👍30
День 2183. #TipsAndTricks
Упрощаем Отладку Сторонних Типов
При отладке часто бывает полезно иметь возможность проверять состояние объектов в отладчике. Однако, когда вы работаете со сторонними типами, которые не имеют форматирования при отладке, вы не можете легко посмотреть их внутреннее состояние. Сегодня посмотрим, как добавить форматирование при отладке к сторонним типам.
DebuggerDisplayAttribute — очень полезный атрибут, позволяющий указать, как объект должен отображаться в отладчике. Ваши типы можно пометить этим атрибутом так:
Это заставит отладчик отображать экземпляр объекта Person как
Но что, если вы работаете со сторонним типом, в который вы не можете добавить атрибут DebuggerDisplay?
Существует менее известное свойство Target, которое определяет, к какому типу следует применять атрибут DebuggerDisplay. Мы можем использовать его в сочетании с атрибутом assembly, чтобы добавить любому типу форматирование при отладке. Для простоты добавим его для типа Task, хотя он уже отображается отформатированным при отладке.
Теперь при наведении мыши на переменную task вы увидите результат, похожий на тот, что на картинке ниже.
У этого подхода есть некоторые «естественные» недостатки:
1. Вы можете помечать только публичные типы или интерфейсы по очевидным причинам.
2. Может быть неочевидно, откуда берётся отладочная информация. Особенно, если у вас большая кодовая база, и кто-то в её «потайном уголке» помечает тип атрибутом DebuggerDisplay для форматирования при отладке.
Источник: https://www.meziantou.net/hsts-for-httpclient-in-dotnet.htm
Упрощаем Отладку Сторонних Типов
При отладке часто бывает полезно иметь возможность проверять состояние объектов в отладчике. Однако, когда вы работаете со сторонними типами, которые не имеют форматирования при отладке, вы не можете легко посмотреть их внутреннее состояние. Сегодня посмотрим, как добавить форматирование при отладке к сторонним типам.
DebuggerDisplayAttribute — очень полезный атрибут, позволяющий указать, как объект должен отображаться в отладчике. Ваши типы можно пометить этим атрибутом так:
[DebuggerDisplay("Name = {Name}, Age = {Age}")]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var person = new Person { Name = "John", Age = 42 };
Это заставит отладчик отображать экземпляр объекта Person как
Name = John, Age = 42
.Но что, если вы работаете со сторонним типом, в который вы не можете добавить атрибут DebuggerDisplay?
Существует менее известное свойство Target, которое определяет, к какому типу следует применять атрибут DebuggerDisplay. Мы можем использовать его в сочетании с атрибутом assembly, чтобы добавить любому типу форматирование при отладке. Для простоты добавим его для типа Task, хотя он уже отображается отформатированным при отладке.
[assembly: DebuggerDisplay("Is Task finished: {IsCompleted}", Target = typeof(Task))]
var task = Task.Delay(100_000);
await task;
Теперь при наведении мыши на переменную task вы увидите результат, похожий на тот, что на картинке ниже.
У этого подхода есть некоторые «естественные» недостатки:
1. Вы можете помечать только публичные типы или интерфейсы по очевидным причинам.
2. Может быть неочевидно, откуда берётся отладочная информация. Особенно, если у вас большая кодовая база, и кто-то в её «потайном уголке» помечает тип атрибутом DebuggerDisplay для форматирования при отладке.
Источник: https://www.meziantou.net/hsts-for-httpclient-in-dotnet.htm
👍35
День 2184. #ЗаметкиНаПолях
Масштабируем Монолиты. Начало
Монолиты среди разработчиков пользуются дурной славой. Считается что они устарели, не масштабируются и что для успеха нам нужны микросервисы. Это неправда. Хорошо спроектированный монолит - часто правильный выбор и может хорошо масштабироваться. Ключ к успеху — понимание ваших потребностей в масштабировании и применение правильных решений в нужное время.
Понимание масштаба
Монолит помещает весь код в одну развёртываемую единицу. Его преимущества - более быстрые циклы разработки, более простые отладка и развёртывания. Но по мере роста системы вы столкнётесь с проблемами масштабирования:
- Запросы к БД замедляются по мере роста объёма данных;
- API, отлично работавшее с сотнями пользователей, начинает тормозить при тысячах;
- Время сборки увеличивается по мере расширения кодовой базы.
Это естественные проблемы роста, с которыми сталкивается каждая успешная система.
1. Вертикальное масштабирование
Это предоставление приложению большего количества ресурсов на одной машине. Самая простая стратегия масштабирования и часто самый эффективный первый шаг. Прежде чем погружаться в сложные распределённые системы, подумайте, может ли модернизация существующей инфраструктуры решить проблемы с производительностью.
Вертикальное масштабирование особенно хорошо работает, когда есть явные узкие места в ресурсах. Если ЦП постоянно загружен более чем на 80%, поможет добавление дополнительных ядер. Если тормозит ввод-вывод в БД, обновление до более быстрого хранилища может значительно повысить производительность. Современные облачные платформы делают это чрезвычайно простым.
Преимущества
Поддерживается простота системы: не нужно перепроектировать архитектуру, внедрять новые шаблоны развёртывания или управлять сложностью распределённой системы. Процедуры мониторинга, отладки и эксплуатации остаются прежними.
Ограничения
В итоге вы достигнете потолка того, что может обработать одна машина. В облаке есть ограничения мощности машин, а затраты обычно экспоненциально увеличиваются. Кроме того, одна машина — это единая точка отказа.
За чем следить:
- Расходы растут быстрее, чем пользовательская база;
- Нужна лучшая избыточность и отказоустойчивость;
- Время простоя развёртывания влияет на бизнес-операции;
- Самый большой доступный размер машины приближается к 70% использования.
2. Горизонтальное масштабирование
Запускает несколько экземпляров приложения за балансировщиком нагрузки. Обеспечивает улучшенную отказоустойчивость и почти линейные возможности масштабирования.
Ключ к успешному горизонтальному масштабированию в дизайне приложения. Оно не должно сохранять состояние — каждый запрос должен содержать всю информацию, необходимую для его обработки. Это означает:
- Аутентификация через токены (например, JWT), а не сессии на сервере;
- Распределённое кэширование.
Балансировщик нагрузки играет решающую роль в этой архитектуре. Его задача — распределять трафик по экземплярам приложения. Популярные варианты включают:
- nginx: мощный, с открытым исходным кодом, отлично подходит для пользовательских конфигураций;
- YARP: обратный прокси от Microsoft, отлично подходит для приложений .NET;
- Облако: AWS ALB, Azure Application Gateway, Google Cloud Load Balancing
Преимущества
- Лучшая отказоустойчивость;
- Возможность обрабатывать больше пользователей одновременно;
- Последовательные развёртывания с нулевым временем простоя;
- Экономически эффективное масштабирование (отключение ненужных экземпляров при низком трафике).
Недостатки
В основном не технические, а архитектурные. Приложение должно быть спроектировано для горизонтального масштабирования с самого начала. Преобразование приложения с сохранением состояния в приложение без него часто требует значительного рефакторинга.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
Масштабируем Монолиты. Начало
Монолиты среди разработчиков пользуются дурной славой. Считается что они устарели, не масштабируются и что для успеха нам нужны микросервисы. Это неправда. Хорошо спроектированный монолит - часто правильный выбор и может хорошо масштабироваться. Ключ к успеху — понимание ваших потребностей в масштабировании и применение правильных решений в нужное время.
Понимание масштаба
Монолит помещает весь код в одну развёртываемую единицу. Его преимущества - более быстрые циклы разработки, более простые отладка и развёртывания. Но по мере роста системы вы столкнётесь с проблемами масштабирования:
- Запросы к БД замедляются по мере роста объёма данных;
- API, отлично работавшее с сотнями пользователей, начинает тормозить при тысячах;
- Время сборки увеличивается по мере расширения кодовой базы.
Это естественные проблемы роста, с которыми сталкивается каждая успешная система.
1. Вертикальное масштабирование
Это предоставление приложению большего количества ресурсов на одной машине. Самая простая стратегия масштабирования и часто самый эффективный первый шаг. Прежде чем погружаться в сложные распределённые системы, подумайте, может ли модернизация существующей инфраструктуры решить проблемы с производительностью.
Вертикальное масштабирование особенно хорошо работает, когда есть явные узкие места в ресурсах. Если ЦП постоянно загружен более чем на 80%, поможет добавление дополнительных ядер. Если тормозит ввод-вывод в БД, обновление до более быстрого хранилища может значительно повысить производительность. Современные облачные платформы делают это чрезвычайно простым.
Преимущества
Поддерживается простота системы: не нужно перепроектировать архитектуру, внедрять новые шаблоны развёртывания или управлять сложностью распределённой системы. Процедуры мониторинга, отладки и эксплуатации остаются прежними.
Ограничения
В итоге вы достигнете потолка того, что может обработать одна машина. В облаке есть ограничения мощности машин, а затраты обычно экспоненциально увеличиваются. Кроме того, одна машина — это единая точка отказа.
За чем следить:
- Расходы растут быстрее, чем пользовательская база;
- Нужна лучшая избыточность и отказоустойчивость;
- Время простоя развёртывания влияет на бизнес-операции;
- Самый большой доступный размер машины приближается к 70% использования.
2. Горизонтальное масштабирование
Запускает несколько экземпляров приложения за балансировщиком нагрузки. Обеспечивает улучшенную отказоустойчивость и почти линейные возможности масштабирования.
Ключ к успешному горизонтальному масштабированию в дизайне приложения. Оно не должно сохранять состояние — каждый запрос должен содержать всю информацию, необходимую для его обработки. Это означает:
- Аутентификация через токены (например, JWT), а не сессии на сервере;
- Распределённое кэширование.
Балансировщик нагрузки играет решающую роль в этой архитектуре. Его задача — распределять трафик по экземплярам приложения. Популярные варианты включают:
- nginx: мощный, с открытым исходным кодом, отлично подходит для пользовательских конфигураций;
- YARP: обратный прокси от Microsoft, отлично подходит для приложений .NET;
- Облако: AWS ALB, Azure Application Gateway, Google Cloud Load Balancing
Преимущества
- Лучшая отказоустойчивость;
- Возможность обрабатывать больше пользователей одновременно;
- Последовательные развёртывания с нулевым временем простоя;
- Экономически эффективное масштабирование (отключение ненужных экземпляров при низком трафике).
Недостатки
В основном не технические, а архитектурные. Приложение должно быть спроектировано для горизонтального масштабирования с самого начала. Преобразование приложения с сохранением состояния в приложение без него часто требует значительного рефакторинга.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
👍16👎1
День 2185. #ЗаметкиНаПолях
Масштабируем Монолиты. Продолжение
Начало
3. Масштабирование БД
Производительность БД - то, где большинство монолитов впервые сталкиваются с реальными ограничениями. Рассмотрим подробно стратегии масштабирования.
Реплики чтения
Часто это первый шаг в масштабировании БД. Создаются копии основной БД, которые обслуживают трафик только для чтения. Каждая реплика поддерживает актуальную копию данных посредством репликаций. Изменения передаются в одном направлении: от основной БД к репликам. Т.е. любые данные, записанные в основную БД, в итоге появятся в репликах. «В итоге», т.е. с задержкой. Так вы жертвуете согласованностью данных ради лучшей производительности чтения.
Большинство поставщиков облачных услуг поддерживают реплики чтения с минимальной настройкой, выполняя репликацию, мониторинг и следя за отказоустойчивостью за вас.
Важно:
- Задержка репликации влияет на актуальность данных;
- Объём записи влияет на скорость репликации;
- Географическое местоположение влияет на задержку;
- Каждая реплика увеличивает ваши расходы.
Материализированные представления
Это предварительно вычисленный набор данных, хранящийся в виде таблицы. В отличие от обычных представлений, которые вычисляют результаты для каждого запроса, материализованные представления сохраняют результаты. Это значительно ускоряет их выполнение, но создает новую проблему: поддержание их актуальности.
Сценарии использования:
- Сложные аналитические запросы;
- Данные, которые обновляются по расписанию;
- Агрегации и сводки;
- Денормализация данных для определённых представлений.
Ключевой компромисс — актуальность против производительности. Нужно решить, как часто обновлять материализованные представления. Слишком часто — нагрузка на БД, слишком редко — данные устаревают.
Шардирование БД
Разделяет данные между несколькими экземплярами БД, причём каждый содержит отдельное подмножество данных.
Шардирование по диапазону разделяет данные на основе диапазонов значений ключа. Например, клиенты А-М – в раздел 1, Н-Я — в раздел 2. Подход хорошо работает с данными, имеющими естественное распределение диапазонов: даты или алфавитный порядок, - но может привести к появлению точек перегрузки, если определённые диапазоны будут запрашиваться чаще, чем другие.
Шардирование по хэшу применяет хэш-функцию к ключу, чтобы определить, в какой раздел поместить данные. Выбор функции хэширования имеет решающее значение. Она должна равномерно распределять данные по разделам, чтобы ни один не стал узким местом. Этот подход обеспечивает лучшее распределение данных, но усложняет запросы на основе диапазонов, поскольку связанные данные могут находиться в разных разделах.
Шардирование по клиенту предоставляет каждому клиенту собственную БД. Подход обеспечивает естественную изоляцию и упрощает операции, специфичные для клиента. Хотя он усложняет запросы между клиентами, он часто является самым чистым решением для мультитенантных систем, где важна изоляция данных.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
Масштабируем Монолиты. Продолжение
Начало
3. Масштабирование БД
Производительность БД - то, где большинство монолитов впервые сталкиваются с реальными ограничениями. Рассмотрим подробно стратегии масштабирования.
Реплики чтения
Часто это первый шаг в масштабировании БД. Создаются копии основной БД, которые обслуживают трафик только для чтения. Каждая реплика поддерживает актуальную копию данных посредством репликаций. Изменения передаются в одном направлении: от основной БД к репликам. Т.е. любые данные, записанные в основную БД, в итоге появятся в репликах. «В итоге», т.е. с задержкой. Так вы жертвуете согласованностью данных ради лучшей производительности чтения.
Большинство поставщиков облачных услуг поддерживают реплики чтения с минимальной настройкой, выполняя репликацию, мониторинг и следя за отказоустойчивостью за вас.
Важно:
- Задержка репликации влияет на актуальность данных;
- Объём записи влияет на скорость репликации;
- Географическое местоположение влияет на задержку;
- Каждая реплика увеличивает ваши расходы.
Материализированные представления
Это предварительно вычисленный набор данных, хранящийся в виде таблицы. В отличие от обычных представлений, которые вычисляют результаты для каждого запроса, материализованные представления сохраняют результаты. Это значительно ускоряет их выполнение, но создает новую проблему: поддержание их актуальности.
Сценарии использования:
- Сложные аналитические запросы;
- Данные, которые обновляются по расписанию;
- Агрегации и сводки;
- Денормализация данных для определённых представлений.
Ключевой компромисс — актуальность против производительности. Нужно решить, как часто обновлять материализованные представления. Слишком часто — нагрузка на БД, слишком редко — данные устаревают.
Шардирование БД
Разделяет данные между несколькими экземплярами БД, причём каждый содержит отдельное подмножество данных.
Шардирование по диапазону разделяет данные на основе диапазонов значений ключа. Например, клиенты А-М – в раздел 1, Н-Я — в раздел 2. Подход хорошо работает с данными, имеющими естественное распределение диапазонов: даты или алфавитный порядок, - но может привести к появлению точек перегрузки, если определённые диапазоны будут запрашиваться чаще, чем другие.
Шардирование по хэшу применяет хэш-функцию к ключу, чтобы определить, в какой раздел поместить данные. Выбор функции хэширования имеет решающее значение. Она должна равномерно распределять данные по разделам, чтобы ни один не стал узким местом. Этот подход обеспечивает лучшее распределение данных, но усложняет запросы на основе диапазонов, поскольку связанные данные могут находиться в разных разделах.
Шардирование по клиенту предоставляет каждому клиенту собственную БД. Подход обеспечивает естественную изоляцию и упрощает операции, специфичные для клиента. Хотя он усложняет запросы между клиентами, он часто является самым чистым решением для мультитенантных систем, где важна изоляция данных.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
👍16
День 2186. #ЗаметкиНаПолях
Масштабируем Монолиты. Окончание
Начало
Продолжение
4. Кэширование
Один из самых эффективных способов повышения производительности системы. Правильно реализованная стратегия кэширования может значительно снизить нагрузку на БД и улучшить время отклика за счёт хранения часто используемых данных в памяти.
Современное кэширование происходит на нескольких уровнях:
- Кэширование в браузере сокращает ненужные сетевые запросы;
- CDN-кэширование приближает контент к пользователям;
- Кэширование на уровне приложений с помощью таких инструментов, как Redis, сохраняет часто используемые данные в памяти;
- Кэширование запросов к БД сокращает дорогостоящие вычисления.
Ключ к эффективному кэшированию — понимание ваших паттернов доступа к данным. Часто читаемые, редко изменяемые данные получат наибольшую выгоду от кэширования. Такие инструменты, как Redis, Memcached или гибридный кэш, отлично справляются с хранением таких данных в памяти, обеспечивая время доступа менее миллисекунды. Поставщики облачных услуг предлагают управляемые сервисы кэширования, такие как Azure Cache для Redis, которые справляются с эксплуатационной сложностью обслуживания распределённого кэша.
5. Очереди сообщений
Позволяют откладывать трудоёмкие операции и распределять работу между несколькими обработчиками. Это сохраняет отзывчивость приложения путём обработки тяжёлых задач в фоновом режиме.
Очереди сообщений преобразуют поведение системы под нагрузкой. Вместо того чтобы обрабатывать всё синхронно, вы можете ставить работу в очередь на потом. Этот шаблон особенно хорошо работает для таких операций, как:
- обработка загруженных файлов,
- отправка писем и уведомлений,
- создание отчётов,
- обновление поисковых индексов,
- выполнение пакетных операций.
Настоящая сила очередей сообщений заключается в их способности справляться с пиками трафика. Когда система сталкивается с всплеском запросов, очереди действуют как буфер. Они позволяют вам принимать работу с пиковой скоростью, но обрабатывать её в равномерном темпе.
Итого
Масштабирование монолита не заключается в выборе между вертикальным или горизонтальным масштабированием, кэшированием или любым другим подходом. Важно использовать правильный инструмент в правильное время. Начните с самого простого решения, которое решает вашу непосредственную проблему, а затем добавляйте сложность при необходимости.
Практический путь масштабирования:
1. Оптимизируйте код и запросы к БД;
2. Добавьте кэширование там, где это наиболее важно;
3. Масштабируйте вертикально, пока это экономически эффективно;
4. Переходите к горизонтальному масштабированию для лучшей отказоустойчивости;
5. Внедряйте очереди сообщений для фоновой работы;
6. Рассмотрите возможность шардирования БД, когда этого требует размер данных.
Хорошо спроектированный монолит может выдерживать значительную нагрузку, используя лишь часть этих методов. Главное — понять фактические узкие места вашей системы и устранить их конкретно. Не позволяйте лучшему быть врагом хорошего. Начните с самого простого решения, которое может работать, измерьте всё и масштабируйте то, что необходимо.
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
Масштабируем Монолиты. Окончание
Начало
Продолжение
4. Кэширование
Один из самых эффективных способов повышения производительности системы. Правильно реализованная стратегия кэширования может значительно снизить нагрузку на БД и улучшить время отклика за счёт хранения часто используемых данных в памяти.
Современное кэширование происходит на нескольких уровнях:
- Кэширование в браузере сокращает ненужные сетевые запросы;
- CDN-кэширование приближает контент к пользователям;
- Кэширование на уровне приложений с помощью таких инструментов, как Redis, сохраняет часто используемые данные в памяти;
- Кэширование запросов к БД сокращает дорогостоящие вычисления.
Ключ к эффективному кэшированию — понимание ваших паттернов доступа к данным. Часто читаемые, редко изменяемые данные получат наибольшую выгоду от кэширования. Такие инструменты, как Redis, Memcached или гибридный кэш, отлично справляются с хранением таких данных в памяти, обеспечивая время доступа менее миллисекунды. Поставщики облачных услуг предлагают управляемые сервисы кэширования, такие как Azure Cache для Redis, которые справляются с эксплуатационной сложностью обслуживания распределённого кэша.
5. Очереди сообщений
Позволяют откладывать трудоёмкие операции и распределять работу между несколькими обработчиками. Это сохраняет отзывчивость приложения путём обработки тяжёлых задач в фоновом режиме.
Очереди сообщений преобразуют поведение системы под нагрузкой. Вместо того чтобы обрабатывать всё синхронно, вы можете ставить работу в очередь на потом. Этот шаблон особенно хорошо работает для таких операций, как:
- обработка загруженных файлов,
- отправка писем и уведомлений,
- создание отчётов,
- обновление поисковых индексов,
- выполнение пакетных операций.
Настоящая сила очередей сообщений заключается в их способности справляться с пиками трафика. Когда система сталкивается с всплеском запросов, очереди действуют как буфер. Они позволяют вам принимать работу с пиковой скоростью, но обрабатывать её в равномерном темпе.
Итого
Масштабирование монолита не заключается в выборе между вертикальным или горизонтальным масштабированием, кэшированием или любым другим подходом. Важно использовать правильный инструмент в правильное время. Начните с самого простого решения, которое решает вашу непосредственную проблему, а затем добавляйте сложность при необходимости.
Практический путь масштабирования:
1. Оптимизируйте код и запросы к БД;
2. Добавьте кэширование там, где это наиболее важно;
3. Масштабируйте вертикально, пока это экономически эффективно;
4. Переходите к горизонтальному масштабированию для лучшей отказоустойчивости;
5. Внедряйте очереди сообщений для фоновой работы;
6. Рассмотрите возможность шардирования БД, когда этого требует размер данных.
Хорошо спроектированный монолит может выдерживать значительную нагрузку, используя лишь часть этих методов. Главное — понять фактические узкие места вашей системы и устранить их конкретно. Не позволяйте лучшему быть врагом хорошего. Начните с самого простого решения, которое может работать, измерьте всё и масштабируйте то, что необходимо.
Источник: https://www.milanjovanovic.tech/blog/scaling-monoliths-a-practical-guide-for-growing-systems
👍11
День 2187. #ЗаметкиНаПолях
Используем Roslyn для Анализа и Изменения Кода Решения
Roslyn можно использовать как библиотеку для анализа и генерации кода. Например, вы можете создать консольное приложение, которое загружает решение, находит шаблоны и переписывает код.
Создадим консольное приложение и добавим необходимые NuGet-пакеты:
Вот пример, как создать рабочее пространство Roslyn из решения:
Теперь можно работать с решением. Вот несколько примеров.
Анализируем синтаксические деревья:
Получаем все ссылки на символ:
Переименовываем символ
Обновляем документ с помощью DocumentEditor
Обновляем документ с помощью CSharpSyntaxRewriter:
Выберите любое «подопытное» решение, введите его путь вместо
Источник: https://www.meziantou.net/using-roslyn-to-analyze-and-rewrite-code-in-a-solution.htm
Используем Roslyn для Анализа и Изменения Кода Решения
Roslyn можно использовать как библиотеку для анализа и генерации кода. Например, вы можете создать консольное приложение, которое загружает решение, находит шаблоны и переписывает код.
Создадим консольное приложение и добавим необходимые NuGet-пакеты:
dotnet new console
dotnet add package Microsoft.Build.Locator
dotnet add package Microsoft.CodeAnalysis.CSharp
dotnet add package Microsoft.CodeAnalysis.CSharp.Workspaces
dotnet add package Microsoft.CodeAnalysis.Workspaces.Common
dotnet add package Microsoft.CodeAnalysis.Workspaces.MSBuild
Вот пример, как создать рабочее пространство Roslyn из решения:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;
// Находим сборки MSBuild в вашей системе
Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
// Возможно надо восстановить NuGet-пакеты решения перед тем, как открыть его в Roslyn.
// Зависимости могут потребоваться для корректного анализа.
// Создаём рабочее пространство Roslyn и загружаем решение
var ws = MSBuildWorkspace.Create();
var solution =
await ws.OpenSolutionAsync(@"my_solution.sln");
Теперь можно работать с решением. Вот несколько примеров.
Анализируем синтаксические деревья:
foreach (var proj in solution.Projects)
{
foreach (var doc in proj.Documents)
{
var syntree = await doc.GetSyntaxTreeAsync();
var semanticModel = await doc.GetSemanticModelAsync();
// Анализируем дерево
// Можно использовать CSharpSyntaxWalker для обхода
}
}
Получаем все ссылки на символ:
var comp =
await solution.Projects.First().GetCompilationAsync();
var symbol =
comp.GetSpecialType(SpecialType.System_String);
var refs =
await SymbolFinder.FindReferencesAsync(symbol, solution);
Переименовываем символ
var symbol = comp
.GetSymbolsWithName(s => s == "MyMethod")
.Single();
var newSolution = await Renamer
.RenameSymbolAsync(
solution,
symbol,
new SymbolRenameOptions()
{
RenameOverloads = true
},
"MyMethod2");
ws.TryApplyChanges(newSolution);
Обновляем документ с помощью DocumentEditor
foreach (var proj in solution.Projects)
{
foreach (var doc in proj.Documents)
{
var editor =
await DocumentEditor.CreateAsync(doc);
// Изменяем
foreach(var emptyStatement in
editor
.OriginalRoot
.DescendantNodes()
.OfType<EmptyStatementSyntax>())
{
editor.RemoveNode(emptyStatement);
}
// Применяем изменения
var newDoc = editor.GetChangedDocument();
if (!ws.TryApplyChanges(newDoc.Project.Solution))
{
Console.WriteLine("Failed!");
}
}
}
Обновляем документ с помощью CSharpSyntaxRewriter:
foreach (var proj in solution.Projects)
{
foreach (var doc in proj.Documents)
{
// Изменяем
var root = await doc.GetSyntaxRootAsync();
if(root is null)
continue;
var newRoot =
new CustomRewriter().Visit(root);
var newDoc =
doc.WithSyntaxRoot(newRoot);
// Применяем изменения
if (!ws.TryApplyChanges(newDoc.Project.Solution))
{
Console.WriteLine("Failed!");
}
}
}
internal sealed class CustomRewriter :
CSharpSyntaxRewriter
{
public override SyntaxNode?
VisitIfStatement(IfStatementSyntax node)
=> node.WithLeadingTrivia(
SyntaxFactory
.ParseLeadingTrivia("/* comment */"));
}
Выберите любое «подопытное» решение, введите его путь вместо
my_solution.sln
, вставьте любой из примеров и можете пройти его в отладчике пошагово, чтобы посмотреть, как работает анализатор.Источник: https://www.meziantou.net/using-roslyn-to-analyze-and-rewrite-code-in-a-solution.htm
👍19
День 2188. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 40. Неформальные подходы, используемые небольшими сплоченными командами, плохо масштабируются
Гейтс и Аллен, Джобс и Возняк, Хьюлетт и Паккард. Скорее всего, ни у кого из них не было письменных инструкций для их ранних проектов. Двум гениям, работающим бок о бок, не нужна документация. Но это трудно масштабировать во времени и пространстве, когда этих разумов сотни и при этом они думают на разных языках и погружены в разные культуры. Большие задачи требуют соответствующих подходов.
Процессы и инструменты
По мере роста команд, проектов и организаций возникает потребность в совершенствовании процессов. Люди могут осознать необходимость в этом, только столкнувшись с проблемой. Может случиться, что две команды выполнят одну и ту же работу или какая-то задача будет пропущена, поскольку все думали, что её сделает кто-то другой. Эти проблемы требуют более чёткого планирования, координации и коммуникации между членами команды и группами. По мере вовлечения в работу все большего количества людей, особенно если они находятся в разных местах, появляются все новые источники разногласия и задержек.
Более крупные проекты требуют письменного оформления большего объёма информации, чтобы другие участники знали, что происходит и что ждёт впереди. Сохранение требований, решений, бизнес-правил, оценок и метрик в групповом хранилище начинает приносить всё большую пользу. Чем дальше друг от друга члены команды, тем больше внимания нужно уделять организации процесса и тем больше люди вынуждены полагаться на инструменты удалённой совместной работы.
Командам, расположенным в разных местах, нужны инструменты управления задачами, моделирования, тестирования, непрерывной интеграции и особенно управления кодом. ПО с открытым кодом — яркий пример распределённой разработки. Как отмечает Эндрю Леонард: «Ни одно нововведение не было столь же важным для разработки ПО распределенными командами, как появление систем управления версиями.»
Необходимость специализации
Работая над проектом в одиночку, вы поочередно выполняете все роли участников проекта. В каждый конкретный момент вы можете действовать как бизнес-аналитик, дизайнер, программист, тестировщик, составитель документации, руководитель проекта или специалист по сопровождению.
Нереально ожидать, что каждый член команды будет в полной мере владеть всеми этими ролями. По мере роста проектов и команд специализация некоторых навыков становится естественной и полезной. В какой-то момент даже Билл Гейтс и Пол Аллен решили, что им нужно нанять людей, обладающих навыками, отличными от программирования, чтобы обеспечить рост своей молодой компании: технического писателя, математика, руководителя проекта и т.д. Я слышал, у них это сработало.
Коммуникационные конфликты
По мере увеличения группы количество коммуникационных каналов растёт экспоненциально. Участникам проекта нужны механизмы, позволяющие быстро и точно обмениваться информацией. При этом люди инстинктивно выбирают способы общения, наиболее удобные для них, но не удобные для другой стороны. В проектах с участием нескольких команд важно заранее заложить основу для общения, используя те способы, которые будут эффективно работать для всех. Кроме того, команды могут по-разному принимать решения. Участникам следует обсудить, как будут приниматься совместные решения до того, как все столкнутся с первой серьезной проблемой.
Успешные организации растут и берутся за всё более сложные задачи. Не стоит ожидать, что методы, эффективные для нескольких человек в гараже, подойдут и для больших распределённых команд. Они могут избежать некоторых трудностей, заранее предусмотрев процессы и инструменты, необходимые для интеграции различных команд. Если участники будут иметь возможность общаться и понимать коллег, работающих удалённо, на ранних этапах проекта, это поможет избежать культурных конфликтов. Потратив время на то, чтобы заложить эти основы, можно предотвратить много неприятностей в будущем.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
Уроки 50 Лет Разработки ПО
Урок 40. Неформальные подходы, используемые небольшими сплоченными командами, плохо масштабируются
Гейтс и Аллен, Джобс и Возняк, Хьюлетт и Паккард. Скорее всего, ни у кого из них не было письменных инструкций для их ранних проектов. Двум гениям, работающим бок о бок, не нужна документация. Но это трудно масштабировать во времени и пространстве, когда этих разумов сотни и при этом они думают на разных языках и погружены в разные культуры. Большие задачи требуют соответствующих подходов.
Процессы и инструменты
По мере роста команд, проектов и организаций возникает потребность в совершенствовании процессов. Люди могут осознать необходимость в этом, только столкнувшись с проблемой. Может случиться, что две команды выполнят одну и ту же работу или какая-то задача будет пропущена, поскольку все думали, что её сделает кто-то другой. Эти проблемы требуют более чёткого планирования, координации и коммуникации между членами команды и группами. По мере вовлечения в работу все большего количества людей, особенно если они находятся в разных местах, появляются все новые источники разногласия и задержек.
Более крупные проекты требуют письменного оформления большего объёма информации, чтобы другие участники знали, что происходит и что ждёт впереди. Сохранение требований, решений, бизнес-правил, оценок и метрик в групповом хранилище начинает приносить всё большую пользу. Чем дальше друг от друга члены команды, тем больше внимания нужно уделять организации процесса и тем больше люди вынуждены полагаться на инструменты удалённой совместной работы.
Командам, расположенным в разных местах, нужны инструменты управления задачами, моделирования, тестирования, непрерывной интеграции и особенно управления кодом. ПО с открытым кодом — яркий пример распределённой разработки. Как отмечает Эндрю Леонард: «Ни одно нововведение не было столь же важным для разработки ПО распределенными командами, как появление систем управления версиями.»
Необходимость специализации
Работая над проектом в одиночку, вы поочередно выполняете все роли участников проекта. В каждый конкретный момент вы можете действовать как бизнес-аналитик, дизайнер, программист, тестировщик, составитель документации, руководитель проекта или специалист по сопровождению.
Нереально ожидать, что каждый член команды будет в полной мере владеть всеми этими ролями. По мере роста проектов и команд специализация некоторых навыков становится естественной и полезной. В какой-то момент даже Билл Гейтс и Пол Аллен решили, что им нужно нанять людей, обладающих навыками, отличными от программирования, чтобы обеспечить рост своей молодой компании: технического писателя, математика, руководителя проекта и т.д. Я слышал, у них это сработало.
Коммуникационные конфликты
По мере увеличения группы количество коммуникационных каналов растёт экспоненциально. Участникам проекта нужны механизмы, позволяющие быстро и точно обмениваться информацией. При этом люди инстинктивно выбирают способы общения, наиболее удобные для них, но не удобные для другой стороны. В проектах с участием нескольких команд важно заранее заложить основу для общения, используя те способы, которые будут эффективно работать для всех. Кроме того, команды могут по-разному принимать решения. Участникам следует обсудить, как будут приниматься совместные решения до того, как все столкнутся с первой серьезной проблемой.
Успешные организации растут и берутся за всё более сложные задачи. Не стоит ожидать, что методы, эффективные для нескольких человек в гараже, подойдут и для больших распределённых команд. Они могут избежать некоторых трудностей, заранее предусмотрев процессы и инструменты, необходимые для интеграции различных команд. Если участники будут иметь возможность общаться и понимать коллег, работающих удалённо, на ранних этапах проекта, это поможет избежать культурных конфликтов. Потратив время на то, чтобы заложить эти основы, можно предотвратить много неприятностей в будущем.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
👍5👎3
День 2189. #Безопасность
CORS. Использование Ресурсов Между Разными Источниками. Начало
Рассмотрим, что было бы, если бы можно было использовать JavaScript для вызова конечной точки из другого источника.
См. определение источника тут.
Ниже показан простой веб-API https://localhost:3000 с конечными точками Get() и Post():
Get() возвращает случайное число между 10 и 99, а Post() ничего не делает.
В другом проекте, в другом источнике https://localhost:5000, для вызова этого API страница Razor использует JavaScript:
Код JavaScript использует метод fetch() для вызова API на другом сервере, а затем выводит результаты. Однако выполнение кода приводит тому, что случайное число не отображается, а на вкладке Сеть в инструментах разработчика браузера вызов API выделен красным цветом.
Запрос был отправлен, но JS не получил никаких данных. Причина: правило ограничения домена (CORS). Если бы этот запрос работал, злоумышленник мог бы использовать JS для отправки HTTP-запроса на страницу, чтобы, например, добавить товар в корзину – автоматически с использованием файла cookie идентификатора сессии пользователя (см. также Безопасность Cookie). В рамках анализа ответа злоумышленник мог бы извлечь antiforgery-токен из формы и, следовательно, обойти защиту от межсайтовой подделки запросов.
И хотя данный вид атаки ещё не был изобретен, когда появилось правило ограничения домена, поскольку JS не может получить доступ к HTTP-ответу (спасибо правилу ограничения домена), атака не сработает.
Продолжение следует…
Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 4.
CORS. Использование Ресурсов Между Разными Источниками. Начало
Рассмотрим, что было бы, если бы можно было использовать JavaScript для вызова конечной точки из другого источника.
См. определение источника тут.
Ниже показан простой веб-API https://localhost:3000 с конечными точками Get() и Post():
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers;
[Route("api/[controller]")]
[ApiController]
public class CorsController : ControllerBase
{
// GET: api/Cors
[HttpGet]
public int Get()
{
return new Random().Next(10, 100);
}
// POST api/Cors
[HttpPost]
public void Post([FromBody] int value)
{
}
}
Get() возвращает случайное число между 10 и 99, а Post() ничего не делает.
В другом проекте, в другом источнике https://localhost:5000, для вызова этого API страница Razor использует JavaScript:
@page
<div class="text-center">
<h1 class="display-4">CORS</h1>
<div id="output"></div>
</div>
@section Scripts {
<script>
fetch("https://localhost:3000/api/Cors")
.then(response => response.json())
.then(data => {
document
.getElementById("output")
.textContent = data;
});
</script>
}
Код JavaScript использует метод fetch() для вызова API на другом сервере, а затем выводит результаты. Однако выполнение кода приводит тому, что случайное число не отображается, а на вкладке Сеть в инструментах разработчика браузера вызов API выделен красным цветом.
Запрос был отправлен, но JS не получил никаких данных. Причина: правило ограничения домена (CORS). Если бы этот запрос работал, злоумышленник мог бы использовать JS для отправки HTTP-запроса на страницу, чтобы, например, добавить товар в корзину – автоматически с использованием файла cookie идентификатора сессии пользователя (см. также Безопасность Cookie). В рамках анализа ответа злоумышленник мог бы извлечь antiforgery-токен из формы и, следовательно, обойти защиту от межсайтовой подделки запросов.
И хотя данный вид атаки ещё не был изобретен, когда появилось правило ограничения домена, поскольку JS не может получить доступ к HTTP-ответу (спасибо правилу ограничения домена), атака не сработает.
Продолжение следует…
Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 4.
👍16
День 2190. #Безопасность
CORS. Использование Ресурсов Между Разными Источниками. Продолжение
Начало
Но что, если у JavaScript кода приложения есть законный интерес к вызову API? Если внимательно посмотреть на HTTP-запрос, который был сгенерирован, когда мы попытались вызвать API из JavaScript, мы заметим кое-что любопытное. Заголовок Origin не отправляется с каждым запросом, но браузер автоматически добавляет его при кросс-доменном запросе:
Заголовок содержит источник – протокол, домен, порт – вызывающей страницы. Тогда сервер может взять эту информацию и решить, может ли код JavaScript иметь доступ к данным, поступающим с сервера. Если да, то HTTP-ответ должен включать заголовок Access-Control-Allow-Origin и в качестве значения для него должен использовать отправленный источник (или заполнитель *, но, как всегда, лучше быть как можно более явным):
Этот механизм называется совместное использование ресурсов между источниками (CORS), и ASP.NET Core поддерживает его – нет необходимости реализовывать его вручную. В диспетчере пакетов NuGet по запросу «CORS» выдаётся длинный список результатов. Но все они предназначены для .NET Standard и .NET Framework. ASP.NET Core автоматически использует собственную версию пакета Microsoft.AspNetCore.Cors. CORS поставляется как промежуточное ПО в ASP.NET Core, поэтому нужно сделать его доступным и активировать. В классе Program требуется:
- добавить поддержку CORS (и настроить её), с помощью AddCors();
- активировать CORS - UseCors().
При вызове AddCors() можно указать параметры. Обычно нужно настроить хотя бы одну политику CORS (т.е. определить разрешённые источники):
Важно:
- Используйте источник клиента API, а не URL самого API!
- Источник должен состоять только из протокола, домена и порта, без слеша в конце.
Можно использовать произвольное количество политик, и у каждой может быть любое количество источников. Переменная bldr (типа CorsPolicyBuilder) также предоставляет методы, чтобы явно разрешить другие фрагменты информации для кросс-доменного запроса с использованием JS:
- WithExposedHeaders() – список заголовков HTTP-ответа, которые возвращаются и становятся доступными для JS;
- WithHeaders() – список разрешённых дополнительных заголовков HTTP-запросов, к которым клиент хотел бы получить доступ;
- WithMethods() – список разрешённых дополнительных HTTP-методов.
- AllowAnyHeader() – разрешать все заголовки;
- AllowAnyMethod() – разрешать все методы.
По умолчанию никакие учётные данные, например заголовки Authorization, не отправляются вместе с кросс-доменным запросом. Опять же, причина
тому – защита от межсайтовой подделки запросов. Если вы хотите, чтобы эта информация была доступна для API, метод AllowCredentials() сообщает клиенту, что её можно отправлять, а DisallowCredentials() - явно запрещает.
Наконец, можно использовать политику по умолчанию:
Окончание следует…
Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 4.
CORS. Использование Ресурсов Между Разными Источниками. Продолжение
Начало
Но что, если у JavaScript кода приложения есть законный интерес к вызову API? Если внимательно посмотреть на HTTP-запрос, который был сгенерирован, когда мы попытались вызвать API из JavaScript, мы заметим кое-что любопытное. Заголовок Origin не отправляется с каждым запросом, но браузер автоматически добавляет его при кросс-доменном запросе:
GET /api/Cors HTTP/2
Host: localhost:3000
…
Origin: https://localhost:5000
…
Заголовок содержит источник – протокол, домен, порт – вызывающей страницы. Тогда сервер может взять эту информацию и решить, может ли код JavaScript иметь доступ к данным, поступающим с сервера. Если да, то HTTP-ответ должен включать заголовок Access-Control-Allow-Origin и в качестве значения для него должен использовать отправленный источник (или заполнитель *, но, как всегда, лучше быть как можно более явным):
Access-Control-Allow-Origin: https://localhost:5000
Этот механизм называется совместное использование ресурсов между источниками (CORS), и ASP.NET Core поддерживает его – нет необходимости реализовывать его вручную. В диспетчере пакетов NuGet по запросу «CORS» выдаётся длинный список результатов. Но все они предназначены для .NET Standard и .NET Framework. ASP.NET Core автоматически использует собственную версию пакета Microsoft.AspNetCore.Cors. CORS поставляется как промежуточное ПО в ASP.NET Core, поэтому нужно сделать его доступным и активировать. В классе Program требуется:
- добавить поддержку CORS (и настроить её), с помощью AddCors();
- активировать CORS - UseCors().
При вызове AddCors() можно указать параметры. Обычно нужно настроить хотя бы одну политику CORS (т.е. определить разрешённые источники):
builder.Services.AddCors(opts =>
{
opts.AddPolicy("CORS API Endpoint",
bldr =>
{
bldr.WithOrigins("https://localhost:5000");
});
});
Важно:
- Используйте источник клиента API, а не URL самого API!
- Источник должен состоять только из протокола, домена и порта, без слеша в конце.
Можно использовать произвольное количество политик, и у каждой может быть любое количество источников. Переменная bldr (типа CorsPolicyBuilder) также предоставляет методы, чтобы явно разрешить другие фрагменты информации для кросс-доменного запроса с использованием JS:
- WithExposedHeaders() – список заголовков HTTP-ответа, которые возвращаются и становятся доступными для JS;
- WithHeaders() – список разрешённых дополнительных заголовков HTTP-запросов, к которым клиент хотел бы получить доступ;
- WithMethods() – список разрешённых дополнительных HTTP-методов.
- AllowAnyHeader() – разрешать все заголовки;
- AllowAnyMethod() – разрешать все методы.
По умолчанию никакие учётные данные, например заголовки Authorization, не отправляются вместе с кросс-доменным запросом. Опять же, причина
тому – защита от межсайтовой подделки запросов. Если вы хотите, чтобы эта информация была доступна для API, метод AllowCredentials() сообщает клиенту, что её можно отправлять, а DisallowCredentials() - явно запрещает.
Наконец, можно использовать политику по умолчанию:
options.AddDefaultPolicy(
bldr =>
{
bldr.WithOrigins("https://localhost:5000");
});
Окончание следует…
Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 4.
👍16