Етап проектування
Цей етап передбачає детальний опис реалізації системи. Цей опис після проведення остаточних змін в наступних етапах (реалізації, тестування) стане частиною технічної документації по системі.
На відміну від етапу аналізу, на етапі проектування розробники повинні знати, яке програмне середовище мови програмування, бібліотеки та інші інструменти будуть застосовуватися на етапі реалізації.
На цьому етапі відбувається перетворення абстрактних понять етапу аналізу в конкретні деталі системи.
Під час виконання цього етапу розробки ПЗ, одна частина працівників працює над проблемами пов’язаними з основними функціями системи і опрацюванням необхідних даних, інша частина працює постійно з клієнтом, з визначенням способу зберігання даних, доступу до даних, управління пам’яттю і подібними питаннями.
На етапі проектування також відбувається оптимізація моделі. Програмні середовища, які розглядаються на цьому етапі використовують різні інструменти, які з однієї сторони обмежують раніше розроблену модель, але з іншої сторони вони забезпечують допоміжні засоби, які можуть спростити реалізацію системи. Таким чином на етапі проектування створюється модель в рамках обмежень та можливих удосконалень з позиції програмних середовищ. На цьому етапі визначається фізична структура моделі.
Виконують наступні завдання:
1. Формується специфікація результатів аналізу
2. Проводиться проектування компонентів системи, які не належать області проблем
3. Проводиться оптимізація системи
4. Відбувається підлаштування моделі системи до обмежень та варіантів програмного середовища
5. Відбувається фізичне визначення структури системи
Детальна модель системи відкриває можливість оцінки варіантів реалізації конструкції системи. Основні конструкції системи повинні підтримуватися допоміжними:
1. Інтерфейси роботи з користувачами
2. Компоненти управління даних при зберіганні даних
3. Компоненти управління пам’яттю
4. Компоненти управління завданнями системи
Цей етап (проектування):
1. Висока якість моделі системи
2. Хороше знання середовища розробки
3. Перевірка системи
4. Узгодженість зі стандартами
5. Необхідно здійснити проектну оптимізацію для основних компонентів системи
В результаті виконання цього етапу отримаємо:
1. Відкоригований документ формулювання вимог
2. Відкоригована модель, яка завершувалася детальною специфікацією
3. Документ, що описує проект:
1. Діаграма класів
2. Діаграма взаємодій
3. Діаграма станів
4. Діаграма діяльності
5. Діаграма компонентів
6. Визначення ознак класів, методів, даних і т.д.
4. Різні класи систем
5. Спроектована БД
6. Фізичний проект структури системи
7. Відкоригований тестовий проект
8. Планування виконання системи
Етап реалізації
Під час реалізації система реалізується в певному середовищі розробки та визначається надійність проекту. Надійність проекту полягає в максимальному уникненні помилок або можливості їх виправлення. Під час реалізації програмного продукту не всі помилки можуть бути виявлені та усунені. Але існує можливість зменшити ймовірність їх виникнення в наслідок:
1. Відмова у використанні ризикованих методів (вказівників)
2. Обмеження принципу доступу (розподіл пам’яті і т.д.)
3. Використання під час реалізації типізованих мов і відповідних компіляторів
4. Використання мов високого рівня
5. Послідовність використання інтерфейсів модулів
6. Врахування надзвичайних ситуацій
7. Можливих невизначеностей
8. Дотримання мінімальних відмінностей між концептуальною моделлю і моделлю реалізації
Крім того на практиці не існує методів, які виключають можливість появи помилки. Але завжди існує можливість забезпечити виконання програми не дивлячись на помилку. Такий механізм називають перекриттям помилки. Він включає:
1. Виявлення помилок
2. Опрацювання помилок
3. Виправлення помилок
Використання такого механізму можливе, якщо передбачена відповідна діагностика системи на помилки.
Існує два методи опрацювання помилок:
1. Перевірка даних
2. Співставлення результатів різних версій модуля
Для успішного виконання цього етапу потрібно:
1. Високоякісна і детальна специфікація проекту
2. Хороше знання середовища розробки
3. Дотримання існуючих стандартів
4. Опрацювання помилок
В результаті виконання цього етапу отримають:
1. Покращений документ по вимогах
2. Покращену аналітичну модель
3. Покращений проект системи
4. Код з перевіреними модулями
5. Звіт про перевірені модулі
6. Розроблена БД
7. Планування етапу тестування
Етап тестування
Під тестуванням розуміють сертифікацію програмного продукту – це:
1. перевірка системи вимогам клієнта
2. перевірка системи (загальна)
Мета тестування полягає в тому: щоб виявити і виправити помилки. Тестування повинно виявляти як загальні помилки в системі так і помилки виконання. Під помилками розуміють: конструкції, які розроблені не правильно. Помилки у виконанні системи можуть бути наслідком інших попередніх помилок.
Тести можуть бути націлені на:
1. виявлення максимальної кількості помилок
2. виявлення статистики помилок (відповідно їх частоти виникнення та надійності обладнання)
Тести можуть бути статичні та динамічні.
Статичні базуються на основі аналізу коду.
Динамічні тести передбачають порівняння за відома правильних результатів і результатів роботи програми.
Фази тестування:
1. тестування модулів (відбувається після їх розробки та реалізації)
2. тестування системи (відбувається після інтегрування всіх модулів в єдину систему і передбачає як тестування системи загалом так і модулів в складі системи)
3. приймальне тестування (система передається клієнту і перевіряється ним же) – таке тестування називається альфа тестування
Для успішного виконання цього етапу:
1. вдала реалізація спеціальних вимог систем, що забезпечить надійність системи
2. мотивоване залучення людей для виконання тестів
Під час виконання цього етапу отримаємо:
1. покращені вимоги
2. покращена модель
3. покращений проект
4. покращений код
5. звіт про тести
6. оцінка надійності програмного продукту
Етап установки
На цьому етапі програмний продукт або система передається користувачеві і він стає власником програмного продукту. На цьому етапі виконуються наступні дії:
1. навчання користувачів та адміністратора
2. установка програмного та апаратного забезпечення
3. установка БД
4. контрольоване використання системи
5. передача системи клієнту
Для успішного виконання цього етапу потрібно:
1. спланувати розклад та графік установки щоб уникнути конфлікту із замовниками
2. позитивна оцінка проекту замовником
Результати:
1. покращені вимоги
2. - модель
3. - код
4. Програмний продукт встановлений у клієнта
Етап підтримки
Етап установки відбувається паралельно із початком експлуатації системи. Етап підтримки – більш довгий і триває під час експлуатації. Під час цього етапу можливі зміни в системі. Існує три основні класи модифікації системи.
1. Усунення помилок
2. Поліпшення якості ПЗ
3. Оновлення ПЗ, яке передбачає сумісність із всіма зовнішніми системами, які теж можуть модифікуватися.
Кожна зміна в системі на етапі підтримки повинна бути чітко проаналізована і повинне бути прийняте рішення чи має ця зміна сенс. Аналіз змін полягає в:
1. Як буде впливати зміна на експлуатацію системи
2. Яка вартість змін у системі
3. Як буде впливати зміна в системі на специфічні компоненти в системі
4. Як ця зміна може відобразитися в технічній документації по системі.
Тільки після такого аналізу на практиці проводять модифікацію системи.
Чинники успіху етапу підтримки:
1. Висока якість вимог до системи
2. Висока якість моделі
3. Висока якість системи
4. Грамотне використання середовищ розробки
5. Кваліфікована команда для виконання системи
6. Висока якість і вартість обслуговування системи
За результатами виконання цього етапу отримаємо:
1. Покращені вимоги
2. - модель
3. - проект
4. - код
Лекція 3. Специфікації програмного забезпечення.
Специфікація вимог до програмного забезпечення (англ. Software Requirements Specification (SRS)) - специфікація вимог для програмної системи - це повний опис поведінки системи що розробляється. Вона включає множину прецедентів які описують всі взаємодії, які користувачі мають з програмним забезпеченням. Прецеденти також відомі як функціональні вимоги. На додачу до прецедентів SRS також включає нефункціональні (чи додаткові) вимоги. Нефункціональні вимоги є вимогами які накладають обмеження на проект, чи реалізацію (такі як вимоги інженерії продуктивності, стандарти якості, чи обмеження проектування).
Загальний план специфікації вимог до ПЗ
Обкладинка
Сторінка змін
Зміст
1. ВСТУП
1. Огляд продукту
2. Мета
3. Межі
4. Посилання
5. Означення та абревіатури
2. ЗАГАЛЬНИЙ ОПИС
1. Перспективи продукту
2. Функції продукту
3. Характеристики корисувачів
4. Загальні обмеження
5. Припущення й залежності
3. КОНКРЕТНІ ВИМОГИ
1. Вимоги до зовнішніх інтерфейсів
1. Інтерфейс користувача
2. Апаратний інтерфейс
3. Програмний інтерфейс
4. Комунікаційний протокол
5. Обмеження пам'яті
6. Операції
7. Функції продукту
8. Припущення й залежності
2. Властивості програмного продукту
3. Атрибути програмного продукту
1. Надійність
2. Доступність
3. Безпека
4. Cупроводжуваність
5. Переносимість
6. Продуктивність
4. Вимоги бази даних
5. Інші вимоги
4. ДОДАТКОВІ МАТЕРІАЛИ
Лекція 4. “Хаотичне” і структурне програмування. Теорія і методи структурного програмування.
1. Структурне програмування
За часів стихійного програмування хорошими програмістами вважали тих, хто створював досить хитромудрі програми, які займали мінімум часу та пам’яті при виконанні. Це було цілком природно, враховуючи тодішні можливості обчислювальної техніки. Результатом такого програмування виявлялись програми, які було важко (якщо взагалі можливо) зрозуміти іншим. Навіть автори таких програм з часом з трудом розуміли власне творіння. Внесення необхідних змін в таку програму робило ситуацію ще більш заплутаною. Подібні програми одержали назву BS-програм (це абревіатура від “bowl of spaghetti” – блюдо спагетті, бо саме так виглядала програма при спробі зобразити всі переходи між її операторами). Піонер структурного програмування Е. Дейкстра навіть проголосив, що “кваліфікація програміста обернено пропорційна кількості операторів безумовного переходу в його програмах”. Структурне програмування іноді називають “програмування без go to”, хоча це екстремальна точка зору. Насправді мова йде про те, щоб не використовувати оператори переходу без особливої необхідності. Перш за все структурне програмування мало своєю метою позбавитись від поганої структури в програмі. Ще однією метою було створення таких програм, які були б легко зрозумілими навіть без їх авторів, адже “програми пишуться для людей – комп’ютером вони лише обробляються”. Зміст цієї фрази полягає у тому, що трансляція і виконання програми будь-якої структури на комп’ютері дійсно не викликає ніяких труднощів. А от роботу з перевірки правильності програми, внесення виправлень і змін доводиться виконувати людині.
Отже, структурне програмування є технологією програмування, яка об’єднує способи складання добре структурованих надійних програм, зручних для читання і розуміння їх людиною, слідкування за логікою їх роботи, внесення до них виправлень та інших змін. Згідно з думкою Н.Вірта “структурізація є принциповим інструментом, яке допомагає програмісту систематично синтезувати складні програми, зберігаючи про них повне уявлення”.
Реалізація цих ідей заснована на таких принципах:
аналітичне (згори донизу) програмування;
структурне кодування , тобто використання лише базових елементів програми;
принцип модульності.
З точки зору структурного програмування, правильна програма – це програма, структура якої включає тільки базові елементи, і жоден з цих базових елементів не є недоступним і не допускає зациклювання. Правильна програма має тільки один вхід і тільки один вихід. В правильній програмі не повинно бути таких частин, які ніколи не виконуються.
1.1. Принцип модульності
Принцип модульності полягає у тому, що програма розбивається на логічно незалежні частини (модулі), які дотримуються зв’язків. Історично поняття модульної програми виникло раніше, ніж були сформульовані принципи структурного програмування, проте ця ідея виявилася просто необхідною складовою нової технології програмування разом з аналітичним проектуванням.
Поняття модуля цілком логічно з’являється на відповідному етапі аналітичного програмування: модуль – це частина програми, яка розв’язує порівняно нескладну задачу, логічно незалежну від інших задач.
Зовсім просто: модулі – це підпрограми (процедури або функції), які мають певні властивості.
Деякі необхідні властивості модуля:
єдиний вхід, єдиний вихід (деякі мови дозволяють існування декількох входів або виходів);
окрема компіляція;
кожний модуль доступний за своїм ідентифікатором;
модуль може викликати інший модуль;
модуль не повинен зберігати історію своїх викликів (інакше може виникати так званий побічний ефект);
модуль порівняно невеликий;
кожен модуль відповідає лише одній задачі;
незалежність функціонування (заміна модуля на аналогічний не впливає на всю програму).
З часом, коли принцип модульності став підтримуватись мовами програмування, на перший план висунулась вимога логічної та програмної незалежності модуля.
Слід зауважити, що повної незалежності між модулями бути не може. Залежність між модулями існує:
через списки параметрів;
тоді, коли вони користуються спільними (глобальними) змінними;
всі модулі програми залежать від структури даних цієї програми;
модулі залежать від логіки функціонування програми (від того фактору, що модуль може викликатися іншими модулями).
Отже, модулі повинні бути незалежні в межах інтерфейсу програми і структури даних. Практика показала, що чим вищий степінь незалежності модулів, тим простіше розібратись в окремих модулях і в програмі в цілому; тим менша ймовірність з’явлення нових помилок при виправленні старих, або внесенні змін в програму, тобто менша ймовірність так званого хвильового ефекту.
Із сказаного вище випливає, що не слід без крайньої необхідності використовувати в модулях глобальні змінні. Всі зв’язки між модулями повинні підтримуватися через списки параметрів.
1.2. Процедурна абстракція. Модулі в Turbo Pascal.
Процедурна абстракція – це філософія, яка полягає у тому, що при розробці підпрограм піклування про те, що повинна виконувати процедура або функція, відокремлюється від того, як це виконується.
Потенціал процедурної абстракції більш повно можна реалізувати не у стандартній реалізації мови Паскаль, а у Turbo Pascal (TP).
Після утворення якоїсь процедури, яка має універсальне значення, TP надає вам можливість помістити її у свою особисту бібліотеку підпрограм, або модуль (unit). Потім цей модуль можна використати (імпортувати цю процедуру) в іншій програмі. При цьому ви дійсно відокремлююте що від як. Знаючи, що робить дана процедура і як її викликати, ви можете без обмежень її використовувати, не маючи при цьому жодного уявлення, як саме вона реалізована.
Модулі TP знаходяться в окремих файлах на диску. Вони можуть містити описи констант, типів даних, змінних, процедур і функцій. Компілювати модуль і виправляти у ньому знайдені помилки можна окремо від програм, у яких цей модуль використовується.
Виклик: uses MyUnit;
Структура модуля аналогічна до структури Паскаль-програми:
unit <ім’я модуля>;
interface
загальнодоступні описи
implementation
приховані описи (змінні, вкладені процедури і т.д.)
описи загальнодоступних процедур і функцій
[розділ ініціалізації]
end.
Розділ interface містить всю інформацію, яку необхідно знати програмісту, щоб користуватися цим модулем. Тут є заголовки і документація (коментарі) всіх підпрограм модуля.
Тіла підпрограм міститься в розділі implementation. Кінець модуля позначається словом end. Для нього не існує відповідного begin, якщо у розділі не існує розділа ініціалізації, у якому змінним, що використовуються всередині модуля, надаються початкові значення. Розділ ініціалізації виконується до виконання будь-якого клієнта модуля (програми або модуля, який використовує наш модуль).
Лекція 5, 6, 7. Тестування і відлагодження програм. Стратегії і методи тестування.
Тестування програмного забезпечення охоплює цілий ряд видів діяльності, аналогічно послідовності процесів розробки програмного забезпечення. У нього входять /1/:
а) постановка завдання для тесту,
б) проектування тесту,
в) написання тестів,
г) тестування тестів,
д) виконання тестів,
е) вивчення результатів тестування.
Вирішальну роль відіграє проектування тестів. Можливі різні підходи до проектування тестів. Перший полягає в тому, що тести проектуються на основі зовнішніх специфікацій програм і модулів, або специфікацій сполучення програми або модуля. Програма при цьому розглядається як чорний ящик (стратегія 'чорного ящика'). Суть такого підходу - перевірити чи відповідає програма зовнішнім специфікаціям. При цьому логіка модуля зовсім не приймається до уваги.
Другий підхід заснований на аналізі логіки програми (стратегія 'білого ящика'). Суть підходу - у перевірці кожного шляху, кожної гілки алгоритму. При цьому зовнішня специфікація до уваги не береться.
Жоден із цих підходів не є оптимальним. З аналізу першого підходу ясно, що його реалізація зводиться до перевірки всіх можливих комбінацій значень на вході програми. Тестування будь-якої програми для всіх значень вхідних даних неможливе, тому що їх безліч, тому обмежуються меншою кількістю. При цьому виходять із максимальної віддачі тесту в порівнянні з витратами на його створення. Вона виміряється ймовірністю того, що тест виявить помилки, якщо вони є в програмі. Витрати вимірюються часом і вартістю підготовки, виконання й перевірки результатів тесту.
Проаналізуємо тепер другий підхід до тестування. Навіть якщо припустити, що виконано тести для всіх шляхів програми, не можна з повною впевненістю стверджувати, що модуль не містить помилок.
Очевидна основа цього твердження полягає в тому, що виконання всіх шляхів не гарантує відповідності програми її специфікаціям. Допустимо, якщо було потрібно написати програму для обчислення кубічного кореня, а програма фактично обчислює корінь квадратний, то програма буде зовсім неправильною, навіть якщо перевірити всі шляхи. Друга проблема - відсутні шляхи. Якщо програма реалізує специфікації не повністю (наприклад, відсутня така спеціалізована функція, як перевіряє на негативне значення вхідних дані програми обчислення квадратного кореня), ніяке тестування існуючих шляхів не виявить такої помилки. І, нарешті, проблема залежності результатів тестування від вхідних даних. Шлях може правильно виконуватися для одних даних і неправильно для інших. Наприклад, якщо для визначення рівності 3 чисел програмується вираз виду:
IF (A+B+C)/3=A,
то воно буде вірним не для всіх значень A, B і C (помилка виникає в тому випадку, коли із двох значень В або С одне більше, а інше на стільки ж менше від А). Якщо концентрувати увагу тільки на тестуванні шляхів, немає гарантії, що ця помилка буде виявлена.
Таким чином, повне тестування програми неможливе. Тест для будь-якої програми буде обов'язково неповним, тобто тестування не гарантує повну відсутність помилок у програмі. Стратегія проектування тестів полягає в тім, щоб спробувати зменшити цю неповноту наскільки це можливо.
2.1 Методи стратегії 'білого ящика'
Тестування за принципом білого ящика характеризується ступенем, який тести виконують або покривають логіку (вихідний текст програми).
2.1.1 Метод покриття операторів
Метою цього методу тестування є виконання кожного оператора програми хоча б один раз.
Приклад:
Малюнок 2.1 Малюнок 2.2
У цій програмі можна виконати кожний оператор, записавши один єдиний тест, що реалізував би шлях ace. Тобто, якби на вході було: А=2, В=0, Х=3, кожний оператор виконався б один раз. Але цей критерій насправді гірший, ніж він здається на перший погляд. Нехай у першій умові замість “and”®“or” і в другому замість “x>1”®“x<1” (блок-схема правильної програми наведена на малюнку 2.1, а неправильної - на малюнку 2.2). Результати тестування наведені в таблиці 2.1. Зверніть увагу: очікуваний результат визначається по алгоритму на малюнку 2.1, а фактичний - по алгоритму малюнка 2.2, оскільки визначається чутливість методу тестування до помилок програмування. Як видно із цієї таблиці, жодна із внесених в алгоритм помилок не буде виявлена .
Таблиця 2.1 - Результат тестування методом покриття операторів
Тест | Очікуваний результат | Фактичний результат | Результат тестування |
A=2, B=0, X=3 | X=2,5 | X=2,5 | неуспішно |
2.2 Метод покриття рішень (покриття переходів)
Більш сильний метод тестування відомий як покриття рішень (покриття переходів). Відповідно до даного методу кожний напрямок переходу повинен бути реалізованим принаймні один раз.
Покриття рішень звичайно задовольняє критерію покриття операторів. Оскільки кожний оператор лежить на деякому шляху, що виходить або з оператора переходу, або із точки входу програми, при виконанні кожного напрямку переходу кожний оператор повинен бути виконаний.
Для програми наведеної на малюнку 2.2 покриття рішень може бути виконано двома тестами, що покривають шляхи {ace, abd}, або {aсd, abe}. Шляхи {aсd, abe} покриємо, вибравши наступні вихідні дані: {A=3, B=0, X=3} і {A=2, B=1, X=1} (результати тестування - у таблиці 2.2).
Таблиця 2.2 - Результат тестування методом покриття рішень
Тест | Очікуваний результат | Фактичний результат | Результат тестування |
A=3, B=0, X=3 | X=1 | X=1 | неуспішно |
А=2, В=1, Х=1 | Х=2 | Х=1,5 | успішно |
2.3 Метод покриття умов
Кращі результати в порівнянні з попередніми може дати метод покриття умов. У цьому випадку записується число тестів, достатнє для того, щоб всі можливі результати кожної умови в рішенні виконувалися принаймні один раз.
У попередньому прикладі маємо чотири умови: {A>1, B=0}, {A=2, X>1}. Отже, потрібне достатнє число тестів, таке, щоб реалізувати ситуації, де A>1, A£1, B=0 і B¹0 у точці а й A=2, A¹2, X>1 і X£1 у точці В. Тести, що задовольняють критерію покриття умов і відповідні до них шляхи:
а) A=2, B=0, X=4 ace
б) A=1, B=1, X=0 abd
Таблиця 2.3 - Результати тестування методом покриття умов
Тест | Очікуваний результат | Фактичний результат | Результат тестування |
A=2, B=0, X=4 | X=3 | X=3 | неуспішно |
A=1, B=1, X=0 | X=0 | X=1 | успішно |
2.4 Критерій рішень (умов)
Критерій покриття рішень/умов вимагає такого достатнього набору тестів, щоб всі можливі результати кожної умови в рішенні виконувалися принаймні один раз, всі результати кожного рішення виконувалися принаймні один раз і, крім того, кожній крапці входу передавалося керування принаймні один раз.
Два тести методу покриття умов
а) A=2, B=0, X=4 ace
б) A=1, B=1, X=0 abd
відповідають і критерію покриття рішень/умов. Це є наслідком того, що одні умови наведених рішень приховують інші умови в цих рішеннях. Так, якщо умова А>1 буде хибною, транслятор може не перевіряти умови В=0, оскільки при будь-якому результаті умови В=0, результат рішення ((А>1)&(В=0)) матиме значення неправда. Отже, недоліком критерію покриття рішень/умов є неможливість його застосування для виконання всіх результатів всіх умов.
Інша реалізація розглянутого прикладу наведена на малюнку 2.3. Рішення вихідної програми, що залежать від багатьох умов, розбиті на окремі рішення й переходи. Найбільш повне покриття тестами в цьому випадку виконується так, щоб виконувалися всі можливі результати кожного простого рішення. Для цього потрібно покрити шляхи HILP (тест А=2,В=0,Х=4), HIMKT (тест А=3, В=1, Х=0), HJKT (тест А=0, В=0, Х=0), HJKR (тест А=0, В=0, Х=2)..
Протестувавши алгоритм на малюнку 2.3, неважко переконатися в тім, що критерії покриття умов і критерії покриття рішень/умов недостатньо чутливі до помилок у логічних виразах.
Малюнок 2.3
2.5 Метод комбінаторного покриття умов.
Критерієм, що вирішує ці й деякі інші проблеми, є комбінаторне покриття умов. Він вимагає створення такого числа тестів, щоб всі можливі комбінації результатів умови в кожному рішенні виконувалися принаймні один раз. Набір тестів, що задовольняють критерію комбінаторного покриття умов, задовольняє також і критеріям покриття рішень, покриття умов і покриття рішень/умов.
За цим критерієм у розглянутому прикладі повинні бути покриті тестами наступні вісім комбінацій:
а) A>1, B=0;
б)A>1, B¹0;
в) A£1, B=0;
г) А£1, B¹0;
д) A=2, X>1;
е) A=2, X£1;
ж) А¹2, X>1;
з) А¹2, X£1;
Для того щоб протестувати ці комбінації, необов'язково використати всі 8 тестів. Фактично вони можуть бути покриті чотирма тестами:
- A=2, B=0, X=4 {покриває а, д};
- A=2, B=1, X=1 {покриває б, е};
- A=0,5, B=0, X=2 {покриває в, ж};
- A=1, B=0, X=1 {покриває г, з}.
Таблиця 2.4 - Результати тестування методом комбінаторного покриття умов
Тест | Очікуваний результат | Фактичний результат | Результат тестування |
A=2, B=0, X=4 | X=3 | X=3 | неуспішно |
A=2, B=1, X=1 | X=2 | X=1,5 | успішно |
A=0,5 B=0, X=2 | X=3 | X=4 | успішно |
A=1, B=0, X=1 | X=1 | X=1 | неуспішно |
Як і тестування, відлагодження програм – це спосіб покращення якості продукту. По своїй суті відлагодження – це спосіб виявлення дефектів у програмі. Важливо пам’ятати, що якість продукту повинна бути закладена від початку розробки: найкращий спосіб створити хороший, якісний продукт – це добре проаналізувати вимоги, вдало продумати архітектуру і застосувати дієву практику написання програмного коду. В цьому випадку відлагодження є останнім виходом.
З іншого боку, відлагодження є корисним для програміста з кількох причин:
1. Дає кращу змогу спеціалісту зрозуміти принцип роботи продукту, над яким він працює.
2. Можливість визначити вид помилок, які найчастіше допускаються програмістом.
3. Дає змогу оцінити власний код з точки зору того, хто його читає.
4. Можливість зрозуміти власну методику виправлення помилок та вирішення проблем.
Загальний огляд процесу відлагодження
На практиці, відлагодження (debugging) – це зупинка та аналіз стану програми в певні моменти часу, можливість покрокового їх виконання та відслідковування значень змінних, стеку викликів функцій (Call Stack), допоміжного виводу тощо. Програмні засоби, які дозволяють виконувати ці дії, називаються відлагоджувачами (debuggers).
Примусова зупинка програм в визначених точках досягається за допомогою так званих точок переривання (breakpoint). При виконанні операції, яка помічена точкою переривання, відлагоджувач автоматично призупиняє виконання програми.
Основні операції відлагоджувача:
1. Зупинка (Break/Pause). Призупиняє виконання програми і відображає поточний рядок виконання.
2. Вихід (Stop/Terminate). Примусово завершує програму і припиняє процес відлагодження.
3. Продовження виконання (Continue). Продовжує виконувати програму до її завершення або до досягнення наступної точки переривання.
4. Наступний крок (Step Over). Виконує наступну операцію, не заглиблюючись у її внутрішню реалізацію.
5. Крок всередину (Step Into). Переходить до ділянки коду, в якому описана реалізація функції і дозволяє відлагоджувати цю ділянку.
6. Крок назовні (Step Out/Step Return). Виконує поточну функцію до кінця, після чого призупиняє програму в функції, яка лежить рівнем вище в стеку виклику.
7. Виконання програми до заданого рядка (Run To Line).Виконує програму, доки не буде досягнутий заданий рядок.
Типові помилки при відлагодженні програм
Найчастішою помилкою програміста є невикористання всієї доступної йому інформації для побудови правильних гіпотез щодо некоректності його програм. Це призводить до того, що програміст часто опирається на часткові та нераціональні рішення, які вирішують лише симптоми, а не справжню проблему.
1. Намагання виправити помилку вгадуванням.
2. Прагнення не «тратити час» на осмислення суті проблеми.
3. Вирішення проблеми найпростішим та найтривіальнішим рішенням.
4. Списання помилок в програмі на помилки компілятора, збої в роботі комп’ютера, віруси та інші «надприродні» проблеми.
Рекомендації щодо знаходження помилки
1. Використовувати всі наявні дані для формулювання правильних гіпотез.
2. Підібрати такий тестовий випадок, на якому проблема відтворюється.
3. Випробувати код модульними тестами (unit tests).
4. Використовувати весь доступний інструментарій.
5. Постаратися відтворити проблему кількома різними способами.
Рекомендації щодо виправлення помилок
1. Зрозуміти проблему, перш ніж починати виправляти її.
2. Розуміти всю програму, не тільки проблему.
3. Не поспішати, розслабитись.
4. Перед виправленням зберегти оригінальну версію коду.
5. За один раз вносити тільки одну зміну, змінювати код тільки усвідомлюючи мету цих змін.
6. Перевірити, чи виправлений код працює коректно.
7. Перевірити код на присутність подібних помилок.
«Агресивне» відлагодження
«Агресивним» відлагодженням називається техніка, яка може бути неефективною щодо часу чи зусиль, але може гарантовано вирішити проблему.
1. Виконати повторне проектування і/або перегляд проблемної ділянки коду.
2. Відкинути ділянку коду і переписати її заново.
3. Стерти всю програму чи окремий модуль, і переписати її заново.
4. Скомпілювати код з повною відлагоджувальною інформацією.
5. Скомпілювати код з найбільшим рівнем зауважень компілятора, виправити код таким чином, щоб всі зауваження зникли.
6. Створити середовище для автоматичного тестування і виконувати тести тривалий час, наприклад, всю ніч.
7. При відлагодженні переступити через велику частину коду і зосередитись на ділянці коду, що може спричинити помилку.
8. Доповнити код командами допоміжного виводу чи логування.
9. Максимально відтворити конфігурацію апаратного забезпечення кінцевого користувача.
10. Новий код вносити малими порціями, ретельно тестуючи кожну з них.
Відлагодження помилок при компіляції програм
1. Не повністю довіряти номерам рядків, на які вказує компілятор.
2. Не повністю довіряти повідомленням компілятора про помилки.
3. Не довіряти другому, третьому і т.д. повідомленням, звертати увагу насамперед на перше.
4. Принцип «розділяй і володій» (Divide And Conquer).
Лекція 8,9. Структури даних.
Напівстатичні та динамічні структури даних.
1. Елементарні структури даних