Всем привет! На днях в рамках образовательной платформы OTUS запускается новый курс: «Архитектура и шаблоны проектирования». В связи со стартом мы провели традиционный открытый урок. На нём изучили особенности монолитного приложения, многоуровневой и бессерверной архитектур. Подробно рассмотрели систему, управляемую событиями, сервис-ориентированную систему и микросервисную архитектуру.
Преподаватель — Матвей Калинин, специалист с более чем 20-летним опытом программирования и автор курса «Архитектура и шаблоны проектирования».
Изначально программы действительно решали поставленную перед собой задачу и были довольно обособленными. Но со временем программы росли, и люди стали понимать, что возникающая сложность функционала начинает влиять на скорость доработок, надежность и устойчивость к разного рода усложнениям.
Действительно, когда у нас одна-две программы, которые одинаковы и не меняются, написать эти программы и обеспечить их взаимодействие несложно. Но когда их всё больше и больше, проблем не избежать, и не важно, о каком комплексе программного обеспечения идёт речь.
Сегодня приложения, в большинстве своём, являются распределенными. Они состоят из нескольких модулей и связаны между собой системными сообщениями. То есть получается довольно большой конгломерат программ, взаимодействующих между собой. А чтобы они взаимодействовали успешно, нам необходимо учитывать:
В то же самое время нельзя не вспомнить следующую цитату:
То есть, написав программу в идеале один раз (если она хорошо написана), доработки будут минимальны. Как же этого добиться и увязать одно и другое? Чтобы ответить на этот вопрос, обратимся к истории.
Итак, мы поняли, что нужно правильно структурировать программный продукт. Но какова же цель архитектуры ПО? И вообще, почему в названии этой статьи мы использовали словосочетание «растут ноги»?
Всё дело в том, что когда вы начинаете программировать, вы уже знаете, что хотите построить. Изначально всё начинается с бизнес-процесса. Есть заказ и заказчик, который описывает (хотя бы словами), как должна работать его система. И вот эта система поначалу существует только в описанном им виде. Потом этот процесс формализуют и обрисовывают, но это ещё полдела, т. к. дальше наступает разработка. А разработчику нужно этот процесс преобразовать в программный продукт, который должен…
Тут самое время вспомнить ещё одну цитату:
Не следует удивляться, что цель сформирована такими общими фразами. Дело в том, что архитектура живёт в абстрактных идеях. Почему? Потому что человек, который занимается архитектурой ПО, преобразует видение бизнес-заказчика в видение разработчика. И если мы говорим об архитекторе команды разработчиков и об Enterprise-архитекторе, то у каждого из них разная цель, но оба они стремятся к одному — уменьшить человеческие трудозатраты.
В таком контексте интересно посмотреть на ценности программного обеспечения:
И тут напрашивается вопрос: а что важнее, работа системы или простота ее изменения? Чтобы ответить на него, давайте посмотрим на программу с точки зрения полезности:
Если есть правильно работающая программа, которая не допускает изменений, то такая программа, со временем, станет неактуальной — когда изменятся требования.
Если же программа работает неправильно, но изменения в ней можно сделать, то её можно заставить работать правильно в рамках изменяющихся требований. Эта программа будет оставаться полезной всегда.
Как вы думаете, какая самая известная (самая первая) модель программирования? Разумеется, монолит. Здесь уместно снова на миг вернуться в 1968 год и вспомнить Эдсгера Дейкстра, который показал, что безудержное использование переходов (инструкций goto) вредно для структуры программы. Он предложил заменить переходы более понятными конструкциями if/then/else и do/while/until.
Сейчас инструкции goto можно увидеть не так часто. Но раньше инструкции goto были очень распространены. Вообще, это форменное зло, ведь когда вы видите код, в котором есть инструкция goto, возникает ощущение, что можно не найти тот самый пункт, куда он уходит. И чем больше goto, тем сложнее, то есть мы получаем спагетти-код. Это сейчас мы называем «спагетти» тот код, где, к примеру, 20 вложенных if’ов и, возможно, один goto. Это тоже не особо понятный код. Представьте, что у вас 10-15 goto, и вы пытаетесь понять, как работает цикл — вот что имел в виду Дейкстра.
Спагетти-код — слабо структурированная, запутанная и трудная для понимания программа, содержащая много операторов goto (особенно, переходов назад), исключений и других конструкций, ухудшающих структурированность. В общем, хорошо известный и довольно распространённый антипаттерн программирования. Такая программа отнимает много времени на понимание, поддержку и тестирование.
Существовали языки программирования, они реализовывали какие-то цели. До определённого момента структура программ не сильно влияла сильно на реализацию. Но программы росли, между ними образовывались многочисленные связи. И в один прекрасный момент человек ощутил, что алгоритм важно упаковывать в структуру, которая легко читается, тестируется. Начались изменения на уровне структуры программы. То есть уже не только сама программа должна была удовлетворять результату, но и структура программы также должна была соответствовать какому-то критерию.
Таким образом, мы плавно перешли к структурному программированию. Согласно ему, программа строится без использования оператора goto и состоит из трёх базовых управляющих структур:
Используются подпрограммы, сама разработка ведётся пошагово, методом «сверху вниз».
И снова вернёмся в 1966-й… В этом году Оле-Йохан Даль и Кристен Нюгор заметили, что в языке ALGOL есть возможность переместить кадр стека вызова функции в динамическую память (кучу), благодаря чему локальные переменные, объявленные внутри функции, могут сохраняться после выхода из нее. В результате функция превратилась в конструктор класса, локальные переменные — в переменные экземпляра, а вложенные функции — в методы. Это привело к открытию полиморфизма через строгое использование указателей на функции.
Как вы все знаете, в ООП программы представляются в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Основные принципы структурирования:
Можно посмотреть на эти все принципы с другой стороны. Роберт Мартин разработал принципы SOLID, которые, с одной стороны, определяют, как именно программисту работать с абстракциями, а с другой стороны, формируют сам процесс полиморфизма, наследования.
Императивная программа похожа на приказы, которые должен выполнить компьютер. Для таких программ характерно:
Тоже очень древняя конструкция. Основные черты императивных языков:
Однако продолжаем «путешествие во времени». На этот раз вернемся на мгновение в 1936(!) год. Он интересен тем, что именно в этом году Алонзо Чёрч изобрел лямбда-исчисление (или λ-исчисление), которое позднее, в 1958 году, легло в основу языка LISP, изобретенного Джоном Маккарти. Основополагающим понятием λ-исчисления является неизменяемость — то есть невозможность изменения значений символов.
Функциональное программирование предполагает обходиться вычислением результатов функций от исходных данных и результатов других функций и не предполагает явного хранения состояния программы.
Фактически, это означает, что функциональный язык не имеет инструкции присваивания.
Посмотрим разницу между императивным и функциональным стилями на примере:
Архитектура программного обеспечения есть совокупность решений об организации программной системы.
Она включает в себя:
Обратите внимание: сначала мы пришли к тому, что goto нас не устраивает, потом мы увидели, что есть определенные правила (инкапсуляция, наследование, полиморфизм), дальше мы поняли, что эти правила работают не просто так, а в соответствии с определенными принципами. Четвертый момент — это уже архитектурный стиль, и о нём мы поговорим далее.
Главное предназначение архитектуры — поддержка жизненного цикла системы. Хорошая архитектура делает систему легкой в освоении, простой в разработке, сопровождении и развертывании. Конечная цель — минимизировать затраты на протяжении срока службы системы и максимизировать продуктивность программиста, а если быть точнее, команды разработчиков.
Сначала мы говорили, какие правила нам нужны для написания программ. Но, помимо написания программ, есть еще сопровождение, разработка и развертывание. То есть архитектура захватывает не какую-то область программирования, а весь цикл разработки.
Хорошая архитектура должна обеспечивать:
В первую очередь, поговорим про всем известный монолит. Этот стиль ещё встречается, правда, в небольших системах. Монолитная архитектура означает, что ваше приложение — это большой связанный модуль. Все компоненты спроектированы так, чтобы работать вместе друг с другом, имеют общую память и ресурсы. Все функции или основная их часть сосредоточены в одном процессе или контейнере, который разбивается на внутренние слои или библиотеки.
Достоинства:
Но недостатков сейчас у него больше:
С одной стороны, монолит хорош, но как только начинаешь его развивать, возникают сложности.
Сейчас все знают, что такое сервис. Его можно определить как видимый ресурс, выполняющий повторяющуюся задачу и описанный внешней инструкцией.
Современные сервисы имеют следующие особенности:
В результате вышеперечисленных особенностей возникло такое понятие, как сервис-ориентированная архитектура (SOA).
SOA — архитектурный стиль для создания ИТ-архитектуры предприятия, использующий принципы ориентации на сервисы для достижения тесной связи между бизнесом и поддерживающими его информационными системами.
SOA обладает следующими характеристиками:
Модель развертывания SOA состоит из бизнес-анализа и разработки и ИТ-анализа и разработки. Сборка состоит из программирования сервисов и построения сложных приложений. Размещение состоит из размещения приложений и средств времени исполнения, таких как Enterprise Service Buses (ESB). Что касается руководства, то оно состоит из поддержки операционной среды, мониторинга производительности сервисов и слежения за соблюдением сервисных политик.
Пришло время поговорить и про микросервисную архитектуру. В ней приложение состоит из маленьких независимых приложений-сервисов, каждый со своими собственными ресурсами. Сервисы взаимодействуют друг с другом для выполнения задач, относящихся к их бизнес-возможностям. Существует несколько единиц развертывания. Каждый сервис развертывается самостоятельно.
Достоинства:
Недостатки:
Стоит отметить, что в этой архитектуре очень сложно что-либо сделать без DevOps.
Многоуровневая архитектура – это наиболее распространенный шаблон архитектуры. Его ещё называют n-tier архитектурой, где n – количество уровней.
Система делится на уровни, каждый из которых взаимодействует лишь с двумя соседними.
Архитектура не подразумевает какое-то обязательное количество уровней — их может быть три, четыре, пять и больше. Чаще всего используют трехзвенные системы: с уровнем представления (клиентом), уровнем логики и уровнем данных.
Наиболее часто встречаются следующие слои:
Концепция изоляции уровней строго отделяет один уровень от другого: перейти с одного уровня можно только на следующий и перескакивать сразу через несколько нельзя.
Система позволяет перепрыгивать через открытые уровни и попадать на те, что расположены ниже.
Концепция MVC была описана в 1978 году. Окончательная версия концепции MVC была опубликована лишь в 1988 году в журнале Technology Object.
Основная цель — в отделении бизнес-логики (модели) от её визуализации (представления, вида). Что это даёт:
Модель предоставляет данные и реагирует на команды контроллера, изменяя своё состояние. Представление отвечает за отображение данных модели пользователю, реагируя на изменения модели. Контроллер интерпретирует действия пользователя, оповещая модель о необходимости изменений.
Ещё одна интересная архитектура. Она применяется при разработке и реализации систем, передающих события среди слабосвязанных программных элементов.
Состоит из разрозненных одноцелевых компонентов обработки событий, которые асинхронно получают и обрабатывают события.
Шаблон состоит из двух основных топологий — посредника и брокера.
Есть процессы, где нужен контроль за последовательностью этапов. Здесь нам пригодится посредник.
Основные типы компонентов архитектуры:
Событие
Событие можно определить как «существенное изменение состояния». Событие может состоять из двух частей:
Топология посредника
Клиент отправляет событие в очередь событий (event queue), которая используется для передачи события посреднику (mediator).
Посредник (mediator) получает начальное событие и отправляет дополнительные асинхронные события в каналы событий (event channels) для выполнения каждого шага процесса.
Обработчики событий (Event processors), которые прослушивают каналы событий, получают событие от посредника и выполняют определенную бизнес-логику, обрабатывая событие.
Топология брокера
Топология брокера отличается от топологии посредника тем, что отсутствует центральный посредник событий. Поток сообщений распределяется по компонентам процессора событий в виде цепочки через брокера облегченных сообщений (например, ActiveMQ, HornetQ и т. д.). Эта топология полезна, когда есть относительно простой поток обработки событий и нет нужды в централизованной оркестровке событий.
Каждый компонент обработчика событий (event-processor) отвечает за обработку события (event) и публикацию нового события, указывающего только что выполненное действие.
Если первая ситуация была асинхронна «где-то внизу», то вторая ситуация асинхронна, можно сказать, совсем. Одно событие порождает несколько событий, и они могут увеличиваться и увеличиваться.
Достоинства архитектуры, управляемой событиями:
Недостатки:
Это способ создания и запуска приложений и сервисов без необходимости управления инфраструктурой. Приложение по-прежнему работает на серверах, но управление этими серверами платформа полностью берет на себя.
Вся инфраструктура поддерживается сторонними провайдерами, а необходимая функциональность предлагается в форме сервисов, отвечающих за процессы аутентификации, передачи сообщений и пр.
Выделяют следующую терминологию:
Если рассматривать архитектуру «Клиент-сервер», то большая часть логики в системе (аутентификация, навигация по страницам, поиск, транзакции) реализуется серверным приложением.
В бессерверной архитектуре всё несколько иначе. Аутентификация заменена сторонней службой BaaS (готовый облачный сервис), доступ к БД также заменен другой службой BaaS. Логика приложения частично уже внутри клиента — например, отслеживание сеанса пользователя.
Клиент уже на пути к тому, чтобы стать одностраничным приложением. Поиск можно делать через услугу поиска (FaaS — функция как услуга). Функция покупки тоже изолирована от клиента отдельной услугой (FaaS).
Что же, на этом всё, если интересуют подробности, смотрите видео целиком. Что касается нового курса, то ознакомиться с его программой можно здесь.
Преподаватель — Матвей Калинин, специалист с более чем 20-летним опытом программирования и автор курса «Архитектура и шаблоны проектирования».
Небольшая предыстория
Изначально программы действительно решали поставленную перед собой задачу и были довольно обособленными. Но со временем программы росли, и люди стали понимать, что возникающая сложность функционала начинает влиять на скорость доработок, надежность и устойчивость к разного рода усложнениям.
Действительно, когда у нас одна-две программы, которые одинаковы и не меняются, написать эти программы и обеспечить их взаимодействие несложно. Но когда их всё больше и больше, проблем не избежать, и не важно, о каком комплексе программного обеспечения идёт речь.
Сегодня приложения, в большинстве своём, являются распределенными. Они состоят из нескольких модулей и связаны между собой системными сообщениями. То есть получается довольно большой конгломерат программ, взаимодействующих между собой. А чтобы они взаимодействовали успешно, нам необходимо учитывать:
- быстроту реагирования;
- пропускную способность;
- производительность в пересчете на одну единицу ресурса;
- способность к масштабированию;
- возможности интеграции;
- особенности используемых платформ;
- особенности существующих бизнес-процессов;
- и многое другое…
В то же самое время нельзя не вспомнить следующую цитату:
«Правильный программный код не требует больших трудозатрат на свое создание и сопровождение. Изменения вносятся легко и быстро. Ошибки немногочисленны. Трудозатраты минимальны, а функциональность и гибкость — максимальны».
Роберт Сесил Мартин
То есть, написав программу в идеале один раз (если она хорошо написана), доработки будут минимальны. Как же этого добиться и увязать одно и другое? Чтобы ответить на этот вопрос, обратимся к истории.
- 1968 год: в научно-исследовательской работе Эдсгера Дейкстры была описана многопрограммная система, в которой все действия разделены на ряд последовательных процессов («The Structure of the «THE»-Multiprogramming System»). Эти последовательные процессы размещены на различных иерархических уровнях, на каждом из которых была реализована одна или несколько независимых абстракций. Были затронуты даже вопросы тестирования!
- 1970 год: Дэвид Парнас в своей статье «On the Criteria To Be Used in Decomposing Systems into Modules» описал подход разделения на модули как механизм для улучшения гибкости и понятности системы, который позволяет сократить время разработки. Эффективность подхода зависит от критериев, используемых при делении системы на модули. Структура системы программного обеспечения стала приобретать важное значение;
- 1996 год: Мэри Шоу и Дэвид Гэрлан из университета Carnegie Mellon написали книгу под названием «Архитектура программного обеспечения: перспективы новой дисциплины» («Software Architecture: Perspectives on an Emerging Discipline»), в которой выдвинули концепции архитектуры программного обеспечения, такие как компоненты, соединители (connectors), стили и т. д.;
- 2007 год: в этом году вышел первый стандарт программной архитектуры — IEEE 1471: ANSI / IEEE 1471 — 2000: Рекомендации по описанию преимущественно программных систем. Он был принят под названием ISO ISO / IEC 42010:2007.
Какова цель архитектуры ПО?
Итак, мы поняли, что нужно правильно структурировать программный продукт. Но какова же цель архитектуры ПО? И вообще, почему в названии этой статьи мы использовали словосочетание «растут ноги»?
Всё дело в том, что когда вы начинаете программировать, вы уже знаете, что хотите построить. Изначально всё начинается с бизнес-процесса. Есть заказ и заказчик, который описывает (хотя бы словами), как должна работать его система. И вот эта система поначалу существует только в описанном им виде. Потом этот процесс формализуют и обрисовывают, но это ещё полдела, т. к. дальше наступает разработка. А разработчику нужно этот процесс преобразовать в программный продукт, который должен…
Тут самое время вспомнить ещё одну цитату:
«Цель архитектуры программного обеспечения — уменьшить человеческие трудозатраты на создание и сопровождение системы».
Роберт Сесил Мартин
Не следует удивляться, что цель сформирована такими общими фразами. Дело в том, что архитектура живёт в абстрактных идеях. Почему? Потому что человек, который занимается архитектурой ПО, преобразует видение бизнес-заказчика в видение разработчика. И если мы говорим об архитекторе команды разработчиков и об Enterprise-архитекторе, то у каждого из них разная цель, но оба они стремятся к одному — уменьшить человеческие трудозатраты.
В таком контексте интересно посмотреть на ценности программного обеспечения:
- код удовлетворяет требованиям бизнес-процесса;
- есть возможность быстрого изменения поведения.
И тут напрашивается вопрос: а что важнее, работа системы или простота ее изменения? Чтобы ответить на него, давайте посмотрим на программу с точки зрения полезности:
Если есть правильно работающая программа, которая не допускает изменений, то такая программа, со временем, станет неактуальной — когда изменятся требования.
Если же программа работает неправильно, но изменения в ней можно сделать, то её можно заставить работать правильно в рамках изменяющихся требований. Эта программа будет оставаться полезной всегда.
Парадигмы (модели) программирования
Как вы думаете, какая самая известная (самая первая) модель программирования? Разумеется, монолит. Здесь уместно снова на миг вернуться в 1968 год и вспомнить Эдсгера Дейкстра, который показал, что безудержное использование переходов (инструкций goto) вредно для структуры программы. Он предложил заменить переходы более понятными конструкциями if/then/else и do/while/until.
Сейчас инструкции goto можно увидеть не так часто. Но раньше инструкции goto были очень распространены. Вообще, это форменное зло, ведь когда вы видите код, в котором есть инструкция goto, возникает ощущение, что можно не найти тот самый пункт, куда он уходит. И чем больше goto, тем сложнее, то есть мы получаем спагетти-код. Это сейчас мы называем «спагетти» тот код, где, к примеру, 20 вложенных if’ов и, возможно, один goto. Это тоже не особо понятный код. Представьте, что у вас 10-15 goto, и вы пытаетесь понять, как работает цикл — вот что имел в виду Дейкстра.
Спагетти-код — слабо структурированная, запутанная и трудная для понимания программа, содержащая много операторов goto (особенно, переходов назад), исключений и других конструкций, ухудшающих структурированность. В общем, хорошо известный и довольно распространённый антипаттерн программирования. Такая программа отнимает много времени на понимание, поддержку и тестирование.
Структурное программирование
Существовали языки программирования, они реализовывали какие-то цели. До определённого момента структура программ не сильно влияла сильно на реализацию. Но программы росли, между ними образовывались многочисленные связи. И в один прекрасный момент человек ощутил, что алгоритм важно упаковывать в структуру, которая легко читается, тестируется. Начались изменения на уровне структуры программы. То есть уже не только сама программа должна была удовлетворять результату, но и структура программы также должна была соответствовать какому-то критерию.
Таким образом, мы плавно перешли к структурному программированию. Согласно ему, программа строится без использования оператора goto и состоит из трёх базовых управляющих структур:
- последовательность,
- ветвление,
- цикл.
Используются подпрограммы, сама разработка ведётся пошагово, методом «сверху вниз».
И снова вернёмся в 1966-й… В этом году Оле-Йохан Даль и Кристен Нюгор заметили, что в языке ALGOL есть возможность переместить кадр стека вызова функции в динамическую память (кучу), благодаря чему локальные переменные, объявленные внутри функции, могут сохраняться после выхода из нее. В результате функция превратилась в конструктор класса, локальные переменные — в переменные экземпляра, а вложенные функции — в методы. Это привело к открытию полиморфизма через строгое использование указателей на функции.
Объектно-ориентированное программирование
Как вы все знаете, в ООП программы представляются в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Основные принципы структурирования:
- абстракция;
- наследование;
- полиморфизм.
Можно посмотреть на эти все принципы с другой стороны. Роберт Мартин разработал принципы SOLID, которые, с одной стороны, определяют, как именно программисту работать с абстракциями, а с другой стороны, формируют сам процесс полиморфизма, наследования.
Императивное программирование
Императивная программа похожа на приказы, которые должен выполнить компьютер. Для таких программ характерно:
- в исходном коде программы записываются инструкции;
- инструкции должны выполняться последовательно;
- данные, получаемые при выполнении предыдущих инструкций, могут читаться из памяти последующими инструкциями;
- данные, полученные при выполнении инструкции, могут записываться в память.
Тоже очень древняя конструкция. Основные черты императивных языков:
- использование именованных переменных;
- использование оператора присваивания;
- использование составных выражений;
- использование подпрограмм.
Однако продолжаем «путешествие во времени». На этот раз вернемся на мгновение в 1936(!) год. Он интересен тем, что именно в этом году Алонзо Чёрч изобрел лямбда-исчисление (или λ-исчисление), которое позднее, в 1958 году, легло в основу языка LISP, изобретенного Джоном Маккарти. Основополагающим понятием λ-исчисления является неизменяемость — то есть невозможность изменения значений символов.
Функциональное программирование
Функциональное программирование предполагает обходиться вычислением результатов функций от исходных данных и результатов других функций и не предполагает явного хранения состояния программы.
Фактически, это означает, что функциональный язык не имеет инструкции присваивания.
Посмотрим разницу между императивным и функциональным стилями на примере:
# императивный стиль
target = [] # создать пустой список
for item in source_list: # для каждого элемента исходного списка
trans1 = G(item) # применить функцию G()
trans2 = F(trans1) # применить функцию F()
target.append(trans2) # добавить преобразованный элемент в список
# функциональный стиль
compose2 = lambda A, B: lambda x: A(B(x))
target = map(compose2(F, G), source_list)
Так что же такое архитектура программного обеспечения?
Архитектура программного обеспечения есть совокупность решений об организации программной системы.
Она включает в себя:
- выбор структурных элементов и их интерфейсов;
- поведение выбранных элементов и интерфейсов, их взаимодействие;
- соединение выбранных элементов структуры и поведения в более крупные системы;
- архитектурный стиль, который направляет всю организацию.
Обратите внимание: сначала мы пришли к тому, что goto нас не устраивает, потом мы увидели, что есть определенные правила (инкапсуляция, наследование, полиморфизм), дальше мы поняли, что эти правила работают не просто так, а в соответствии с определенными принципами. Четвертый момент — это уже архитектурный стиль, и о нём мы поговорим далее.
Главное предназначение архитектуры — поддержка жизненного цикла системы. Хорошая архитектура делает систему легкой в освоении, простой в разработке, сопровождении и развертывании. Конечная цель — минимизировать затраты на протяжении срока службы системы и максимизировать продуктивность программиста, а если быть точнее, команды разработчиков.
Сначала мы говорили, какие правила нам нужны для написания программ. Но, помимо написания программ, есть еще сопровождение, разработка и развертывание. То есть архитектура захватывает не какую-то область программирования, а весь цикл разработки.
Хорошая архитектура должна обеспечивать:
- Разнообразие вариантов использования и эффективную работу системы.
- Простоту сопровождения системы.
- Простоту разработки системы.
- Простоту развертывания системы.
Архитектурные стили
Монолит
В первую очередь, поговорим про всем известный монолит. Этот стиль ещё встречается, правда, в небольших системах. Монолитная архитектура означает, что ваше приложение — это большой связанный модуль. Все компоненты спроектированы так, чтобы работать вместе друг с другом, имеют общую память и ресурсы. Все функции или основная их часть сосредоточены в одном процессе или контейнере, который разбивается на внутренние слои или библиотеки.
Достоинства:
- Легко реализовать. Не надо тратить время на размышления о межпроцессном взаимодействие.
- Легко разработать сквозные тесты.
- Простота развертывания.
- Простое масштабирование за счёт Loadbalancer перед несколькими экземплярами вашего приложения.
- Простота в эксплуатации.
Но недостатков сейчас у него больше:
- Сильная связанность приводит к запутанности с эволюцией приложения.
- Независимое масштабирование компонентов приводит к усложнению и полному ретесту функционала.
- Сложнее для понимания.
- С ростом сложности растет время разработки.
- Отсутствие изоляции компонентов.
С одной стороны, монолит хорош, но как только начинаешь его развивать, возникают сложности.
Что такое сервис?
Сейчас все знают, что такое сервис. Его можно определить как видимый ресурс, выполняющий повторяющуюся задачу и описанный внешней инструкцией.
Современные сервисы имеют следующие особенности:
- сервисы ориентируются не на возможности ИТ, а на нужды бизнеса;
- сервисы самодостаточны и описываются в терминах интерфейсов, операций, семантики, динамических характеристик, политик и свойств сервиса;
- повторное использование сервисов обеспечивается их модульным планированием;
- сервисные соглашения заключаются между сущностями, именуемыми поставщиками и пользователями, и не влияют на реализацию самих сервисов;
- в течение своего жизненного цикла сервисы размещаются и становятся видимы благодаря сервисным метаданным, реестрам и хранилищам;
- агрегация: на слабо связанных сервисах строятся объединяющие бизнес-процессы и сложные приложения для одного или нескольких предприятий.
В результате вышеперечисленных особенностей возникло такое понятие, как сервис-ориентированная архитектура (SOA).
Сервис-ориентированная архитектура (SOA)
SOA — архитектурный стиль для создания ИТ-архитектуры предприятия, использующий принципы ориентации на сервисы для достижения тесной связи между бизнесом и поддерживающими его информационными системами.
SOA обладает следующими характеристиками:
- Улучшает взаимосвязь между архитектурой предприятия и бизнесом.
- Позволяет из наборов интегрированных сервисов создавать сложные приложения.
- Создает гибкие бизнес-процессы.
- Не зависит от набора технологий.
- Автономна в смысле независимой эволюции и развертывании.
Модель развертывания SOA состоит из бизнес-анализа и разработки и ИТ-анализа и разработки. Сборка состоит из программирования сервисов и построения сложных приложений. Размещение состоит из размещения приложений и средств времени исполнения, таких как Enterprise Service Buses (ESB). Что касается руководства, то оно состоит из поддержки операционной среды, мониторинга производительности сервисов и слежения за соблюдением сервисных политик.
Микросервисная архитектура
Пришло время поговорить и про микросервисную архитектуру. В ней приложение состоит из маленьких независимых приложений-сервисов, каждый со своими собственными ресурсами. Сервисы взаимодействуют друг с другом для выполнения задач, относящихся к их бизнес-возможностям. Существует несколько единиц развертывания. Каждый сервис развертывается самостоятельно.
Достоинства:
- Поддерживает модульность всей системы.
- Несвязанные сервисы проще дорабатывать для обслуживания различных приложений.
- Разные сервисы могут принадлежать разным командам.
- Услуги сервиса могут быть повторно использованы всей компанией.
- Легче понять и протестировать.
- Не привязаны к технологии, используемой в других сервисах.
- Изолированность сервиса повышает общую надёжность всего функционала.
Недостатки:
- Сложности с реализацией в общей функциональности (логирование, права доступа и пр.).
- Сложно проводить сквозные тесты системы.
- Сложнее эксплуатация и поддержка.
- Требуется больше оборудования, чем для монолита.
- Поддержка несколькими командами приводит к координации взаимодействия между ними.
Стоит отметить, что в этой архитектуре очень сложно что-либо сделать без DevOps.
Многоуровневая архитектура
Многоуровневая архитектура – это наиболее распространенный шаблон архитектуры. Его ещё называют n-tier архитектурой, где n – количество уровней.
Система делится на уровни, каждый из которых взаимодействует лишь с двумя соседними.
Архитектура не подразумевает какое-то обязательное количество уровней — их может быть три, четыре, пять и больше. Чаще всего используют трехзвенные системы: с уровнем представления (клиентом), уровнем логики и уровнем данных.
Наиболее часто встречаются следующие слои:
- слой представления (для работы с пользователями);
- слой приложения (сервиса — безопасность, доступ);
- слой бизнес-логики (реализация предметной области);
- слой доступа к данным (представление интерфейса к БД).
Закрытые слои
Концепция изоляции уровней строго отделяет один уровень от другого: перейти с одного уровня можно только на следующий и перескакивать сразу через несколько нельзя.
Открытые слои
Система позволяет перепрыгивать через открытые уровни и попадать на те, что расположены ниже.
MVC
Концепция MVC была описана в 1978 году. Окончательная версия концепции MVC была опубликована лишь в 1988 году в журнале Technology Object.
Основная цель — в отделении бизнес-логики (модели) от её визуализации (представления, вида). Что это даёт:
- повышается возможность повторного использования кода.
- пользователь может видеть те же самые данные одновременно в различных контекстах.
Модель предоставляет данные и реагирует на команды контроллера, изменяя своё состояние. Представление отвечает за отображение данных модели пользователю, реагируя на изменения модели. Контроллер интерпретирует действия пользователя, оповещая модель о необходимости изменений.
Архитектура, управляемая событиями
Ещё одна интересная архитектура. Она применяется при разработке и реализации систем, передающих события среди слабосвязанных программных элементов.
Состоит из разрозненных одноцелевых компонентов обработки событий, которые асинхронно получают и обрабатывают события.
Шаблон состоит из двух основных топологий — посредника и брокера.
Топология посредника
Есть процессы, где нужен контроль за последовательностью этапов. Здесь нам пригодится посредник.
Основные типы компонентов архитектуры:
- очереди событий;
- посредник событий;
- каналы событий;
- обработчики событий.
Событие
Событие можно определить как «существенное изменение состояния». Событие может состоять из двух частей:
- заголовка (имя события, временную метку для события, и тип события);
- тела (описывает то, что в действительности произошло).
Топология посредника
Клиент отправляет событие в очередь событий (event queue), которая используется для передачи события посреднику (mediator).
Посредник (mediator) получает начальное событие и отправляет дополнительные асинхронные события в каналы событий (event channels) для выполнения каждого шага процесса.
Обработчики событий (Event processors), которые прослушивают каналы событий, получают событие от посредника и выполняют определенную бизнес-логику, обрабатывая событие.
Топология брокера
Топология брокера отличается от топологии посредника тем, что отсутствует центральный посредник событий. Поток сообщений распределяется по компонентам процессора событий в виде цепочки через брокера облегченных сообщений (например, ActiveMQ, HornetQ и т. д.). Эта топология полезна, когда есть относительно простой поток обработки событий и нет нужды в централизованной оркестровке событий.
Каждый компонент обработчика событий (event-processor) отвечает за обработку события (event) и публикацию нового события, указывающего только что выполненное действие.
Если первая ситуация была асинхронна «где-то внизу», то вторая ситуация асинхронна, можно сказать, совсем. Одно событие порождает несколько событий, и они могут увеличиваться и увеличиваться.
Достоинства архитектуры, управляемой событиями:
- компоненты изолированы и позволяют делать доработку каждого без влияния на остальные части системы;
- простота развертывания;
- высокая производительность. Позволяет выполнять параллельные асинхронные операции;
- хорошо масштабируется.
Недостатки:
- сложно тестировать;
- сложно развивать из-за ярко выраженной асинхронности.
Бессерверная архитектура
Это способ создания и запуска приложений и сервисов без необходимости управления инфраструктурой. Приложение по-прежнему работает на серверах, но управление этими серверами платформа полностью берет на себя.
Вся инфраструктура поддерживается сторонними провайдерами, а необходимая функциональность предлагается в форме сервисов, отвечающих за процессы аутентификации, передачи сообщений и пр.
Выделяют следующую терминологию:
- Функция как услуга (Function-as-a-Service) — модель, дающая возможность вызова экземпляра управляющего кода без необходимости управления серверами и серверным приложением.
- Бэкенд как услуга (Backend as a Service) — модель, позволяющая разработчикам веб-приложений и мобильных приложений связать их приложения с серверным облачным хранилищем и API, выставляемыми серверными приложениями. Предоставляет такие функции, как управление пользователями, извещающие уведомления, интеграция со службами социальных сетей.
Если рассматривать архитектуру «Клиент-сервер», то большая часть логики в системе (аутентификация, навигация по страницам, поиск, транзакции) реализуется серверным приложением.
В бессерверной архитектуре всё несколько иначе. Аутентификация заменена сторонней службой BaaS (готовый облачный сервис), доступ к БД также заменен другой службой BaaS. Логика приложения частично уже внутри клиента — например, отслеживание сеанса пользователя.
Клиент уже на пути к тому, чтобы стать одностраничным приложением. Поиск можно делать через услугу поиска (FaaS — функция как услуга). Функция покупки тоже изолирована от клиента отдельной услугой (FaaS).
Что же, на этом всё, если интересуют подробности, смотрите видео целиком. Что касается нового курса, то ознакомиться с его программой можно здесь.