ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.05.2021
Просмотров: 244
Скачиваний: 1
1.3.1. Читабельность
Одним из важнейших показателей языка программирования является легкость чтения и понимания написанных на нем программ. На заре развития разработка ПО в основном сводилась к написанию кода. Однако в 1970-х годах была создана концепция жизненного цикла ПО. Значение собственно кодирования команд снизилось, а основной частью жизненного цикла ПО стали считать его эксплуатацию, особенно с точки зрения стоимости. Поскольку легкость эксплуатации (сопровождения) в основном определяется читабельностью программ, то она стала важной характеристикой качества программ и языков программирования.
Читабельность необходимо рассматривать лишь в контексте определенной прикладной области. Если вычислительная программа была написана на языке, для этого не предназначенном, то она может оказаться неестественной и запутанной, так что читать ее будет крайне трудно.
Далее описываются характеристики, способствующие улучшению читабельности языка программирования.
1.3.1.1. Простота
На читабельность языка программирования существенное влияние оказывает его простота. Во-первых, язык, содержащий большое количество элементарных конструкций, изучить сложнее, чем язык, в котором их меньше. Программисты, вынужденные использовать большой язык, стремятся изучить лишь некоторое его подмножество и пренебречь остальными возможностями. Такой способ изучения иногда оправдывают тем, что количество конструкций в языке слишком велико, однако этот аргумент неверен. Проблемы при чтении программы возникают всякий раз, когда автор и читатель программы изучали разные подмножества языка.
Второй характеристикой языка программирования, снижающей читабельность программ, является множественность свойств, т.е. наличие нескольких способов совершения какого-либо действия. Например, на языке C можно прибавить единицу к целому числу как минимум четырьмя различными способами:
count = count + 1; count += 1; count++; ++count;
Значения двух последних выражений несколько отличаются друг от друга и от значений остальных выражений, однако применение всех четырех приведет к одинаковым результатам. Другое дело, что наличие этого многообразия оправдано требованием эффективности программ.
Третьей потенциальной проблемой является перегрузка операций, т.е. наличие у символа операции нескольких значений. Это свойство полезно, однако может ухудшить читабельность программы, особенно если пользователи имеют право создавать собственные перегруженные операторы и делают это без разумных оснований. Например, допустимо использование операции "+" как для целочисленных, так и вещественных операндов. Перегрузка упрощает язык, уменьшая число возможных операций. Предположим, однако, что программист определил "+" с двумя операндами, представляющими собой одномерные массивы, имея в виду суммирование всех элементов обоих массивов. Поскольку обычно сложение векторов имеет совершенно иной смысл, это может сбить с толку как автора, так и читателей программы.
Однако упрощение языка может зайти слишком далеко. Форма и смысл большинства операторов языка ассемблера чрезвычайно просты. Однако чрезмерная простота снижает читабельность программ на ассемблере. Эти программы имеют менее ясную для привычного человеческого понимания структуру. Кроме того, вследствие простоты операторов размер текста программы на ассемблере намного превышает объем эквивалентной программы на языке высокого уровня.
1.3.1.2. Ортогональность
Ортогональность языка программирования означает, что любые (на практике – многие) возможные комбинации различных языковых конструкций являются осмысленными. В этом случае операторы и структуры данных языка можно записывать с помощью относительно небольшого количества элементарных конструкций, пользуясь ограниченным числом способов. При этом любая возможная комбинация этих конструкций разрешена и имеет смысл.
Например, к признаку ортогональности относится возможность использования общего набора арифметических операций (+, -, *, /) как с целыми, так и вещественными данными. Язык C более ортогонален, чем Pascal. Так в условном операторе C в качестве условия можно использовать существенно более разнообразные выражения.
Когда конструкции языка ортогональны, язык легче выучить и на нем проще писать программы, поскольку в его правилах меньше исключений и специальных случаев, требующих запоминания. Отрицательной стороной ортогональности является то, что программа не будет выдавать ошибки при компиляции, даже если она содержит логически несогласованную или заведомо неэффективную конструкцию. В частности, типичной ошибкой программирования на C является неосмысленное использование в условии оператора if выражения A=B вместо A = = B.
Здесь термин «ортогональность» соответствует ортогональности, например, двух осей координат в геометрии, где при формировании точек плоскости допускаются комбинации любых значений независимых координат X и Y.
1.3.1.3. Управляющие конструкции
Произошедшая в 1970-х годах революция в структурном программировании была вызвана плохой читабельностью разработанных в 1950-60-х годах языков, в которых недоставало управляющих операторов. В частности, распространилось мнение, что беспорядочное использование оператора безусловного перехода goto значительно снижает читабельность программы. Программа, которую можно прочесть последовательно от начала до конца, значительно проще для понимания, чем программа, для прослеживания хода выполнения которой читателю требуется переходить от одного оператора к другому, находящемуся в любом месте программы.
Однако в некоторых языках использование goto было необходимо для перехода назад: эти операторы нужны, например, для построения циклов while в языке FORTRAN 77. Использовавшимся в начале 1970-х годов версиям языка BASIC и FORTRAN не хватало управляющих операторов, которые налагали бы строгие ограничения на использование безусловных переходов, поэтому писать удобочитаемые программы на этих языках было трудно.
Большинство появившихся позднее языков программирования имело достаточное количество управляющих операторов, так что потребность в операторе безусловного перехода практически отпала. Была также доказана теорема Э.Дейкстры, согласно которой любой императивный алгоритм может быть реализован с использованием трех основных управляющих конструкций: цепочки, условного оператора и цикла while. Таким образом, управляющие конструкции языка уже не так влияют на его читабельность, как это было раньше.
1.3.1.4. Типы и структуры данных
Существенный вклад в читабельность программ вносят имеющиеся средства определения типов и данных. Если в некотором языке нет булевских данных, то для индикаторов может использоваться числовой тип. Тогда присваивание sum_is_too_big = 1 будет не совсем понятным, в то время как в языке с булевским типом можно записать выражение sum_is_too_big = true, смысл которого существенно яснее.
Аналогично, тип данных, называемый записью, обеспечивает более читабельный способ хранения информации о сотрудниках, чем набор сходных массивов, в каждом из которых хранится отдельный элемент данных, как это бывает, если в языке не предусмотрена поддержка записей. В языке FORTRAN 77, например, информация о сотрудниках может храниться в следующих массивах:
CHARACTER (LEN = 30) NAME (100)
INTEGER AGE (100), EMPLOYEE_NUMBER (100)
REAL SALARY (100)
1.3.1.5. Синтаксическая структура
Существенное влияние на читабельность программ оказывает синтаксис элементов языка программирования. Ниже перечислены три элемента синтаксической структуры языка, воздействующие на читабельность программы.
Формы идентификаторов.
Ограничение длины идентификаторов до маленьких размеров уменьшает читабельность. Например, в языке FORTRAN 77 длина идентификатора не может превышать шести символов, поэтому в нем часто невозможно использовать осмысленные названия переменных. Еще большей крайностью отличается созданный Национальным институтом стандартизации США (ANSI – American National Standards Institute) язык BASIC, в котором идентификатор может состоять только из одной буквы или сочетания, состоящего из буквы и следующей за ней цифры.
Специальные слова.
Внешний вид программ существенно зависит от набора специальных слов языка (begin, end, for, …). Особенно важен способ образования составных операторов. В некоторых языках для формирования групп используются согласованные пары слов или символов. В языке Pascal для всех управляющих структур, кроме оператора repeat, используется пара специальных слов begin-end, причем даже там, где она может быть пропущена. В языке C для той же цели используются фигурные скобки. В обоих вариантах недостатком можно считать единообразное завершение группы операторов. Иногда довольно трудно определить, какая именно группа замыкается очередным оператором end или символом }. В языках FORTRAN 90 и Ada эта проблема не так остра, поскольку для каждого вида группы операторов используется отдельный синтаксис замыкания. В языке Ada, например, для замыкания конструкции ветвления используется оператор end if, а для замыкания цикла – оператор end loop. Это пример противоречия между простотой языка Pascal, приводящей к малому количеству зарезервированных слов, и лучшей читабельностью языка Ada, обеспеченной многочисленными зарезервированными словами.
Интересный подход к выделению блоков принят в языке Python. В нем вообще нет аналогов слов begin-end, а блоки кода выделяются отступами от левой границы строки. Подобный стиль принудительно заставляет правильно структурировать программу, что повышает ее читабельность.
Другим важным вопросом является использование специальных слов языка в качестве имен переменных в программе. Если такая возможность есть, то программа может оказаться весьма запутанной. Например, в языке FORTRAN 90 такие специальные слова, как DO и END, можно использовать в качестве имен переменных, так что их появление в программе может означать не то что кажется на первый взгляд.
Форма и значение.
Облегчить чтение программы могут также операторы, само появление которых отчасти указывает на их цели. В некоторых случаях этот принцип нарушается двумя языковыми конструкциями, идентичными или похожими по форме, но различными по смыслу, который может зависеть от контекста. В языке C, например, смысл слова static зависит от контекста, в котором оно появляется. Если оно использовано при определении переменной внутри функции, это означает, что данная переменная создается во время компиляции. Если слово static используется при определении переменной вне всех функций, это означает, что она видима только в файле, содержащем данное описание.
Одна из основных претензий к набору команд оболочки операционной системы UNIX связана с тем, что названия этих команд не всегда связаны с их предназначением. Например, название используемой в системе UNIX команды grep может быть расшифровано только при наличии предварительных знаний, а также опыта работы с текстовым редактором ed системы UNIX. Для начинающих пользователей системы UNIX появление указанной команды ни о чем не говорит.
В текстовом редакторе ed команда /стандартное выражение/ выполняет поиск подстроки, совпадающей с указанным стандартным выражением. Если предварить эту команду атрибутом g, то ее выполнение станет глобальным, определяя весь редактируемый файл как область поиска. Употребление атрибута p после указанной команды приведет к печати строки, содержащей искомое выражение. Таким образом, команда g/стандартное_выражение/p, которая сокращается до grep (по первым буквам), печатает все строки файла, содержащие подстроку, совпадающую с искомым стандартным выражением.