Архитектура приложений: Как объяснить маме, что такое архитектура приложения?
Как объяснить маме, что такое архитектура приложения?
Мама не понимает, чем вы занимаетесь? Попробуйте объяснить. Начать лучше с основ, например, с разбора того, что такое архитектура приложения.
Это тема сложна для понимания, даже если вы немного разбираетесь в технологиях. Но если коротко, архитектура приложения − это набор методов и шаблонов, которые помогают разработчикам создавать структурированные приложения. В этом материале специалисты из команды Crypterium разбирают тему архитектуры и рассказывают о подходе компании к её разработке.
Давайте в объяснении того, что есть архитектура приложения, отойдем от технических терминов и проведем аналогию с повседневной жизнью. Посмотрите на свое тело. Все, что находится снаружи, − голова и тело, − это front, а всё, что внутри, − сердце, мозг и внутренние органы, − back.
Crypterium занимается разработкой платёжного сервиса. Back-end команда разрабатывает технологии, отвечающие за обмен, передачу, хранение и прочее, а Front-end следят за тем, чтобы пользователю было удобно взаимодействовать с функциями приложения.
Теперь, когда мы разобрались с различием front и back частей, давайте рассмотрим два ключевых подхода, которые используют современные разработчики: API First и Loose Coupling. Они позволяют программистам легко менять структуру приложения. Более того, они делают так, что каждая отдельная часть приложения может быть изменена без затрагивания остальных частей.
Метод API First отвечает за высокую скорость работы и нововведения. Идея в том, чтобы ввести данные и получить в ответ API, необходимый для Front-end и Back-end команд разработки: это позволяет им одновременно писать код и параллельно тестировать его. Преимущества метода заключаются в снижении издержек на разработку, увеличении скорости и снижении рисков.
Пример из жизни: когда вы готовите пасту Болоньезе, вам не нужна сначала паста, потом соус: вы можете готовить их параллельно. В таком случае, еда приготовится быстрее, ничего не успеет остыть, а друзья смогут оценить блюдо в том состоянии, в котором оно и должно быть (а не как обычно).
Одна из функций, за которую команда приложения любит подход API First, называется Swagger − это open-source фреймворк, который помогает разработчикам строить архитектуру, проектировать и создавать документацию для своих приложений. Swagger автоматически генерирует описание API для большинства языков и фреймворков, для обеих − Front-end и Back-end − команд.
Следующий подход называется Loose Coupling, в дословном переводе − слабая связь. И если в жизни примером Loose Coupling может быть отмена свидания в День святого Валентина, то в программировании это наоборот помогает. Если быть точнее, то эта функция упрощает соединение компонентов в сети.
Система Loose Coupling уменьшает риск случайного изменения отдельных объектов, без изменения других − так как в приложении всё взаимосвязано, это может привести к поломкам и уязвимостям. Так вот, благодаря возможности ограничения работы отдельных соединений, система помогает найти и решить проблему быстрее, прямо во время тестирования.
Благодаря принципам API First и Loose Coupling, приложение может выступать микросервисом − приложением, состоящем из независимых служб, способных работать самостоятельно, свободно масштабироваться на разных устройствах.
Микросервисные архитектуры лучше организованы, так как у каждого микросервиса есть определенная задача. Их преимущество ещё и в легкой реконфигурации и перестройке для различных целей. Кроме того, они характеризуются быстрым развертыванием, отказоустойчивостью, горизонтальным масштабированием, низким порогом входа и простотой управления.
Представьте себе умный дом, где все можно контролировать и управлять с помощью одного устройства. Допустим, это устройство − * core *, а управляемыми элементами являются * services *. С помощью основного устройства вы можете открывать окна, включать телевизор или даже закрывать шторы. Так работает архитектура микросервисов.
Но всегда есть альтернативный вариант, верно? Второй тип архитектуры − монолитная архитектура. Это означает, что приложение написано как одна единица кода, чьи компоненты предназначены для совместной работы, используют одни и те же ресурсы и место на диске. Службы в таких приложениях тесно связаны, и при изменении одной из них проблемы могут возникнуть у остальных.
Представьте себе многослойный шоколадный торт. Каждый новый слой делает торт ещё вкуснее, но вы не можете добавить слой с клубникой в середину, не изменив вкус и структуру торта. Можно считать, что у торта − монолитная архитектура.
Мультифункциональные приложения, например, мобильные кошельки, обычно связаны ещё с сотнями различных служб. Чтобы структурировать работу приложения, в Crypterium разделили команду Back-end разработчиков на две. Одна работает только над ядром продукта, вторая − над всем остальным, то есть авторизацией, коммуникацией и так далее.
Каждая команда использует собственные фреймворки. Основная выбрала .NET Core − платформу, которая характеризуется быстрой разработкой, отладкой и тестированием. Вдобавок, она высокопроизводительна, подходит для работы с кросс-платформенными приложениями и ориентирована на микросервисы. В то же время, остальные сервисы разрабатываются с помощью JVM-фреймворка, который, кстати, является прямым конкурентом продукту от Oracle.
Использование сразу двух популярных фреймворков позволяет выбирать из большего количества специалистов на рынке. Для .NET мы используем языки C, а для JVM − Kotlin и Java. Кроме того, эти же языки используются Android-разработчиками.
Команда Front-end специалистов следит за тем, чтобы приложение было удобным, а интерфейс − интуитивно-понятным и быстрым.
Android-версия приложения Crypterium основана на языках Java и Kotlin (как и среда JVM), а приложение iOS − на новом, простом в использовании языке программирования Swift. Функции языка включают в себя контроль доступа, управление памятью, отладку, цепочку вызовов и протокол-ориентированное программирование.
Команда разработчиков Crypterium для iOS, выбрала стиль архитектуры MVVM и роутинг. Благодаря структуре, архитектуры удобны и для разработчиков, и для пользователей.
MVVM − это Model-View-ViewModel, где Model означает информацию о продукте, а View показывает, как клиенты видят продукт. В MVVM есть структура слоев: первый уровень − UI (пользовательский интерфейс). Другие уровни содержат сетевые и логические сервисы. Роутинг отвечает за технические процессы − действия пользователей, перемещения внутри приложения, регулируются именно им.
Давайте разберем пример, когда пользователь хочет отправить криптовалюту на другой адрес. Слой сетевых сервисов содержит информацию о количестве отправленных монет данных и адресе. Когда пользователь подтверждает транзакцию, следующий слой проверяет, достаточно ли монет для отправки на счету, и предоставляет положительный или отрицательный ответ.
Чтобы повысить простоту обслуживания и гибкость приложений, команда Android решила использовать метод под названием «Чистая архитектура». Он гарантирует отсутствие ненужных связей и делает приложение более тестируемым.
Результатом является чистое, новое, свежее, простое в использовании приложение для Android с четырьмя уровнями:
- веб, базы данных, пользовательский интерфейс;
- шлюзы, презентаторы;
- варианты использования;
- юридическая информация.
Архитектура приложений − очень сложная тема, и все, что написано выше, является лишь верхушкой айсберга.
Если вам понравился материал о том, что такое архитектура приложения, посмотрите следующее:
Источник: Объясни это маме − что такое архитектура приложения on Hackernoon
Создание архитектуры программы или как проектировать табуретку / Хабр
Взявшись за написание небольшого, но реального и растущего проекта, мы «на собственной шкуре» убедились, насколько важно то, чтобы программа не только хорошо работала, но и была хорошо организована. Не верьте, что продуманная архитектура нужна только большим проектам (просто для больших проектов «смертельность» отсутствия архитектуры очевидна). Сложность, как правило, растет гораздо быстрее размеров программы. И если не позаботиться об этом заранее, то довольно быстро наступает момент, когда ты перестаешь ее контролировать. Правильная архитектура экономит очень много сил, времени и денег. А нередко вообще определяет то, выживет ваш проект или нет. И даже если речь идет всего лишь о «построении табуретки» все равно вначале очень полезно ее спроектировать.
К моему удивлению оказалось, что на вроде бы актуальный вопрос: «Как построить хорошую/красивую архитектуру ПО?» — не так легко найти ответ. Не смотря на то, что есть много книг и статей, посвященных и шаблонам проектирования и принципам проектирования, например, принципам SOLID (кратко описаны тут, подробно и с примерами можно посмотреть тут, тут и тут) и тому, как правильно оформлять код, все равно оставалось чувство, что чего-то важного не хватает. Это было похоже на то, как если бы вам дали множество замечательных и полезных инструментов, но забыли главное — объяснить, а как же «проектировать табуретку».
Хотелось разобраться, что вообще в себя включает процесс создания архитектуры программы, какие задачи при этом решаются, какие критерии используются (чтобы правила и принципы перестали быть всего лишь догмами, а стали бы понятны их логика и назначение). Тогда будет понятнее и какие инструменты лучше использовать в том или ином случае.
Данная статья является попыткой ответить на эти вопросы хотя бы в первом приближении. Материал собирался для себя, но, может, он окажется полезен кому-то еще. Мне данная работа позволила не только узнать много нового, но и в ином контексте взглянуть на кажущиеся уже почти банальными основные принципы ООП и по настоящему оценить их важность.
Информации оказалось довольно много, поэтому приведены лишь общая идея и краткие описания, дающие начальное представление о теме и понимание, где искать дальше.
Вообще говоря, не существует общепринятого термина «архитектура программного обеспечения». Тем не менее, когда дело касается практики, то для большинства разработчиков и так понятно какой код является хорошим, а какой плохим. Хорошая архитектура это прежде всего выгодная архитектура, делающая процесс разработки и сопровождения программы более простым и эффективным. Программу с хорошей архитектурой легче расширять и изменять, а также тестировать, отлаживать и понимать. То есть, на самом деле можно сформулировать список вполне разумных и универсальных критериев:
Эффективность системы. В первую очередь программа, конечно же, должна решать поставленные задачи и хорошо выполнять свои функции, причем в различных условиях. Сюда можно отнести такие характеристики, как надежность, безопасность, производительность, способность справляться с увеличением нагрузки (масштабируемость) и т.п.
Гибкость системы. Любое приложение приходится менять со временем — изменяются требования, добавляются новые. Чем быстрее и удобнее можно внести изменения в существующий функционал, чем меньше проблем и ошибок это вызовет — тем гибче и конкурентоспособнее система. Поэтому в процессе разработки старайтесь оценивать то, что получается, на предмет того, как вам это потом, возможно, придется менять. Спросите у себя: «А что будет, если текущее архитектурное решение окажется неверным?», «Какое количество кода подвергнется при этом изменениям?». Изменение одного фрагмента системы не должно влиять на ее другие фрагменты. По возможности, архитектурные решения не должны «вырубаться в камне», и последствия архитектурных ошибок должны быть в разумной степени ограничены. «Хорошая архитектура позволяет ОТКЛАДЫВАТЬ принятие ключевых решений» (Боб Мартин) и минимизирует «цену» ошибок.
Расширяемость системы. Возможность добавлять в систему новые сущности и функции, не нарушая ее основной структуры. На начальном этапе в систему имеет смысл закладывать лишь основной и самый необходимый функционал (принцип YAGNI — you ain’t gonna need it, «Вам это не понадобится») Но при этом архитектура должна позволять легко наращивать дополнительный функционал по мере необходимости. Причем так, чтобы внесение наиболее вероятных изменений требовало наименьших усилии.
Требование, чтобы архитектура системы обладала гибкостью и расширяемостью (то есть была способна к изменениям и эволюции) является настолько важным, что оно даже сформулировано в виде отдельного принципа — «Принципа открытости/закрытости» (Open-Closed Principle — второй из пяти принципов SOLID): Программные сущности (классы, модули, функции и т.п.) должны быть открытыми для расширения, но закрытыми для модификации.
Иными словами: Должна быть возможность расширить/изменить поведение системы без изменения/переписывания уже существующих частей системы.
Это означает, что приложение следует проектировать так, чтобы изменение его поведения и добавление новой функциональности достигалось бы за счет написания нового кода (расширения), и при этом не приходилось бы менять уже существующий код. В таком случае появление новых требований не повлечет за собой модификацию существующей логики, а сможет быть реализовано прежде всего за счет ее расширения. Именно этот принцип является основой «плагинной архитектуры» (Plugin Architecture). О том, за счет каких техник это может быть достигнуто, будет рассказано дальше.
Масштабируемость процесса разработки. Возможность сократить срок разработки за счёт добавления к проекту новых людей. Архитектура должна позволять распараллелить процесс разработки, так чтобы множество людей могли работать над программой одновременно.
Тестируемость. Код, который легче тестировать, будет содержать меньше ошибок и надежнее работать. Но тесты не только улучшают качество кода. Многие разработчики приходят к выводу, что требование «хорошей тестируемости» является также направляющей силой, автоматически ведущей к хорошему дизайну, и одновременно одним из важнейших критериев, позволяющих оценить его качество: «Используйте принцип «тестируемости» класса в качестве «лакмусовой бумажки» хорошего дизайна класса. Даже если вы не напишите ни строчки тестового кода, ответ на этот вопрос в 90% случаев поможет понять, насколько все «хорошо» или «плохо» с его дизайном» (Идеальная архитектура).
Существует целая методология разработки программ на основе тестов, которая так и называется — Разработка через тестирование (Test-Driven Development, TDD).
Возможность повторного использования. Систему желательно проектировать так, чтобы ее фрагменты можно было повторно использовать в других системах.
Хорошо структурированный, читаемый и понятный код. Сопровождаемость. Над программой, как правило, работает множество людей — одни уходят, приходят новые. После написания сопровождать программу тоже, как правило, приходится людям, не участвовавшем в ее разработке. Поэтому хорошая архитектура должна давать возможность относительно легко и быстро разобраться в системе новым людям. Проект должен быть хорошо структурирован, не содержать дублирования, иметь хорошо оформленный код и желательно документацию. И по возможности в системе лучше применять стандартные, общепринятые решения привычные для программистов. Чем экзотичнее система, тем сложнее ее понять другим (Принцип наименьшего удивления — Principle of least astonishment. Обычно, он используется в отношении пользовательского интерфейса, но применим и к написанию кода).
Ну и для полноты критерии плохого дизайна:
- Его тяжело изменить, поскольку любое изменение влияет на слишком большое количество других частей системы. (Жесткость, Rigidity).
- При внесении изменений неожиданно ломаются другие части системы. (Хрупкость, Fragility).
- Код тяжело использовать повторно в другом приложении, поскольку его слишком тяжело «выпутать» из текущего приложения. (Неподвижность, Immobility).
Не смотря на разнообразие критериев, все же главной при разработке больших систем считается задача снижения сложности. А для снижения сложности ничего, кроме деления на части, пока не придумано. Иногда это называют принципом «разделяй и властвуй» (divide et impera), но по сути речь идет об иерархической декомпозиции. Сложная система должна строится из небольшого количества более простых подсистем, каждая из которых, в свою очередь, строится из частей меньшего размера, и т. д., до тех пор, пока самые небольшие части не будут достаточно просты для непосредственного понимания и создания.
Удача заключается в том, что данное решение является не только единственно известным, но и универсальным. Помимо снижения сложности, оно одновременно обеспечивает гибкость системы, дает хорошие возможности для масштабирования, а также позволяет повышать устойчивость за счет дублирования критически важных частей.
Соответственно, когда речь идет о построении архитектуры программы, создании ее структуры, под этим, главным образом, подразумевается декомпозиция программы на подсистемы (функциональные модули, сервисы, слои, подпрограммы) и организация их взаимодействия друг с другом и внешним миром. Причем, чем более независимы подсистемы, тем безопаснее сосредоточиться на разработке каждой из них в отдельности в конкретный момент времени и при этом не заботиться обо всех остальных частях.
В этом случае программа из «спагетти-кода» превращается в конструктор, состоящий из набора модулей/подпрограмм, взаимодействующих друг с другом по хорошо определенным и простым правилам, что собственно и позволяет контролировать ее сложность, а также дает возможность получить все те преимущества, которые обычно соотносятся с понятием хорошая архитектура:
- Масштабируемость (Scalability)
возможность расширять систему и увеличивать ее производительность, за счет добавления новых модулей. - Ремонтопригодность (Maintainability)
изменение одного модуля не требует изменения других модулей - Заменимость модулей (Swappability)
модуль легко заменить на другой - Возможность тестирования (Unit Testing)
модуль можно отсоединить от всех остальных и протестировать / починить - Переиспользование (Reusability)
модуль может быть переиспользован в других программах и другом окружении - Сопровождаемость (Maintenance)
разбитую на модули программу легче понимать и сопровождать
Можно сказать, что в разбиении сложной проблемы на простые фрагменты и заключается цель всех методик проектирования. А термином «архитектура», в большинстве случаев, просто обозначают результат такого деления, плюс «некие конструктивные решения, которые после их принятия с трудом поддаются изменению» (Мартин Фаулер «Архитектура корпоративных программных приложений»). Поэтому большинство определений в той или иной форме сводятся к следующему:
«Архитектура идентифицирует главные компоненты системы и способы их взаимодействия. Также это выбор таких решений, которые интерпретируются как основополагающие и не подлежащие изменению в будущем.«
«Архитектура — это организация системы, воплощенная в ее компонентах, их отношениях между собой и с окружением.
Система — это набор компонентов, объединенных для выполнения определенной функции.«
Таким образом, хорошая архитектура это, прежде всего, модульная/блочная архитектура. Чтобы получить хорошую архитектуру надо знать, как правильно делать декомпозицию системы. А значит, необходимо понимать — какая декомпозиция считается «правильной» и каким образом ее лучше проводить?
1. Иерархическая
Не стоит сходу рубить приложение на сотни классов. Как уже говорилось, декомпозицию надо проводить иерархически — сначала систему разбивают на крупные функциональные модули/подсистемы, описывающие ее работу в самом общем виде. Затем, полученные модули, анализируются более детально и, в свою очередь, делятся на под-модули либо на объекты.
Перед тем как выделять объекты разделите систему на основные смысловые блоки хотя бы мысленно. Для небольших приложений двух уровней иерархии часто оказывается вполне достаточно — система вначале делится на подсистемы/пакеты, а пакеты делятся на классы.
Эта мысль, при всей своей очевидности, не так банальна как кажется. Например, в чем заключается суть такого распространенного «архитектурного шаблона» как Модель-Вид-Контроллер (MVC)? Всего навсего в отделении представления от бизнес-логики, то есть в том, что любое пользовательское приложение вначале делится на два модуля — один из которых отвечает за реализацию собственно самой бизнес логики (Модель), а второй — за взаимодействие с пользователем (Пользовательский Интерфейс или Представление). Затем, для того чтобы эти модули могли разрабатываться независимо, связь между ними ослабляется с помощью паттерна «Наблюдатель» (подробно о способах ослабления связей будет рассказано дальше) и мы фактически получаем один из самых мощных и востребованных «шаблонов», которые используются в настоящее время.
Типичными модулями первого уровня (полученными в результате первого деления системы на наиболее крупные составные части) как раз и являются — «бизнес-логика», «пользовательский интерфейс», «доступ к БД», «связь с конкретным оборудованием или ОС».
Для обозримости на каждом иерархическом уровне рекомендуют выделять от 2 до 7 модулей.
2. Функциональная
Деление на модули/подсистемы лучше всего производить исходя из тех задач, которые решает система. Основная задача разбивается на составляющие ее подзадачи, которые могут решаться/выполняться независимо друг от друга. Каждый модуль должен отвечать за решение какой-то подзадачи и выполнять соответствующую ей функцию. Помимо функционального назначения модуль характеризуется также набором данных, необходимых ему для выполнения его функции, то есть:
Модуль = Функция + Данные, необходимые для ее выполнения.
Причем желательно, чтобы свою функцию модуль мог выполнить самостоятельно, без помощи остальных модулей, лишь на основе своих входящих данных.
Модуль — это не произвольный кусок кода, а отдельная функционально осмысленная и законченная программная единица (подпрограмма), которая обеспечивает решение некоторой задачи и в идеале может работать самостоятельно или в другом окружении и быть переиспользуемой. Модуль должен быть некой «целостностью, способной к относительной самостоятельности в поведении и развитии» (Кристофер Александер).
Таким образом, грамотная декомпозиция основывается, прежде всего, на анализе функций системы и необходимых для выполнения этих функций данных.
3. High Cohesion + Low Coupling
Самым же главным критерием качества декомпозиции является то, насколько модули сфокусированы на решение своих задач и независимы. Обычно это формулируют следующим образом: «Модули, полученные в результате декомпозиции, должны быть максимально сопряженны внутри (high internal cohesion) и минимально связанны друг с другом (low external coupling).«
- High Cohesion, высокая сопряженность или «сплоченность» внутри модуля, говорит о том, модуль сфокусирован на решении одной узкой проблемы, а не занимается выполнением разнородных функций или несвязанных между собой обязанностей. (Сопряженность — cohesion, характеризует степень, в которой задачи, выполняемые модулем, связаны друг с другом )
Следствием High Cohesion является принцип единственной ответственности (Single Responsibility Principle — первый из пяти принципов SOLID), согласно которому любой объект/модуль должен иметь лишь одну обязанность и соответственно не должно быть больше одной причины для его изменения.
- Low Coupling, слабая связанность, означает что модули, на которые разбивается система, должны быть, по возможности, независимы или слабо связанны друг с другом. Они должны иметь возможность взаимодействовать, но при этом как можно меньше знать друг о друге (принцип минимального знания).
Это значит, что при правильном проектировании, при изменении одного модуля, не придется править другие или эти изменения будут минимальными. Чем слабее связанность, тем легче писать/понимать/расширять/чинить программу.
Считается, что хорошо спроектированные модули должны обладать следующими свойствами:
- функциональная целостность и завершенность — каждый модуль реализует одну функцию, но реализует хорошо и полностью; модуль самостоятельно (без помощи дополнительных средств) выполняет полный набор операций для реализации своей функции.
- один вход и один выход — на входе программный модуль получает определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор результатных данных, т.е. реализуется стандартный принцип IPO — вход–процесс–выход;
- логическая независимость — результат работы программного модуля зависит только от исходных данных, но не зависит от работы других модулей;
- слабые информационные связи с другими модулями — обмен информацией между модулями должен быть по возможности минимизирован.
Грамотная декомпозиция — это своего рода искусство и гигантская проблема для многих программистов. Простота тут очень обманчива, а ошибки обходятся очень дорого. Если выделенные модули оказываются сильно сцеплены друг с другом, если их не удается разрабатывать независимо или не ясно за какую конкретно функцию каждый из них отвечает, то стоит задуматься а правильно ли вообще производится деление. Должно быть понятно, какую роль выполняет каждый модуль. Самый же надежный критерий того, что декомпозиция делается правильно, это если модули получаются самостоятельными и ценными сами по себе подпрограммами, которые могут быть использованы в отрыве от всего остального приложения (а значит, могут быть переиспользуемы).
Делая декомпозицию системы желательно проверять ее качество задавая себе вопросы: «Какую функцию выполняет каждый модуль?«, “Насколько модули легко тестировать?”, “Возможно ли использовать модули самостоятельно или в другом окружении?”, “Как сильно изменения в одном модуле отразятся на остальных?”
В первую очередь следует, конечно же, стремиться к тому, чтобы модули были предельно автономны. Как и было сказано, это является ключевым параметром правильной декомпозиции. Поэтому проводить ее нужно таким образом, чтобы модули изначально слабо зависели друг от друга. Но кроме того, имеется ряд специальных техник и шаблонов, позволяющих затем дополнительно минимизировать и ослабить связи между подсистемами. Например, в случае MVC для этой цели использовался шаблон «Наблюдатель», но возможны и другие решения. Можно сказать, что техники для уменьшения связанности, как раз и составляют основной «инструментарий архитектора». Только необходимо понимать, что речь идет о всех подсистемах и ослаблять связанность нужно на всех уровнях иерархии, то есть не только между классам, но также и между модулями на каждом иерархическом уровне.
Для наглядности, картинка из неплохой статьи «Decoupling of Object-Oriented Systems», иллюстрирующая основные моменты, о которых будет идти речь.
1. Интерфейсы. Фасад
Главным, что позволяет уменьшать связанность системы, являются конечно же Интерфейсы (и стоящий за ними принцип Инкапсуляция + Абстракция + Полиморфизм):
- Модули должны быть друг для друга «черными ящиками» (инкапсуляция). Это означает, что один модуль не должен «лезть» внутрь другого модуля и что либо знать о его внутренней структуре. Объекты одной подсистемы не должны обращаться напрямую к объектам другой подсистемы
- Модули/подсистемы должны взаимодействовать друг с другом лишь посредством интерфейсов (то есть, абстракций, не зависящих от деталей реализации) Соответственно каждый модуль должен иметь четко определенный интерфейс или интерфейсы для взаимодействия с другими модулями.
Принцип «черного ящика» (инкапсуляция) позволяет рассматривать структуру каждой подсистемы независимо от других подсистем. Модуль, представляющий собой черный ящик, можно относительно свободно менять. Проблемы могут возникнуть лишь на стыке разных модулей (или модуля и окружения). И вот это взаимодействие нужно описывать в максимально общей (абстрактной) форме — в форме интерфейса. В этом случае код будет работать одинаково с любой реализацией, соответствующей контракту интерфейса. Собственно именно эта возможность работать с различными реализациями (модулями или объектами) через унифицированный интерфейс и называется полиморфизмом. Полиморфизм это вовсе не переопределение методов, как иногда ошибочно полагают, а прежде всего — взаимозаменяемость модулей/объектов с одинаковым интерфейсом, или «один интерфейс, множество реализаций» (подробнее тут). Для реализации полиморфизма механизм наследования совсем не нужен. Это важно понимать, поскольку наследования вообще, по возможности, следует избегать.
Благодаря интерфейсам и полиморфизму, как раз и достигается возможность модифицировать и расширять код, без изменения того, что уже написано (Open-Closed Principle). До тех пор, пока взаимодействие модулей описано исключительно в виде интерфейсов, и не завязано на конкретные реализации, мы имеем возможность абсолютно «безболезненно» для системы заменить один модуль на любой другой, реализующий тот же самый интерфейс, а также добавить новый и тем самым расширить функциональность. Это как в конструкторе или «плагинной архитектуре» (plugin architecture) — интерфейс служит своего рода коннектором, куда может быть подключен любой модуль с подходящим разъемом. Гибкость конструктора обеспечивается тем, что мы можем просто заменить одни модули/«детали» на другие, с такими же разъемами (с тем же интерфейсом), а также добавить сколько угодно новых деталей (при этом уже существующие детали никак не изменяются и не переделываются). Подробнее про Open-Closed Principle и про то, как он может быть реализован можно почитать тут + хорошая статья на английском.
Интерфейсы позволяют строить систему более высокого уровня, рассматривая каждую подсистему как единое целое и игнорируя ее внутреннее устройство. Они дают возможность модулям взаимодействовать и при этом ничего не знать о внутренней структуре друг друга, тем самым в полной мере реализуя принцип минимального знания, являющейся основой слабой связанности. Причем, чем в более общей/абстрактной форме определены интерфейсы и чем меньше ограничений они накладывают на взаимодействие, тем гибче система. Отсюда фактически следует еще один из принципов SOLID — Принцип разделения интерфейса (Interface Segregation Principle), который выступает против «толстых интерфейсов» и говорит, что большие, объемные интерфейсы надо разбивать на более маленькие и специфические, чтобы клиенты маленьких интерфейсов (зависящие модули) знали только о методах, которые необходимы им в работе. Формулируется он следующим образом: «Клиенты не должны зависеть от методов (знать о методах), которые они не используют» или “Много специализированных интерфейсов лучше, чем один универсальный”.
Итак, когда взаимодействие и зависимости модулей описываются лишь с помощью интерфейсов, те есть абстракций, без использования знаний об их внутреннем устройстве и структуре, то фактически тем самым реализуется инкапсуляция, плюс мы имеем возможность расширять/изменять поведения системы за счет добавления и использования различных реализаций, то есть за счет полиморфизма. Из этого следует, что концепция интерфейсов включает в себя и в некотором смысле обобщает почти все основные принципы ООП — Инкапсуляцию, Абстракцию, Полиморфизм. Но тут возникает один вопрос. Когда проектирование идет не на уровне объектов, которые сами же и реализуют соответствующие интерфейсы, а на уровне модулей, то что является реализацией интерфейса модуля? Ответ: если говорить языком шаблонов, то как вариант, за реализацию интерфейса модуля может отвечать специальный объект — Фасад.
Фасад — это объект-интерфейс, аккумулирующий в себе высокоуровневый набор операций для работы с некоторой подсистемой, скрывающий за собой ее внутреннюю структуру и истинную сложность. Обеспечивает защиту от изменений в реализации подсистемы. Служит единой точкой входа — «вы пинаете фасад, а он знает, кого там надо пнуть в этой подсистеме, чтобы получить нужное».
Таким образом, мы получаем первый, самый важный паттерн, позволяющий использовать концепцию интерфейсов при проектировании модулей и тем самым ослаблять их связанность — «Фасад». Помимо этого «Фасад» вообще дает возможность работать с модулями точно также как с обычными объектами и применять при проектировании модулей все те полезные принципы и техники, которые используются при проектирования классов.
Замечание: Хотя большинство программистов понимают важность интерфейсов при проектировании классов (объектов), складывается впечатление, что идея необходимости использовать интерфейсы также и на уровне модулей только зарождается. Мне встретилось очень мало статей и проектов, где интерфейсы бы применялись для ослабления связанности между модулями/слоями и соответственно использовался бы паттерн «Фасад». Кто, например, видел «Фасад» на схемах уже упоминавшегося «архитектурного шаблона» Модель-Вид-Контроллер, или хотя бы слышал его упоминание среди паттернов, входящих в состав MVC (наряду с Observer и Composite)? А ведь он там должен быть, поскольку Модель это не класс, это модуль, причем центральный. И у создателя MVC Трюгве Реенскауга он, конечно же, был (смотрим «The Model-View-Controller (MVC ). Its Past and Present», только учитываем, что это писалось в 1973 году и то, что мы сейчас называем Представлением — Presentaition/UI тогда называлось Editior). Странным образом «Фасад» потерялся на многие годы и вновь обнаружить его мне удалось лишь недавно, в основном, в обобщенном варианте MVC от Microsoft («Microsoft Application Architecture Guide»). Вот соответствующие слайды:
А разработчикам, к сожалению, приходится заново «переоткрывать» идею, что к объектам Модели, отвечающей за бизнес-логику приложения, нужно обращаться не напрямую а через интерфейс, то есть «Фасад», как например, в этой статье, откуда для полноты картины взят еще один слайд:
2. Dependency Inversion. Корректное создание и получение зависимостей
Формально, требование, чтобы модули не содержали ссылок на конкретные реализации, а все зависимости и взаимодействие между ними строились исключительно на основе абстракций, то есть интерфейсов, выражается принципом Инвертирования зависимостей (Dependency Inversion — последний из пяти принципов SOLID):
- Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те, и другие должны зависеть от абстракций.
- Абстракции не должны зависеть от деталей. Реализация должна зависеть от абстракции.
У этого принципа не самая очевидная формулировка, но суть его, как и было сказано, выражается правилом: «Все зависимости должны быть в виде интерфейсов». Подробно и очень хорошо принцип инвертирования зависимостей разбирается в статье Модульный дизайн или «что такое DIP, SRP, IoC, DI и т.п.». Статья из разряда must-read, лучшее, что доводилось читать по архитектуре ПО.
Не смотря на свою фундаментальность и кажущуюся простоту это правило нарушается, пожалуй, чаще всего. А именно, каждый раз, когда в коде программы/модуля мы используем оператор new и создаем новый объект конкретного типа, то тем самым вместо зависимости от интерфейса образуется зависимость от реализации.
Понятно, что этого нельзя избежать и объекты где-то должны создаваться. Но, по крайней мере, нужно свести к минимуму количество мест, где это делается и в которых явно указываются классы, а также локализовать и изолировать такие места, чтобы они не были разбросаны по всему коду программы. Решение заключается в том, чтобы сконцентрировать создание новых объектов в рамках специализированных объектов и модулей — фабрик, сервис локаторов, IoC-контейнеров.
В каком-то смысле такое решение следует Принципу единственного выбора (Single Choice Principle), который говорит: «всякий раз, когда система программного обеспечения должна поддерживать множество альтернатив, их полный список должен быть известен только одному модулю системы«. В этом случае, если в будущем придется добавить новые варианты (или новые реализации, как в рассматриваемом нами случае создания новых объектов), то достаточно будет произвести обновление только того модуля, в котором содержится эта информация, а все остальные модули останутся незатронутыми и смогут продолжать свою работу как обычно.
Ну а теперь разберем подробнее, как это делается на практике и каким образом модули могут корректно создавать и получать свои «зависимости», не нарушая принципа Dependency Inversion.
Итак, при проектировании модуля должны быть определены следующие ключевые вещи:
- что модуль делает, какую функцию выполняет
- что модулю нужно от его окружения, то есть с какими объектами/модулями ему придется иметь дело и
- как он это будет получать
Крайне важно то, как модуль получает ссылки на объекты, которые он использует в своей работе. И тут возможны следующие варианты:
- Модуль сам создает объекты необходимые ему для работы.
Но, как и было сказано, модуль не может это сделать напрямую — для создания необходимо вызвать конструктор конкретного типа, и в результате модуль будет зависеть не от интерфейса, а от конкретной реализации. Решить проблему в данном случае позволяет шаблон Фабричный Метод (Factory Method).
«Суть заключается в том, что вместо непосредственного инстанцирования объекта через new, мы предоставляем классу-клиенту некоторый интерфейс для создания объектов. Поскольку такой интерфейс при правильном дизайне всегда может быть переопределён, мы получаем определённую гибкость при использовании низкоуровневых модулей в модулях высокого уровня».
В случаях, когда нужно создавать группы или семейства взаимосвязанных объектов, вместо Фабричного Метода используется Абстрактная Фабрика (Abstract factory).
- Модуль берет необходимые объекты у того, у кого они уже есть (обычно это некоторый, известный всем репозиторий, в котором уже лежит все, что только может понадобиться для работы программы).
Этот подход реализуется шаблоном Локатор Сервисов (Service Locator), основная идея которого заключается в том, что в программе имеется объект, знающий, как получить все зависимости (сервисы), которые могут потребоваться.
Главное отличие от фабрик в том, что Service Locator не создаёт объекты, а фактически уже содержит в себе инстанцированные объекты (или знает где/как их получить, а если и создает, то только один раз при первом обращении). Фабрика при каждом обращении создает новый объект, который вы получаете в полную собственность и можете делать с ним что хотите. Локатор же сервисов выдает ссылки на одни и те же, уже существующие объекты. Поэтому с объектами, выданными Service Locator, нужно быть очень осторожным, так как одновременно с вами ими может пользоваться кто-то еще.
Объекты в Service Locator могут быть добавлены напрямую, через конфигурационный файл, да и вообще любым удобным программисту способом. Сам Service Locator может быть статическим классом с набором статических методов, синглетоном или интерфейсом и передаваться требуемым классам через конструктор или метод.
Вообще говоря, Service Locator иногда называют антипаттерном и не рекомендуют использовать (главным образом потому, что он создает неявные связности и дает лишь видимость хорошего дизайна). Подробно можно почитать у Марка Симана:
Service Locator is an Anti-Pattern
Abstract Factory or Service Locator? - Модуль вообще не заботиться о «добывании» зависимостей. Он лишь определяет, что ему нужно для работы, а все необходимые зависимости ему поставляются («впрыскиваются») из вне кем-то другим.
Это так и называется — Внедрение Зависимостей (Dependency Injection). Обычно требуемые зависимости передаются либо в качестве параметров конструктора (Constructor Injection), либо через методы класса (Setter injection).
Такой подход инвертирует процесс создания зависимости — вместо самого модуля создание зависимостей контролирует кто-то извне. Модуль из активного элемента, становится пассивным — не он делает, а для него делают. Такое изменение направления действия называется Инверсия Контроля (Inversion of Control), или Принцип Голливуда — «Не звоните нам, мы сами вам позвоним».
Это самое гибкое решение, дающее модулям наибольшую автономность. Можно сказать, что только оно в полной мере реализует «Принцип единственной ответственности» — модуль должен быть полностью сфокусирован на том, чтобы хорошо выполнять свою функцию и не заботиться ни о чем другом. Обеспечение его всем необходимым для работы это отдельная задача, которой должен заниматься соответствующий «специалист» (обычно управлением зависимостями и их внедрениями занимается некий контейнер — IoC-контейнер).
По сути, здесь все как в жизни: в хорошо организованной компании программисты программируют, а столы, компьютеры и все необходимое им для работы покупает и обеспечивает кладовщик. Или, если использовать метафору программы как конструктора — модуль не должен думать о проводах, сборкой конструктора занимается кто-то другой, а не сами детали.
Более подробно и с примерами о способах создания и получения зависимостей можно почитать, например, в этой статье (только надо иметь ввиду, что хотя автор пишет о Dependency Inversion, он использует термин Inversion of Control; возможно потому, что в русской википедии содержится ошибка и этим терминам даны одинаковые определения). А принцип Inversion of Control (вместе с Dependency Injection и Service Locator) детально разбирается Мартином Фаулером и есть переводы обеих его статей: «Inversion of Control Containers and the Dependency Injection pattern» и “Inversion of Control”.
Не будет преувеличением сказать, что использование интерфейсов для описания зависимостей между модулями (Dependency Inversion) + корректное создание и внедрение этих зависимостей (прежде всего Dependency Injection) являются центральными/базовыми техниками для снижения связанности. Они служат тем фундаментом, на котором вообще держится слабая связанность кода, его гибкость, устойчивость к изменениям, переиспользование, и без которого все остальные техники имеют мало смысла. Но, если с фундаментом все в порядке, то знание дополнительных приемов может быть очень даже полезным. Поэтому продолжим.
3. Замена прямых зависимостей на обмен сообщениями
Иногда модулю нужно всего лишь известить других о том, что в нем произошли какие-то события/изменения и ему не важно, что с этой информацией будет происходить потом. В этом случае модулям вовсе нет необходимости «знать друг о друге», то есть содержать прямые ссылки и взаимодействовать непосредственно, а достаточно всего лишь обмениваться сообщениями (messages) или событиями (events).
Связь модулей через обмен сообщениями является гораздо более слабой, чем прямая зависимость и реализуется она чаще всего с помощью следующих шаблонов:
- Наблюдатель (Observer). Применяется в случае зависимости «один-ко-многим», когда множество модулей зависят от состояния одного — основного. Использует механизм рассылки, который заключается в том, что основной модуль просто осуществляет рассылку одинаковых сообщений всем своим подписчикам, а модули, заинтересованные в этой информации, реализуют интерфейс «подписчика» и подписываются на рассылку. Находит широкое применение в системах с пользовательским интерфейсом, позволяя ядру приложения (модели) оставаться независимым и при этом информировать связанные с ним интерфейсы о том что произошли какие-то изменения и нужно обновиться.
Организация взаимодействия посредством рассылки сообщений имеет дополнительный «бонус» — необязательность существования «подписчиков» на «опубликованные» (т.е. рассылаемые) сообщения. Качественно спроектированная подобная система допускает добавление/удаление модулей в любое время.
- Посредник (Mediator). Применяется, когда между модулями имеется зависимость «многие ко многим. Медиатор выступает в качестве посредника в общении между модулями, действуя как центр связи и избавляет модули от необходимости явно ссылаться друг на друга. В результате взаимодействие модулей друг с другом («все со всеми») заменяется взаимодействием модулей лишь с посредником («один со всеми»). Говорят, что посредник инкапсулирует взаимодействие между множеством модулей.
Типичный пример — контроль трафика в аэропорту. Все сообщения, исходящие от самолетов, поступают в башню управления диспетчеру, вместо того, чтобы пересылаться между самолетами напрямую. А диспетчер уже принимает решения о том, какие самолеты могут взлетать или садиться, и в свою очередь отправляет самолетам соответствующие сообщения. Подробнее, например, тут.
Дополнение: Модули могут пересылать друг другу не только «простые сообщения, но и объекты-команды. Такое взаимодействие описывается шаблоном Команда (Command). Суть заключается в инкапсулировании запроса на выполнение определенного действия в виде отдельного объекта (фактически этот объект содержит один единственный метод execute()), что позволяет затем передавать это действие другим модулям на выполнение в качестве параметра, и вообще производить с объектом-командой любые операции, какие могут быть произведены над обычными объектами. Кратко рассмотрен тут, соответствующая глава из книги банды четырех тут, есть также статья на хабре.
4. Замена прямых зависимостей на синхронизацию через общее ядро
Данный подход обобщает и развивает идею заложенную в шаблоне «Посредник». Когда в системе присутствует большое количество модулей, их прямое взаимодействие друг с другом становится слишком сложным. Поэтому имеет смысл взаимодействие «все со всеми» заменить на взаимодействие «один со всеми». Для этого вводится некий обобщенный посредник, это может быть общее ядро приложения, хранилище или шина данных, а все остальные модули становятся независимыми друг от друга клиентами, использующими сервисы этого ядра или выполняющими обработку содержащейся там информации. Реализация этой идеи позволяет модулям-клиентам общаться друг с другом через посредника и при этом ничего друг о друге не знать.
Ядро-посредник может как знать о модулях-клиентах и управлять ими (пример — архитектура apache ), так и может быть полностью, или почти полностью, независимым и ничего о клиентах не знать. В сущности именно этот подход реализован в «шаблоне» Модель-Вид-Контроллер (MVC), где с одной Моделью (являющейся ядром приложение и общим хранилищем данных) могут взаимодействовать множество Пользовательских Интерфейсов, которые работают синхронно и при этом не знают друг о друге, а Модель не знает о них. Ничто не мешает подключить к общей модели и синхронизировать таким образом не только интерфейсы, но и другие вспомогательные модули.
Очень активно эта идея также используется при разработке игр, где независимые модули, отвечающие за графику, звук, физику, управление программой синхронизируются друг с другом через игровое ядро (модель), где хранятся все данные о состоянии игры и ее персонажах. В отличие от MVC, в играх согласование модулей с ядром (моделью) происходит не за счет шаблона «Наблюдатель», а по таймеру, что само по себе является интересным архитектурным решением весьма полезным для программ с анимацией и «бегущей» графикой.
5. Закон Деметры (law of Demeter)
Закон Деметры запрещает использование неявных зависимостей: «Объект A не должен иметь возможность получить непосредственный доступ к объекту C, если у объекта A есть доступ к объекту B и у объекта B есть доступ к объекту C«. Java-пример.
Это означает, что все зависимости в коде должны быть «явными» — классы/модули могут использовать в работе только «свои зависимости» и не должны лезть через них к другим. Кратко этот принцип формулируют еще таким образом: «Взаимодействуй только с непосредственными друзьями, а не с друзьями друзей«. Тем самым достигается меньшая связанность кода, а также большая наглядность и прозрачность его дизайна.
Закон Деметры реализует уже упоминавшийся «принцип минимального знания», являющейся основой слабой связанности и заключающийся в том, что объект/модуль должен знать как можно меньше деталей о структуре и свойствах других объектов/модулей и вообще чего угодно, включая собственные подкомпоненты. Аналогия из жизни: Если Вы хотите, чтобы собака побежала, глупо командовать ее лапами, лучше отдать команду собаке, а она уже разберётся со своими лапами сама.
6. Композиция вместо наследования
Одну из самых сильных связей между объектами дает наследование, поэтому, по возможности, его следует избегать и заменять композицией. Эта тема хорошо раскрыта в статье Герба Саттера — «Предпочитайте композицию наследованию».
Могу только посоветовать в данном контексте обратить внимание на шаблон Делегат (Delegation/Delegate) и пришедший из игр шаблон Компонет (Component), который подробно описан в книге «Game Programming Patterns» (соответствующая глава из этой книги на английском и ее перевод).
Статьи в интернете:
Замечательный ресурс — Архитектура приложений с открытым исходным кодом, где «авторы четырех дюжин приложений с открытым исходным кодом рассказывают о структуре созданных ими программ и о том, как эти программы создавались. Каковы их основные компоненты? Как они взаимодействуют? И что открыли для себя их создатели в процессе разработки? В ответах на эти вопросы авторы статей, собранных в данных книгах, дают вам уникальную возможность проникнуть в то, как они творят«. Одна из статей полностью была опубликована на хабре — «Масштабируемая веб-архитектура и распределенные системы».
Интересные решения и идеи можно найти в материалах, посвященных разработке игр. Game Programming Patterns — большой сайт с подробным описанием многих шаблонов и примерами их применения к задаче создания игр (оказывается, есть уже его перевод — «Шаблоны игрового программирования», спасибо strannik_k за ссылку). Возможно будет полезна также статья «Гибкая и масштабируемая архитектура для компьютерных игр» (и ее оригинал. Нужно только иметь ввиду что автор почему-то композицию называет шаблоном «Наблюдатель»).
По поводу паттернов проектирования:
Есть еще принципы/паттерны GRASP, описанные Крэгом Лэрманом в книге «Применение UML 2.0 и шаблонов проектирования», но они больше запутывают чем проясняют. Краткий обзор и обсуждение на хабре (самое ценное в комментариях).
Ну и конечно же книги:
НОУ ИНТУИТ | Лекция | Архитектура приложений
Аннотация: Рассматриваются архитектуры прикладных систем предприятия, контекст управления портфелем прикладных систем, модели и инструменты управления портфелем приложений
Архитектура приложений
Контекст и основные элементы архитектуры приложений
intuit.ru/2010/edi»>Архитектура приложений покрывает достаточно широкую область, которая начинается с идентификации того, какие прикладные системы нужны предприятию для выполнения бизнес-процессов, и включает такие аспекты, как проектирование, разработка (или приобретение) и интеграция прикладных систем.При такой широкой «области ответственности» архитектуры приложений следует уточнить содержание этого домена архитектуры предприятия.
В Архитектуре приложений, как правило, выделяют две основные области [4.3]:
- формирование и управление портфелем прикладных систем предприятия;
- разработку прикладных систем.
Рис.
6.1.
Две области Архитектуры приложений предприятия
Портфель прикладных систем предприятия является общим планом того, как потребности бизнес-процессов предприятия обеспечиваются набором прикладных систем. Он определяет область ответственности и приоритетность каждого приложения, а также то, как будет достигаться необходимая функциональность: за счет разработки системы, через покупку готовых приложений, аренду приложения или интеграцию и использование возможностей уже имеющихся приложений. Портфель прикладных систем описывает приложения, предназначенные для выполнения функций организации, а также обмена информацией между клиентами, поставщиками и партнерами предприятия. При этом описываются также каналы возможного взаимодействия пользователей с приложениями: web-браузеры, графический интерфейс «толстого» клиента, мобильные устройства и т.д.
Портфель прикладных систем обеспечивает целостный взгляд на функциональные компоненты информационных систем, которые обеспечивают потребности бизнес-архитектуры и архитектуры информации и поддерживаются технологической архитектурой. Тема управления портфелем прикладных систем тесно переплетается с темой управления ИТ-проектами и ИТ-активами в целом.
Область разработки прикладных систем описывает те технологии, которые используются для построения систем, разделения их на функциональные составляющие, создания интерфейсов, настройки, а также используемые для этого шаблоны, руководства и т.д. Эта область также определяет организацию процесса разработки, используемые для этого средства, принятый на предприятии цикл разработки систем, контроль версий, управление конфигурациями, используемое программное обеспечение промежуточного слоя, средства проектирования. Независимо от выбранных границ этой области, ее суть состоит не в ответе на вопрос, какие приложения должны быть созданы, а в выборе технологий для построения приложений и способов их применения. Основной задачей области является уменьшение стоимости создания прикладных систем и повышение их качества за счет обеспечения единых подходов к разработке. Это, в свою очередь, ведет к уменьшению общего количества различных технических сценариев, связанных с проектированием архитектуры,
операционной поддержкой, архитектурой интеграции систем, обучением персонала. Именно здесь требуется участие архитекторов прикладных систем (системных архитекторов). Разумеется, эту область имеет смысл выделять только для тех организаций, в которых производится самостоятельная разработка или доработка приложений, в отличие от модели аутсорсинга.
Отметим здесь отдельно важность той части архитектуры, связанной с разработкой прикладных систем, которая относится к использованию шаблонов проектирования. Мы отдельно затронем тему шаблонов в
«Технологическая архитектура, стандарты и шаблоны»
. Несмотря на то, что в настоящее время в этой области поставщиками технологий ведется активная работа, сами организации также должны уделять этому существенное внимание. Действительно, шаблоны находятся на стыке между обеспечением функциональных возможностей и технологиями. Они создают руководства по быстрому построению хорошо работающих систем в определенном контексте.
С учетом этих замечаний и выделения в архитектуре приложений двух областей – портфеля прикладных систем и разработки, – можно сказать, что внедрение на предприятии некоторой новой системы, например биллинга, является частью управления портфелем прикладных систем предприятия. При этом технологии и принципы, которые используются при проектировании системы, а также ее реализации и сопровождения, относятся к области разработки.
В нашем дальнейшем тексте мы будем говорить об архитектуре приложений, имея в виду, прежде всего, портфель прикладных систем. В идеале, портфель прикладных систем предприятия должен включать текущий набор приложений и некоторую модель, позволяющую понять, какие прикладные системы потребуются в будущем для обеспечения новых потребностей бизнеса и деятельности организации. Портфель приложений должен также задавать взаимосвязи между функциональными и технологическими (операционными) компонентами среды информационных технологий предприятия, т.е. объяснять, почему именно те или иные технологии были заложены в инфраструктуру для построения портфеля прикладных систем предприятия. Этот аспект важен, поскольку инвестиции в инфраструктуру составляют существенную часть капитальных затрат и нуждаются в серьезном обосновании. Наконец, портфель приложений должен давать представления о том, во что он обойдется с точки зрения финансовых затрат и как долго организация будет мигрировать в желаемое будущее состояние
с помощью данных прикладных систем.
Таким образом, портфель прикладных систем – это интегрированный набор информационных систем предприятия, который обеспечивает потребности бизнеса и включает в себя следующие аспекты:
- Имеющийся портфель прикладных систем. Это каталог имеющихся приложений и компонент, который отражает их связи с поддерживаемыми ими бизнес-процессами, интерфейсы с другими системами, используемую и требуемую информацию, используемые инфраструктурные шаблоны. Чтобы быть реально полезным инструментом, он также должен помогать в идентификации тех элементов портфеля, которые можно использовать повторно и многократно в рамках предприятия, и стимулировать такое повторное использование.
- Планируемый портфель прикладных систем. Представляет функциональность, которая требуется для обеспечения желаемого состояния бизнес-архитектуры и архитектуры информации предприятия.
- План миграции. Процесс перехода от текущего к будущему портфелю прикладных систем в рамках ИТ-проектов. Проекты также могут объединяться в портфели проектов.
Контекст управления портфелем прикладных систем показан на рис. 6.2.
Рис.
6.2.
Контекст управления портфелем прикладных систем
В левой части мы рассматриваем существующий в организации портфель прикладных систем. Портфель описывает достаточно большое количество взаимосвязей, включая бизнес-процессы, которые обеспечиваются работой прикладных систем. Прикладным системам для работы необходимы данные, и они также создают новые данные. Прикладные системы и данные, в свою очередь, обеспечиваются соответствующей инфраструктурой, которая определяется принятой в организации технологической архитектурой. Обратите внимание, что для различных типов прикладных систем могут потребоваться различные шаблоны (или стили) инфраструктуры (мы обсудим это ниже).
Первым шагом в планировании портфеля прикладных систем является оценка текущего состояния портфеля и того, насколько он соответствует потребностям организации со стратегической и технологической точек зрения, т.е. с точки зрения задач, стратегий бизнеса и с точки зрения технического состояния и стратегий использования технологий на предприятии. Соответствие бизнес-стратегиям оценивается на основе вклада прикладных систем в достижение бизнес-результатов, что определяется бизнес-архитектурой предприятия. Технологическое соответствие оценивается на основе анализа того, насколько прикладные системы соответствуют принципам и технологическим стандартам, принятым в технологической архитектуре предприятия.
Для такого рода оценок можно использовать различные модели и инструменты, которые кратко описаны в следующем разделе.
Общие архитектуры веб-приложений | Microsoft Docs
-
- Чтение занимает 18 мин
В этой статье
«Если вы считаете хорошую архитектуру слишком дорогой, попробуйте использовать плохую».»If you think good architecture is expensive, try bad architecture.»
— Брайан Фут (Brian Foote) и Джозеф Йодер (Joseph Yoder)— Brian Foote and Joseph Yoder
Большинство традиционных приложений .NET развертывается в виде одного элемента, соответствующего исполняемому файлу, или одного веб-приложения, выполняющегося в домене приложений служб IIS. Most traditional .NET applications are deployed as single units corresponding to an executable or a single web application running within a single IIS appdomain. Это простейшая модель развертывания, которая оптимально подходит для множества внутренних и небольших общедоступных приложений.This approach is the simplest deployment model and serves many internal and smaller public applications very well. Тем не менее даже в такой простой модели развертывания большинство бизнес-приложений использует преимущества логического разделения на слои.However, even given this single unit of deployment, most non-trivial business applications benefit from some logical separation into several layers.
Что собой представляет монолитное приложение?What is a monolithic application?
Монолитное приложение полностью замкнуто в контексте поведения.A monolithic application is one that is entirely self-contained, in terms of its behavior. Во время работы оно может взаимодействовать с другими службами или хранилищами данных, однако основа его поведения реализуется в собственном процессе, а все приложение обычно развертывается как один элемент. It may interact with other services or data stores in the course of performing its operations, but the core of its behavior runs within its own process and the entire application is typically deployed as a single unit. Для горизонтального масштабирования такое приложение обычно целиком дублируется на нескольких серверах или виртуальных машинах.If such an application needs to scale horizontally, typically the entire application is duplicated across multiple servers or virtual machines.
Комплексные приложенияAll-in-one applications
Архитектура приложения содержит как минимум один проект.The smallest possible number of projects for an application architecture is one. В таком случае вся логика приложения заключена в одном проекте, компилируется в одну сборку и развертывается как один элемент.In this architecture, the entire logic of the application is contained in a single project, compiled to a single assembly, and deployed as a single unit.
Любой создаваемый в Visual Studio или из командной строки проект ASP. NET Core изначально будет представлять собой комплексный монолитный проект.A new ASP.NET Core project, whether created in Visual Studio or from the command line, starts out as a simple «all-in-one» monolith. В нем будет заключено все поведение приложения, включая презентацию данных, бизнес-логику и логику доступа к данным.It contains all of the behavior of the application, including presentation, business, and data access logic. На рис. 5-1 показана файловая структура приложения, состоящего из одного проекта.Figure 5-1 shows the file structure of a single-project app.
Рис. 5-1.Figure 5-1. Приложение ASP.NET Core, состоящее из одного проекта.A single project ASP.NET Core app.
В сценарии с одним проектом разделение задач реализуется с помощью папок.In a single project scenario, separation of concerns is achieved through the use of folders. Используемый по умолчанию шаблон включает отдельные папки для обязанностей шаблона MVC (модели, представления и контроллеры), а также дополнительные папки для данных и служб. The default template includes separate folders for MVC pattern responsibilities of Models, Views, and Controllers, as well as additional folders for Data and Services. При такой организации детали презентации данных в максимально возможной степени размещаются в папке представлений (Views), а детали реализации доступа к данным должны быть ограничены классами, содержащимися в папке данных (Data).In this arrangement, presentation details should be limited as much as possible to the Views folder, and data access implementation details should be limited to classes kept in the Data folder. Бизнес-логика при этом размещается в службах и классах, находящихся в папке моделей (Models).Business logic should reside in services and classes within the Models folder.
Несмотря на свою простоту, монолитное решение с одним проектом имеет определенные недостатки.Although simple, the single-project monolithic solution has some disadvantages. По мере увеличения размера и сложности проекта будет расти число файлов и папок. As the project’s size and complexity grows, the number of files and folders will continue to grow as well. Задачи, связанные с пользовательским интерфейсом (модели, представления, контроллеры), размещаются в разных папках, которые не упорядочены по алфавиту.User interface (UI) concerns (models, views, controllers) reside in multiple folders, which aren’t grouped together alphabetically. С добавлением в отдельные папки конструкций уровня пользовательского интерфейса, например фильтров или связывателей модели, ситуация только ухудшается.This issue only gets worse when additional UI-level constructs, such as Filters or ModelBinders, are added in their own folders. Бизнес-логика теряется в папках моделей (Models) и служб (Services), в результате чего невозможно четко определить, какие классы в каких папках должны зависеть от других классов.Business logic is scattered between the Models and Services folders, and there’s no clear indication of which classes in which folders should depend on which others. Подобная неэффективная организация на уровне проекта часто приводит к получению плохо структурированного кода.This lack of organization at the project level frequently leads to spaghetti code.
Для решения подобных проблем приложения часто организуются в виде решений, состоящих из множества проектов, где каждый проект размещается в отдельном слое приложения.To address these issues, applications often evolve into multi-project solutions, where each project is considered to reside in a particular layer of the application.
Что представляют собой слои?What are layers?
По мере увеличения сложности приложения для эффективного управления им может применяться разбиение по обязанностям и задачам.As applications grow in complexity, one way to manage that complexity is to break up the application according to its responsibilities or concerns. Такой подход соответствует принципу разделения задач и помогает сохранить организацию расширяющейся базы кода, благодаря чему разработчики могут быстро определять, где именно реализованы определенные функции. This approach follows the separation of concerns principle and can help keep a growing codebase organized so that developers can easily find where certain functionality is implemented. Многослойная архитектура имеет также целый ряд других преимуществ.Layered architecture offers a number of advantages beyond just code organization, though.
Благодаря упорядочению кода с помощью слоев общие низкоуровневые функции могут многократно использоваться по всему приложению.By organizing code into layers, common low-level functionality can be reused throughout the application. Это крайне важно, поскольку такой подход требует меньшего объема кода и, за счет стандартизации приложения на уровне одной реализации, соответствует принципу «Не повторяйся».This reuse is beneficial because it means less code needs to be written and because it can allow the application to standardize on a single implementation, following the don’t repeat yourself (DRY) principle.
В приложениях с многослойной архитектурой могут устанавливаться ограничения на взаимодействие между слоями. With a layered architecture, applications can enforce restrictions on which layers can communicate with other layers. Такая архитектура помогает реализовать инкапсуляцию.This architecture helps to achieve encapsulation. При изменении или замене слоя будут затронуты только те слои, которые работают непосредственно с ним.When a layer is changed or replaced, only those layers that work with it should be impacted. Ограничивая зависимости слоев друг от друга, можно уменьшить последствия внесения изменений, в результате чего единичное изменение не будет влиять на все приложение.By limiting which layers depend on which other layers, the impact of changes can be mitigated so that a single change doesn’t impact the entire application.
Применение слоев (и инкапсуляция) позволяет заметно упростить замену функциональных возможностей в рамках приложения.Layers (and encapsulation) make it much easier to replace functionality within the application. Например, приложение может изначально использовать собственную базу данных SQL Server для сохраняемости, а впоследствии перейти на стратегию сохранения состояния на основе облака или веб-API. For example, an application might initially use its own SQL Server database for persistence, but later could choose to use a cloud-based persistence strategy, or one behind a web API. Если в приложении надлежащим образом инкапсулирована реализация сохраняемости на логическом слое, этот слой SQL Server может быть заменен новым, где будет реализовываться тот же открытый интерфейс.If the application has properly encapsulated its persistence implementation within a logical layer, that SQL Server-specific layer could be replaced by a new one implementing the same public interface.
Помимо возможности замены реализаций в связи с последующими изменениями, применение слоев в приложении также позволяет менять реализации в целях тестирования.In addition to the potential of swapping out implementations in response to future changes in requirements, application layers can also make it easier to swap out implementations for testing purposes. Вместо написания тестов, которые применяются к слоям реальных данных или пользовательского интерфейса приложения, во время тестирования они заменяются фиктивными реализациями, которые демонстрируют известную реакцию на запросы. Instead of having to write tests that operate against the real data layer or UI layer of the application, these layers can be replaced at test time with fake implementations that provide known responses to requests. Как правило, это значительно упрощает написание тестов и ускоряет их выполнение по сравнению с тестированием в реальной инфраструктуре приложения.This approach typically makes tests much easier to write and much faster to run when compared to running tests against the application’s real infrastructure.
Разделение на логические слои широко распространено и помогает упорядочить код приложений предприятия. Сделать это можно несколькими способами.Logical layering is a common technique for improving the organization of code in enterprise software applications, and there are several ways in which code can be organized into layers.
Примечание
Слои обеспечивают логический уровень разделения в приложении.Layers represent logical separation within the application. Если логика приложения физически распределена между несколькими серверами или процессами, такие раздельные физические целевые объекты развертывания называются уровнями.In the event that application logic is physically distributed to separate servers or processes, these separate physical deployment targets are referred to as tiers. Таким образом, не только возможно, но и широко распространено развертывание N-слойных приложений на одном уровне.It’s possible, and quite common, to have an N-Layer application that is deployed to a single tier.
Традиционные приложения с N-слойной архитектуройTraditional «N-Layer» architecture applications
Общепринятая организация логики приложения по слоям показана на рис. 5-2.The most common organization of application logic into layers is shown in Figure 5-2.
Рис. 5-2.Figure 5-2. Слои типового приложения.Typical application layers.
Как правило, в приложении определяются слои пользовательского интерфейса, бизнес-логики и доступа к данным. These layers are frequently abbreviated as UI, BLL (Business Logic Layer), and DAL (Data Access Layer). В рамках такой архитектуры пользователи выполняют запросы через слой пользовательского интерфейса, который взаимодействует только со слоем бизнес-логики.Using this architecture, users make requests through the UI layer, which interacts only with the BLL. Слой бизнес-логики, в свою очередь, может вызывать слой доступа к данным для обработки запросов.The BLL, in turn, can call the DAL for data access requests. Слой пользовательского интерфейса не должен выполнять запросы напрямую к слою доступа к данным и какими-либо другими способами напрямую взаимодействовать с функциями сохраняемости.The UI layer shouldn’t make any requests to the DAL directly, nor should it interact with persistence directly through other means. Аналогичным образом, слой бизнес-логики должен взаимодействовать с функциями сохраняемости только через слой доступа к данным.Likewise, the BLL should only interact with persistence by going through the DAL. Таким образом, для каждого слоя четко определена своя обязанность.In this way, each layer has its own well-known responsibility.
Одним из недостатков традиционного многослойного подхода является то, что обработка зависимостей во время компиляции осуществляется сверху вниз.One disadvantage of this traditional layering approach is that compile-time dependencies run from the top to the bottom. Это значит, что слой пользовательского интерфейса зависит от слоя бизнес-логики, который, в свою очередь, зависит от слоя доступа к данным.That is, the UI layer depends on the BLL, which depends on the DAL. Это значит, что слой бизнес-логики, который обычно содержит ключевые функции приложения, зависит от деталей реализации доступа к данным (и зачастую от наличия самой базы данных).This means that the BLL, which usually holds the most important logic in the application, is dependent on data access implementation details (and often on the existence of a database). Тестирование бизнес-логики в такой архитектуре зачастую затруднено и требует наличия тестовой базы данных. Testing business logic in such an architecture is often difficult, requiring a test database. Для решения этой проблемы может применяться принцип инверсии зависимостей, как описывается в следующем разделе.The dependency inversion principle can be used to address this issue, as you’ll see in the next section.
На рис. 5-3 показан пример решения, в котором приложение разделено на три проекта (или слоя) в соответствии с определенными обязанностями.Figure 5-3 shows an example solution, breaking the application into three projects by responsibility (or layer).
Рис. 5-3.Figure 5-3. Простое монолитное приложение, состоящее из трех проектов.A simple monolithic application with three projects.
Несмотря на то, что в целях упорядочения в этом приложении используется несколько проектов, оно по-прежнему развертывается как единый элемент, и его клиенты взаимодействуют с ним как с одним веб-приложением.Although this application uses several projects for organizational purposes, it’s still deployed as a single unit and its clients will interact with it as a single web app. Это позволяет реализовать крайне простой процесс развертывания.This allows for very simple deployment process. На рис. 5-4 показано, как такое приложение можно разместить с использованием Azure.Figure 5-4 shows how such an app might be hosted using Azure.
Рис. 5-4.Figure 5-4. Простое развертывание веб-приложения AzureSimple deployment of Azure Web App
По мере развития приложения могут потребоваться более сложные и надежные решения для развертывания.As application needs grow, more complex and robust deployment solutions may be required. На рис. 5-5 показан пример более сложного плана развертывания, который поддерживает дополнительные возможности.Figure 5-5 shows an example of a more complex deployment plan that supports additional capabilities.
Рис. 5-5.Figure 5-5. Развертывание веб-приложения в службе приложений AzureDeploying a web app to an Azure App Service
Разбиение этого проекта на несколько проектов на основе обязанностей позволяет повысить удобство поддержки приложения. Internally, this project’s organization into multiple projects based on responsibility improves the maintainability of the application.
Такой элемент поддерживает вертикальное и горизонтальное масштабирование, что позволяет использовать преимущества облачного масштабирования по запросу.This unit can be scaled up or out to take advantage of cloud-based on-demand scalability. Под вертикальным масштабированием понимается увеличение числа ЦП, объема памяти, места на диске и других ресурсов на серверах, где размещается приложение.Scaling up means adding additional CPU, memory, disk space, or other resources to the server(s) hosting your app. Горизонтальное масштабирование заключается в добавлении дополнительных экземпляров таких физических серверов, виртуальных машин или контейнеров.Scaling out means adding additional instances of such servers, whether these are physical servers, virtual machines, or containers. Если приложение размещается на нескольких экземплярах, для распределения запросов между экземплярами приложения используется система балансировки нагрузки. When your app is hosted across multiple instances, a load balancer is used to assign requests to individual app instances.
Самый простой подход к масштабированию веб-приложения в Azure заключается в ручной настройке масштабирования в плане службы приложений для приложения.The simplest approach to scaling a web application in Azure is to configure scaling manually in the application’s App Service Plan. На рис. 5-6 показан экран панели мониторинга Azure, предназначенный для настройки числа экземпляров, обслуживающих приложение.Figure 5-6 shows the appropriate Azure dashboard screen to configure how many instances are serving an app.
Рис. 5-6.Figure 5-6. Масштабирование плана службы приложений в Azure.App Service Plan scaling in Azure.
Чистая архитектураClean architecture
Приложения, использующие принципы инверсии зависимостей и проблемно-ориентированного проектирования, имеют схожую архитектуру.Applications that follow the Dependency Inversion Principle as well as the Domain-Driven Design (DDD) principles tend to arrive at a similar architecture. На протяжении многих лет она носила самые разные названия.This architecture has gone by many names over the years. Сначала это была шестигранная архитектура, на смену которой пришла архитектура портов и адаптеров.One of the first names was Hexagonal Architecture, followed by Ports-and-Adapters. На современном этапе она называется многослойной или чистой архитектурой.More recently, it’s been cited as the Onion Architecture or Clean Architecture. В этой электронной книге используется термин «чистая архитектура».The latter name, Clean Architecture, is used as the name for this architecture in this e-book.
Эталонное приложение eShopOnWeb использует подход на основе чистой архитектуры для организации кода в проекты.The eShopOnWeb reference application uses the Clean Architecture approach in organizing its code into projects. Вы можете найти шаблон решения, который можно использовать в качестве отправной точки для собственных решений ASP.NET Core в репозитории ardalis/cleanarchitecture на GitHub. You can find a solution template you can use as a starting point for your own ASP.NET Core on the ardalis/cleanarchitecture GitHub repository.
В рамках чистой архитектуры центральным элементом приложения являются его бизнес-логика и модель.Clean architecture puts the business logic and application model at the center of the application. В этом случае бизнес-логика не зависит от доступа к данным или другим инфраструктурам, то есть стандартная зависимость инвертируется: инфраструктура и детали реализации зависят от ядра приложения.Instead of having business logic depend on data access or other infrastructure concerns, this dependency is inverted: infrastructure and implementation details depend on the Application Core. Эта функциональность достигается путем определения абстракций или интерфейсов в ядре приложения, которые реализуются типами, определенными в слое инфраструктуры.This functionality is achieved by defining abstractions, or interfaces, in the Application Core, which are then implemented by types defined in the Infrastructure layer. Такую архитектуру обычно рисуют в виде серии окружностей с общим центром, которая внешне напоминает срез луковицы.A common way of visualizing this architecture is to use a series of concentric circles, similar to an onion. На рис. 5-7 показан пример такого стиля представления архитектуры.Figure 5-7 shows an example of this style of architectural representation.
Рис. 5-7.Figure 5-7. Чистая архитектура (многослойное представление)Clean Architecture; onion view
На этой схеме зависимости направлены из самой внутренней окружности.In this diagram, dependencies flow toward the innermost circle. Ядро приложения называется так потому, что находится в самом центре этой схемы.The Application Core takes its name from its position at the core of this diagram. Как видно на схеме, ядро приложения не имеет зависимостей от других слоев приложения.And you can see on the diagram that the Application Core has no dependencies on other application layers. Сущности и интерфейсы приложения находятся в самом центре.The application’s entities and interfaces are at the very center. Сразу после них, но все еще в пределах ядра приложения, расположены доменные службы, которые обычно реализуют интерфейсы, определенные во внутренней окружности.Just outside, but still in the Application Core, are domain services, which typically implement interfaces defined in the inner circle. За пределами ядра приложения располагаются слои пользовательского интерфейса и инфраструктуры, которые зависят от ядра приложения, но не друг от друга (обязательно).Outside of the Application Core, both the UI and the Infrastructure layers depend on the Application Core, but not on one another (necessarily).
На рис. 5-8 показана более привычная горизонтальная схема слоев, которая лучше отражает зависимости между слоем пользовательского интерфейса и другими слоями.Figure 5-8 shows a more traditional horizontal layer diagram that better reflects the dependency between the UI and other layers.
Рис. 5-8.Figure 5-8. Чистая архитектура (горизонтальное представление слоев)Clean Architecture; horizontal layer view
Обратите внимание, что сплошные стрелки соответствуют зависимостям времени компиляции, а пунктирные — зависимостям, которые существуют только во время выполнения.Note that the solid arrows represent compile-time dependencies, while the dashed arrow represents a runtime-only dependency. В рамках чистой архитектуры слой пользовательского интерфейса работает с интерфейсами, которые определены в ядре приложения во время компиляции, и в идеальном случае не должен знать ничего о типах реализации, определенных в слое инфраструктуры.With the clean architecture, the UI layer works with interfaces defined in the Application Core at compile time, and ideally shouldn’t know about the implementation types defined in the Infrastructure layer. Тем не менее во время выполнения эти типы реализации необходимы для выполнения приложения, поэтому они должны существовать и быть привязаны к интерфейсам ядра приложения посредством внедрения зависимостей. At run time, however, these implementation types are required for the app to execute, so they need to be present and wired up to the Application Core interfaces via dependency injection.
На рис. 5-9 показано более подробное представление архитектуры приложения ASP.NET Core, построенного с соблюдением этих рекомендаций.Figure 5-9 shows a more detailed view of an ASP.NET Core application’s architecture when built following these recommendations.
Рис. 5-9.Figure 5-9. Схема чистой архитектуры ASP.NET Core.ASP.NET Core architecture diagram following Clean Architecture.
Поскольку ядро приложения не зависит от инфраструктуры, для этого слоя легко писать автоматические модульные тесты.Because the Application Core doesn’t depend on Infrastructure, it’s very easy to write automated unit tests for this layer. На рис. 5-10 и 5-11 показано, как эти тесты вписываются в такую архитектуру.Figures 5-10 and 5-11 show how tests fit into this architecture.
Рис. 5-10.Figure 5-10. Изолированное модульное тестирование ядра приложения.Unit testing Application Core in isolation.
Рис. 5-11.Figure 5-11. Интеграционное тестирование реализаций инфраструктуры с внешними зависимостями.Integration testing Infrastructure implementations with external dependencies.
Поскольку слой пользовательского интерфейса не имеет прямых зависимостей от типов, определенных в проекте инфраструктуры, будет так же просто менять реализации в целях тестирования или в случае изменения требований к приложению.Since the UI layer doesn’t have any direct dependency on types defined in the Infrastructure project, it’s likewise very easy to swap out implementations, either to facilitate testing or in response to changing application requirements. ASP.NET Core предлагает встроенную поддержку внедрения зависимостей, в связи с чем такая архитектура представляет собой оптимальный подход к структурированию нетривиальных монолитных приложений. ASP.NET Core’s built-in use of and support for dependency injection makes this architecture the most appropriate way to structure non-trivial monolithic applications.
Для монолитных приложений проекты ядра приложения, инфраструктуры и пользовательского интерфейса выполняются как единое приложение.For monolithic applications, the Application Core, Infrastructure, and UI projects are all run as a single application. Во время выполнения архитектура приложения будет выглядеть так, как показано на рис. 5-12.The runtime application architecture might look something like Figure 5-12.
Рис. 5-12.Figure 5-12. Пример архитектуры приложения ASP.NET Core во время выполнения.A sample ASP.NET Core app’s runtime architecture.
Упорядочение кода в рамках чистой архитектурыOrganizing code in Clean Architecture
В решении с чистой архитектурой для каждого проекта четко определены обязанности.In a Clean Architecture solution, each project has clear responsibilities. Фактически, каждому проекту будут принадлежать определенные типы, а в проектах будут представлены соответствующие этим типам папки.As such, certain types belong in each project and you’ll frequently find folders corresponding to these types in the appropriate project.
Ядро приложенияApplication Core
Ядро приложения содержит бизнес-модель, которая включает в себя сущности, службы и интерфейсы.The Application Core holds the business model, which includes entities, services, and interfaces. Такие интерфейсы включают абстракции для операций, которые будут выполняться с использованием архитектуры, включая операции доступа к данным или файловой системе, сетевые вызовы и т. д. В некоторых случаях службы или интерфейсы, определенные в этом слое, должны работать с типами, не являющимися типами сущностей, которые не имеют зависимостей от пользовательского интерфейса или инфраструктуры.These interfaces include abstractions for operations that will be performed using Infrastructure, such as data access, file system access, network calls, etc. Sometimes services or interfaces defined at this layer will need to work with non-entity types that have no dependencies on UI or Infrastructure. Они могут определяться как простые объекты передачи данных.These can be defined as simple Data Transfer Objects (DTOs).
Типы ядра приложенияApplication Core types
- Сущности (сохраняемые классы бизнес-модели)Entities (business model classes that are persisted)
- интерфейсов,Interfaces
- СлужбыServices
- Объекты передачи данныхDTOs
ИнфраструктураInfrastructure
Как правило, проект инфраструктуры включает реализацию доступа к данным.The Infrastructure project typically includes data access implementations. В типовом веб-приложении ASP.NET Core эта реализация включает Entity Framework (EF) DbContext, любые определенные объекты Migration
EF Core, а также классы реализации доступа к данным.In a typical ASP.NET Core web application, these implementations include the Entity Framework (EF) DbContext, any EF Core Migration
objects that have been defined, and data access implementation classes. Наиболее распространенный подход к абстрагированию кода реализации доступа к данным заключается в использовании конструктивного шаблона репозитория.The most common way to abstract data access implementation code is through the use of the Repository design pattern.
Помимо реализации доступа к данным, проект инфраструктуры должен также включать реализации служб, которые должны взаимодействовать с инфраструктурными задачами.In addition to data access implementations, the Infrastructure project should contain implementations of services that must interact with infrastructure concerns. Эти службы должны реализовывать интерфейсы, определенные в ядре приложения. Таким образом, инфраструктура должна содержать ссылку на проект ядра приложения.These services should implement interfaces defined in the Application Core, and so Infrastructure should have a reference to the Application Core project.
Типы инфраструктурыInfrastructure types
- Типы EF Core (
DbContext
,Migration
)EF Core types (DbContext
,Migration
) - Типы реализации доступа к данным (репозитории)Data access implementation types (Repositories)
- Службы, связанные с инфраструктурой (например,
FileLogger
илиSmtpNotifier
)Infrastructure-specific services (for example,FileLogger
orSmtpNotifier
)
Уровень пользовательского интерфейсаUI Layer
Слой пользовательского интерфейса в приложении MVC ASP. NET Core выступает в качестве точки входа для приложения.The user interface layer in an ASP.NET Core MVC application is the entry point for the application. Этот проект должен ссылаться на слой ядра приложения, а его типы должны взаимодействовать с инфраструктурой строго через интерфейсы, определенные в ядре приложения.This project should reference the Application Core project, and its types should interact with infrastructure strictly through interfaces defined in Application Core. В слое пользовательского интерфейса не должны разрешаться прямое создание экземпляров для типов слоя инфраструктуры, а также их статические вызовы.No direct instantiation of or static calls to the Infrastructure layer types should be allowed in the UI layer.
Типы слоев пользовательского интерфейсаUI Layer types
- КонтроллерыControllers
- ФильтрыFilters
- ПредставленияViews
- Модели представленийViewModels
- ЗапускStartup
Класс Startup отвечает за настройку приложений и запись типов реализации в интерфейсы, обеспечивая корректную работу внедрения зависимостей во время выполнения. The Startup class is responsible for configuring the application, and for wiring up implementation types to interfaces, allowing dependency injection to work properly at run time.
Примечание
Чтобы привязать внедрение зависимостей в ConfigureServices в файле Startup.cs проекта пользовательского интерфейса, в этом проекте может потребоваться ссылка на проект инфраструктуры.In order to wire up dependency injection in ConfigureServices in the Startup.cs file of the UI project, the project may need to reference the Infrastructure project. Эту зависимость можно исключить. Проще всего это сделать с помощью настраиваемого контейнера внедрения зависимостей.This dependency can be eliminated, most easily by using a custom DI container. В рамках этого примера применяется простейший подход, при котором разрешаются ссылки из проекта пользовательского интерфейса на проект инфраструктуры.For the purposes of this sample, the simplest approach is to allow the UI project to reference the Infrastructure project.
Монолитные приложения и контейнерыMonolithic applications and containers
Вы можете создать одно монолитное веб-приложение или службу и развернуть их как контейнер.You can build a single and monolithic-deployment based Web Application or Service and deploy it as a container. В рамках приложения монолитность может не соблюдаться, однако будет реализована организация на основе нескольких библиотек, компонентов или слоев.Within the application, it might not be monolithic but organized into several libraries, components, or layers. Внешне оно будет представлять собой единый контейнер — единый процесс, единое веб-приложение или единую службу.Externally, it’s a single container like a single process, single web application, or single service.
Для управления этой моделью вы развертываете один контейнер, представляющий собой приложение.To manage this model, you deploy a single container to represent the application. Для увеличения масштаба просто добавьте дополнительные копии с подсистемой балансировки нагрузки спереди. To scale, just add additional copies with a load balancer in front. Управлять одним развертыванием в одном контейнере или виртуальной машине гораздо проще.The simplicity comes from managing a single deployment in a single container or VM.
Вы можете включить в один контейнер несколько компонентов, библиотек или внутренних слоев, как показано на рис. 5-13.You can include multiple components/libraries or internal layers within each container, as illustrated in Figure 5-13. Такой монолитный шаблон может конфликтовать с принципом контейнера: «контейнер выполняет одно дело и в одном процессе«.But, following the container principle of «a container does one thing, and does it in one process«, the monolithic pattern might be a conflict.
Недостаток этого подхода становится очевидным, когда приложение разрастается и его необходимо масштабировать.The downside of this approach comes if/when the application grows, requiring it to scale. Если масштабируется приложение целиком, все получится. If the entire application scales, it’s not really a problem. Но в большинстве случаев необходимо масштабировать всего несколько частей приложения, пока другие компоненты работают нормально.However, in most cases, a few parts of the application are the choke points requiring scaling, while other components are used less.
В примере приложения для электронной торговли, вероятнее всего, потребуется масштабирование компонента со сведениями о товарах.Using the typical eCommerce example, what you likely need to scale is the product information component. Клиенты чаще просматривают товары, чем приобретают их.Many more customers browse products than purchase them. Клиенты чаще складывают товары в корзину, чем оплачивают их.More customers use their basket than use the payment pipeline. Не так много клиентов пишут комментарии или просматривают историю покупок.Fewer customers add comments or view their purchase history. И у вас скорее всего может быть лишь несколько сотрудников в одном регионе, которые управляют содержимым и маркетинговыми кампаниями. And you likely only have a handful of employees, in a single region, that need to manage the content and marketing campaigns. При масштабировании монолитных решений весь код развертывается многократно.By scaling the monolithic design, all the code is deployed multiple times.
Помимо того, что необходимо масштабировать все компоненты, изменения в одном компоненте требуют полного повторного тестирования всего приложения и полного повторного развертывания всех его экземпляров.In addition to the «scale everything» problem, changes to a single component require complete retesting of the entire application, and a complete redeployment of all the instances.
Монолитный подход нашел широкое распространение и используется многими организациями при разработке архитектуры.The monolithic approach is common, and many organizations are developing with this architectural approach. Во многих случаях это позволяет добиться желаемых результатов, однако иногда организация сталкивается с достигнутыми ограничениями. Many are having good enough results, while others are hitting limits. Во многих организациях приложения строились по такой модели, поскольку несколько лет назад с помощью существующих инструментов и инфраструктуры слишком сложно было создавать архитектуры, ориентированные на службы (SOA), и проблем не возникало, пока приложение не начинало разрастаться.Many designed their applications in this model, because the tools and infrastructure were too difficult to build service-oriented architectures (SOA), and they didn’t see the need until the app grew. Если ваша организация столкнулась с ограничениями монолитного подхода, следующим логичным шагом может стать разбиение приложения для более эффективного использования контейнеров и микрослужб.If you find you’re hitting the limits of the monolithic approach, breaking up the app to enable it to better leverage containers and microservices may be the next logical step.
Монолитные приложения в Microsoft Azure можно развертывать с использованием выделенных виртуальных машин для каждого экземпляра. Deploying monolithic applications in Microsoft Azure can be achieved using dedicated VMs for each instance. С помощью масштабируемых наборов виртуальных машин Azure можно легко масштабировать виртуальные машины.Using Azure Virtual Machine Scale Sets, you can easily scale the VMs. Службы приложений Azure также могут выполнять монолитные приложения и легко масштабировать экземпляры, и вам не придется управлять виртуальными машинами.Azure App Services can run monolithic applications and easily scale instances without having to manage the VMs. Службы приложений Azure также могут выполнять отдельные экземпляры контейнеров Docker, упрощая развертывание.Azure App Services can run single instances of Docker containers as well, simplifying the deployment. С помощью Docker вы можете развернуть одну виртуальную машину на узле Docker и выполнять на ней несколько экземпляров.Using Docker, you can deploy a single VM as a Docker host, and run multiple instances. Для управления масштабированием можно использовать систему балансировки Azure, как показано на рис. 5-14.Using the Azure balancer, as shown in the Figure 5-14, you can manage scaling.
Развертыванием на различных узлах можно управлять с помощью традиционных методов развертывания.The deployment to the various hosts can be managed with traditional deployment techniques. Узлами Docker можно управлять с помощью вводимых вручную команд вида docker run или автоматизированно, например с помощью конвейеров непрерывной поставки (CD).The Docker hosts can be managed with commands like docker run performed manually, or through automation such as Continuous Delivery (CD) pipelines.
Развертывание монолитного приложения в контейнереMonolithic application deployed as a container
Использование контейнеров для управления развертываниями монолитных приложений имеет свои преимущества.There are benefits of using containers to manage monolithic application deployments. Масштабировать экземпляры контейнера гораздо быстрее и проще, чем развертывать дополнительные виртуальные машины. Scaling the instances of containers is far faster and easier than deploying additional VMs. Даже при использовании масштабируемых наборов виртуальных машин применяется основанный на экземплярах подход.Even when using virtual machine scale sets to scale VMs, they take time to instance. При развертывании в виде экземпляров приложения управление конфигурацией приложения осуществляется в составе виртуальной машины.When deployed as app instances, the configuration of the app is managed as part of the VM.
Развертывание обновлений в виде образов Docker выполняется гораздо быстрее и эффективнее с точки зрения использования сети.Deploying updates as Docker images is far faster and network efficient. Образы Docker обычно запускаются за считанные секунды, что позволяет ускорить выпуск.Docker Images typically start in seconds, speeding rollouts. Остановить образ Docker можно с помощью команды docker stop
, и обычно это происходит моментально.Tearing down a Docker instance is as easy as issuing a docker stop
command, typically completing in less than a second.
Так как контейнеры по своей природе являются неизменяемыми, вам не придется беспокоиться о возможности повреждения виртуальной машины, когда скрипты обновления не учитывают некоторые оставшиеся на диске конфигурации или файлы.As containers are inherently immutable by design, you never need to worry about corrupted VMs, whereas update scripts might forget to account for some specific configuration or file left on the disk.
Контейнеры Docker можно использовать для монолитного развертывания простых веб-приложений.You can use Docker containers for a monolithic deployment of simpler web applications. Это позволяет оптимизировать конвейеры непрерывной интеграции и непрерывного развертывания, а также добиться успешного развертывания в рабочей среде.This approach improves continuous integration and continuous deployment pipelines and helps achieve deployment-to-production success. Вам больше не придется гадать, почему решение, выполняющееся на вашем компьютере, не выполняется в рабочей среде. No more “It works on my machine, why does it not work in production?”
Архитектура на основе микрослужб имеет много преимуществ, но обратной стороной является повышение сложности.A microservices-based architecture has many benefits, but those benefits come at a cost of increased complexity. В некоторых случаях затраты перевешивают преимущества, и лучше прибегнуть к монолитному развертыванию приложения в одном контейнере или буквально нескольких.In some cases, the costs outweigh the benefits, so a monolithic deployment application running in a single container or in just a few containers is a better option.
Монолитное приложение может быть непросто разделить на отдельные микрослужбы.A monolithic application might not be easily decomposable into well-separated microservices. Микрослужбы должны работать независимо друг от друга для повышения отказоустойчивости приложения.Microservices should work independently of each other to provide a more resilient application. Если приложение невозможно разложить на независимые функциональные составляющие, то его разделение лишь увеличит сложность. If you can’t deliver independent feature slices of the application, separating it only adds complexity.
Приложению пока может не требоваться независимое масштабирование компонентов.An application might not yet need to scale features independently. Многие приложения, когда им требуется использовать более одного экземпляра, относительно легко клонируют весь экземпляр.Many applications, when they need to scale beyond a single instance, can do so through the relatively simple process of cloning that entire instance. Дополнительный труд по разделению приложений на отдельные службы предоставляет минимум преимуществ, тогда как масштабирование полноценных экземпляров приложения — это простое и экономичное решение.The additional work to separate the application into discrete services provides a minimal benefit when scaling full instances of the application is simple and cost-effective.
На ранних этапах развертывания приложения может отсутствовать ясное представление о том, где пролегают границы между функциональными областями. Early in the development of an application, you might not have a clear idea where the natural functional boundaries are. В процессе разработки продукта, обладающего минимальным необходимым набором возможностей, его естественное разделение на части может быть не очевидным.As you develop a minimum viable product, the natural separation might not yet have emerged. Некоторые из этих условий могут быть временными.Some of these conditions might be temporary. Вы можете сначала создать монолитное приложение, а в дальнейшем отделить некоторые компоненты для разработки и развертывания в качестве микрослужб.You might start by creating a monolithic application, and later separate some features to be developed and deployed as microservices. Другие условия могут быть неотъемлемыми особенностями приложения. Это означает, что приложение в принципе невозможно разделить на несколько микрослужб.Other conditions might be essential to the application’s problem space, meaning that the application might never be broken into multiple microservices.
Разделение приложения на множество отдельных процессов также приводит к накладным расходам.Separating an application into many discrete processes also introduces overhead. При разделении компонента на несколько процессов повышается сложность.There’s more complexity in separating features into different processes. Усложняются протоколы обмена данными.The communication protocols become more complex. Вместо вызовов методов необходимо использовать асинхронное взаимодействие между службами.Instead of method calls, you must use asynchronous communications between services. При переходе на архитектуру микрослужб необходимо добавить множество стандартных блоков, реализованных в версии приложения eShopOnContainers на основе микрослужб: обработку шины событий, отказоустойчивость и повторную отправку сообщений, итоговую согласованность и многое другое.As you move to a microservices architecture, you need to add many of the building blocks implemented in the microservices version of the eShopOnContainers application: event bus handling, message resiliency and retries, eventual consistency, and more.
Гораздо более простой пример приложения eShopOnWeb поддерживает использование одного монолитного контейнера.The much simpler eShopOnWeb reference application supports single-container monolithic container usage. Приложение включает одно веб-приложение с традиционными представлениями MVC, веб-API и Razor Pages.The application includes one web application that includes traditional MVC views, web APIs, and Razor Pages. Это приложение может запускаться из корня решения с помощью команд docker-compose build
и docker-compose up
.This application can be launched from the solution root using the docker-compose build
and docker-compose up
commands. Эта команда настраивает контейнер для веб-экземпляра с помощью Dockerfile
из корневого каталога веб-проекта и выполняет контейнер в указанном порте.This command configures a container for the web instance, using the Dockerfile
found in the web project’s root, and runs the container on a specified port. Вы можете скачать исходный код этого приложения из GitHub и запустить его в локальной системе.You can download the source for this application from GitHub and run it locally. Даже такое монолитное приложение выигрывает от развертывания в контейнерной среде.Even this monolithic application benefits from being deployed in a container environment.
Во-первых, контейнерное развертывание означает, что каждый экземпляр приложения выполняется в одной и той же среде.For one, the containerized deployment means that every instance of the application runs in the same environment. Это относится и к среде разработки, в которой проводятся начальные этапы тестирования и разработки.This approach includes the developer environment where early testing and development take place. Команда разработчиков может запускать приложение в контейнерной среде, которая аналогична рабочей.The development team can run the application in a containerized environment that matches the production environment.
Кроме того, контейнерные приложения обеспечивают более экономичное горизонтальное масштабирование.In addition, containerized applications scale out at a lower cost. Контейнерная среда позволяет эффективнее организовывать совместное использование ресурсов, чем традиционные среды виртуальных машин.Using a container environment enables greater resource sharing than traditional VM environments.
Наконец, помещая приложение в контейнеры, вы разделяете бизнес-логику и сервер хранилища.Finally, containerizing the application forces a separation between the business logic and the storage server. По мере масштабирования приложения все контейнеры будут использовать один физический носитель данных.As the application scales out, the multiple containers will all rely on a single physical storage medium. В качестве хранилища, как правило, используется сервер высокой доступности с базой данных SQL Server.This storage medium would typically be a high-availability server running a SQL Server database.
Поддержка DockerDocker support
Проект eShopOnWeb
работает в .NET.The eShopOnWeb
project runs on .NET. Поэтому его можно запускать как в контейнерах Linux, так и в контейнерах Windows.Therefore, it can run in either Linux-based or Windows-based containers. Обратите внимание на то, что для развертывания Docker необходимо использовать тот же тип узла для SQL Server.Note that for Docker deployment, you want to use the same host type for SQL Server. Контейнеры на основе Linux требуют меньше ресурсов и более предпочтительны.Linux-based containers allow a smaller footprint and are preferred.
Вы можете использовать Visual Studio 2017, чтобы добавить поддержку Docker в существующее приложение, щелкнув проект в обозревателе решений правой кнопкой мыши и выбрав Добавить > Поддержка Docker.You can use Visual Studio 2017 or later to add Docker support to an existing application by right-clicking on a project in Solution Explorer and choosing Add > Docker Support. Таким образом вы добавите необходимые файлы и внесете изменения в проект для их использования.This step adds the files required and modifies the project to use them. В текущем примере eShopOnWeb
эти файлы уже есть.The current eShopOnWeb
sample already has these files in place.
Файл docker-compose.yml
на уровне решения содержит сведения о том, какие образы необходимо создать и какие контейнеры запустить.The solution-level docker-compose.yml
file contains information about what images to build and what containers to launch. Этот файл позволяет использовать команду docker-compose
для запуска нескольких приложений одновременно.The file allows you to use the docker-compose
command to launch multiple applications at the same time. В этом случае он запускает только веб-проект.In this case, it is only launching the Web project. Вы также можете с его помощью настроить зависимости, например отдельный контейнер базы данных.You can also use it to configure dependencies, such as a separate database container.
version: '3'
services:
eshopwebmvc:
image: eshopwebmvc
build:
context: .
dockerfile: src/Web/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "5106:5106"
networks:
default:
external:
name: nat
Файл docker-compose.yml
ссылается на Dockerfile
в проекте Web
.The docker-compose.yml
file references the Dockerfile
in the Web
project. С помощью Dockerfile
можно указать, какой базовый контейнер будет использоваться и как приложение будет настроено на нем.The Dockerfile
is used to specify which base container will be used and how the application will be configured on it. Dockerfile``Web
:The Web
‘ Dockerfile
:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app
COPY *.sln .
COPY . .
WORKDIR /app/src/Web
RUN dotnet restore
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime
WORKDIR /app
COPY --from=build /app/src/Web/out ./
ENTRYPOINT ["dotnet", "Web.dll"]
Устранение неполадок с DockerTroubleshooting Docker problems
После запуска контейнерное приложение продолжает работать, пока его не остановят.Once you run the containerized application, it continues to run until you stop it. Используйте команду docker ps
, чтобы посмотреть, какие контейнеры выполняются.You can view which containers are running with the docker ps
command. Вы можете остановить выполняющийся контейнер с помощью команды docker stop
и идентификатора контейнера.You can stop a running container by using the docker stop
command and specifying the container ID.
Обратите внимание, что запущенные контейнеры Docker могут быть привязаны к портам, которые в противном случае вы могли бы использовать в среде разработки.Note that running Docker containers may be bound to ports you might otherwise try to use in your development environment. При попытке запустить или выполнить отладку приложения через порт, связанный с контейнером Docker, возникнет ошибка с сообщением о том, что сервер не может выполнить привязку к этому порту.If you try to run or debug an application using the same port as a running Docker container, you’ll get an error stating that the server can’t bind to that port. Проблемы будет решена, если вы остановите контейнер.Once again, stopping the container should resolve the issue.
Если вы хотите добавить поддержку Docker в приложение с помощью Visual Studio, убедитесь, что Docker Desktop при этом запущен.If you want to add Docker support to your application using Visual Studio, make sure Docker Desktop is running when you do so. Если при запуске мастера средство Docker Desktop не выполняется, мастер будет работать неправильно.The wizard won’t run correctly if Docker Desktop isn’t running when you start the wizard. Кроме того, мастер проверяет выбранные контейнеры, чтобы правильно реализовать поддержку Docker.In addition, the wizard examines your current container choice to add the correct Docker support. Чтобы добавить поддержку контейнеров Windows, необходимо запускать мастер при запущенном инструменте Docker Desktop с настроенными контейнерами Windows.If you want to add, support for Windows Containers, you need to run the wizard while you have Docker Desktop running with Windows Containers configured. Чтобы добавить поддержку контейнеров Linux, запускайте мастер при запущенном инструменте Docker с настроенными контейнерами Linux.If you want to add, support for Linux containers, run the wizard while you have Docker running with Linux containers configured.
Ссылки — общие архитектуры веб-приложенийReferences – Common web architectures
Что такое архитектура приложений?
Архитектура приложения — это организационный дизайн всего программного приложения, включая все подкомпоненты и внешние приложения. Существует несколько шаблонов проектирования, которые используются для определения архитектуры этого типа, и эти шаблоны помогают сообщать, как приложение завершит необходимые бизнес-процессы, как определено в системных требованиях.
Программное приложение представляет собой систему, предназначенную для автоматизации конкретных задач логически, чтобы удовлетворить набор требований. Он использует базовые операционные системы и базы данных для хранения и выполнения задач в приложении. Архитектура приложения — это проект, который определяет, как программа будет взаимодействовать с серверами и компонентами в доменах прикладных уровней.
С расширением функциональности в программном обеспечении были созданы модульные компоненты, которые специализируются на определенных областях бизнес-процессов в приложении. Архитектура определяет все компоненты в дизайне и как они будут взаимодействовать в приложении. Это определение включает все уровни приложения.
Во всех приложениях есть три основные области управления: уровень представления, бизнес-уровень и уровень доступа к данным. Каждый домен в приложении несет определенную ответственность за то, что при соединении с другими уровнями удовлетворяют основные бизнес-требования приложения.
Архитектура приложения используется в качестве плана, чтобы гарантировать, что базовые модули приложения будут поддерживать будущий рост. Рост может произойти в областях будущей функциональной совместимости, увеличения спроса на ресурсы или повышения требований к надежности. С завершенной архитектурой заинтересованные стороны понимают сложность базовых компонентов, если в будущем должны быть необходимы изменения.
С созданием современного объектно-ориентированного программирования организационный дизайн стал важным компонентом в определении того, как приложение будет функционировать. Это связано с широким использованием приложений N-Tier на большинстве предприятий. Приложения N-Tier позволяют развертывать подкомпоненты или модули на нескольких серверах внутри предприятия.
При определении архитектуры приложения также важно определить архитектуру сервера приложений. Эта архитектура сервера накладывает аппаратный дизайн, который будет способствовать развертыванию программных компонентов. Хорошие архитектуры серверов приложений должны поддерживать как горизонтальные, так и вертикальные парадигмы роста.
Архитектура прикладной службы определяет, как приложение будет использовать ключевые бизнес-компоненты для других модулей в приложении. Благодаря определению доступных интерфейсов взаимодействие между уровнями приложений лучше понимается заинтересованными сторонами в организации.
Архитектура приложений: концептуальные слои и договоренности по их использованию
Просто о NET |
created:
2/3/2017
|
published:
2/3/2017
|
updated:
3/1/2021
|
view count:
7260
Построение сложных и не очень сложных систем задача не тривиальная. Причем сложность разработки увеличивается прямо пропорционально числу разработчиков, которые в ней участвуют. При таких условиях разработки, принято придерживаться предопределённых правил, шаблонов и договоренностей, не говоря уже о паттернах проектирования, общеизвестных методологий по разработки ПО и, вообще, принципах ООП.
Пример договоренностей
Разберем для примера общеизвестный фреймворк ASP.NET MVC. Если вы работали с этой системой, то наверное обратили внимание на то, что в проекте, который создается Visual Studio по умолчанию присутствуют папки Models, Views, Controllers. Это первая договоренность, что каждый тип файла (класса) лежит в своей собственной папке.
В первых версиях фреймворка ASP.NET MVC контролеры могли лежать только в папке Controllers. Позже это ограничение было снято.
Eсли при разработки какого-либо метода контролера вы попробуете создать метод и открыть его, не создав представление (View) этого метода, то система выдаст вам сообщение об ошибке:
Обратите внимание на то, где система попыталась найти «потерянное» представление, прежде чем выдать сообщение. Такое поведение также предопределено договоренностями фреймворка. В данном случае, правило гласит, что если представление (View) не найдено в папке контролера Home, то следует ее поискать сначала в папке Shared, потом всё то же самое, но уже с другим расширением для другого движка рендеринга (при наличии подключенных нескольких движков рендеринга разметки). На самом деле договоренностей подобного рода в ASP.NET MVC очень большое количество. И тем больше вы их будете встречать, чем глубже будете погружаться в «дебри» фреймворка.
ASP.NET MVC фреймворк как и все фреймворки, во всяком случае в большинстве своем, построены на основе парадигмы «соглашения по конфигрурации» (configuration over convention).
Принцип соглашения по конфигрурации как правило, применяется в разработке фреймворков, и позволяет сократить количество требуемой конфигурации без потери гибкости.
Суть данной статьи показать, что использование упомянутой выше парадигмы применительно к коллективной разработке, может существенно ускорить (упростить) процесс разработки приложений, особенно если в разработке учавствует большое количество разработчиков. «Соглашения по конфигурации» позволяют решить вопросы, на которые зачастую тратятся драгоценные минуты, часы и даже дни и недели. Например, часто возникает вопрос, как правильно назвать создаваемый класс, свойство, метод, проект, переменную, решение (solution)? Сколько разработчиков, столько и вариантов, если не договорится заранее о правилах именования. А если в коллектив пришел новый разработчик, то как он может начать писать корректный код, не зная о правилах, по которым этот код пишется? Безусловно, существуют огромное количество вспомогательных утилит (например, StyleCop), которые упрощают задачу, но и они бывают бессильны в некоторых случаях.
Надо признать, что с каждым годом задачи для разработчиков усложняются в силу сложности задач, которые решает бизнес. Более сложные задачи требуют более комплексных подходов в их решении. Зачастую бывает недостаточно создать приложение (программу, систему), обычно требуется ее поддерживать и развивать после выпуска окончательной версии. И если в вашем коллективе существуют подобные правила и договоренности, вам будет гораздо проще найти место в коде, правильный контролер и метод. Договоренности и правила именования помогают быстрее ориентироваться в коде.
Немного истории
В качестве примера нарастания сложности, приведу эволюцию паттернов Business Logic, которые описывают, как и где дожна быть релизована бизнес-логика. Паттерны для организации бизнес-уровеня (бизнес-логика) с течением времени претерпели существенные изменения, от простого к сложному. Более того, на этом эволюция не остановилась.
Каждый из них подробно описал Martin Fowler, поэтому я не буду на них останавливаться подробно. Эволюция говорит о том, что программировать системы, которые манипулируют данными становится всё сложнее. Надо понимать, что использование паттернов проектирования для построения архитектуры сложных систем существенно упрощает дальнейшую поддержку системы (maintainability) и введение нового функционала, но при этом разработка сильно усложняется. Для упрощения этой самой разработки, я и предлагаю использовать договоренности правила, то есть «соглашения по конфигурации» но применительно к процессу написания кода.
Что говорить, если уже не только среди разработчиков, но и среди заказчиков всё чаще и чаще слышатся подобные слова и фразы: ORM, Repository, Business Layer, Abstraction и Dependency Injection, MVVM и другие.
Среди разработчиков ходят давнишние споры относительно того, следует ли использовать дополнительную «прослойку» типа ORM между базами данных и DAL. Например, на sql.ru или на habrahabr.ru частенько поднимаются темы. Лейтмотивом в подобных спорах звучит мысль: «… для сложных проектов использование ORM существенно сокращает рутину…».
Так повелось, что с некоторого времени я перестал разделять проекты на сложные и простые, взяв за основу использование ORM для проектов любой сложности. Особенно если учесть, что ORM позволяет использовать подход CodeFirst (в частности, EntityFramework).
Осмелюсь предположить, что вы уже знакомы с паттернами проектирования, и в частности, с паттернами Repository и UnitOfWork, именно на их основе я и буду говорить о договоренностях для построения уровня доступа к данным (Data Access Layer). А также предположу, что вы имеете представление о Dependency Injection.
Использование паттернов не дает гарантии, что ваш код будет написан правильно.
Первичные правила и договоренности по именованию
Собственно говоря, далее речь пойдет о договоренностях, которые были выработаны опытным путем за достаточно продолжительный срок коллективной разработки. Хочется верить, что они кому-то помогут в работе над сложными проектами. И было бы просто замечательно, если бы вы поделились в комментариях своими собственными правилами и договоренностями, которыми пользуетесь вы и ваша команда.
Не устаю повторять фразу «всё уже придумано за нас», повторю ее и в данном контексте. В мире разработки уже существуют договоренности об именовании, например от компания Microsoft или те, другой вариант в Wikipedia. За основу для своих правил я взял договоренности от Microsoft. Итак, начнем.
Правила именования пространства имен для проекто компании:
✓ Название любого проекта должно начинаться с {CompanyName}. Данное правило актуально для разработчиков компании {CompanyName}.
✓ После первого слова {CompanyName} через точку должно быть указано имя проекта.
✓ За названием проекта обязательно должна следовать название платформы.
✓ После указанной платформы части внутренней архитектуры проекта.
X Запрещается использовать знаки подчеркивания, дефисы и другие символы.
X Запрещается использовать сокращения и общеизвестные аббревиатуры
X Запрещается использовать цифры в именованиях.
X Рекомендуется избегать использования сложно составных названий в указанных частях именования
Правила именования переменных:
✓ Используйте легко читаемые имена идентификаторов. Например, свойство с именем HorizontalAlignment является более понятным, чем AlignmentHorizontal.
✓ Читабельность важнее краткости. Имя свойства CanScrollHorizontally лучше, чем ScrollableX (непрозрачными ссылка на ось x).
X Запрещается использовать знаки подчеркивания, дефисы и другие символы.
X Запрещается использовать венгерскую нотацию.
X ИЗБЕГАЙТЕ использования имен идентификаторов, конфликтующих с ключевыми словами широко используемых языков программирования.
X Не используйте аббревиатуры или сокращения как часть имени идентификатора. Например, используйте GetWindow вместо GetWin.
X Запрещается использовать акронимы, которые не являются общепринятым и даже в том случае, если они находятся, только при необходимости.
✓ Используйте семантически значимые имена вместо зарезервированных слов языка для имен типов. Например GetLength является именем лучше, чем GetInt.
✓ Используйте имя универсального типа CLR, а не имя конкретного языка, в редких случаях, когда идентификатор не имеет семантического значения за пределами своего типа. Например, преобразование в метод Int64 должен быть назван ToInt64, а не ToLong (поскольку Int64 — это имя среды CLR для C#-псевдоним long). В следующей таблице представлены некоторые базовые типы данных с помощью имен типов среды CLR (а также соответствующие имена типов для C#, Visual Basic и C++).
✓ Используйте обычные имена, таких как value или item, вместо того чтобы повторение имени типа в редких случаях, когда идентификатор не имеет семантического значения и тип параметра не имеет значения.
Примеры, которые не стоит использовать при именовании пространства имен:
{CompanyName}.ProjectForManagingContent
{CompanyName}.Project.API.V1
{CompanyName}.ProjectForManaging
{CompanyName}.ManagingSystem
{COMPANYNAME}.WEB.PORTAL
MVC.Site.Utils.{CompanyName}
{CompanyName}.Client.System
Примеры именования пространства имен и проектов:
Для примера именованя решения возмем несуществующий сайт http://project.company.ru. Проект портала на платформе ASP.NET MVC должен иметь следующие пространство имен.
Название решения (solution):
{CompanyName}.Project
Названия проектов (projects) по типу принадлежности к уровню абстракции:
{CompanyName}.Project.Contracts
{CompanyName}.Project.Models
{CompanyName}.Project.Data
{CompanyName}.Project.Globalization
{CompanyName}.Project.Utils
{CompanyName}.Project.Android
{CompanyName}.Project.MacOS
{CompanyName}.Project.UWP
{CompanyName}.Project.WebAPI
{CompanyName}.Project.WPF
Названия проектов (projects) при использовании Unit-тестирования:
{CompanyName}.Project.Contracts.Tests
{CompanyName}.Project.Models.Tests
{CompanyName}.Project.Data.Tests
{CompanyName}.Project.Globalization.Tests
{CompanyName}.Project.Utils.Tests
{CompanyName}.Project.Android.Tests
{CompanyName}.Project.MacOS.Tests
{CompanyName}.Project.UWP.Tests
{CompanyName}.Project.API.Tests
{CompanyName}.Project.WPF.Tests
Абстрактные уровни Data Access Layer
Собственно говоря, мы подошли к ключевому моменту статьи. Я буду приводить примеры применительно к платформе ASP.NET и, в часности, к проекту MVC 5, однако, примите к сведению, что ничего не мешает использовать данную концепцию в WPF-приложении или в каком-либо еще, например, JavaScript-приложения на основе Single Page Application (SPA).
Итак, в своих проектов я использую следующие уровни абстракции для уровня бизнес-логики:
Это базовые понятия для большинства проектов, но надо признаться, что были проекты, для которых приходилось добавлять уровни выше над уровнем Manager. Теперь обо всем по порядку. Давайте для пущей наглядности возьмем конкретные сущности и сделаем для них обёртку из классов для бизнес-уровня. Предположим, что у нас в проекте есть сущности Category, Post, Tag, Comment. Похоже на сущности для реализации блога? Так оно и есть.
Repository
Надеюсь, вы прочитали описание на картинке для Repository, лишь поясню, что базовые операции это: чтение из базы списка, чтение из базы одной сущности по идентификатору, вставка новой записи в базу, редактирование существующей в базе записи, удаление записи. Некоторые Repository могут иметь дополнительные методы, например, метод Clear для репозитория LogRepository. Итак, для каждой из указанных сущностей создаем свой репозиторий: CategoryRepository, PostRepository, TagRepository, CommentRepository.
Правило именования для Repository: название сущности в единственном числе перед словом Repository.
У меня есть ReadableRepositoryBase<T> класс, который реализует методы PagedList<T>() и GetById(). Таком образом, унаследовавшись от этого класса, репозиторий наследник приобретает возможность получать запись по идентификатору и коллекцию разбитую на страницы. А также если наследник от ReadableRepositoryBase<T>, который называется WritableRepositoryBase<T> и имеет методы Create, Update, Delete. Конкретную реализацию я приводить не буду, ибо это не есть цель моей статьи, но если кому-то потребуется, отпишитесь в комментариях.
Такой подход дает мне возможность наследоваться от одного или от второго абстрактного класса, реализуя ролевой доступ к сущности на этапе разработки. Итак, у нас уже есть четыре класса, которые могут управлять (CRUD) каждый своей сущностью.
Provider
Далее в иерархии уровней бизнес-логики доступа к данным идет Provider. Говоря о нем, приведу пример взаимосвязи между сущностями Tag и Post. Допустим, что метка (tag) связана с записью блога (post) в отношении «многое-ко-многим» и метки для записи блога обязательны. Так вот, получается, что при добавлении записи блога, мне придется каким-то образом обрабатывать метки (tags). Данный функционал подпадает под паттерн Unit of Work, который управляет централизовано несколькими сущностями. Таким образом, PostProvider частично реализует паттерн Unit of Work.
Правило именования для Provider: название сущности указывается в единственном числе перед словом Provider.
Провайдеры через вливание зависимостей принимают в конструктор Repository. То есть провайдеры управляют репозиториями. Таким образом, мы подошли к первому правилу Dependency Injection для уровней Data Access Layer.
Правило Dependency Injection: В конструкторы классов Provider могут вливаться как зависимости объекты Repository.
Забыл упомянуть, что в классы Repository должны вливаться DbContext (EntityFramework) или его абстрактный представитель.
Правило Dependency Injection: В классы Repository могут вливаться DbContext (EntityFramework) или абстракция на этот класс.
Manager
Следующим на очереди уровень Manager. Менеджеры служат для управления связанными сущностями (в том числе и провайдерами), но на более высоком уровне абстракции. Допустим, что мне нужно изменить видимость категории, которую я хочу скрыть. Но скрывая категорию, я должен скрыть и записи в этой категории. Решая поставленную задачу, я создам класс CategoryManager, в котором создам метод SetVisibilityForCategory. В классе PostProvider я создам метод SetVisibilityForPostsByCategoryId(int categoryId), который будет использовать класс PostRepository устанавливать свойство IsVisisble у всех записей блога принадлежащий выбранной категории. То есть, просто изменять значение одного свойства, а это обычная операция обновления (update).
Правило Dependency Injection: В классы Manager могут вливаться как зависимости объекты Provider.
Ключевым моментом в данном примере является то, что каждый из описанных уровней абстракции реализует свой собственный функционал, который подлежит расширению, если потребуется. Строится, своего рода пирамида, по управлению сущностями. От более «мелких» операций в Repository к более «крупным» в Manager. Причем «размер» операции зависит от количества сущностей, которые она затрагивает.
Controller
Говоря об ASP.NET MVC нельзя не упомянуть о контролерах, которые являются основой в фреймворке, вокруг которых и построена вся инфраструктура. В MVC-контролер (API-контроллер тоже) могут вливаться зависимости типа Repository, Provider, Manager.
Правило Dependency Injection: В классы Manager могут также вливаться как зависимости объекты Repository.
Хочу заметить, что в большестве случаев, операции, которые вы будете вызывать из контролера должны находитcя на уровне Provider и Manager, потому что эти два уровня совместно реализуют Unit of Work, а операции из Repository зачастую не участвуют в бизнес-процессах «большого» приложения.
Правило именования для Controller: название сущности указывается во множественном числе перед словом Controller.
Service
Стоит также упомянуть, что обычно в приложениях существуют бизнес-процессы, которые не привязаны к конкретной сущности. Например, при формировании заказа на покупку товара, требуется отправить сообщение менеджеру или уведомление в бухгалтерию по электронной почте. Для реализации такого функционала я создаю EmailService, реализующий отправку сообщения по электронной почте.
Правило Dependency Injection: В классы Repository, Provider, Manager могут вливаться объекты Service.
Таким образом, для каждого из перечисленных уровней (Repository, Provider, Manager) может возникнуть потребность инъекции какого либо сервиса. Хорошим примером может служит LogService. Протоколирование (logging) уместно на любом из уровней логики. В Repository запись в журнал о том, что запись создана. Provider может записать данные о добавленнии новых меток при добавлении записи в блог. Manager может записать информацию о том, что при сокрытии категории, также скрыты и все записи в этой категории. В общем, всё хорошо в меру.
Заключение
Представленная модель бизнес-логики и иерархии зависимостей автоматически проверяется при использовании Dependency Injection контейнера, потому что при наличии цикличности в зависимостях, сразу будет выдана ошибка (крайнем случае на этапе выполнения).
Стоит также отметить, что три уровня абстракции дают широкие возможности для выбора места реализации методов бизнес-процессов, так сказать, распределенная бизнес-логика. А вот решение на каком уровне реализовывать конкретный бизнес-процесс вам уже предстоит решить самостоятельно, ибо всё зависит от задач, которые вы перед собой ставите. Но в крайнем случае можно спросить и у архитектора системы. 🙂
Видео по этой статье доступно на канале в youtube
Как реализовать чистую архитектуру на Android? – Devcolibri
Что вы найдёте в этой статье?
В 2016 году я начал изучать Java, а в начале 2017 года — Android. С самого начала я уже знал, что существует понятие архитектуры приложений, но не знал, как это применить в своём коде. Я находил много разных гайдов, но понятнее от этого мне не становилось.
Эта статья — именно та, которую мне хотелось бы прочитать в начале своего пути.
Важность архитектуры приложений
Многие компании проводят технические тесты для кандидатов, которые проходят отбор. Тесты могут отличаться, но есть то, что их объединяет. Все они требуют понимания и умения применения хорошей программной архитектуры.
Хорошая программная архитектура позволяет легко понимать, разрабатывать, поддерживать и внедрять систему [Книга «Чистая архитектура», глава 15]
Цель этой статьи — научить того, кто никогда не использовал архитектуру для разработки приложений на Android, делать это. Для этого мы рассмотрим практический пример приложения, при создании которого реализуем наименее гибкое решение и более оптимальное решение с использованием архитектуры.
Пример
Элементы в RecyclerView:
- Мы будем получать данные из API и показывать результаты пользователю.
- Результатом будет список пива с названием, описанием, изображением и содержанием алкоголя для каждого.
- Пиво должно быть упорядочено по градусу крепости.
Для решения этой задачи:
- Мы должны получить данные из API.
- Упорядочить элементы от самого низкого до самого высокого градуса крепости.
- Если содержание алкоголя меньше 5%, будет нарисован зелёный кружок, если оно находится между 5% и 8% — кружок будет оранжевым, а выше 8% — красный кружок.
- Наконец, мы должны показать список элементов.
Какое наименее гибкое решение?
Наименее гибким решением является создание одного класса, который будет выполнять четыре предыдущих пункта. Это то решение, которое любой из нас делал бы, если бы не знал, что такое архитектура приложений.
Результат для пользователя будет приемлемым: он увидит упорядоченный список на экране. Но если нам понадобится масштабировать эту систему, мы поймём, что структуру нелегко понять, разрабатывать дальше, поддерживать и внедрять.
Как понять архитектуру приложений в Android?
Я приведу очень простой пример. Представьте себе автомобильный завод с пятью зонами:
- Первая зона создает шасси.
- Вторая зона соединяет механические части.
- Третья зона собирает электронную схему.
- Четвертая область — покрасочная.
- И последняя область добавляет эстетические детали.
Это означает, что у каждой зоны есть своя ответственность, и они работают в цепочке с первой зоны по пятую для достижения результата.
У такой системы есть определённое преимущество. Если автомобиль выдаст ошибку после того, как он будет закончен, то в зависимости от его поведения мы будем знать, какой отдел должен её исправить, не беспокоя других.
Если мы захотим добавить больше эстетических деталей, мы обратимся непосредственно к пятому отделу. А если мы захотим изменить цвет, мы обратимся к четвёртому. И если мы изменим шасси, это никак не изменит способ работы покрасочной области. То есть мы можем точечно модифицировать нашу машину, не беспокоя при этом всю фабрику.
Кроме того, если со временем мы захотим открыть вторую фабрику для создания новой модели автомобиля, будет легче разделить рабочие зоны.
Применение архитектуры в Android
Мы собираемся добиться того, чтобы не было класса, который выполнял бы всю работу в одиночку: запрос данных от API, их сортировка и отображение. Всё это будет распределено по нескольким областям, которые называются слоями.
Что это за слои?
Для этого примера мы собираемся создать чистую архитектуру, которая состоит из трёх уровней, которые в свою очередь будут подразделяться на пять:
- Уровень представления.
- Уровень бизнес-логики.
- И уровень данных.
1. Уровень представления
Уровень представления — это пользовательский уровень, графический интерфейс, который фиксирует события пользователя и показывает ему результаты. Он также выполняет проверку того, что во введённых пользователем данных нет ошибок форматирования, а отображаемые данные отображаются корректно.
В нашем примере эти операции разделены между уровнем пользовательского интерфейса и уровнем ViewModel:
- Уровень пользовательского интерфейса содержит Activity и фрагменты, фиксирующие пользовательские события и отображающие данные.
- Уровень ViewModel форматирует данные так, что пользовательский интерфейс показывает их определённым образом.
Вместо использования ViewModel мы можем использовать другой слой, который выполняет эту функцию, просто важно понять обязанности каждого слоя.
В нашем примере слой пользовательского интерфейса отображает список пива, а слой ViewModel сообщает цвет, который вы должны использовать в зависимости от алкогольного диапазона.
2. Уровень бизнес-логики
На этом уровне находятся все бизнес-требования, которым должно соответствовать приложение. Для этого здесь выполняются необходимые операции. В нашем примере это сортировка сортов пива от самой низкой до самой высокой крепости.
3. Уровень данных
На этом уровне находятся данные и способ доступа к ним.
Эти операции разделены между уровнем репозитория и уровнем источника данных:
- Уровень репозитория реализует логику доступа к данным. Его ответственность заключается в том, чтобы получить данные. Необходимо проверить, где искать их в определённый момент. Например, вы можете сначала проверить локальную базу данных и, если там данных нет, сделать запрос к API и сохранить данные в базу данных. То есть он определяет способ доступа к данным. В нашем примере он запрашивает данные о пиве непосредственно у уровня, который взаимодействует с API.
- Уровень источника данных отвечает непосредственно за получение данных. В нашем примере он реализует логику доступа к API для получения данных о пиве.
Как слои взаимодействуют?
Давайте посмотрим на теоретический и практический подходы взаимодействия.
В теории:
Каждый слой должен общаться только со своими непосредственными соседями. В этом случае, если мы посмотрим на схему архитектуры программного обеспечения:
- Пользовательский интерфейс может общаться только с ViewModel.
- ViewModel может общаться только с уровнем бизнес-логики.
- Уровень бизнес-логики может общаться только с уровнем репозитория.
- И репозиторий может общаться только с источником данных.
На практике:
Структура пакетов в IDE Android Studio при чистой архитектуре:
У нас есть структура пакетов, в которой создаются классы, каждый из которых имеет свою зону ответственности.
Заключительные замечания по архитектуре приложений
Мы увидели, что каждый уровень архитектуры программного обеспечения имеет свою зону ответственности и все они связаны между собой.
Важно подчеркнуть, что ни разу не говорилось об используемых библиотеках или языках программирования, поскольку архитектура ориентирована на правильное структурирование кода, чтобы он был масштабируемым. Со временем библиотеки меняются, но принципы архитектуры сохраняются.
Дальше рекомендуется почитать о внедрении зависимостей, чтобы избежать создания экземпляров объектов непосредственно в классах архитектуры и, таким образом, иметь возможность выполнить модульное тестирование с помощью Mockito и JUnit.
Я делюсь репозиторием, где вы можете увидеть:
- Пример чистой архитектуры на Android с Kotlin.
- Использование LiveData для связи пользовательского интерфейса с ViewModel.
- Использование корутин.
- Kodein для внедрения зависимостей.
- JUnit и Mockito для тестирования бизнес-логики.
Перевод статьи «How to implement a Clean Architecture on Android»
Что такое архитектура приложения?
Архитектура приложения описывает шаблоны и методы, используемые для разработки и создания приложения. Архитектура дает вам план действий и передовые практики, которым следует следовать при создании приложения, так что вы получите хорошо структурированное приложение.
Шаблоны проектирования программного обеспечения могут помочь вам создать приложение. Шаблон описывает повторяемое решение проблемы.
Шаблоны можно связывать вместе для создания более общих архитектур приложений.Вместо того, чтобы полностью создавать архитектуру самостоятельно, вы можете использовать существующие шаблоны проектирования, которые также гарантируют, что все будет работать должным образом.
В рамках архитектуры приложения будут существовать как внешние, так и внутренние службы. Внешняя разработка связана с пользовательским интерфейсом приложения, в то время как внутренняя разработка фокусируется на предоставлении доступа к данным, службам и другим существующим системам, которые обеспечивают работу приложения.
Архитектура — это отправная точка или дорожная карта для создания приложения, но вам нужно будет сделать выбор реализации, не отраженный в архитектуре.Например, первым шагом является выбор языка программирования, на котором будет написано приложение.
Для разработки программного обеспечения используется множество языков программирования. Определенные языки могут использоваться для создания определенных типов приложений, таких как Swift для мобильных приложений или JavaScript для интерфейсной разработки.
JavaScript, используемый с HTML и CSS, в настоящее время является одним из наиболее популярных языков программирования для разработки веб-приложений.
Среди других популярных языков программирования — Ruby, Python, Swift, TypeScript, Java, PHP и SQL.Язык, используемый при создании приложения, будет зависеть от типа приложения, доступных ресурсов разработки и требований.
Исторически приложения писались как единый блок кода, в котором все компоненты совместно используют одни и те же ресурсы и пространство памяти. Этот стиль архитектуры называют монолитом.
Современные архитектуры приложений чаще всего слабо связаны, используя микросервисы и интерфейсы прикладного программирования (API) для подключения сервисов, которые обеспечивают основу для облачных приложений.
Разработка с использованием собственных облачных сред — это способ ускорить создание новых приложений, оптимизировать существующие и обеспечить единообразную разработку и автоматизированное управление в частных, общедоступных и гибридных облаках.
Выбор архитектуры приложения
При принятии решения, какую архитектуру приложения использовать для нового приложения, или при оценке вашей текущей архитектуры, начните с определения ваших стратегических целей.
Затем вы можете спроектировать архитектуру, которая поддерживает ваши цели, вместо того, чтобы сначала выбирать архитектуру и пытаться приспособить приложение к этой структуре.
Подумайте, как часто вы хотите выпускать обновления для удовлетворения потребностей клиентов или эксплуатации, а также какие функции требуются для достижения бизнес-целей или потребностей разработки.
Способность быстро предоставлять клиентам новые услуги и новые функции — одно из ключевых конкурентных преимуществ, которые может предложить компания. А более быстрая разработка позволяет предприятиям чаще выпускать новые функции и выпускать обновления, как только обнаруживается уязвимость.
Существует много различных типов архитектур приложений, но наиболее заметными сегодня, основанными на взаимосвязях между службами, являются: монолиты и многоуровневая архитектура (тесно связанные), микросервисы (разделенные), а также архитектура, управляемая событиями, и службы. ориентированная архитектура (слабосвязанная).
Многоуровневая или многоуровневая архитектура
Многоуровневая или многоуровневая архитектура — это традиционная архитектура, которая часто используется для создания локальных и корпоративных приложений и часто ассоциируется с устаревшими приложениями.
В многоуровневой архитектуре существует несколько уровней или уровней, часто 3, но может быть и больше, составляющих приложение, каждый со своей ответственностью.
Уровни помогают управлять зависимостями и выполнять логические функции. В многоуровневой архитектуре слои расположены горизонтально, поэтому они могут вызывать только слой ниже.
Слой может либо вызывать только слой, находящийся непосредственно под ним, либо он может вызывать любой из нижележащих слоев.
Монолитная архитектура
Монолит, другой тип архитектуры, связанный с унаследованными системами, представляет собой единый стек приложений, который содержит все функции в рамках этого 1 приложения. Это тесно связано как во взаимодействии между сервисами, так и в том, как они разрабатываются и доставляются.
Обновление или масштабирование одного аспекта монолитного приложения имеет последствия для всего приложения и его базовой инфраструктуры.
Одно изменение кода приложения требует повторного выпуска всего приложения. Из-за этого обновления и новые выпуски обычно могут происходить только один или два раза в год и могут включать только общее обслуживание вместо новых функций.
Напротив, более современные архитектуры пытаются разбить услуги по функциональности или бизнес-возможностям, чтобы обеспечить большую гибкость.
Архитектура микросервисов
Микросервисы — это одновременно архитектура и подход к написанию программного обеспечения.С помощью микросервисов приложения разбиваются на мельчайшие компоненты, независимые друг от друга. Каждый из этих компонентов или процессов представляет собой микросервис.
Микросервисы распределены и слабо связаны, поэтому они не влияют друг на друга. Это дает преимущества как с точки зрения динамической масштабируемости, так и с точки зрения отказоустойчивости: отдельные службы можно масштабировать по мере необходимости, не требуя тяжелой инфраструктуры, или можно переключаться при отказе, не влияя на другие службы.
Целью использования микросервисной архитектуры является более быстрое предоставление качественного программного обеспечения.Вы можете одновременно разрабатывать несколько микросервисов. А поскольку службы развертываются независимо, вам не нужно перестраивать или повторно развертывать все приложение после внесения изменений.
Это приводит к тому, что больше разработчиков работают над своими отдельными службами одновременно, вместо того, чтобы обновлять все приложение, в результате чего на разработку тратится меньше времени и появляется возможность чаще выпускать новые функции.
Вместе с API и командами DevOps контейнерные микросервисы являются основой для облачных приложений.
Архитектура, управляемая событиями
В системе, управляемой событиями, захват, передача, обработка и сохранение событий являются основной структурой решения. Это отличается от традиционной модели, основанной на запросах.
Событие — это любое существенное событие или изменение состояния аппаратного или программного обеспечения системы. Источником события может быть внутренний или внешний вход.
Архитектура, управляемая событиями, обеспечивает минимальную взаимосвязь, что делает ее хорошим вариантом для современных распределенных архитектур приложений.
Архитектура, управляемая событиями, состоит из производителей и потребителей событий. Производитель событий обнаруживает или воспринимает событие и представляет событие как сообщение. Он не знает потребителя события или результата события.
После обнаружения события оно передается от производителя событий потребителям событий по каналам событий, где платформа обработки событий обрабатывает событие асинхронно.
Архитектура, управляемая событиями, может быть основана либо на модели публикации / подмодели, либо на модели потока событий.
Модель публикации / подписки основана на подписках на поток событий. В этой модели после того, как событие происходит или публикуется, оно отправляется подписчикам, которых необходимо проинформировать.
Это отличается от модели потоковой передачи событий, в которой потребители событий не подписываются на поток событий. Вместо этого они могут читать из любой части потока и могут присоединиться к потоку в любое время.
События фиксируются по мере их возникновения из источников событий, таких как устройства Интернета вещей (IoT), приложения и сети, что позволяет производителям событий и потребителям событий обмениваться информацией о состоянии и ответах в режиме реального времени.
Сервис-ориентированная архитектура
Сервисно-ориентированная архитектура (SOA) — это устоявшийся стиль разработки программного обеспечения, который похож на стиль архитектуры микросервисов.
SOA структурирует приложения в дискретные повторно используемые сервисы, которые обмениваются данными через служебную шину предприятия (ESB).
В этой архитектуре отдельные службы, каждая из которых организована вокруг определенного бизнес-процесса, придерживаются протокола связи (например, SOAP, ActiveMQ или Apache Thrift) и проявляют себя через платформу ESB.В совокупности этот набор услуг, интегрированный через ESB, используется интерфейсным приложением для обеспечения ценности для бизнеса или клиента.
Как Red Hat может помочь в разработке приложений
Решения Red Hat помогут вам повысить гибкость бизнеса за счет разделения ваших монолитных приложений на микросервисы, управления ими, их оркестровки и обработки данных, которые они создают, чтобы помочь вашим командам предоставлять качественные решения для вашего бизнеса. клиенты быстрее.
Создавая новые бизнес-приложения, вы можете делать это, думая о будущем, с самого начала создавая гибкие и легко масштабируемые облачные приложения и интегрируя их с остальной частью вашего бизнеса.
Посмотрите эту серию веб-семинаров, чтобы узнать мнение экспертов о том, как создавать, запускать, развертывать и модернизировать приложения с помощью платформы данных корпоративного уровня на Red Hat® OpenShift®.
Нет необходимости полностью менять существующие системы, чтобы получить значимые преимущества. Благодаря открытому исходному коду, открытым стандартам и нашему многолетнему опыту мы можем помочь вам найти решение на основе микросервисов, подходящее для вашей организации.
Благодаря нашему портфолио с открытым исходным кодом, включая Red Hat® Enterprise Linux®, Red Hat OpenShift и Red Hat Middleware, мы считаем, что Red Hat имеет уникальные возможности для партнерства с компаниями, которым необходимо измениться, чтобы конкурировать на быстро меняющихся рынках, основанных на программном обеспечении. .
Что такое архитектура приложения? — Определение с сайта WhatIs.com
Архитектура приложения — это карта того, как программные приложения организации собираются как часть всеобъемлющей корпоративной архитектуры и как эти приложения взаимодействуют друг с другом для удовлетворения требований бизнеса или пользователей. Архитектура приложения помогает обеспечить масштабируемость и надежность приложений, а также помогает предприятиям выявлять пробелы в функциональности.
В общем, архитектура приложения определяет, как приложения взаимодействуют с промежуточным программным обеспечением, базами данных и другими приложениями.Архитектура приложений обычно следует принципам проектирования программного обеспечения, которые общеприняты среди их приверженцев, но могут не иметь формальных отраслевых стандартов.
Одной из наиболее заметных архитектур приложений является сервис-ориентированная архитектура (SOA), которая возникла в 1990-х годах, когда операции интеграции приложений и совместного использования компонентов стали связаны с пулами ресурсов хостинга и распределенными базами данных. За последние 20 лет SOA превратилась в несколько других архитектур, в первую очередь в микросервисные архитектуры.
Технологии и отраслевые стандарты
Крупные издатели программного обеспечения, в том числе Microsoft, обычно издают рекомендации по архитектуре приложений, чтобы помочь сторонним разработчикам создавать приложения для своей платформы. В этом случае Microsoft предлагает Руководство по архитектуре приложений Azure, чтобы помочь разработчикам создавать облачные приложения для платформы общедоступных облачных вычислений Microsoft Azure. Он предоставляет ряд облачных сервисов, в том числе для вычислений, аналитики, хранения и работы в сети.Пользователи могут выбирать из этих сервисов для разработки и масштабирования новых приложений или запуска существующих приложений в общедоступном облаке.
Кроме того, были созданы консорциумы для определения архитектурных стандартов для конкретных отраслей и технологий. Например, TM Forum, торговая группа для поставщиков услуг связи, создала платформу приложений (TAM) для предоставления архитектуры приложений для использования поставщиками услуг и другими лицами в сфере связи и развлечений.Аналогичным образом, Object Management Group (OMG), консорциум стандартов, состоящий из поставщиков, конечных пользователей, академических институтов и государственных учреждений, управляет несколькими рабочими группами по разработке стандартов интеграции предприятия. Стандарты моделирования OMG включают унифицированный язык моделирования (UML) и архитектуру, управляемую моделями.
Преимущества архитектуры приложения
В целом, архитектура приложения помогает ИТ-специалистам и специалистам по бизнес-планированию работать вместе, обеспечивая наличие правильных технических решений для достижения бизнес-целей.В частности, архитектура приложения:
- Снижает затраты за счет выявления избыточностей, например использования двух разрозненных баз данных, которые можно заменить одной;
- Повышает эффективность за счет выявления пробелов, например, когда одно приложение не может работать с другим или когда мобильные пользователи не могут получить доступ к необходимым услугам;
- Делает корпоративную платформу доступной и привлекательной для сторонних разработчиков;
- Производит совместимые модульные системы, которые проще использовать и поддерживать;
- Помогает архитектору увидеть общую картину и сопоставить ее с целями организации.
Как выбрать правильную архитектуру программного обеспечения: 5 основных шаблонов
Сколько сюжетов в голливудских фильмах? Некоторые критики говорят, что их всего пять. Сколько способов вы можете структурировать программу? Сейчас большинство программ используют одну из пяти архитектур.
Марк Ричардс — архитектор программного обеспечения из Бостона, который более 30 лет размышлял о том, как данные должны проходить через программное обеспечение.Его новая (бесплатная) книга Software Architecture Patterns, фокусируется на пяти архитектурах, которые обычно используются для организации программных систем. Лучший способ спланировать новые программы — изучить их и понять их сильные и слабые стороны.
В этой статье я выделил пять архитектур, сделав краткий справочник сильных и слабых сторон, а также оптимальных вариантов использования. Помните, что вы можете использовать несколько шаблонов в одной системе, чтобы оптимизировать каждый раздел кода с лучшей архитектурой.Хотя они называют это информатикой, часто это искусство.
Многоуровневая (n-уровневая) архитектура
Этот подход, вероятно, является наиболее распространенным, поскольку он обычно строится на базе данных, и многие бизнес-приложения, естественно, позволяют хранить информацию в таблицах.
Это что-то вроде самоисполняющегося пророчества. Многие из крупнейших и лучших программных фреймворков, таких как Java EE, Drupal и Express, были созданы с учетом этой структуры, поэтому многие приложения, созданные с их помощью, естественно, имеют многоуровневую архитектуру.
Код устроен так, что данные поступают на верхний уровень и проходят вниз по каждому слою, пока не достигнут нижнего, которым обычно является база данных. Попутно каждый уровень выполняет определенную задачу, например, проверяет данные на согласованность или переформатирует значения, чтобы они оставались согласованными. Разным программистам свойственно работать независимо на разных уровнях.
Изображение предоставлено: Izhaki
Структура модель-представление-контроллер (MVC), которая представляет собой стандартный подход к разработке программного обеспечения, предлагаемый большинством популярных веб-фреймворков, явно представляет собой многоуровневую архитектуру.Чуть выше базы данных находится уровень модели, который часто содержит бизнес-логику и информацию о типах данных в базе данных. Вверху находится уровень представления, который часто представляет собой CSS, JavaScript и HTML с динамическим встроенным кодом. В середине у вас есть контроллер, который имеет различные правила и методы для преобразования данных, перемещающихся между представлением и моделью.
Преимущество многоуровневой архитектуры заключается в том, что разделение проблем означает, что каждый уровень может сосредоточиться исключительно на своей роли.Это делает это:
Правильная многоуровневая архитектура будет иметь изолированные слои, на которые не влияют определенные изменения в других уровнях, что упрощает рефакторинг. Эта архитектура также может содержать дополнительные открытые уровни, такие как уровень служб, которые можно использовать для доступа к общим службам только на бизнес-уровне, но их также можно обойти из-за скорости.
Разделение задач и определение отдельных слоев — самая большая проблема для архитектора. Когда требования соответствуют шаблону, слои можно будет легко разделить и назначить разным программистам.
Предостережения:
Исходный код может превратиться в «большой комок грязи», если он неорганизован и у модулей нет четких ролей или взаимосвязей.
Код может работать медленно из-за того, что некоторые разработчики называют «антипаттерном воронки». Большая часть кода может быть посвящена передаче данных через слои без использования какой-либо логики.
Изоляция уровней, которая является важной целью для архитектуры, также может затруднить понимание архитектуры без понимания каждого модуля.
Кодеры могут пропускать прошлые уровни, чтобы создать тесную связь и создать логический беспорядок, полный сложных взаимозависимостей.
Монолитное развертывание часто неизбежно, что означает, что небольшие изменения могут потребовать полного повторного развертывания приложения.
Подходит для:
Новые приложения, которые необходимо создавать быстро
Корпоративные или бизнес-приложения, которые должны отражать традиционные ИТ-отделы и процессы
Команды с неопытными разработчиками, которые этого не делают понимать другие архитектуры еще
Приложения, требующие строгих стандартов ремонтопригодности и тестируемости
Архитектура, управляемая событиями
Многие программы проводят большую часть своего времени в ожидании чего-либо.Это особенно верно для компьютеров, которые работают напрямую с людьми, но также распространено в таких областях, как сети. Иногда данные требуют обработки, а иногда нет.
Управляемая событиями архитектура помогает управлять этим, создавая центральный блок, который принимает все данные и затем делегирует их отдельным модулям, которые обрабатывают конкретный тип. Говорят, что эта передача обслуживания генерирует «событие», и она делегируется коду, присвоенному этому типу.
Программирование веб-страницы с помощью JavaScript включает в себя написание небольших модулей, которые реагируют на такие события, как щелчки мыши или нажатия клавиш.Сам браузер организует весь ввод и следит за тем, чтобы только правильный код видел нужные события. В браузере часто встречаются различные типы событий, но модули взаимодействуют только с событиями, которые их касаются. Это сильно отличается от многоуровневой архитектуры, где все данные обычно проходят через все уровни. В целом, архитектуры, управляемые событиями:
Легко адаптируются к сложной, часто хаотической среде
Легко масштабируются
Легко расширяются при появлении новых типов событий
Предостережения:
Обработку ошибок может быть сложно структурировать, особенно когда несколько модулей должны обрабатывать одни и те же события.
Когда модули выходят из строя, центральный блок должен иметь план резервного копирования.
Накладные расходы на обмен сообщениями могут снизить скорость обработки, особенно когда центральный блок должен буферизовать сообщения, поступающие пачками.
Разработка общесистемной структуры данных для событий может быть сложной, если события имеют совершенно разные потребности.
Поддержание механизма согласованности на основе транзакций затруднено из-за того, что модули настолько разделены и независимы.
Определение того, что принадлежит микроядру, часто является искусством. Он должен содержать часто используемый код.
Плагины должны включать достаточное количество кода подтверждения связи, чтобы микроядро знало, что плагин установлен и готов к работе.
Изменение микроядра может быть очень трудным или даже невозможным, если от него зависит несколько подключаемых модулей. Единственное решение — также модифицировать плагины.
Выбрать правильную степень детализации для функций ядра сложно заранее, но почти невозможно изменить позже в игре.
Инструменты, используемые широким кругом людей
Приложения с четким разделением между базовыми процедурами и правилами более высокого порядка
Приложения с фиксированным набором основных процедур и динамический набор правил, который необходимо часто обновлять
Сервисы должны быть в значительной степени независимыми, иначе взаимодействие может привести к несбалансированности облака.
Не во всех приложениях есть задачи, которые нельзя легко разделить на независимые блоки.
Производительность может снизиться, если задачи распределены между разными микросервисами. Затраты на связь могут быть значительными.
Слишком большое количество микросервисов может сбить с толку пользователей, поскольку части веб-страницы появляются намного позже других.
Веб-сайты с небольшими компонентами
Корпоративные центры обработки данных с четко определенными границами
Быстро развивающиеся новые предприятия и веб-приложения
Разрозненные группы разработчиков , часто по всему миру
Поддержка транзакций сложнее с базами данных RAM.
Создание достаточной нагрузки для тестирования системы может быть сложной задачей, но отдельные узлы можно тестировать независимо.
Трудно развить навыки кэширования данных для повышения скорости без повреждения нескольких копий.
Данные большого объема, такие как потоки кликов и журналы пользователей
Низкие данные, которые могут быть потеряны время от времени без больших последствий — другими словами, не банковские транзакции
Социальные сети
- Выбор монолитной архитектуры
- Выбор микросервисной архитектуры
- Начиная с монолитной архитектуры, а затем масштабируйтесь до микросервисной архитектуры.
- MySQL
- Microsoft SQL Server
- PostgreSQL
- MariaDB
- MongoDB
- Редис
- Кассандра
- HBASE
- Для взаимодействия с внутренним сервером в режиме реального времени, например с приложением для обмена сообщениями или приложением для потоковой передачи аудио-видео, например Spotify, Netflix и т. Д.
- Постоянное соединение между клиентом и сервером и неблокирующая технология на сервере.
- Читать 3 минуты
Compute относится к модели размещения вычислительных ресурсов, на которых работают ваши приложения. Дополнительные сведения см. В разделе Выбор вычислительной службы.
Хранилища данных включают базы данных, но также хранилище для очередей сообщений, кешей, журналов и всего остального, что приложение может сохранять в хранилище. Для получения дополнительной информации см. Выбор хранилища данных.
Обмен сообщениями технологии позволяют передавать асинхронные сообщения между компонентами системы.Дополнительные сведения см. В разделе Выбор службы обмена сообщениями.
- Тестирование может быть сложным, если модули могут влиять друг на друга.Хотя отдельные модули можно тестировать независимо, взаимодействие между ними можно тестировать только в полностью функционирующей системе.
Подходит для:
Архитектура микроядра
Многие приложения имеют базовый набор операций, которые снова и снова используются в различных шаблонах, которые зависят от данных и поставленной задачи.Популярный инструмент разработки Eclipse, например, открывает файлы, аннотирует их, редактирует их и запускает фоновые процессоры. Инструмент известен тем, что выполняет все эти задания с кодом Java, а затем, когда нажимается кнопка, компилирует код и запускает его.
В этом случае основные процедуры для отображения файла и его редактирования являются частью микроядра. Компилятор Java — это просто дополнительная часть, которая прикреплена для поддержки основных функций микроядра. Другие программисты расширили Eclipse для разработки кода для других языков с помощью других компиляторов.Многие даже не используют компилятор Java, но все они используют одни и те же базовые процедуры для редактирования и аннотирования файлов.
Дополнительные функции, которые накладываются друг на друга, часто называют плагинами. Многие называют этот расширяемый подход архитектурой подключаемых модулей.
Ричардс любит объяснять это на примере из страхового бизнеса: «Обработка требований обязательно сложна, но реальные шаги — нет. Все правила усложняют его ».
Решение состоит в том, чтобы перенести некоторые базовые задачи, такие как запрос имени или проверка оплаты, в микроядро.Затем различные бизнес-подразделения могут писать плагины для различных типов заявок, связывая правила вместе с вызовами основных функций в ядре.
Предостережения:
Подходит для:
Архитектура микросервисов
Программное обеспечение может быть похоже на слоненка: это мило и весело, когда оно маленькое, но когда оно становится большим, им трудно управлять, и его трудно изменить .Архитектура микросервисов предназначена для того, чтобы помочь разработчикам не допустить, чтобы их дети вырастали громоздкими, монолитными и негибкими. Вместо создания одной большой программы цель состоит в том, чтобы создать несколько разных крошечных программ, а затем создавать новую маленькую программу каждый раз, когда кто-то хочет добавить новую функцию. Представьте стадо морских свинок.
через GIPHY
«Если вы войдете в свой iPad и посмотрите пользовательский интерфейс Netflix, все элементы этого интерфейса поступят из отдельной службы», — отмечает Ричардс.Список избранных, рейтинги, которые вы даете отдельным фильмам, и бухгалтерская информация предоставляются отдельными службами отдельными пакетами. Это как если бы Netflix — это созвездие из десятков небольших веб-сайтов, которые просто представляют собой одну услугу.
Этот подход аналогичен подходу, управляемому событиями, и подходу с использованием микроядра, но он используется в основном, когда различные задачи легко разделяются. Во многих случаях разные задачи могут требовать разного объема обработки и могут различаться в использовании.Серверы, доставляющие контент Netflix, загружаются намного сильнее в пятницу и субботу вечером, поэтому они должны быть готовы к расширению. С другой стороны, серверы, отслеживающие возврат DVD, выполняют основную часть своей работы в течение недели, сразу после того, как почтовое отделение доставит дневную почту. Реализуя их как отдельные сервисы, облако Netflix может масштабировать их вверх и вниз независимо по мере изменения спроса.
Предостережения:
Подходит для:
Космическая архитектура
Многие веб-сайты построены на базе базы данных, и они функционируют хорошо, пока база данных способна не отставать от нагрузки.Но когда использование достигает пика, и база данных не справляется с постоянной проблемой записи журнала транзакций, весь веб-сайт выходит из строя.
Архитектура, основанная на пространстве, предназначена для предотвращения функционального коллапса при высокой нагрузке за счет разделения обработки и хранения между несколькими серверами. Данные распределяются по узлам точно так же, как и ответственность за обслуживание вызовов. Некоторые архитекторы используют более аморфный термин «облачная архитектура». Имя «на основе пространства» относится к «пространству кортежей» пользователей, которое разделено для разделения работы между узлами.«Это все объекты в памяти», — говорит Ричардс. «Космическая архитектура поддерживает вещи, которые имеют непредсказуемые всплески, за счет исключения базы данных».
Хранение информации в ОЗУ значительно ускоряет выполнение многих задач, а распределение хранилища вместе с обработкой может упростить многие основные задачи. Но распределенная архитектура может усложнить некоторые виды анализа. Вычисления, которые должны быть распределены по всему набору данных — например, определение среднего значения или выполнение статистического анализа — должны быть разделены на подзадачи, распределены по всем узлам, а затем агрегированы, когда это будет выполнено.
Предостережения:
Подходит для:
Это большая пятерка Ричардса.Они могут быть именно тем, что вам нужно. А если это не так, правильным решением может быть сочетание двух. А может, даже три. Обязательно скачайте его книгу бесплатно; он содержит намного больше деталей. Если вы можете придумать что-то еще, дайте нам знать в комментариях.
Изображение предоставлено: Moose Winans
Продолжайте учиться
Как разработать веб-приложение: архитектура программного обеспечения 101
Когда использовать монолитную архитектуру
Монолитные приложения лучше всего подходят для случаев использования, когда требования довольно просты, ожидается, что приложение будет обрабатывать ограниченный объем трафика.Одним из примеров этого является приложение для внутреннего расчета налогов организации или аналогичный открытый общедоступный инструмент.
Это сценарии использования, в которых компания уверена, что не будет экспоненциального роста пользовательской базы и трафика с течением времени.
Также есть случаи, когда группы разработчиков решают начать с монолитной архитектуры, а затем перейти к распределенной архитектуре микросервисов.
Когда использовать микросервисную архитектуру
Архитектура микросервисов лучше всего подходит для сложных случаев использования и для приложений, которые ожидают, что трафик будет расти в геометрической прогрессии в будущем, как в модном приложении социальной сети.
Типичное приложение социальной сети имеет различные компоненты, такие как обмен сообщениями, чат в реальном времени, потоковое видео в реальном времени, загрузка изображений, функция «Нравится», «Поделиться» и т. Д.
В этом сценарии я бы предложил разрабатывать каждый компонент отдельно, имея в виду принцип единой ответственности и разделения проблем.
Написание каждой функции в единой кодовой базе быстро превратилось бы в беспорядок.
Итак, к настоящему времени в контексте монолитных и микросервисов мы прошли три подхода:
Выбор монолитной или микросервисной архитектуры во многом зависит от нашего варианта использования.
Я предлагаю, чтобы все было проще, хорошо разбираюсь в требованиях. Ознакомьтесь с местностью, создавайте что-то только тогда, когда это необходимо, и продолжайте итеративно развивать код. Это правильный путь.
Когда следует использовать NoSQL или SQL?
Когда выбирать базу данных SQL?
Если вы пишете приложение для торговли акциями, банковское дело или финансы или вам нужно сохранить множество взаимосвязей, например, при написании приложения для социальной сети, такого как Facebook, тогда вам следует выбрать реляционную базу данных.Вот почему:
Транзакции и согласованность данных
Если вы пишете программное обеспечение, которое имеет какое-либо отношение к деньгам или числам, что делает транзакции, ACID, согласованность данных очень важными для вас.
Реляционные БД превосходны, когда дело доходит до транзакций и согласованности данных. Они соответствуют правилу ACID, существуют уже много лет и проверены в боях.
Хранение отношений
Если у ваших данных много отношений, например, какие из ваших друзей живут в определенном городе? Кто из ваших друзей уже ел в ресторане, который вы планируете посетить сегодня? и Т. Д.Нет ничего лучше реляционной базы данных для хранения такого рода данных.
Реляционные базы данных созданы для хранения взаимосвязей. Они были испытаны и протестированы и используются крупными игроками в отрасли, такими как Facebook, в качестве основной пользовательской базы данных.
Популярные реляционные базы данных:
Когда выбирать базу данных NoSQL
Вот несколько причин, по которым вы можете выбрать базу данных NoSQL:
Обработка большого количества операций чтения и записи
Если вам нужно быстро масштабироваться, обратите внимание на базы данных NoSQL.Например, когда на вашем веб-сайте выполняется большое количество операций чтения-записи и при работе с большим объемом данных, базы данных NoSQL лучше всего подходят для этих сценариев.
Поскольку у них есть возможность добавлять узлы на лету, они могут обрабатывать больше одновременного трафика и большие объемы данных с минимальной задержкой.
Выполнение аналитики данных
Базы данных
NoSQL также лучше всего подходят для случаев использования аналитики данных, когда нам приходится иметь дело с притоком огромных объемов данных.
Популярные базы данных NoSQL:
Выбор подходящей техники для работы
Взаимодействие с данными в реальном времени
Если вы создаете приложение, которому требуется:
Тогда некоторые из популярных технологий, которые позволяют вам писать эти приложения, — это NodeJS и популярный фреймворк Python, известный как Tornado. Если вы работаете в экосистеме Java, вы можете изучить Spring Reactor, Play и Akka.
Одноранговое веб-приложение
Если вы намереваетесь создать одноранговое веб-приложение, например, распределенную поисковую систему P2P или радиослужбу P2P Live TV, что-то похожее на LiveStation от Microsoft, вам нужно изучить JavaScript, протоколы, такие как DAT, IPFS.Checkout FreedomJS, это платформа для создания веб-приложений P2P, которые работают в современных веб-браузерах.
Обычное приложение на основе CRUD
Если у вас есть простые варианты использования, такие как обычное приложение на основе CRUD, то вы можете использовать следующие технологии: Spring MVC, Python Django, Ruby on Rails, PHP Laravel, ASP .NET MVC.
Простые небольшие приложения
Если вы собираетесь написать приложение, не требующее особой сложности, например блог, простую онлайн-форму, простые приложения, которые интегрируются с социальными сетями, которые работают в IFrame портала, тогда вы можете выбрать PHP.
Вы также можете рассмотреть другие веб-фреймворки, такие как Spring boot, Ruby on Rails, которые сокращают многословие, настройку и время разработки на несколько ступеней и облегчают быструю разработку. Но хостинг PHP будет стоить намного дешевле по сравнению с хостингом других технологий. Он идеально подходит для очень простых случаев использования.
Приложения, интенсивно использующие ЦП и память
Вам нужно выполнять интенсивные вычислительные задачи с интенсивным использованием ЦП и памяти на серверной части, такие как обработка больших данных, параллельная обработка, мониторинг и анализ довольно большого объема данных?
Обычные веб-фреймворки и языки сценариев не предназначены для обработки чисел.Технология, обычно используемая в отрасли для написания производительных, масштабируемых, распределенных систем, — это
C ++.
Он имеет функции, которые облегчают манипулирование памятью на низком уровне, обеспечивая разработчикам больший контроль над памятью при написании распределенных систем. Большинство криптовалют написано на этом языке. Вот отличный бесплатный курс по изучению C ++.
Rust — это язык программирования, похожий на C ++. Он создан для обеспечения высокой производительности и безопасного параллелизма. В последнее время он набирает популярность в кругах разработчиков.Java, Scala и Erlang также являются хорошим выбором. Большинство крупных корпоративных систем написано на Java.
Go — это язык программирования от Google для написания приложений для многоядерных машин и обработки большого количества данных.
Вот как вы можете начать разработку Go.
Julia — это динамически программируемый язык, созданный для высокопроизводительных и выполняемых вычислений и численной аналитики.
Как стать архитектором программного обеспечения?
Если все это звучит интересно, то вы можете стремиться стать архитектором программного обеспечения.Но с чего начать? Что ж, крайне редко кто-то начинает как архитектор программного обеспечения, поэтому большинство инженеров-программистов работают несколько лет, прежде чем приступить к проектированию архитектуры.
Один из лучших способов познакомиться с архитектурой программного обеспечения — это создание собственных веб-приложений. Это заставит вас продумать все аспекты вашего приложения, от балансировки нагрузки, организации очереди сообщений, потоковой обработки, кеширования и т. Д.
Как только вы начнете понимать, как эти концепции вписываются в ваше приложение, вы будете на пути к тому, чтобы стать архитектором программного обеспечения.
Как начинающий архитектор программного обеспечения, вам необходимо постоянно расширять свои знания и оставаться в курсе последних тенденций в отрасли. Вы можете начать с изучения одного или нескольких языков программирования, поработать разработчиком программного обеспечения и постепенно продвигаться вперед.
Куда идти дальше?
Хотя в этом посте было много всего, мы коснулись этой темы лишь поверхностно. Нам еще предстоит изучить REST API, высокую доступность и теорему CAP.
Если вы хотите глубоко погрузиться в архитектуру программного обеспечения, я настоятельно рекомендую Архитектура веб-приложений и программного обеспечения 101 .Он шаг за шагом проведет вас по различным компонентам и концепциям, задействованным при проектировании архитектуры веб-приложения.
Вы узнаете о различных архитектурных стилях, таких как клиент-сервер, одноранговая децентрализованная архитектура, микросервисы, основы потока данных в веб-приложении, различные задействованные уровни, такие концепции, как масштабируемость, высокая доступность и многое другое.
Это также поможет вам с собеседованиями по разработке программного обеспечения, особенно для должностей разработчиков полного стека.
Удачного обучения!
Продолжайте читать об архитектуре программного обеспечения
Архитектура приложения
объяснена так, как ваша мама поймет.
Предупреждение. Эта статья содержит много информации о программировании и технической терминологии. Но здесь не будет упоминания о стилях готики или барокко, это не такая архитектура.
Проще говоря, архитектура мобильного приложения — это набор методов и шаблонов, которые помогают разработчикам создавать хорошо структурированные приложения.
В Crypterium мы создаем очень сложное мобильное приложение, которое позволяет пользователям расплачиваться криптовалютой с такой же легкостью, как наличными и картами. Тем не менее, мы хотим, чтобы наши пользователи понимали, как все работает за сценой. И мы постараемся сделать его максимально простым, чтобы вы, наконец, поняли, как создаются приложения, которые вы используете каждый день.
Объяснение лицевой и оборотной сторон
Вы, наверное, слышали, что архитектура приложений сильно различается во внешнем и внутреннем интерфейсе, но никто толком не объясняет, что это означает.Отойдем от технических терминов и проведем аналогию с повседневной жизнью.
Взгляните на собственное тело. Все снаружи, например, ваша голова и тело, находится «спереди», тогда как все, что находится внутри, например, ваше сердце, мозг и внутренние органы, является частью вашей «спины».
Мы создаем платежное приложение, и пока наша бэкэнд-команда разрабатывает сервисы, обеспечивающие все обмены, переводы, хранение данных и т. Д., Наши фронтендеры следят за тем, чтобы все эти сложные операции были показаны пользователям приложения в пользовательском интерфейсе. дружелюбный и понятный способ.
Ключевые принципы разработки гибкого приложения
Как только мы поняли разницу между лицевой и обратной стороной, давайте также разберемся с двумя ключевыми принципами, которые сегодня используют в своей работе самые прогрессивные разработчики: API First и Loose Coupling. Это современные методы, позволяющие разработать современное приложение, которое можно легко улучшить. Кроме того, любую отдельную часть приложения можно независимо улучшать без необходимости изменять другие части.
API first method превыше всего ценит высокую скорость и новинки.Идея проста: вы вводите ключевые исходные данные и получаете API, поверх которого бэкенд и фронтенд команды пишут свои коды параллельно, а тестировщики одновременно готовят тестирование. Преимущества этого подхода включают снижение затрат на разработку, увеличение скорости и минимизацию риска сбоя.
Вот аналогия из повседневной жизни: когда вы готовите болоньезе, вы не делаете сначала макароны, а потом соус, вы делаете все параллельно. Таким образом, вы получите вкусную еду быстрее, ничего не остынет, и ваши друзья смогут проверить результаты на основе того, чего они ожидали.
Одна из функций, которые мы используем в нашем методе API-first, называется Swagger (не путать с тенденцией, которая была популярна в хип-хопе в 2015 году, или описанием городского словаря). Swagger — это программный фреймворк с открытым исходным кодом, который помогает разработчикам создавать, проектировать, документировать и проектировать услуги. Инструменты Swagger автоматически генерируют описание API для большинства языков и фреймворков для передней и задней части.
Второй принцип называется «Свободная муфта ». Ситуация, когда ваше свидание отменяется в день святого Валентина, не является слабой связью, как раз наоборот, в вычислительной технике и проектировании систем слабая связь означает соединение компонентов в сети.
Слабая связь относится к степени непосредственного знания, которое один из элементов системы имеет о другом, эти элементы зависят друг от друга в наименьшей возможной степени. Цель состоит в том, чтобы снизить риск того, что изменение, внесенное в какой-либо элемент, приведет к изменениям и в других элементах. Ограничение межсоединений может помочь изолировать и идентифицировать проблемы, когда что-то идет не так, что упрощает тестирование и обслуживание.
Microservices vs Monolith
Благодаря принципам API First и Loose Coupling, Crypterium запускает свое приложение на микросервисах.Все приложение состоит из независимых сервисов, способных работать в собственном пространстве памяти и свободно масштабироваться друг от друга на многих отдельных машинах.
Архитектура микросервисов лучше организована, поскольку каждая микрослужба выполняет определенную работу. Разделенные службы также легче перенастроить и перекомпоновать для обслуживания различных приложений. Кроме того, они характеризуются быстрым развертыванием, отказоустойчивостью, горизонтальным масштабированием, низким начальным уровнем для команд, небольшой командной разработкой и простотой управления.
Представьте себе умный дом, где всем можно управлять и управлять с помощью одного устройства. Это устройство * ядро *, а управляемые элементы — * службы *. С помощью основного устройства вы можете открывать окна, включать телевизор или даже закрывать шторы. В основном так работает архитектура микросервисов.
Но ведь всегда есть другой вариант? Второй тип архитектуры — монолитная. Это означает, что приложение написано как одна единица кода, компоненты которой предназначены для совместной работы, разделяя одни и те же ресурсы и пространство памяти.Сервисы в таких приложениях тесно связаны, и у вас возникнут проблемы с изменением одного из них, не мешая другим. Представьте себе изумительный 12-слойный шоколадный торт. Слои могут сделать этот торт в 12 раз вкуснее, но вы не можете изменить один из слоев, не испортив весь торт. Это в основном то, что такое Monolith Architecture.
.NET Core и платформы JVM
Многофункциональные приложения, такие как мобильные кошельки, обычно имеют сотни различных сервисов. Чтобы сделать работу более структурированной, в Crypterium мы решили разделить наших внутренних разработчиков на 2 разные команды.Одна команда работает исключительно над основными продуктами, а другая — над всем остальным (авторизация, связь и т. Д.)
Каждая из этих команд использует свою собственную структуру. «Основная команда» больше работает над .NET Core. Эта платформа отличается быстрой разработкой, развертыванием и тестированием. Кроме того, к основным преимуществам можно отнести высокую производительность, пригодность для кросс-платформенных требований и ориентацию на микросервисы. Между тем, дополнительные сервисы разрабатываются в рамках JVM, основного конкурента.NetCore поддерживается Oracle.
Наличие двух самых популярных фреймворков позволяет нам нанимать разработчиков, которые используют разные языки программирования. Для .NET Core мы используем языки программирования C Sharp, а для JVM мы используем Kotlin и Java. Кроме того, используются те же языки, что и наша команда FrontEnd для нашего приложения для Android.
Разъяснение переднего плана
Передняя группа следит за тем, чтобы приложение было удобным для пользователя, а интерфейс читаемым, управляемым и понятным для всех.У нас есть приложение на iOS для пользователей iPhone и на Android для других пользователей смартфонов.
Версия приложения Crypterium для Android основана на языках Java и Kotlin (как и фреймворк JVM), а приложение iOS основано на новом, простом в использовании языке программирования Swift. Swift был создан Apple и идеально подходит для iPhone и / или MacOS. Возможности включают контроль доступа, управление памятью, отладку, создание цепочек и протокольно-ориентированное программирование.
MVVM и стиль маршрутизации для iOS
Команда разработчиков iOS Crypterium выбрала MVVM и стиль маршрутизации архитектур.Эти архитектуры удобны как для пользователей, так и для разработчиков, кроме того, они очень структурированы.
MVVM расшифровывается как Model-View-ViewModel, где Model означает информацию о продукте, а View показывает, как клиенты видят продукт. В MVVM есть многоуровневая структура: первый уровень обозначает UI (пользовательский интерфейс). Другие уровни включают сетевые сервисы и логические сервисы. Между тем, Routing отвечает за переходы за экраны, определяя путь клиента. Куда идет пользователь и что он видит, нажимая любую кнопку, регулируется маршрутизацией.
Давайте проанализируем пример, когда пользователь хочет отправить свою криптовалюту на другой адрес. Уровень сетевых сервисов содержит информацию о количестве отправленных криптовалют и адресе. Когда пользователь подтверждает транзакцию, уровень логических служб проверяет, достаточно ли криптовалюты для перевода, и дает пользователю положительный или отрицательный ответ.
Чистая архитектура для Android
Чтобы упростить обслуживание и повысить гибкость наших приложений, наша команда Android решила использовать метод под названием «Чистая архитектура».Этот метод гарантирует, что ненужное связывание отсутствует, и делает приложение более тестируемым.
Результатом является чистое, новое, свежее, простое в использовании приложение для Android с 4 уровнями сверху вниз: мобильное устройство (или Интернет, база данных, пользовательский интерфейс), контроллеры (шлюзы, докладчики), использование дела и сущности.
Заключение
Архитектура приложения — очень сложная тема, и все, что написано выше, — лишь верхушка айсберга. Однако хорошая новость заключается в том, что мы продолжим изучать эту и другие актуальные темы и будем чаще публиковать сообщения о технической части нашего продукта.
О Crypterium
CCrypterium создает мобильное приложение, которое превратит криптовалюты в деньги, которые вы можете тратить с такой же легкостью, как и наличные. Делайте покупки по всему миру и платите своими монетами и токенами на любом терминале NFC или путем сканирования QR-кодов. Совершайте покупки в интернет-магазинах, оплачивайте счета или просто отправляйте деньги через границу за секунды, надежно и за доли копейки.
Присоединяйтесь к нашему новостному каналу в Telegram или в других социальных сетях, чтобы оставаться в курсе!
Веб-сайт ๏ Telegram ๏ Facebook ๏ Twitter ๏ BitcoinTalk ๏ LinkedIn
Связанные
Теги
Присоединяйтесь к Hacker Noon
Создайте бесплатную учетную запись, чтобы разблокировать свой собственный опыт чтения.
Определение архитектуры приложения — Глоссарий по информационным технологиям Gartner
название компании
Страна
AustraliaCanadaIndiaUnited KingdomUnited Штаты —— AfghanistanAlbaniaAlgeriaAmerican SamoaAndorraAngolaAnguillaAntarcticaAntigua и BarbudaArgentinaArmeniaArubaAustriaAzerbaijanBahamasBahrainBangladeshBarbadosBelarusBelgiumBelizeBeninBermudaBhutanBoliviaBonaire, Синт-Эстатиус и SabaBosnia и HerzegovinaBotswanaBouvet IslandBrazilBritish Индийский океан TerritoryBrunei DarussalamBulgariaBurkina FasoBurundiCambodiaCameroonCape VerdeCayman IslandsCentral африканских RepublicChadChileChinaChristmas IslandCocos (Килинг) IslandsColombiaComorosCongoCongo, Демократическая Республика theCook IslandsCosta RicaCroatiaCubaCuraçaoCuraçaoCyprusCzech RepublicCôte D’IvoireCôte D’IvoireDenmarkDjiboutiDominicaDominican РеспубликаЭквадорЭгипетЭль-СальвадорЭкваториальная ГвинеяЭритреяЭстонияЭфиопияФолклендские (Мальвинские) острова Фарерские островаФинляндияФранцияФранцияФранцузская ГвианаФранцузская ПолинезияФранцузские Южные территорииГабонГамбияГрузияГерманияГанаГибралтарГрецияГренландияГвинеяГвинеяГвина Бисау, Гайана, Гаити, Херд, острова Макдональд.HondurasHong KongHungaryIcelandIndonesiaIran, Исламская Республика ofIraqIrelandIsle из ManIsraelItalyJamaicaJapanJerseyJordanKazakhstanKenyaKiribatiKorea, Корейская Народно-Демократическая Республика ofKorea, Республика ofKuwaitKyrgyzstanLao Народная Демократическая RepublicLatviaLebanonLesothoLiberiaLibyaLiechtensteinLithuaniaLuxembourgMacaoMacedonia, бывшая югославская Республика ofMadagascarMalawiMalaysiaMaldivesMaliMaltaMarshall IslandsMartiniqueMauritaniaMauritiusMayotteMexicoMicronesia, Федеративные Штаты ofMoldova, Республика ofMonacoMongoliaMontenegroMontserratMoroccoMozambiqueMyanmarNamibiaNauruNepalNetherlandsNetherlands AntillesNew CaledoniaNew ZealandNicaraguaNigerNigeriaNiueNorfolk IslandNorthern Mariana IslandsNorwayOmanPakistanPalauPalestine, Государственный ofPanamaPapua Новый GuineaParaguayPeruPhilippinesPitcairnPolandPortugalPuerto RicoQatarRomaniaRussian FederationRwandaRéunionRéunionSaint BarthélemySaint BarthélemySaint Helena, Вознесение и Тристан-да-Кунья, Сент-Китс и Невис, Сент-Люсия, Сен-Мартен (Франция). ч часть) Сен-Пьер и MiquelonSaint Винсент и GrenadinesSamoaSan MarinoSao Томе и PrincipeSaudi ArabiaSenegalSerbiaSerbia и MontenegroSeychellesSierra LeoneSingaporeSint Маартен (Голландская часть) SlovakiaSloveniaSolomon IslandsSomaliaSouth AfricaSouth Джорджия и Южные Сандвичевы IslandsSouth SudanSpainSri LankaSudanSurinameSvalbard и Ян MayenSwazilandSwedenSwitzerlandSyrian Arab RepublicTaiwanTajikistanTanzania, Объединенная Республика ofThailandTimor-LesteTogoTokelauTongaTrinidad и TobagoTunisiaTurkeyTurkmenistanTurks и Кайкос ОстроваТувалуУгандаУкраинаОбъединенные Арабские ЭмиратыМалые отдаленные острова СШАУругвайУзбекистанВануатуВатиканВенесуэла, Боливарианская РеспубликаВьетнамВиргинские острова, Британские Виргинские острова, СШАСан-Уоллис и Футуна, Западная Сахара, Йемен, Замбия, Зимбабве, Аландские острова, Аландские острова.
Руководство по архитектуре приложений Azure — Центр архитектуры Azure
В этой статье
В этом руководстве представлен структурированный подход к разработке приложений в Azure, которые являются масштабируемыми, безопасными, отказоустойчивыми и высокодоступными.Он основан на проверенных практиках, которые мы извлекли из взаимодействия с клиентами.
Введение
Облако меняет способ разработки и защиты приложений. Вместо монолитов приложения разбиваются на более мелкие децентрализованные службы. Эти службы взаимодействуют через API-интерфейсы, асинхронный обмен сообщениями или событиями. Приложения масштабируются по горизонтали, добавляя новые экземпляры по мере необходимости.
Эти тенденции порождают новые проблемы. Состояние приложения распределено.Операции выполняются параллельно и асинхронно. Приложения должны быть устойчивыми при возникновении сбоев. Злоумышленники постоянно атакуют приложения. Развертывание должно быть автоматическим и предсказуемым. Мониторинг и телеметрия имеют решающее значение для понимания системы. Это руководство разработано, чтобы помочь вам сориентироваться в этих изменениях.
Традиционное локальное | Современное облако |
---|---|
Монолитное Предназначено для предсказуемой масштабируемости Реляционная база данных Синхронизированная обработка Дизайн для предотвращения сбоев (MTBF) Время от времени большие обновления 452 Серверы управления вручную | Разложенный Разработан для эластичного масштабирования Сохраняемость полиглота (сочетание технологий хранения) Асинхронная обработка Расчет на отказ (MTTR) Частые небольшие обновления Автоматическое самоуправление Неизменяемая инфраструктура |
Структура данного руководства
Руководство по архитектуре приложений Azure организовано в виде серии шагов, от архитектуры и дизайна до реализации.Для каждого шага есть вспомогательные инструкции, которые помогут вам в разработке архитектуры вашего приложения.
Архитектурные стили
Первая точка принятия решения является наиболее фундаментальной. Какую архитектуру вы строите? Это может быть архитектура микросервисов, более традиционное многоуровневое приложение или решение для больших данных. Мы выделили несколько различных архитектурных стилей. У каждого есть свои преимущества и проблемы.
Подробнее: Стили архитектуры
Выбор технологий
Зная тип архитектуры, которую вы строите, теперь вы можете начать выбирать основные технологические элементы для этой архитектуры.Следующие технологические решения имеют решающее значение:
Возможно, вам придется сделать выбор дополнительных технологий в процессе, но эти три элемента (вычисления, данные и обмен сообщениями) являются центральными для большинства облачных приложений и будут определять многие аспекты вашего дизайна.
Дизайн архитектуры
После того, как вы выбрали стиль архитектуры и основные технологические компоненты, вы готовы приступить к конкретному дизайну вашего приложения. Все приложения разные, но следующие ресурсы могут помочь вам в этом:
Эталонные архитектуры
В зависимости от вашего сценария, одна из наших эталонных архитектур может быть хорошей отправной точкой.Каждая эталонная архитектура включает рекомендуемые методы, а также соображения по масштабируемости, доступности, безопасности, устойчивости и другим аспектам дизайна. Большинство из них также включают развертываемое решение или эталонную реализацию.
Принципы проектирования
Мы определили 10 принципов проектирования высокого уровня, которые сделают ваше приложение более масштабируемым, отказоустойчивым и управляемым. Эти принципы дизайна применимы к любому архитектурному стилю. На протяжении всего процесса проектирования помните об этих 10 общих принципах проектирования.Для получения дополнительной информации см. Принципы проектирования.
Паттерны проектирования
Шаблоны проектирования программного обеспечения — это повторяемые шаблоны, которые, как доказано, решают определенные проблемы. Наш каталог шаблонов облачного проектирования предназначен для решения конкретных задач в распределенных системах. Они касаются таких аспектов, как доступность, высокая доступность, операционное превосходство, отказоустойчивость, производительность и безопасность. Вы можете найти наш каталог шаблонов дизайна здесь.
Лучшие практики
Наши статьи с лучшими практиками охватывают различные аспекты проектирования, включая разработку API, автоматическое масштабирование, разделение данных, кэширование и т.