Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A_Kpo.pdf
Скачиваний:
157
Добавлен:
10.06.2015
Размер:
1.82 Mб
Скачать

будут реже приводить к ошибкам, поскольку вы не сможете по невнимательности внести в идентичные фрагменты программы чуть различающиеся изменения

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

41.Сокрытие информации. Две категории секретов программ.

Ссокрытием информации тесно связана идея «секретов» — аспектов проектирования и реализации, которые разработчик ПО решает скрыть в каком-то месте от остальной части программы.

Сокрытие информации — мощный метод избавления от нерациональной и повторной работы. Оно особенно эффективно в инкрементных средах с высоким уровнем изменений.

Ответ на вопрос «Что надо скрыть?» устраняет много сложных проблем конструирования. Сокрытие информации — один из основных принципов и структурного, и объектно-ориентированного проектирования.

Впервом случае сокрытие информации лежит в основе идеи «черных ящиков». Во втором оно дает начало концепциям инкапсуляции.

Вконтексте Главного Технического Принципа разработки ПО (уменьшение сложности) сокрытие информации оказывается особенно мощным эвристическим принципом, так как все его аспекты и даже само название подчеркивают сокрытие сложности. При сокрытии информации каждый класс (пакет, метод) характеризуется аспектами проектирования или конструирования, которые он скрывает от остальных классов.

Секретом может быть источник вероятных изменений, формат файла, реализация типа данных или область, изоляция которой требуется для сведения к минимуму вреда от возможных ошибок. Класс должен скрывать эту информацию и защищать свое право на «личную жизнь». Небольшие изменения системы могут влиять на несколько методов класса, но не должны распространяться за его интерфейс. Интерфейсы классов должны принятие решения о том, какие свойства сделать доступными 6ыть полными вне класса, а какие оставить секретными. Класс может использовать несколько типов данных, не раскрывая сведений о них. Этот аспект проектирования классов называют «видимостью», так как он определяет, какие свойства класса «видимы» или «доступны» извне. Интерфейс класса должен сообщать как можно меньше о внутренней работе класса.

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

60

Избыточное распространение информации в программе

Связанные с сокрытием информации секреты относятся к двум общим категориям:

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

2.секреты, которые скрывают источники изменений с целью локализации результатов возможных изменений в одном месте.

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

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

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

Если программа будет обращаться к данным только через методы доступа, детали реализации будут известны только этим методам.

Опасность использования глобальных переменных

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

Глобальные данные имеют два главных недостатка:

методы, обращающиеся к глобальным данным, не знают о том, что другие методы тоже обращаются к этим данным, или же методы знают об этом, но не знают, что именно другие методы делают с глобальными данными.

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

Конечно, это предполагает, что система включает грамотно спроектированные небольшие классы. Если программа использует огромные классы, включающие десятки методов, различие между данными класса

[Введите текст]

и глобальными данными стирается, и данные приобретают многие недостатки, характерные для глобальных данных.

42.Прерывания программы в «неудобное» время

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

Даже в задачах, реализованных в одном процессе, где связи легко организовать, так как передача данных идет в одном адресном пространстве, имеются возможность утраты целостности данных(искажения) при использовании неправильных конструкций языка программирования. Проблема целостности данных возникает тогда, когда данные, связанные в массив, таблицу или другую структуру данных передаются во время исполнения задачи. Если во время передачи произойдет «несвоевременное» прерывание, некоторые из данных структуры будут связаны со старыми значениями, а некоторые с новыми и весь набор данных может оказаться неверным.

Следующая утрата целостности данных может произойти, когда переменная используется несколько раз в последовательности операторов и её правильное окончательное значение формируется после последнего оператора. В этом случае прерывание задачи более приоритетной задачей, использующей ту же переменную, может привести к ошибке – использованию в прервавшей приоритетной задаче «недообработанного» значения переменной.

