Некоторые говорят, что разработка программного обеспечения является сложной из-за сложности . Это может быть правдой, но это определение не помогает нам находить решения для уменьшения сложности. Нам нужен лучший способ объяснить сложность нетехническим людям.
Реальность такова, что при кодировании размер проекта имеет значение . Размер измеряется количеством путей через базу кода, а не количеством строк кода. Размер пропорционален количеству функциональных точек в проекте.
Есть много ИТ-специалистов, которые преуспевают с программами определенного размера, а затем с треском проваливаются, принимая более сложные программы. Сложность возрастает с увеличением размера , поскольку число путей увеличения экспоненциально в больших программах.
Практически любой (даже генеральный директор :-)) может построить привет, мир! применение; приложение, которое имеет только один путь через него и настолько простое, насколько вы можете получить. Некоторые руководители пишут просто привет, мир! Программируют и неправильно убеждают себя, что разработка проста . Привет мир! есть только один путь, и практически любой может написать это.
main() { printf( "hello, world" ); }
Если у вас есть руководитель, который не может даже завершить
привет, мир, то вы должны забрать его компьютер ?
Сложность определена
По мере того как программы становятся более сложными, количество решений , которые необходимо принять, увеличивается, а глубина дерева вызовов увеличивается . Каждая нетривиальная рутина будет проходить через нее несколько путей .
Если ваша средняя глубина вызова составляет 10 со средним числом 4 путей в каждой процедуре, то это представляет более 1 миллиона путей. Если средняя глубина вызова составляет 15, то это представляет 107 миллионов путей. Растущие сложные программы имеют большую глубину вызовов, чем когда-либо, а распределенные приложения увеличивают глубину вызовов, даже если глубина вызовов системы является аддитивной. Это то, что мы подразумеваем под сложностью; для нас невозможно проверить все различные пути в стиле черного ящика.
Теперь в действительности каждая комбинация путей невозможна, но вам нужно всего лишь оставить пробелы в нескольких подпрограммах, и у вас будут сотни, если не тысячи путей, где вычисления и решения могут пойти не так.
Кроме того, неправильные вычисления или решения, расположенные выше в дереве вызовов, могут привести к трудностям в поиске дефектов, которые могут взорваться намного дальше от источника проблемы.
Какие дефекты?
Дефекты программного обеспечения возникают по очень простым причинам, выполняется неправильный расчет, который приводит к неверному выходному значению. Иногда нет вообще никакого расчета, потому что входные данные не проверяются на согласованность и эти данные либо хранятся неправильно, либо приводят к неправильным вычислениям.
Мы признаем, что имеем дефект, только когда видим выходное значение и признаем, что оно неверно. Скорее всего, QA видит это и говорит нам, что мы не правы.
По сути, мы следуем по правильному пути через узлы 1, 2, 3, 4 и 5. В точке 6 мы делаем расчет просчета , а затем у нас неправильные значения в точках 7 и 8 и обнаруживаем проблему в узле 9. Поэтому, как только у нас произойдет просчет, мы будем либо продолжать делать неправильные вычисления, либо принимать неправильные решения и идти по неверным путям (где мы затем будем делать неправильные вычисления).
Не все дефекты равны
Ясно, что чем больше расстояние между просчетом и его обнаружением, тем труднее будет обнаружить дефекты . Чем длиннее глубина вызова, тем больше вероятность того, что между источником и обнаружением может быть большое расстояние, другими словами:
Сегодня мы создаем сложные системы из множества взаимодействующих приложений, и глубина вызовов экспоненциально зависит от размера системы. Это то, что мы подразумеваем под
сложностью программного обеспечения.
Уменьшение сложности
Сложность уменьшается для каждой функции, где:
- Вы можете определить, когда непоследовательные параметры передаются в функцию
- Все вычисления внутри функции выполнены правильно
- Все решения через код принимаются правильно
Лучший способ решить все 3 проблемы — это формальное планирование и разработка. Двумя методологиями, непосредственно ориентированными на планирование на личном и командном уровне, являются « Процесс персонального программного обеспечения» (PSP) и « Процесс группового программного обеспечения» (TSP), изобретенный Уоттсом Хамфри.
Выявить противоречивые параметры проще всего, когда вы используете Design By Contract (DbC), метод, впервые внедренный в язык программирования Eiffel. Важно использовать DbC для всех функций, которые находятся в основных путях приложения.
Использование разработки через тестирование — это верный способ убедиться, что все вычисления внутри функции выполнены правильно, но только если вы пишете тесты для каждого пути через функцию.
Убедиться в том, что все вычисления внутри функции выполняются правильно и что правильные решения принимаются с помощью кода, лучше всего выполнять с помощью проверок кода (см. « Проверки не являются обязательными», а « Специалисты по программному обеспечению выполняют проверки» ).
Все методы, которые могут использоваться, чтобы уменьшить сложность и доказать правильность вашей программы, описаны в отладчиках для проигравших . Отладчики NB как единственный формализм будут хорошо работать только для систем с низкой глубиной вызовов и низким уровнем ветвления.
Вывод
Поэтому сложность в разработке программного обеспечения заключается в том, чтобы обеспечить учет всех путей кода. Во все более сложных программных системах число путей кода увеличивается экспоненциально с глубиной вызова. Использование формальных методов — единственный способ объяснить все пути в сложной программе; в противном случае количество дефектов будет увеличиваться экспоненциально, что приведет к провалу проекта.
Только проекты с низкой сложностью (т. Е. С малой глубиной вызовов) могут позволить себе быть неформальным и использовать только отладчики для получения контроля над системными путями. Поскольку система становится больше, только использование формальных механизмов может уменьшить сложность и разработать сложные системы. Эти формальные механизмы включают в себя:
- Персональный программный процесс и командный программный процесс
- Проектирование по контракту (с помощью аспектно-ориентированного программирования)
- Разработка через тестирование
- Проверка кода и дизайна