Существует ли принцип разработки программного обеспечения, который связывает затраты на повторное использование и регрессионное тестирование в производственной системе?

12

Я работал над крупной системой финансовых транзакций для банка, который заботился о пенсиях и инвестициях. После 15 лет изменений функций стоимость ручного регрессионного тестирования поднялась до 200 тыс. Долл. За выпуск. (10 миллионов LOC, 10 миллионов долларов США в день). Эта система также взаимодействует с 19 другими системами вокруг компании, перемещая большое количество данных. Эта система была реализована на Java.

Однако мы наблюдаем, что чем больше «повторного использования» мы делаем, тем больше растут затраты на регрессионное тестирование. (Причина в том, что вам нужно «протестировать код, к которому вы прикасаетесь» - и повторно используемый / совместно используемый код влияет на множество мест при прикосновении к нему. Поэтому, несмотря на «СУХОЙ - НЕ ПОВТОРЯЙТЕСЯ» - т.е. не копируйте и не вставляйте код - мы наблюдаем финансовый стимул для копирования и вставки кода. Это должно снизить затраты на регрессионное тестирование, потому что мы не хотим изменять код, который можно было бы использовать совместно, потому что это вызовет большое влияние регрессионного теста.)

Мой вопрос: существует ли принцип разработки программного обеспечения, который описывает взаимосвязь между повторным использованием и затратами на регрессионное тестирование?

Причина, по которой я бы задал этот вопрос, состоит в том, что, возможно, есть ценовая выгода в разложении системы на более мелкие части, которые будут тестироваться.

Предположения:

  1. «Регрессивный тест» означает «приемочный тест», т. Е. Другая группа тратит время на написание новых и повторное использование старых тестов для системы от имени бизнеса, включая настройки среды и данных.

  2. Я знаю, что реакция коленного рефлекса на большие затраты на регрессионное тестирование - это «более автоматизированные тесты». Это хороший принцип. В этой среде есть несколько проблем.

    (a) Автоматизированные тесты менее полезны через границы системы, если только эта система также не имеет высокого охвата автоматизированных тестов. (Сфера влияния вызов).

    (б) С культурной точки зрения трудно получить импульс от времени программистов или капиталовложений на высокий охват автоматизированных тестов, когда ваша система уже большая и сложная.

    (c) Стоимость обслуживания автоматических тестов скрыта в проекте, и поэтому они легко отбрасываются на уровне проекта.

    (г) Это просто культурная реальность работы в банке.

    (д) Я работаю, чтобы решить эту проблему по-другому (разложение).

Hawkeye
источник
2
Вы делаете смутное заявление, что « мы наблюдаем […], что чем больше« повторного использования »мы делаем, тем больше растут затраты на [приемочные] испытания » - не могли бы вы остановиться на этом? Разве приемочный тест не должен быть независим от деталей реализации, таких как иерархии наследования, и вместо этого воспроизводить, например, сценарии использования?
Амон
2
Ваш вопрос интересен, но он содержит некоторые очень предвзятые предположения, такие как «повторное использование является следствием ОО» или упомянутая часть @amon. Я предлагаю вам полностью удалить часть «ОО», поскольку ваш основной вопрос не зависит от языка программирования или какого-либо ОО-программирования. И совершенно неясно, какой тип «повторного использования» вы имеете в виду - «повторное использование» - это широкий термин, повторное использование копирование-вставка отличается от повторного использования компонента или библиотеки.
Док Браун
Спасибо, это полезно. Я удалил ссылки на OO - и расширил идею касания общего кода (или кода, который станет общим кодом).
Ястреб
1
В нынешней форме, я думаю, я бы ответил просто «нет, я так не думаю» на ваш вопрос - который, я думаю, не будет очень удовлетворительным для вашего. Или вас интересуют принципы и методы, позволяющие реально снизить затраты на тестирование при создании большой системы, подобной вашей, с использованием самодельных многократно используемых компонентов?
Док Браун

Ответы:

11

мы не хотим изменять код, который можно было бы использовать совместно, потому что это вызовет большое влияние регрессионного теста

Выше звучит о праве на меня. Чем важнее код, тем больше он передается, чем выше требования к качеству, тем больше должна быть гарантия качества при его изменении.

Поскольку ваша система реализована на Java, вы можете увидеть пример выше прямо здесь, в стандартных библиотеках Java (JDK). Его основные выпуски нечасты и сопровождаются очень трудоемким тестированием. И даже незначительные выпуски проходят через очень полный набор тестов JCK, чтобы проверить отсутствие регрессий.

Вы можете подумать, что это как-то душит эволюцию общего кода, и ... да, это правильно. Чем больше влияние и риск связаны с изменением кода, чем более осторожны вы должны делать это, тем больше усилий нужно приложить для тестирования его выпусков.

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

Публичные API, как и бриллианты, вечны. У вас есть один шанс сделать все правильно, поэтому приложите все усилия.


С учетом вышесказанного, похоже, что некоторые из описанных вами проблем вызваны неэффективной стратегией разработки общего кода. В частности, особенно проблематично то, что для повторно используемого кода рассматриваются только два варианта: либо дублировать этот код, либо сразу включить его в «основные» разделяемые библиотеки.

Ограничение только этими двумя опциями не нужно, и, опять же, вы можете найти примеры того, как это можно сделать лучше в том самом JDK, который вы используете. Посмотрите на java.util.concurrentпакеты ( JSR 166 ) - до выпуска Java 5 они представляли собой отдельную библиотеку, а не часть основных выпусков JDK.

