Что такое модуль в информатике кратко

Обновлено: 05.07.2024

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

Модульное программирование — это способ создания программы посредством объединения модулей в единую структуру.

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

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

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

В чем состоит особенность, основные принципы

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

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

Технологически процесс выглядит так:

  1. Описание данных.
  2. Проектирование по нисходящему принципу.
  3. Модульное программирование.
  4. Создание главной программы.
  5. Сборка продукта.

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

Разновидности модулей

В информатике существуют дополнительные понятия модуля.

Модуль — это набор команд, который имеет свое обозначение и который можно вызвать по имени.

Модуль — это совокупность программных операторов, имеющая идентификатор и граничные компоненты.

Также принято выделять три разновидности:

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

Примерами крупных могут послужить набор пакетов в языках Java, Ada, а также набор модулей в программном языке Modula-2.

Проблемы модульного программирования

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

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

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

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

Введение

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

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

Принципы модульного программирования

Базовыми принципами модульного программирования являются следующие:

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

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

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

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

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

Готовые работы на аналогичную тему

Определение и разновидности модулей

Существуют следующие дополнительные определения модуля:

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

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

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

Можно выделить следующие модульные разновидности:

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

  • Набор задач в программном языке Ada.
  • Кластеры в программном языке CLU.
  • Набор классов в языках С++ и Java.

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

  • Набор модулей в программном языке Modula-2.
  • Набор пакетов в программных языках Ada и Java.

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

Модуль — функционально законченный фрагмент программы, оформленный в виде отдельного файла с исходным кодом или поименованной непрерывной её части (например, Active Oberon), предназначенный для использования в других программах. Модули позволяют разбивать сложные задачи на более мелкие в соответствии с принципом модульности. Обычно проектируются таким образом, чтобы предоставлять программистам удобную для многократного использования функциональность (интерфейс) в виде набора функций, классов, констант. Модули могут объединяться в пакеты и, далее, в библиотеки. Удобство использования модульной архитектуры заключается в возможности обновления (замены) модуля, без необходимости изменения остальной системы. В большинстве случаев различные модули могут запускаться как на одном сервере, так и на разных, для распределения нагрузки и создания распределенной архитектуры.

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

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

Поддерживающие языки

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

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

Примечания

  1. ↑A brief history of FORTRAN
  2. ↑COBOL Subprograms
  3. ↑Никлаус Вирт. Краткая история Modula и Lilith, перевод с англ. с комментариями в тексте Р. Богатырева
  4. ↑The History of Modula-2 and Oberon
  • Концепции языков программирования
  • Структурные языки программирования

Wikimedia Foundation . 2010 .

Полезное

Смотреть что такое "Модуль (программирование)" в других словарях:

Контрактное программирование — (design by contract (DbC), programming by contract, contract based programming) это метод проектирования программного обеспечения. Он предполагает, что проектировщик должен определить формальные, точные и верифицируемые спецификации… … Википедия

Связанность (программирование) — Связанность (англ. coupling) или зависимость (англ. dependency) характеристика взаимосвязи модуля с другими модулями. Это степень, в которой каждый программный модуль полагается на другие модули. Связанность обычно… … Википедия

Функциональное программирование на Питоне — Функциональное программирование является одной из парадигм, поддерживаемых языком программирования Python. Основными предпосылками для полноценного функционального программирования в Python являются: функции высших порядков, развитые средства… … Википедия

Функциональное программирование на Python — Функциональное программирование является одной из парадигм, поддерживаемых языком программирования Python. Основными предпосылками для полноценного функционального программирования в Python являются: функции высших порядков, развитые средства… … Википедия

Объектно-ориентированное программирование на Python — Объектно ориентированное программирование на Python программирование на Python с использованием парадигмы ООП: с самого начала Python проектировался как объектно ориентированный язык программирования[1]. Содержание 1 Введение 1.1 … Википедия

Аспектно-ориентированное программирование — Парадигмы программирования Агентно ориентированная Компонентно ориентированная Конкатенативная Декларативная (контрастирует с Императивной) Ограничениями Функциональная Потоком данных Таблично ориентированная (электронные таблицы) Реактивная … Википедия

Эволюционное программирование — Содержание 1 Эволюционное программирование 2 Современное эволюционное программирование … Википедия

Компонентно-ориентированное программирование — Парадигмы программирования Агентно ориентированная Компонентно ориентированная Конкатенативная Декларативная (контрастирует с Императивной) Ограничениями Функциональная Потоком данных Таблично ориентированная (электронные таблицы) Реактивная … Википедия

Термин "модуль" (module) взят из статьи Modules vs. microservices. Так же для описания чего-то среднего между микросервисами и монолитами иногда используют термины "микролит" (microlith) или "моносервис" (monoservice). Но, не смотря на то, что термин "модуль" и так уже нагружен общеизвестным смыслом, на мой взгляд он подходит лучше других вариантов. Update: В комментарии lega использовал термин "встроенный микросервис" — он лучше описывает суть подхода, чем "модуль".

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

