Понимание внутреннего цикла
Внутренний цикл — это фундаментальная концепция разработки программного обеспечения, которая значительно влияет на производительность разработчика и циклы обратной связи. Понимание и оптимизация внутреннего цикла имеет решающее значение для эффективной практики DevOps и непрерывного улучшения.
Что такое внутренний цикл?
Внутренний цикл — это итеративный процесс, который разработчик выполняет при написании, создании и отладке кода. Он представляет быстрый цикл обратной связи , который происходит локально на компьютере разработчика, прежде чем код будет предоставлен совместно с командой или развернут в рабочей среде.
Основные характеристики
- Локальное выполнение: Выполняется полностью на рабочей станции разработчика
- Быстрая итерация: Предназначен для быстрого отзыва и быстрых изменений
- Частое повторение: Выполняется много раз в день во время активной разработки
- Индивидуальный фокус: Оптимизировано для продуктивности одного разработчика
- Действия перед коммитом: Происходит перед добавлением кода в систему управления версиями
Многие команды разработчиков считают важным сделать внутренний цикл как можно короче, так как более быстрая обратная связь приводит к повышению производительности и улучшению качества кода.
Вариации внутренних циклов в зависимости от технологии
Конкретные действия в внутреннем цикле разработчика значительно зависят от следующих действий:
- Используемые технологии: Языки программирования, платформы и среды выполнения
- Доступные средства: Среды разработки, системы сборки и платформы тестирования
- Параметры разработчика: Оптимизация и привычки отдельных рабочих процессов
- Тип проекта: Веб-приложения, библиотеки, микрослужбы или мобильные приложения
Пример. Внутренний цикл разработки библиотеки
Для разработки библиотеки типичный внутренний цикл включает:
- Кодирование: Написание или изменение кода библиотеки
- Здание: Компиляция библиотеки
- Тестирование: Запуск модульных тестов для проверки функциональности
- Отладка: Устранение проблем, обнаруженных во время тестирования
- Фиксация: Сохранение изменений в локальном репозитории Git
Пример: внутренний цикл разработки веб-интерфейсов
Для работы веб-интерфейса внутренний цикл оптимизирован по-разному:
- Кодирование: Изменение HTML, CSS и JavaScript
- Бандлинг: Запуск средств сборки (Webpack, Vite и т. д.)
- Обновление: Перезагрузите браузер, чтобы увидеть изменения
- Отладка: Использование средств разработки браузера для проверки поведения
- Фиксация: Сохранение изменений в локальном репозитории Git
Контекстное переключение
Большинство современных баз кода состоят из нескольких компонентов, поэтому внутренний цикл разработчика может быть альтернативным в зависимости от того, что работает:
- Api серверной части: Фокус на коде, сборке, тестировании, отладке
- Пользовательский интерфейс фронтенда: Фокус на коде, бандле, обновлении, проверке
- Схема базы данных: Фокус на миграции, тестировании, откате
- Инфраструктура: Сосредоточьтесь на конфигурации, развертывании, проверке
Классификация внутренних действий цикла
Шаги внутри внутреннего цикла можно сгруппировать в три широкие категории действий:
1. Экспериментирование
Действия, которые добавляют ценность клиента:
- Кодирование: Написание новых функций или исправление ошибок
- Проектирование: Архитектура планирования или пользовательские интерфейсы
- Прототипирования: Изучение новых подходов или решений
Характерный: Эти действия являются единственными, которые непосредственно добавляют значение в конечный продукт.
2. Сбор отзывов
Действия, которые проверяют качество:
- Сборка: Компиляция кода для проверки синтаксиса и зависимостей
- Тестирование: Выполнение модульных тестов для проверки функциональности
- Отладка: Выявление и устранение проблем
- Анализ кода: Запуск линтеров и статических анализаторов
Характеристика: Эти действия не добавляют ценность напрямую, но предоставляют важную обратную связь, чтобы обеспечить качество кода и корректность.
3. Налог
Действия, которые необходимы, но не добавляют ценность или отзывы:
- Коммит: Сохранение кода в систему управления версиями
- Конфигурация: Настройка сред сборки
- Синхронизация: Извлечение последних изменений из удаленных репозиториев
- Обновления документации: Обновление файлов или комментариев README
Характеристика: Эти действия необходимая работа, но они не добавляют ценности для клиента и не предоставляют обратную связь. Если действие ненужно, это отходы и должны быть устранены.
Пример классификации: разработка библиотеки
Для сценария разработки библиотеки:
| Activity | Категория | Purpose |
|---|---|---|
| Coding | Experimentation | Повышает ценность для клиента |
| Здание | Коллекция отзывов | Проверяет компиляцию кода |
| Тестирование и отладка | Коллекция отзывов | Проверяет функциональные возможности |
| Совершении | Налоги | Необходимо, но не добавляет значения |
Замечание
Размещение фиксации в налоговой категории может показаться суровым, но классификация помогает определить действия, которые следует свести к минимуму или отложить до абсолютной необходимости.
Оптимизация внутреннего цикла
Классифицировав шаги в цикле, теперь можно установить принципы оптимизации:
Основные принципы оптимизации
1. Скорость пропорционально изменению
- Цель: Выполнение цикла как можно быстрее
- Принцип: Общее время выполнения должно быть пропорционально размеру внесенных изменений.
- Выгода: Небольшие изменения получают быстрые отзывы; Крупные изменения занимают достаточно больше времени
2. Максимальное качество отзывов, минимизация времени обратной связи
- Цель: Получение наиболее полезных сведений в ближайшее время
- Принцип: Баланс между комплексным тестированием и быстрой итерацией
- Выгода: Быстро обнаружить критические проблемы при отложении менее критических проверок
3. Минимизация или отсрочка налога
- Цель: Сокращение ненужных затрат
- Принцип: Устранение отходов и отсрочка некритических действий
- Пример: Отложить обновления документации до момента фиксации изменений
4. Борьба с ростом сложности
- Вызов: По мере роста баз кода внутренние циклы естественно замедляются
- Причина: Больше кода означает больше тестов, зависимостей и времени сборки
- Влияние: Даже небольшие изменения требуют непропорционального времени для сбора отзывов
Проблема с монолитной базой кода
В больших монолитных базах кода можно столкнуться с ситуациями, в которых:
- Небольшое изменение: Модификация одной функции
- Непропорциональные затраты: Подождите 10+ минут для полной сборки и набора тестов
- Разочарование разработчика: Производительность снижается по мере замедления циклов обратной связи
- Переключение контекста: Разработчики теряют фокус, ожидая сборки
Это проблема, которую необходимо решать упреждающе.
Стратегии оптимизации большой базы кода
Команды могут использовать несколько стратегий для оптимизации внутреннего цикла для более крупных кодовых баз.
1. Добавочные сборки и тесты
Только сборка и проверка того, что изменилось:
- Интеллектуальные системы сборки: Обнаружение измененных файлов и перестроение только затронутых компонентов
- Выбор теста: Выполнение только тестов, затронутых изменениями кода
- Отслеживание зависимостей: Понимание того, какие тесты зависят от кода
- Инструменты: Использование систем сборки, таких как Bazel, Buck или Gradle с интеллектуальными добавочными сборками
Преимущества:
- Резко сокращено время сборки для небольших изменений
- Пропорциональное время обратной связи для изменения размера
- Более быстрые циклы итерации
2. Кэширование промежуточных результатов
Кэширование артефактов сборки для ускорения выполнения полных сборок:
- Локальное кэширование: Хранение скомпилированных объектов и результатов тестирования локально
- Распределенное кэширование: Совместное использование артефактов сборки между участниками команды
- Удаленное выполнение: Разгрузка компиляции в фермы облачных сборок
- Инструменты: Реализация кэширования с помощью таких систем, как ccache, sccache или облачные решения
Преимущества:
- Избегайте повторной компиляции кода, который не изменился
- Быстрая очистка сборок после переключения веток
- Сокращение времени работы конвейера CI/CD
Модульность и совместное использование бинарных файлов
Разбить базу кода на небольшие единицы и предоставить общий доступ к двоичным файлам:
- Извлечение библиотек: Извлечение общих функций в отдельные пакеты
- Определите границы: Создание четких интерфейсов модулей и зависимостей
- Пакеты версий: Публикация стабильных версий внутренних библиотек
- Управление зависимостями: Использование диспетчеров пакетов для использования стабильных версий
Предупреждение: Эта стратегия может быть обоюдоострым мечом, если она реализована неправильно (см. раздел "Запутанные циклы" ниже).
Преимущества при правильном выполнении:
- Меньшие единицы компиляции
- Независимое управление версиями и развертывание
- Более четкие архитектурные границы
- Повторно используемые компоненты в проектах
Риски при неправильном выполнении:
- Запутанные зависимости, требующие изменений в нескольких репозиториях
- Увеличение налога из-за накладных расходов внешнего цикла
- Проблемы несоответствия версий
Общие сведения о запутанных циклах
Концепция запутанных циклов иллюстрирует, что происходит при неправильной модульизации, что приводит к тому, что внутренние и внешние циклы становятся запутанными.
Внешний цикл
Прежде чем понимать запутанные циклы, необходимо определить внешний цикл:
Характеристики внешнего цикла:
- Совместная работа в команде: Код делится с командой через пул-реквесты
- Контрольные точки качества: Проверки кода, автоматизированное сканирование, проверки безопасности
- Интеграция: Код объединяется в основную ветвь и развертывается
- Более высокий налог: Дополнительные издержки из-за совместной работы и автоматизации
- Более медленная обратная связь: Минуты до часов вместо секунд до минут
Сценарий модульизации
Рассмотрим этот распространенный сценарий:
Начальное состояние: Монолитное приложение с фреймворком для конкретных приложений, который берет на себя основную нагрузку.
Решение модульной обработки: Извлеките платформу в отдельный пакет.
Этапы реализации:
- Извлечение кода в отдельный репозиторий: Код платформы перемещается в собственный репозиторий
- Настройка конвейера CI/CD: Автоматическая сборка и публикация пакета платформы
- Добавьте ворота качества: Обзор запросов на изменение, сканирование безопасности, рабочие процессы утверждения
- Публикация в виде пакета: Платформа становится зависимостью с версиями
Начальный результат: Вещи работают хорошо изначально. Монолит потребляет стабильные версии фреймворков.
При перепутывании
Сценарий проблемы: Необходимо разработать новую функцию , требующую обширных новых возможностей в платформе.
Точка боли: Теперь необходимо совместно развивать код в двух отдельных репозиториях с двоичной зависимостью между ними.
Что происходит:
- Добавление метода в платформу: Создание новой возможности в репозитории платформы
- Пройдите внешний цикл: Проверка кода, тесты, проверки безопасности, утверждение
- Дождитесь публикации пакета: Пакет платформы должен быть создан и опубликован
- Обновление приложения: Изменение приложения для использования нового метода платформы
- Повторять: Для каждой итерации требуется полный внешний цикл
Проблема: Внутренний цикл исходного кода теперь включает внешний цикл кода фреймворка.
Внешний налог на цикл
Внешний цикл включает значительный налог:
- Проверки кода: Дождитесь, пока рецензенты предоставят отзывы
- Проверка безопасности: Автоматизированные проверки уязвимостей и соответствия требованиям
- Двоичная подпись: Подписывание на основе сертификатов для опубликованных пакетов
- Конвейеры выпуска: Автоматизация развертывания и тестирование
- Шлюзы утверждения: Ручные утверждения для выпусков в производство
Влияние: Вы не хотите нести эту нагрузку каждый раз, когда добавляете метод в класс и хотите его немедленно использовать.
Обходные решения для разработчиков
Что обычно происходит:
Локальные взлома: Разработчики создают обходные пути для объединения внутренних циклов:
- Ссылки на локальный пакет: Наведите указатель на локальную файловую систему вместо опубликованного пакета
- Подмодули Git: Включите исходный код фреймворка непосредственно в приложение
- Ссылки на sym: Создание связей между репозиториями
- Пакеты предварительной версии: Публикация в тестовых веб-каналах
Следствие: Эти обходные пути быстро становятся запутанными и всё равно требуют уплаты налога на внешний цикл в конечном итоге.
Правильный способ модульизации
Модульная настройка по сути не плоха - она может работать блестяще при правильном выполнении:
Хорошая модульизация:
- Стабильные интерфейсы: Интерфейсы API платформы редко изменяются
- Независимая эволюция: Платформа и приложение развиваются отдельно
- Очистить границы: Четко определенные обязанности и контракты
- Свободное связывание: Минимальные зависимости между компонентами
Плохая модульизация:
- Жесткое связывание: Платформа и приложение должны меняться вместе
- Частое совместное развитие: Для каждой функции требуются изменения платформы
- Неясные границы: Обязанности перекрываются между компонентами
- Искусственное разделение: Разделение по организационным причинам, а не техническим причинам
Ключевой принцип: Тщательно сделайте модульные разрезы на основе фактических архитектурных границ, а не организационной структуры.
Лучшие практики для оптимизации внутреннего цикла
Мониторинг и измерение
Отслеживание метрик внутреннего цикла:
- Время сборки: Сколько времени занимает компиляция?
- Время выполнения теста: Сколько времени выполняются тесты?
- Задержка обратной связи: Время от сохранения до просмотра результатов
- Удовлетворенность разработчиков: Проведение опроса среди команды о проблемных аспектах
Средства измерения:
- Создание системной аналитики
- Профилировщики производительности интегрированной среды разработки
- Отчеты об исполнении тестов
- Опросы по производительности разработчиков
Проактивное устранение замедлений
Предупреждающие знаки:
- Разработчики жаловаются на медленные сборки
- Переключение контекста увеличивается во время ожидания сборки
- Локально команда начинает пропускать тесты
- Пул-реквесты включают непроверенный код
Стратегии реагирования:
- Немедленное изучение первопричин
- Приоритизируйте работу по оптимизации
- Участие всей команды в решениях
- Оценивать улучшения с течением времени
Баланс компромиссов
Основные компромиссы, которые следует учитывать:
| оптимизации | Преимущества | Cost |
|---|---|---|
| Добавочные сборки | Более быстрые локальные сборки | Сложная конфигурация сборки |
| Кэширование сборки | Быстрая очистка сборок | Расходы на хранение и сеть |
| Модульизация | Меньшие единицы компиляции | Потенциальные запутанные циклы |
| Меньше тестов | Более быстрый отзыв | Снижение достоверности |
| Параллельное выполнение | Более быстрое общее время | Более высокое использование ресурсов |
Принцип: Улучшение одного аспекта часто вызывает проблемы в другом. Непрерывная оценка компромиссов.
Согласованность команды
Общая ответственность:
- Архитекторы: Разработка с учетом тестируемости и модульности
- Разработчики: Создание эффективных тестов и предотвращение ненужных зависимостей
- DevOps: Предоставление инфраструктуры сборки и кэширования
- Управление: Сосредоточьте усилия на оптимизации внутреннего цикла
Культурные методики:
- Рассматривать внутреннее время цикла как ключевую метрику производительности
- Обеспечьте, чтобы "медленный прогресс" стал допустимой причиной для приостановки работ над функционалом.
- Празднование улучшений внутреннего цикла
- Совместное использование знаний по оптимизации между командами
Основные выводы
Помните следующие принципы:
- Нет серебряной пули: Универсальное решение для внутренней оптимизации цикла отсутствует
- Общие сведения о проблеме: Определить, когда происходит замедление и их первопричины
- Измеряйте все: Отслеживание метрик для понимания влияния изменений
- Действовать заранее: Устранение проблем, прежде чем они сильно влияют на производительность
- Баланс компромиссов: Каждая оптимизация имеет затраты; выбрать мудро
- Тщательно разрабатывайте модульность: Разделяйте базы кода на основе технических аспектов, а не удобства
- Непрерывное улучшение: Внутренняя оптимизация цикла продолжается
Архитектура имеет значение: Решения о том, как вы создаете, тестируете и выполняете отладку приложений, значительно влияет на производительность и счастье разработчиков. Вкладывайте время в освоение этих основ.