Як привернути увагу програміста в певних умовах?


13

Почнемо з прикладу.

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

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

У мене дві ідеї, але в обох є вади.

Розумна обгортка "Прочитати все"

Я можу створити розумну обгортку, яка гарантує чітке зчитування всіх даних.

Щось на зразок цього:

def export():
    checker = AllReadChecker.new(table_row)

    name    = checker.get('name')
    surname = checker.get('surname')
              checker.ignore('age') # explicitly ignore the "age" field

    result = [name, surname] # or whatever

    checker.check_now() # check all is read

    return result

Отже, checkerстверджує, що table_rowмістить інші поля, які не були прочитані. Але все це виглядає важким і (можливо) впливає на продуктивність.

"Перевірте цей метод" тестування

Я можу просто створити unittest, який запам’ятовує останню схему таблиці і виходить з ладу щоразу, коли таблиця змінюється. У такому випадку програміст побачить щось на кшталт "не забудьте перевірити exportметод". Щоб приховати програміст попередження, він (або не буде - це проблема) перевірить exportі вручну (це ще одна проблема) виправить тест, додавши в нього нові поля.

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


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


Ви можете, можливо, генерувати exportна основі схеми?
coredump

Це не може бути автоматично генеровано, тому я повинен попросити програміста переглянути код і прийняти рішення.
Вадим Пуштаєв

Чи було б рішенням додати два списки імен полів (експорт та не-експорт) до класу експорту та провести одиничний тест, який перевіряє, що ці два списки разом містять повний набір полів із бази даних?
Joe Postbut

Чи можете ви автогенерувати тест, хоча він перевіряє, чи exportє все, що вам реально потрібно?
biziclop

1
коментар у вихідному коді занадто спрощене рішення? Зазвичай речі пропускають, оскільки немає нагадування, коментар виправить це.
gbjbaanb

Відповіді:


11

Ви на правильному шляху зі своєю ідеєю тестування одиниці, але ваша реалізація неправильна.

Якщо exportсхема пов'язана зі схемою, а схема змінена, є два можливі випадки:

  • Або exportвсе ще працює чудово, оскільки це не вплинуло на незначну зміну схеми,

  • Або зламається.

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

Чому ваша реалізація неправильна? Ну, з кількох причин.

  1. Це не має нічого спільного з одиничними тестами ...

  2. ... і, власне, це навіть не тест.

  3. Найгірша частина полягає в тому, що для виправлення "тесту" потрібно фактично змінити "тест", тобто зробити операцію, абсолютно не пов'язану з export.

Натомість, роблячи фактичні тести для exportпроцедури, ви переконуєтесь, що розробник виправить це export.


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

Хоча я конкретно говорю про класи, це стосується більшої чи меншої міри також і для інших об'єктів. Наприклад, зміна схеми бази даних повинна бути або відображена автоматично у вашому коді, наприклад, через генератори коду, які використовуються багатьма ORM, або, принаймні, легко локалізуватися: якщо я додаю Descriptionстовпець до Productтаблиці і не використовую ORM або генератори коду, Я, принаймні, розраховую внести одну зміну в Data.Productклас DAL, без необхідності шукати всю базу коду та знаходити деякі події Productкласу в, скажімо, шарі презентації.

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

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

У всіх випадках уникайте покладатися на такі випадки лише на коментарі. Щось на зразок:

// If you change the following line, make sure you also change the corresponding
// `measure` value in `Scaffolding.Builder`.

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


Так, тест справді не є тестом, це якась пастка, якась If you change the following line...працює автоматично і не може бути просто проігнорована. Я ніколи не бачив, щоб хтось насправді використовував такі пастки, отже, сумніви.
Вадим Пуштаєв

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

@VadimPushtaev: якщо мова йде про тестування, "можливо, починає працювати неправильно", а "перестає працювати" - це саме те саме. Ви не можете передбачити майбутнє, але ви повинні мати можливість точно знати вимоги та перевірити, чи ці вимоги відповідає вашому фактичному продукту.
Арсеній Муренко

Так, це річ. Я насправді хочу нагадати розробнику думати про нові вимоги . Я просто хочу помахати рукою: «Здрастуйте, ви впевнені, що не забудете про експорт? Запитайте менеджера чи щось таке - це загальна проблема ”.
Вадим Пуштаєв

Все одно дякую, ваша відповідь допомогла мені організувати свої думки, і я зараз маю певний план.
Вадим Пуштаєв

3

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

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

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

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

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


2

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


це може перевірити, що кожен об'єкт зберігається та перезавантажується з db. Це не охоплює випадок, коли існуюче db-поле не має відповідного об'єктного поля.
k3b

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