Практики розробки та контролю якості програмного забезпечення

ЗМІСТ

1. Підходи, методики та стандарти розробки програмного забезпечення

1.1. Підходи та методики розробки

Під час розробки компонентів інформаційної системи впроваджені наступні методики та підходи:

  1. Використання об’єктно-орієнтованого підходу у розробці програмного забезпечення;

  2. Впровадження віртуалізації на основі контейнерів;

  3. Автоматизація розгортання з допомогою GitOps-підходу;

  4. Організація документації як коду;

  5. Уніфікація та стандартизація програмних компонентів;

  6. Декомпозиція підсистем на модулі;

  7. Оцінка ризиків та моделювання загроз безпеки;

  8. Виконання функціонального та нефункціонального тестування.

1.2. Стандарти Кодування

1.2.1. Стандарти та рекомендації з дизайну

  1. Дотримуйтеся філософії "Zen of Python":

    • Вищість гарного над потворним.

    • Перевага явного перед неявним.

    • Простота переважає складність.

    • Складність є кращою, ніж заплутаність.

    • Плоска структура краща за вкладену.

    • Розрідженість переважає щільність.

    • Важливість легкості читання.

    • Особливі випадки не є настільки особливими, щоб порушувати правила.

    • Однак практичність важливіша за бездоганність.

    • Помилки не мають залишатись непомітними.

    • Якщо приховування помилок не зазначено явно.

    • При стиканні з неоднозначностями, відкиньте спокусу вгадувати.

    • Має існувати один і, бажано, лише один очевидний спосіб зробити це.

    • Хоча він може бути не очевидним, якщо ви не голландець.

    • Час діяти — зараз.

    • Хоча "ніколи" часто краще, ніж просто зараз.

    • Якщо важко пояснити реалізацію — задум поганий.

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

    • Простори імен — це велика перевага, створюймо їх більше!

  2. Опція Fail fast найчастіше є найкращим рішенням.

  3. Використовуйте "Return early" для перевірки вхідних параметрів.

  4. Використовуйте Правило скаутів: "Залишаємо код у стані, кращому ніж ми його знайшли".

  5. Уникайте використання break, continue, return у складних конструкціях.

  6. Завжди використовуйте фігурні дужки у циклах та умовах.

  7. Уникайте створення методів з понад чотирма вхідними параметрами.

  8. Уникайте створення методів, що модифікують вхідний параметр.

  9. Логування об’єктів має здійснюватися без трансформації об’єктів, з огляду на NPE.

1.2.2. Стандарти стилістики коду (Code Style)

  1. Табуляція: використовуйте чотири пробіли.

  2. Використовуйте статичні імпорти лише під час роботи з DSL.

  3. Замінюйте загальні імпорти ("*") на специфічні.

  4. Виділяйте новими рядками лише групи логічно пов’язаних полів, а не кожне поле окремо.

  5. Визначайте поля класу перед полями об’єкта.

  6. При виборі імен змінних орієнтуйтеся на їх функцію, а не на тип. Наприклад, StringBuilder stringbuilder = new StringBuilder() — погано, StringBuilder fields = new StringBuilder() — добре.

  7. Віддавайте перевагу назвам класів, які починаються з доменного значення. Наприклад: UserService, UserKafkaService (технологічна складова може йти посередині).

1.2.3. Стандарти роботи з Git

  1. У репозиторії не повинно бути специфічних даних, таких як локальні шляхи або налаштування, характерні для конкретного розробника (properties).

  2. При створенні Git-повідомлень:

    • Номер завдання з Jira має бути вказаний на початку у квадратних дужках.

    • Повідомлення має відповідати на питання: "Що змінив цей commit?".

    • Якщо опис commit потребує більш детального пояснення, то слід використати короткий заголовок на першому рядку, а потім на новому рядку додати детальний опис (Git вміє з цим працювати).

    • Крапку в кінці повідомлення не ставимо.

1.2.4. Вимоги до роботи з POM

  1. Використовуйте батьківський pom.xml для:

    • визначення версії залежності;

    • управління плагінами.

  2. При перенесенні версії бібліотеки до налаштувань (.properties), необхідно додати суфікс .version. Наприклад, <querydsl.version>…​</querydsl.version>.

1.2.5. Стандарти модульного тестування

  1. Рекомендується використовувати підхід ААА — ArrangeActAssert.

  2. Немає потреби в коментарях (given, when, then), відділення порожніми рядками є достатнім.

  3. Використовуйте анотацію @DisplayName в JUnit 5 для надання більш детальної інформації.

  4. Уникайте "throws Exception" у декларації тестів.

  5. Не рекомендується використовувати PowerMock.

  6. Для mock-об’єктів додавайте відповідний префікс mock. Наприклад, mockRepository.

  7. Уникайте беззмістовних повідомлень у перевірках. Наприклад, Assertions.assertNotNull(object, "Shouldn’t be null").

