Работа с пересечениями объектов

11

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

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

Размеры этой проблемы пересечения признаков представляют собой невероятную сложность. Допустим, текущая версия программного обеспечения имеет Nфункции, и вы добавляете одну новую функцию. Давайте также упростим ситуацию, сказав, что каждая из функций может быть только включена или выключена, тогда у вас уже есть 2^(N+1)возможные комбинации функций для рассмотрения. Из-за отсутствия более точных формулировок / поисковых терминов, я имею в виду существование этих комбинаций как проблему пересечения признаков . (Бонусные баллы за ответ, включая ссылку (и) на более установленный термин.)

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

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

  • Спецификация: Когда вы указываете новую функцию - как вы гарантируете, что она хорошо работает со всеми другими детьми?

    Я вижу, что можно систематически проверять каждую существующую функцию в сочетании с новой функцией, но это было бы в изоляции от других функций. Учитывая сложную природу некоторых особенностей, это изолированное представление часто уже настолько вовлечено, что нуждается в структурированном подходе само по себе, не говоря уже о 2^(N-1)факторе, вызванном другими особенностями, которые один охотно игнорировал.

  • Реализация: когда вы реализуете функцию - как вы гарантируете, что ваш код правильно взаимодействует / пересекается во всех случаях.

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

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

    Достаточно сложно понять, что тестирование отдельной функции в отдельности не гарантирует ничего, кроме безошибочного кода, но когда вы уменьшаете его до доли, 2^-Nкажется, что сотни тестов даже не покрывают ни одной капли воды во всех океанах вместе взятых. , Хуже того, наиболее проблемные ошибки - это ошибки, связанные с пересечением функций, которые, возможно, не приведут к каким-либо проблемам - но как вы можете их проверить, если не ожидаете такого сильного пересечения?

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

Фрэнк
источник
6
Грамотно разработанная архитектура приложений может вместить новые функции, не переворачивая мир с ног на голову; опыт здесь - великий нивелир. Тем не менее, такую ​​архитектуру не всегда легко получить с первой попытки, и иногда приходится вносить сложные изменения. Проблема тестирования не обязательно является проблемой, которую вы делаете, если знаете, как правильно инкапсулировать функции и функциональные возможности и покрыть их адекватными модульными тестами.
Роберт Харви

Ответы:

6

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

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

Что касается источников, мне кажется, что почти каждая книга или блог о разработке программного обеспечения эффективно пытается максимально сократить эти 2 ^ N, хотя я не знаю ни одного, который бы рассматривал проблему так же, как вы делать.

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

А может и нет. Я ничего не знаю о RavenDB. Архитектура не может предотвратить проблемы пересечения объектов, если функции действительно непонятным образом переплетены, и мы никогда не узнаем заранее, что нам не понадобится функция, которая действительно имеет худший случай пересечения 2 ^ N. Но архитектура может по крайней мере ограничить пересечения из-за проблем с реализацией.

Даже если я ошибаюсь по поводу RavenDB и eTags (и я просто использую это для аргументации - они умные люди и, вероятно, правильно поняли), должно быть понятно, как архитектура может помочь. Большинство шаблонов, о которых говорят люди, разработаны явно с целью уменьшения количества изменений кода, необходимых для новых или изменяющихся функций. Это происходит в обратном направлении - например, «Шаблоны проектирования, элементы многократно используемого объектно-ориентированного программного обеспечения», введение гласит: «Каждый шаблон проектирования позволяет некоторым аспектам архитектуры варьироваться независимо от других аспектов, тем самым делая систему более устойчивой к определенному виду. изменение".

Моя точка зрения заключается в том, что на практике можно получить представление о Большой точке пересечения функций, если посмотреть на то, что происходит на практике. Изучая этот ответ, я обнаружил, что большинство анализов функциональных точек / усилий по разработке (т. Е. Производительности) обнаруживают либо меньший, чем линейный рост проектных усилий на функциональную точку, либо очень незначительно выше линейного роста. Что я нашел немного удивительным. Это был довольно читаемый пример.

Это (и аналогичные исследования, некоторые из которых используют функциональные точки вместо строк кода) не доказывают, что пересечение объектов не происходит и не вызывает проблем, но кажется разумным доказательством того, что на практике это не разрушительно.

PSR
источник
0

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

Структурная поддержка

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

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

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

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

дизайн

При разработке ядра программы, начните с подхода «сверху вниз», который может превратить вещи в управляемые куски и позволит вам обернуть голову вокруг проблемной области; после этого я думаю, что следует использовать подход «снизу вверх» - это поможет сделать вещи меньше, более гибкими и более удобными для последующего добавления. (Как упомянуто в ссылке, выполнение таких действий приводит к меньшим реализациям функций, что означает меньше конфликтов / ошибок.)

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

Когда добавляется новая функция, я думаю, что при ее проектировании можно было бы пойти тем же путем, что и при проектировании остальной части фреймворка: разложить ее и затем пойти снизу вверх. Если вы можете повторно использовать любой из оригинальных блоков из фреймворка при реализации этой функции, это определенно будет полезно; Как только вы закончите, вы можете добавить любые новые блоки, которые вы получаете от этой функции, к тем, которые уже есть в базовой структуре, тестируя их с исходным набором блоков - таким образом, они будут совместимы с остальной частью системы и могут использоваться в будущем. особенности также.

Упростить!

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

Во всяком случае, это мой 2с.

Павел
источник