Я пишу микросервисы с 2009 года, но применять модули вместо микросервисов в реальных проектах пока не пробовал — всё описанное далее это моё предположение о том, каким должен быть вышеупомянутый баланс, и оно нуждается как в теоретической критике так и в проверке практикой.

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

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

В отличие от микросервисов, модуль:

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

В отличие от обычных библиотек, модуль:

  • Не должен разделять с использующим его API кодом никаких общих данных — все данные должны передаваться через API либо в виде копии, либо, если данных очень много и к ним нужен доступ только на чтение, в виде неизменяемой (immutable) структуры данных (требует поддержки на уровне языка).
  • Не предоставляет функций, которые могут вызывать другие модули — т.е. не выполняет никакого своего кода в чужом потоке выполнения (нити, горутине, etc.), таким образом изолируя от вызывающего кода даже исключения, которые могут возникать в коде модуля.
    • У модуля есть публичная функция инициализации и запуска модуля, которая вызывается при запуске приложения, но она не предназначена для (повторного) вызова из других модулей.
    • Конфигурацию (передаваемую ему при запуске приложения).
      • Она может включать общие для всех модулей настройки логирования.
    • Хранилище данных (если оно ему нужно).
      • Поддержка версионирования схемы этих данных и миграций при обновлениях — так же ответственность модуля, хотя запуск миграций данных каждого модуля может быть частью общего для всех модулей процесса деплоя приложения.

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

    Есть константная добавленная сложность (accidental complexity), одинаковая в каждом микросервисе (регистрация/обнаружение сервисов, подключение и переподключение к ним, авторизация между сервисами, (де)маршалинг и шифрование трафика, использование прерывателей зацикленных запросов, реализация трассировки запросов, etc.). Есть аналогичная константная добавленная операционная сложность (необходимость автоматизации тестирования и выката, реализация детального мониторинга, агрегация логов, использование служебных сервисов для регистрации и поиска сервисов, для хранения конфигурации сервисов, для аудита, etc.). С этим можно смириться, потому что реализовать всё это можно один раз, по мере роста количества микросервисов эта сложность не растёт, а преимущества микросервисов с лихвой компенсируют эти затраты.

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

    • Необходимость разделять идемпотентные и не идемпотентные запросы.
    • Для всех запросов на клиенте:
      • Необходимость использовать таймауты (которые могут быть разными для разных запросов).
      • Необходимость использовать больше асинхронности для ускорения работы.
      • Больше ситуаций eventual consistency и вызванных этим сложностей.
        • В т.ч. необходимость иногда кешировать данные других сервисов.
      • Необходимость повторять некоторые запросы:
        • Используя ограничение по количеству или времени повторов.
        • Используя задержки между повторами.
      • Необходимость реализовать возможность определения дубликатов при повторе запросов.
      • Необходимость определять и обрабатывать дубликаты запросов (по-разному, в зависимости от бизнес-логики каждого запроса).

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

      • Падение модуля приводит к падению всего приложения.
      • Уменьшается скорость сборки и тестирования.
        • Не уверен, что скорость сборки это реальная проблема — есть много способов её ускорения.
        • В принципе возможно при тестировании ветки/PR запускать только тесты изменившегося модуля, а тесты всего проекта выполнять только перед деплоем — это в достаточной степени должно нивелировать эту проблему.
        • Здесь проблема не столько в реальном замедлении, сколько в том, что когда сервисов много время запуска "размазано" по нескольким сервисам, которые (пере)запускаются независимо друг от друга. Тем не менее, видимый эффект более медленного запуска этот факт не отменяет.

        Так же у модульного подхода появляются новые достоинства:

        • Увеличивается скорость взаимодействия между модулями-сервисами, что и позволяет значительно уменьшить необходимость в асинхронности, eventual consistency и кешировании.
        • Пока у модуля нет внешнего (сетевого) API его API намного проще изменять и деплоить эти изменения атомарно с деплоем использующих этот модуль клиентов (других модулей этого же приложения).
        • Совместную работу модулей проще тестировать, чем группу микросервисов.
        • Проще использовать монорепо (если хочется), хоть это и не обязательно.
          • Монорепо упрощает рефакторинг и изменение API, по крайней мере пока есть гарантия что у модуля нет сетевого интерфейса и внешних клиентов.

          Необходимая поддержка этого подхода в данный момент есть далеко не во всех языках, но в некоторых есть: автор статьи "Modules vs. microservices" писал о поддержке модульности в Java 9, в Go уже пару лет есть поддержка internal-пакетов, в Erlang судя по статье на эту же тему Dawn of the Microlith — Monoservices with Elixir всё хорошо, …. Я не уверен, насколько на скриптовых языках возможно обеспечить реальную изоляцию модулей, но попытки есть: micromono на NodeJS, в комментарии lega ссылка на подход для Python, …

          Если у вас есть соображения по теме (а ещё лучше — опыт реального проекта на похожих принципах) или дополнительные ссылки на статьи/проекты по теме — пишите в комментариях, я постараюсь дополнять ими статью.

          Читайте также: