Модульное программирование

Эта статья находится на начальном уровне проработки, в одной из её версий выборочно используется текст из источника, распространяемого под свободной лицензией
Материал из энциклопедии Руниверсалис
Парадигмы программирования

Рефлексивность
Гомоиконность

Мо́дульное программи́рование — это организация программы как совокупности небольших независимых блоков, называемых модулями, структура и поведение которых подчиняются определённым правилам.[1]

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

Мо́дуль — это последовательность логически связанных фрагментов, оформленных как отдельная часть программы[2]. Во многих языках (но далеко не обязательно) оформляется в виде отдельного файла с исходным кодом или поименованной непрерывной её части.

При построении модуля используется концепция: «один модуль – одна функция». Таким образом, модуль – это элемент программы, решающий одну самостоятельную задачу. Некоторые языки предусматривают объединение модулей в пакеты[3].

Модульность программного кода

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

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

При разбиении ПО на модули для каждого указывается реализуемая им функциональность, а также связи с другими модулями.[5]


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

  • возможность обновления кода - необходимо через промежуток времени для оптимизации или устранение логических ошибок;
  • дополнение к исходному коду - необходимо для расширения функционала модуля;
  • рефакторинг - редактирование, изменение или переработка кода для устранения излишней сложности, увеличения понятности, повышения гибкости, но без изменений в его поведении, что проверяется прогоном после каждой переделки тестов[6];
  • замена модуля другой логикой - в случае потери актуальности, несоизмеримости или необходимости удаление данного модуля.

Все это происходит без необходимости изменения остального программного кода проекта.


Основные концепции модульного программирования[7]:

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

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

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

Также это возможность замены отдельных компонентов (таких как jar-файлы, so или dll библиотеки) конечного программного продукта, без необходимости пересборки всего проекта (например, разработка плагинов к уже готовой программе).

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

Модульная система модулей

Несмотря на то, что модульное программирование никак не связано с деталями конкретного языка (и даже в случае отсутствия явной поддержки со стороны языка может применяться при достаточной дисциплине со стороны программистов), большинство языков выдвигают на верхний уровень свою собственную систему модулей, словно перенос системы модулей с одного языка на другой был бы невозможен[9].

В 2000 году Ксавье Лерой предложил делать системы модулей модульными, то есть параметризуемыми описанием конкретного ядра языка со своей системой типов[10]. В качестве примера он продемонстрировал обобщённую реализацию языка модулей ML (как наиболее развитой системы модулей из известных на данный момент) и примеры её инстанцирования на традиционный для неё язык ML и на язык Си.

Реализация Лероя сама построена посредством языка модулей ML, а именно в виде функтора, параметризованного данными о ядре языка и описанием его механизма проверки согласования типов. Это значит, что при написании компилятора некоторого языка достаточно описать ядро языка и передать его данному функтору (как библиотечной функции) — в результате получится компилятор расширения известного языка системой модулей ML.

История концепции модулей

История концепции модулей как единиц компиляции восходит к языкам Фортран II и Кобол, то есть, к концу 1950-х годов[11][12]. В 1976 году появилась публикация, в которой была развита концепция модульности — о языке Mesa[en], который был разработан в Xerox PARC. В 1977 году подробно ознакомился с этой концепцией учёный Никлаус Вирт, общаясь с разработчиками в Xerox PARC.[13] Эти идеи были использованы Виртом при создании языка Модула-2, публикация о котором вышла в 1977 году[14].

Термин «модуль» в программировании начал использоваться в связи с внедрением модульных принципов при создании программ. В 1970-х годах под модулем понимали какую-либо процедуру или функцию, написанную в соответствии с определёнными правилами. Например: «модуль должен быть простым, замкнутым (независимым), обозримым (от 50 до 100 строк), реализующим только одну функцию задачи, имеющим одну входную и одну выходную точку».

Первым основные свойства программного модуля более-менее чётко сформулировал Д. Парнас (David Parnas) в 1972 году: «Для написания одного модуля должно быть достаточно минимальных знаний о тексте другого». Таким образом, в соответствии с определением, модулем могла быть любая отдельная процедура (функция) как самого нижнего уровня иерархии (уровня реализации), так и самого верхнего уровня, на котором происходят только вызовы других процедур-модулей.[15]

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

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

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

Впервые специализированная синтаксическая конструкция модуля была предложена Н. Виртом в 1975 г. и включена в его новый язык Modula . Насколько сильно изменяются свойства языка, при введении механизма модулей, свидетельствует следующее замечание Н.Вирта, сделанное им по поводу более позднего языка Модула-2: «Модули — самая важная черта, отличающая язык Модула-2 от его предшественника Паскаля».

Реализация в языках программирования

Языки, формально поддерживающие концепцию модулей: IBM S/360 Assembler, Кобол, RPG, ПЛ/1, Ада, D, F (англ.), Фортран, Haskell, Blitz BASIC, OCaml, Паскаль, ML, Модула-2, Оберон, Компонентный Паскаль, Zonnon, Erlang, Perl, Python и Ruby. В IBM System использовались «модули» от языков RPG, Кобол и CL, когда программировалась в среде ILE.

Модульное программирование может быть осуществлено, даже когда синтаксис языка программирования не поддерживает явное задание имён модулям.

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

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

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

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

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

См. также

Примечания

  1. https://cyberpedia.su/6x88a4.html Архивная копия от 22 октября 2013 на Wayback Machine
  2. Модульное программирование — Студопедия. studopedia.ru. Дата обращения: 21 ноября 2022.
  3. Разработка программного обеспечения. poisk-ru.ru. Дата обращения: 21 ноября 2022.
  4. End Sub. При выполнении первой подпрограммы (proc1) в этом примере происходит вызов процедуры (AcB). lektsii.org. Дата обращения: 21 ноября 2022.
  5. МОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ - Визуальный словарь. Дата обращения: 18 апреля 2013. Архивировано 19 апреля 2013 года.
  6. Экстремальное программирование. studopedia.su. Дата обращения: 21 ноября 2022.
  7. Понятие модуля. Принципы модульного программирования. Понятие объекта как динамического модуля.. infopedia.su. Дата обращения: 21 ноября 2022.
  8. Модульность программного кода — КиберПедия. cyberpedia.su. Дата обращения: 21 ноября 2022.
  9. Leroy, 2000.
  10. Структурное и модульное программирование — КиберПедия. cyberpedia.su. Дата обращения: 21 ноября 2022.
  11. A brief history of FORTRAN
  12. COBOL Subprograms. Дата обращения: 23 октября 2009. Архивировано 5 мая 2009 года.
  13. Никлаус Вирт. Краткая история Modula и Lilith Архивная копия от 20 января 2007 на Wayback Machine, перевод с англ. с комментариями в тексте Р. Богатырева
  14. The History of Modula-2 and Oberon. Дата обращения: 22 октября 2009. Архивировано 1 июня 2012 года.
  15. D. L. Parnas. On the criteria to be used in decomposing systems into modules (англ.) // Communications of the ACM. — 1972. — Vol. 15, no. 12. — doi:10.1145/361598.361623.
  16. http://www.pascal.helpov.net/index/pascal_modules_programming Архивная копия от 21 октября 2013 на Wayback Machine [неавторитетный источник?]
  17. Павловская Татьяна Александровна. Язык программирования Pascal (учебный курс) (недоступная ссылка). Дата обращения: 21 октября 2013. Архивировано 21 октября 2013 года.

Литература

  • Xavier Leroy. A Modular Module System // vol.10, issue 3. — Journal of Functional Programming, 2000. — С. 269–303.