Проверяем, существует ли документ в коллекции MongoDB
Всем привет! Сегодня взглянем на интересные детали работы с MongoDB.
Итак, задача: написать метод, который проверяет, существует ли документ в БД по фильтру.
Вроде всё просто, однако у Mongo нет операции Exist на уровне документов и коллекций. А это значит, что мы можем выполнить задачу двумя способами:
1. Сделать запрос
2. Сделать запрос
Если рассуждать логически, не вникая в детали монги, то вызов
Собственно, в проекте мы думали также, поэтому изначально для проверки существования документа в коллекции использовали
И тут уже возникает вопрос:
Я решил провести небольшой бенчмарк с локальной монгой для того, чтобы проверить разницу этих методов. Код бенчмарка тут, в Readme есть описание происходящего, а выводы сделаны следующие:
- Разница минимальна - наносекунды для фильтров по идентификатору и милисекунды для фильтров без индексов
- В случае поиска по индексу (по
- В случае поиска без индекса - быстрее будет
Flexible Coding
Всем привет! Сегодня взглянем на интересные детали работы с MongoDB.
MongoDB - это документная база данных, которая позволяет хранить неструктурированные данные в json-like формате под названием bson.
Итак, задача: написать метод, который проверяет, существует ли документ в БД по фильтру.
Вроде всё просто, однако у Mongo нет операции Exist на уровне документов и коллекций. А это значит, что мы можем выполнить задачу двумя способами:
1. Сделать запрос
find
с фильтром и параметром limit=1
- чтобы получить первый документ по фильтру. Если он не null - значит такой документ есть.2. Сделать запрос
countDocuments
по фильтру и получить количество документов. Если их больше нуля - значит документ существуетЕсли рассуждать логически, не вникая в детали монги, то вызов
countDocuments
кажется наиболее быстрой операцией - ведь нам по сети надо гонять только число (4 или 8 байт), а не целый bson-документ, у которого есть как минимум идентификатор. Да и можно предположить, что у метода countDocuments
есть ещё какие-то оптимизации...Собственно, в проекте мы думали также, поэтому изначально для проверки существования документа в коллекции использовали
countDocuments
. Однако выяснилось, что эта операция внутри монги раскрывается в агрегацию следующего формата:
db.collection.aggregate(
[
{ $match: <query> },
{ $group: { _id: null, n: { $sum: 1 }}}
])
И тут уже возникает вопрос:
А точно ли это быстрее, чем find с лимитом и проекцией?
Я решил провести небольшой бенчмарк с локальной монгой для того, чтобы проверить разницу этих методов. Код бенчмарка тут, в Readme есть описание происходящего, а выводы сделаны следующие:
- Разница минимальна - наносекунды для фильтров по идентификатору и милисекунды для фильтров без индексов
- В случае поиска по индексу (по
_id
) - быстрее будет find
с проекцией- В случае поиска без индекса - быстрее будет
countDocuments
Flexible Coding
👍8🔥2
Всем привет!
Начал писать цикл статей про многопоточность на разных уровнях абстракции. И представляю вам первую статью из этой серии - про процессор!
Начал писать цикл статей про многопоточность на разных уровнях абстракции. И представляю вам первую статью из этой серии - про процессор!
вАЙТИ
Многопоточность. Снизу вверх. Процессор
DIY-медиа для ИТ-специалистов. Практические истории про решение самых разных задач из ИТ и смежных областей.
🔥13
Интеграционное тестирование MongoDB. Точки отказа
Всем привет! Сегодня рассмотрим тему настроек MongoDB для интгерационного тестирования и узнаем, что такое FailPoint и как он может помочь проверить нашу логику в нестандартных ситуациях.
Часто нам приходится писать интеграционные тесты. Интеграционные тесты — это тесты, которые проверяют взаимодействие нашего кода с внешними системами (БД, внешние API и т. д.) в как можно более приближённых к реальности условиях.
Зачем нужны такие тесты? Ну, например, чтобы убедиться, что наша логика корректно обрабатывает ситуации, когда база данных возвращает ошибку создания индекса или отказывает в записи. Юнит-тесты здесь уже не справятся, ведь они не покрывают фактическое взаимодействие с “живой” MongoDB.
Test Commands в MongoDB
MongoDB поддерживает набор специальных команд для тестирования (testCommands), которые обычно отключены в продакшене. Среди них есть конфигурация FailPoint — «точка отказа», позволяющая искусственно вызывать сбои и ошибки в различных операциях.
Чтобы включить testCommands, достаточно при запуске MongoDB задать параметр enableTestCommands=1. Вот пример docker-compose для этой задачи:
Для запуска команд нужно выбрать базу данных (для
Определение
1.
2.
3.
Пример использования для команды
А когда тесты будут завершены, точку отказа можно отключить:
В следующем посте мы рассмотрим пример интеграционного теста, который использует данную функциональность, а пока что можете погрузиться в вики-страничку про данный механизм.
Всем спасибо, с вами был Flexible Coding!
Всем привет! Сегодня рассмотрим тему настроек MongoDB для интгерационного тестирования и узнаем, что такое FailPoint и как он может помочь проверить нашу логику в нестандартных ситуациях.
Часто нам приходится писать интеграционные тесты. Интеграционные тесты — это тесты, которые проверяют взаимодействие нашего кода с внешними системами (БД, внешние API и т. д.) в как можно более приближённых к реальности условиях.
Зачем нужны такие тесты? Ну, например, чтобы убедиться, что наша логика корректно обрабатывает ситуации, когда база данных возвращает ошибку создания индекса или отказывает в записи. Юнит-тесты здесь уже не справятся, ведь они не покрывают фактическое взаимодействие с “живой” MongoDB.
Test Commands в MongoDB
MongoDB поддерживает набор специальных команд для тестирования (testCommands), которые обычно отключены в продакшене. Среди них есть конфигурация FailPoint — «точка отказа», позволяющая искусственно вызывать сбои и ошибки в различных операциях.
Чтобы включить testCommands, достаточно при запуске MongoDB задать параметр enableTestCommands=1. Вот пример docker-compose для этой задачи:
services:
mongo:
image: mongo:6.0
command: mongod --setParameter enableTestCommands=1
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
Для запуска команд нужно выбрать базу данных (для
ConfigureFailPoint
это база данных admin) и вызвать метод db.runCommand({})
.Определение
ConfigureFailPoint
состоит из следующих полей:1.
configureFailPoint
- название точки отказа, которую мы настраиваем. Чаще всего встречается значение failCommand
для настройки отказа конкретной команды2.
mode
: определяет режим срабатывания точки отказа: alwaysOn
, off
, {times: n}
и другие3.
data
- является вложенным объектом, в котором указываются детали и условия сбояПример использования для команды
createIndexes
:
use admin;
db.runCommand({
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["createIndexes"],
errorCode: 100,
closeConnection: false
}
});
А когда тесты будут завершены, точку отказа можно отключить:
use admin;
db.runCommand({
configureFailPoint: "failCommand",
mode: "off"
});
В следующем посте мы рассмотрим пример интеграционного теста, который использует данную функциональность, а пока что можете погрузиться в вики-страничку про данный механизм.
Всем спасибо, с вами был Flexible Coding!
🔥4👍2❤1🤔1
Flexible Coding
Всем привет! Начал писать цикл статей про многопоточность на разных уровнях абстракции. И представляю вам первую статью из этой серии - про процессор!
Тем временем готова следующая статья из цикла про многопоточность - сегодня залезем на уровень операционной системы
вАЙТИ
Многопоточность. Снизу вверх. ОС
DIY-медиа для ИТ-специалистов. Практические истории про решение самых разных задач из ИТ и смежных областей.
🔥7👀2❤1
Интеграционное тестирование MongoDB. Точки отказа. .NET
Всем привет! Продолжаем тему точек отказа у MongoDb. С основами разобрались, а теперь приступим к написанию тестов на .NET.
Тесты разделяются на три этапа: Given (Arrange), When (Act) и Then (Assert). Так же в рамках теста может происходит подготовка окружения -
В рамках конкретного теста точку отказа удобнее всего настраивать на этапе Setup. В NUnit это будет выглядеть следующим образом:
Далее - сама логика теста:
А затем возвращаем MongoDB в исходное состояние:
Таким образом можно настраивать необходимое поведение БД в рамках теста.
Flexible Coding
Всем привет! Продолжаем тему точек отказа у MongoDb. С основами разобрались, а теперь приступим к написанию тестов на .NET.
Тесты разделяются на три этапа: Given (Arrange), When (Act) и Then (Assert). Так же в рамках теста может происходит подготовка окружения -
Setup
и очистка - TearDown
.В рамках конкретного теста точку отказа удобнее всего настраивать на этапе Setup. В NUnit это будет выглядеть следующим образом:
[SetUp]
public void Setup()
{
// Подключаемся к локальной монге, где включены testCommands
var client = new MongoClient("mongodb://root:password@localhost:27017");
_database = client.GetDatabase("testDb");
_collection = _database.GetCollection<BsonDocument>("testCollection");
_adminDatabase = client.GetDatabase("admin");
// Включаем FailPoint для команды createIndexes
var enableFailPoint = new BsonDocument
{
{ "configureFailPoint", "failCommand" },
{ "mode", new BsonDocument("times", 1) },
{
"data", new BsonDocument
{
{ "failCommands", new BsonArray { "createIndexes" } },
{ "errorCode", 100 }, // код ошибки (для проверки)
{ "closeConnection", false } // соединение не рвём
}
}
};
_adminDatabase.RunCommand<BsonDocument>(enableFailPoint);
}
Далее - сама логика теста:
[Test]
public void CreateIndexes_ShouldThrowException_WhenFailPointEnabled()
{
var ex = Assert.Throws<MongoCommandException>(() =>
{
_collection.Indexes.CreateOne(
new CreateIndexModel<BsonDocument>(
Builders<BsonDocument>.IndexKeys.Ascending("someField")));
});
Assert.That(ex.Code, Is.EqualTo(100));
}
А затем возвращаем MongoDB в исходное состояние:
[TearDown]
public void TearDown()
{
// Выключаем FailPoint, чтобы вернуть MongoDb в исходное состояние
var disableFailPoint = new BsonDocument
{
{ "configureFailPoint", "failCommand" },
{ "mode", "off" }
};
_adminDatabase.RunCommand<BsonDocument>(disableFailPoint);
}
Таким образом можно настраивать необходимое поведение БД в рамках теста.
Flexible Coding
🔥3✍2
💵 Open-Source становится платным (опять)
Всем привет! Сегодня поговорим о том, как open-source проекты собираются переходить на коммерческие модели. В прошлый раз была библиотека FluentAssertions, а на этот раз речь идёт о MassTransit, MediatR и AutoMapper.
🔗 Ссылки на анонсы:
- MassTransit
- MediatR и AutoMapper
К медиатору и автомапперу у меня довольно предвзятое отношение, а за MassTransit немного печально. Это действительно мощная библиотека для работы с сообщениями, и переход на коммерческую модель заставляет задуматься о будущем её использования.
🤔 Какие есть альтернативы MassTransit?
Из того, с чем работал я, могу предложить следующие варианты:
- EasyNetQ для RabbitMQ
- KafkaFlow для Apache Kafka
Flexible Coding
Всем привет! Сегодня поговорим о том, как open-source проекты собираются переходить на коммерческие модели. В прошлый раз была библиотека FluentAssertions, а на этот раз речь идёт о MassTransit, MediatR и AutoMapper.
🔗 Ссылки на анонсы:
- MassTransit
- MediatR и AutoMapper
К медиатору и автомапперу у меня довольно предвзятое отношение, а за MassTransit немного печально. Это действительно мощная библиотека для работы с сообщениями, и переход на коммерческую модель заставляет задуматься о будущем её использования.
Надеюсь, в старых версиях MassTransit не найдут какую-нибудь страшную уязвимость, которую пофиксят только в платной версии
🤔 Какие есть альтернативы MassTransit?
Из того, с чем работал я, могу предложить следующие варианты:
- EasyNetQ для RabbitMQ
- KafkaFlow для Apache Kafka
Flexible Coding
🤬5❤1👍1
Flexible Coding
Тем временем готова следующая статья из цикла про многопоточность - сегодня залезем на уровень операционной системы
Слегка прошёлся по Thread в дотнете в новой статье из цикла про многопоточность. Приятного чтения!
Flexible Coding
Flexible Coding
вАЙТИ
Многопоточность. Снизу вверх. Потоки в языке C#
DIY-медиа для ИТ-специалистов. Практические истории про решение самых разных задач из ИТ и смежных областей.
🔥7👍3👀2❤1
🤖 Заметки ИИ-юзера. Qwen-coder, continue и VS Code
Всем привет! С недавних пор я начал пользоваться плагином Continue, который предоставляет некоторые ИИ-возможности для вашей IDE. Среди них:
- Чат с возможностью положить в контекст файлы, папки и т.д.
- Tab-автокомплит (как в GitHub Copilot)
- Автоматическое редактирование файла на основе промпта
- Создание и использование своих провайдеров контекста (например на основе браузера или БД) - пока не пробовал, но знаю что есть
Начал я с чего-то попроще: для чата настроил модель GPT-4o, а для автокомплита поднял локальную модель qwen-coder. Подключил это дело в файлах конфигурации и пошёл тестить - сразу на большом проекте.
Вот мои промежуточные выводы.
😡 Сначала плохое
- Во-первых, КАК ЖЕ QWEN-CODER ЛЮБИТ ФИГУРНЫЕ СКОБКИ!!! Я писал некоторе большое switch-выражение, и он постоянно добавлял мне эти скобки, игнорируя их наличие ниже. По итогу я выключил автокомплит, пока писал этот свич, потому что это невозможно
- Во-вторых - qwen как будто бы ничего не знает про ValueTask, и даже когда метод в сигнатуре содержит его, локальная модель всё равно предлагает использовать Task.CompletedTask или другие методы класса Task.
🥹А теперь хорошее
Это прекрасный генератор json! Когда мне надо было подготовить тестовые переменные для сериализации, я просто открыл нужный класс-dto, написал
И автокомплит сам мне предложил корректный json на базе класса. Тема классная, пользуйтесь)
А модель ChatGPT в чате и в задачах авторедактирования файла действительно неплоха - главное добавить в промпт пример, так как эти модели лучше понимают задачи с примерами и аналогиями.
❓ Что дальше?
- Я хочу попробовать Codestral от Mistral - судя по документации Continue это лучшее решение для автокомплита
- Тестирование IDE Cursor - это вызывает у меня скептицизм и сомнения относительно большого проекта на миллион строк, но попробовать можно
- Возможно, использование GitHub Copilot и Jetbrains AI Assistant
Flexible Coding
TLDR: Он поднял локальную модель, которая хуже облачных и теперь ругает её. А плагин норм.
Всем привет! С недавних пор я начал пользоваться плагином Continue, который предоставляет некоторые ИИ-возможности для вашей IDE. Среди них:
- Чат с возможностью положить в контекст файлы, папки и т.д.
- Tab-автокомплит (как в GitHub Copilot)
- Автоматическое редактирование файла на основе промпта
- Создание и использование своих провайдеров контекста (например на основе браузера или БД) - пока не пробовал, но знаю что есть
Начал я с чего-то попроще: для чата настроил модель GPT-4o, а для автокомплита поднял локальную модель qwen-coder. Подключил это дело в файлах конфигурации и пошёл тестить - сразу на большом проекте.
Вот мои промежуточные выводы.
😡 Сначала плохое
- Во-первых, КАК ЖЕ QWEN-CODER ЛЮБИТ ФИГУРНЫЕ СКОБКИ!!! Я писал некоторе большое switch-выражение, и он постоянно добавлял мне эти скобки, игнорируя их наличие ниже. По итогу я выключил автокомплит, пока писал этот свич, потому что это невозможно
}}}}}}}
- Во-вторых - qwen как будто бы ничего не знает про ValueTask, и даже когда метод в сигнатуре содержит его, локальная модель всё равно предлагает использовать Task.CompletedTask или другие методы класса Task.
🥹А теперь хорошее
Это прекрасный генератор json! Когда мне надо было подготовить тестовые переменные для сериализации, я просто открыл нужный класс-dto, написал
var json = """
"""
И автокомплит сам мне предложил корректный json на базе класса. Тема классная, пользуйтесь)
А модель ChatGPT в чате и в задачах авторедактирования файла действительно неплоха - главное добавить в промпт пример, так как эти модели лучше понимают задачи с примерами и аналогиями.
Внедрение ИИ в повседневную работу с кодом - это отличный повод вкачать промпт-инженирнг - чтобы не оказаться в ситуации, когда тестирование промптов в поисках подходящего становится дольше, чем написание кода самостоятельно.
❓ Что дальше?
- Я хочу попробовать Codestral от Mistral - судя по документации Continue это лучшее решение для автокомплита
- Тестирование IDE Cursor - это вызывает у меня скептицизм и сомнения относительно большого проекта на миллион строк, но попробовать можно
- Возможно, использование GitHub Copilot и Jetbrains AI Assistant
Flexible Coding
🔥6👍1
🎨Опять рисуем схемы
Всем привет! Давно не было обзоров приложений, исправляюсь. Встречайте - Excalidraw!
Предыстория
Я люблю рисовать схемки - майнд-мапы, UML-диаграммы, просто какие-то схемы процессов или описание моих размышлений. И помимо ручки с бумагой я хочу использовать какое-то приложение.
Всё началось с Miro, и это действительно монстр из мира вайтбордов. Монстр, который решил покинуть РФ, а бесплатной версии ой как не хватает.
После Miro я начал использовать Whimsical, о котором писал тут и даже частично внедрил его использование в компанию. Изначально там была удобная модель лицензирования - не по количеству досок, а по количеству элементов на каждой доске, но она изменилась, и бесплатная версия перестала меня удовлетворять.
Время шло, я исследовал тему ведения заметок, узнал про Obsidian, и вместе с ним про Excalidraw. И понял: это оно. То, что мне надо.
Exalidraw
У этого приложения есть открытая версия, где можно сразу рисовать схемки и даже создавать сессии коллаборации.
✅Плюсы:
- Бесплатная веб-версия. Даже не надо регистрироваться, и всё отлично работает как на планшетах, так и на пк
- Возможность коллаборации
- Библиотеки с фигурами под любой набор задач
❌Минусы:
В бесплатной версии нет автоматического сохранения, и приходится работать с импортом-экспортом файлов. Плохо ли это? Не думаю, но кого-то может раздражать.
Все схемы для статей и постов, кстати, стараюсь рисовать так же с помощью этого инструмента.
В общем, всем рекомендую. С вами был Flexible Coding.
#приложения
Всем привет! Давно не было обзоров приложений, исправляюсь. Встречайте - Excalidraw!
Предыстория
Я люблю рисовать схемки - майнд-мапы, UML-диаграммы, просто какие-то схемы процессов или описание моих размышлений. И помимо ручки с бумагой я хочу использовать какое-то приложение.
Всё началось с Miro, и это действительно монстр из мира вайтбордов. Монстр, который решил покинуть РФ, а бесплатной версии ой как не хватает.
После Miro я начал использовать Whimsical, о котором писал тут и даже частично внедрил его использование в компанию. Изначально там была удобная модель лицензирования - не по количеству досок, а по количеству элементов на каждой доске, но она изменилась, и бесплатная версия перестала меня удовлетворять.
Время шло, я исследовал тему ведения заметок, узнал про Obsidian, и вместе с ним про Excalidraw. И понял: это оно. То, что мне надо.
Exalidraw
У этого приложения есть открытая версия, где можно сразу рисовать схемки и даже создавать сессии коллаборации.
✅Плюсы:
- Бесплатная веб-версия. Даже не надо регистрироваться, и всё отлично работает как на планшетах, так и на пк
- Возможность коллаборации
- Библиотеки с фигурами под любой набор задач
Я даже нашёл библиотеку с прикольными человечками и стилизовал на её основе свою презентацию про процессы
❌Минусы:
В бесплатной версии нет автоматического сохранения, и приходится работать с импортом-экспортом файлов. Плохо ли это? Не думаю, но кого-то может раздражать.
Помимо версии с сайта, это приложение может встраиваться в другие приложения - например в тот же заметочник Obsidian. Таким образом заметки можно объединять со схемами, всё это добро будет храниться у вас на ПК - и никакой облачный сервис внезапно не скажет: "Русский? Отказано."
Все схемы для статей и постов, кстати, стараюсь рисовать так же с помощью этого инструмента.
В общем, всем рекомендую. С вами был Flexible Coding.
#приложения
Excalidraw
Excalidraw — Collaborative whiteboarding made easy
Excalidraw is a virtual collaborative whiteboard tool that lets you easily sketch diagrams that have a hand-drawn feel to them.
👍4🔥3
Flexible Coding
Слегка прошёлся по Thread в дотнете в новой статье из цикла про многопоточность. Приятного чтения! Flexible Coding
Перебираемся ещё на уровень выше в теме многопоточности - в новой статье затронем пул потоков и асинхронность
Flexible Coding
Flexible Coding
вАЙТИ
Многопоточность. Снизу вверх. Асинхронность и пул потоков
DIY-медиа для ИТ-специалистов. Практические истории про решение самых разных задач из ИТ и смежных областей.
👍4🔥2
var functions = new List<Func<int, int>>();
for (int i = 0; i < 10; i++)
{
Func<int, int> function = x => i * x;
if (!functions.Contains(function))
{
functions.Add(function);
}
}
Console.WriteLine(functions.Count);
Правильный ответ - 1. Почему так? Давайте разбираться
Сравнение делегатов
Сперва нам кажется, что тут всё просто.
Но делегат - это непростой тип в .NET. Давайте посмотрим, из каких полей он состоит.
Method
Это поле с типом данных MethodInfo, который должен быть вызван при обращении к делегату. В памяти он представлен через внутренние поля
Target
Это объект, к которому привязан метод, если он нестатический. То есть если метод — экземплярный,
У делегатов так же переопределён метод Equals. В репозитории reference source можно увидеть полную его реализацию, и нас интересует следующий фрагмент:
Приватные поля
Если мы вызовем этот метод в цикле из примера выше, то обнаружим одинаковые адреса делегата на каждой итерации цикла.
Как вы думаете, почему так?
Flexible Coding
Сравнение делегатов
Сперва нам кажется, что тут всё просто.
Func<int, int> function = x => i * x;
- это создание новой переменной. На основе документации Microsoft узнаём, что делегат - это reference type, значит они сравниваются по ссылке. А раз мы на каждой итерации цикла создаём новую переменную function
- у неё каждый раз будет новый адрес в памяти и Contains всегда вернёт false.Но делегат - это непростой тип в .NET. Давайте посмотрим, из каких полей он состоит.
Method
Это поле с типом данных MethodInfo, который должен быть вызван при обращении к делегату. В памяти он представлен через внутренние поля
_methodPtr
и _methodPtrAux
, которые являются указателями на конкретную функцию.Target
Это объект, к которому привязан метод, если он нестатический. То есть если метод — экземплярный,
Target
указывает на объект, для которого этот метод будет вызван. Если метод статический, Target
может быть null
.У делегатов так же переопределён метод Equals. В репозитории reference source можно увидеть полную его реализацию, и нас интересует следующий фрагмент:
// do an optimistic check first. This is hopefully cheap enough to be worth
if (_target == d._target && _methodPtr == d._methodPtr && _methodPtrAux == d._methodPtrAux)
return true;
Приватные поля
_target
, _methodPtr
и _methodPtrAux
могут нам указывать на то, что два делегата равны. Они как раз дают нам информацию о методе и привязке метода к объекту. Попробуем вытащить их из делегата (тут нам пригодится немного магии unsafe):
void PrintFunctionInfo(Func<int, int> function)
{
unsafe
{
TypedReference tr = __makeref(function);
IntPtr* ptr = (IntPtr*)*(IntPtr*)&tr;
Console.WriteLine($"Pointer to Delegate: 0x{(ulong)ptr:X}");
IntPtr target = ptr[1];
IntPtr methodPtr = ptr[3];
IntPtr methodPtrAux = ptr[4];
Console.WriteLine($"Target: 0x{(ulong)target:X}");
Console.WriteLine($"MethodPtr: 0x{(ulong)methodPtr:X}");
Console.WriteLine($"MethodPtrAux: 0x{(ulong)methodPtrAux:X}");
}
}
Если мы вызовем этот метод в цикле из примера выше, то обнаружим одинаковые адреса делегата на каждой итерации цикла.
Как вы думаете, почему так?
Flexible Coding
🤔7🆒1
Сравнение делегатов
Как мы узнали из предыдущего поста, создаваемые делегаты в цикле равны. Но почему так происходит, ведь
Тут в игру вступают замыкания.
Скажем проще. В этом коде:
Делегат
Вернёмся к примеру с циклом:
Так как переменная-итератор создаётся вне тела цикла, функция превращается в замыкание, которое выглядит как класс
Однако если мы добавим одну маленькую деталь - скопируем
то вывод будет уже 10, и логика приложения будет корректна.
Какие выводы можно сделать?
1. Аккуратнее со сравнением делегатов. Тут велик шанс допустить ошибку и долго пытаться понять, а что же пошло не так
2. Если вы увидели такой код в продакшене, убейте автора
А с вами был Flexible Coding!
P.S. И кстати, спасибо за комментарий к предыдущему посту, там всё написано верно!
Как мы узнали из предыдущего поста, создаваемые делегаты в цикле равны. Но почему так происходит, ведь
i
меняется с каждой итерацией?Тут в игру вступают замыкания.
Замыкание (closure) представляет объект функции, который запоминает свое лексическое окружение даже в том случае, когда она выполняется вне своей области видимости.
Скажем проще. В этом коде:
var i = 1;
Action a = () =>
{
Console.WriteLine(i);
}
Делегат
a
"знает", что он использует переменную i
из другой области видимости - это и есть "запоминание лексического окружения"Вернёмся к примеру с циклом:
var functions = new List<Func<int, int>>();
for (int i = 0; i < 10; i++)
{
Func<int, int> function = x => i * x;
if (!functions.Contains(function))
{
functions.Add(function);
}
}
Так как переменная-итератор создаётся вне тела цикла, функция превращается в замыкание, которое выглядит как класс
...DisplayClass0_0
в IL-коде. И у этого класса можно увидеть поле .field public Int32 i
- наш "захваченный" итератор. Так как объект замыкания был создан вне тела цикла и только один раз - функции считаются равными.Однако если мы добавим одну маленькую деталь - скопируем
i
в переменную в области видимости цикла
var functions = new List<Func<int, int>>();
for (int i = 0; i < 10; i++)
{
var iCopy = i;
Func<int, int> function = x => iCopy * x;
if (!functions.Contains(function))
{
functions.Add(function);
}
}
Console.WriteLine(functions.Count);
то вывод будет уже 10, и логика приложения будет корректна.
Какие выводы можно сделать?
1. Аккуратнее со сравнением делегатов. Тут велик шанс допустить ошибку и долго пытаться понять, а что же пошло не так
2. Если вы увидели такой код в продакшене, убейте автора
А с вами был Flexible Coding!
P.S. И кстати, спасибо за комментарий к предыдущему посту, там всё написано верно!
🔥5👍3
Всем привет!
Сегодня о странностях в EF Core.
Миграции в EF - это обновления схемы данных, которые можно сгенерировать или написать самостоятельно. В них используется абстракция
И вот, допустим, у нас есть необходимость написать часть миграции с помощью sql-скрипта. Пишем:
Вроде всё хорошо. Вот примерный сгенерированный скрипт:
Видите ошибку? При генерации скрипта EF Core не добавляет ; между кастомным скриптом и дальнейшим декларативным описанием. Из-за этого при прогоне миграции я получил ошибку: "syntax error near or at CREATE" и очень долго пытался найти, а какой такой
В общем, несмотря на наличие крутых IDE, линтеров и прочего, спустя много лет разработки я наткнулся на ошибку, связанную с ПРОПУЩЕННОЙ ТОЧКОЙ С ЗАПЯТОЙ!
Будьте внимательны, коллеги)
С вами был Flexible Coding
Сегодня о странностях в EF Core.
EF Core - это библиотека-ORM от Microsoft, которая позволяет взаимодействовать с сущностями в БД как с объектами
Миграции в EF - это обновления схемы данных, которые можно сгенерировать или написать самостоятельно. В них используется абстракция
MigrationBuilder
, с помощью которой можно декларативно описывать создаваемые объекты: индексы, таблицы и т.д. А с помощью метода Sql()
можно написать свой sql-скрипт, ну для крайних случаев.И вот, допустим, у нас есть необходимость написать часть миграции с помощью sql-скрипта. Пишем:
protected override void Up(MigrationBuilder migrationBuilder)
{
// some code
migrationBuilder.Sql(
@"UPDATE schema.table
SET key = id::text
WHERE key IS NULL");
migrationBuilder.CreateIndex(
name: "IX_NAME",
schema: "schema",
table: "table",
columns: new[] { "key" },
unique: true);
}
Вроде всё хорошо. Вот примерный сгенерированный скрипт:
UPDATE schema.table SET key = id::text WHERE key IS NULL CREATE UNIQUE INDEX IX_NAME ...
Видите ошибку? При генерации скрипта EF Core не добавляет ; между кастомным скриптом и дальнейшим декларативным описанием. Из-за этого при прогоне миграции я получил ошибку: "syntax error near or at CREATE" и очень долго пытался найти, а какой такой
CREATE
есть в этой миграции?В общем, несмотря на наличие крутых IDE, линтеров и прочего, спустя много лет разработки я наткнулся на ошибку, связанную с ПРОПУЩЕННОЙ ТОЧКОЙ С ЗАПЯТОЙ!
Будьте внимательны, коллеги)
С вами был Flexible Coding
😱8👍2
Всем привет! Вот и наступило лето, а у нас - итоги прошедшего сезона!
Этой весной мы:
💥 Контролируемо ломали MongoDB - первая и вторая части
😤 Расстраивались из-за Open Source, который становится всё дороже
🧠 Закончили цикл статей про многопоточность (или нет???) - 2, 3 и 4
🔀 Сравнивали делегаты
❗ Пропускали точку с запятой в SQL
🤖 А так же смотрели на ИИ и рисовали схемки в Excalidraw
Flexible Coding
Этой весной мы:
💥 Контролируемо ломали MongoDB - первая и вторая части
😤 Расстраивались из-за Open Source, который становится всё дороже
🧠 Закончили цикл статей про многопоточность (или нет???) - 2, 3 и 4
🔀 Сравнивали делегаты
❗ Пропускали точку с запятой в SQL
🤖 А так же смотрели на ИИ и рисовали схемки в Excalidraw
Flexible Coding
❤5😁1
🕵️ Open Source, которому не доверяешь
Всем привет!
На работе рисёрчил разные open source системы веб-аналитики. Это приложения, которые считают метрики, посещаемость сайта, просмотры страниц — если знаете Яндекс.Метрика или Google Analytics — оно, только надо open-source и self-hosted.
И вроде бы
🐘 PostHog - https://posthog.com/
Это большое и мощное решение. Оно требует Kafka, ClickHouse, Elastic, PostgreSQL и ещё кучу всего. В сумме — 22 контейнера
И даже варианте Self Hosted PostHog лезет в облако...
🧾 фронтенд — за информацией о фичах, а ещё отправляет метрики в облачный PostHog
📡 бэкенд — постоянно чекает биллинг
📊 Umami - https://umami.is/
Это более лёгкое и дружелюбное решение. Оно написано на Node.js и использует Prisma ORM. Разворачивается легко, вроде всё круто. Но вот беда: Prisma при выполнении миграций автоматически скачивает бинарники с внешнего ресурса - https://binaries.prisma.sh. И вот что мы получаем:
💥 В изолированной среде — падение.
🕳️ В открытой — потенциальная дыра в безопасности.
🧪 Выводы
Для успешного внедрения даже open source решения требуется:
- Аудит внешних запросов 🌐
- Замеры производительности 📉
- Проверка работы в офлайне 🔌
Open source ≠ безопасно по умолчанию.
С вами был Flexible Coding
Всем привет!
На работе рисёрчил разные open source системы веб-аналитики. Это приложения, которые считают метрики, посещаемость сайта, просмотры страниц — если знаете Яндекс.Метрика или Google Analytics — оно, только надо open-source и self-hosted.
И вроде бы
опенсорс = хорошо
, системы есть, можно тестить. И тут начинают вылезать разные нюансы.🐘 PostHog - https://posthog.com/
Это большое и мощное решение. Оно требует Kafka, ClickHouse, Elastic, PostgreSQL и ещё кучу всего. В сумме — 22 контейнера
И даже варианте Self Hosted PostHog лезет в облако...
🧾 фронтенд — за информацией о фичах, а ещё отправляет метрики в облачный PostHog
📡 бэкенд — постоянно чекает биллинг
Да, сервер (слава богу) работает без интернета, но нужно вручную вычищать обращения к облаку с клиентской части. Без этого — ощущение, что ты просто хостишь чей-то SaaS.
📊 Umami - https://umami.is/
Это более лёгкое и дружелюбное решение. Оно написано на Node.js и использует Prisma ORM. Разворачивается легко, вроде всё круто. Но вот беда: Prisma при выполнении миграций автоматически скачивает бинарники с внешнего ресурса - https://binaries.prisma.sh. И вот что мы получаем:
💥 В изолированной среде — падение.
🕳️ В открытой — потенциальная дыра в безопасности.
🧪 Выводы
Для успешного внедрения даже open source решения требуется:
- Аудит внешних запросов 🌐
- Замеры производительности 📉
- Проверка работы в офлайне 🔌
Open source ≠ безопасно по умолчанию.
С вами был Flexible Coding
👏4🔥3😢2
Я часто делаю презентации - внутренние доклады на работе, конференции или просто для себя. И постоянной проблемой были слайды с кодом.
📏 Разный масштаб и размер кода
🎨 Разные темы в IDE, если в процессе работы над презой я её менял
✂️ Непонятно как обрезать, что переносить, как показать длинные строки....
Знаю, что такие сервисы уже давно есть, но вот недавно я решил попробовать визуализатор сниппетов carbon (
В общем, я тут над одним докладом работаю, и это просто отличная находка!
А вы пользуетесь подобным сервисом? Пишите в комментарии!
Flexible Coding
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Версионирование
Всем привет!
Сегодня мы поговорим про версии и версионирование. Они повсюду:
🧪 у релизов приложений
🧱 у миграций баз данных
🔌 у API и протоколов
Но зачем вообще нужны эти версии?
Какие бывают версии?
Semantic Versioning (SemVer)
📍 Формат:
📌 MAJOR — ломает обратную совместимость
📌 MINOR — добавляет функциональность
📌 PATCH — фиксит баги
Используется повсеместно — от npm-библиотек до .NET NuGet-пакетов.
Calendar Versioning (CalVer)
📅 Формат: 2025.07.1,
🧭 Привязан к дате выпуска, а не к смыслу изменений.
Полезен, когда частота релизов важнее, чем их содержание.
👀 Пример: Ubuntu 24.04 (тут можно почитать подробнее), JetBrains 2024.1
SeqVer — Sequential Versioning
🔢 Просто увеличивающийся счётчик (v1, v2, v3)
Минимум смысла, максимум простоты.
Подходит для внутреннего использования, документации или версий данных в БД/API
Гибриды
Иногда какой-то принятой методики недостаточно - и приходится комбинировать подходы. Такие версии дают максимум контекста.
📅➕🔢 Date + Counter - 2025.07.01.1
🧠➕🔡 SemVer + Git SHA - 1.0.0+abc123
🧠➕🔁 SemVer + Revision - 1.0.0.1
Flexible Coding 2.0 (да, раньше был ещё один такой же канал)
P.S. Пост написан в telegram версии 11.13
Всем привет!
Сегодня мы поговорим про версии и версионирование. Они повсюду:
🧪 у релизов приложений
🧱 у миграций баз данных
🔌 у API и протоколов
Но зачем вообще нужны эти версии?
💡 Версия — это способ сказать: «Эта штука изменилась».
Она помогает понять, что именно изменилось, насколько это важно, и как с этим работать. Версии дают структуру хаосу и позволяют системам (и людям) быть на одной волне.
Какие бывают версии?
Semantic Versioning (SemVer)
📍 Формат:
MAJOR.MINOR.PATCH
(например, 1.4.2)📌 MAJOR — ломает обратную совместимость
📌 MINOR — добавляет функциональность
📌 PATCH — фиксит баги
Используется повсеместно — от npm-библиотек до .NET NuGet-пакетов.
Calendar Versioning (CalVer)
📅 Формат: 2025.07.1,
YY.MM
, YYYY.MM.DD
и т.д.🧭 Привязан к дате выпуска, а не к смыслу изменений.
Полезен, когда частота релизов важнее, чем их содержание.
👀 Пример: Ubuntu 24.04 (тут можно почитать подробнее), JetBrains 2024.1
SeqVer — Sequential Versioning
🔢 Просто увеличивающийся счётчик (v1, v2, v3)
Минимум смысла, максимум простоты.
Подходит для внутреннего использования, документации или версий данных в БД/API
Гибриды
Иногда какой-то принятой методики недостаточно - и приходится комбинировать подходы. Такие версии дают максимум контекста.
📅➕🔢 Date + Counter - 2025.07.01.1
🧠➕🔡 SemVer + Git SHA - 1.0.0+abc123
🧠➕🔁 SemVer + Revision - 1.0.0.1
Flexible Coding 2.0 (да, раньше был ещё один такой же канал)
P.S. Пост написан в telegram версии 11.13
👍8🔥2🤔1🤩1
🤖 Заметки ИИ-юзера. Mistral и continue
Запоздалый пост про мои эксперименты с AI. В этот раз я добрался до codestral - французской модели от компании Mistral. Плагин Continue уже подключил и в Rider, и в VS Code.
Эта модель уже облачная, и посильнее чем локальная qwen. А ещё там дают триал на целых 8 недель!
Какие выводы теперь?
Автокомплит уже лучше, не так любит скобки как qwen и делает меньше странных предложений
Плагин Continue ломает райдер и становится невозможно работать - умирает навигация по коду, помогает только откат к дефолтным настройкам
А вот чат у Mistral очень слабый - рекомендации так себе, действия в коде - тоже
В общем, для бесплатного теста работы с автокомплитом - норм, для серьёзного вайбкодинга - не подойдёт.
А теперь пришло время тестить агентов и копайлота!
Flexible Coding
Запоздалый пост про мои эксперименты с AI. В этот раз я добрался до codestral - французской модели от компании Mistral. Плагин Continue уже подключил и в Rider, и в VS Code.
Эта модель уже облачная, и посильнее чем локальная qwen. А ещё там дают триал на целых 8 недель!
Какие выводы теперь?
Автокомплит уже лучше, не так любит скобки как qwen и делает меньше странных предложений
Плагин Continue ломает райдер и становится невозможно работать - умирает навигация по коду, помогает только откат к дефолтным настройкам
А вот чат у Mistral очень слабый - рекомендации так себе, действия в коде - тоже
В общем, для бесплатного теста работы с автокомплитом - норм, для серьёзного вайбкодинга - не подойдёт.
Как запустить Codestral:
* Регистрируемся в mistral на гугл аккаунт
* Указываем номер телефона (оно даже для рф работает, но иностранный надёжнее)
* Подключаем continue
* Profit!
А теперь пришло время тестить агентов и копайлота!
Flexible Coding
mistral.ai
Codestral | Mistral AI
Empowering developers and democratising coding with Mistral AI.
👍2🔥1👏1