Ада 95

Качество и стиль.

[Ada 95 Quality and Style Guide]

 

 

Руководство для профессиональных программистов.

[Guidelines for Professional Programmers]

 

 

Октябрь 1995

 

 

Версия 01.00.10 SPC-94093-CMC

 

Оглавление

 

Предисловие.

Авторы.

Глава 1:   Введение

Глава 2:   Представление исходного текста

Глава 3:   Удобочитаемость

Глава 4:   Структура программы

Глава 5:   Программирование методов

Глава 6:   Параллелизм

Глава 7:   Мобильность

Глава 8:   Возможность многократного использования

Глава 9:   Объектно-ориентированные особенности

Глава 10: Оптимизация

Глава 11: Полный пример приложения 

Приложение

Ссылки

Список литературы

Индексы

Поиск ключевого слова

 

 

 

 

 

 

 

Подготовлено Software Productivity Consortium, SPC Building 2214 Rock Hill Road Herndon, VA 22070 для Министерства обороны, Ada Joint Program Office.

 

Copyright 1995, Software Productivity Consortium, Herndon, Virginia.

 

Этот документ может свободно копироваться и распространятся в США, или других странах. Это стало возможным в соответствии с лицензией DoD Ada Joint  и позволяет использовать это материал, без каких бы то ни было ограничений. Данный материал частично базируется на работе, спонсируемой DoD Ada Joint Program Office с участием Advanced Research Projects Agency. Grant #MDA972-92-J-1018. Содержание не обязательно отражает позицию или политику Американского Правительства и не требует никакого официального одобрения.

 

Эта книга доступна в переплете за $30 в:

Software Productivity Consortium

ATTN:Gerry Brewer

2214 Rock Hill Road

Herndon, VA 22070

Phone: 703/742-7211

 

 

Software Productivity Consortium не должен упоминаться при рекламировании или гласности, имеющей отношение к этому материалу без предварительного письменного разрешения Software Productivity Consortium, Inc.

 

 

SOFTWARE PRODUCTIVITY CONSORTIUM, INC. НЕ ДАЕТ НИКАКИХ ЯВНЫХ ИЛИ НЕЯВНЫХ ГАРАНТИЙ ПРИГОДНОСТИ КАК САМОГО МАТЕРИАЛА ТАК И НА ЕГО ИСПОЛЬЗОВАНИЕ.

 

 

 

Ada-ASSURED торговая марка GrammaTech, Inc.

 

ADARTS сервисная марка Software Productivity Consortium Limited Partnership.

 

IBM зарегистрированная торговая марка International Business Machines Corporation.

 

VAX зарегистрированная торговая марка Digital Equipment Corporation.

 

X Window System торговая марка Massachusetts Institute of Technology.

 

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

 

Цель

 

Цель данного материала помочь программистам создавать более качественные программы с использованием языка программирования Ада, идентифицируя ряд стилистических рекомендаций которые непосредственно влияют на качество Ада-программ. Этот материал не заменяет Ada Reference Manual (1995) или Rationale (1995) и не служит обучающим руководством по программированию на языке Ада. Также оно не является руководством по переходу от Ада83 к Ада95 (transitioning from Ada 83 to Ada 95). Читатель при необходимости должен обращаться к вышеуказанным руководствам.

 

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

 

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

 

 

 

Замечания

 

Ada Joint Program Office (AJPO) инициировало работы по созданию новой версии документа путем слияния оригинального руководства - Ada Quality and Style: Guidelines for Professional Programmers, version 02.01.01 (AQ&S 83) (Software Productivity Consortium 1992), ориентированного на Ада83, с рядом рекомендаций, используемых в Ада95. Эти нововведения базируются на данных доступных из Ada 9X Project, AJPO library и Ада семейства в целом.

 

В работе участвовали Software Productivity Consortium's (Консорциум) и Advanced Research Projects Agency (ARPA).

 

 Существовавший ранее AQ&S 83 представлял ряд рекомендаций, и был предназначен для помощи программисту в дисциплинированном использовании особенностей Ада. В 1992, Консорциум закончил модификацию версии 2.1 согласно контракту с AJPO. AJPO именовал то руководство стиля как «предложенное руководство стиля для всех программ DoD».

 

 

 

Комментарии

 

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

 

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

 

Электронные копии этого руководства доступны для загрузки с Ada Information Clearinghouse (e-mail: webmaster@adaic.com).

 

Комментарии и предложения можно направлять:

 

Christine Ausnit

Software Productivity Consortium

2214 Rock Hill Road

Herndon, VA 22070

E-mail: ausnit@software.org

Fax: (703) 742-7200

 

или

 

Kent A. Johnson

Software Productivity Consortium

2214 Rock Hill Road

Herndon, VA 22070

E-mail: johnson@software.org

Fax: (703) 742-7200

 

Просьба включать в комментарии свои контактные координаты.

 

Вопросы, связанные с форматированием HTML версии должны быть направлены webmaster компании AdaIC.

 

 

 

** Этот материал частично базируется на работе, спонсируемой Department of Defense Ada Joint Program Office, через Advanced Research Projects Agency grant #MDA972-92-J-1018. Содержание не обязательно отражает позицию или стратегию Американского Правительства и не требует никакого официального одобрения.
АВТОРЫ И БЛАГОДАРНОСТИ

 

Консорциум желает отметить всех, без малого сто, разработчиков предыдущих версий этого руководства, написанного для Ада83, включая ее авторов, редакторов и отличных рецензентов. В разработке текущей версии принимали участие авторы: Ms. Christine Ausnit-Hood, Mr. Kent A. Johnson, Mr. Robert G. Pettit, and Mr. Steven B. Opdahl; выдающиеся рецензенты, опытные рецензенты и технические советники.

 

 

Выдающиеся рецензенты:

 

·                      Mr. Bill Beckwith, Objective Interface Systems, Inc.;

·                      Dr. Norman H. Cohen, IBM's T.J.Watson Research Center;

·                      Dr. Robert Dewar, New York University;

·                      Dr. Charles B. Engle, Jr., Department of Computer Science, Florida Institute of Technology;

·                      Mr. Jay Ferguson, NSA, Department of Defense;

·                      Mr. Ken Garlington, Lockheed Martin, Fort Worth Company;

·                      Mr. Tim Harrison, ParcPlace-Digitalk Inc.;

·                      Mr. Ed Seidewitz, NASA, Goddard Space Flight Center;

·                      Mr. S. Tucker Taft, Intermetrics Inc.

 

 

Опытные рецензенты:

 

·          Mr. Brad Balfour, CACI;

·          Dr. Bryce Bardin, Ada Consulting and Training;

·          Mr. Philip Brashear, CTA Inc.;

·          Dr. Ben Brosgol, Brosgol Consulting and Training;

·          Dr. Michael B. Feldman, Department of Electrical Engineering and Computer Science,  George Washington University;

·          Mr. Gil Myers, NOSC;

·          Mr. Jim Moore, The MITRE Corporation;

·          Ms. Eileen S. Quann, FASTRAK Training, Inc.;

·          Mr. Richard Riehle, AdaWorks;

·          Dr. Tim Teitelbaum, GrammaTech, Inc.;

·          Dr. Joyce Tokar, Tartan (acquired by Texas Instruments).

 

Технические советники:

 

·          Mr. John Barnes, John Barnes Informatics;

·          Mr. Leslie Dupaix, OO-ALC/TISE, Hill AFB;

·          Mr. Dave Emery, The MITRE Corporation;

·          Mr. Magnus Kempe, Kempe Software CE;

·          Ms. Judy Kerner, The Aerospace Corporation;

·          Mr. Alexander Miethe, CCI;

·          LtCol Pat Lawlis, AFIT/ENG, Wright-Patterson AFB.

 

 

 

Также выразить благодарность всем кто присылал свои комментарии, рекомендации и примеры включая Lisa Chan, Bo Sanden, Wesley Groleau, Terry D. Humphrey, Pascal Leroy, Gilles Demailly, Philippe Kipfer, Tomas Peterson, Ted Baker, Mike Dingas, Willem Treurniet, T. A. Vo и Dave Weller.

 

 

Специальные благодарности:

 

Ed Seidewitz, Tim Harrison, Bill Beckwith, Ken Garlington, Tucker Taft, Chuck Engle и Don Reifer которые выкроили время из своего расписания для отслеживания Distinguished Reviewer Technical Interchange Meetings.

 

Mike Evans и Dan Hocking из Army Research Lab за внедрение электронного обмена сообщениями Distinguished Reviewer Technical Interchange Meetings.

 

Philip Brashear за переработку 10 главы.

 

Mike Feldman и Brian Kallberg за их модификацию «Обедающие философы» (пример приложения в 11 главе).

 

John Barnes за представленные материалы из его новой книги.

 

GrammaTech, Inc.  которая сделала доступной новую версию Ada-ASSURED. Примеры форматировались, полностью или частично, используя их инструмент.

 

 Кроме того, Bobbie Troy и Mary Mallonee, которые обеспечили техническое редактирование; Debbie Morgan и Lisa Smith обеспечили обработку текстов; и Bobbie Troy обеспечил чистовую корректировку.
Введение

 

Стиль - часто пропускаемый, но очень критичный атрибут написания. Стиль написания непосредственно влияет на удобочитаемость и понимание готового продукта. Стиль программирования, как написание исходного текста в машинном языке, также страдает от этого пренебрежения. Программы должны быть читаемыми и понятными людям, не только машинам. Это требование важно для создания продуктов высокого качества, которые не только соответствуют требованиям заказчика, но также и могут быть разработаны по графику и в пределах предполагаемой стоимости. Эта книга предназначена помочь программистам разрабатывать программы с использованием Ада лучше. Она представляет ряд определенных стилистических рекомендаций для использования мощных особенностей Ада95 (Ada Reference Manual 1995) контролированным, дисциплинированным способом.

 

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

 

Язык Ада спроектирован для поддержки разработки высококачественного, надежного,  переносимого программного обеспечения многократного использования. По ряду причин, никакой язык программирования не может гарантировать достижение этих желательных целей самостоятельно. Например, программирование должно быть основано на дисциплинированном процессе развития, который предполагает анализ требований, дизайн, разработку, проверку, тестирование, и обслуживание организованным способом. Использование языка должно соответствовать хорошей программной практике, основанной на известных принципах разработки программного обеспечения. Эта книга предназначена помочь соединить эти принципы с фактической практикой программирования с использованием Ада.

 

Многие из рекомендаций этой книги призваны обеспечить ясный исходный текст. Цель состоит в том, чтобы улучшить непринужденность развития программы, адаптации, и обслуживания. Понятный исходный текст, более вероятно, будет правилен и надежен. Адаптация требует полного понимания программы, что значительно облегчается ясностью кода. Эффективная адаптация кода - предпосылка к многократному использованию кода, методика, которая позволяет резко сократить стоимость развития программного продукта. Наконец, потому что обслуживание (действительное развитие) - дорогостоящий процесс, который продолжается в течение всей жизни системы, где ясность играет главную роль в снижении стоимостей технического обслуживания. По всему полному эксплуатационному циклу, код читается и должен пониматься далеко чаще, чем это предполагается; таким образом, инвестиции в написание читаемого, понятного кода являются стоящими.

 

Дальнейшие разделы этого введения обсуждают организацию этой книги и как представленный материал может использоваться разными людьми, включая программистов-новичков, опытных программистов, объектно-ориентированных программистов, технических организаторов проекта, подрядные организации, организации стандартизации, и планировщиков перевода программ на Ада95 из стандарта Ада83 (Ada Reference Manual 1983).

 

 

 Организация этой книги

 

Формат этой книги следует формату Ada Quality and Style: Guidelines for Professional Programmer's, version 02.01.01 (AQ&S 83) (Software Productivity Consortium 1992). Книга разделена на разделы, которые должен использовать каждый программист, создавая высококачественное, надежное, и переносимое программное обеспечение многократного использования. Существуют некоторые взаимосвязи между главами, поскольку некоторые моменты нельзя описать в терминах одной главы.

 

Индивидуальные главы сосредоточены на представлении исходного текста, удобочитаемости, структуре программы, программировании методов, параллелизме, мобильности, возможности многократного использования и новую главу объектно-ориентированных особенностей. В заключении каждой главы расположено резюме рекомендаций, которые содержатся в ней. Последняя глава содержит полную реализацию примера «Обедающие философы», написанного Dr. Michael B. Feldman и Mr. Bjorn Kallberg. Многие из рекомендаций этой книги использованы в этом примере. Приложение содержит перекрестные ссылки на Ada Reference Manual (1995) и разделы этого руководства.

 

Эта книга написана с использованием общего словаря разработки программного обеспечения, создававшегося прошлые 20 лет. Разработка программного обеспечения - быстро развивающаяся дисциплина с относительно новыми понятиями и терминологией. Однако чтобы установить общую систему отсчета, необходимые определения извлечены из Ada Reference Manual (1995) и Rationale (1995).

 

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

 

В этой книге под понятием "Ада" имеется в виду последний стандарт Ада, выпущенный в феврале 1995 (иногда также известный как Ада95). Обращение к более раннему стандарту явно указывается как "Ада83".

 

Представление исходного кода и читаемость

Во второй и третьей главах непосредственно обсуждается проблема создания ясного, читабельного и понятного исходного кода. Глава 2 сосредотачивается на форматировании кода, а Глава 3 на использовании комментариев, соглашений об именах и типах.

 

Есть два главных аспекта ясности кода: (1) осторожное и последовательное размещение исходного текста на странице или экране, обсуждается во второй главе, который может расширить удобочитаемость драматично; (2) внимательное отношение к структуре кода, обсуждается в третьей главе, которое может сделать код понятнее. Это истинно как для частных случаев (например, осторожным выбором названия идентификатора или дисциплинированным использованием циклов) так и в глобальном масштабе (например, надлежащим использованием пакетов). Эти главы затрагивают оба аспекта.

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

 

Структура программы

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

 

Практика программирования

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

 

Параллелизм

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

 

Мобильность и повторное использование

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

 

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

 

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

 

Объектно-ориентированные особенности

