Пользовательские интерфейсы
До сих пор мы говорили главным образом об интерфейсах между компонентами программы или несколькими программами. Но есть же и еще один, очень важный, вид интерфейса – между программой и ее пользователями-людьми.
Большинство примеров программ в этой книге основаны на работе с текстом, так что их пользовательский интерфейс представляется более-менее очевидным. В предыдущем разделе мы выяснили, что ошибки надо отслеживать и сообщать о них; при необходимости должны предприниматься попытки восстановления. Сообщение об ошибке должно включать в себя всю доступную информацию и быть максимально информативным для каждого конкретного контекста; незачем выводить:
estrdup failed
Когда можно сообщить:
markov: estrdup("Derrida") неудача: мало места в памяти
Нам ничего не стоит включить дополнительную информацию (вспомните, как мы это делали в estrdup), а пользователю это может помочь идентифицировать проблему или хотя бы просто подобрать корректные входные данные.
Если пользователь допустил ошибку, программа должна показать ему пример правильного ввода, как это сделано в функциях типа:
Имя программы, вырабатываемое функцией prog name, идентифицирует источник сообщения. Это особенно важно в случае, если программа является частью какого-то большого процесса. Если программа будет выводить сообщения вроде syntax error или estrdup failed, то пользователь может просто не понять, откуда пришло сообщение.
Текст сообщений об ошибке, подсказок и окон диалога должен обязательно четко описывать допустимые значения: не утверждайте, что параметр слишком велик, а приведите диапазон допустимых значений для этого параметра. Когда это возможно, текст должен сам по себе являться корректным вводом, например полной командной строкой с правильно заданным параметром. Это не только даст возможность пользователю понять, чего же от него ждут, но и позволит сохранить такой выводимый текст в файле (или "вырезать" его с помощью мыши) и потом использовать для запуска какого-то следующего процесса. Здесь, кстати, сразу становится виден один из недостатков окон диалога: их содержимое довольно трудно запомнить для дальнейшего использования.
Эффективный способ создать хороший пользовательский интерфейс для ввода – спроектировать специализированный язык для установки параметров, контролирования действий и т. п. Интерфейсы, основанные на языках, мы подробно обсудим в главе 9.
Защитное программирование, то есть такое программирование, при котором можно быть уверенным, что программе не страшен никакой некорректный ввод, не только защитит пользователя от самого себя и своих ошибок, но и предохранит всю систему в целом. Об этом речь пойдет в главе 6, посвященной тестированию программ.
Большинство людей пользуется сейчас графическими интерфейсами. Графические пользовательские интерфейсы – отдельная большая тема, поэтому мы упомянем лишь о нескольких связанных с ними моментах. Во-первых, графический интерфейс трудно сделать "правильным", поскольку его пригодность и удобство оцениваются пользователями субъективно. Во-вторых, с чисто практической точки зрения в системе с графическим пользовательским интерфейсом размер кода, обрабатывающего взаимодействие с пользователем, как правило, гораздо больше; чем код для любого самого сложного алгоритма.
Тем не менее в проектировании как внутренней реализации, так и наружного дизайна пользовательского интерфейса действуют одни и те же принципы. С точки зрения пользователя, хорошая проработка вопросов стиля – простоты, прозрачности, стандартности, предсказуемости, привычности и строгости – является синонимом хорошего интерфейса; отсутствие же перечисленных качеств наверняка приведет к зачислению интерфейса в разряд неудобных.
Стандартность и привычность интерфейса крайне желательны; это требование включает в себя последовательное использование терминов, модулей, форматов, шрифтов, цветов, размеров и всех остальных составляющих графическую среду элементов. Сколько различных английских слов используется для выхода из программы или закрытия окна? С десяток – от Abandon до control-Z; подобная непоследовательность может слегка запутать даже пользователя, для которого английский является родным языком, иностранца же она просто заводит в тупик.
Внутри кода, работающего с графикой, интерфейсам следует уделить особое внимание, поскольку эти системы, как правило, велики и сложны, а процесс ввода данных (и вообще получение реакции пользователя) весьма нетривиален. В разработке графических пользовательских интерфейсов большим преимуществом обладает объектно-ориентированная модель программирования, поскольку она предоставляет способ инкапсуляции состояний и поведения окон. При этом используется наследование для объединения одинаковых моментов в базовые классы и вынесения различий в классы-наследники.