1.2.6. Вимога до підтримки "Чистоти" коду

При розробці коду дотримуйтеся підходу "Clean code" ("чистий код"), що передбачає створення якісного, добре написаного коду.

Код вважається "добрим", якщо він:

  • відповідає вимогам, тобто пройшов тести;

  • чітко виражає всі замисли дизайну, які були задумані;

  • не містить дублювання;

  • мінімізує кількість компонентів.

1.2.7. Використання метрик SQALE для оцінки та управління технічним боргом

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

Для вимірювання та керування обсягами технічного боргу застосовується методологія SQALE.

2. Методології розробки програмного забезпечення

Розробка Платформи здійснюється за допомогою методології Agile software development.

Agile software development (або гнучка методологія розробки програмного забезпечення) — це клас методологій, що ґрунтується на ітеративній розробці. Вона передбачає, що вимоги та рішення еволюціонують у процесі співпраці між самоорганізованими багатофункціональними командами.

2.1. Структура виконавців системи (Delivery)

2.1.1. Команди розробки та управління

  • Управлінська команда (Management)

  • Платформна команда (Platform Team)

    • Три Scrum-команди

    • Сервісна команда Платформи (Platform Service Team)

  • Команда системних архітекторів (SA Team)

  • Центр компетенцій та команда реєстрів (Competence Center and Register Team)

  • Команда управління сервісами (Service Management Team)

2.1.2. Впровадження Agile-методології

У рамках використання Agile-методології, основним підходом виступає Scrum.

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

Враховуючи, що Платформа є масштабним та технічно складним продуктом, при розробці якого бере участь велика кількість команд та спеціалістів, використовується підхід LeSS (Large Scale Scrum). LeSS — це великомасштабний Scrum, призначений для багатьох команд, які працюють над одним продуктом.

Такий підхід передбачає тривалість спринту два тижні.

Scrum-майстром виступає спеціаліст з управлінської команди — Delivery Manager.

Оцінка зусиль, необхідних для виконання завдань, вимірюється в одиницях story points. Кожне завдання, яке може бути подроблене на менші частини, фіксується в Jira backlog та розподіляється між розробниками відповідних команд управлінською командою.

Процес планування проводиться управлінською командою за участю провідних розробників і, за необхідності, усіх членів команди розробників. Для оцінки складності завдань використовується метод планування покером — Planning poker, який передбачає оцінювання складності задач консенсусно. Виходячи з песимістичних очікувань, задається термін виконання задач, що дає запас часу на їх виконання та забезпечує гнучкість при виникненні ускладнень.

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

2.1.3. Інструменти співпраці між командами

  • Система управління задачами (Ticket management system) Jira.

  • База знань для формування документації (Knowledge base) Confluence.

  • Git-репозиторії для взаємодії з вихідним кодом.

2.1.4. Використання Scrum-артефактів

2.1.4.1. Артефакт Definition of Ready (DoR)

Definition of Ready (DoR) у Scrum-фреймворку — це критерії готовності задачі (користувацької історії — User Story) до початку роботи над нею. Вони визначають умови, за яких користувацьку історію можна прийняти до виконання і включити у спринт. Для команди важливо мати чіткі DoR для елементів беклогу.

Критерії готовності включають наступне:

  • Історія та задача для беклогу спринту чітко визначені та оцінені на вищому рівні.

  • Технічні пріоритети встановлені на основі залежностей або технічних можливостей.

  • Історія/задача включає детальний опис, критерії прийняття у форматі списку, нефункціональні вимоги, та ризики.

  • Керівники/архітектори розуміють, що і як слід робити, і мають можливі запитання для уточнення.

  • Історія/задача знаходиться в одному зі статусів: "В аналізі", "Відкрито", "Заблоковано".

  • Історія/задача має посилання на відповідне завдання Epic.

  • Історія/задача призначена відповідальній за її виконання команді.

  • В історії/задачі зазначена фаза розробки проєкту.

  • Історія/задача незалежна.

  • Історія/задача затверджена та пріоритезована замовником на основі заявлених вимог під час сесії грумінгу (grooming session).

  • Усі блокуючі фактори для історій/задач спринту вирішені.

  • Критерії прийняття чітко описані та зрозумілі з точки зору розробки та тестування для команди розробників та контролю якості.

  • Назва історії/завдання може містити певний префікс для позначення конкретного завдання/історії: [SPIKE], [POC], [DESIGN].

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

  • Історія/задача знаходиться в статусі "Готова до розробки".

  • Усі підзадачі детально визначені (один-два дні для розробки кожної) й призначені виконавцям.

  • Усі підзадачі повинні мати один з префіксів, залежно від спеціалізації: [UX], [BA], [BE], [FE], [DB], [DEVOPS], [QA], [TW], [AUTO].

  • Для історій/задач з моделюванням даних — в описі має бути посилання на сторінку в Knowledge Base з затвердженою моделлю даних.

  • Для історій/задач з моделюванням бізнес-процесів — має бути доступним посилання на сторінку в Knowledge Base, яка містить наступну інформацію:

    • Опис точок інтеграції.

    • Опис полів форми.

    • Опис потоку користувачів.

    • Макети UX/UI.

