Протестировать основной модульный принцип сборки компьютера

Обновлено: 20.11.2024

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

Концепция модуляризации

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

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

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

  1. определить функцию (ее определение или код, который она будет выполнять)
  2. вызвать функцию
  3. объявить функцию (прототип — это объявление для компилятора)

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

Функции управления программой обычно не передают информацию друг другу, а используют общую область для хранения переменных. Специальные функции Task создаются таким образом, чтобы данные могли передаваться между вызывающей частью программы (которая обычно является другой функцией) и вызываемой функцией. Именно эта способность передавать данные позволяет нам создать специальную функцию задачи, которую можно использовать во многих программах. Правила того, как данные передаются в функцию и из функции, сильно различаются в зависимости от языка программирования, но концепция одна и та же. Передаваемые (или сообщаемые) элементы данных называются параметрами. Таким образом, формулировка: передача параметров. Четыре варианта передачи данных включают:

  1. нет связи на входе и нет связи на выходе
  2. нет входящей связи с некоторой исходящей связью
  3. некоторая связь входящая и некоторая исходящая информация
  4. некоторые входящие сообщения без исходящих сообщений

Функция управления программой

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

Конкретная функция задачи

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

Общий вид функции на языке с динамической типизацией, таком как JavaScript и Python:

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

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

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

Макет программы

Большинство программ имеют несколько элементов перед функциями, в том числе:

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

Ключевые термины

Ссылки

Лицензия

Книга «Основы программирования» Кеннета Лероя Басби и Дэйва Брауншвейга распространяется под лицензией Creative Commons Attribution-ShareAlike 4.0 International License, если не указано иное.

Шейн Бринкман-Дэвис Деламор — мастер своего дела, увлеченный UX-дизайном и продуктивностью программиста.

Обновлено 22 января 2020 г.

Зачем нам модульная конструкция?

Зачем нам модульная конструкция? Позвольте мне рассказать вам историю о моем друге Майке Келли. В 2016 году он устроился на подработку, чтобы создать простую платформу для курсов. Поскольку это была подработка, а Майку было скучно, он предложил выполнить эту работу по значительно сниженной ставке, если он сможет сохранить права на исходный код. Это был блестящий ход. У этого клиента был охват, и другие люди начали спрашивать о его работе. «Это действительно хорошая платформа. Его действительно легко использовать. Это быстро и хорошо работает. Что это?»

Майк решил прощупать почву. Его план состоял в том, чтобы упаковать продукт так, чтобы его было проще установить на оборудование каждого клиента. Он быстро понял, что поддерживать программное обеспечение в среде каждого клиента будет кошмаром. Вместо этого он перешел к решению «программное обеспечение как услуга», размещая курс каждого клиента в одном месте за ежемесячную плату. Так родился MemberVault.co.

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

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

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

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

Проблема заключалась в том, что код Майка был беспорядочным. Он не был модульным. Она росла органично, поскольку он изо всех сил старался не отставать от всех потребностей успешной, растущей компании SAAS. Например, вместо того, чтобы быть заключенным в один хорошо спроектированный модуль, код для добавления пользователей был продублирован и распределен по нескольким базам кода: Member-user-signup, member-admin, membervault-admin, задания cron, API и другие внешние интеграции.

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

Модульный дизайн

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

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

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

Модульная конструкция дает нам сверхспособности в борьбе со сложностью.

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

5 основных элементов модульного дизайна

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

Сделайте каждый модуль максимально простым в разработке, реализации, тестировании, развертывании, обновлении и обслуживании.

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

Интерфейс: интерфейс модуля должен быть простым в использовании, простым для понимания и легким для обеспечения правильности. Он должен предлагать все это без необходимости понимать какие-либо детали его реализации.
Для этого API модуля должен быть четко определен и задокументирован. API должен быть полным и минимальным. В нем должно быть именно то, что нужно и ничего лишнего. Наконец, его должно быть трудно использовать не по назначению. Самый простой способ использования модуля также должен быть правильным.
(три принципа превосходного дизайна API Арно)

