Flexible Coding
158 subscribers
165 photos
2 files
101 links
Download Telegram
🤖 Заметки ИИ-юзера. Qwen-coder, continue и VS Code

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
У этого приложения есть открытая версия, где можно сразу рисовать схемки и даже создавать сессии коллаборации.

Плюсы:
- Бесплатная веб-версия. Даже не надо регистрироваться, и всё отлично работает как на планшетах, так и на пк
- Возможность коллаборации
- Библиотеки с фигурами под любой набор задач

Я даже нашёл библиотеку с прикольными человечками и стилизовал на её основе свою презентацию про процессы


Минусы:
В бесплатной версии нет автоматического сохранения, и приходится работать с импортом-экспортом файлов. Плохо ли это? Не думаю, но кого-то может раздражать.

Помимо версии с сайта, это приложение может встраиваться в другие приложения - например в тот же заметочник Obsidian. Таким образом заметки можно объединять со схемами, всё это добро будет храниться у вас на ПК - и никакой облачный сервис внезапно не скажет: "Русский? Отказано."


Все схемы для статей и постов, кстати, стараюсь рисовать так же с помощью этого инструмента.

В общем, всем рекомендую. С вами был Flexible Coding.

#приложения
👍4🔥3
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. Почему так? Давайте разбираться

Сравнение делегатов

Сперва нам кажется, что тут всё просто. 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
Сравнение делегатов

Как мы узнали из предыдущего поста, создаваемые делегаты в цикле равны. Но почему так происходит, ведь 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 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
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
📡 бэкенд — постоянно чекает биллинг

Да, сервер (слава богу) работает без интернета, но нужно вручную вычищать обращения к облаку с клиентской части. Без этого — ощущение, что ты просто хостишь чей-то 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 (почему он называется так же как продукт в Positive Technologies????). Не знаю, есть ли сервисы лучше, но мне прям зашло - можно отрегулировать длину сниппета, выбрать тему, выбрать язык...

В общем, я тут над одним докладом работаю, и это просто отличная находка!

А вы пользуетесь подобным сервисом? Пишите в комментарии!

Flexible Coding
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Версионирование
 
Всем привет!
Сегодня мы поговорим про версии и версионирование. Они повсюду:
🧪 у релизов приложений
🧱 у миграций баз данных
🔌 у 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 очень слабый - рекомендации так себе, действия в коде - тоже
В общем, для бесплатного теста работы с автокомплитом - норм, для серьёзного вайбкодинга - не подойдёт.

Как запустить Codestral:

* Регистрируемся в mistral на гугл аккаунт
* Указываем номер телефона (оно даже для рф работает, но иностранный надёжнее)
* Подключаем continue
* Profit!


А теперь пришло время тестить агентов и копайлота!

Flexible Coding
👍3🔥2👏2