AI везде...
В Windows Task Manager появилась отдельная вкладка, отображающая нагрузку на NPU. Удобно.
Так вот - при включении Zoom там появляется стабильная загрузка в районе 10-15%.
Это наверняка Zoom AI companion.
Но... размытие фона у меня выключено, как и в принципе видео камера, расшифровка речи тоже, нагрузка не только во время разговора (убрать шумы).
Вопрос - что он там считает?)
#ai
В Windows Task Manager появилась отдельная вкладка, отображающая нагрузку на NPU. Удобно.
Так вот - при включении Zoom там появляется стабильная загрузка в районе 10-15%.
Это наверняка Zoom AI companion.
Но... размытие фона у меня выключено, как и в принципе видео камера, расшифровка речи тоже, нагрузка не только во время разговора (убрать шумы).
Вопрос - что он там считает?)
#ai
Немного о протекании абстракций.
Сегодня про кейс из жизни - как работает Docker на Windows.
Есть тестовый проект суть которого - работа с локальной LLM. Модель - gemma с 4b параметров. Для запуска модели (инференса) используется Docker образ ollama. Запускаю все это в Windows, что немаловажно.
Да, Docker в Windows это не тоже самое, что Docker в Linux, т.к. появляется новый слой трансляции.
Ну ок, не 5% накладные расходы, а скажем 10. Или 15.
А что в реальности?
gemma, запущенная напрямую в Windows выдает на глаз 10 токенов\с.
А в Docker скорость падает раз в 10, что уже больно.
При этом - все ядра процессора загружены на 100%.
И по использованию памяти видно, что модель полностью загрузилась в RAM. Это, кстати, отдельная тема - как LLM используют RAM.
Но вернемся к проблеме.
В 10 раз отличие по скорости...
Диалог с ChatGPT и Gemini дал пару наводок - все мимо. Docker видит все ядра процессора, доступна вся RAM, все наборы инструкций процессора, требуемые LLM, ollama видит.
Есть подсказка, что плохо пробрасывать том файловой системы с хоста Windows в Docker - ок, качаем модель внутрь файловой системы Linux. Не помогает. Да и сомнительно, т.к. модель полностью грузится в RAM, иначе LLM не работают, т.е. замедление должно быть лишь в момент запуска.
В итоге язабил смирился.
Но факт остается - по всем признакам Docker в Windows жизнеспособен для задач отладки. И в большинстве задач вполне себе нормально работает. А в конкретном кейсе - разница в 10 раз.
#docker #win #ai
Сегодня про кейс из жизни - как работает Docker на Windows.
Есть тестовый проект суть которого - работа с локальной LLM. Модель - gemma с 4b параметров. Для запуска модели (инференса) используется Docker образ ollama. Запускаю все это в Windows, что немаловажно.
Да, Docker в Windows это не тоже самое, что Docker в Linux, т.к. появляется новый слой трансляции.
Ну ок, не 5% накладные расходы, а скажем 10. Или 15.
А что в реальности?
gemma, запущенная напрямую в Windows выдает на глаз 10 токенов\с.
А в Docker скорость падает раз в 10, что уже больно.
При этом - все ядра процессора загружены на 100%.
И по использованию памяти видно, что модель полностью загрузилась в RAM. Это, кстати, отдельная тема - как LLM используют RAM.
Но вернемся к проблеме.
В 10 раз отличие по скорости...
Диалог с ChatGPT и Gemini дал пару наводок - все мимо. Docker видит все ядра процессора, доступна вся RAM, все наборы инструкций процессора, требуемые LLM, ollama видит.
Есть подсказка, что плохо пробрасывать том файловой системы с хоста Windows в Docker - ок, качаем модель внутрь файловой системы Linux. Не помогает. Да и сомнительно, т.к. модель полностью грузится в RAM, иначе LLM не работают, т.е. замедление должно быть лишь в момент запуска.
В итоге я
Но факт остается - по всем признакам Docker в Windows жизнеспособен для задач отладки. И в большинстве задач вполне себе нормально работает. А в конкретном кейсе - разница в 10 раз.
#docker #win #ai
Что такое совершенный код?
Читая одноименную книгу (да, я снова о ней), у меня возникла уверенность в том, что автор практикующий и очень педантичный, уделяющий внимание деталям разработчик.
В принципе, для этого книгу можно не читать, достаточно оценить ее размер)
Но тем не менее.
По каждой казалось бы простой теме: переменные, методы, классы, условные операторы, циклы... - есть есть что сказать, и сказать много.
И в большинстве случаев - по делу.
Пример.
Я всегда топлю за читаемость кода.
Но никогда не задумывался о расположении локальных переменных.
А Стив задумывался)
Он вводит понятия частоты использования и времени жизни переменной.
Вот это неправильно, т.к.
1) не нужно разделять объявление, инициализацию и использование переменной, т.е. переменную для цикла надо объявлять прямо перед ним.
2) блоки по поиску файла и заметки нужно четко разделить, чтобы было легко рефакторить и при необходимость разделить на методы.
3) еще один риск - если между объявлением переменной и ее использованием много кода - возрастает вероятность "случайно" ее поменять так, что сломается использующий переменную код.
Т.е. частота использования (число строк с переменной/число строк от первого до последнего появления переменной) должна быть высокой, время жизни - коротким.
И это увеличивает читаемость. Вроде простая штука, но отдельно о ней не задумываешь.
#book_review
Читая одноименную книгу (да, я снова о ней), у меня возникла уверенность в том, что автор практикующий и очень педантичный, уделяющий внимание деталям разработчик.
В принципе, для этого книгу можно не читать, достаточно оценить ее размер)
Но тем не менее.
По каждой казалось бы простой теме: переменные, методы, классы, условные операторы, циклы... - есть есть что сказать, и сказать много.
И в большинстве случаев - по делу.
Пример.
Я всегда топлю за читаемость кода.
Но никогда не задумывался о расположении локальных переменных.
А Стив задумывался)
Он вводит понятия частоты использования и времени жизни переменной.
var fileFound = false;
var noteFound = false;
...
while (!found) {
...
}
...
noteFound = findNotes(...);
Вот это неправильно, т.к.
1) не нужно разделять объявление, инициализацию и использование переменной, т.е. переменную для цикла надо объявлять прямо перед ним.
2) блоки по поиску файла и заметки нужно четко разделить, чтобы было легко рефакторить и при необходимость разделить на методы.
3) еще один риск - если между объявлением переменной и ее использованием много кода - возрастает вероятность "случайно" ее поменять так, что сломается использующий переменную код.
Т.е. частота использования (число строк с переменной/число строк от первого до последнего появления переменной) должна быть высокой, время жизни - коротким.
И это увеличивает читаемость. Вроде простая штука, но отдельно о ней не задумываешь.
#book_review
Как-то я упустил важное обновление в IDEA - MCP сервер.
Почему важное и зачем вообще это нужно?
AI агенты уже умеют многое. Их стандартные навыки, они же тулы - просмотр содержимого каталогов, чтение и изменение файлов, выполнение скриптов в CLI. Примерный список навыков можно посмотреть на примере OpenCode https://opencode.ai/docs/tools/
Но IDEA умеет гораздо больше - поиск проблем в коде, разного рода рефакторинги, более умный поиск, уже готовые конфигурации запуска... Вот это бы это все агент мог делать за нас...
Ну собственно уже может)
https://www.jetbrains.com/help/idea/mcp-server.html
Список тулов на старте неплох:
- create_new_file
- execute_run_configuration
- execute_terminal_command
- find_files_by_glob
- find_files_by_name_keyword
- get_all_open_file_paths
- get_file_problems
- get_file_text_by_path
- get_project_dependencies
- get_project_modules
- get_repositories
- get_run_configurations
- get_symbol_info
- list_directory_tree
- open_file_in_editor
- reformat_file
- rename_refactoring
- replace_text_in_file
- search_in_files_by_regex
- search_in_files_by_text
Особенно радуют reformat_file и get_file_problems - даже за самым хорошим агентом приходилось исправлять.
rename_refactoring конечно же надо делать средствами IDE, т.к. в этом случае вероятность ошибок стремится к нулю.
execute_terminal_command - меня постоянно раздражают мелкие окошки терминала в чате, по возможности стоит использовать терминал IDEA.
ну и работа с run configuration ускорит процесс отладки для агента (не нужен подбор команд) и уберет дублирование (не надо дублировать в промте)
Фича в Community, поэтому появится в форках - уже в OpenIDE https://habr.com/ru/articles/989716/ и скоро в GigaIDE.
Не хватает остальных рефакторингов. И хорошая новость - плагины тоже могут добавлять MCP навыки, я думаю сейчас этот процесс в самом разгаре)
Лично я буду тестить. Да, по умолчанию MCP сервер выключен. И для части агентов есть автоконфигурация - Cline, Cloude Code. Но даже там, где ее нет это не проблема.
#ide #idea #ai #mcp
Почему важное и зачем вообще это нужно?
AI агенты уже умеют многое. Их стандартные навыки, они же тулы - просмотр содержимого каталогов, чтение и изменение файлов, выполнение скриптов в CLI. Примерный список навыков можно посмотреть на примере OpenCode https://opencode.ai/docs/tools/
Но IDEA умеет гораздо больше - поиск проблем в коде, разного рода рефакторинги, более умный поиск, уже готовые конфигурации запуска... Вот это бы это все агент мог делать за нас...
Ну собственно уже может)
https://www.jetbrains.com/help/idea/mcp-server.html
Список тулов на старте неплох:
- create_new_file
- execute_run_configuration
- execute_terminal_command
- find_files_by_glob
- find_files_by_name_keyword
- get_all_open_file_paths
- get_file_problems
- get_file_text_by_path
- get_project_dependencies
- get_project_modules
- get_repositories
- get_run_configurations
- get_symbol_info
- list_directory_tree
- open_file_in_editor
- reformat_file
- rename_refactoring
- replace_text_in_file
- search_in_files_by_regex
- search_in_files_by_text
Особенно радуют reformat_file и get_file_problems - даже за самым хорошим агентом приходилось исправлять.
rename_refactoring конечно же надо делать средствами IDE, т.к. в этом случае вероятность ошибок стремится к нулю.
execute_terminal_command - меня постоянно раздражают мелкие окошки терминала в чате, по возможности стоит использовать терминал IDEA.
ну и работа с run configuration ускорит процесс отладки для агента (не нужен подбор команд) и уберет дублирование (не надо дублировать в промте)
Фича в Community, поэтому появится в форках - уже в OpenIDE https://habr.com/ru/articles/989716/ и скоро в GigaIDE.
Не хватает остальных рефакторингов. И хорошая новость - плагины тоже могут добавлять MCP навыки, я думаю сейчас этот процесс в самом разгаре)
Лично я буду тестить. Да, по умолчанию MCP сервер выключен. И для части агентов есть автоконфигурация - Cline, Cloude Code. Но даже там, где ее нет это не проблема.
#ide #idea #ai #mcp
OpenCode
Tools
Manage the tools an LLM can use.
И чтобы "зафиналить" тему с множественными отрицаниями в условиях пару цитат из книжки)))
P.S. Кто-нибудь пробовал вычислить вторую фразу?)
#book_review
Я не не нетупой.
Гомер Симпсон
(Homer Simpson)
Не немногие люди не имеют проблем с непониманием некоротких неположительных фраз, т. е. большинство людей имеют трудности с пониманием большого количества отрицаний.
P.S. Кто-нибудь пробовал вычислить вторую фразу?)
#book_review
🔥1
Каким должен быть AI autocomplete?
Для начала - почему я задался этим вопросом?
Потому что перед глазами есть autocomplete, который слишком часто выдает ерунду, и у каждого, кто им пользовался, появляется желание его отключить)
Необходимые условия:
1) у агента autocomplete должен быть свой RAG, где он хранит контекст всего проекта. В идеале - с подключением внешних папок с кодом или других репозиториев git.
2) агент должен быть быстрым, т.е. это отдельная модель с небольшим числом параметров. Т.к. скорость модели прямо пропорциональна числу ее параметров.
3) агент должен оперативно подхватывать изменения - т.е. если я изменил класс А, перешел в класс Б и хочу вызвать новый код класса А - он сразу же должен быть доступен.
Достаточное условие: агент должен уметь молчать) Т.е. должен быть хороший механизм расчета вероятности подсказки, и при низкой вероятности агент просто не должен ничего предлагать.
Я бы даже не выносил это в параметры. Если этого не сделать - получается резко негативный клиентский опыт.
Приведу хорошие примеры, когда autocomplete должен работать:
1)
2)
3)
Когда лучше ничего не предлагать - при добавлении новых полей и методов в класс. Или на первой строке нового метода, если по его названию не понятно, что он будет делать.
Итого - иногда лучше молчать, чем говорить)
#ai #ide #ai_agents
Для начала - почему я задался этим вопросом?
Потому что перед глазами есть autocomplete, который слишком часто выдает ерунду, и у каждого, кто им пользовался, появляется желание его отключить)
Необходимые условия:
1) у агента autocomplete должен быть свой RAG, где он хранит контекст всего проекта. В идеале - с подключением внешних папок с кодом или других репозиториев git.
2) агент должен быть быстрым, т.е. это отдельная модель с небольшим числом параметров. Т.к. скорость модели прямо пропорциональна числу ее параметров.
3) агент должен оперативно подхватывать изменения - т.е. если я изменил класс А, перешел в класс Б и хочу вызвать новый код класса А - он сразу же должен быть доступен.
Достаточное условие: агент должен уметь молчать) Т.е. должен быть хороший механизм расчета вероятности подсказки, и при низкой вероятности агент просто не должен ничего предлагать.
Я бы даже не выносил это в параметры. Если этого не сделать - получается резко негативный клиентский опыт.
Приведу хорошие примеры, когда autocomplete должен работать:
1)
List<String> someList = // тут бы лучше помолчать, если подходящего list нет в контексте метода
List<String> someList = someSet. // вот тут уже можно предложить например stream().collect(Collectors.toList());
2)
BigInteger md5Hash(String text) {
// вот тут autocomplete вполне бы мог добавить расчет хэша с помощью java.security.MessageDigest с конвертацией в int
// а вот пока я пишу объявление метода - лучше помолчать3)
var someEntity = SomeEntity.builder(). // тут в теории можно предлагать методы билдера в порядке следования полей в классе, но не критично
// а вот следующим шагом вполне можно предложить someEntityRepocitory.save(someEntity);
Когда лучше ничего не предлагать - при добавлении новых полей и методов в класс. Или на первой строке нового метода, если по его названию не понятно, что он будет делать.
Итого - иногда лучше молчать, чем говорить)
#ai #ide #ai_agents
Два подхода к написанию функций (методов).
Первый - у метода должна быть одна точка выхода (в общем случае - как можно меньше точек выхода). А точка входа по умолчанию одна. Потому что это улучшает читаемость.
Второй - если у метода есть предусловия, то их нужно проверять с помощью охранных выражений в начале метода. Т.к. это уменьшает вложенность и опять же улучшает читаемость)
Т.е
vs
Второй вариант может быть длиннее первого, если всегда "как завещано" использовать фигурные скобки. Но в данном случае видится, что можно их убрать для улучшения читаемости.
И тогда мы получаем более понятный из-за линейной структуры.
В Совершенном коде автор тоже за второй вариант. Присоединяюсь и считаю, что второй вариант - это база.
Возможно есть кейсы, когда он не применим, но я пока придумать не могу.
Даже на 2 условиях. Даже если недостаточно простого return.
#book_review #code
Первый - у метода должна быть одна точка выхода (в общем случае - как можно меньше точек выхода). А точка входа по умолчанию одна. Потому что это улучшает читаемость.
Второй - если у метода есть предусловия, то их нужно проверять с помощью охранных выражений в начале метода. Т.к. это уменьшает вложенность и опять же улучшает читаемость)
Т.е
public void processUser(User user) {
if (user != null) {
if (user.getAge() >= 18) {
if (validateEmail(user.getEmail()) != null && user.getEmail().contains("@")) {
if (user.isVerified()) {
performUserRegistration(user);
}
}
}
}
}vs
public void processUser(User user) {
if (user == null) return;
if (user.getAge() < 18) return;
if (user.getEmail() == null || !user.getEmail().contains("@")) return;
if (!user.isVerified()) return;
performUserRegistration(user);
}Второй вариант может быть длиннее первого, если всегда "как завещано" использовать фигурные скобки. Но в данном случае видится, что можно их убрать для улучшения читаемости.
И тогда мы получаем более понятный из-за линейной структуры.
В Совершенном коде автор тоже за второй вариант. Присоединяюсь и считаю, что второй вариант - это база.
Возможно есть кейсы, когда он не применим, но я пока придумать не могу.
Даже на 2 условиях. Даже если недостаточно простого return.
#book_review #code
Снова минутка цитат на канале:
Лично я вижу смысл в этом термине. И суть его в том, что в мире победившего ООП не стоит забывать об операциях (функциях) и о простоте.
Я уже писал про структурный дизайн - https://t.me/javaKotlinDevOps/400.
Напомню, там была речь о том, что не обязательно заводить кучу объектов и интерфейсов, если процесс простой и раскладывается на три части - подготовка данных, преобразования и запись.
Тогда его можно реализовать в виде сервиса, "чистой" модели и репозитория. К слову: ETL = Extract -> Transform -> Load - о том же.
Так вот - структурное программирование тоже раскладывает любой процесс на три части, только уже на уровне метода: последовательный код, условия и циклы.
Казалось бы - ну да, очевидно это так. Но есть нюанс - тут речь идет о проблеме множественных выходов из метода.
Структурное программирование появилось как ответ на широкое распространение оператора go to и призвано бороться с ним.
Опять вопрос - go to мы победили, тогда зачем эти "предания старины глубокой"?
Нет, не победили. Точнее победили, но не до конца.
Т.к. у нас есть множественный return и throw. А если копнуть глубже, и расширить проблему на любые прыжки по коду - break и continue.
Надо ли от них отказываться, учитывая что парадигма то вроде полезная?
На мой взгляд - нет.
Охранные выражения (guard pattern) - однозначно полезны.
throw для сигнализации об ошибке - тоже ок, они для этого создавались.
С рядом условий:
1) unchecked
2) не надо просто для передачи управления
3) должен быть определен слой\процесс перехвата исключений на уровне сервиса
break и continue - если без них код сложнее читать - тоже допустимы. Прыжки то небольшие, в рамках цикла. Хотя я ими пользуюсь редко, кейсов мало.
Т.е. снова приходим к искусству компромиссов.
Всякий раз, перед написанием такого оператора стоит подумать - нет ли других вариантов? Не усложняется ли он чтение и понимание кода?
Суть структурного программирования - код каждой операции должен просто читаться. Нет "спагетти-коду"!
#book_review #java #code #structure_programming #structure_xxx #principles
«Термин „структурное программирование“ был введён в 1969 году.
С тех пор термин „структурный“ применялся к любой деятельности в области ПО, включая структурный анализ, структурный дизайн и структурное валяние дурака».
Стив Макконнелл «Совершенный код».
Лично я вижу смысл в этом термине. И суть его в том, что в мире победившего ООП не стоит забывать об операциях (функциях) и о простоте.
Я уже писал про структурный дизайн - https://t.me/javaKotlinDevOps/400.
Напомню, там была речь о том, что не обязательно заводить кучу объектов и интерфейсов, если процесс простой и раскладывается на три части - подготовка данных, преобразования и запись.
Тогда его можно реализовать в виде сервиса, "чистой" модели и репозитория. К слову: ETL = Extract -> Transform -> Load - о том же.
Так вот - структурное программирование тоже раскладывает любой процесс на три части, только уже на уровне метода: последовательный код, условия и циклы.
Казалось бы - ну да, очевидно это так. Но есть нюанс - тут речь идет о проблеме множественных выходов из метода.
Структурное программирование появилось как ответ на широкое распространение оператора go to и призвано бороться с ним.
Опять вопрос - go to мы победили, тогда зачем эти "предания старины глубокой"?
Нет, не победили. Точнее победили, но не до конца.
Т.к. у нас есть множественный return и throw. А если копнуть глубже, и расширить проблему на любые прыжки по коду - break и continue.
Надо ли от них отказываться, учитывая что парадигма то вроде полезная?
На мой взгляд - нет.
Охранные выражения (guard pattern) - однозначно полезны.
throw для сигнализации об ошибке - тоже ок, они для этого создавались.
С рядом условий:
1) unchecked
2) не надо просто для передачи управления
3) должен быть определен слой\процесс перехвата исключений на уровне сервиса
break и continue - если без них код сложнее читать - тоже допустимы. Прыжки то небольшие, в рамках цикла. Хотя я ими пользуюсь редко, кейсов мало.
Т.е. снова приходим к искусству компромиссов.
Всякий раз, перед написанием такого оператора стоит подумать - нет ли других вариантов? Не усложняется ли он чтение и понимание кода?
Суть структурного программирования - код каждой операции должен просто читаться. Нет "спагетти-коду"!
#book_review #java #code #structure_programming #structure_xxx #principles
Telegram
(java || kotlin) && devOps
Всем привет!
Я уже писал про то, что не люблю код, в котором интерфейсы делаются ради интерфейсов. Самый яркий антипаттерн: интерфейс с единственной реализацией, лежащей рядом. Подозреваю, одной из причин такого проектирования является принцип Dependency…
Я уже писал про то, что не люблю код, в котором интерфейсы делаются ради интерфейсов. Самый яркий антипаттерн: интерфейс с единственной реализацией, лежащей рядом. Подозреваю, одной из причин такого проектирования является принцип Dependency…
Медленная загрузка сервиса - значит Java?)
Есть такая проблема у Java, в частности при использовании Spring Framework. А точнее когда поверх Spring-а накручиваются свои компоненты.
Загружается куча классов, много кода инициализации = много времени. Как с этим борются - см. по тэгу #java_start_boost
Но только ли это проблема Java?
Запускал небольшую AI модельку на Python. Один скрипт. Скрипт стартует более 20 секунд.
Ну, думаю, модель так долго грузится. Померил - нет, модель порядка 3 секунд. Она уже в виде кэша скачана на локальный компьютер, да и не LLM это.
Антивирус? Интерпретатор Python?
Нет, всего лишь библиотека sentence-transformers.
На самом деле конечно не всего лишь. Она под капотом грузит движок для инференса - PyTorch. Плюс другие зависимости.
Но за 20 секунд старта ответственна именно строчка c импортом:
Тут еще видится "выстрелил" высокий уровень абстракции, принятый в Python.
Пишешь пару строк - у тебя все работает. Удобно? Да. Но есть нюансы)
Вывод - высокий уровень может превратится в айсберг. Ты видишь вершину, а под ней еще...
#python #java
Есть такая проблема у Java, в частности при использовании Spring Framework. А точнее когда поверх Spring-а накручиваются свои компоненты.
Загружается куча классов, много кода инициализации = много времени. Как с этим борются - см. по тэгу #java_start_boost
Но только ли это проблема Java?
Запускал небольшую AI модельку на Python. Один скрипт. Скрипт стартует более 20 секунд.
Ну, думаю, модель так долго грузится. Померил - нет, модель порядка 3 секунд. Она уже в виде кэша скачана на локальный компьютер, да и не LLM это.
Антивирус? Интерпретатор Python?
Нет, всего лишь библиотека sentence-transformers.
На самом деле конечно не всего лишь. Она под капотом грузит движок для инференса - PyTorch. Плюс другие зависимости.
Но за 20 секунд старта ответственна именно строчка c импортом:
from sentence_transformers import SentenceTransformer
Тут еще видится "выстрелил" высокий уровень абстракции, принятый в Python.
Пишешь пару строк - у тебя все работает. Удобно? Да. Но есть нюансы)
Вывод - высокий уровень может превратится в айсберг. Ты видишь вершину, а под ней еще...
#python #java
Сколько багов в час делает разработчик?
И снова цитата из Совершенного кода:
Хоть ты код не пиши!)))
А если серьёзно - рулит код-ревью и тесты. Именно в таком порядке.
Типичный концер процент нахождения багов в ПО при использовании различных практик из той же книги:
Неформальный обзор дизайна (тех. проекта) 35%
Формальные инспекции дизайна (тех. проекта) 55%
Моделирование и прототипирование 65%
Неформальный обзор кода (code review) 25%
Самостоятельная проверка код 35%
Формальные инспекции кода 60%
Юнит-тестирование 30%
Регрессионное тестирование 25%
Тестирование новой функции (компонента) 30%
Интеграционное тестирование 35%
Системное тестирование 40%
Бета-тестирование (<10 тестеров) 35%
Бета-тестирование (>1000 тестеров) 75%
Что бросается в глаза:
1) очень высокая эффективность ревью кода. Что понятно, т.к. получаем shift left и, главное, при код-ревью мы не просто находим баг, но ещё и его причину, в отличие от тестирования. Т.е. не тратим время на отладку.
2) формальные ревью сильно эффективнее неформальных. Немного странно на первый взгляд. Но объяснение есть - формальное = выделено время + есть чек-лист + нужен отчёт. Т.е. его сложно провести "формально" (да, велик и могуч русский язык))) Т.е. правильно было бы назвать его глубокое код-ревью
3) Хорошая эффективность у самостоятельного ревью, а его провести проще всего. Например, при подготовке pull request. И снова понятно почему - своей код ты уже знаешь, главное чтобы между кодированием и ревью прошло время, чтобы сменился фокус.
4) низкая эффективность unit тестов, сравнимая с регрессом и тестированием нового функционала. Это странно. Но если подумать - TDD тогда ещё только появилось, да и сейчас его проникновение оставляет желать лучшего. А без него UT - это в основном регресс. И немного тестирование нового функционала, но методом "прозрачного" ящика.
5) высокие цифры у прототипирования и бета-тестах на большом числе людей. Пр сути они связаны - это проверка гипотезы и реализации. Провести сложно, но эффект похоже есть.
Ну и банальная вещь - ни один метод сам по себе не даёт 100%. Только в комплекте.
#code_review #quality_assurance
И снова цитата из Совершенного кода:
Исследования, проведенные в Институте
разработки П0 (Software Engincering Institute), показали, что разработчики допускают в среднем
от 1 до З дефектов в час при проектировании и от 5 до 8 дефектов в час при кодировании
(Humphrey, 1997). Ясно, что устранение дефектов — обязательное условие эффективного конструирования.
Хоть ты код не пиши!)))
А если серьёзно - рулит код-ревью и тесты. Именно в таком порядке.
Типичный концер процент нахождения багов в ПО при использовании различных практик из той же книги:
Неформальный обзор дизайна (тех. проекта) 35%
Формальные инспекции дизайна (тех. проекта) 55%
Моделирование и прототипирование 65%
Неформальный обзор кода (code review) 25%
Самостоятельная проверка код 35%
Формальные инспекции кода 60%
Юнит-тестирование 30%
Регрессионное тестирование 25%
Тестирование новой функции (компонента) 30%
Интеграционное тестирование 35%
Системное тестирование 40%
Бета-тестирование (<10 тестеров) 35%
Бета-тестирование (>1000 тестеров) 75%
Что бросается в глаза:
1) очень высокая эффективность ревью кода. Что понятно, т.к. получаем shift left и, главное, при код-ревью мы не просто находим баг, но ещё и его причину, в отличие от тестирования. Т.е. не тратим время на отладку.
2) формальные ревью сильно эффективнее неформальных. Немного странно на первый взгляд. Но объяснение есть - формальное = выделено время + есть чек-лист + нужен отчёт. Т.е. его сложно провести "формально" (да, велик и могуч русский язык))) Т.е. правильно было бы назвать его глубокое код-ревью
3) Хорошая эффективность у самостоятельного ревью, а его провести проще всего. Например, при подготовке pull request. И снова понятно почему - своей код ты уже знаешь, главное чтобы между кодированием и ревью прошло время, чтобы сменился фокус.
4) низкая эффективность unit тестов, сравнимая с регрессом и тестированием нового функционала. Это странно. Но если подумать - TDD тогда ещё только появилось, да и сейчас его проникновение оставляет желать лучшего. А без него UT - это в основном регресс. И немного тестирование нового функционала, но методом "прозрачного" ящика.
5) высокие цифры у прототипирования и бета-тестах на большом числе людей. Пр сути они связаны - это проверка гипотезы и реализации. Провести сложно, но эффект похоже есть.
Ну и банальная вещь - ни один метод сам по себе не даёт 100%. Только в комплекте.
#code_review #quality_assurance
Письмо от CTO, который не взял тебя в команду
Привет! Хочу объяснить, почему мы не сделали тебе оффер.
Сразу скажу, с кодом у тебя всё ок. Вопрос вообще не в этом. У меня ощущение, что ты мало сталкивался с тем, что происходит после коммита/мержа.
Помнишь, мы обсуждали прод, я спрашивал тебя: как устроен пайплайн деплоя, как собирается сервис, как управлять образами, как контейнеры оркестрируются на проде? А ты говорил, что это всё докер-кубер и вообще команда инфры. Но нам нужен инженер, который понимает это практически.
Сейчас без контейнеров почти никуда, особенно если сервис живой и его часто релизят. И docker — это не “инструмент devops”. Это среда выполнения. Если ты понимаешь docker, ты контролируешь архитектуру, ресурсы сервиса, изоляцию процессов, сетевое поведение, стратегию масштабирования. Sidecar, Service Mesh, сетевые политики, безопасность, observability — всё это превращается в набор страшных слов, которые вроде слышал, но не трогал руками.
Да, ты пишешь код, но вся система шире чем код. Мы используем кубер, масштабируемся автоматически, деплоим десятки раз в день. И нам нужен человек, который понимает, что происходит на уровне контейнера. Не «где-то там в инфраструктуре». Рынок меняется. Стартапам нужны T-shape инженеры, нельзя быть “только про код” — приходится лезть во всё. Не потому что мы экономим на devops. Знание инфры вообще и контейнеров в частности — снижает операционные риски до того, как они станут инцидентами. Когда ты понимаешь, как это работает под капотом, сюрпризов становится сильно меньше. Меньше неопределённости — выше скорость команды. А скорость для стартапа — это не "удобство", а шанс выжить.
Инженер, который понимает контейнеризацию, разговаривает на одном языке с инфраструктурой.
Инженер, который не понимает, бьется лбом в стену между «кодом» и «реальностью».
Мы бы с радостью поработали с тобой. Когда будешь понимать не только код, но и прод. Хочешь расти — закрой этот пробел как можно быстрее. ASAP. Не призываю тебя получать черный пояс по YAML-driven development, но базу знать нужно. Сейчас это база для синьоров, а скоро станет обязательным минимумом для мидлов. А docker — не сложнее, чем любой фреймворк, который ты учишь за несколько недель.
--
Если серьезно, мы из этого сделали отдельный курс — потому что с этим реально у многих пробел. Приходи на "Docker и Kubernetes: основы разработки под облачную инфраструктуру". Старт через неделю, курс ведет Коля Ихалайнен, и он, кстати, и меня несколько лет назад докеру обучил (не шутка).
Привет! Хочу объяснить, почему мы не сделали тебе оффер.
Сразу скажу, с кодом у тебя всё ок. Вопрос вообще не в этом. У меня ощущение, что ты мало сталкивался с тем, что происходит после коммита/мержа.
Помнишь, мы обсуждали прод, я спрашивал тебя: как устроен пайплайн деплоя, как собирается сервис, как управлять образами, как контейнеры оркестрируются на проде? А ты говорил, что это всё докер-кубер и вообще команда инфры. Но нам нужен инженер, который понимает это практически.
Сейчас без контейнеров почти никуда, особенно если сервис живой и его часто релизят. И docker — это не “инструмент devops”. Это среда выполнения. Если ты понимаешь docker, ты контролируешь архитектуру, ресурсы сервиса, изоляцию процессов, сетевое поведение, стратегию масштабирования. Sidecar, Service Mesh, сетевые политики, безопасность, observability — всё это превращается в набор страшных слов, которые вроде слышал, но не трогал руками.
Да, ты пишешь код, но вся система шире чем код. Мы используем кубер, масштабируемся автоматически, деплоим десятки раз в день. И нам нужен человек, который понимает, что происходит на уровне контейнера. Не «где-то там в инфраструктуре». Рынок меняется. Стартапам нужны T-shape инженеры, нельзя быть “только про код” — приходится лезть во всё. Не потому что мы экономим на devops. Знание инфры вообще и контейнеров в частности — снижает операционные риски до того, как они станут инцидентами. Когда ты понимаешь, как это работает под капотом, сюрпризов становится сильно меньше. Меньше неопределённости — выше скорость команды. А скорость для стартапа — это не "удобство", а шанс выжить.
Инженер, который понимает контейнеризацию, разговаривает на одном языке с инфраструктурой.
Инженер, который не понимает, бьется лбом в стену между «кодом» и «реальностью».
Мы бы с радостью поработали с тобой. Когда будешь понимать не только код, но и прод. Хочешь расти — закрой этот пробел как можно быстрее. ASAP. Не призываю тебя получать черный пояс по YAML-driven development, но базу знать нужно. Сейчас это база для синьоров, а скоро станет обязательным минимумом для мидлов. А docker — не сложнее, чем любой фреймворк, который ты учишь за несколько недель.
--
Если серьезно, мы из этого сделали отдельный курс — потому что с этим реально у многих пробел. Приходи на "Docker и Kubernetes: основы разработки под облачную инфраструктуру". Старт через неделю, курс ведет Коля Ихалайнен, и он, кстати, и меня несколько лет назад докеру обучил (не шутка).
🔥2👍1
Алексей Рыбак: системный дизайн, хайлоад, разработка с агентами
Письмо от CTO, который не взял тебя в команду Привет! Хочу объяснить, почему мы не сделали тебе оффер. Сразу скажу, с кодом у тебя всё ок. Вопрос вообще не в этом. У меня ощущение, что ты мало сталкивался с тем, что происходит после коммита/мержа. Помнишь…
Что интересно - хотя в конце поста есть реклама, я ее заметил только после пересылки в канал. Т.е. пост зацепил.
Что ещё интересно - судя по реакциям и комментариям в канале автора - проблема актуальна.
Отмазки следующие:
1) в кровавом enterprise меня не пускают к инфре. Видимо не очень то и хотелось)
2) AI придёт и все сгенерит. Видимо вместе с кодом)
3) функции, faas, докера там нет. На самом деле по капотом есть, но главное - я в России работающих faas не видел.
4) ну и очевидное - это все реклама, не нужен мне ваш Docker. Пусть даже и реклама, но написано хорошо, а Docker и k8s - это база!)
#комментарии
Что ещё интересно - судя по реакциям и комментариям в канале автора - проблема актуальна.
Отмазки следующие:
1) в кровавом enterprise меня не пускают к инфре. Видимо не очень то и хотелось)
2) AI придёт и все сгенерит. Видимо вместе с кодом)
3) функции, faas, докера там нет. На самом деле по капотом есть, но главное - я в России работающих faas не видел.
4) ну и очевидное - это все реклама, не нужен мне ваш Docker. Пусть даже и реклама, но написано хорошо, а Docker и k8s - это база!)
#комментарии
Чем заменить сложный if?
В рамках борьбы за читаемость кода, конечно же.
Ответ - табличным методом.
Название, возможно, неизвестное, но многие этим подходом пользовались, не зная как его назвать.
Но ближе к коду)
Вот есть у нас, предположим, такое условие:
Сложно, т.к. много кода. Но вот так намного проще:
Собственно таблица - это коллекция, из которой по ключу получаем нужное значение в одну строчку без if.
Хорошо. Но не всегда ключ можно прямо замапить на значение.
Возможно, ключ однозначно преобразуется в требуемый. Тогда получаем табличный доступ с преобразованием:
Еше кейс. Предположим, у нас целевое значение зависит от положения точки в диапазоне, тогда получаем табличный метод со ступенчатым доступом:
Ну и возвращать можно не только значение, но и лямбду:
Важный плюс такого решения - "таблица" легко выносится в файл при необходимости настройки.
Или любой внешний источник.
Таблица может быть мапой, а не только массивом или списком.
P.S. Да, это снова Совершенный код)
#code_review #code
В рамках борьбы за читаемость кода, конечно же.
Ответ - табличным методом.
Название, возможно, неизвестное, но многие этим подходом пользовались, не зная как его назвать.
Но ближе к коду)
Вот есть у нас, предположим, такое условие:
int getDaysInMonth(int month) {
if (month == 1) return 31;
else if (month == 2) return 28;
else if (month == 3) return 31;
// ... ещё 9 веток
}Сложно, т.к. много кода. Но вот так намного проще:
private static final int[] DAYS_IN_MONTH = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int getDaysInMonth(int month) {
return DAYS_IN_MONTH[month];
}Собственно таблица - это коллекция, из которой по ключу получаем нужное значение в одну строчку без if.
Хорошо. Но не всегда ключ можно прямо замапить на значение.
Возможно, ключ однозначно преобразуется в требуемый. Тогда получаем табличный доступ с преобразованием:
public int resolveMonth(LocalDate date) {
return date.getMonthValue();
}
int getDaysInMonth(LocalDate date) {
return DAYS_IN_MONTH[resolveMonth(date)];
}Еше кейс. Предположим, у нас целевое значение зависит от положения точки в диапазоне, тогда получаем табличный метод со ступенчатым доступом:
@Getter
@RequiredArgsConstructor
enum Zone {
NIGHT ("Ночная", 2.15),
SEMI_PEAK ("Полупиковая", 4.30),
PEAK ("Пиковая", 6.45);
private final String label;
private final double ratePerKwh;
}
private static final int[] HOUR_THRESHOLDS = { 6, 9, 16, 20, 22, 23 };
private static final Zone[] TARIFF_TABLE = { Zone.NIGHT, Zone.PEAK, Zone.SEMI_PEAK, Zone.PEAK, Zone.SEMI_PEAK, Zone.NIGHT };
private static Zone lookupZone(int hour) {
for (int i = 0; i < HOUR_THRESHOLDS.length; i++) {
if (hour <= HOUR_THRESHOLDS[i]) {
return TARIFF_TABLE[i];
}
}
}
public static double getZonePrice(int hour) {
var zone = lookupZone(hour);
return zone.getRatePerKwh();
}
Ну и возвращать можно не только значение, но и лямбду:
private static final Map<String, Consumer<String>> HANDLERS = Map.of(
"ERROR", msg -> System.err.println("[ERROR] " + msg),
"WARNING", msg -> System.out.println("[WARN] " + msg),
"INFO", msg -> System.out.println("[INFO] " + msg),
"DEBUG", msg -> { /* no-op in prod */ }
);
public static void dispatch(String level, String message) {
HANDLERS.getOrDefault(level, m -> System.out.println("[UNKNOWN] " + m))
.accept(message);
}
Важный плюс такого решения - "таблица" легко выносится в файл при необходимости настройки.
Или любой внешний источник.
Таблица может быть мапой, а не только массивом или списком.
P.S. Да, это снова Совершенный код)
#code_review #code
👍2
Сложно не заметить, что последние пару месяцев у меня основная тема блока - "жемчужины" из книги Совершенный код.
Сегодня еще один пост, пост-"мысль вслух".
Самое удивительное в этой книжке - это два факта:
1) на английском она издана в 2004 году
2) она актуальна.
Я пытаюсь вспомнить, что же там устарело и вспоминаю лишь следующее:
а) в Java появились Enum (на тот момент еще нет)
б) Visual Basic умер (там есть примеры в числе прочего на VB)
в) IDE стали сильно лучше, считать открывающие и закрывающие скобки самому уже не надо
г) кажется все языки получили свой аналог xUnit, "костылить" свой подобный фреймворк тоже не надо
д) у нас есть git и история изменений в IDEA, "прихранивать" копию исходников перед изменением не нужно
е) на способы проверки повреждения данных в памяти из-за кривых указателей смотришь с ужасом, но все такие главы подписаны - для C\C++ и при желании их можно пропускать. Да и скорее всего большая часть этой информации актуальна до сих пор.
И пожалуй это все! За 20+ лет.
Даже обсуждение go to и глобальных переменных лишь на первый взгляд кажется не актуальным для Java...
Вот как надо книжки писать!
Вспоминается: "Новые песни сочиняет тот, у кого старые плохие". И это тот редкий случай, когда фраза справедлива)
#book_review #java
Сегодня еще один пост, пост-"мысль вслух".
Самое удивительное в этой книжке - это два факта:
1) на английском она издана в 2004 году
2) она актуальна.
Я пытаюсь вспомнить, что же там устарело и вспоминаю лишь следующее:
а) в Java появились Enum (на тот момент еще нет)
б) Visual Basic умер (там есть примеры в числе прочего на VB)
в) IDE стали сильно лучше, считать открывающие и закрывающие скобки самому уже не надо
г) кажется все языки получили свой аналог xUnit, "костылить" свой подобный фреймворк тоже не надо
д) у нас есть git и история изменений в IDEA, "прихранивать" копию исходников перед изменением не нужно
е) на способы проверки повреждения данных в памяти из-за кривых указателей смотришь с ужасом, но все такие главы подписаны - для C\C++ и при желании их можно пропускать. Да и скорее всего большая часть этой информации актуальна до сих пор.
И пожалуй это все! За 20+ лет.
Даже обсуждение go to и глобальных переменных лишь на первый взгляд кажется не актуальным для Java...
Вот как надо книжки писать!
Вспоминается: "Новые песни сочиняет тот, у кого старые плохие". И это тот редкий случай, когда фраза справедлива)
#book_review #java
💯5
Есть мнение, что разработка - это молодая отрасль. Этим часто объясняется ее несовершенство. Нет чётких законов, парадигмы меняются, всегда приходится идти на компромиссы. Как пример - те же принципы чистого кода нельзя понимать буквально, за что книгу часто критикуют.
Но посмотрим, когда появились некоторые ключевые идеи.
Закон Конвея, упомянутый ранее https://t.me/javaKotlinDevOps/301 - структура кода повторяет структуру организации - 1967 год. Практически 60 лет назад.
Спор о вреде go to (а это значит, что он уже активно использовался) начал Дейкстра в письме Go To Statement Considered Harmful практически тогда же - 1968 году. 58 лет назад. Дискуссии, к слову, тогда велись через письма в журналы. В рамках дискуссии о go to понятие спагетти-код стало общепринятым примерно в 1977 году. 49 лет назад.
В 1970 году сотрудник IBM Эдгар Кодд опубликовал статью «A Relational Model of Data for Large Shared Data Banks», которая стала фундаментом для всех реляционных баз данных. В 1979 году появилась первая коммерческая реляционная СУБД Oracle. 56 и 47 лет соответственно.
Мифический человеко-месяц был написан в 1975 году. Знаменитый закон Брукса: добавление разработчиков ближе к концу проекта лишь увеличивает его сроки. А на русский книга была переведена в 1979 году, соответственно, в СССР. Это 51 и 47 лет назад. Я ещё не родился)
Совершенный код (да, опять), первое издание - 1993 год. 33 года назад.
Java 1.0 (еще без collections, не говоря уже и стримах, generic, enum, JDBC и многого другого) появилась в 1996 - 30 лет в этом году.
В 1999 был сформирован DRY («Don't Repeat Yourself» — «Не повторяй себя») Эндрю Хантом и Дэвидом Томасом в книге The Pragmatic Programmer. 27 лет назад. Принцип KISS сильно моложе, но его снимем с дистанции - он появится в ВВС США.
Принципы SOLID были сформулированы на год позже Робертом Мартином в статье Design Principles and Design Patterns. 26 лет назад.
Тогда же вышла книжка Кента Бека про XP (экстремальное программирование, включая TDD). И в 2001 Agile Manifest, который с ним связан.
В 2001 году появилась IDEA и рефакторинг стал доступен всем. Ну почти всем , Community появилась на 8 лет позже и началось ее победное шествие. 25 лет назад.
И лишь Docker, Kafka, DevOps, Kotlin можно считать относительно новыми - 15-20 лет назад. K8s так вообще чуть больше 10 лет.
Т.е. отрасль все же достигла зрелости.
И тут пришёл AI и хочет ее отменить)
Но это уже другая история)
#it_history
Но посмотрим, когда появились некоторые ключевые идеи.
Закон Конвея, упомянутый ранее https://t.me/javaKotlinDevOps/301 - структура кода повторяет структуру организации - 1967 год. Практически 60 лет назад.
Спор о вреде go to (а это значит, что он уже активно использовался) начал Дейкстра в письме Go To Statement Considered Harmful практически тогда же - 1968 году. 58 лет назад. Дискуссии, к слову, тогда велись через письма в журналы. В рамках дискуссии о go to понятие спагетти-код стало общепринятым примерно в 1977 году. 49 лет назад.
В 1970 году сотрудник IBM Эдгар Кодд опубликовал статью «A Relational Model of Data for Large Shared Data Banks», которая стала фундаментом для всех реляционных баз данных. В 1979 году появилась первая коммерческая реляционная СУБД Oracle. 56 и 47 лет соответственно.
Мифический человеко-месяц был написан в 1975 году. Знаменитый закон Брукса: добавление разработчиков ближе к концу проекта лишь увеличивает его сроки. А на русский книга была переведена в 1979 году, соответственно, в СССР. Это 51 и 47 лет назад. Я ещё не родился)
Совершенный код (да, опять), первое издание - 1993 год. 33 года назад.
Java 1.0 (еще без collections, не говоря уже и стримах, generic, enum, JDBC и многого другого) появилась в 1996 - 30 лет в этом году.
В 1999 был сформирован DRY («Don't Repeat Yourself» — «Не повторяй себя») Эндрю Хантом и Дэвидом Томасом в книге The Pragmatic Programmer. 27 лет назад. Принцип KISS сильно моложе, но его снимем с дистанции - он появится в ВВС США.
Принципы SOLID были сформулированы на год позже Робертом Мартином в статье Design Principles and Design Patterns. 26 лет назад.
Тогда же вышла книжка Кента Бека про XP (экстремальное программирование, включая TDD). И в 2001 Agile Manifest, который с ним связан.
В 2001 году появилась IDEA и рефакторинг стал доступен всем. Ну почти всем , Community появилась на 8 лет позже и началось ее победное шествие. 25 лет назад.
И лишь Docker, Kafka, DevOps, Kotlin можно считать относительно новыми - 15-20 лет назад. K8s так вообще чуть больше 10 лет.
Т.е. отрасль все же достигла зрелости.
И тут пришёл AI и хочет ее отменить)
Но это уже другая история)
#it_history
Telegram
(java || kotlin) && devOps
Всем привет!
Разработка ПО - очень динамичная сфера. Мэйнфреймы, ассемблер, CSV, RDBMS, C, Delphi, Java, REST, MQ, git, DevOps, Docker, k8s, Kafka, noSQL, microservices, reactive programming, DataLake, GitOps, ChatGPT...
Но есть вещи, которые не меняются.…
Разработка ПО - очень динамичная сфера. Мэйнфреймы, ассемблер, CSV, RDBMS, C, Delphi, Java, REST, MQ, git, DevOps, Docker, k8s, Kafka, noSQL, microservices, reactive programming, DataLake, GitOps, ChatGPT...
Но есть вещи, которые не меняются.…
👍4❤1
Чем похожи LLM и blockchain?
И там, и там для генерации следующего элемента используют данные предыдущих. И LLM также не может изменить уже сгенерированные токены, даже если в какой-то момент поняла, что они не верны. Ну и ещё потому что у нас как правило стриминг и пользователь уже их увидел)
Разница конечно есть - в blockchain вся цепочка живёт вечно, а LLM ограничена длиной контекстного окна и возможностью чата/агента хранить историю
И эта особенность является одной из причин галлюцинаций LLM. Т.к. придя к неверному выводу модель опирается на него в дальнейших ответах.
#ai
Разница конечно есть - в blockchain вся цепочка живёт вечно, а LLM ограничена длиной контекстного окна и возможностью чата/агента хранить историю
И эта особенность является одной из причин галлюцинаций LLM. Т.к. придя к неверному выводу модель опирается на него в дальнейших ответах.
#ai
В продолжение предыдущего поста - почему модели галлюцинируют?
Попробую собрать все возможные причины:
1) как уже говорил - один раз сделав неверный вывод модель не может его исправить, он ложится в ее контекст, на основании которого выдаются все последующие ответы.
Да, не все токены из контекста выбираются при генерации ответа, только наиболее близкие (скалярное произведение векторов). И когда в диалоге появляются новые токены, более релевантные - например, "твой ответ неверный, обрати внимание на ..." - они "забивают" старые.
Иначе модель будет строить всю цепочку рассуждений опираясь на неверный вывод.
2) неверные данные от пользователя. Модель верит пользователю. Почему?
Модель обучалась на каких-то открытых документах. Форумы, новости, GitHub,... Сколько там неверной информации?
Она конечно есть, но в большинство документов содержит более менее актуальную информацию.
Модель, соответственно, ожидает, что пользователь тоже дает ей верную информацию.
Особенно в тех областях, по которым нет явно опровергающих это фактов.
Земля плоская - опровержений много. Я уже установил последнюю версию драйверов - как это проверить?) Есть OpenClaws, но я бы не рискнул ставить его на свой компьютер)
3) модель в принципе не оперирует понятиями ложь и правда. Она ищет наиболее вероятный следующий токен, из которых в итоге появляется фраза.
Вероятность зависит от данных обучения и предыдущего диалога. Т.е. ей нужен внешний арбитр, который знает - что правда, а что нет.
Это может быть другая модель - но в целом у нее те же проблемы. Или человек - т.е. информацию надо перепроверять.
4) И самое интересное.
Если точных данных нет, а это как раз самые интересные и сложные кейсы - модель их может угадать.
Может угадать, может не угадать.
Но на обучении - Supervised fine-tuning (SFT) и Reinforcement Learning (RL) - модель оценивают по проценту верных ответов.
Все бенчмарки для людей о том же - процент правильных ответов.
Т.е. для модели лучшая стратегия - что-то придумать, чем честно сказать "Я не знаю".
Об этом даже авторы OpenAI пишут и предлагают менять систему оценок: https://openai.com/ru-RU/index/why-language-models-hallucinate
В итоге имеем то, что имеем)
#ai
Попробую собрать все возможные причины:
1) как уже говорил - один раз сделав неверный вывод модель не может его исправить, он ложится в ее контекст, на основании которого выдаются все последующие ответы.
Да, не все токены из контекста выбираются при генерации ответа, только наиболее близкие (скалярное произведение векторов). И когда в диалоге появляются новые токены, более релевантные - например, "твой ответ неверный, обрати внимание на ..." - они "забивают" старые.
Иначе модель будет строить всю цепочку рассуждений опираясь на неверный вывод.
2) неверные данные от пользователя. Модель верит пользователю. Почему?
Модель обучалась на каких-то открытых документах. Форумы, новости, GitHub,... Сколько там неверной информации?
Она конечно есть, но в большинство документов содержит более менее актуальную информацию.
Модель, соответственно, ожидает, что пользователь тоже дает ей верную информацию.
Особенно в тех областях, по которым нет явно опровергающих это фактов.
Земля плоская - опровержений много. Я уже установил последнюю версию драйверов - как это проверить?) Есть OpenClaws, но я бы не рискнул ставить его на свой компьютер)
3) модель в принципе не оперирует понятиями ложь и правда. Она ищет наиболее вероятный следующий токен, из которых в итоге появляется фраза.
Вероятность зависит от данных обучения и предыдущего диалога. Т.е. ей нужен внешний арбитр, который знает - что правда, а что нет.
Это может быть другая модель - но в целом у нее те же проблемы. Или человек - т.е. информацию надо перепроверять.
4) И самое интересное.
Если точных данных нет, а это как раз самые интересные и сложные кейсы - модель их может угадать.
Может угадать, может не угадать.
Но на обучении - Supervised fine-tuning (SFT) и Reinforcement Learning (RL) - модель оценивают по проценту верных ответов.
Все бенчмарки для людей о том же - процент правильных ответов.
Т.е. для модели лучшая стратегия - что-то придумать, чем честно сказать "Я не знаю".
Об этом даже авторы OpenAI пишут и предлагают менять систему оценок: https://openai.com/ru-RU/index/why-language-models-hallucinate
В итоге имеем то, что имеем)
#ai
OpenAI
Почему языковые модели испытывают галлюцинации
Новая научная публикация OpenAI объясняет, почему языковые модели выдают галлюцинации. Результаты показывают, как улучшенные оценки могут повысить надежность, честность и безопасность ИИ.
Все AI dev агенты делятся на 2 категории по тому, как хранят свои правила.
Один файл:
Claude Code — CLAUDE.md
Gemini CLI — GEMINI.md
OpenAI Codex CLI — AGENTS.md
JetBrains Junie — .junie/guidelines.md
Папка с несколькими файлами:
Cursor — .cursor/rules/*.mdc
Windsurf — .windsurf/rules/*.md
Cline — .clinerules/*.md
Roocode — .roo/rules/*.md
GitHub Copilot — .github/instructions/*.instructions.md
JetBrains AI Assistant — .aiassistant/rules/*.md
Continue — .continue/rules/*.md
GigaCode - .gitverse/pr_rules/*.md (для версии на GitVerse)
Cline тут выделяется тем, что вообще говоря позволяет оба варианта - файл .clinerules или одноименный каталог.
Особенность Claude - кастомные команды, хранятся в кастомные команды в ~/.claude/commands/<name>.md. В принципе можно использовать и как аналог rule при явном указании в чате. Но без автозагрузки.
И еще сильнее выделяется OpenCode.
Он вначале пытается быть совместимым с OpenAI (AGENTS.md), если не нашел - с Claude Code (CLAUDE.md). А кроме того позволяет через customInstructions в opencode.json подключать произвольные файлы, включая загрузку по http, что является уникальной фичей.
Какие плюсы\минусы у этих подходов?
Один файл - простота.
Особенно учитывая тот факт, что практически ни один агент не дает менять имя файла\папки - т.е. имеем дело с convention over configuration во всей красе.
Пару слов про смену имени: единственное исключение - Gemini CLI, позволяет задать contextFileName в settings.json.
Еще в теории с этим подходом больше шансов получить непротиворечивые правила, но с ростом размера файла это преимущество нивелируется.
Каталог - а мне этот вариант кажется более удобным - имеет следующие плюсы:
1) если в репо лежит разнородный код, который пишут разные люди: фронт, бэк, devops, автотесты то удобнее, если у каждого будет свой файл с правилами. Да, AI способствует T-shape, но это пока что процесс, а не свершившийся факт.
2) несколько файлов точно легче читать и править человеку. А со слабыми моделями - возможно и LLM.
3) в теории при наличии нескольких файлов LLM исходя из текущей задачи сама могла бы выбрать только нужные, тем самым уменьшив расход токенов и контекстного окна и ускорив работу.
Обходной вариант для single rule агентов - можно указать в промте или rules: "прочитай инструкции из каталога xxx", - и т.об решить проблему. Но это менее надежно.
И главный вопрос - как избежать vendor lock и не нарушать DRY?
Делаем базовую папку с правилами, дале в Windows - создаем ссылку с помощью junction, в Linux - symlink.
И лучше добавить в .gitignore для надежности, чтобы случайно не задублировалось.
Для single rule агентов можно навайбкодить утилиту по склеиванию всех файлов в один, или использовать готовую cursor2claude.
Но вообще говоря эта область прям напрашивается на стандартизацию - либо через convention, либо через использование отдельного компонента.
#ai #ai_agents
Один файл:
Claude Code — CLAUDE.md
Gemini CLI — GEMINI.md
OpenAI Codex CLI — AGENTS.md
JetBrains Junie — .junie/guidelines.md
Папка с несколькими файлами:
Cursor — .cursor/rules/*.mdc
Windsurf — .windsurf/rules/*.md
Cline — .clinerules/*.md
Roocode — .roo/rules/*.md
GitHub Copilot — .github/instructions/*.instructions.md
JetBrains AI Assistant — .aiassistant/rules/*.md
Continue — .continue/rules/*.md
GigaCode - .gitverse/pr_rules/*.md (для версии на GitVerse)
Cline тут выделяется тем, что вообще говоря позволяет оба варианта - файл .clinerules или одноименный каталог.
Особенность Claude - кастомные команды, хранятся в кастомные команды в ~/.claude/commands/<name>.md. В принципе можно использовать и как аналог rule при явном указании в чате. Но без автозагрузки.
И еще сильнее выделяется OpenCode.
Он вначале пытается быть совместимым с OpenAI (AGENTS.md), если не нашел - с Claude Code (CLAUDE.md). А кроме того позволяет через customInstructions в opencode.json подключать произвольные файлы, включая загрузку по http, что является уникальной фичей.
Какие плюсы\минусы у этих подходов?
Один файл - простота.
Особенно учитывая тот факт, что практически ни один агент не дает менять имя файла\папки - т.е. имеем дело с convention over configuration во всей красе.
Пару слов про смену имени: единственное исключение - Gemini CLI, позволяет задать contextFileName в settings.json.
Еще в теории с этим подходом больше шансов получить непротиворечивые правила, но с ростом размера файла это преимущество нивелируется.
Каталог - а мне этот вариант кажется более удобным - имеет следующие плюсы:
1) если в репо лежит разнородный код, который пишут разные люди: фронт, бэк, devops, автотесты то удобнее, если у каждого будет свой файл с правилами. Да, AI способствует T-shape, но это пока что процесс, а не свершившийся факт.
2) несколько файлов точно легче читать и править человеку. А со слабыми моделями - возможно и LLM.
3) в теории при наличии нескольких файлов LLM исходя из текущей задачи сама могла бы выбрать только нужные, тем самым уменьшив расход токенов и контекстного окна и ускорив работу.
Обходной вариант для single rule агентов - можно указать в промте или rules: "прочитай инструкции из каталога xxx", - и т.об решить проблему. Но это менее надежно.
И главный вопрос - как избежать vendor lock и не нарушать DRY?
Делаем базовую папку с правилами, дале в Windows - создаем ссылку с помощью junction, в Linux - symlink.
И лучше добавить в .gitignore для надежности, чтобы случайно не задублировалось.
Для single rule агентов можно навайбкодить утилиту по склеиванию всех файлов в один, или использовать готовую cursor2claude.
Но вообще говоря эта область прям напрашивается на стандартизацию - либо через convention, либо через использование отдельного компонента.
#ai #ai_agents
Agile мир победил, микросервисы оказались сильней)
Вот данные из моей любимой книжки по разработке.
Медиану можно оценить ~9, среднее ~19, но среднее мало информативно из-за сильной правой асимметрии (маленьких команд сильно больше, чем больших).
Я бы из него сделал вывод, что микросервисы были всегда, просто раньше назывались по-другому — например, SOA (Service Oriented Architecture).
Но конечно ситуация меняется(хотел написать «не могла не измениться», но вспомнил свой же пост про двойное отрицание))) .
А вот более современные данные, не такие подробные.
Если сравнить 2003 и 2012 годы — медиана уменьшилась почти в 2 раза: 9 → 5.
Ещё есть данные опроса пользователей JetBrains (2024) https://www.jetbrains.com/lp/devecosystem-2024/
Медиана ≈ 6 человек, среднее ≈ 11. Примерно то же, что в 2012, только как ни странно числа стали чуть больше). Зато видно, что больших команд стало в 2+ раза меньше.
По моему опыту (кровавый enterprise) медианный размер команды на данный момент выше, ближе к 9. Но то, что 80% команд укладываются в 12 человек — сходится.
В 2003 году было ~60%.
Т.е. мы пока одной ногой шагнули в новую эру) enterprise требует жертв. Но тренд понятен.
О причинах — часть уже назвал: Agile и микросервисы. Ещё — улучшившийся инструментарий: IDE и фреймворки/библиотеки под любую потребность. А сейчас ещё и AI.
Так что думаю, что к 6 людям в команде мы все скоро придём. Будет ли меньше? В теории да: ВП, аналитик, 1–2 разработчика, тестировщик.
P.S. Т.к. в таблицах процент команд, а не процент людей - в командах более 12 человек все еще работает более 50% разработчиков. Было - более 80%. Интересно кто это?
P.P.S. Станет ли медианным значением 1 — ВП, который с помощью AI пилит и тестирует сервисы сам? ...Где-то да, уже сейчас. Но массово — может помешать Skynet. Или поспособствовать — сидишь себе в матрице, вайб-кодишь с AI микросервисы.
#book_review #agile #ai #microservices
Вот данные из моей любимой книжки по разработке.
Процентное соотношение проектов по размеру команды:
Размер команды | Доля
----------------|------
1–3 человека | 25%
4–10 человек | 30%
11–25 человек | 20%
26–50 человек | 15%
>50 человек | 10%
Источники: Beck and Perkins (1983), Highsmith (2002), Boehm and Turner (2003)
Медиану можно оценить ~9, среднее ~19, но среднее мало информативно из-за сильной правой асимметрии (маленьких команд сильно больше, чем больших).
Я бы из него сделал вывод, что микросервисы были всегда, просто раньше назывались по-другому — например, SOA (Service Oriented Architecture).
Но конечно ситуация меняется
А вот более современные данные, не такие подробные.
В исследовании Rodriguez et al. (JSS, 2012) на базе 951 проекта — 75% имели команду менее 10 человек. Медиана = 5, среднее ≈ 7.9.
Если сравнить 2003 и 2012 годы — медиана уменьшилась почти в 2 раза: 9 → 5.
Ещё есть данные опроса пользователей JetBrains (2024) https://www.jetbrains.com/lp/devecosystem-2024/
Размер команды | Доля
----------------|------
1 человек | 8%
2–7 человек | 49%
8–12 человек | 22%
13–20 человек | 10%
21–40 человек | 6%
>40 человек | 5%
Медиана ≈ 6 человек, среднее ≈ 11. Примерно то же, что в 2012, только как ни странно числа стали чуть больше). Зато видно, что больших команд стало в 2+ раза меньше.
По моему опыту (кровавый enterprise) медианный размер команды на данный момент выше, ближе к 9. Но то, что 80% команд укладываются в 12 человек — сходится.
В 2003 году было ~60%.
Т.е. мы пока одной ногой шагнули в новую эру) enterprise требует жертв. Но тренд понятен.
О причинах — часть уже назвал: Agile и микросервисы. Ещё — улучшившийся инструментарий: IDE и фреймворки/библиотеки под любую потребность. А сейчас ещё и AI.
Так что думаю, что к 6 людям в команде мы все скоро придём. Будет ли меньше? В теории да: ВП, аналитик, 1–2 разработчика, тестировщик.
P.S. Т.к. в таблицах процент команд, а не процент людей - в командах более 12 человек все еще работает более 50% разработчиков. Было - более 80%. Интересно кто это?
P.P.S. Станет ли медианным значением 1 — ВП, который с помощью AI пилит и тестирует сервисы сам? ...Где-то да, уже сейчас. Но массово — может помешать Skynet. Или поспособствовать — сидишь себе в матрице, вайб-кодишь с AI микросервисы.
#book_review #agile #ai #microservices
JetBrains: Developer Tools for Professionals and Teams
Software Developers Statistics 2024 - State of Developer Ecosystem Report
Explore key software developer statistics for 2024 in the State of Developer Ecosystem Report. Trends, insights, and tools shaping the developer world
👍1