инкапсуляция: реализация модуля является закрытой. Модули должны выставлять как можно меньше. Они не должны раскрывать свою функциональную структуру, структуру данных или собственные зависимости. Любая деталь реализации модуля должна быть изменяемой, не затрагивая ни одного клиента.
Это, пожалуй, самый важный элемент модульной конструкции. Все остальные четыре элемента можно выразить в терминах максимальной изоляции внутренней реализации от внешнего мира. В качестве абстракции каждый модуль должен быть максимально герметичным. Утечки становятся случайными, скрытыми частями общедоступного API. Без строгой инкапсуляции вы получите неявные зависимости, которые могут иметь катастрофические последствия для масштабирования проектов.
(Закон дырявых абстракций Джоэла

реализация: чтобы модуль был простым в использовании, он должен хорошо работать. Модуль с лучшим назначением, интерфейсом и инкапсуляцией все равно не будет работать без хорошей реализации. Реализация модуля должна быть правильной, производительной, протестированной и минимальной. Чем хуже реализация, тем хуже абстракция.

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

Что не должно быть модулем

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

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

монозависимость: если модуль используется только один раз в другом модуле, родительском, может не иметь смысла делать его отдельным модулем. Это нормально, даже хорошо иметь модули, которые имеют только одну зависимость. Их часто называют субмодулями. Пока они решают отдельную подзадачу для своего родителя, а также придерживаются других основных элементов хорошего модульного дизайна, они могут быть необходимы для управления сложностью этого родителя.
С другой стороны, если код используется два или более раз, особенно в разных модулях, он почти наверняка должен быть модулем, чтобы все оставалось СУХИМ.

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

Модуль с двумя или более зависимостями почти наверняка должен быть модулем, чтобы все оставалось СУХИМ.

Субъективная реальность модульности

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

Хорошо изучите правила, чтобы знать, как правильно их нарушать - Далай-лама

Преимущества модульности

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

понятность: в хорошо модульной системе намного легче рассуждать, думать и общаться с другими.

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

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

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

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

Масштабируемость. Все это составляет самое важное преимущество модулей: они позволяют масштабировать наши приложения. Невозможно создавать большие приложения без хорошей модульности. Без модулей сложность подорвет вашу продуктивность.

Без модулей сложность подорвет вашу продуктивность.

Выше, дальше, быстрее

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

Модули позволяют нам подниматься выше, идти дальше и строить быстрее.

Так что бегом! Поднимите свои навыки модульного проектирования на новый уровень и создайте что-то потрясающее!

Дополнительная литература

Узнайте больше о модульном дизайне с помощью практического примера применения этих принципов к приложениям JavaScript React-Redux:

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

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

Давайте начнем с некоторых определений.

Что такое модульное программирование?

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

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

Хотя большинство людей говорят о модульности на уровне файлов/папок/репозиториев, я думаю о модульности на нескольких уровнях:

  • Функции внутри файлов
  • Файлы в репозиториях/библиотеках
  • Библиотеки/репозитории в проектах

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

Модули и API

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

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

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

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

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

  • Катамари – используется для структур данных.
  • Sugar – Манипулирование HTML DOM – наш тестировщик

Каждый «модуль» содержит файлы и папки, соответствующие определенным правилам. Katamari — хороший пример со своими папками API и Util, которые содержат определенные виды кода в соответствии с нашими стандартами и рекомендациями. Затем папка API содержит файл для каждой концепции, предоставляемой через API Katamari, и все они собраны в файле Main.ts. Таким образом, если мы хотим узнать, какие методы у Katamari есть для массивов, мы можем просто заглянуть в Main.ts, чтобы увидеть, что предоставляет Katamari, а оттуда перейти к любому из файлов API, например к Arr.ts, который содержит методы. для работы с массивами. Это позволяет быстро и легко найти нужный код.

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

Зачем модульное программирование?

Цель модульного программирования – упростить разработку и обслуживание больших программ путем их разбиения на более мелкие части. Он имеет ряд преимуществ:

Код легче читать

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

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

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

Код легче тестировать

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

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

Легкий поиск вещей позже

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

  • Вспомогательные функции Unicode
  • Вспомогательные методы для работы с объектами
  • Вспомогательные методы для массивов

… и этот список можно продолжить. Разделение функций таким образом может значительно ускорить и упростить поиск нужной информации позже.

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

Повторное использование без раздувания

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

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

Единый источник для быстрого исправления

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

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

Обновление проще и с меньшим риском

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

Легкий рефакторинг

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

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

Легче сотрудничать

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

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

Есть ли недостатки?

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

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

На самом деле есть несколько причин, по которым некоторые люди до сих пор пишут спагетти-код:

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

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

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

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

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

Будущее модульного программирования

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

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

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

Использование TinyMCE с сборщиком модулей

Уже внедряете принципы модульного программирования в свои проекты или хотите поэкспериментировать с этой концепцией?

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

Вы занимаетесь модульным программированием? Почему или почему бы и нет?

Давайте продолжим обсуждение в Твиттере @joinTiny. Расскажите нам, используете ли вы или ваша команда модульное программирование и почему. И дайте нам знать, какой ваш любимый инструмент, который поможет вам сделать ваш код модульным!

Подпишитесь на нашу рассылку, чтобы не пропустить остальные наши блоги из этой серии!

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

Концепция модуляризации

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

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

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

  1. определить функцию (ее определение или код, который она будет выполнять)
  2. вызвать функцию
  3. объявить функцию (прототип — это объявление для компилятора)

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

Функции управления программой обычно не передают информацию друг другу, а используют общую область для хранения переменных. Специальные функции Task создаются таким образом, чтобы данные могли передаваться между вызывающей частью программы (которая обычно является другой функцией) и вызываемой функцией. Именно эта способность передавать данные позволяет нам создать специальную функцию задачи, которую можно использовать во многих программах. Правила того, как данные передаются в функцию и из функции, сильно различаются в зависимости от языка программирования, но концепция одна и та же. Передаваемые (или сообщаемые) элементы данных называются параметрами. Таким образом, формулировка: передача параметров. Четыре варианта передачи данных включают:

  1. нет связи на входе и нет связи на выходе
  2. нет входящей связи с некоторой исходящей связью
  3. некоторая связь входящая и некоторая исходящая информация
  4. некоторые входящие сообщения без исходящих сообщений

Функция управления программой

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

Конкретная функция задачи

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

Общий вид функции на языке с динамической типизацией, таком как JavaScript и Python:

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

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

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

Макет программы

Большинство программ имеют несколько элементов перед функциями, в том числе:

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

Ключевые термины

Ссылки

Лицензия

Книга «Основы программирования» Кеннета Лероя Басби и Дэйва Брауншвейга распространяется под лицензией Creative Commons Attribution-ShareAlike 4.0 International License, если не указано иное.

Шейн Бринкман-Дэвис Деламор — мастер своего дела, увлеченный UX-дизайном и продуктивностью программиста.

Обновлено 22 января 2020 г.

Зачем нам модульная конструкция?

Зачем нам модульная конструкция? Позвольте мне рассказать вам историю о моем друге Майке Келли. В 2016 году он устроился на подработку, чтобы создать простую платформу для курсов. Поскольку это была подработка, а Майку было скучно, он предложил выполнить эту работу по значительно сниженной ставке, если он сможет сохранить права на исходный код. Это был блестящий ход. У этого клиента был охват, и другие люди начали спрашивать о его работе. «Это действительно хорошая платформа. Его действительно легко использовать. Это быстро и хорошо работает. Что это?»

Майк решил прощупать почву. Его план состоял в том, чтобы упаковать продукт так, чтобы его было проще установить на оборудование каждого клиента. Он быстро понял, что поддерживать программное обеспечение в среде каждого клиента будет кошмаром. Вместо этого он перешел к решению «программное обеспечение как услуга», размещая курс каждого клиента в одном месте за ежемесячную плату. Так родился MemberVault.co.

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

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

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

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

Проблема заключалась в том, что код Майка был беспорядочным. Он не был модульным. Она росла органично, поскольку он изо всех сил старался не отставать от всех потребностей успешной, растущей компании SAAS. Например, вместо того, чтобы быть заключенным в один хорошо спроектированный модуль, код для добавления пользователей был продублирован и распределен по нескольким базам кода: Member-user-signup, member-admin, membervault-admin, задания cron, API и другие внешние интеграции.

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

Модульный дизайн

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

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

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

Модульная конструкция дает нам сверхспособности в борьбе со сложностью.

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

5 основных элементов модульного дизайна

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

Сделайте каждый модуль максимально простым в разработке, реализации, тестировании, развертывании, обновлении и обслуживании.

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

Интерфейс: интерфейс модуля должен быть простым в использовании, простым для понимания и легким для обеспечения правильности. Он должен предлагать все это без необходимости понимать какие-либо детали его реализации.
Для этого API модуля должен быть четко определен и задокументирован. API должен быть полным и минимальным. В нем должно быть именно то, что нужно и ничего лишнего. Наконец, его должно быть трудно использовать не по назначению. Самый простой способ использования модуля также должен быть правильным.
(три принципа превосходного дизайна API Арно)

инкапсуляция: реализация модуля является закрытой. Модули должны выставлять как можно меньше. Они не должны раскрывать свою функциональную структуру, структуру данных или собственные зависимости. Любая деталь реализации модуля должна быть изменяемой, не затрагивая ни одного клиента.
Это, пожалуй, самый важный элемент модульной конструкции. Все остальные четыре элемента можно выразить в терминах максимальной изоляции внутренней реализации от внешнего мира. В качестве абстракции каждый модуль должен быть максимально герметичным. Утечки становятся случайными, скрытыми частями общедоступного API. Без строгой инкапсуляции вы получите неявные зависимости, которые могут иметь катастрофические последствия для масштабирования проектов.
(Закон дырявых абстракций Джоэла

реализация: чтобы модуль был простым в использовании, он должен хорошо работать. Модуль с лучшим назначением, интерфейсом и инкапсуляцией все равно не будет работать без хорошей реализации. Реализация модуля должна быть правильной, производительной, протестированной и минимальной. Чем хуже реализация, тем хуже абстракция.

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

Что не должно быть модулем

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

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

монозависимость: если модуль используется только один раз в другом модуле, родительском, может не иметь смысла делать его отдельным модулем. Это нормально, даже хорошо иметь модули, которые имеют только одну зависимость. Их часто называют субмодулями. Пока они решают отдельную подзадачу для своего родителя, а также придерживаются других основных элементов хорошего модульного дизайна, они могут быть необходимы для управления сложностью этого родителя.
С другой стороны, если код используется два или более раз, особенно в разных модулях, он почти наверняка должен быть модулем, чтобы все оставалось СУХИМ.

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

Модуль с двумя или более зависимостями почти наверняка должен быть модулем, чтобы все оставалось СУХИМ.

Субъективная реальность модульности

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

Хорошо изучите правила, чтобы знать, как правильно их нарушать - Далай-лама

Преимущества модульности

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

понятность: в хорошо модульной системе намного легче рассуждать, думать и общаться с другими.

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

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

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

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

Масштабируемость. Все это составляет самое важное преимущество модулей: они позволяют масштабировать наши приложения. Невозможно создавать большие приложения без хорошей модульности. Без модулей сложность подорвет вашу продуктивность.

Без модулей сложность подорвет вашу продуктивность.

Выше, дальше, быстрее

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

Модули позволяют нам подниматься выше, идти дальше и строить быстрее.

Так что бегом! Поднимите свои навыки модульного проектирования на новый уровень и создайте что-то потрясающее!

Дополнительная литература

Узнайте больше о модульном дизайне с помощью практического примера применения этих принципов к приложениям JavaScript React-Redux:

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