Про те, що ускладнює формалізацію проекту і плодить приховані помилки

Працювати в проекті без помилок — мрія будь-якого ІТ-шника. Досягається це в реальності? Це питання є одночасно і простим, і складним, тому що, щоб уникнути помилок, треба, з одного боку, мати чітко вивірену ланцюжок, починаючи від формування загальних вимог до детальної реалізації. З іншого боку, у сферу ІТ вливається потік фахівців, які слабо уявляють, як можна довести відсутність помилок в програмі або вибудувати структуру, яка скорочує можливості помилок, насамперед логічних, які носять принциповий характер.

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

Для математика, постановка питання зрозуміла. Мається рахунковий обмежена кількість об'єктів, рахунковий обмежена кількість ступенів свободи, станів об'єктів і тд і тп. Всі характеристики піддаються простому рахунку. Оцінки і підрахунки для рахункових кінцевих множин не складуть праці. Людина, що пройшла курс комбінаторики або дискретної математики, зможе намітити план, як можна формалізувати всі можливі стани системи і як виділити коректні і некоректні стану. Ось що може дати математика:

  • підрахунок кількості можливих варіантів станів об'єкта;
  • доказ повноти, чи враховані всі варіанти або є невраховані;
  • доказ наявності або відсутності некоректних станів;
  • пошук прикладів, які призведуть до некоректних або коректним станів;
  • доведення еквівалентності тих чи інших дій;
  • і багато іншого.
Тепер спробуємо розібратися з підступним ворогом, який ускладнює цей процес. Наприклад, автор ТЗ передає якийсь список типів договорів, для яких буде виконуватися якусь дію. Іноді в ТЗ може з'явитися фраза «всі типи договорів» або «всі інші типи договорів, крім...». Програміст прагне виконати ТЗ правильно при нестачі часу і тиску з боку бізнесу. Замислюватися про те, наскільки програма готова до нових змін часто не доводиться, — лише б пройти тести, виправити зауваження, здати, відзвітувати, йти далі.

Припустимо, програміст робить процедуру, яка підставляє номер рахунку в бухгалтерській проводці. Побачивши в ТЗ список всіх типів договорів які присутні в системі або побачивши фразу «всі типи договорів», програміст робить першу помилку — він узагальнює, що може бути навіть приємно для мозку, так як можна висловити думку стисло. В результаті його процедура, яка підставляє рахунок не аналізує тип договору. На перший погляд ніякого криміналу немає.

Ось чому підступ — бачите, поняття «всі типи договорів» на момент написання ТЗ включало 10 типів. Потім це поняття змінюється, і через півроку додається ще пара типів. Такий випадок не є проблемою в маленьких проектах, скажімо до мільйона рядків, де є спадкоємність досвіду і програмісти швидко вчаться один у одного.

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

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

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

Скільки від цього користі судіть самі.

  1. Зменшуються розбіжності між упорядником ТЗ і розробником. Загальні слова підкріплені конкретикою.
  2. Зменшується ймовірність того, що в налагоджений алгоритм потраплять параметри, на яких він не тестувався.
  3. Стають видні місця в коді, де треба додавати обробку нових типів.
  4. Підвищується рівень дисципліни в коді. Збільшується ймовірність, що логіка буде концентруватися в одному і тому ж місці, а не буде розкидана.
  5. Полегшується формалізація і автоматичний аналіз коду.


Я не пропоную хардкодить списки, коли їх можна вести в базі. Просто наводжу найпростіші приклади для ілюстрації принципів на псевдокоде, схожому на pl/sql.

//Приклад 1.
//Невірний код, немає перевірки на потрапляння нового типу.
//Список змінюється з часом, з'являються різночитання з початковим ТЗ.
//З часом цей шматок коду впливає на все більшу кількість даних,
//тому зміни стає ризикованим.
forall type_id in (all_type_list) loop
do_something;
end loop;

//приклад 2
//теж
if type_id not in (555,666) then 
do_something;
end if;

//приклад 3
//Невірний код, немає перевірки на потрапляння нового типу.
//У разі нового типу виконання продовжується без попереджень
//Дія не виконується, і на це можуть не звернути уваги
if type_id in (333,444) then 
do_something;
end if;

//////////////////////////////////////////////////////////////////////
//Вірний код та його розвиток. ////////////////////
//Приклад 4.
if type_id in (1,2,3) then
do something;
else
//Попався невідомий тип, сигнал додати нову обробку, см нижче.
raise error;
end if;


//Розвиток коду для нових типів 4,5,6.
//Варіант 1, нові типи обробляються стандартно по старому.
if type_id in (1,2,3,4,5,6) then
do_something;
else
raise error; 
end if;


//Варіант 2, нові типи обробляються особливо.
if type_id in (1,2,3) then
do_something;
elsif type_id in (4,5,6) then
do_something_2;
else
raise error; 
end if;

Планую написати продовження на теми:

  • як обробляти зв'язки умов типів/під-типів
  • як автоматично виявляти суперечливі вимоги ТЗ
  • як автоматизувати складання списків і дозволити аналітику ними управляти
  • як використовувати математику для аналізу системи
  • розвиток проекту через мета-системи
Д.А. Рибалок, 2016
к. т. н.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.