"Цените легкость чтения кода выше, чем удобство его написания"
Я постоянно топлю за то, что код должен легко читаться.
И цитата из сами понимаете какой книжки как нельзя лучше иллюстрирует данный принцип.
Т.к. если не задумываться об удобстве чтения кода, то мы получаем:
1) дублирование - проще же скопировать, чем выделить новую абстракцию
2) вечный техдолг из-за не проведенного вовремя рефакторинга
3) божественные классы: пусть новый метод Y не вписывается в абстракцию класса Х, но чтобы это заметить - надо выйти за рамки текущей задачи
4) огромные иерархии классов, длинные методы - проще добавить код по аналогии
5) слабое покрытие тестами - код работает, мне он на данный момент абсолютно понятен. Зачем тесты писать - ради тестов?
6) методы и классы с неактуальными названиями
7) все методы в классе являются public - они же вызываются из public метода, да и вдруг кому-то пригодятся
8) спагетти-код
...
и получаем легаси в итоге.
#book_review
Я постоянно топлю за то, что код должен легко читаться.
И цитата из сами понимаете какой книжки как нельзя лучше иллюстрирует данный принцип.
Т.к. если не задумываться об удобстве чтения кода, то мы получаем:
1) дублирование - проще же скопировать, чем выделить новую абстракцию
2) вечный техдолг из-за не проведенного вовремя рефакторинга
3) божественные классы: пусть новый метод Y не вписывается в абстракцию класса Х, но чтобы это заметить - надо выйти за рамки текущей задачи
4) огромные иерархии классов, длинные методы - проще добавить код по аналогии
5) слабое покрытие тестами - код работает, мне он на данный момент абсолютно понятен. Зачем тесты писать - ради тестов?
6) методы и классы с неактуальными названиями
7) все методы в классе являются public - они же вызываются из public метода, да и вдруг кому-то пригодятся
8) спагетти-код
...
и получаем легаси в итоге.
#book_review
Рубрика "Загадки от Стива".
Если объект класса создается в коде всего один раз - стоит заменить такой класс объектом.
О чем речь?
Пример:
у нас есть разные виды карт: Мир, Мир Supreme, Visa Classic, Visa Digital..
Можно завести под каждый тип отдельный подкласс, но в большинстве случае достаточно параметризовать все отличия разных типов карт и просто создавать объекты одного класса.
#book_review #oop
Если объект класса создается в коде всего один раз - стоит заменить такой класс объектом.
О чем речь?
у нас есть разные виды карт: Мир, Мир Supreme, Visa Classic, Visa Digital..
Можно завести под каждый тип отдельный подкласс, но в большинстве случае достаточно параметризовать все отличия разных типов карт и просто создавать объекты одного класса.
#book_review #oop
Ещё один элемент AI-пазла.
Сделаю паузу по книжке.
У нас есть стандарт для получения данных из внешних источников (MCP), потенциальный протокол для запросов в LLM (TOON, хотя тут борьба ещё впереди), паттерн локальной БД (RAG), стандарт памяти для контекста (GAM), навыков агентов (Agent Skills), реестр opensource-моделей (HuggingFace).
Если смотреть на агентов и их локальные возможности, в частности для разработки и смежных активностей, то тут можно найти место для стандарта. Что делает такой агент: читает файлы (код), создаёт и меняет их, запускает команды в консоли и анализирует вывод, возможно запускает браузер. Также — запуск скилов и вызов MCP. Плюс мультиагентность — отдельно агенты для планирования, правки кода, возможно тестирования...
Вот всё это реализует OpenCode https://opencode.ai/. Плюс работа с сессиями, аутентификация у разных провайдеров LLM, выбор модели и даже sharing сессии. Обещают, что, кроме режима sharing, на сервер ничего не шлют.На свой сервер, на сервер LLM конечно же шлют.
Но есть поддержка Ollama для запуска моделей локально. Ещё интересно, что инструмент поддерживает три типа взаимодействия: консоль, web и TUI. TUI — Terminal User Interface. И это реальный консольный UI. Вспоминается MS DOS и Norton Commander. Попробовал — мне понравилось. Удобно.
Минусы:
- для установки и шаринга сессии нужен VPN;
- кроме основной модели есть ещё так называемая small model, в качестве которой у меня OpenCode сам выбрал платную модель OpenRouter (а основную модель я выбрал там же бесплатную) и втихаря сожрал 5 центов за час.
А вообще классная штука, в первую очередь для разработки, но вижу пользу и для анализа данных, тестирования...
P. S. Вот только в стане фреймворков разработки агентов всё ещё разброд и шатание, хотя для Python выделяется пара LangChain/LangGraph.
#ai #llm
Сделаю паузу по книжке.
У нас есть стандарт для получения данных из внешних источников (MCP), потенциальный протокол для запросов в LLM (TOON, хотя тут борьба ещё впереди), паттерн локальной БД (RAG), стандарт памяти для контекста (GAM), навыков агентов (Agent Skills), реестр opensource-моделей (HuggingFace).
Если смотреть на агентов и их локальные возможности, в частности для разработки и смежных активностей, то тут можно найти место для стандарта. Что делает такой агент: читает файлы (код), создаёт и меняет их, запускает команды в консоли и анализирует вывод, возможно запускает браузер. Также — запуск скилов и вызов MCP. Плюс мультиагентность — отдельно агенты для планирования, правки кода, возможно тестирования...
Вот всё это реализует OpenCode https://opencode.ai/. Плюс работа с сессиями, аутентификация у разных провайдеров LLM, выбор модели и даже sharing сессии. Обещают, что, кроме режима sharing, на сервер ничего не шлют.На свой сервер, на сервер LLM конечно же шлют.
Но есть поддержка Ollama для запуска моделей локально. Ещё интересно, что инструмент поддерживает три типа взаимодействия: консоль, web и TUI. TUI — Terminal User Interface. И это реальный консольный UI. Вспоминается MS DOS и Norton Commander. Попробовал — мне понравилось. Удобно.
Минусы:
- для установки и шаринга сессии нужен VPN;
- кроме основной модели есть ещё так называемая small model, в качестве которой у меня OpenCode сам выбрал платную модель OpenRouter (а основную модель я выбрал там же бесплатную) и втихаря сожрал 5 центов за час.
А вообще классная штука, в первую очередь для разработки, но вижу пользу и для анализа данных, тестирования...
P. S. Вот только в стане фреймворков разработки агентов всё ещё разброд и шатание, хотя для Python выделяется пара LangChain/LangGraph.
#ai #llm
opencode.ai
OpenCode | The open source AI coding agent
OpenCode - The open source coding agent.
Еще одна загадка "от Стива":
Цитата:
"В одном исследовании 450 методов было обнаружено, что дефекты отсутствовали у 50% методов, обладающих высокой связностью,
и только в 18% методов с низкой связностью (Card, Church, and Agresti, 1986).
Другое исследование методов (это просто совпадение, хотя и весьма необычное) показало,
что в сравнении с методами, имеющими самое низкое отношение «сопряжение/связность» (coupling-to-cohesion),
методы с максимальным отношением «сопряжение/связность» содержали в 7 раз больше ошибок,
а исправление этих методов было в 20 раз более дорогим (Selby and Basili, 1991)."
Речь про то, что в методах с высокой связностью кода - single responsibility по сути - меньше ошибок.
Почему?
Мой ответ:
низкая связность может иметь одну из двух причин:
1) плохое проектирование = больше ошибок
2) плохо проведенный\не проведенный вовремя рефакторинг, когда в метод добавили новый функционал, "гвоздями прибив" его к существующему без нормального тестирования
Ну и банально - больше функционала в методе = больше метод = больше вероятность ошибки. Но тут зависимость не линейная, при нормальном проектировании.
#book_review #quest
Цитата:
"В одном исследовании 450 методов было обнаружено, что дефекты отсутствовали у 50% методов, обладающих высокой связностью,
и только в 18% методов с низкой связностью (Card, Church, and Agresti, 1986).
Другое исследование методов (это просто совпадение, хотя и весьма необычное) показало,
что в сравнении с методами, имеющими самое низкое отношение «сопряжение/связность» (coupling-to-cohesion),
методы с максимальным отношением «сопряжение/связность» содержали в 7 раз больше ошибок,
а исправление этих методов было в 20 раз более дорогим (Selby and Basili, 1991)."
Речь про то, что в методах с высокой связностью кода - single responsibility по сути - меньше ошибок.
Почему?
низкая связность может иметь одну из двух причин:
1) плохое проектирование = больше ошибок
2) плохо проведенный\не проведенный вовремя рефакторинг, когда в метод добавили новый функционал, "гвоздями прибив" его к существующему без нормального тестирования
Ну и банально - больше функционала в методе = больше метод = больше вероятность ошибки. Но тут зависимость не линейная, при нормальном проектировании.
#book_review #quest
🔥1
И еще один вопрос от Стива, попроще:
"Используйте утвердительные имена булевых переменных"
Почему?
Ответ:
чтобы избежать вот такого кода:
if ((!notFound) && ... )
затрудняющего чтение.
А кстати в Python все еще хуже:
if (not notFound) and ...:
#book_review
"Используйте утвердительные имена булевых переменных"
Почему?
чтобы избежать вот такого кода:
if ((!notFound) && ... )
затрудняющего чтение.
А кстати в Python все еще хуже:
if (not notFound) and ...:
#book_review
Долговременное хранение контекста AI агента - можно ли попроще?
Я уже писал про GAB - систему хранения контекста диалога https://t.me/javaKotlinDevOps/495.
Напомню тем кто забыл - там два компонента Memorizer (фоновое сохранение данных) и Researcher (компиляция ответа под конкретный запрос пользователя) и два вида памяти: весь диалог и короткие сводки (кэш).
И в целом GAB - это научная работа без практического внедрения.
Когда появится реализация - это будет отдельный сервис а-ля RAG.
Так вот - как можно сделать примерно тоже самое проще? Например, в контексте агента для разработки
Краткий ответ - можно. Подробный - давайте напишем промт для агента с просьбой собрать, сохранить и поддерживать актуальность информации по проекту внутри проекта в текстовых файлах.
Пусть это будет Markdown как некий стандарт, сложившийся не только в AI.
Т.е. процесс выглядит так:
1) инициализируем память собрав всю информацию по проекту и сохранив ее
2) при старте любого диалога подтягиваем информацию
2) после успешного выполнения любых действий над проектом обновляем\чистим информацию в долговременной памяти
Как говорится - ближе к делу.
Встречаем Cline Memory Bank https://docs.cline.bot/prompting/cline-memory-bank
На что стоит обратить внимание:
1) лично я когда говорил о долговременной памяти - я подразумевал контекст сессии.
На самом деле не обязательно им ограничиваться.
В случае разработки - сессия = таска, а контекст по проекту имеет смысл хранить постоянно.
Т.е по сути он разделяется на постоянную часть и текучку.
На примере Cline Memory Bank постоянная часть:
Текучка:
2) Является ли такая структура памяти оптимальной? Хз, но я бы с нее начал.
3) что с поддержкой данной штуки в других агентах? без проблем, т.к. по сути memory bank = промт + способность агента читать и писать в файл.
Пример для Cursor https://www.youtube.com/watch?v=azXNHRtzd5s
Roo Code решили обвернуть это в MCP сервер https://skywork.ai/skypage/en/roo-code-memory-bank-ai-agent/1980851096638783488
Почему бы и нет, поможет при разработке других агентов, причем это могут быть агенты с разным назначением.
4) в Memory Bank хранится информация по архитектуре\структуре проекта, его стек, команды запуска, code style и прочие правила работы.
И если они уже есть в проекте - можно просто их переиспользовать, стандартизировав место хранения.
5) что из этого хранить в git? постоянную часть точно, текучку - наверное нет, т.к. у каждого она своя, но надо смотреть
В общем - рекомендую, сам буду настраивать на всех проектах.
P.S. если сравнить два подхода GAB vs Memory Bank - это как JIT и AoT компиляция
#ai #ai_agents #mcp
Я уже писал про GAB - систему хранения контекста диалога https://t.me/javaKotlinDevOps/495.
Напомню тем кто забыл - там два компонента Memorizer (фоновое сохранение данных) и Researcher (компиляция ответа под конкретный запрос пользователя) и два вида памяти: весь диалог и короткие сводки (кэш).
И в целом GAB - это научная работа без практического внедрения.
Когда появится реализация - это будет отдельный сервис а-ля RAG.
Так вот - как можно сделать примерно тоже самое проще? Например, в контексте агента для разработки
Краткий ответ - можно. Подробный - давайте напишем промт для агента с просьбой собрать, сохранить и поддерживать актуальность информации по проекту внутри проекта в текстовых файлах.
Пусть это будет Markdown как некий стандарт, сложившийся не только в AI.
Т.е. процесс выглядит так:
1) инициализируем память собрав всю информацию по проекту и сохранив ее
2) при старте любого диалога подтягиваем информацию
2) после успешного выполнения любых действий над проектом обновляем\чистим информацию в долговременной памяти
Как говорится - ближе к делу.
Встречаем Cline Memory Bank https://docs.cline.bot/prompting/cline-memory-bank
На что стоит обратить внимание:
1) лично я когда говорил о долговременной памяти - я подразумевал контекст сессии.
На самом деле не обязательно им ограничиваться.
В случае разработки - сессия = таска, а контекст по проекту имеет смысл хранить постоянно.
Т.е по сути он разделяется на постоянную часть и текучку.
На примере Cline Memory Bank постоянная часть:
`projectbrief.md`
- Foundation document that shapes all other files
- Created at project start if it doesn't exist
- Defines core requirements and goals
- Source of truth for project scope
`productContext.md`
- Why this project exists
- Problems it solves
- How it should work
- User experience goals
`systemPatterns.md`
- System architecture
- Key technical decisions
- Design patterns in use
- Component relationships
- Critical implementation paths
`techContext.md`
- Technologies used
- Development setup
- Technical constraints
- Dependencies
- Tool usage patterns
Текучка:
`activeContext.md`
- Current work focus
- Recent changes
- Next steps
- Active decisions and considerations
- Important patterns and preferences
- Learnings and project insights
`progress.md`
2) Является ли такая структура памяти оптимальной? Хз, но я бы с нее начал.
3) что с поддержкой данной штуки в других агентах? без проблем, т.к. по сути memory bank = промт + способность агента читать и писать в файл.
Пример для Cursor https://www.youtube.com/watch?v=azXNHRtzd5s
Roo Code решили обвернуть это в MCP сервер https://skywork.ai/skypage/en/roo-code-memory-bank-ai-agent/1980851096638783488
Почему бы и нет, поможет при разработке других агентов, причем это могут быть агенты с разным назначением.
4) в Memory Bank хранится информация по архитектуре\структуре проекта, его стек, команды запуска, code style и прочие правила работы.
И если они уже есть в проекте - можно просто их переиспользовать, стандартизировав место хранения.
5) что из этого хранить в git? постоянную часть точно, текучку - наверное нет, т.к. у каждого она своя, но надо смотреть
В общем - рекомендую, сам буду настраивать на всех проектах.
P.S. если сравнить два подхода GAB vs Memory Bank - это как JIT и AoT компиляция
#ai #ai_agents #mcp
Telegram
(java || kotlin) && devOps
Заметка про стандартизацию AI.
Вот и кандидат на стандарт для хранения контекста диалога подъехал https://habr.com/ru/companies/bothub/news/972054 Не факт, что именно эта технология, см. Китай и Гонконг, но сам принцип вполне может стать стандартом.
P.S.…
Вот и кандидат на стандарт для хранения контекста диалога подъехал https://habr.com/ru/companies/bothub/news/972054 Не факт, что именно эта технология, см. Китай и Гонконг, но сам принцип вполне может стать стандартом.
P.S.…
Что не докрутили в record-ах?
Для начала кратко о том, что докрутили:
1) компактное объявление, типовые методы из коробки
2) иммутабельность
3) минимально необходимая расширяемость - дополнительные конструкторы, интерфейсы, обычные методы, статические поля, методы и внутренние классы.
Получаем аналог data class в Kotlin. Или структур из древних языков типа C.
Но с небольшим отличием - не хватает метода копирования "из коробки".
Почему так сделали? Есть же Cloneable интерфейс. И его даже можно добавить в record руками.
Думаю, причина в иммутабельности record и скажем так скомпрометированности clone().
Для иммутабельной сущности нет смысла в полной копии - можно использовать текущий объект.
С clone() основная проблема в том, что "из коробки" он делает поверхностную копию, но при переопределении может дать полную. И вообще полную копию автоматически сделать сложно. А это приводит к путанице - метод один, а поведение может отличаться.
В итоге приходим к тому, что иметь возможность быстро сделать поверхностную копию записи с изменением пары полей было бы неплохо. И такой JEP есть https://openjdk.org/jeps/468
Надеюсь внедрят.
#java #иммутабельность
Для начала кратко о том, что докрутили:
1) компактное объявление, типовые методы из коробки
2) иммутабельность
3) минимально необходимая расширяемость - дополнительные конструкторы, интерфейсы, обычные методы, статические поля, методы и внутренние классы.
Получаем аналог data class в Kotlin. Или структур из древних языков типа C.
Но с небольшим отличием - не хватает метода копирования "из коробки".
Почему так сделали? Есть же Cloneable интерфейс. И его даже можно добавить в record руками.
Думаю, причина в иммутабельности record и скажем так скомпрометированности clone().
Для иммутабельной сущности нет смысла в полной копии - можно использовать текущий объект.
С clone() основная проблема в том, что "из коробки" он делает поверхностную копию, но при переопределении может дать полную. И вообще полную копию автоматически сделать сложно. А это приводит к путанице - метод один, а поведение может отличаться.
В итоге приходим к тому, что иметь возможность быстро сделать поверхностную копию записи с изменением пары полей было бы неплохо. И такой JEP есть https://openjdk.org/jeps/468
Надеюсь внедрят.
#java #иммутабельность
AI как база знаний.
В разработке есть проблема передачи знаний.
Есть разные способы - обучение, книги, онлайн контент, конференции, поиск, общение с коллегами и вот теперь AI.
Я уже писал, что AI вытесняет поиск и т.об. приводит к смерти сайтов типа stack-overflow.
Но может ли общение с LLM заменить все источники?
Т.е. есть разраб и сильная LLM, и больше ничего не надо?
Если говорить про источник знаний, то ключевые его характеристики IMHO - скорость поиска, структурированность изложения, полнота и точность.
В плане скорости AI пожалуй лучший. Это реальный прорыв
Структурированность - по большинству ответом LLM видно, что системные промты у них заточены на это.
Там и объяснения, и ссылки, и вывод, и рекомендации. А это важно, чтобы разработчик понимал, почему предлагается то или иное решение.
А вот с полнотой и точностью вечные проблемы.
Почему вечные?
В LLM по определению не может попасть вся информация.
Части нет в цифровом виде вообще. Часть "под замком" - во внутренних сетях компаний.
Часть потерялась при "сжатии" как несущественная. И к слову теряется еще сильней при квантизации LLM для запуска на более слабых устройствах.
С точностью главная беда в том, что модели почему-то не могут четко разграничить - вот точные знания, вот предположение и ссылки для самостоятельного изучения.
А пытаются скомпилировать ответ из того, что знают. Не знаю, насколько это можно пофиксить в будущем обучением, но пока так.
В теории можно фиксить проверками кода перед выдачей пользователю, хотя это более трудоемкий и концептуально плохой путь (перебор по сути).
Второй источник проблем с точностью - отсутствие метаданных в модели, в частности по версиям ПО, ОС, железа ... для которых применим тот или иной код.
В итоге что мы получаем?
LLM может сильно ускорить разработку, если ты в целом знаешь предметную область, умеешь искать информацию и критически ее анализировать.
Т.е. поможет миддлам и синьорам.
А вот джуну кажется AI способен навредить, убив в зародыше навыки, упомянутые выше.
Ну и разраб, принципиально отказывающий от AI, будет в проигрыше.
И подытоживая - в любом случае AI сильно ускоряет обмен знаниями.
#ai #knowledge_base
В разработке есть проблема передачи знаний.
Есть разные способы - обучение, книги, онлайн контент, конференции, поиск, общение с коллегами и вот теперь AI.
Я уже писал, что AI вытесняет поиск и т.об. приводит к смерти сайтов типа stack-overflow.
Но может ли общение с LLM заменить все источники?
Т.е. есть разраб и сильная LLM, и больше ничего не надо?
Если говорить про источник знаний, то ключевые его характеристики IMHO - скорость поиска, структурированность изложения, полнота и точность.
В плане скорости AI пожалуй лучший. Это реальный прорыв
Структурированность - по большинству ответом LLM видно, что системные промты у них заточены на это.
Там и объяснения, и ссылки, и вывод, и рекомендации. А это важно, чтобы разработчик понимал, почему предлагается то или иное решение.
А вот с полнотой и точностью вечные проблемы.
Почему вечные?
В LLM по определению не может попасть вся информация.
Части нет в цифровом виде вообще. Часть "под замком" - во внутренних сетях компаний.
Часть потерялась при "сжатии" как несущественная. И к слову теряется еще сильней при квантизации LLM для запуска на более слабых устройствах.
С точностью главная беда в том, что модели почему-то не могут четко разграничить - вот точные знания, вот предположение и ссылки для самостоятельного изучения.
А пытаются скомпилировать ответ из того, что знают. Не знаю, насколько это можно пофиксить в будущем обучением, но пока так.
В теории можно фиксить проверками кода перед выдачей пользователю, хотя это более трудоемкий и концептуально плохой путь (перебор по сути).
Второй источник проблем с точностью - отсутствие метаданных в модели, в частности по версиям ПО, ОС, железа ... для которых применим тот или иной код.
В итоге что мы получаем?
LLM может сильно ускорить разработку, если ты в целом знаешь предметную область, умеешь искать информацию и критически ее анализировать.
Т.е. поможет миддлам и синьорам.
А вот джуну кажется AI способен навредить, убив в зародыше навыки, упомянутые выше.
Ну и разраб, принципиально отказывающий от AI, будет в проигрыше.
И подытоживая - в любом случае AI сильно ускоряет обмен знаниями.
#ai #knowledge_base
👍1
Может ли бюрократия быть полезной?)
Я про разработку.
И если вы сейчас думаете, что я расскажу, как многочисленные согласования:
1) текстовок и дизайна
2) рисков
3) квоты на железо (а планировать ее надо было в прошлом году...)
4) концептуальной архитектуры и архитектуры АС
5) тестовой модели
6) профиля нагрузки
7) требований сопровождения
8) и конечно же безопасности
приносит пользу команде... то нет.
Определенную пользу команде они приносят, но сейчас хочу сделать акцент на другом.
Мы живем в мире победивших микросервисов.
Я наблюдаю за тем, как люди проектируют новые сервисы и как говорят о существующих.
Вот несколько зарисовок:
1) давайте условный сервис блогов сразу разделим на микросервисы для создания постов, чтения постов, работы с комментами...
И при этом пусть работают с одной БД(
2) ну вот тут у нас большой сервис, можно сказать монолит (и чувствуется, что это слово ругательное), т.к не дали нам его нормально на микросервисы распилить.
Что тут хочется сказать. Есть такая штука - преждевременная оптимизация. Это когда ты во время проектирования или написания первой версии сервиса, до НТ и проверки на реальной нагрузке, пытаешься оптимизировать код.
И вроде как все знают, что это плохо.
Но как речь заходит про микросервисы - сразу про преждевременную оптимизацию забываем и пытаемся сделать наносервисы.
Так вот - тут нам на помощь приходит бюрократия.
Если для вывода нового сервиса нужно пройти 7+ кругов ада (а именно при выводе нового сервиса нужно пройти максимальное число кругов) - тут точно команда задумается, а не рано ли делить стали)))
#microservices #arch
Я про разработку.
И если вы сейчас думаете, что я расскажу, как многочисленные согласования:
1) текстовок и дизайна
2) рисков
3) квоты на железо (а планировать ее надо было в прошлом году...)
4) концептуальной архитектуры и архитектуры АС
5) тестовой модели
6) профиля нагрузки
7) требований сопровождения
8) и конечно же безопасности
приносит пользу команде... то нет.
Определенную пользу команде они приносят, но сейчас хочу сделать акцент на другом.
Мы живем в мире победивших микросервисов.
Я наблюдаю за тем, как люди проектируют новые сервисы и как говорят о существующих.
Вот несколько зарисовок:
1) давайте условный сервис блогов сразу разделим на микросервисы для создания постов, чтения постов, работы с комментами...
И при этом пусть работают с одной БД(
2) ну вот тут у нас большой сервис, можно сказать монолит (и чувствуется, что это слово ругательное), т.к не дали нам его нормально на микросервисы распилить.
Что тут хочется сказать. Есть такая штука - преждевременная оптимизация. Это когда ты во время проектирования или написания первой версии сервиса, до НТ и проверки на реальной нагрузке, пытаешься оптимизировать код.
И вроде как все знают, что это плохо.
Но как речь заходит про микросервисы - сразу про преждевременную оптимизацию забываем и пытаемся сделать наносервисы.
Так вот - тут нам на помощь приходит бюрократия.
Если для вывода нового сервиса нужно пройти 7+ кругов ада (а именно при выводе нового сервиса нужно пройти максимальное число кругов) - тут точно команда задумается, а не рано ли делить стали)))
#microservices #arch
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