2.1.4.2. Артефакт DoD

Означення виконаної роботи (Definition of Done) — це встановлені умови, при виконанні яких задача або користувацька історія можуть бути визнані виконаними ("Done"). Ці критерії розробляються для користувацької історії, аби команда розробників мала чітке уявлення про очікуваний результат роботи.

Критерії успішності:

  1. Розробка завершена:

    • проведено перевірку коду відповідно до внутрішніх стандартів;

    • код успішно застосовано (merged) до Master-гілки;

    • проведено статичний аналіз коду та його розгортання (критичні проблеми відсутні — покриття Unit-тестами > 80%);

    • функціональність відтестована у середовищі "UAT-Integration";

    • проведено автоматичне сканування безпеки з допомогою SAST, SCA та DAST-сканерів.

  2. Успішно пройдено тестування розробки в середовищі "UAT-Integration".

  3. Успішно пройдено ручне тестування.

  4. Розроблено автотести, які передано на CI/CD (досягнуто всіх критеріїв приймання).

  5. Зареєстровано час виконання історій/задач в Jira.

  6. Результат історії/задачі можна продемонструвати Замовнику в середовищі UAT.

  7. Статус історії/задачі в Jira встановлено як "Закрито".

  8. У разі виявлення дефектів, створено, відсортовано, призначено та заплановано усі виявлені дефекти.

2.1.5. Підходи до управління релізом ІС

Як підхід управління релізом системи використовується семантичне версіонування Платформи та компонентів Платформи.

Загальний підхід використовує три основні типи релізу:

  • MAJOR, основна версія — включає несумісні зміни API.

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

  • Версія PATCH або HOTFIX — включає виправлення помилок із можливістю зворотної сумісності.

Релізи Платформи та компонентів Платформи є незалежними.

2.1.5.1. Спринти та нумерація релізів

Тривалість спринту складає два тижні.

Шаблон нумерації релізів Платформи та компонентів Платформи на цей час є наступним: 1.X.X, де X — розширення функціональності, версія релізу. Наприклад, наприклад, 1.9.5.

Після кожного релізу новий Jenkins-pipeline створюється із назвою release-1-X-X за допомогою EDP Admin Console.

3. Контроль якості коду (code quality)

Для забезпечення високої якості коду при розробці програмного забезпечення використовуються спеціалізовані методики та інструменти, відомі як контроль якості коду (Code Quality).

3.1. Статичний аналіз коду

Основним методом, який використовують розробники, є статичний аналіз коду.

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

Наступні інструменти використовуються для проведення статичного аналізу коду:

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

  • SonarQube — це платформа з відкритим кодом, розроблена для постійного аналізу і перевірки якості коду, що дозволяє виявляти помилки та вразливості безпеки за допомогою статичного аналізу коду. Інструмент використовується на етапах Jenkins pipelines при створенні запиту на злиття змін до master-гілки, а також під час злиття гілки розробника до master-гілки.

  • Semgrep — це аналізатор статичного коду, який дозволяє виявляти потенційні помилки та вразливості в програмах Java.

  • Yelp Detect-secrets — це аналізатор коду, що допомагає виявляти секрети, що були випадково збережені в коді.

  • Checkmarx KICS (Keeping Infrastructure as Code Secure) — це рішення з відкритим кодом для статичного аналізу інфраструктури, описаної кодом.

  • Trivy — це статичний сканер Docker-образів, що виявляє вразливості та помилки конфігурації.

3.2. Покриття коду тестами (Code coverage)

Розробники використовують метод аналізу покриття коду тестами. Покриття тестами за метриками інструментів аналізу code coverage має бути більшим за 80%.

Для перевірки покриття коду тестами використовуються наступні інструменти:

  • IntelliJ IDEA — інтегроване середовище розробки ПЗ.

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

    IntelliJ IDEA застосовує декілька локальних плагінів для цих потреб, наприклад, EMMA, JaCoCo тощо.

  • SonarQube — платформа з відкритим кодом, розроблена для постійного аналізу (continuous inspection) та перевірки якості коду для автоматичного огляду зі статичним аналізом коду для виявлення помилок, та вразливостей безпеки.

