Робота з перехрестями функцій


11

Останнім часом я став свідком дедалі більшої кількості проблем, подібних до тих, що пояснюються у цій статті про перехрестя зображень. Іншим терміном для цього будуть продуктові лінії, хоча я, як правило, пов'язую їх із фактично різними продуктами, тоді як я зазвичай стикаюся з цими проблемами у вигляді можливих конфігурацій товару.

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

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

Тепер питання, з яким я боюся, - як вирішити цю проблему складності на кожному рівні процесу розвитку. З очевидних причин вартості недоцільно розглядати кожну комбінацію окремо, доки не є утопічною. Зрештою, ми намагаємось уважно триматися осторонь від алгоритмів експоненціальної складності, але перетворення самого процесу розвитку на чудовисько в експоненціальному розмірі неодмінно призведе до повного збою.

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

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

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

  • Впровадження: Коли ви реалізуєте функцію - як ви гарантуєте, що ваш код взаємодіє / перетинається належним чином у всіх випадках.

    Знову ж, мені цікаво, яка вона складна. Мені відомі різні методики зменшення потенціалу помилок двох особливостей, що перетинаються, але жодна, яка б не була можливою в масштабах. Я припускаю, що хороша стратегія під час специфікації повинна тримати проблему під час впровадження.

  • Перевірка: Коли ви тестуєте функцію - як ви маєте справу з тим фактом, що ви можете протестувати лише частину простору перетину цієї функції?

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

Хоча я хотів би почути, як інші вирішують цю проблему, мене в першу чергу цікавить література чи статті, що аналізують цю тему більш глибоко. Тож якщо ви особисто дотримуєтесь певної стратегії, було б непогано включити у відповідь відповідні джерела.


6
Розумно розроблена архітектура прикладних програм може вмістити нові функції, не перетворюючи світ догори дном; досвід є великим рівнем тут. Однак, подібну архітектуру не завжди легко отримати з першої спроби, і іноді доводиться вносити важкі корективи. Проблема тестування не обов'язково є трясовиною, яку ви розкрили, якщо ви знаєте, як правильно інкапсулювати функції та функціональність та покрити їх адекватними тестовими одиницями.
Роберт Харві

Відповіді:


6

Ми вже математично знали, що перевірка програми неможлива в кінцеві терміни в найбільш загальному випадку через проблему зупинки. Тож така проблема не нова.

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

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

Для прикладу того, як дизайн може допомогти у цьому, у статті згадувалося про те, що перетин особливості трапився через те, що реплікація та індексація ініціювались eTag. Якби у них був інший канал зв'язку, який би сигналізував про потребу кожного з них окремо, можливо, вони могли б легше контролювати порядок подій і мали б менше проблем.

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

Навіть якщо я помиляюся про RavenDB та eTags (а я просто використовую це для аргументу - вони розумні люди і, ймовірно, правильно це зрозуміли), повинно бути зрозуміло, як архітектура може допомогти. Більшість моделей, про які люди говорять, розроблені явно з метою зменшення кількості змін коду, необхідних для нових або змін функцій. Це йде назад - наприклад, "Шаблони дизайну, елементи багаторазового використання об'єктно-орієнтованого програмного забезпечення", у вступі зазначено "Кожна модель дизайну дозволяє деяким аспектам архітектури змінюватися незалежно від інших аспектів, тим самим роблячи систему більш надійною для певного виду змінити ".

Моя думка, можна зрозуміти, що великі перекриття функції на практиці знаходяться на практиці, добре, дивлячись на те, що відбувається на практиці. Досліджуючи цю відповідь, я виявив, що більшість аналіз точок функціонування / зусилля на розробці (тобто - продуктивності) виявили або менший, ніж лінійний приріст зусиль проекту на функціональну точку, або дуже дещо вище лінійного зростання. Що мене трохи дивно. Це мав досить читабельний приклад.

Це (і подібні дослідження, деякі з яких використовують функціональні точки замість рядків коду) не доводить, що перетин функції не виникає і не створює проблем, але здається розумним доказом того, що це не руйнує на практиці.


0

Це не буде найкращою відповіддю будь-якими способами, але я думав над деякими речами, які перетинаються з точками у вашому запитанні, тому я думав, що згадаю їх:

Структурна підтримка

З малого, що я бачив, коли функції баггі і / або не зв’язуються добре з іншими, це значною мірою пояснюється поганою підтримкою, яку надає основна структура / структура програми для управління / координації їх. Гадаю, витрачається більше часу на розгортання та закріплення ядра, я можу полегшити додавання нових функцій.

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

Це стає досить критичним при додаванні підтримки для декількох X, які включають потоковий / асинхронний / керований подіями код, тому що цей матеріал може вийти з ладу досить швидко - я мав радість налагоджувати ряд питань, пов’язаних із цим.

Мабуть, важко виправдати подібні зусилля наперед, хоча це стосується прототипів чи разових проектів - навіть якщо деякі з цих прототипів або одноразових робіт знову використовуються або як (основа) кінцевої системи, це означає, що витрати були б варті того, щоб у перспективі.

Дизайн

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

Якщо ви зосередитесь на основних будівельних блоках системи і переконайтеся, що всі вони добре взаємодіють, то все, що побудовано на їх основі, також, ймовірно, буде добре поводитися і має краще інтегруватися з рештою системи.

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

Спростіть!

Я займав мінімалістичну позицію щодо дизайну пізно, починаючи зі спрощення проблеми, а потім спрощення рішення. Якщо час може зайняти секунду, спрощуючи ітерацію дизайну для проекту, то я міг би бачити, що це дуже корисно, коли ви додаєте речі згодом.

У всякому разі, це мій 2с.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.