Например, следующая короткая последовательность операторов используется, чтобы ограничить величину переменной ( нелинейность типа насыщения)

x = some_calculation();

if (x≥ max) x=max;

Если этот код находится в низкоприоритетной задаче, а высокоприоритетная задача использует значение х, и прерывание произошло между этими двумя строками кода, то высокоприоритетная задача будет использовать значение х до того, как оно будет обрезано второй строкой. Этот промежуточный результат не предназначен для использования и может являться ошибочным. Высокоприоритетная задача может получить ошибочное значение х. Описанные проблемы возникают не всегда. Проблема отсутствует, если прерывание пришло в «правильное» время. Но оно приходит асинхронно относительно процесса решения задачи. Мы не можем ни предсказать, ни управлять моментом прихода прерывания. Существует вероятность того, что оно придет в неправильное время и рассмотренные ошибки произойдут. Беда в том, что вероятность попадания прерывания на неудачный момент очень мала и при отладке не реализуется, тем более, что при автономной отладке вообще всё работает правильно( прерываний нет по определению). Но по иизвестному закону подлости отмеченные ошибки несмотря на низкую вероятность обязательно проявятся при эксплуатации, поскольку за время эксплуатации число реализаций программы будет горазда больше, чем при отладке.

62

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

Резюме эвристических принципов конструирования

Следующие эвристические принципы также иногда бывают полезны:

1.рисуйте диаграммы - лучше один раз увидеть, чем сто раз услышать.

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

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

43.Адаптации программы к возможным изменениям

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

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

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

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

Ниже описано несколько областей, изменяющихся чаще всего:

1. Бизнес правилаусловия контрактов,

[Введите текст]

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

3.Ввод-вывод информации. Анализ всех внешних интерфейсов на предмет изменения числа полей представления данных, последовательность данных и т.п.

4.Сложные аспекты проектирования и конструирования,

5.Размеры структур данных.

Описанное в настоящем разделе относится к программированию «в малом» при разработке программных модулей. Не менее важно закладывать легкость проведения изменений при программировании «в большом» – при разработке ПО задачи. Рассмотренные методы иерархического структурирования, как отмечалось ранее, помогают решить эту задачу.

44.Защита от ошибок

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

Выход здесь один: коль скоро мы не можем гарантировать отсутствие ошибок, то надо предпринять меры, чтобы их проявление не приводило к фатальным последствиям для критических систем. Термин защитное программирование (конструирование) относится к приемам и эвристическим методам создания программ устойчивых к ошибками и к ошибкам данных. Трактовка слов «устойчивый к ошибкам» оказывается не простой и приведена ниже.

Конечно, лучший способ защитного программирования — изначально не плодить ошибок. Итеративное проектирование, написание псевдокода и тестов до начала кодирования, проверка на моделях закладываемых в систему данных и низкоуровневая взаимная проверка соответствия проекту всех разрабатываемых артефактов с обеспечением однозначной интерпретации представленной в них информации(верификация) - это все, что помогает избежать добавления дефектов. Поэтому этим известным технологиям должен быть дан высокий приоритет наряду с защитным конструированием.

Однако, конструирование защиты от ошибок в «малом» на уровне программ и модулей и аварийной защиты ПО в «большом» обязательно должно быть использовано для создания качественного программного обеспечения.

Хорошая программа никогда не выдает «мусор» на выходе независимо от того, что у нее было на входе. Вместо этого она использует принципы: «мусор на входе — ничего на выходе», «мусор на входе — сообщение об ошибке на выходе» или «мусор на выходе – замена на не точный, но допустимый результат». По сегодняшним стандартам «мусор на входе — мусор на выходе» — признак небрежного, небезопасного кода.

64

Защита от ошибок, а точнее придание программному обеспечению свойств информационной устойчивости к ошибкам должна быть построена по иерархическому принципу: можно подразделить её на низкоуровневую защиту отдельных структурных единиц ПО и защиту всего ПО и системы на системном уровне. Во многих случаях низкоуровневая защита также вызывает системную защиту, но это происходит не всегда.

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