3.3. Модульне тестування (Unit Testing)

Для забезпечення високої якості та "чистоти" написаного розробниками коду, використовується метод модульного тестування. Покриття коду модульними тестами має бути більшим за 80%.

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

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

Для виконання модульного тестування, розробники використовують наступні інструменти:

  • JUnit;

  • AssertJ;

  • Wiremock;

  • MockMvc;

  • Spring-boot-test.

Стандарти та рекомендації щодо проведення розробниками модульного тестування при розробці цієї інформаційної системи описані у розділі Стандарти модульного тестування поточного документа.

3.4. Покриття автоматизованими тестами

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

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

3.4.1. Інструменти тестування Платформи

Перелік інструментів, які залучені для тестування Платформи, наведений у таблиці "Інструменти тестування Платформи" (див. нижче).

Визначено декілька категорій інструментів:

  • Інструменти збереження та обміну інформації — інструменти, призначені для збереження та створення проєктної документації, та служать єдиним місцем входу до проєкту.

  • Інструменти тестування — інструменти, що використані під час ручного та автоматизованого тестування.

  • Інструменти моніторингу — інструменти, що використовуються для моніторингу стану платформи та відображення його на налаштованих попередньо моніторах.

Таблиця 1. Інструменти тестування Платформи
Категорія Назва інструменту

Інструменти збереження та обміну інформації

Система збереження вимог

JIRA, Confluence

Система збереження тест-кейсів

JIRA Plugins

Система збереження дефектів

JIRA

Інструменти тестування

API-контракти

SoapUi, RestAssured, Postman

SOAP-контракти

SoapUI,JAX-WS

Web-додатків

Selenium WebDriver, Cucumber або похідні

Desktop-систем (Camunda)

TBD

Тестування даних

WireMock (маскування даних)

Інтеграція з Трембітою

SoapUi

Тестування навантаження

Gatling

Тестування безпеки

  • owasp zap — DAST

  • trivy — continer security/SCA

  • secrets scanner — detect-secrets from yelp

  • Iaac security — kics from checkmarx

  • semgrep from owasp — SAST

Тестування доступності вебконтенту

Wave (Web Accessibility Evaluation Tool)

Інструментимоніторингу

Система моніторингу

Prometheus

Система візуалізації даних

Grafana

Загальний обсяг функціонального та нефункціонального тестування, а також методологія (стратегія) тестування інформаційної системи детально описані у розділі Функціональне тестування

3.5. Перевірка вихідного коду (Code review)

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

3.5.1. Процес огляду коду в контексті розробки інформаційної системи

  • При розгортанні компонентів інформаційної системи застосовується GitOps-підхід, заснований на процесах CI/CD. Однією з ключових особливостей цього підходу, включаючи аспект безпеки, є те, що Git служить єдиною точкою входу для внесення будь-яких змін до системи.

  • Розробник спочатку вносить зміни до своєї власної гілки захищеного віддаленого VCS-репозиторію, виконуючи команди git commit і git push.

  • Наступним кроком є створення запита на злиття змін із гілки розробника до master-гілки репозиторію — це називається Merge Request або MR.

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

  • Для злиття коду до master-гілки потрібно отримати принаймні одне підтвердження від головного розробника команди.

  • Злиття змін, що були обговорені в рамках створеного Merge Request, здійснює уповноважена особа з відповідними правами доступу.

3.5.2. Рефакторинг коду (Code refactoring)

Для покращення якості та оптимізації коду використовується стандартна методика — Code refactoring.

Code refactoring, як правило, проводиться у двох випадках:

  • рефакторинг коду в рамках code review для виправлення критичних помилок та покращення роботи застосунків;

  • рефакторинг коду як частина оптимізації системи (некритичні задачі).

Оптимізація вихідного коду визначається, але не обмежується наступними критеріями:

  • найменування (naming);

  • "чистота коду" ("Clean code");

  • оптимізація продуктивності (performance optimization): ОЗУ, ЦП, кількість запитів за секунду тощо;

  • оптимізація коду;

  • Спрощення API-контрактів.

4. Контроль за виконанням нефункціональних вимог

Розробка Платформи провадиться із дотриманням наступних принципів (нефункціональних вимог):

  • ефективність роботи (Performance efficiency);

  • безпека (Security);

  • надійність (Reliability);

  • переносимість (Portability);

  • працездатність (Operability);

  • змінність (Modifiability);

  • здатність до контролю/перевіреність (Verifiability);

  • інтеграційна взаємодія (Interoperability).