Подумайте об этом, это третий вариант, который вы упустили из виду, и довольно прагматичный, который вы должны учитывать при «создании» нового общего кода. Когда вы просто рисуете некоторый код, который можно разделить между 2-3 компонентами, ничто не заставляет вас немедленно включать его в базовый API системы.

Вы можете упаковать и выпустить этот «незрелый» общий код как отдельную библиотеку, как это было сделано для параллельных утилит Java. Этот способ избавляет вас от необходимости полного регрессионного тестирования, поскольку вы можете использовать только относительно небольшое количество задействованных компонентов. В результате у вас есть больше возможностей для изменения и улучшения этого общего кода и для проверки его работы на производстве.

После того, как ваша библиотека вырастет и стабилизируется достаточно, чтобы дать вам уверенность в том, что дальнейшие изменения в ней маловероятны, вы можете рассмотреть ее включение в основные библиотеки системы, так же как параллельные утилиты в конечном итоге были включены в JDK.


Конкретный пример того, сколько усилий (включая тестирование) может быть приложено к изменению сильно повторно используемого кода, можно найти снова в JDK. В выпуске 7u6 они изменили внутреннее Stringпредставление, что повлекло за собой изменение substringпроизводительности. Комментарии разработчика функции в Reddit обрисовывают в общих чертах, сколько усилий было приложено к этому изменению:

Первоначальный анализ вышел из группы GC в 2007 году ...

Внутренне группа производительности Oracle поддерживает набор представительных и важных приложений и тестов, которые они используют для оценки изменений производительности. Этот набор приложений имел решающее значение при оценке изменения подстроки. Мы внимательно изучили как изменения в производительности, так и изменения в занимаемой площади. Неизбежно, как и в случае каких-либо существенных изменений, в одних приложениях были регрессии, а в других - выгоды. Мы исследовали регрессии, чтобы увидеть, была ли производительность по-прежнему приемлемой, и правильность была сохранена ...

Мой ответ не является исчерпывающим, но представляет собой очень краткое изложение того, что было почти шесть месяцев самоотверженной работы ...

комар
источник
Похоже, мы оба работали над ответом параллельно, с множеством схожих мыслей ...
Док Браун
@DocBrown да, интересно, что мы также ответили почти одновременно, примерно через час после того, как вопрос был отредактирован в форме
комнат
9

Я не думаю, что существуют какие-либо метрики для расчета «затрат на регрессионные тесты / LOC построенного повторно используемого кода». И я не думаю, что кто-то когда-либо столько времени и денег тратил на создание одной и той же «большой» системы, одной версии с большим количеством компонентов, которые можно было бы пересмотреть, и одной без, чтобы провести серьезное исследование этого вопроса.

Но я видел проблемы, вызванные повторным использованием, как у вас раньше, и, возможно, вы заинтересованы в некоторых мыслях о том, как справиться с этим лучше.

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

  • эти компоненты очень зрелые и стабильные

  • они разработаны и полностью протестированы в изоляции совершенно другой организацией

  • чтобы (повторно) использовать их, вам не нужно менять их (на самом деле вы не могли бы этого сделать, даже если бы вам этого хотелось, поскольку вы не поддерживаете исходный код)

  • вы не получаете ежедневно новую версию, только незначительные обновления (максимум в месяц) или крупные обновления с интервалами в год

  • большинство обновлений рассчитано на 100% -ную совместимость, особенно небольшие обновления

Поэтому, чтобы сделать ваши собственные повторно используемые компоненты более успешными, вы должны адаптировать некоторые из этих вещей сверху для собственной разработки:

  • для любого повторно используемого компонента несите четкую ответственность за обслуживание и следите за тем, чтобы все люди, повторно использующие компонент, могли сразу же получить исправление в случае возникновения проблем.

  • установить строгие правила управления версиями и релизами. При разработке многократно используемого компонента не выпускайте его «каждому» каждый день (по крайней мере, если это не означает, что в системе будет выполняться полный регрессионный тест стоимостью 200 000 долларов США). Вместо этого разрешайте время от времени публиковать только новые версии и предоставляйте механизмы, позволяющие пользователю этого компонента переносить изменение в новую версию.

  • чем чаще компонент используется повторно, тем важнее то, что он обеспечивает стабильный интерфейс и поведение, совместимое вниз.

  • Для многоразовых компонентов требуются очень полные тестовые наборы, чтобы тестировать их изолированно.

Многие из этих вещей будут означать, что стоимость сборки самого компонента будет увеличиваться, но это также уменьшит стоимость изменений, вызванных неудачными регрессиями.

Док Браун
источник
0

Хотя может произойти «заметное» повышение стоимости из-за необходимости проведения дополнительного тестирования, такой тип рефакторинга обычно делает код более удобным для сопровождения в будущем, поскольку вы уменьшаете техническую задолженность в системе.

Надеемся, что это должно уменьшить будущие ошибки и упростить реализацию новых функций или изменений существующих функций.

Проще говоря, я имею в виду, что они должны занимать меньше времени и, следовательно, стоить дешевле.

Сокращать, проще и меньше - все это довольно туманные термины, и любую будущую экономию (или, скорее, надежду на экономию) невозможно рассчитать, поскольку это еще не произошло.

Более простая кодовая база должна позволить новым сотрудникам или существующим сотрудникам, переходящим на проект, быстрее набирать скорость, особенно для больших систем.

Это также может снизить текучесть кадров, так как моральный дух существующих участников проекта может быть улучшен.

Конечно, не гарантируется, что вы получите эти преимущества, но это вещи, которые следует учитывать наряду с затратами (например, расширенное тестирование), которые можно измерить.

На самом деле, лучший код должен со временем снизить затраты на тестирование, даже если есть первоначальное увеличение из-за того, что вы описываете.

Ozz
источник