Эксплуатация и сопровождение программы
Ранее было показано распределение временных затрат по этапам при разработке нового проекта. Однако, будучи формально правильными, приведенные данные не отражают истинного положения дел. На указанные виды работ приходится лишь от четверти до трети всех расходов, затрачиваемых в течение жизненного цикла системы. Более полное представление о временных затратах на реализацию жизненного цикла программ с учетом этапа сопровождения дают данные, приведенные ниже:
Автономное тестирование......................... 8%
Комплексное тестирование....................... 7%
Кодирование ................................................ 7%
Проектирование .......................................... 5%
Определение спецификаций ..................... 3%
Анализ требований ..................................... 3%
Сопровождение ......................................... 67%
Этап проектирования программ оказывает влияние на стиль программирования, надежность, эффективность, отладку, тестирование и эксплуатационные свойства программ. Таким образом, это важнейшая часть любой программной разработки. Однако здесь рекомендации для одного проекта или одного программиста не всегда подходят для другого проекта или другого программиста.
Вот одно очевидное утверждение: проектируйте до этапа кодирования. Желание сделать хоть что-нибудь приводит к тому, что кодирование начинают, не окончив стадию проектирования, а иногда даже не начав ее. Небольшие программы, конечно, не вызывают таких трудностей, как большие, так как с их составлением легко справится один человек. Но как организовать проектирование программ, которые так значительны по объему, что при их разработке один человек не справится? Над этой проблемой работают давно, но и сейчас мы действуем как любители, когда возникает вопрос о создании больших программ. Ниже приводятся некоторые сведения по поводу проектирования программ.
Стремление к простоте
Простота при проектировании программы - это первый шаг, ведущий к получению легко читаемой программы. Кодирование должно быть простым. Должен соблюдаться так называемый KISS-принцип: Keep It Simple, Stupid (делай проще, глупец!). Изощренное программирование может обойтись слишком дорого при отладке и модификации программы. Необычное кодирование (например, использование скрытых возможностей языка) часто препятствует отладке программы и, конечно, затрудняет ее использование другими программистами.
Было даже предложено увольнять программиста, который слишком изощрённо программирует. Действительно, для такого предположения есть основания, так как если написанная программа так сложна и непонятна, что только автор может в ней разобраться, то она никому не нужна. Программа должна отлаживаться и использоваться как автором, так и другими лицами, а ее сложность существенно затрудняет эти процессы.
Иногда пишут сложные программы с целью доказать, что без автора этих программ обойтись нельзя. Такая цель может быть оправдана с точки зрения программиста, но никак не руководителя проекта, который заинтересован в получении максимально простой программы. Сложные программы требуют больших усилий и являются показателем плохого качества программирования. Такие программы трудно отладить или модифицировать даже их авторам, и последние просто не в состоянии получить правильно работающие программы.
Структура программы должна раскрывать ее логику. Например, если тестируемая программа имеет несколько ветвей, было бы удобно расположить части программы, соответствующие каждой ветви, в определенном порядке, например по возрастанию значения параметра теста. Этот метод наиболее целесообразен, поскольку именно такого решения и ожидает тот, кто читает программу.
Существенна простота и при написании отдельных операторов. Если при синтаксическом контроле компилятор выдает сообщение:
Error 42: Error in expression (Ошибка в выражении)
А := В/*С,
то ошибку обнаружить легко. Но если оператор слишком длинный или в этой строке содержится несколько операторов, то нахождение ошибки становится затруднительным. Простота операторов помогает обнаружить ошибку и в процессе ее вычисления, если курсор указывает место ошибки (Турбо Паскаль) или в сообщении об ошибке указывается номер строки с ошибочным оператором (Фортран).
Например, сообщение: Error 62: Division by zero (Деление на ноль) указывает на строку, в которой четыре оператора:
А:= В/Е: R:=1/(A+B); C:=(A-F)/SIN(R-F); ALFA:= (A+D)/SQRT(B*C-D);
Возникает вопрос: в каком операторе ошибка?
Определить место ошибки было бы гораздо проще, еслибы в каждой строке был только один оператор.
Но не следует впадать в другую крайность. Так, например, сложный оператор:
ROON := (- B+SQRT(B*B-4*A*C)/(2*A)
легче для восприятия, чем группа операторов, на которые его можно разбить:
ВВ := В*В
А1 := А*С
А2 := 4 *А1
В1 := ВВ - А2
В2 := SQRT(B1)
BOTTOM: = 2*А
ТОР := - В+ В2
ROON: = TOP/BOTTOM
Последняя запись не только не эффективна, но и порождает новые ошибки; более того, она трудна для понимания.
Возникает проблема: как решить, что такое простой и что такое сложный оператор? Ответ зависит от пользователей и их знакомства с языком программирования, а также от программируемой задачи. Одна из очевидных рекомендаций: при программировании числовых выражений оператор не должен превышать одной строки (60-70 позиций). Если оператор длиннее, то его следует разбить на два.
Психологи считают, что семь элементов - оптимальная длина оператора. Это длина телефонного номера. По-видимому, это число является подходящим ограничением. Каждый программист может варьировать эту границу в зависимости от своих индивидуальных потребностей. Кроме того, он должен решить, что считать элементом в операторе. По мере знакомства программиста с языком программирования длина оператора, как правило, увеличивается.
Еще один путь упрощения программ - это постоянство приемов кодирования. Например, переключатели программы должны всегда использоваться одинаковым образом: значение “О” для обозначения состояния <Выключено>, значение “1” для обозначения состояния <Включено>. Кроме того, желательно для всех таблиц в одной программе применять один и тот же метод просмотра. При вводе используйте один и тот же размер поля для всех вещественных переменных и одинаковый размер поля для всех целых переменных. Это поможет вам избежать большого количества ошибок. Кроме того, лучше не допускать смешения целых и вещественных значений при записи входных данных, если это возможно.
4.5. “Дружественность” к программисту. Читаемость программ
Кроме автора, программу должен читать кто-нибудь еще. Если программист знает, что кто-то другой будет читать его программу, то отношение к кодированию резко меняется. Программу снабжают комментариями, делят на параграфы, она становится ясной и точной.
В некоторых разработках использовался метод, гарантирующий простоту программирования, - так называемая контролируемая система программирования.
В этой системе над составлением каждой программы работают по крайней мере два программиста. Первый пишет программу, второй должен просмотреть и понять ее. Эта система имеет два преимущества. Во-первых, она гарантирует получение простых и понятных программ. Во-вторых, если первый программист по какой-либо причине не может довести программу до конца, другой в состоянии заменить его.
Аналогичный метод - это оценка программы на выполнение стандартов. Для данной вычислительной машины устанавливаются определенные стандарты программирования. Затем каждая программа проверяется на выполнение этих стандартов, прежде чем она будет записана в библиотеку программ. Обычно все программисты по очереди делают такую оценку.
Описание задачи
Нет ничего хуже, чем неполное или неправильное определение требований к программному обеспечению. Если заказчики не могут определить свои запросы или если программист не может понять, чего хочет заказчик (под программистом здесь подразумевается тот, кто пишет спецификации проекта), то при разработке проекта можно ожидать серьезных затруднений. Говорят, что идеальная программа - это такая программа, которая дает точный желаемый выход при неясно сформулированных требованиях пользователя. Однако редко нечеткое описание требований приводит к желаемому результату.
Один из путей уточнения описания требований заказчика - это проведение регулярных просмотров для координации установленных требований и действительных намерений заказчика. В результате этих проверок могут быть обнаружены несоответствия, которые при отсутствии таких проверок выявились бы значительно позже. Следует отметить важность полноты и непротиворечивости предварительного проекта. Лучше проявить прагматизм в начале проектирования, чем вносить изменения, когда система уже готова.
Постановка задачи
Задача может быть определена хорошо или плохо. Для плохо сформулированной задачи нельзя составить четкого проекта программы. К сожалению, большинство задач, подлежащих программированию, определены недостаточно хорошо.
Но если вам удастся четко определить задачу до этапа программирования, вы сэкономите много времени и избежите лишней работы.
Если в проекте программы имеются пробелы, это обнаружится или во время программирования, или после передачи разработанной программы пользователю. Впоследствии программу надо будет переделать в соответствии с правильным проектом. Очень много переделок в программе связано с тем, что никто не заботился о правильности проекта с самого начала.
Задачи, подлежащие программированию, обычно ставят перед теми, кто будет программировать. Имеются две причины, по которым программист приступает к работе без полного понимания задачи.
Во-первых, заказчик, ставящий задачу, может не иметь четкого представления о ней; во-вторых, программист может не понять, чего хочет заказчик. Когда программист и постановщик задачи - не одно лицо, первый вынужден работать с представлением второго о данной задаче.
Заказчик должен подготовить описание задачи. Это необходимо даже в том случае, если программист является одновременно и постановщиком задачи. Такое описание заставит заказчика серьезно обдумать задачу и четко определить ее постановку. Далее должно состояться обсуждение задачи программистом и заказчиком. Если задача достаточно сложна, то обсуждение лучше провести до того, как заказчик попытается описать задачу. Это поможет ему лучше оценить возможности вычислительной машины, а также программиста. Такое обсуждение часто помогает заказчику разобраться в своем представлении задачи.
Далее программист должен переписать спецификации задачи, ориентируясь на вычислительную машину и предполагаемый язык программирования. Необходимо сжатое, но полное описание задачи, объем которого может составлять от нескольких предложений для небольшой задачи до целой книги в случае большой системы. Это описание является основой для большого количества документации.
Затем программист и заказчик должны вместе тщательно изучить написанные спецификации задачи, чтобы быть уверенными в их правильном понимании. Возможно, понадобится повторить это несколько раз. Необходимо, чтобы заказчик уяснил для себя: он собирается получить именно то, что описано в спецификациях. Более поздние изменения или добавления не только приводят к удорожанию проекта, но и задерживают его завершение. Любая небрежность, допущенная на стадии определения задачи, вызовет впоследствии осложнения. Добивайтесь точности при определении задачи!
После того как задача определена, лучше всего зафиксировать спецификации и в дальнейшем не вносить в них каких-либо изменений или дополнений. Любой пересмотр откладывается на более позднее время. В том случае, если изменения вносятся после начала программирования, следует увеличить расходы и выделить дополнительное время на проектирование. Более того, эти дополнительные расходы должны быть достаточно высоки. Это один из способов контролировать изменения и предусматривать дополнительное время на их внесение. Многие проекты невозможно планировать из-за постоянно изменяющихся спецификаций. Заказчики, считающие, что ничего не стоит внести незначительное изменение в выходные результаты, не поймут также и то, почему нельзя сделать небольшое изменение, например, в главном входном файле, не вызвав дополнительных издержек и расхода времени. Отсюда следует, что надо приучить заказчиков дорого платить за все изменения. Это заставит их более тщательно составлять спецификации.
Выбор алгоритма
Важнейшим шагом для получения эффективной и правильной программы является составление алгоритма. При этом предполагаются правильный выбор языка и полнота спецификаций программы. Таким образом, хороший алгоритм - необходимое, но не достаточное условие хорошей программы. Если пользователь формулирует задачу в виде четкого алгоритма, то процесс проектирования существенно облегчается. Вот простой пример вычисления значения Y:
Y= Ax3+ Bx2+ Cx + D.
Прямое решение (Фортран) выглядит так:
Y= А*Х**3 + В*Х**2 + С*Х + D (где **- возведение в степень).
Но повторное умножение более эффективно, чем возведение в степень при небольшом целом показателе степени, поэтому алгоритм может быть изменен следующим образом:
Y= А*Х*Х*Х + В*Х*Х + С*Х + D.
В Турбо Паскале нет операции возведения в степень, поэтому выражение для расчета Y целесообразно записать именно в этом виде.
При таком алгоритме требуется выполнить шесть действий умножения и три действия сложения. Казалось бы, больше ничего нельзя улучшить. В действительности этот алгоритм можно упростить, если воспользоваться, например, разложением полинома (методом Горнера):
Y = Ах3+ Вх2+ Cx + D = х(Ах2+ Вх + С) + D = х(х(Ах + В) + С) + D.
Теперь алгоритм вычисления имеет вид:
Y = Х*(Х*(А*Х + В) + С) + D.
В этом случае требуется выполнить по три действия умножения и сложения. Таким образом, мы уменьшили число операций, увеличив при этом точность.