Чтобы дать вам небольшую предысторию: я работаю в компании с примерно двенадцатью разработчиками Ruby on Rails (+/- стажеры). Удаленная работа является распространенным явлением. Наш продукт состоит из двух частей: довольно толстое ядро и рассчитано на крупные клиентские проекты, основанные на нем. Заказчики обычно расширяют ядро. Перезаписи ключевых функций не происходит. Я мог бы добавить, что ядро имеет несколько довольно плохих частей, которые нуждаются в срочной реорганизации. Есть спецификации, но в основном для клиентских проектов. Худшая часть ядра не проверена (не так, как должно быть ...).
Разработчики разделены на две команды, работающие с одним или двумя ПО для каждого спринта. Обычно один клиентский проект строго связан с одной из команд и ПО.
Теперь наша проблема: довольно часто мы ломаем вещи друг друга. Кто-то из команды A расширяет или реорганизует основную функцию Y, вызывая непредвиденные ошибки в одном из клиентских проектов команды B. В основном, изменения не объявляются по командам, поэтому ошибки появляются почти всегда неожиданно. Команда B, включая ПО, считала функцию Y стабильной и не тестировала ее перед выпуском, не подозревая об изменениях.
Как избавиться от этих проблем? Какую «технику объявления» вы можете мне порекомендовать?
Ответы:
Я бы порекомендовал прочитать книгу « Эффективная работа с устаревшим кодом» Майкла С. Фезерса . Это объясняет, что вам действительно нужны автоматизированные тесты, как вы можете их легко добавить, если у вас их еще нет, и что «пахнет кодом» для рефакторинга и каким образом.
Кроме того, еще одной ключевой проблемой в вашей ситуации является отсутствие связи между двумя командами. Насколько велики эти команды? Работают ли они на разных бэках?
Практически всегда плохо разделять команды в соответствии с вашей архитектурой. Например, основная команда и непрофильная команда. Вместо этого я бы создавал команды в функциональной области, но с несколькими компонентами.
источник
Это проблема. Эффективный рефакторинг сильно зависит от набора автоматизированных тестов. Если у вас их нет, проблемы, которые вы описываете, начинают появляться. Это особенно важно, если вы используете динамический язык, такой как Ruby, где нет компилятора, который улавливал бы основные ошибки, связанные с передачей параметров в методы.
источник
Предыдущие ответы, которые указывают на лучшие юнит-тесты, хороши, но я чувствую, что, возможно, есть более фундаментальные проблемы, на которые следует обратить внимание. Вам нужны четкие интерфейсы для доступа к основному коду из кода для проектов заказчика. Таким образом, если вы реорганизуете основной код без изменения поведения, наблюдаемого через интерфейсы , код другой группы не будет нарушен. Это позволит намного легче узнать, что можно «безопасно» реорганизовать, а что нужно, возможно, сломать интерфейс, изменить дизайн.
источник
В других ответах были выделены важные моменты (больше юнит-тестов, функциональных команд, чистые интерфейсы с основными компонентами), но есть один момент, который я нахожу упущенным - это управление версиями.
Если вы замораживаете поведение своего ядра, выпуская выпуск 1, и помещаете этот выпуск в частную систему управления артефактами 2 , тогда любой проект клиента может объявить свою зависимость от базовой версии X , и он не будет нарушен в следующем выпуске X + 1 .
Тогда «политика объявления» сводится к наличию файла CHANGES вместе с каждым выпуском или к совещанию группы, на котором объявляются все функции каждого нового основного выпуска.
Кроме того, я думаю, что вам нужно лучше определить, что такое «ядро», а какое подмножество этого «ключ». Кажется, вы (правильно) избегаете внесения многих изменений в «ключевые компоненты», но допускаете частые изменения в «ядре». Чтобы на что-то положиться, вы должны сохранять его стабильность; если что-то не стабильно, не называйте это ядром. Может быть, я мог бы предложить назвать его «вспомогательными» компонентами?
РЕДАКТИРОВАТЬ : Если вы следуете соглашениям в системе семантического управления версиями , то любое несовместимое изменение в API ядра должно быть отмечено значительным изменением версии . То есть, когда вы изменяете поведение ранее существующего ядра или удаляете что-то, а не просто добавляете что-то новое. При таком соглашении разработчики знают, что обновление с версии «1.1» до «1.2» безопасно, но переход с «1.X» на «2.0» является рискованным и требует тщательного изучения.
1: я думаю, что это называется гем в мире Ruby
2: эквивалент Nexus в Java или PyPI в Python
источник
Как говорили другие люди, хороший набор модульных тестов не решит вашу проблему: у вас будут проблемы при объединении изменений, даже если каждый набор командных тестов пройдёт.
То же самое для TDD. Я не вижу, как это может решить это.
Ваше решение не является техническим. Вам нужно четко определить границы «ядра» и назначить кому-то роль «сторожевого пса», будь то ведущий разработчик или архитектор. Любые изменения в ядре должны проходить через этот сторожевой таймер. Он отвечает за то, чтобы все выходы всех команд сливались без особых побочных убытков.
источник
В качестве более долгосрочного решения вам также необходимо более эффективное и своевременное общение между командами. Каждая из команд, которые когда-либо будут использовать, например, базовую функцию Y, должна участвовать в создании запланированных тестовых сценариев для этой функции. Это планирование, само по себе, выделит различные варианты использования, присущие функции Y между двумя командами. После того, как функция должна работать, и тестовые сценарии реализованы и согласованы, необходимо внести дополнительные изменения в схему реализации. Команда, выпускающая эту функцию, должна запускать тестовый сценарий, а не команда, которая собирается ее использовать. Задача, если таковая имеется, которая должна вызывать коллизии, заключается в добавлении нового тестового сценария от любой из команд. Когда член команды думает о новом аспекте функции, которая не была протестирована, они могут свободно добавлять тестовый пример, который они подтвердили, передав в свою собственную песочницу. Таким образом, единственные столкновения, которые будут происходить, будут на уровне намерений, и должны быть зафиксированы до того, как переработанный объект будет выпущен в дикую природу.
источник
В то время как каждая система нуждается в эффективных наборах тестов (что подразумевает, помимо прочего, автоматизацию), и хотя эти тесты, при их эффективном использовании, обнаружат эти конфликты раньше, чем сейчас, это не решает основные проблемы.
Этот вопрос раскрывает как минимум две основные проблемы: практика изменения «ядра» для удовлетворения требований отдельных клиентов и неспособность команд общаться и координировать свои намерения вносить изменения. Ни одна из этих причин не является первопричиной, и вам нужно понять, почему это делается, прежде чем вы сможете это исправить.
Одна из первых вещей, которые необходимо определить, - понимают ли разработчики и менеджеры, что здесь есть проблема. Если, по крайней мере, некоторые это сделают, вам нужно выяснить, почему они либо думают, что ничего не могут с этим поделать, либо решают не делать этого. Для тех, кто этого не делает, вы можете попытаться увеличить их способность предвидеть, как их текущие действия могут создать будущие проблемы, или заменить их людьми, которые могут. Пока у вас нет рабочей силы, которая знает, как все идет не так, вы вряд ли сможете решить проблему (и, возможно, даже тогда, по крайней мере, в краткосрочной перспективе).
Может быть трудно проанализировать проблему в абстрактных терминах, по крайней мере на начальном этапе, поэтому сосредоточьтесь на конкретном инциденте, который привел к проблеме, и попытайтесь определить, как это произошло. Поскольку вовлеченные люди, вероятно, будут защищаться, вам нужно быть готовым к корыстным и постфактумным оправданиям, чтобы выяснить, что на самом деле происходит.
Есть одна возможность, которую я стесняюсь упомянуть, потому что это очень маловероятно: требования клиентов настолько несопоставимы, что недостаточно, чтобы оправдать общий код ядра. Если это так, то у вас фактически есть несколько отдельных продуктов, и вы должны управлять ими как таковыми, а не создавать искусственную связь между ними.
источник
Мы все знаем, что юнит тесты - это путь. Но мы также знаем, что реально установить их в ядро сложно.
Конкретный метод, который может быть полезен для вас при расширении функциональности, - это попытаться временно и локально проверить, что существующая функциональность не была изменена. Это можно сделать так:
Оригинальный псевдокод:
Временный тестовый код на месте:
Запустите эту версию через любые существующие тесты системного уровня. Если все в порядке, вы знаете, что ничего не сломали, и можете приступить к удалению старого кода. Обратите внимание, что когда вы проверяете совпадение старых и новых результатов, вы также можете добавить код для анализа различий, чтобы зафиксировать случаи, которые, как вы знаете, должны отличаться из-за предполагаемого изменения, такого как исправление ошибки.
источник
« В основном, эти изменения не объявлены над командами, так что ошибки ударил почти всегда неожиданно»
Коммуникации проблемы кого - нибудь? Как насчет (в дополнение к тому, что все остальные уже указали, что вы должны проходить тщательное тестирование), чтобы убедиться, что есть правильное общение? Чтобы люди знали, что интерфейс, к которому они пишут, изменится в следующем выпуске, и какими будут эти изменения?
И предоставьте им доступ как минимум к фиктивному взаимодействию (с пустой реализацией) как можно скорее во время разработки, чтобы они могли начать писать свой собственный код.
Без всего этого, модульные тесты мало что дадут, кроме того, что на последних этапах укажут, что между частями системы что-то не так. Вы хотите знать это, но вы хотите знать это рано, очень рано, и чтобы команды разговаривали друг с другом, координировали усилия и фактически имели частый доступ к работе, выполняемой другой командой (так что регулярные коммиты, а не один массовый совершать через несколько недель или месяцев, за 1-2 дня до родов).
Ваша ошибка НЕ в коде, конечно, не в коде другой команды, которая не знала, что вы возитесь с интерфейсом, против которого они пишут. Ваша ошибка в процессе разработки, отсутствие общения и сотрудничества между людьми. То, что вы сидите в разных комнатах, не означает, что вы должны изолировать себя от других парней.
источник
Прежде всего, у вас есть проблема со связью (вероятно, также связанная с проблемой построения команды ), поэтому я думаю, что решение вашего дела должно быть сосредоточено на ... ну, а не на методах разработки, а на общении.
Я считаю само собой разумеющимся, что невозможно замораживать или разветвлять основной модуль при запуске клиентского проекта (в противном случае вам просто нужно интегрировать в графики своей компании некоторые не связанные с клиентами проекты, направленные на обновление основного модуля).
Таким образом, мы остаемся с проблемой улучшения коммуникации между командами. Это можно решить двумя способами:
Вы можете найти больше информации о КИ как процессе общения здесь .
Наконец, у вас все еще есть проблема с отсутствием командной работы на уровне компании. Я не большой поклонник событий тимбилдинга, но это похоже на случай, когда они будут полезны. У вас есть встречи на уровне разработчиков на регулярной основе? Можете ли вы пригласить людей из других команд на ретроспективу вашего проекта? Или, может быть, иногда есть пиво в пятницу вечером?
источник