Модифицируемость кода (Changeability QA)

Оглавление

Содержимое

Программный продукт обладает свойст­вом модифицируемости, если он имеет структуру, позволяющую легко вносить требуемые изменения.

Для начала стоит отметить традиционно разные подходы в программировании. В Windows изначально развивался подход комбайнов, вся многочисленная функциональность в одном приложении. В Linux использовались маленькие утилиты имеющие строго ограниченную функциональность для конкретных целей. В современном мире кроссплатформенных приложений такое деление уже не играет особой роли.

Не смотря на это у программ есть назначение, ведь они создаются для решения каких-то конкретных задач. Любое изменение в функционале, такое как наращивание или отсечение возможностей, а так же усовершенствование существующих алгоритмов связано со свойством модифицируемости. Наплевательский подход состоит в том, чтобы держать одних и тех же программистов, которые будут худо ли бедно хранить маркеры изменений у себя в голове.

Чисто умозрительно представим весь код программы в виде таблицы в базе данных, тогда для его модификации нам бы потребовался язык манипулирования данными (Data Manipulation Language). Функции языков DML определяются первым словом в предложении (часто называемом запросом), которое почти всегда является глаголом. В случае с SQL эти глаголы — выбрать (select), вставить (insert), обновить (update), удалить (delete).

Для примера простой код на C++:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return EXIT_SUCCESS;
}

В сложные детали самодокументированного кода или иной технологии вдаваться не будем. Везде будут использованы комментарии, которые как правило есть практически в любом языке программирования.

Деление по структуре кода могло бы иметь следующий вид:

// begin: заголовочные файлы
#include <stdlib.h>
#include <stdio.h>
// end: заголовочные файлы

// begin: точка входа в приложение
int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return EXIT_SUCCESS;
}
// end: точка входа в приложение

Ключевой особенностью группировки являются синтаксические конструкции. В классе это могут быть закрытые поля, искусственное выделение свойств и методов. Главное, что для конкретной программы подобное разделение не уникально.

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

Предположим есть некий функционал:

1. ...
2. ...
3. поздороваться с миром.
n. ...

Где 1…n уникальные идентификаторы функционала.

Буквы обозначают.

  • b — begin (начало секции)
  • e — end (конец секции)
  • c — continue (секция до конца строки)

Вставили новый функционал (insert):

#include <stdlib.h>
#include <stdio.h> // 3.c

int main(int argc, char* argv[])
{
    printf("Hello World!\n"); // 3.c
    return EXIT_SUCCESS;
}

Обновили текущий функционал (update):

#include <stdlib.h>
#include <stdio.h> // 3.c

// 3.b
inline void hello_world()
{
    printf("Hello World!\n");
}
// 3.e

int main(int argc, char* argv[])
{
    hello_world(); // 3.c
    return EXIT_SUCCESS;
}

Удалили текущий функционал (delete):

#include <stdlib.h>

int main(int argc, char* argv[])
{
    return EXIT_SUCCESS;
}

Выделение нового функционала (select) могло бы осуществляться простым поиском по файлам проекта «// 3.».

Конечно, всё это условность и можно использовать более совершенные методы отвечающие за возможность модифицируемости. В статье же хотелось показать сам принцип. Произведя операцию удаления функционала под номером 3 после вставки или после обновления получаем абсолютно одинаковые результаты. Та же директива включения stdlib.h нужна была лишь для использования EXIT_SUCCESS.

Текущий список функционала программы:

  1. запустить приложение.
  2. выйти из приложения.
  3. поздороваться с миром.

Код с маркерами изменения функционала:

#include <stdlib.h> // 2.c
#include <stdio.h> // 3.c

// 3.b
inline void hello_world()
{
    printf("Hello World!\n");
}
// 3.e

// 1.b
int main(int argc, char* argv[])
{
    hello_world(); // 3.c
    return EXIT_SUCCESS; // 2.c
}
// 1.e

Или вариант не меняющий количество строк кода. Так же не мешает однострочным комментариям и самодокументируемому коду. Применительно к C++ не прерывает многострочные комментарии (/*..*/):

#include <stdlib.h> // 2.c
#include <stdio.h> // 3.c

inline void hello_world() // 3.b
{
    printf("Hello World!\n");
} // 3.e

int main(int argc, char* argv[]) // 1.b
{
    hello_world(); // 3.c
    return EXIT_SUCCESS; // 2.c
} // 1.e

Литература

Добавить комментарий