В девятой главе содержится ряд рекомендаций в терминах объектно-ориентированного программирования, использующие особенности Ада95, которые отсутствовали в Ада83. В них обсуждается использование новых особенностей языка Ада, таких как  расширение типов (теговые типы), абстрактные теговые типы и абстрактные подпрограммы, для обеспечения одиночного наследования, множественного наследования и полиморфизма.

 

Оптимизация

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

 

 

 Как использовать данный материал

 

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

 

Есть множество вариантов использования данной книги: как руководство хорошего стиля написания Ада-кода; как всесторонний список рекомендаций, которые внесут свой вклад в улучшение Ада-программ; или как справочной информацией, вопросов использования и дизайна определенных особенностей языка. Книга содержит много рекомендаций, некоторые из которых весьма сложные. Изучение их всех за раз не должно быть целью, маловероятно, что Вы будете использовать их все сразу. Однако рекомендуется, чтобы все программисты (а также и другой персонал проекта) предприняли усилие для прочтения и понимания глав 2, 3, 4 и пятой до раздела 5.7. Часть материала весьма трудна (например, раздел 4.2, в котором обсуждается видимость), но в нем обсуждаются фундаментальные проблемы использования Ада, и важны для любого профессионала, вовлеченного в проект использующий Ада.

 

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

 

Если Вы только начали изучать язык, не лишним будет, сначала, ознакомится с учебными пособиями таких авторов как Barnes (1989) и Cohen (1986) основанных на стандарте Ада83. Также изданы новые книги этих авторов, основанных на новом Ада95 стандарте (Barnes 1996, Cohen 1996). Как только Вы ознакомитесь с этими пособиями необходимо обращаться к Rationale (1995). Ada Reference Manual (1995) надо рассматривать как компаньона этих книг. Большинство рекомендаций ссылаются на разделы  Ada Reference Manual (1995) в которых определены обсуждаемые языковые особенности. Приложение «А» содержит ссылки на Ada Reference Manual (1995) и данный материал.

 

 

 Новичкам в программировании на языка Ада.

 

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

 

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

 

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

 

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

 

 

 Опытным Ада программистам

 

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

 

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

 

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

 

 

 Опытным объектно-ориентрованным программистам

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

           

            Использовать рекомендации девятой главы будет проще, если проектирование проводилось с учетом объектно-ориентированного подхода. В результате такого проектирования появится ряд значимых абстракций и иерархия классов. Абстракции должны включать определения объектов, структуру и состояния, операции над объектами, и достаточную инкапсуляцию. Подробности относительно проектирования этих абстракций и иерархий классов не являются предметом рассмотрения данной книги. Есть множество хороших материалов на эту тему, включая Rumbaugh et al. (1991), Jacobson et al. (1992), ADARTS Guidebook (Software Productivity Consortium 1993) и Booch (1994).

 

 

 

1.6 Менеджерам проектов

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

           

            Важная часть работы менеджера заключается в определении стандартов написания кода для проекта или организации в целом. Представленные здесь рекомендации не являются комплектом стандартов, а скорее представляют базис для их создания. Некоторые рекомендации представляют диапазон решений, но не предписывают конкретного специфического решения. Например, вторая рекомендация (Рекомендация 2.1.2), рекомендует последовательно использовать одинаковое число пробелов для отступа, а в объяснении рекомендуется использовать от двух до четырех пробелов. Вы должны принимать решение о конкретной реализации каждой такой рекомендации, которая войдет в стандарты проекта или организации.

           

            Другой аспект стандартизации требует организаторских решений. Рекомендация 3.1.4 советует избегать произвольных сокращений в названиях модулей и объектах. Вы должны подготовить глоссарий приемлемых сокращений для проекта, который позволяет использовать более короткие версии специфических для приложения терминов (например, FFT для Быстрого преобразования Фурье или SPN для Стохастической Сети Петри). Вы должны ограничить этот глоссарий наиболее часто употребляемыми терминами. Необходимость непрерывно обращаться к глоссарию, чтобы понять исходный текст, сделает работу труднее.

 

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

           

            Решения по стандартизации должны быть включены в проектную документацию как  стандарт представления исходного кода. С появлением такого документа необходимо гарантировать следование ему. Получение искреннего обязательства штата программистов использовать стандарты является критическим. Учитывая наличие стандартов, а также примеры кода, написанные Вашими опытными программистами, упрощает проведение экспертного анализа кода.  Некоторые общие проблемы, связанные с управлением Ада проектами обсуждаются Hefley, et al. (1992).

 

 

1.7 Подрядчикам и организациям стандартизации

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

 

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

 

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

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

 

1.8 Планировщикам перехода к новому стандарту Ада95

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

 

Обратная совместимость в Ада95 была главным требованием. Небольшое количество нюансов совместимости Ада83 и Ада95, которые, возможно появятся на практике, легко преодолимы (см. Ada 95 Rationale [1995] Appendix X entitled Upward Compatibility). Подробная информация по проблемным моментам может быть найдена  Taylor (1995) and Intermetrics (1995).

 

Планировщики перехода могут ознакомится с нововведениями языка двумя путями. Во-первых, таблица 1 представляет список новых возможностей с ссылками на рекомендации данной книги. Во-вторых,  Appendix A связывает Ada Reference Manual (1995) и разделы данного руководства.

 

 

 

 


2. ПРЕДСТАВЛЕНИЕ ИСХОДНОГО ТЕКСТА

 

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

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

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

 

 

2.1 Форматирование кода

 

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

 

 

 

 

2.1.1 Горизонтальный интервал

 

Концепция:

 

·          используйте пробелы до и после разделителей;

·          используйте пробелы, так же, как и в обычном тексте;

 

Реализация:

 

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

 

-         перед и после следующих разделителей и бинарных операторов:

 

+            -            *            /            &

<            =            >            /=            <=            >=

:=            =>            |            ..

:

<>

 