Мы рассматриваем проявление ошибок в уже скомпилированных программах в процессе их работы. Синтаксические и семантические ошибки, фиксируемые компилятором, нас в данном изложении не интересуют, так как они на стадии компиляции и устраняются.

Защита от ошибок строится на

1.Обнаружении факта неправильного функционирования ПО – следствия проявившейся ошибки или неверных данных средствами контроля результатов функционирования ПО

2.Непосредственном контроле входных данных на их допустимость,

3.Локализации ошибки – определения структурного элемента системы или ПО, в котором она находится,

4.Определение и реализация мер безопасности, либо полностью восстанавливающих работоспособность ПО и системы, либо обеспечивающих функционирование СТС с ухудшением характеристик его качества, либо организованно прекращающих функционирование – аварийный останов ПО и как правило СТС.

При этом определение и реализация мер безопасности зависит от характера ошибки т.е. от полноты работы, проведенной на этапе локализации ошибки. В том случае, когда эта локализация невозможна или груба меры защиты вынужденно будут достаточно общими и связаны с аварийным прекращением работы ПО.

Виды контроля работы ПО. Контроль работы ПО встроенными средствами без прекращения его функционирования

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

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

[Введите текст]

заданной траектории при её неуправляемом движении вследствие того же зависания ПО. Если «пожару

не дать разгореться», то он может быть локализован и быстро погашен. Чем раньше обнаружена ошибка, тем ранее будет прекращена неправильная работа ПО, тем к меньшему ущербу эта неправильная ра-

бота ПО приведет, тем большая вероятность того, что предпринятые защитные меры спасут процесс или систему от необратимого развития событий и разрушения. Именно с целью раннего обнаружения ошибок и проводится контроль работы ПО, так как в принципе в процессе эксплуатации системы контроль работы ПО можно не проводить, а контролировать только поведение системы.

Например, можно контролировать работу ПО бухгалтерии по специальным алгоритмам бухгалтерии, проводя текущие сверки, но можно этого не делать и дождаться пока ошибки ПО не скажутся на финансовом положении предприятия – тогда они станут видны всем, но видны с опозданием.

Поэтому разработчики ПО для критических систем понимают необходимость контроля работы не только системы, но и её ПО.

Но ПО работает очень быстро и человек не в силах отследить изменения значений переменных, логических условий и т.п., если не предпринимать специальных мер. Здесь возможны три варианта:

1.Автоматический контроль работы ПО встроенными в ПО средствами, когда некоторые части работающего ПО осуществляют контроль правильности его работы и работы системы. В этом случае контроль работы ПО осуществляется в реальном времени и без прекращения нормального функционирования системы. Правда, это приводит к увеличению размера ПО до 20%.

2.Контроль работы ПО в точках его останова внешними по отношению к ПО средствами. Такой контроль приводит для систем реального времени к прекращению нормального функционирования системы и требует к тому же повторного запуска системы и ПО.

3.Контроль путем сбора и представления на более высокий уровень иерархии или оператору данных по работе ПО, полученных результатах и т.п. Сбор и представление этих данных должен происходить автоматически внутри работающего ПО фрагментами самого ПО. Здесь можно говорить о контроле без прекращения функционирования системы, но запаздывание оператора на полученную контрольную информацию будет велико и в большинстве случаев не соответствует требованиям автоматических систем реального времени. Кроме того поток контролируемых данных к оператору может быть огромен и необходимы меры по его сжатию или прореживанию.

Разница между п.1 и п.3 в том, что в первом случае анализ и принятие решения происходит сразу же и в самом ПО. Поэтому автоматический контроль правильности работы ПО в процессе его эксплуатации является важной и актуальной задачей и в дальнейшем мы рассмотрим именно такой вид контроля работы ПО.

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

66

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]