-         за строковыми (") и символьными (') кавычками, кроме мест где это запрещено;

-         за, но не внутри, круглыми скобками;

-         после запятых (,) и точек с запятой (;)

 

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

 

-         после плюса (+) и минуса (-), если они используются как униарные операторы; 

-         после вызова  функций;

-         в разделителях меток (<<  >>)

-         до и после оператора возведения в степень (**), апострофа ('), и периода (.)

-         между кратным последовательным открытием или закрытием круглых скобок;

-         перед запятыми (,) и точками с запятой (;)

 

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

 

Пример:

 

Default_String : constant String :=

      "This is the long string returned by" &

      " default. It is broken into multiple" &

      " Ada source lines for convenience.";

type Signed_Whole_16 is range -2**15 .. 2**15 - 1;

type Address_Area is array (Natural range <>) of Signed_Whole_16;

 

Register : Address_Area (16#7FF0# .. 16#7FFF#);

Memory   : Address_Area (       0 .. 16#7FEC#);

 

Register(Pc) := Register(A);

 

X := Signed_Whole_16(Radius * Sin(Angle));

 

Register(Index) := Memory(Base_Address + Index * Element_Length);

 

Get(Value => Sensor);

 

Error_Term := 1.0 - (Cos(Theta)**2 + Sin(Theta)**2);

 

Z      := X**3;

Y      := C * X + B;

Volume := Length * Width * Height;

 

 

Обсуждение:

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

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

 

 

Исключения:

Существует одно исключение - двоеточие (:) . В языке Ада двоеточие используется как табулятор или разделитель (см. 2.1.4). В этом контексте имеет смысл помещать пробелы до и после двоеточия, а не только после, как это делается в обычном тексте.

 

Автоматизация:

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

 

 

 

 

2.1.2 Отступы

 

Концепция:

 

·          используйте, последовательно, отступы и выравнивание вложенных управляющих инструкций, продолжений строк и вложенных модулей;

·          используйте разные отступы для вложенных управляющих инструкций и для продолжений строк;

·          используйте для этого пробелы, не табуляцию (Nissen and Wallis 1984, §2.2);

 

Реализация:

 

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

 

-         Используйте рекомендованные в Ada Reference Manual (1995) отступы;

-         Используйте три пробела как базовый отступ вложения;

-         Используйте два пробела как базовый отступ для продолжения строки;

 

 

Вложение с меткой и продолжение строки:

 

begin

 

<<label>>

<long statement with line break>

   <statement>

  <trailing part of same statement>

end;

 

 

 

Условный оператор и простой цикл:

 

if <condition> then

<name>:

   <statements>

loop

elsif <condition> then

   <statements>

   <statements>

exit when <condition>;

else

   <statements>

   <statements>

end loop <name>;

end if;

 

 

Условные циклы:

 

<name>:

<name>:

   for <scheme> loop

   while <condition> loop

      <statements>

      <statements>

   end loop <name>;

   end loop <name>;

 

 

 Блок и оператор выбора, как рекомендовано в Ada Reference Manual (1995):

 

<name>:

case <expression> is

   declare

   when <choice>=>

      <declarations>

      <statements>

   begin 

   when <choice>=>

      <statements>

      <statements>

   exception

   when others =>

      when <choice> =>

      <statements>

         <statements>

end case;  --<comment>

      when others =>

 

         <statements>

 

   end <name>;

 

 

 

Операторы выбора с экономией места, и рекомендованный в Ada Reference Manual (1995), и применимы при маленьких списках действий. Какой бы вариант не был выбран, ему надо следовать неуклонно:

 

case <expression> is

case <expression> is

   when <choice>=>

   when <choice>=> <statements>

      <statements>

   when <choice>=> <statements>

   when <choice>=>

   when others => <statements>

      <statements>

end case;

   when others =>

 

      <statements>

 

end case;

 

 

 

 Различные формы входов, выборочных, ограниченных по времени и по условию:

 

select

select

   when <guard> =>

   <entry call>;

      <accept statement>

   <statements>

      <statements>

or

or

   delay <interval>;

   <accept statement>

   <statements>

   <statements>

end select;

   or

 

      when <guard> =>

select

         delay <interval>;

   <entry call>;

         <statements>

   <statements>

   or

else

      when <guard> =>

   <statements>

         terminate;

end select;

   else

 

      <statements>

select

   end select;

   <triggering alternative>

 

then abort

 

   <abortable part>

 

end select;

 

 

Оператор принятия:

 

accept <specification> do

   <statements>

end <name>;

 

 Подмодуль:

 

separate (<parent unit>)

   <proper body>

end <name>;

 

 

 Тела методов программных модулей:

 

procedure <specification> is

package body <name> is

   <declarations>

   <declarations>

begin

begin

   <statements>

   <statements>

exception

exception

   when <choice> =>

   when <choice>=>

      <statements>

      <statements>

end <name>;

end <name>;

 

 

function  <specification>

task body <name> is

  return  <type name> is

   <declarations>

   <declarations>

begin

begin

   <statements>

   <statements>

exception

exception

   when <choice>=>

   when <choice> =>

      <statements>

      <statements>

end <name>;

end <name>;

 

 

 

 

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

 

with <name>; use <name>;

function <specification>

with <name>;

  return <type>;

with <name>;

 

 

package <name> is

 

   <declarations>

 

private

<compilation unit>

   <declarations>

 

end <name>;

 

 

generic 

task type <name> is

   <formal parameters>

   <entry declarations>

<compilation unit>

end <name>;

 

 

Конкретизация настраиваемых модулей и отступ для структуры:

 

procedure <name> is

type ... is

   new <generic name> <actuals>

   record

 

      <component list>

function <name> is

      case <discriminant name> is

   new <generic name> <actuals>

        when <choice> =>

 

           <component list>

package <name> is

        when<choice> =>

   new <generic name> <actuals>

           <component list>

 

     end case;

 

   end record;

 

 

Отступ для выравнивания структуры:

 

for <name> use

   record <mod clause>

      <component clause>

   end record;

 

 

 Тэговые типы и расширение типа:

 

type ... is tagged

   record

      <component list>

   End record;

 

type ... is new ... with

   record

      <component list>

   end record;

 

 

Пример:

 

Default_String : constant String :=

          "This is the long string returned by" &

          " default.  It is broken into multiple" &

          " Ada source lines for convenience.";

 

       if Input_Found then

          Count_Characters;

       else  --not Input_Found

 

          Reset_State;

          Character_Total :=

            First_Part_Total  * First_Part_Scale_Factor  +

            Second_Part_Total * Second_Part_Scale_Factor +

            Default_String'Length + Delimiter_Size;

       end if;

    end loop;

 

 

Обсуждение:

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

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

Дополнительно, Ada Reference Manual (1995, §1.1.4) заявляет, что размещение, которому следуют в примерах и правилах синтаксиса в руководстве – рекомендовано для использования при форматировании текста Ада программ: "Синтаксис, описывающий структурированные конструкции, представлен в форме, рекомендованной к использованию.... Разрывы строк используются для частей правил синтаксиса, если соответствующие части конструкции предназначены для переноса на следующую строку.... Рекомендуется, чтобы весе отступы были кратными основному сдвигу (число пробелов для основного отступа не определено)".

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

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

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

 

Исключения:

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

 

Автоматизация:

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

 

 

 

 

2.1.3 Выравнивание операторов

 

 

Концепция:

 

·          выравнивайте операторы вертикально для выделения локальной структуры программы и семантики;

 

 

Пример:

 

    if Slot_A >= Slot_B then

       Temporary := Slot_A;

       Slot_A    := Slot_B;

       Slot_B    := Temporary;

    end if;

    ----------------------------------------------------------------

    Numerator   := B**2 - 4.0 * A * C;

    Denominator := 2.0 * A;

    Solution_1  := (B + Square_Root(Numerator)) / Denominator;

    Solution_2  := (B - Square_Root(Numerator)) / Denominator;

    ----------------------------------------------------------------

     := A * B +

        C * D +

        E * F;

    Y := (A * B + C) +  (2.0 * D - E) -  -- basic equation

         3.5;                            -- account for error factor

 

 

Обсуждение:

Выравнивание облегчает визуализацию операторов и обеспечивает дополнительный акцент на функциональности кода.

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

 

 

Исключения:

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

 

 

Автоматизация:

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

 

 

 

 

2.1.4 Выравнивание объявлений

 

Концепция:

 

·          используйте вертикальное выравнивание, чтобы улучшить удобочитаемость объявлений;

·          не записывайте на строке более одного объявления;

·          выровняйте все объявления текущей декларативной части на одном и том же уровне;

 

Реализация:

Для объявлений, не отделенных пустыми строками, используйте следующие правила выравнивания:

-         выравнивайте «:» разделитель двоеточие.

-         выравнивайте «:=» разделитель инициализации.

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

-         если объявление выходит за пределы строки, добавляйте стандартное смешение разрыва строки. Наиболее оправданными местами разрыва строки являются: (1) разделитель комментария; (2) разделитель инициализации; (3) разделитель двоеточие.

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

 

Пример:

 

Переменные и константы могут быть размешены как таблица с колонками в местах символов «:», «:=» и «--»:

 

Prompt_Column : constant        := 40;

Question_Mark : constant String := " ? ";   -- prompt on error input

Prompt_String : constant String := " ==> ";

 

Если в результате получается слишком длинная строка, то ее можно разделить на части используя уникальный сдвиг:

 

    subtype User_Response_Text_Frame is String (1 .. 72);

      -- If the declaration needed a comment, it would fit here.

 

    Input_Line_Buffer : User_Response_Text_Frame

        := Prompt_String &

        String'(1 .. User_Response_Text_Frame'Length -

                     Prompt_String'Length => ' ');

 

Объявление перечислимых типов может быть представлено в виде одной или нескольких колонок:

  type Op_Codes_In_Column is

        (Push,

         Pop,

         Add,

         Subtract,

         Multiply,

         Divide,

         Subroutine_Call,

         Subroutine_Return,

         Branch,

         Branch_On_Zero,

         Branch_On_Negative);

 

или для экономии места:

 

    type Op_Codes_Multiple_Columns is

          (Push,            Pop,                Add,

           Subtract,        Multiply,           Divide,

           Subroutine_Call, Subroutine_Return,  Branch,

           Branch_On_Zero,  Branch_On_Negative);

 

или группируя связанные значения:

 

    type Op_Codes_In_Table is

          (Push,               Pop,

           Add,                Subtract,          Multiply,    Divide,

           Subroutine_Call,    Subroutine_Return,

           Branch,             Branch_On_Zero,

           Branch_On_Negative);

 

Обсуждение:

Многие стандарты документирования программ требуют перечислять в табличной форме все описания имен, их типов и начальных значений модуля в комментариях его заголовка. Эти комментарии избыточны и со временем могут перестать соответствовать коду.

Выравнивание непосредственно объявлений табличным способом (см. примеры выше) обеспечивает достаточную визуализацию; размещение по одному объявлению на строке; и позволяет непринужденно обслуживать их, обеспечивая пространство для инициализаций и необходимых комментариев. Табличное размещение улучшает удобочитаемость, таким образом, препятствуя визуальному сокрытию объявления  в массе объявлений декларативной части. Это относится ко всем объявлениям, будь то типы, подтипы, объекты, исключения, именованные числа и т.д.

 

Автоматизация:

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

 

 

 

 

2.1.5 Еще о выравнивании

 

Концепция:

·          выравнивайте параметры и круглые скобки вертикально;

 

 

Пример:

 

procedure Display_Menu (Title   : in     String;

                        Options : in     Menus;

                        Choice  :    out Alpha_Numerics);

 

Следующие примеры показывают альтернативные варианты:

 

procedure Display_Menu_On_Primary_Window

 (Title : in String; Options : in Menus; Choice : out Alpha_Numerics);

 

или:

    procedure Display_Menu_On_Screen (

          Title   : in     String;

          Options : in     Menus;

          Choice  :    out Alpha_Numerics

        );

 

Выравнивание скобок делает сложные выражения более понятными:

 

    if not (First_Character in Alpha_Numerics and then

            Valid_Option(First_Character)             ) then

 

Обсуждение:

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

 

Исключения:

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

 

Третий пример, наиболее часто используемый для уменьшения необходимости форматирования параметров, в случае, когда необходимо добавить, удалить или поменять местами параметры. Необходимости переносить круглые скобки со строки на строку нет, поэтому последний параметр единственный без точки с запятой.

 

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

 

    type Color_Scheme is (Red, Purple, Blue, Green, Yellow, White,  

            Black, Brown, Gray, Pink);

   function "&" (Left, Right : Color_Scheme) return Color_Scheme;

 

Автоматизация:

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

 

 

 

 

2.1.6 Пустые строки

 

Концепция:

·          используйте пустые строки для группировки логически связанных строк кода (NASA 1987);

 

Пример:

 

if ... then

   <statment>

 

elsif ... then

   <statment>

 

else

   <statment>

end if;

 

данный пример разделяет не связанные декларации пустой строкой:

 

    type Employee_Record is

       record

          Legal_Name    : Name;

          Date_Of_Birth : Date;

          Date_Of_Hire  : Date;

          Salary        : Money;

       end record;

 

    type Day is

          (Monday,    Tuesday,   Wednesday, Thursday,  Friday,

           Saturday,  Sunday);

    subtype Weekday is Day range Monday   .. Friday;

    subtype Weekend is Day range Saturday .. Sunday;

 

Обсуждение:

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

 

Автоматизация:

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

 

 

 

 

2.1.7 Разделение кода комментариями

 

Концепция:

·          выделяйте начало каждого пакета или спецификации задачи, начало реализации каждой подпрограммы, каждого модуля;

 

Реализация:

Специальные рекомендации:

-       используйте прологи для файлов, заголовки для спецификаций и заголовки для реализаций для выделения структуры как указано в Рекомендации 3.3;

-       используйте строку, состоящую из символов минуса “-” и используя текущий сдвиг для выделения вложенных подпрограмм, введенных в декларативную часть. Используйте такие строки непосредственно до, и после определения;

 

Пример:

 

with Basic_Types;

 

package body SPC_Numeric_Types is

 

-------------------------------------------------------

function Max

      (Left  : in Basic_Types.Tiny_Integer;

       Right : in Basic_Types.Tiny_Integer)

      return Basic_Types.Tiny_Integer is

begin

   if Right < Left then

      return Left;

   else

      return Right;

   end if;

end Max;

 

-------------------------------------------------------

function Min

      (Left  : in Basic_Types.Tiny_Integer;

       Right : in Basic_Types.Tiny_Integer)

      return Basic_Types.Tiny_Integer is

begin

   if Left < Right then

      return Left;

   else

      return Right;

   end if;

end Min;

 

-------------------------------------------------------

use Basic_Types;

begin -- SPC_Numeric_Types

   Max_Tiny_Integer := Min(System_Max, Local_Max);

   Min_Tiny_Integer := Max(System_Min, Local_Min);

   -- ...

end SPC_Numeric_Types;

 

Обсуждение:

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

 

Исключения:

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

 

Автоматизация:

Эти рекомендации легко реализуются с использованием форматеров.

 

 

 


2.1.8 Количество инструкций в одной строке

 

Концепция:

·                 начинайте новую инструкцию с новой строки;

·                 записывайте не более одной простой инструкции в одной строке;

·                 размещайте составные инструкции на нескольких строках;

 

Пример:

            Используйте:

 

     if End_Of_File then

        Close_File;

     else

        Get_Next_Record;

     end if;

 

            вместо:

 

     if End_Of_File then Close_File;

     else Get_Next_Record; end if;

 

            исключительный случай:

 

     Put("A="); Natural_IO.Put(A); New_Line;

     Put("B="); Natural_IO.Put(B); New_Line;

     Put("C="); Natural_IO.Put(C); New_Line;

 

Обсуждение:

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

 

Исключения:

Если инструкция длиннее оставшегося пространства строки необходимо разбить ее на две строки. Эта рекомендация затрагивает так же объявления, контекстные конструкции, и параметры подпрограммы.

Согласно Ada Reference Manual (1995, §1.1.4), “Предпочтительное место для разрыва строки – после точки с запятой"

 

Автоматизация:

Данные рекомендации легко реализуются автоматическими форматерами кода. Исключением является последний пример, который учитывает семантическую структуру программы и показывает семантическую группировку инструкций.

 

Исключения:

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

 

 

 

 

2.1.9 Длинна строки исходного кода

 

Концепция:

·                 учитывайте максимальную длину строки (Nissen and Wallis 1984, §2.3);

 

Реализация:

Специальные рекомендации:

-      ограничивайте длину строки максимумом из 72 символов;

 

Обсуждение:

Когда Ада код переносится из одной системы в другую, можно столкнуться с ограничениями на представляемую длину строки исходного кода, поскольку некоторые операционные системы, возможно, не поддерживают переменную длину строки, или некоторые принтеры и терминалы поддерживают 80-символьную ширину строки. Дальнейшее обсуждение приводится в Рекомендации 7.1.2.

 

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

 

Кроме того, есть ограничения в ширине поля обзора человеческих глаз, которая налагает ограничения на длину строки, приемлемую для легкого чтения кода. Эти ограничения соответствуют примерно диапазону от 70 до 80 символов.

 

Исключения:

Альтернативная реализация ограничивает длину строки исходного текста 79 символами. 79-символьный лимит дифференцирует код от ФОРТРАНа (72-символьный предел). Это также позволяет избежать проблем с 80-символьными терминалами, где последний символ, возможно, не отображается корректно.

 

Автоматизация:

Данная рекомендация легко реализуются на автоматических форматерах.

 

 

 

 

2.2 Заключение

 

Форматирование кода

·          последовательно используйте разделение пробелами вокруг разделителей;

·          используйте одинаковый интервал для разделителей;

·          последовательно выделяйте и выравнивайте вложенные управляющие инструкции, продолжение строк и вложенные структуры;

·          используйте разный сдвиг для продолжений строк и вложенных структурных компонентов;

·          используйте для сдвига пробелы, не табуляцию (Nissen and Wallis 1984, §2.2).

·          выравнивайте операторы вертикально для подчеркивания локальной структуры и семантики программы;

·          используйте вертикальное выравнивание для подчеркивания объявлений;

·          размещайте на строке не больше одного объявления;

·          выравнивайте все объявления одной декларативной части на одном уровне;

·          выравнивайте режимы параметров и круглые скобки вертикально;

·          используйте пустые строки для группировки логических структур программы (NASA 1987);

·          выделяйте начало каждого пакета, спецификации задачи, начало реализаций подпрограмм;

·          начинайте управляющие инструкции с новой строки;

·          размещайте на строке не более одной управляющей инструкции;

·          размещайте составные, длинные управляющие инструкции на нескольких строках;

·          учитывайте максимальную длину строки для представления исходного кода (Nissen and Wallis 1984, §2.3).
3. ЧИТАБЕЛЬНОСТЬ

 

            В этой главе рассматривается использование особенностей языка Ада для улучшения читабельности кода, что влияет на его понимание. Существует множество мифов о комментариях и читабельности. Читабельность кода в большей степени зависит от именований и структуры кода, нежели от комментариев. Обилие строк с комментариями, которые по объему не уступают строкам с кодом, не гарантирует легкости чтения; скорее это свидетельствует о том, что программист не понимает что важно для общения.

 

 

 

3.1 Соглашения о написании идентификаторов.

 

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

 

 

 

3.1.1       Символ подчеркивания “_” (call символ)

 

Концепция:

·          используйте символ подчеркивания для отделения слов в составном идентификаторе;

 

Пример:

 

Miles_Per_Hour

Entry_Value

 

Обсуждение:

            Когда идентификатор состоит больше чем из одного слова, он легче воспринимается, если слова отделены знаком подчеркивания. В действительности это несвойственно английскому языку, в котором для разделения составных имен используется дефис или пробел. Использование символа подчеркивания дает возможность форматеру кода лучше контролировать использование букв верхнего регистра (См. Рекомендацию 3.1.3).

 

 

 

3.1.2 Цифровые значения

 

Концепция:

·       представляйте цифровые значения однотипно;

·       представляйте дробную часть значений соответственно проблемной области;

·       используйте символ подчеркивания для разделения групп цифр так же, как в обычном тексте их разделяют запятой (или пробелом для не десятичной системы счисления);

·       для представления экспоненциальных значений используйте либо верхний, либо нижний регистр для записи символа “Е”;

·       в альтернативных системах счисления для записи алфавитных символов используйте постоянно либо верхний, либо нижний регистр;

 

Реализация:

-         числа десятичной и восьмеричной системы счисления записывайте, группируя по три цифры влево от точки, и по пять символов вправо;

-         используйте верхний регистр для записи експотенциального символа “E”;

-         используйте верхний регистр для записи алфавитных символов, представляющих цифры;

-         числа шестнадцатиричной системы счисления записывайте, группируя их по четыре символа в обоих от точки направлениях;

 

Пример:

 

type Maximum_Samples     is range          1 .. 1_000_000;

type Legal_Hex_Address   is range   16#0000# .. 16#FFFF#;

type Legal_Octal_Address is range 8#000_000# .. 8#777_777#;

Avogadro_Number : constant := 6.02216_9E+23;

 

для представления числа 1/3 как константы используйте:

 

One_Third : constant := 1.0 / 3.0;

 

избегайте использовать:

 

One_Third_As_Decimal_Approximation : constant := 0.33333_33333_3333;

 

или:

 

One_Third_Base_3 : constant := 3#0.1#;

 

Обсуждение:

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

 

Заметки:

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

 

 

 

3.1.3 Заглавные буквы

 

Концепция:

·          сделайте зарезервированные слова и другие элементы программы визуально отличимыми друг от друга;

 

Реализация:

-         используйте нижний регистр для записи зарезервированных слов (если они используются как зарезервированные слова);

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

-         используйте верхний регистр для сокращений и акронимов (см. автоматизация).

 

Пример:

...

type Second_Of_Day      is range 0 .. 86_400;

type Noon_Relative_Time is (Before_Noon, After_Noon, High_Noon);

subtype Morning   is Second_Of_Day range 0 .. 86_400 / 2 – 1;

subtype Afternoon is Second_Of_Day range Morning'Last + 2 .. 86_400;

...

Current_Time := Second_Of_Day(Calendar.Seconds(Calendar.Clock));

if Current_Time in Morning then

   Time_Of_Day := Before_Noon;

elsif Current_Time in Afternoon then

   Time_Of_Day := After_Noon;

else

   Time_Of_Day := High_Noon;

end if;

case Time_Of_Day is

   when Before_Noon => Get_Ready_For_Lunch;

   when High_Noon   => Eat_Lunch;

   when After_Noon  => Get_To_Work;

end case;

...

 

Обсуждение:

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

 

            Показанная реализация предназначена для облегчения работы с исходным кодом опытного программиста, который не нуждается в выделении зарезервированных слов. Напротив, новички в любом языке зачастую требуют выделения зарезервированных слов для облегчения поиска и управляющих инструкций. Поэтому преподаватели в классной комнате, а также в книгах, являющихся введением в язык Ада, могут использовать альтернативную реализацию. Ada Reference Manual (1995) рекомендует для всех зарезервированных слов использовать нижний регистр и полужирный шрифт.

 

Автоматизация:

            В языке Ада идентификаторы не чувствительны к регистру. Поэтому, названия max_limit, MAX_LIMIT и Max_Limit обозначают один и тот же объект. Хороший форматер кода должен уметь преобразовать такие идентификаторы при условии использования символа подчеркивания.

 

            Как указывается в Рекомендации 3.1.4, сокращения должны объявляться для всего проекта. Инструментарий должен давать возможность определять для проекта собственные аббревиатуры и форматировать их соответственно.

 

 

 

3.1.4 Аббревиатуры

           

Концепция:

·       не используйте сокращение длинного слова как идентификатор, когда существует более короткий синоним;

·       используйте  единую стратегию для сокращений;

·       не используйте неоднозначные сокращения;

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

·       используйте аббревиатуры принятые в прикладной области;

·       подготовьте список аббревиатур и используйте только их;

 

Пример:

 

Используйте

            Time_Of_Receipt

вместо

            Recd_Time или R_Time

 

            Однако если приложении используется стандарт сокращений как у военных, тогда DOD_STD_MSG_FMT - приемлемое сокращение для:

Department_Of_Defense_Standard_Message_Format.

 

Обсуждение:

            Многие аббревиатуры и сокращения неоднозначны или непонятны, если не известен контекст. Например, сокращение Temp с одинаковым успехом может обозначать как temporary (временный) так и temperature (температура). Поэтому выбор аббревиатур является ответственным процессом. В Руководстве 8.1.2 обсуждается, как контекст должен влиять на использование аббревиатур.

           

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

           

            Также можно использовать сокращенный вариант полного имени, используя переименования. Особенно это оправдано, когда длинный полный идентификатор встречается много раз в ограниченном участке кода (см. Руководство 5.7.2).

 

            Список принятых для проекта сокращений определяет стандартный контекст использования каждой аббревиатуры.

 

 

 

 

3.2 Соглашения об именовании.

 

            Выбирайте названия, разъясняющие планируемое использование переменной или объекта. Язык Ада позволяет использовать идентификаторы с таким количеством символов, сколько помещается на строке. Идентификаторы - названия, используемые для переменных, констант, подпрограмм и других объектов программы.

 

 

 

3.2.1 Имена

 

Концепция:

·       выбирайте интуитивно понятные названия, насколько это возможно;

·       используйте короткие синонимы вместо аббревиатур (см. Руководство 3.1.4);

·       используйте имена предметной области, но не жаргон;

·       избегайте использовать одинаковые идентификаторы для различных объектов;

 

Пример:

 

            В примере (tree-walker в конце книги), использование названия Left вместо Left_Branch достаточно для передачи значения, в данном контексте. Однако используйте Time_Of_Day вместо TOD.

 

            Математические формулы часто используют один символ для названия переменных. Используйте это соглашение для математических уравнений, которые используют эти формулы, например:

 

            A*(X**2) + B*X + C.

 

            С использованием дочерних пакетов, необоснованный выбор идентификаторов пакета, подпрограмм или переменных может привести к сокрытию их видимости. Обратитесь к Rationale (1995, §8.1) за примером о затенении видимости.

 

Обсуждение:

            Код, в котором учтены данные рекомендации будет более понятным.  Интуитивно понятные идентификаторы требуют меньшего числа комментариев. Эмпирические исследования показали, что использование коротких идентификаторов так же улучшают понимание кода (Schneiderman 1986, 7). Так же этому способствует знание контекста и предметной области. Единица измерения может быть основой для названия подтипа.

           

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

 

Примечания:          

            В Руководстве 8.1.2 обсуждается, как использовать прикладную область для выбора аббревиатур.

 

 

 

3.2.2 Именование подтипов

 

Концепция:

·       используйте существительные в единственном числе для идентификаторов подтипов;

·       выбирайте идентификаторы, которые описывают одно из значений подтипа;

·       выберите суффиксы для общедоступных ссылочных идентификаторов, поддиапазонов и массивов;

·       не используйте для приватных типов конструкции идентификаторов (такие как, например, суффиксы) являющиеся уникальными для подтипа;

·       не используйте имена подтипов из предопределенных пакетов;

 

Пример:

type Day is

   (Monday, Tuesday, Wednesday, Thursday, Friday,

    Saturday, Sunday);

type Day_Of_Month    is range      0 .. 31;

type Month_Number    is range      1 .. 12;

type Historical_Year is range -6_000 .. 2_500;

type Date is

   record

      Day   : Day_Of_Month;

      Month : Month_Number;

      Year  : Historical_Year;

   end record;

 

            Предпочтительней использовать идентификатор Day вместо Days или Day_Type.

 

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

 

----------------------------------------------------------------------procedure Disk_Driver is

   -- In this procedure, a number of important disk parameters

   -- are linked.

   Number_Of_Sectors  : constant := 4;

   Number_Of_Tracks   : constant := 200;

   Number_Of_Surfaces : constant := 18;

   Sector_Capacity    : constant := 4_096;

   Track_Capacity     : constant := Number_Of_Sectors  *

                                      Sector_Capacity;

 

   Surface_Capacity : constant := Number_Of_Tracks   * Track_Capacity;

   Disk_Capacity    : constant := Number_Of_Surfaces *

                                    Surface_Capacity;

 

   type Sector_Range  is range 1 .. Number_Of_Sectors;

   type Track_Range   is range 1 .. Number_Of_Tracks;

   type Surface_Range is range 1 .. Number_Of_Surfaces;

 

   type Track_Map   is array (Sector_Range)  of ...;

   type Surface_Map is array (Track_Range)   of Track_Map;

   type Disk_Map    is array (Surface_Range) of Surface_Map;

begin – Disk_Driver

   ...

end Disk_Driver;

----------------------------------------------------------------------

 

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

 

            Обсуждение:

            Когда используются эта рекомендация и предложенная реализация рекомендации по именованию объектов, исходный код больше напоминает английский язык (см. Руководство 3.2.3). Кроме того, такой стиль используется в предопределенных идентификаторах. Они не названы как Integers, Booleans, Integer_Type или Boolean_Type.

 

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

 

Примечания:          

            Понятия "тип" и "подтип" употребляется в соответствии с Ada Reference Manual (1995). Вообще, "тип" используется как абстрактное понятие, как в декларации типа, в то время как "подтип" обеспечивает связывание абстрактного имени типа и фактической декларацией. Таким образом, понятие “тип” Ада83 Ada 83 (Ada Reference Manual 1983) теперь называется подтипом.

 

 

 

3.2.3 Именование объектов

 

Концепция:

·       используйте префикс или прилагательные для Boolean объектов;

·       используйте уникальные специфические существительные как идентификаторы объектов;

·       используйте идентификаторы, которые описывают значение объекта в процессе выполнения;

·       используйте уникальные общие существительные как идентификаторы компонентов структуры;

 

Пример:

Не Boolean объекты:

 

Today           : Day;

Yesterday       : Day;

Retirement_Date : Date;

 

Boolean объекты:

 

User_Is_Available : Boolean;  -- используется суффикс

List_Is_Empty     : Boolean;  -- используется суффикс

Empty             : Boolean;  -- прилагательное

Bright            : Boolean;  -- прилагательное

 

 

Обсуждение:

            Использование специфических существительных для именования объектов определяет контекст, помогает понять значения объекта, которые являются одним из значений, характерных для производного типа, согласно его имени (см. Руководство 3.2.2). Используя такой стиль, объявления переменных очень напоминают разговорный английский. Например, объявление первой переменной из примера читается как "Today is a Day".

            Использование общих существительных предпочтительнее специфических для именования компонентов структуры, поскольку эти названия должны давать представление о контексте содержимого структуры. Таким образом, следующая конструкция читается как "the year of retirement":

            Retirement_Date.Year

 

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

 

if List_Is_Empty then

   Number_Of_Elements := 0;

else

   Number_Of_Elements := Length_Of_List;

end if;

 

Примечания:          

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

 

 

 

3.2.4 Именование теговых типов и соответствующих пакетов

 

Концепция:

·       постоянно следуйте единому стилю именования теговых типов и взаимосвязанных пакетов;

 

Реализация:

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

-         именуйте теговые типы таким же образом, как и подтипы (см. Руководство 3.2.2);

-         используйте префикс Abstract_ для пакетов, которые экспортируют абстракцию, для которой необходимо обеспечить реализации (см. Руководство 9.2.4);

-         используйте суффикс _Mixin для пакетов, которые представляют собой “смесь” функциональности или абстракций;

 

      Вторая реализация акцентирует использование объектно-ориентированных особенностей посредством использование специальных названий или суффиксов:

-         используйте для пакетов названия классов, которые они представляют, без суффикса (Rosen 1995);

-         используйте для смешанных пакетов аспект, который они представляют, добавляя суффикс _Facet (Rosen 1995);

-         используете для основного тегового типа название Instance (Rosen 1995);

-         используйте для названия надклассового типа имя Class (Rosen 1995).

 

Пример:

            Следующий пример из двух частей, взятый из Rationale (1995, §§4.4.4 and 4.6.2),  использует соглашения первой представленной реализации.

            В первой части встречается тип Set_Element, который, будем считать, объявлен в другом месте (пакете)

 

package Abstract_Sets is

 

   type Set is abstract tagged private;

 

   -- empty set

   function Empty return Set is abstract;

 

   -- build set with 1 element

   function Unit (Element: Set_Element) return Set is abstract;

 

   -- union of two sets

   function Union (Left, Right: Set) return Set is abstract;

 

   -- intersection of two sets

   function Intersection (Left, Right: Set) return Set is abstract;

 

   -- remove an element from a set

   procedure Take (From    : in out Set;

                   Element :    out set_Element) is abstract;

 

   Element_Too_Large : exception;

  

private

   type Set is abstract tagged null record;

end Abstract_Sets;

 

with Abstract_Sets;

 

package Bit_Vector_Sets is -- one implementation of set abstraction

  

   type Bit_Set is new Abstract_Sets.Set with private;

   ...

private

  Bit_Set_Size : constant := 64;

 

  type Bit_Vector is ...

  type Bit_Set is new Abstract_Sets.Set with

     record

        Data : Bit_Vector;

     end record;

end Bit_Vector_Sets;

 

with Abstract_Sets;

 

package Sparse_Sets -- alternate implementation of set abstraction 

   type Sparse_Set is new Abstract_Sets.Set with private;

   ...

private

   ...

end Bit_Vector_Sets;

 

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

 

-- assume you have type Basic_Window is tagged limited private;

 

generic

   type Some_Window is abstract new Basic_Window with private;

 

package Label_Mixin is

   type Window_With_Label is abstract new Some_Window

     with private;

   ...

private

   ...

end Label_Mixin;

 

generic

   type Some_Window is abstract new Basic_Window with private;

 

package Border_Mixin is

   type Window_With_Label is abstract new Some_Window

     with private;

   ...

private

    ...

end Border_Mixin;

 

 В следующем примере используются соглашения второй реализации, как обсуждается в Rosen (1995):

 

package Shape is

   subtype Side_Count is range 0 .. 100;

   type Instance (Sides: Side_Count) is tagged private;

   subtype Class is Instance'Class;

   . . .

   -- operations on Shape.Instance

private

   . . .

end Shape;

 

with Shape; use Shape;

 

package Line is

   type Instance is new Shape.Instance with private;

   subtype Class is Instance'Class;

   . . .

   -- Overridden or new operations

private

   . . .

end Line;

 

with Shape; use Shape;

 

generic

   type Origin is new Shape.Instance;

 

package With_Color_Facet is

   type Instance is new Origin with private;

   subtype Class is Instance'Class;

   -- operations for colored shapes

private

   . . .

end With_Color_Facet;

 

with Line;             use Line;

with With_Color_Facet;

 

package Colored_Line is new With_Color_Facet (Line.Instance);

 

 

Использование таких типов может выглядеть следующим образом:

 

Red_Line : Colored_Line.Instance;

procedure Draw (What : Shape.Instance);

 

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

 

Обсуждение:

            Хочется использовать схему именования, которая является последовательной, читабельной и передает сущность абстракции. Идеально, такая схема должна быть однородной в части обработки различных путей, в которых теговые типы используются для создания классов. Если эти соглашения будут слишком жесткими,  то это приведет к созданию кода, который будет смотреться неестественно. Использование рассмотренных соглашений, для расширения типов и настраиваемых пакетов, (см. также Руководство 9.5.1), улучшает читаемость объявлений объектов и процедур.

 

Примечания:

            Соглашения об именовании различаются для объектно-ориентированных абстракций и других видов абстракций. Учитывая, что абстрактные типы были определены в Ада83 (Ada Reference Manual 1983), более чем 10 лет назад, Вы можете не захотеть менять соглашения об именовании только из за возможности расширения типов. Вы должны рассмотреть насколько необходимо использование наследования и абстракций в полном объеме в Вашей программе. Если Вы предпочитаете подчеркивать, что абстракция, по большому счету, является механизмом для воплощения иерархии классов (то есть наследование, расширение типа и полиморфизм), Вы можете не захотеть наложить строгие правила именования. Качество кода не сильно будет страдать при использовании более гладкого перехода от устоявшихся соглашений об именовании абстракций к соглашениям, учитывающим  возможность расширения и наследования.

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

 

 

3.2.5 Именование подпрограмм

 

Концепция:

·       используйте глаголы действий для именования процедур и входов;

·       используйте предиктаты для функций возвращающих тип BOOL;

·       используйте существительные для не булевых функций;

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

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

·       для защищенных модулей используйте существительные описывающие данные заключенные в нем;

·       используйте для настраиваемых подпрограмм те же соглашения что и для обычных подпрограмм;

·       используйте для настраиваемых пакетов те же соглашения что и для обычных пакетов;

·       используйте для именования настраиваемых сущностей более общие понятия;

 

Пример:

Типовые названия элементов, составляющих Ада программу:

 

типовые имена процедур:

 

procedure Get_Next_Token -- get is a transitive verb

procedure Create         -- create is a transitive verb

 

типовые имена булеан функций:

 

function Is_Last_Item -- predicate clause

function Is_Empty     -- predicate clause

 

типовые имена небулеан функций:

 

function Successor -- common noun

function Length    -– attribute

function Top       -- component

 

типовые имена пакетов:

 

package Terminals is     -- common noun

package Text_Routines is -- common noun

 

типовые имена защищенных объектов:

 

protected Current_Location is -- data being protected

protected type Guardian is    -- noun implying protection

 

типовые имена задач:

 

task Terminal_Resource_Manager is

  -- common noun that shows action

 

Следующий отрывок показывает, насколько код становится яснее при использовании в соглашениях именования частей разговорного языка:

 

Get_Next_Token(Current_Token);

 

case Current_Token is

   when Identifier => Process_Identifier;

   when Numeric    => Process_Numeric;

end case; -- Current_Token

 

if Is_Empty(Current_List) then

   Number_Of_Elements := 0;

else

   Number_Of_Elements := Length(Current_List);

end if;

 

Когда пакеты и их подпрограммы именуются совместно – получается очень описательный код:

 

if Stack.Is_Empty(Current_List) then

   Current_Token := Stack.Top(Current_List);

end if;

 

Обсуждение:

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

            См. также Руководство 3.2.4, в котором обсуждаются вопросы применения суффиксов в пакетах с теговыми типами.

 

Примечания:

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

 

 

3.2.6 Константы и именованные числа

 

Концепция:

·       используйте символические значения вместо литералов, где это возможно;

·       используйте предопределенные константы Ada.Numerics.Pi и  Ada.Numerics.e для математических констант Pi и e.

·       используйте константы вместо переменных для константных значений;

·       используйте константы, когда значение является специфическим для типа или когда значение должно быть статическим;

·       используйте именованные числа вместо констант, где это возможно;

·       используйте именованные числа вместо числовых литералов когда их тип или контекст является универсальным;

·       используйте константы для объектов, значение которых не должно изменятся после элаборации (United Technologies 1987);

·       показывайте взаимосвязи между символическими значениями путем объявления их со статическими выражениями;

·       используйте линейно независимые наборы литералов;

·       используйте атрибуты, такие как 'First и 'Last, вместо литералов, где это возможно;

 

Пример:

 

3.14159_26535_89793                               -– literal

Max_Entries      : constant Integer := 400;       -- constant

Avogadros_Number : constant := 6.022137 * 10**23; -- named number

Avogadros_Number / 2                              -- static expression

Avogadros_Number                                  -- symbolic value

 

            Объявление Pi как именованного числа (с применением предиктата пакета Ada.Numerics Ada Reference Manual [1995, §A.5]) позволяет использовать его в выражениях как показано ниже:

     Area := Pi * Radius**2;        -- if radius is known.

 

что предпочтительней чем:

     Area := 3.14159 * Radius**2;   -- Needs explanatory comment.

 

            Конечно использование Ada.Characters.Latin_1.Bel более предпочтительно чем Character'Val(8#007#).

 

            Использование констант и именованных чисел для объявления других констант и именованных числе позволяет внести ясность и улучшить понимание кода. Например:

    

     Bytes_Per_Page   : constant := 512;

     Pages_Per_Buffer : constant := 10;

     Buffer_Size      : constant := Pages_Per_Buffer * Bytes_Per_Page;

 

            что является более простым для понимания нежели:

 

     Buffer_Size : constant := 5_120; -- ten pages

 

            следующие литералы необходимо заменить константами:

 

     if New_Character = '$' then  -- "constant" that may change

        ...

     if Current_Column = 7 then   -- "constant" that may change

 

 

Обсуждение:

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

 

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

 

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

           

            См. Руководство 4.1.4, где обсуждаются вопросы выбора функций без параметров или констант.

 

Комментарии:

 

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

 

Fahrenheit := 32.0 + (9.0 * Celsius) / 5.0;

 

 

3.2.7                               Исключения

 

Концепция:

·          используйте название, которое указывает на проблему, при которой оно будет генерироваться;

 

Пример:

 

Invalid_Name  : exception;

Stack_Overflow: exception;

Обсуждение:

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

 

 

3.2.8        Конструкторы

 

Концепция:

·          используйте префикс New, Make, или Create в именах конструкторов (подразумеваются процедуры для создания или инициализации объектов);

·          используйте для дочерних пакетов, содержащих конструкторы, интуитивно понятные имена;

 

Реализация:

-         назовите дочерний пакет, содержащий конструкторы <Пакет> .Constructor

 

Пример:

 

function Make_Square (Center : Cartesian_Coordinates;

                      Side   : Positive)

  return Square;

 

Обсуждение:

Включайте New, Make, или Create в название конструктора, что ясно даст понять назначение подпрограммы. Вы можете ограничить использование префикса New для конструкторов, возвращающих указатель на созданный объект, поскольку данное зарезервированное слово языка резервирует новое место под объект.

 

Размещение всех конструкторов, возвращающих ссылку на объект, в дочернем пакете является хорошей практикой.

 

Информация относительно использования конструкторов Ада так же находится в Руководстве 9.3.3.

 

 

3.3 Комментарии

 

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

 

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

 

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

 

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

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

 

 

3.3.1 Общие комментарии

 

Концепция:

·         создавайте настолько ясный код, насколько это возможно, что позволит уменьшить количество комментариев;

·         никогда не повторяйте в комментариях информацию, которая и так ясно видна из кода;

·         при необходимости комментария, создавайте его кратким и полным;

·         следите за правописанием в комментариях;

·         сделайте комментарий визуально отличимым от кода;

·         структурируйте комментарии в заголовках для облегчения автоматического извлечения информации инструментальными средствами.

 

Обсуждение:

 

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

 

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

 

Комментарии необходимы, когда нет возможности передать нужную информацию непосредственно в коде. Далее приведены примеры таких комментариев. В комментарии информация должна представляться полностью и кратко.

 

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

 

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

 

Автоматизация:

 

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

 

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

 

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

 

 

3.3.2 Заголовки файлов

 

Концепция:

·          помещайте заголовок в каждый файл с исходным кодом;

·          помещайте информацию о владельце, правах и истории в заголовок;

 

Реализация:

-         помещайте информацию об авторе в заголовок файла;

-         помещайте информацию об авторском праве в заголовок файла;

-         помещайте информацию об изменениях в заголовок файла, включая резюме каждого изменения, дату, и информацию о человеке, сделавшего изменение;

 

Пример:

 

------------------------------------------------------------------------

--      Copyright (c) 1991, Software Productivity Consortium, Inc.

--      All rights reserved.

-- Author: J. Smith

-- Department:System Software Department

-- Revision History:

--   7/9/91 J. Smith

--     - Added function Size_Of to support queries of node sizes.

--     - Fixed bug in Set_Size which caused overlap of large nodes.

--   7/1/91 M. Jones

--     - Optimized clipping algorithm for speed.

--   6/25/91 J. Smith

--     - Original version.

------------------------------------------------------------------------

 

Обсуждение:

 

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

 

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

 

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

 

Комментарии:

 

Современные системы конфигурирования, поддерживают хронологию версий. Это позволяет отказаться от ведения журнала в заголовке файла. Такие средства поддерживают более надежную и последовательную хронологию. Некоторые из них могут воссоздавать предыдущие версии.

 

 

3.3.3 Заголовки спецификаций модулей

 

Концепция:

·          создавайте заголовок для спецификации каждого программного модуля;

·          помещайте в заголовок спецификации информацию, необходимую для пользователя;

·          не дублируйте информацию (кроме названия) в заголовке спецификации, которая итак присутствует в коде спецификации;

·          опишите назначение программного модуля, но не как или почему он это делает;

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

·          не включайте информацию о том, как программного модуля вписывается в систему;

·          опишите требования (время и используемую память) программного модуля;

 

Реализация:

-         поместите название программного модуля в заголовке;

-         кратко опишите назначение программного модуля;

-         для пакетов, опишите взаимодействие видимых подпрограмм друг на друга и как они должны использоваться совместно;

-         перечислите все исключения, которые могут генерироваться программным модулем;

-         перечислите все глобальные эффекты модуля;

-         перечислите входные и результирующие условия модуля;

-         перечислите скрытые задачи, активируемые модулем;

-         не перечисляйте названия параметров подпрограммы;

-         не перечисляйте названия модулей, только ради их перечисления;

-         не перечисляйте названия всех других модулей, используемых данным модулем;

-         не перечисляйте названия всех других модулей, которые используют данный модуль;

 

Пример:

 

------------------------------------------------------------------------

-- AUTOLAYOUT

-- Purpose:

--   This package computes positional information for nodes and arcs

--   of a directed graph.  It encapsulates a layout algorithm which is

--   designed to minimize the number of crossing arcs and to emphasize

--   the primary direction of arc flow through the graph.

-- Effects:

--   - The expected usage is:

--     1. Call Define for each node and arc to define the graph.

--     2. Call Layout to assign positions to all nodes and arcs.

--     3. Call Position_Of for each node and arc to determine the

--        assigned coordinate positions.

--   - Layout can be called multiple times, and recomputes the

--     positions of all currently defined nodes and arcs each time.

--   - Once a node or arc has been defined, it remains defined until

--     Clear is called to delete all nodes and arcs.

-- Performance:

--   This package has been optimized for time, in preference to space.

--   Layout times are on the order of N*log(N) where N is the number

--   of nodes, but memory space is used inefficiently.

------------------------------------------------------------------------

 

package Autolayout is

   ...

 

   ---------------------------------------------------------------------

   -- Define

   -- Purpose:

   --   This procedure defines one node of the current graph.

   -- Exceptions:

   --   Node_Already_Defined

   ---------------------------------------------------------------------

   procedure Define

         (New_Node : in     Node);

 

   ---------------------------------------------------------------------

   -- Layout

   -- Purpose:

   --   This procedure assigns coordinate positions to all defined

   --   nodes and arcs.

   -- Exceptions:

   --   None.

   ---------------------------------------------------------------------

   procedure Layout;

 

   ---------------------------------------------------------------------

   -- Position_Of

   -- Purpose:

   --   This function returns the coordinate position of the

   --   specified node.  The default position (0,0) is returned if no

   --   position has been assigned yet.

   -- Exceptions:

   --   Node_Not_Defined

   ---------------------------------------------------------------------

   function Position_Of (Current : in     Node)

         return Position;

   ...

end Autolayout;

 

 

Обсуждение:

 

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

 

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

 

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

 

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

 

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

 

Комментарии:

 

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

 

Исключения:

 

            Если несколько программных модулей тесно связаны друг с другом, либо их комплекс легче понять в комплексе, приемлемо использовать для них общий заголовок. Например, имеет смысл использовать общий заголовок для описания поведения функций Max и Min; Sin, Cos и Tan; или для группы функций доступа к атрибутам объекта, сокрытого в пакете. Это особенно актуально для подпрограмм, генерирующих одно и то же исключение.

 

 

3.3.4 Заголовки реализаций программных модулей

 

Концепция:

·          поместите информацию, необходимую для сопровождения модуля в заголовок реализации;

·          объясните, как модуль функционирует, но не включайте информации о функциональности;

·          не дублируйте информацию (за исключением названия подпрограммы) в заголовке, которая и так ясно понятна из кода;

·          не дублируйте информацию (за исключением названия подпрограммы) в заголовке, которая доступна из заголовка спецификации;

 

Реализация:

-         поместите название программного модуля в заголовок;

-         поместите информацию о переносимости кода;

-         опишите сложные либо трудные к пониманию алгоритмы;

-         опишите основные либо спорные моменты реализаций;

-         опишите альтернативные варианты реализации и причины, по которым от них отказались;

-         помещайте информацию о дальнейших планах модификаций либо улучшений, которые необходимо добавить, особенно если эта работа по улучшению (оптимизации) выполняется частями;

 

Пример:

 

------------------------------------------------------------------------

-- Autolayout

-- Implementation Notes:

--   - This package uses a heuristic algorithm to minimize the number

--     of arc crossings.  It does not always achieve the true minimum

--     number which could theoretically be reached.  However it does a

--     nearly perfect job in relatively little time.  For details about

--     the algorithm, see ...

-- Portability Issues:

--   - The native math package Math_Lib is used for computations of

--     coordinate positions.

--   - 32-bit integers are required.

--   - No operating system specific routines are called.

-- Anticipated Changes:

--   - Coordinate_Type below could be changed from integer to float

--     with little effort.  Care has been taken to not depend on the

--     specific characteristics of integer arithmetic.

------------------------------------------------------------------------

 

package body Autolayout is

   ...

   ---------------------------------------------------------------------

   -- Define

   -- Implementation Notes:

   --   - This routine stores a node in the general purpose Graph data

   --     structure, not the Fast_Graph structure because ...

   ---------------------------------------------------------------------

   procedure Define

         (New_Node : in     Node) is

   begin

      ...

   end Define;

 

   ---------------------------------------------------------------------

   -- Layout

   -- Implementation Notes:

   --   - This routine copies the Graph data structure (optimized for

   --     fast random access) into the Fast_Graph data structure

   --     (optimized for fast sequential iteration), then performs the

   --     layout, and copies the data back to the Graph structure.  This

   --     technique was introduced as an optimization when the algorithm

   --     was found to be too slow, and it produced an order of

   --     magnitude improvement.

   ---------------------------------------------------------------------

   procedure Layout is

   begin

      ...

   end Layout;

 

   ---------------------------------------------------------------------

   -- Position_Of

   ---------------------------------------------------------------------

   function Position_Of (Current : in     Node)

         return Position is

   begin

      ...

   end Position_Of;

   ...

end Autolayout;

 

Обсуждение:

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

 

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

 

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

 

Комментарии:

 

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

 

-- Implementation Notes:  None.

и

            -- NonPortable Features:  None.

 

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

 

 

3.3.5 Комментарии данных

 

Концепция:

·          комментируйте все типы данных, объекты и исключения назначение которых не ясно из их названия;

·          включайте информацию относительно семантической структуры сложных, ссылочных структур данных;

·          включайте информацию о взаимоотношениях между объектами данных;

·          не используйте комментарии которые повторяют информацию, доступную из названия;

·          включайте информацию о диспетчеризации для теговых типов в случае, когда производится специализация (например, в производных типах) для выделения этих операций;

 

Пример:

 

Объекты могут быть сгруппированы по назначению и прокомментированы примерно так:

 

...

---------------------------------------------------------------------

-- Current position of the cursor in the currently selected text

-- buffer, and the most recent position explicitly marked by the

-- user.

-- Note:  It is necessary to maintain both current and desired

--        column positions because the cursor cannot always be

--        displayed in the desired position when moving between

--        lines of different lengths.

---------------------------------------------------------------------

Desired_Column : Column_Counter;

Current_Column : Column_Counter;

Current_Row    : Row_Counter;

Marked_Column  : Column_Counter;

Marked_Row     : Row_Counter;

 

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

 

---------------------------------------------------------------------

-- Exceptions

---------------------------------------------------------------------

Node_Already_Defined : exception;   -- Raised when an attempt is made

                                    --|   to define a node with an

                                    --|   identifier which already

                                    --|   defines a node.

Node_Not_Defined     : exception;   -- Raised when a reference is

                                    --|   made to a node which has

                                    --|   not been defined.

 

 Вот более сложный пример, использующий вложенные записи и ссылочные типы:

 

---------------------------------------------------------------------

-- These data structures are used to store the graph during the

-- layout process. The overall organization is a sorted list of

-- "ranks," each containing a sorted list of nodes, each containing

-- a list of incoming arcs and a list of outgoing arcs.

-- The lists are doubly linked to support forward and backward

-- passes for sorting. Arc lists do not need to be doubly linked

-- because order of arcs is irrelevant.

-- The nodes and arcs are doubly linked to each other to support

-- efficient lookup of all arcs to/from a node, as well as efficient

-- lookup of the source/target node of an arc.

---------------------------------------------------------------------

type Arc;

type Arc_Pointer is access Arc;

type Node;

type Node_Pointer is access Node;

type Node is

   record

      Id       : Node_Pointer;-- Unique node ID supplied by the user.

      Arc_In   : Arc_Pointer;

      Arc_Out  : Arc_Pointer;

      Next     : Node_Pointer;

      Previous : Node_Pointer;

   end record;

type Arc is

   record

      ID     : Arc_ID;        -- Unique arc ID supplied by the user.

      Source : Node_Pointer;

      Target : Node_Pointer;

      Next   : Arc_Pointer;

   end record;

type Rank;

type Rank_Pointer is access Rank;

type Rank is

   record

      Number     : Level_ID;  -- Computed ordinal number of the rank.

      First_Node : Node_Pointer;

      Last_Node  : Node_Pointer;

      Next       : Rank_Pointer;

      Previous   : Rank_Pointer;

   end record;

First_Rank : Rank_Pointer;

Last_Rank  : Rank_Pointer;

 

 

Обсуждение:

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

 

В первом приведенном здесь примере, названия Current_Column и Current_Row очевидны. Название Desired_Column также хорошо подобрано, однако оставляет открытым вопрос, для чего нужна эта разница. Комментарий объясняет причину введения данной переменной.

 

Другое преимущество комментирования данных при их объявлении заключается в том, что использование одного комментария перед объявлением сокращает количество комментариев в коде, которые были бы необходимы в тех местах, где переменная используется. В приведенном выше примере в комментарии кратко объясняются "current" и "marked". Там объясняется что "current" – текущая позиция курсора в текущем буфере, а "marked" – позиция, помеченная пользователем. Такой комментарий, наряду с мнемоническими названиями переменных, значительно снижает потребность в комментариях кода, где используются эти переменные.

 

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

 

Группирование всех исключений, как показано в примере, предоставляет читателю своеобразный "глоссарий" специфических условий, при которых возникают исключения. Это особенно актуально, когда одно и тоже исключение генерируется во множестве разных подпрограмм пакета. Исключение, которое генерируется только в определенной подпрограмме лучше группировать с такой подпрограммой.

 

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

 

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

 

См. Руководство 9.3.1, в котором затрагиваются вопросы документирования диспетчеризируемых операций. (Диспетчеризация означает преобразование параметра одной примитивной операции к надклассовому типу и вызов другой примитивной операции). В Руководстве 9.3.1 обсуждается, где должна содержаться такая информация, в спецификации или теле.

 

 

3.3.6 Комментарии управляющих структур

 

Концепция:

·          минимизируйте комментарии управляющих структур;

·          комментируйте только те части кода, которые не очевидны;

·          отделяйте комментарии от кода;

·          не используйте комментарии, перефразирующие код;

·          не комментируйте отдаленные части кода, такие как подпрограммы вызываемые данным кодом;

·          сделайте комментарий визуально отличимым от кода;

 

Пример:

            Вот пример очень плохо комментирования кода:

...

-- Loop through all the strings in the array Strings, converting

-- them to integers by calling Convert_To_Integer on each one,

-- accumulating the sum of all the values in Sum, and counting them

-- in Count.  Then divide Sum by Count to get the average and store

-- it in Average. Also, record the maximum number in the global

-- variable Max_Number.

 

for I in Strings'Range loop

   -- Convert each string to an integer value by looping through

   -- the characters which are digits, until a nondigit is found,

   -- taking the ordinal value of each, subtracting the ordinal value

   -- of '0', and multiplying by 10 if another digit follows.  Store

   -- the result in Number.

   Number := Convert_To_Integer(Strings(I));

   -- Accumulate the sum of the numbers in Total.

   Sum := Sum + Number;

   -- Count the numbers.

   Count := Count + 1;

   -- Decide whether this number is more than the current maximum.

   if Number > Max_Number then

      -- Update the global variable Max_Number.

      Max_Number := Number;

   end if;

end loop;

-- Compute the average.

Average := Sum / Count;

 

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

 

Sum_Integers_Converted_From_Strings:

   for I in Strings'Range loop

      Number := Convert_To_Integer(Strings(I));

      Sum    := Sum   + Number;

      Count  := Count + 1;

 

      -- The global Max_Number is computed here for efficiency.

      if Number > Max_Number then

         Max_Number := Number;

      end if;

   end loop Sum_Integers_Converted_From_Strings;

 

Average := Sum / Count;

 

 

Обсуждение:

Улучшенный вариант примера улучшен не за счет удаления комментариев, он улучшен за счет удаления бесполезных комментариев.

 

Комментарии, которые перефразируют или объясняют очевидные аспекты кода, не имеют никакой пользы. Это попросту трата времени автора и затраты на их сопровождение. Поэтому, они зачастую становятся некорректными. Подобные комментарии затрудняют прочтение кода и скрывают действительно нужные комментарии.

 

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

 

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

 

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

 

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

 

См. также Руководство 9.3.1, где обсуждается, как необходимо документировать теговые типы и диспетчеризируемые подпрограммы.

 

Комментарии:

Пример может быть еще более усовершенствован путем объявления переменных Count и Sum в локальном блоке для ограничения их видимости, тем боле, что инициализация их происходит непосредственно возле использования, назвав блок Compute_Average либо переместив код в функцию Average_Of. Вычисление Max_Number может быть так же отделено от вычисления Average. Однако такие изменения - тема других руководств; этот пример предназначен только для иллюстрации надлежащего использования комментариев.

 

 

3.3.7 Комментарии – маркеры

 

Концепция:

·          используйте маркеры для разбиения на страницы, чтобы отметить границы подпрограммы (см. Руководство 2.1.7);

·          продублируйте в комментарии название тела пакета, тела подпрограммы, тела задачи или блока, если началу предшествуют декларации;

·          для длинных или многократно вложенных конструкций if и case отметьте их окончание с коротким резюме управляющих условий;

·          для длинных или многократно вложенных конструкций if отметьте else с резюме условий попадающих в эту секцию;

 

Пример:

 

if    A_Found then

   ...

elsif B_Found then

   ...

else  -- A and B were both not found

   ...

   if Count = Max then

      ...

   end if;

   ...

end if;  -- A_Found

 

 

------------------------------------------------------------------------

package body Abstract_Strings is

   ...

   ---------------------------------------------------------------------

   procedure Concatenate (...) is

   begin

      ...

   end Concatenate;

   ---------------------------------------------------------------------

   ...

begin  -- Abstract_Strings

   ...

end Abstract_Strings;

------------------------------------------------------------------------

 

Обсуждение:

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

 

Зарезервированные слова if, elsif, else, и end if конструкции выбора зачастую отделяются длинными последовательностями операторов, иногда с использованием других инструкций выбора. Как показано в первом примере, маркеры подчеркивают связь ключевых слов одной конструкции на большом протяжении кода. Для блоков и loop конструкций маркеры не нужны, поскольку эти конструкции могут быть именованы с повторением имени в конце. Использование именования предпочтительней, чем маркеры, поскольку компилятор проверяет эти имена на идентичность.

 

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

 

Комментарии:

 

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

 

 

3.4 Использование типов

 

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

 

 

3.4.1 Объявление типов

 

Концепция:

·          ограничьте диапазон скалярных типов в максимально возможной степени;

·          извлекайте информацию о возможных значениях из прикладной области;

·          не используйте для именования названия из пакета Standard;

·          используйте объявления подтипов для улучшения читабельности кода (Booch 1987);

·          используйте производные типы и подтипы осознанно (см. Руководство 5.3.1);

 

 

Пример:

 

subtype Card_Image is String (1 .. 80);

Input_Line : Card_Image := (others => ' ');

-- restricted integer type:

type    Day_Of_Leap_Year     is                  range 1 .. 366;

subtype Day_Of_Non_Leap_Year is Day_Of_Leap_Year range 1 .. 365;

 

Следующая декларация подразумевает, что автор мыслит приблизительно так «я имею самое туманное представление сколько", но фактический диапазон будет присутствовать в коде либо будет системным параметром:

 

Employee_Count : Integer;

 

 

Обсуждение:

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

 

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

 

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

 

Вы можете переименовать тип, объявляя подтип без указания диапазона (Ada Reference Manual 1995, §8.5). Перегрузить название подтипа нельзя. Перегрузка имен возможна только для названых сущностей. Перечислимые значения обрабатываются как функции без параметров  и потому включены в это правило.

 

Типы могут иметь жестко ограниченный набор значений, не устраняя при этом нужные значения. Их использование, как описано в Руководстве 5.3.1, устраняет много переменных-флагов и преобразований типов в пределах инструкций. Это способствует читабельности программы, позволяет компилятору строго контролировать использование типов.

 

Комментарии:

 

Объявление подтипа не определяет новый тип, оно только ограничивает существующий.

 

Любое отклонение от этого руководства уменьшает преимущества строгого контроля типов языка Ада.

 

Исключения:

Встречаются ситуации, когда специфический диапазон числовых значений не определен. Это, например, индекс массива (т.е. список, размер которого не ограничен никакой специфичной ситуацией). См. Руководство 7.2.1, где обсуждается использование встроенных типов.

 

 

3.4.2 Перечислимые типы

 

Концепция:

·          используйте перечислимые типы вместо числовых кодов;

·          только если абсолютно необходимо, определяйте внутренне представление, например, для соответствия требованиям внешних устройств;

 

Пример:

 

Используйте

 

type Color is (Blue, Red, Green, Yellow);

 

      вместо

 

Blue   : constant := 1;

Red    : constant := 2;

Green  : constant := 3;

Yellow : constant := 4;

 

            и при необходимости добавьте

 

for Color use (Blue   => 1,

               Red    => 2,

               Green  => 3,

               Yellow => 4);

 

 

Обсуждение:

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

 

Кроме того, в языке определено множество атрибутов ('Pos, 'Val, 'Succ, 'Pred, 'Image и 'Value) для перечислимых типов, которые надежнее чем написанные пользовательские операции.

 

Числовые значения, по началу, могут казаться более приемлемыми, особенно для аппаратных кодов. Однако в таких ситуациях лучше использовать перечислимые типы. Объявления таких типов являются еще и частью документации кода. Если программа должным образом структурирована для изолирования аппаратно зависимых участков (см. Руководство 7.1.5), числовые представления перечислимого типа, которыми заканчивается пакет интерфейса, легко найти и изменить, если требования изменятся.

 

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

 

 

3.5 Заключение

 

Использование специальных символов

 

·          используйте символ «_» для разделения названия на составные части;

·          представляйте числовые значения однотипно;

·          представляйте дробную часть соответственно прикладной области;

·          используйте символ подчеркивания для разделения групп цифр так же как в обычном тексте их разделяют запятой (или пробелом для не десятичной системы счисления);

·          для представления экспоненциальных значений используйте либо верхний, либо нижний регистр при записи символа “Е”;

·          в альтернативных системах счисления для записи алфавитных символов используйте постоянно либо верхний, либо нижний регистр;

·          сделайте зарезервированные слова и другие элементы программы визуально отличимыми друг от друга;

·          не используйте сокращение длинного слова как идентификатор, когда существует более короткий синоним;

·          используйте  единую стратегию для сокращений;

·          не используйте неоднозначные сокращения;

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

·          используйте аббревиатуры принятые в прикладной области;

·          подготовьте список аббревиатур и используйте только их;

 

 

Соглашения об именовании

 

·          выбирайте интуитивно понятные названия, насколько это возможно;

·          используйте короткие синонимы вместо аббревиатур (см. Руководство 3.1.4);

·          используйте имена предметной области, но не жаргон;

·          избегайте использовать одинаковые идентификаторы для различных объектов;

·          используйте уникальные общие существительные для идентификаторов производных типов;

·          выбирайте идентификаторы, которые описывают одно из значений производного типа;

·          выберите суффиксы для общедоступных ссылочных идентификаторов, поддиапазонов и массивов;

·          не используйте для приватных типов конструкции идентификаторов (такие как, например, суффиксы) являющиеся уникальными для производного типа;

·          не используйте имена производных типов из предопределенных пакетов;

·          используйте префикс или прилагательные для Boolean объектов;

·          используйте уникальные специфические существительные как идентификаторы объектов;

·          используйте идентификаторы, которые описывают значение объекта в процессе выполнения;

·          используйте уникальные общие существительные как идентификаторы компонентов структуры;

·          постоянно следуйте единому стилю именования теговых типов и взаимосвязанных пакетов;

·          используйте глаголы действий для именования процедур и входов;

·          используйте предиктаты для функций возвращающих тип BOOL;

·          используйте существительные для не булевых функций;

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

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

·          для защищенных модулей используйте существительные описывающие данные заключенные в нем;

·          используйте для настраиваемых подпрограмм те же соглашения что и для обычных подпрограмм;

·          используйте для настраиваемых пакетов те же соглашения что и для обычных пакетов;

·          используйте для именования настраиваемых сущностей более общие понятия;

·          используйте символические значения вместо литералов, где это возможно;

·          используйте предопределенные константы Ada.Numerics.Pi и  Ada.Numerics.e для математических констант Pi и e;

·          используйте константы вместо переменных для константных значений;

·          используйте константы, когда значение является специфическим для типа или когда значение должно быть статическим;

·          используйте именованные числа вместо констант, где это возможно;

·          используйте именованные числа вместо числовых литералов когда их тип или контекст является универсальным;

·          используйте константы для объектов, значение которых не должно изменятся после элаборации (United Technologies 1987);

·          показывайте взаимосвязи между символическими значениями путем объявления их со статическими выражениями;

·          используйте линейно независимые наборы литералов;

·          используйте атрибуты, такие как 'First и 'Last, вместо литералов, где это возможно;

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

·          используйте префикс New, Make, или Create в именах конструкторов (подразумеваются процедуры для создания или инициализации объектов);

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

 

Комментарии

 

·          создавайте настолько ясный код, насколько это возможно, что позволит уменьшить количество комментариев;

·          никогда не повторяйте в комментариях информацию, которая и так ясно видна из кода;

·          при необходимости комментария, создавайте его кратким и полным;

·          следите за правописанием в комментариях;

·          сделайте комментарий визуально отличимым от кода;

·          структурируйте комментарии в заголовках для облегчения автоматического извлечения информации инструментальными средствами.

·          помещайте заголовок в каждый файл с исходным кодом;

·          помещайте информацию о владельце, правах и истории в заголовок;

·          создавайте заголовок для спецификации каждой подпрограммы;

·          помещайте в заголовок спецификации информацию, необходимую для пользователя;

·          не дублируйте информацию (кроме названия) в заголовке спецификации, которая итак присутствует в коде спецификации;

·          опишите назначение подпрограммы, но не как или почему она это делает;

·          опишите полный интерфейс подпрограммы, включая любые исключения, которые она может генерировать и любые глобальные эффекты, к которым она может привести;

·          не включайте информацию о том, как подпрограмма вписывается в систему;

·          опишите требования (время и используемую память) подпрограммы;

·          поместите информацию, необходимую для сопровождения подпрограммы в заголовок реализации;

·          объясните, как подпрограмма функционирует, но не включайте информации о функциональности;

·          объясните, как подпрограмма функционирует, но не включайте информации о функциональности;

·          не дублируйте информацию (за исключением названия подпрограммы) в заголовке, которая доступна из заголовка спецификации;

·          комментируйте все типы данных, объекты и исключения назначение которых не ясно из их названия;

·          включайте информацию относительно семантической структуры сложных, ссылочных структур данных;

·          включайте информацию о взаимоотношениях между объектами данных;

·          не используйте комментарии которые повторяют информацию, доступную из названия;

·          включайте информацию о диспетчеризации для теговых типов в случае, когда производится специализация (например, в производных типах) для выделения этих операций;

·          минимизируйте комментарии управляющих структур;

·          комментируйте только те части кода, которые не очевидны;

·          отделяйте комментарии от кода;

·          не используйте комментарии, перефразирующие код;

·          не комментируйте отдаленные части кода, такие как подпрограммы вызываемые данным кодом;

·          сделайте комментарий визуально отличимым от кода;

·          используйте маркеры для разбиения на страницы, чтобы отметить границы подпрограммы (см. Руководство 2.1.7);

·          продублируйте в комментарии название тела пакета, тела подпрограммы, тела задачи или блока, если началу предшествуют декларации;

·          для длинных или многократно вложенных конструкций if и case отметьте их окончание с коротким резюме управляющих условий;

·          для длинных или многократно вложенных конструкций if отметьте else с резюме условий попадающих в эту секцию;

 

Использование типов

 

·          ограничьте диапазон скалярных типов в максимально возможной степени;

·          извлекайте информацию о возможных значениях из прикладной области;

·          не используйте для именования названия из пакета Standard;

·          используйте объявления подтипов для улучшения читабельности кода (Booch 1987);

·          используйте производные типы и подтипы осознанно (см. Руководство 5.3.1);

·          используйте перечислимые типы вместо числовых кодов;

·          только если абсолютно необходимо, определяйте внутренне представление, например для соответствия требованиям внешних устройств;
4. СТРУКТУРА ПРОГРАММЫ

 

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

 

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

 

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

 

 

4.1 Общая структура

 

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

 

 

4.1.1 Возможности раздельной компиляции

 

Концепция:

·          размещайте спецификацию каждого пакета в отдельном от реализации файле;

·          ограничьте подпрограммы уровня библиотеки только подпрограммами, которые могут использоваться как главные программы. Если другие подпрограммы все же необходимы, создайте для них явные спецификации и разместите их в отдельном для каждой подпрограммы файле спецификации;

·          минимизируйте количество подмодулей;

·          вместо подмодулей используйте дочерние пакеты для структурирования иерархии пакетов;

·          поместите каждый подмодуль в отдельный файл;

·          используйте последовательный подход к именованию файлов;

·          вместо вложенных, приватных пакетов в теле пакета используйте приватные дочерние пакеты с указанием контекста использования (with) в теле родительского пакета;

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

 Пример:

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

text_io.ads                 -- спецификация

text_io.adb                 -- реализация

text_io_integer_io.adb      -- подмодуль

text_io_fixed_io.adb        -- подмодуль

text_io_float_io.adb        -- подмодуль

text_io_enumeration_io.adb  -- подмодуль

 

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

 

text_io.ads                 -- спецификация

text_io.adb                 -- реализация

text_io#integer_io.adb      -- подмодуль

text_io#fixed_io.adb        -- подмодуль

text_io#float_io.adb        -- подмодуль

text_io#enumeration_io.adb  -- подмодуль

 

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

 

Обсуждение:

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

 

Минимизируйте подпрограммы библиотечных модулей. Единственное реальное использование библиотечных подпрограмм - как главная подпрограмма. Почти во всех остальных случаях лучше размещать подпрограммы в отдельных пакетах. Это обеспечит место (тело пакета) для сокрытия данных, требующихся для подпрограммы. Кроме того, это сокращает число отдельных модулей в системе.

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

Как альтернативный вариант, можно перенести такие подпрограммы в приватный дочерний пакет. Поскольку спецификация основного пакета будет неизменной, снижается количество необходимых перекомпиляций. Сервисные подпрограммы и, возможно, необходимые для них данные должны быть объявлены в спецификации приватного дочернего модуля, чтобы сделать их доступными для реализации основного пакета, а так же для всех дочерних пакетов, расширяющих абстракцию (См. также Руководства 4.1.6 и 4.2.). Такое использование приватных дочерних пакетов уменьшает перекомпиляции в пределах иерархии пакетов абстракции, а так же и среди клиентов.

 

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

 

 

4.1.2 Директивы конфиругации

 

Концепция:

·          если возможно используйте для директив конфигурирования опции компилятора или другие пути, не требующие модификации исходного кода;

·          если директивы необходимо разместить в исходном коде, постарайтесь разместить их в одном отдельном компилируемом модуле, желательно чтоб это был модуль с главной программой, если таковая определена;

 

Обсуждение:

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

 

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

 

Исключения:

            Некоторые директивы (как например Suppress) могут использоваться в различных участках кода. Данное руководство не относится к таким директивам, если они используются не как конфигурационные директивы.

 

 

4.1.3 Подпрограммы

 

Концепция:

·          используйте подпрограммы, чтобы улучшить абстрагирование;

·          ограничьте подпрограммы выполнением одной операции;

 

Пример:

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

 

...

----------------------------------------------------------------------

procedure Draw_Menu

      (Title   : in    String;

       Options : in    Menu) is

   ...

begin  -- Draw_Menu

   Ada.Text_IO.New_Page;

   Ada.Text_IO.New_Line;

   Ada.Text_IO.Set_Col  (Right_Column);

   Ada.Text_IO.Put_Line (Title);

   Ada.Text_IO.New_Line;

   for Choice in Alpha_Numeric loop

     if Options (Choice) /= Empty_Line then

         Valid_Option (Choice) := True;

         Ada.Text_IO.Set_Col (Left_Column);

         Ada.Text_IO.Put (Choice & " -- ");

         Ada.Text_IO.Put_Line (Options (Choice));

     end if;

     ...

   end loop;

end Draw_Menu;

----------------------------------------------------------------------

 

Обсуждение:

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

  

Комментарии:

            В Руководстве 10.7.1 обсуждаются вопросы накладных расходов на вызовы подпрограмм.

 

 

4.1.4 Функции

 

Концепция:

·          используйте функцию, когда основная цель подпрограммы состоит в том, чтобы возвратить одно значение;

·          минимизируйте побочные эффекты функции;

·          рассмотрите возможность использования функции без параметров, где не требуется статическое значение;

·          используйте функцию без параметров (вместо константы), если значение должно быть унаследовано типами, производными от данного типа;

·          используйте функцию без параметров, если само значение часто меняется;

 

 

 

Пример:

 

Хотя, чтение символа из файла приводит к смещению на следующий символ - это приемлемый побочный эффект учитывая основное назначение следующей функции:

 

function Next_Character return Character is separate;

 

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

 

  Word : constant String := String'(1 .. 5 => Next_Character);

begin  -- Start_Parsing

   Parse(Keyword => Word,

         Suffix1 => Next_Character,

         Suffix2 => Next_Character);

end Start_Parsing;

 

Конечно, если порядок значений не важен (как в генераторе случайного числа), то неважен и порядок их обработки.

 

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

 

type T is private;

function Nil return T;       -- Эти операции являются наследуемыми

function Default return T;   -- операциями типа Т. Наследники могут  

                             -- переопределить их. Так же можно

                             -- изменить значение в теле функции и

                             -- перекомпилировав реализацию.

 

 

Этот же пример можно записать с использованием констант:

 

type T is private;

Nil     : constant T;

Default : constant T;

 

 

Обсуждение:

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

 

 

4.1.5 Пакеты

 

Концепция:

·          используйте пакеты для сокрытия информации;

·          используйте пакеты для теговых и приватных типов для абстрагирования типов;

·          используйте пакеты для моделирования абстракций объектов соответственно прикладной области;

·          используйте пакеты для группирования близких объектов и деклараций (например, общие декларации для двух или больше библиотечных модулей);

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

·          поместите код, использующий низкоуровневые средства в подпрограммах, в отдельный пакет;

·          используйте пакеты и подпрограммы для инкапсуляции и скрытия подробностей реализации, которая может измениться (Nissen и Воллис 1984).

 

Пример:

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

 

package Directory is

 

   type Directory_Listing is limited private;

 

   procedure Read_Current_Directory (D : in out Directory_Listing);

 

   generic

      with procedure Process (Filename : in String);

   procedure Iterate (Over : in Directory_Listing);

 

   ...

 

private

 

   type Directory_Listing is ...

 

end Directory;

 

---------------------------------------------------------------

 

package body Directory is

 

   -- This procedure is machine dependent

   procedure Read_Current_Directory (D : in out Directory_Listing) is separate;

 

 

   procedure Iterate (Over : in Directory_Listing) is

      ...

   begin

      ...

 

      Process (Filename);

 

      ...

   end Iterate;

 

   ...

 

end Directory;

 

Обсуждение:

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

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

 

Комментарии:

Игнорирование данного руководства добавляет программисту ненужной работы. См. Руководство 10.7.1 где обсуждаются накладные расходы на вызовы подпрограмм.

 

 

4.1.6 Дочерние библиотечные модули

 

Концепция:

 

Пример:

 

Следующий пример системы управления окнами взят из Cohen et al. (1993) и иллюстрирует некоторые аспекты использования дочерних модулей в проектировании подсистем. Исходный (корневой) пакет объявляет типы, подтипы, и константы, в которых нуждаются клиенты и подсистемы. Индивидуальные дочерние пакеты реализовывают определенные части абстракций как например атомы, шрифты, вывод графических данных, курсоров и т.д.

 

package X_Windows is

   ...

private

   ...

end X_Windows;

 

 

package X_Windows.Atoms is

   type Atom is private;

   ...

private

   ...

end X_Windows.Atoms;

 

 

package X_Windows.Fonts is

   type Font is private;

   ...

private

   ...

end X_Windows.Fonts;

 

 

package X_Windows.Graphic_Output is

   type Graphic_Context is private;

   type Image is private;

   ...

private

   ...

end X_Windows.Graphic_Output;

 

 

package X_Windows.Cursors is

   ...

end X_Windows.Cursors;

 

 

package X_Windows.Keyboard is

   ...

end X_Windows.Keyboard;

 

 

Обсуждение:

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

Дочерние пакеты основываются на модульной силе Ада, где "разделение на  спецификацию и тело разграничивают пользовательский интерфейс пакета (спецификацию) от ее реализации (тела)" (Rationale 1995, §II.7). Дочерние пакеты обеспечивают дополнительную функциональность, для расширения корневого пакета без необходимости перекомпиляции самого корневого пакета, а так же и его пользователей.

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

Использование приватных дочерних пакетов для объявления локальных переменных дает возможность иметь легко доступные вспомогательные декларации, в которых Вы нуждаетесь, реализуя как корневой пакет, так и расширения исходного пакета. Тем самым облегчается сопровождение программы, за счет использования общего набора вспомогательных деклараций (представления данных, подпрограмм манипулирования данными). Это позволяет изменить внутреннее представление и реализацию вспомогательных подпрограмм, не изменяя или перекомпилируя остальную часть подсистемы, поскольку эти подпрограммы реализованы в теле приватного дочернего пакета. См. также Руководства 4.1.1, 4.2.1, 8.4.1, и 8.4.8.

 

См. также Руководство 9.4.1 где обсуждается использование дочерних библиотечных модулей в создании иерархии теговых типов.

 

 

4.1.7 Взаимосвязь

 

Концепция:

 

Пример:

 

Как пример того, как не надо делать возьмем пакет Project_Definitions. Как очевидно из названия он будет содержать объявления для всего проекта, и вероятнее всего в нем в беспорядке будут находиться абсолютно не связанные между собой данные. Вероятнее всего, такая конструкция используется для включения в контекст видимости одного модуля всеми частями программы.

Лучшим примером может служить пакет Display_Format_Definitions в котором содержатся все типы и константы требующиеся для определенного дисплея и формата, а так же пакет Cartridge_Tape_Handler, содержащий все типы, константы, и подпрограммы, обеспечивающие интерфейс специального устройства.

 

Обсуждение:

Степень, с которой объекты связаны в пакете, непосредственно воздействует на непринужденность понимания пакетов и программ, использующих их. Есть различные критерии для группирования, и некоторые из них менее эффективны, чем другие. Группируя класс данных или функциональности (например, модули инициализации) или группируя данные или действия, основанные на их временных характеристиках менее эффективно, чем группирование основанное на функции или потребности общаться через данные (Charette 1986).

"Правильное" структурирование системы оказывает огромное влияние на ее ремонтопригодность. Хотя это и может казаться сложным, все-таки важно реструктурировать пакеты, если изначальная структура не совсем правильна.

 

См. также Руководство 5.4.2, где обсуждаются гетерогенные данные.

 

Комментарии:

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

 

 

4.1.8 Связь с данными

Концепция:

 

Пример:

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

 

-------------------------------------------------------------------------

package Compilation_Status is

   type Line_Number is range 1 .. 2_500_000;

   function Source_Line_Number return Line_Number;

end Compilation_Status;

-------------------------------------------------------------------------

with Compilation_Status;

package Error_Message_Processing is

   -- Handle compile-time diagnostic.

end Error_Message_Processing;

-------------------------------------------------------------------------

with Compilation_Status;

 

package Code_Generation is

   -- Operations for code generation.

end Code_Generation;

-------------------------------------------------------------------------

 

Обсуждение:

Наличие сильной связи с данными осложняет отладку и сопровождение кода. Использование функций доступа защищает общие данные и уменьшает связь. Это предотвращает зависимость кода от структуры данных и дает возможность управлять ими.

 

Комментарии:

 

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

 

 

4.1.9 Задачи

 

Концепция:

 

Обсуждение:

Детальное обсуждение данного руководства приведено в Руководстве 6.1.2, в главе, посвященной задачам.

 

 

4.1.10 Защищенные типы

 

Концепция:

 

Пример:

            Смотрите пример, приведенный в Руководстве 6.1.1

 

Обсуждение:

Параллелизму и защищенным типам посвящена глава №6. Детальное обсуждение данного руководства приведено в Руководстве 6.1.1 

 

 

 

 

4.2 Видимость

 

Возможность предписывать сокрытие информации и разделять проблемы посредством  управления видимостью - одно из самых важных преимуществ языка, особенно когда "части большой системы разрабатываются отдельно". Игнорирование этих особенностей, например, злоупотребляя директивой use, является расточительным и опасным. См. также Руководства 5.7 и 9.4.1.

 

 

4.2.1 Минимизация интерфейсов

Концепция:

 

Пример:

-------------------------------------------------------------------------

package Telephone_Book is

   type Listing is limited private;

   procedure Set_Name (New_Name : in     String;

                       Current  : in out Listing);

   procedure Insert (Name    : in     String;

                     Current : in out Listing);

   procedure Delete (Obsolete : in     String;

                     Current  : in out Listing);

private

   type Information;

   type Listing is access Information;

end Telephone_Book;

-------------------------------------------------------------------------

package body Telephone_Book is

   -- Full details of record for a listing

   type Information is

      record

         ...

         Next : Listing;

      end record;

   First : Listing;

   procedure Set_Name (New_Name : in     String;

                       Current  : in out Listing) is separate;

   procedure Insert (Name    : in      String;

                     Current : in out  Listing) is separate;

   procedure Delete (Obsolete : in     String;

                     Current  : in out Listing) is separate;

end Telephone_Book;

-------------------------------------------------------------------------

 

Обсуждение:

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

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

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

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

Дочерние библиотечные модули могут обеспечить отличную иерархию библиотеки. Инженер может обеспечить различное представление для клиента и конструктора (Rationale 1995, §10.1). Создавая приватные дочерние пакеты, инженер может обеспечить средства, которые являются доступными только в подсистеме, произведенной от библиотечного пакета. Декларации из спецификации приватного дочернего пакета не экспортируются за пределы подсистемы. Таким образом, инженер может объявить утилиты абстракции в приватном дочернем пакете (например, отладочные программы [Cohen et al. 1993]) и быть уверенным, что пользователи абстракции (то есть, клиенты) не смогут их использовать.

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

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

 

Комментарии:

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

 

 

 

4.2.2 Вложенные пакеты

 

Концепция:

 

Пример:

 

Annex A в Ada Reference Manual (1995) предоставляет пример использования вложенной спецификации пакета. Спецификация настраиваемого пакета Generic_Bounded_Length вложена в спецификацию пакета Ada.Strings.Bounded. Вложенный настраиваемый пакет группирует тесно связанные операции.

 

Обсуждение:

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

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

 

 См. обсуждение Руководства 4.2.1.

 

 

4.2.3 Ограничение видимости

 

Концепция:

 

Пример:

 

Эта программа иллюстрирует использование дочерних библиотечных модулей для ограничения видимости. Процедура Rational_Numbers.Reduce вынесена в тело  Rational_Numbers для ограничения ее видимости только реализацией самого пакета. Вместо того, чтобы сделать средства ввода/вывода доступными в корневом пакете и всей  его иерархии, здесь эти средства объявлены как используемые только в дочернем пакете Rational_Numbers.IO. Этот пример адаптирован из Ada Reference Manual (1995), §§7.1, 7.2, и 10.1.1):

 

-------------------------------------------------------------------------
package Rational_Numbers is
   type Rational is private;
   function "=" (X, Y: Rational) return Boolean;
   function "/" (X, Y: Integer)  return Rational;  -- construct a rational number
   function "+" (X, Y: Rational) return Rational;
   function "-" (X, Y: Rational) return Rational;
   function "*" (X, Y: Rational) return Rational;
   function "/" (X, Y: Rational) return Rational;  -- rational division
private
   ...
end Rational_Numbers;
 
package body Rational_Numbers is
   procedure Reduce (R :in out Rational) is . . . end Reduce;
   . . .
end Rational_Numbers;
 
package Rational_Numbers.IO is
   procedure Put (R : in  Rational);
   procedure Get (R : out Rational);
end Rational_Numbers.IO;
 
with Ada.Text_IO;
with Ada.Integer_Text_IO;
package body Rational_Numbers.IO is   -- has visibility to parent private type declaration
   procedure Put (R : in  Rational) is
   begin
      Ada.Integer_Text_IO.Put (Item => R.Numerator, Width => 0);
      Ada.Text_IO.Put ("/");
      Ada.Integer_Text_IO.Put (Item => R.Denominator, Width => 0);
   end Put;
   procedure Get (R : out Rational) is . . . end Get;
end Rational_Numbers.IO;

 

 

Обсуждение:

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

Ограничение использования библиотечных модулей только дочерними пакетами, где они используются, вместо объявления их использования прямо в корневом пакете так же полезно. В примере выше видно, что пакет Text_IO используется только в дочернем пакете Rational_Numbers.IO.

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

 

 См. также Руководство 4.2.1, где обсуждается использование дочерних модулей.

 

Комментарии:

 

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

 

 

4.2.4 Сокрытие задач

 

Концепция:

 

 

 

Пример:

 

-------------------------------------------------------------------------
package Disk_Head_Scheduler is
   type Words        is ...
   type Track_Number is ...
   procedure Transmit (Track : in     Track_Number;
                       Data  : in     Words);
   ...
end Disk_Head_Scheduler;
-------------------------------------------------------------------------
package body Disk_Head_Scheduler is
   ...
   task Control is
      entry Sign_In (Track : in     Track_Number);
      ...
   end Control;
   ----------------------------------------------------------------------
   task Track_Manager is
      entry Transfer(Track_Number) (Data : in     Words);
   end Track_Manager;
   ----------------------------------------------------------------------
   ...
   procedure Transmit (Track : in     Track_Number;
                       Data  : in     Words) is
   begin
      Control.Sign_In(Track);
      Track_Manager.Transfer(Track)(Data);
   end Transmit;
   ----------------------------------------------------------------------
   ...
end Disk_Head_Scheduler;
-------------------------------------------------------------------------

 

Обсуждение:

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

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

 

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

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

 

 

4.3 Исключения

 

Этот раздел касается проблем использования исключений в контексте структуры программы. Тут обсуждается, как использовать исключения как часть интерфейса модуля, как их объявить, как генерировать и при каких обстоятельствах. Информация относительно того, как их обрабатывать, распространять и избегать их генерации находится в Руководстве 5.8. Проблемы переносимости находятся в Руководстве 7.5.

 

 

4.3.1 Использование исключений для определения абстракции.

 

Концепция:

 

Пример:

 

В этой спецификации пакета определено два исключения, которые расширяют абстракцию:

 

-------------------------------------------------------------------------

generic

   type Element is private;

package Stack is

 

   function Stack_Empty return Boolean;

   function Stack_Full  return Boolean;

 

   procedure Pop  (From_Top :    out Element);

   procedure Push (Onto_Top : in     Element);

 

   -- Raised when Pop is used on empty stack.

   Underflow : exception;

 

   -- Raised when Push is used on full stack.

   Overflow  : exception;

 

end Stack;

-------------------------------------------------------------------------

...

----------------------------------------------------------------------

procedure Pop (From_Top :    out Element) is

begin

   ...

 

   if Stack_Empty then

      raise Underflow;

 

   else -- Stack contains at least one element

      Top_Index := Top_Index - 1;

      From_Top  := Data(Top_Index + 1);

 

   end if;

end Pop;

--------------------------------------------------------------------

...

 

 

Обсуждение:

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

 

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

 

Несколько из представленных пунктов введены для расширения возможности пользователей отличать и исправлять различные виды ошибок. Объявление новых названий исключений, вместо использования объявленных в других пакетах, уменьшает связь между пакетами и делает их более различимыми. Экспортирование названий всех исключений, которые могут генерироваться в модуле, вместо сокрытия их в приватной части, позволяет пользователям модуля создавать специфические обработчики исключений. Иначе, пользователь будет вынужден обрабатывать исключения в разделе others. Наконец, документируйте какие из исключений, объявленных в пакете могут быть генерированы каждой подпрограммой или входом задачи, что позволит пользователю знать, какие обработчики исключений необходимы в каждой конкретной ситуации.

 

В ситуациях, когда пользователь не может принять никакого интеллектуального действия связанного с возникшей ошибкой лучше генерировать единственное исключение, сигнализирующее о внутренней ошибке. В пределах пакета такие внутренние ошибки все же лучше различать. Это позволит включить их в протокол или обработать соответствующим образом. Когда исключение будет передаваться пользователю, измените его на исключение внутренней ошибки. Это проинформирует его о том, что данную ошибку нельзя исправить. Так же обеспечьте уместную информацию для исключения, используя средства определенные в Ada.Exceptions. Таким образом, для любой абстракции необходимо определить N + 1 различных исключений. N различных ошибок, которые можно исправить, и одна неисправимая внутренняя ошибка. Прикладные требования и нужды клиентов в информации о возникших ошибках помогут Вам составить список соответствующих исключений для абстракции.

 

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

 

Для предоставления пользователю максимальной гибкости необходимы функции, позволяющие определить, будет ли сгенерировано исключение при вызове подпрограммы или входа задачи. Функция Stack_Empty из предыдущего примера является такой функцией. Она позволяет определить, генерировалось ли исключение Underflow при вызове процедуры Pop. Наличие таких функций позволяет пользователю избежать генерации исключений.

 

Для обеспечения возможности исправления ошибки пользователем, модуль должен избегать изменять свое состояние до генерации исключения. Если требуемая операция не может быть полностью и правильно выполнена, то модуль должен обнаружить это перед изменением любой внутренней информации либо откатить изменения до состояния перед выполнением запроса. Например, в приведенном выше примере после генерации исключения Underflow, абстракция имеет то же состояние как и до вызова процедуры Pop. Если бы это условие не было выполнено, то последующие вызовы процедур Push и Pop могли бы выполняться неверно. Такое поведение всегда желательно, но не всегда возможно.

 

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

 

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

 

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

 

4.4 Заключение

 

Общая структура

 

·          размещайте спецификацию каждого пакета в отдельном от реализации файле;

·          ограничьте подпрограммы уровня библиотеки только подпрограммами, которые могут использоваться как главные программы. Если другие подпрограммы все же необходимы, создайте для них явные спецификации и разместите их в отдельном для каждой подпрограммы файле спецификации;

·          минимизируйте количество подмодулей;

·          вместо подмодулей используйте дочерние пакеты для структурирования иерархии пакетов;

·          поместите каждый подмодуль в отдельный файл;

·          используйте последовательный подход к именованию файлов;

·          вместо вложенных, приватных пакетов в теле пакета используйте приватные дочерние пакеты с указанием контекста использования (with) в теле родительского пакета;

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

·          если возможно используйте для директив конфигурирования опции компилятора или другие пути, не требующие модификации исходного кода;

·          если директивы необходимо разместить в исходном коде, постарайтесь разместить их в одном отдельном компилируемом модуле, желательно чтоб это был модуль с главной программой, если таковая определена;

·          используйте подпрограммы, чтобы улучшить абстрагирование;

·          ограничьте подпрограммы выполнением одной операции;

·          используйте функцию, когда основная цель подпрограммы состоит в том, чтобы возвратить одно значение;

·          минимизируйте побочные эффекты функции;

·          рассмотрите возможность использования функции без параметров, где не требуется статическое значение;

·          используйте функцию без параметров (вместо константы), если значение должно быть унаследовано типами, производными от данного типа;

·          используйте функцию без параметров, если само значение часто меняется;

·          используйте пакеты для сокрытия информации;

·          используйте пакеты для теговых и приватных типов для абстрагирования типов;

·