Привет! Меня зовут Грант, я .Net-разработчик. Знаете вы это или нет, но ваш код можно переиспользовать: будь то модуль, компонент или архитектура. Одни разработчики делают это осознанно, другие на уровне рефлексов. Повторное использование хорошего кода экономит время и другие ресурсы, позволяет применять лучшие практики на проектах, чтобы в итоге эффективнее решать бизнес-задачи. Мне стало интересно разобраться, когда возможен code reuse, какие проблемы стоит предусмотреть, и какие ресурсы заложить при реализации проектов. Для этого я проанализировал более 30 источников, в том числе иностранных, и вспомнил свой личный опыт на проектах. Разберу классификации механизмов повторного использования и расскажу о своей, покажу примеры разных масштабов: от уровня нескольких операторов до уровня архитектуры. Этот обзор полезен практически для всех разработчиков. Кто-то столкнется с понятиями идиом или архитектурных тактик, кому-то статья поможет систематизировать имеющиеся знания, кто-то найдет полезные материалы для решения конкретных кейсов при разработке и проектировании программ. В процессе разработки существует множество вещей, которые можно использовать повторно: например, документацию, исходный код, объекты, дизайн, архитектуру и даже другое программное обеспечение. Однако в связи с тем, что под повторным использованием ПО чаще всего понимают повторное использование исходного кода, многие воспринимают его как единственный вариант. Мы разделяем эти понятия, и для ясности приведем такое определение: Повторное использование программного обеспечения — это процесс создания программных систем на основе существующего программного обеспечения, а не создание их с нуля . Стоит также учесть, что более значительное увеличение производительности (с точки зрения скорости разработки, а не скорости исполнения алгоритмов) будет результатом повторного использования более высоких уровней абстракции. Мы будем говорить о переиспользовании кода и компонентов с разных уровней масштаба и абстракции, а именно рассмотрим: уровень кода; уровень, лежащий непосредственно над уровнем программного кода (программные структуры, из которых состоят модули); модули; компоненты, единицы развертывания; архитектуры. Начнем с классификации, которую предлагает Эрих Гамма . Он выделяет три уровня повторного использования. Фреймворки находятся на самом высоком уровне. Они определяют ключевые абстракции для решения проблемы.  На среднем уровне — шаблоны проектирования. Они меньше и более абстрактны, чем фреймворки. На самом низком уровне располагаются классы: библиотеки классов, контейнеры, объединения классов (например, контейнеры или итераторы). Таким образом, уровень повторного использования повышается, если переходить от классов к шаблонам и, наконец, к фреймворкам. Еще одна классификация, которая представлена «бандой четырех» : Между указанными на рисунке механизмами нет стрелок, указывающих отношение иерархии, так как все они применяются в паттернах проектирования и относятся к уровню, который лежит непосредственно над уровнем программного кода. Наконец, предлагаем нашу классификацию, элементы которой стремятся к некоторому упорядочению, но не всегда содержат строгие границы между собой. Например, некоторые идиомы могут быть как на уровне нескольких операторов, так и на уровне подпрограмм. При ее создании мы опирались на первую классификацию, проведя более подробную декомпозицию блоков, добавив других элементов после обзора механизмов и проведя частичное упорядочивание: В нее мы не включили такие элементы, как чистые функции, «ленивые» функции, функции высшего порядка и прочие, так как они входят в подпрограммы. Отметим также, что некоторые методы рефакторинга используют механизмы повторного использования для избавления от таких «запахов кода», как дублирование кода или большие классы . Блок «Архитектуры» многогранен, и множество концептов онтологии проектирования архитектуры может включать в себя: эталонные архитектуры; архитектурные стили; архитектурные шаблоны; шаблоны развертывания; архитектурные тактики. Более подробно об архитектурах поговорим в одноименном разделе далее. Можно также упомянуть классификацию принципов переиспользования дизайна . Здесь собраны принципы за несколько десятилетий, они не зависят от языка и предметной области. Подходы, которые описаны в принципах дизайна, перекликаются с механизмами повторного использования кода, однако, сейчас мы не об этом.  Далее приведем обзор нетривиальных механизмов повторного использования, таких как идиомы, паттерны, библиотеки, фреймворки и архитектуры. Если про константы, переменные, подпрограммы, классы и структуры мы слышим достаточно часто и переиспользуем их повседневно, то про идиомы мало кто упоминает. Однако мы с ними встречаемся с завидной регулярностью. В естественных языках идиома — это фраза, которая имеет не буквальное значение. Например, «she has a green thumb» дословно означает, что «у нее зеленый большой палец». А настоящее значение — «она хороший садовод, у нее талант в выращивании растений». Или идиома на русском языке «держать язык за зубами» означает «молчать, хранить тайну». В искусственных языках идиома — это шаблон решения задачи путем комбинирования встроенных элементов языка. Поэтому идиома зависит от конкретного языка. Приведем несколько примеров идиом для C#. «When normalizing strings, it is highly recommended that you use ToUpperInvariant instead of ToLowerInvariant because Microsoft has optimized the code for performing uppercase comparisons» Используйте паттерн var для сопоставления с любым выражением, включая null, и присвоения его результата новой локальной переменной: Вместо большого количества логических операторов “||”   используйте массив соответствующих значений и метод расширения Any<TSource> из пространства имен System.Linq: Вместо множества условных операторов “If” для поиска значения   используйте, например, коллекцию делегатов Func<TResult> из пространства имен System и метод расширения FirstOrDefault<TSource> из пространства имен System.Linq: Управление ресурсами с помощью конструкции using Используйте цепочку операторов null-объединения “??” для множественного сравнения с null: Или похожий пример, но из веб-разработки: При использовании оператора switch вместо вложенного условия if/else в выражении case  используйте выражение case/when: Эти и некоторые другие идиомы C# можно найти здесь: C# idioms Series' Articles Mike-Ward.Net — Favorite C# Idioms Rick Strahl's Weblog — Chaining the C# ?? Operator Pattern matching — the is and switch expressions Почти 100 идиом на языке C++ приведено на Wikibooks. И еще множество идиом с фильтрацией по различным  языкам программирования. Идиомы существуют также в тестировании. Например, для того, чтобы обеспечить  соблюдение лучших практик при написании тестов с применением Autofixture разработан пакет AutoFixture.Idioms. Из приведенных примеров и источников (под спойлером выше) видно, что идиомы требуют хороших знаний специфики языка и стандартов. Иногда это связано с синтаксическим сахаром, а иногда просто с устоявшимися правилами. Однако при всех своих преимуществах у идиом есть и недостатки. Отметим следующие: Их применение ведет к тому, что разработчикам других языков сложнее понять код; Лаконичные идиомы не всегда являются эффективным решением. Следующие механизмы повторного использования, которые мы рассмотрим — это паттерны. Обычно имеют в виду 23 паттерна проектирования, которые описаны «бандой четырех» . На следующем рисунке мы привели расширенную классификацию, которая кроме классических паттернов проектирования содержит: идиомы как низкоуровневые паттерны; паттерны реализации; паттерны тестирования; паттерны анализа; паттерны параллельного программирования; архитектурные паттерны. Про идиомы мы уже говорили ранее, рассмотрим остальные элементы. Паттерны реализации (Implementation patterns) — совокупность компонентов и других элементов реализации, используемых в структуре модели при написании программного кода. Они делятся на: паттерны организации программного кода; паттерны оптимизации программного кода; паттерны устойчивости кода; паттерны разработки графического интерфейса пользователя и другие. Паттерны тестирования (Test patterns) — особый тип шаблонов, которые могут использоваться на этапе тестирования для уменьшения избыточности, экономии времени и ресурсов и обеспечения эффективного механизма повторного использования для большего покрытия и повышения качества сопровождения одновременно . Паттерны анализа (Analysis patterns) — это группа связанных общих объектов (мета-классов) со стереотипными атрибутами (определениями данных), поведением (сигнатуры методов) и ожидаемыми взаимодействиями, определенными независимо от предметной области . К ним относятся паттерны бизнес-моделирования ARIS (Architecture of Integrated Information Systems). Также каталог таких паттернов представлен в труде Фаулера . Паттерны параллельного программирования (Concurrency and Parallel programming patterns). В настоящее время сложно представить эффективную многопользовательскую программу без конкурентной разработки. Такие паттерны содержат модели успешных решений тех проблем, с которыми разработчики сталкиваются при конкурентной разработке. При этом полезно отличать понятия конкурентности и ее разновидностей: Конкурентность — выполнение сразу нескольких действий в одно и то же время; Многопоточность — форма конкурентности, использующая несколько программных потоков выполнения; Параллельная обработка — выполнение большого объема работы за счет; распределения ее между несколькими потоками, выполняемыми одновременно; Асинхронное программирование — разновидность конкурентности, использующая обещания или обратные вызовы для предотвращения создания лишних потоков . Архитектурные паттерны (Architectural patterns) — множество предварительно определенных подсистем со спецификацией их ответственности, правил и базовых принципов установления отношений между ними. К данной категории можно отнести такие паттерны: многоуровневая архитектура; каналы и фильтры; клиент — сервер; управляемая событиями архитектура; архитектура на основе микросервисов; модель — представление — контроллер: MVC; HMVC (Hierarchical MVC) — расширение MVC с помощью иерархии триад; MVP — модификация MVC, в которой View больше не следит за обновлениями Model, события проходят через Presenter; MVVM — модификация MVC с применением концепции «связывания данных». EBI (Entity-Boundary-Interactor) — альтернатива MVC, при которой основные элементы и поведения, представляемые объектами Interactor и Entity, отделены от входящих и исходящих данных с помощью Boundary. В некотором смысле к архитектурным паттернам можно отнести каталог паттернов для архитектуры корпоративных приложений, которые описаны у Мартина Фаулера . Непосредственно паттерны проектирования активно представлены в платформах разработки. Обычно это происходит в двух формах: Паттерны применены для решения определенных задач в самой платформе. Платформа предоставляет нужные механизмы (обычно это соответствующие интерфейсы) для удобной реализации паттернов. Рассмотрим несколько таких примеров на C#. Примеры используемых паттернов в платформе: Фабрики/фабричные методы Microsoft.Extensions.Logging.LoggerFactory— создает экземпляры Microsoft.Extensions.Logging.ILoggerна основе заданных поставщиков Microsoft.AspNetCore.Http.MiddlewareFactory— реализация IMiddlewareFactory по умолчанию, которая содержит методы для создания Microsoft.AspNetCore.Http.IMiddleware System.Threading.Tasks.TaskFactory — обеспечивает поддержку для создания и планирования задач System.Threading.Tasks.Task Строитель, builder System.Text.StringBuilder — представляет собой изменяемую строку Microsoft.AspNetCore.Builder.WebApplicationBuilder — строитель для веб-приложений и сервисов. Посетитель System.Linq.Expressions.ExpressionVisitor  — посетитель для деревьев выражений. Его реализация для динамических деревьев выражений — System.Linq.Expressions.DynamicExpressionVisitor Интерфейсы для реализации паттернов: Прототип представлен интерфейсом System.ICloneable. Для удобства также может быть использован защищенный метод System.Object.MemberwiseClone, который возвращает неглубокую копию объекта. Для реализации Итератора можно использовать два интерфейса: System.Collections.IEnumerable и System.Collections.IEnumerator. Так же есть их обобщенные версии: System.Collections.Generic.IEnumerable<T> System.Collections.Generic.IEnumerator<T>. Наблюдатель представлен интерфейсами System.IObservable<T> и System.IObserver<T>. Для любителей реактивных расширений можно вспомнить про System.Reactive.Subjects.Subject<T>. Это был далеко не полный перечень, а всего лишь несколько примеров. Отмечу, что в данный пункт мы специально не включили паттерны GRASP (General Responsibility Assignment Software Pattern) — общие шаблоны распределения ответственностей . Хотя слово pattern на момент разработки шаблонов GRASP стало уже популярным, GRASP это скорее принципы (распределения ответственности между классами), а не паттерны.  Следующий нетривиальный механизм повторного использования по нашей классификации — это библиотеки. Про них обычно все понятно: мы их подключаем к своему приложению и вызываем нужные функции, либо переиспользуем целые библиотечные классы или модули. В отличие от библиотек фреймворки работают несколько иначе: они определяют каркас, внутри которого мы можем встраивать своё расширение или поведение.  Фреймворки состоят из: неизменяемой части, которая определяет общий подход (каркас, архитектуру); изменяемой части, которая связана с конкретной реализацией приложения, его логикой. Таким примером фреймворков может служить ASP.Net Core. Рассмотрим в нем три примера механизмов, которые содержат неизменяемую и изменяемую части. Конвейер обработки запросов, в котором компоненты, так называемые middleware, завершают обработку запроса или передают запрос на обработку следующему компоненту. После обработки запроса последним компонентом данные запроса возвращаются к предыдущему компоненту по цепочке. Это то поведение, на которое мы повлиять не можем (неизменяемая часть). Однако мы можем сами определять, какие именно компоненты должны быть в данном конвейере (изменяемая часть). Реализация шаблона MVC. В нем мы должны создавать контроллеры, имена которых содержат суффикс Controller, или базовый класс контроллера содержит суффикс, или к классу применяется атрибут [Controller]), а файлы представлений, как правило, объединяются в папки с именами соответствующими контроллерам (неизменяемая часть). При таких заданных правилах мы можем создавать произвольные контроллеры и произвольные представления (изменяемая часть). Встроенный контейнер внедрения зависимостей, который позволяет внедрять зависимости через конструкторы классов и использовать три типа жизненных циклов (неизменяемая часть). При этом то, какие именно сервисы и куда внедрять, определяет сам разработчик (изменяемая часть). Рассмотрим классификацию фреймворков, которая учитывает сразу три параметра: По оси абсцисс указан параметр Диапазон применения, который показывает, какие приложения можно реализовать с помощью данного фреймворка. По оси ордината отложено два параметра, один из них — Скорость разработки. Тут название говорит само за себя. Второй параметра по оси ординат — это Управляемость и гибкость, он показывает, какие ограничения накладывает фреймворк. Подход “No Frameworks” означает писать на чистом языке, без фреймворков. В таком случае мы получаем самый широкий диапазон применения и самую высокую гибкость, но самую низкую скорость разработки, так как придется писать много велосипедов. Конечно, если у вас задача написать эффективный алгоритм или разработать свой фреймворк, то данный подход вам может подойти. Подход “Narrow-focused Frameworks” — это узкоспециализированные фреймворки, которые помогают писать нам корпоративные приложения. Сюда можно отнести как отдельные ORM фреймворки (EF, Hibernate), так и «фреймворки фреймворков» (Spring или ASP.NET Core). Данный подход обладает все еще высокой гибкостью и достаточно большим диапазоном применения. Подход “Code Generators/Aggregators” позволяет ускорить разработку на стадии старта проекта. Такие генераторы выстраивают структуру приложений, основанных на узкоспециализированных фреймворках. Например, JHipster генерирует приложение на базе Spring с пользовательским интерфейсом на Angular. Подход “Full-stack Frameworks” — фреймворки, которые предоставляют готовую инфраструктуру и позволяют создавать такие приложения как ERP, BPMS. Один из представителей такого класса систем это Jmix. Подход “Low/No Code Frameworks” — это самый быстрый способ создания приложений, но и наименее гибкий, потому что в таких фреймворках вы не контролируете кодовую базу, а можете реализовывать только отдельные кусочки логики. Типичные представители данной группы это конструкторы сайтов, CMS системы (Wordpress, Drupal и другие). Архитектура — это способ решения проблем сложной системы путем абстракции реализации от интерфейса и разграничения полномочий между блоками код. Иоганн Вольфганг Гете писал: «Архитектура — это онемевшая музыка». Действительно, музыка существует в динамике, и точно так же приложение является процессом. У него есть момент запуска, развития и завершения. Архитектура приложения — его срез в любой конкретный момент времени. В любой момент наше приложение как музыкальная тема должно быть четким, ясным, понятным, предсказуемым. Часто именно работа с архитектурой – это первый шаг к долгосрочному сотрудничеству с заказчиком. Для команды это возможность показать экспертизу, обеспечить доверие и подключить специалистов к дальнейшей разработке. Я и мои коллеги в SimbirSoft занимаемся этими вопросами в Архитектурном комитете. Это группа экспертов, которые прорабатывают и проводят аудит IT-решений, помогают выбрать оптимальный технологический стек для каждого проекта. За несколько лет мы спроектировали уже более 70 крутых продуктов.  Зачем вообще нам нужна архитектура? Это первый шаг в разработке, который рассказывает, не только как решить проблему, как устроена систем, может рассказать о поведении системы до фактического выполнения. Помогает оценить потребность в ресурсах области решения. Помогает обнаружить в системе области, подверженные риску на этапе архитектуры. Отображает систему с точки зрения компонентов, поэтому если две системы имеют одинаковые компоненты, можно легко повторно использовать компонент для одной системы в другой. Помогает улучшить качество системы: обеспечить сопровождение, надежность, эффективность, удобство использования. В начале статьи мы упоминали понятия в сфере проектирования архитектуры, раскроем их: Эталонная архитектура (reference architectures) — это шаблон обязательных компонентов и технических требований для их реализации. Обычно эталонные архитектуры предоставляют структуру для приложений в определенных областях и могут воплощать разные архитектурные стили, отображаемые на один или несколько архитектурных шаблонов. Обзор видов архитектуры Azure Центр архитектурных решений AWS  Google Cloud solutions GitLab Reference Architectures Next-Gen Enterprise Architecture Center  Архитектурный стиль, или тип — это согласованный набор архитектурных ограничений, который устанавливает роли, функции элементов и допустимые взаимосвязи между ними в любой архитектуре, соответствующей этому стилю. Архитектурные стили определяют способ организации компонентов системы таким образом, чтобы можно было построить целостную систему и удовлетворить требования заказчика. Можно сказать, что архитектурный стиль обладает наивысшим уровнем абстракции. В таблице ниже приведен перечень архитектурных стилей, которые соответствуют определенным типам приложений: Тип приложения Архитектурный стиль Разделяемая память   Классная доска Дата-центрический Основанный на правилах Распределенная система Клиент-серверный Пространственно-ориентированная архитектура Одноранговая Архитектура без разделения ресурсов Посредник Передача репрезентативного состояния (REST) Сервис-ориентированный Обмен сообщениями   Событийная Асинхронный обмен сообщениями Издатель-подписчик Структурные   Основанный на компонентах Трубы и фильтры Монолит Многослойная Настраиваемые системы   Плагины Основанный на рефлексиях Микроядерный Современные системы   Архитектура распределенных вычисления Мультитенантный (мультиарендный) стиль Архитектура больших данных Далее рассмотрим более узкое понятие, чем архитектурный стиль. Архитектурный шаблон — это общее и повторяющееся решение часто возникающей проблемы архитектуры приложений в пределах заданного контекста. Более научное определение: абстракция структуры программной системы, состоящая из компонентов и связей между ними. Архитектурные шаблоны решают проблемы, связанные с архитектурными стилями. Например: Сколько будет уровней в нашей клиент-серверной архитектур: 1-tier, 2-tier, 3-tier или N-tier? Какие модули стоит выделить в нашей сервис-ориентированной архитектуре? На элементы шаблона архитектуры влияют выбранные тактики проектирования, реализующие особенности проектирования и зависящие от них. Архитектурная тактика — это проектное решение, которое влияет на достижение реакции атрибута качества. Тактика напрямую влияет на реакцию системы на некоторый стимул, придает переносимость одному дизайну, высокую производительность другому и интегрируемость третьему.  Проще говоря, архитектурные тактики применяются для достижения атрибута качества или не функционального требования. Еще один важный паттерн, который можно переиспользовать — это шаблон развертывания. Вследствие роста требований к разработке и развитию гибких методологий командам появилась необходимость быстрее и с большей стабильностью выпускать изменения. Инфраструктура и код приложений стали частью единого процесса, которым надо управлять. Для автоматизации процесса развертывания стали использовать инфраструктуру как код (IaC). Развертывание включает в себя шаги, которые называют планом развертывания. Шаблон развертывания — это несвязанный план развертывания, который определяет этапы выполнения, но не профили и системы. Шаблоны развертывания — это шаблоны, на основе которых можно создавать планы развертывания. Шаблоны Azure Resource Manager Шаблоны AWS CloudFormation  В заключение темы архитектуры отметим интересный пример под названием Web Architecture 101, который содержит базовые концепции веб-архитектуры и может быть полезен для веб-разработчиков. На рисунке представлены основные ее компоненты: (1) DNS — Система доменных имен; (2) Балансировщик нагрузки; (3) Серверы веб-приложений; (4) Сервера баз данных; (5) Служба кэширования; (6a) Очереди и (6b) сервера заданий; (7) Служба полнотекстового поиска; (8) Сервисы; (9a) Data firehose — потоковый интерфейс для приема и обработки данных; (10) Облачное хранилище (cloud storage); (9c) Хранилище данных (data warehouse); (11) CDN (Сеть доставки содержимого). Итак, пора ответить на два ключевых вопроса: когда возможен code reuse и какие проблемы при этом возникают? Вы можете повторно использовать код, когда он: легко расширяется и адаптируется под новое приложение; при необходимости портируется на другое оборудование; не содержит дефектов или проблем, которые влияют на надежность, сохранность и защищенность нового приложения; позволяет переиспользовать свою часть, если такое требуется. По мере увеличения количества проектов и разработчиков становится все труднее повторно использовать программное обеспечение. При этом сложнее сообщать о подробностях и требованиях для переиспользования кода. Еще увеличение количества проектов и разработчиков затрудняет обмен библиотеками. Каталогизация, архивирование и поиск повторно используемых ресурсов в глобальном масштабе — сложная задача. Такие платформы, как GitHub, могут упростить ее, но все равно создание удобного и масштабируемого репозитория требует времени и усилий. Часто бизнес-подразделения стремятся к автономии и конкурируют между собой, и могут попытаться заблокировать повторное использование своих наработок соседями.  Отдельные разработчики могут рассматривать повторное использование кода как подавление их творческих способностей или неуверенность в их технических способностях. Это может привести к сопротивлению. Для поддержки запланированного повторного использования командам нужно уделить дополнительное время на написание документации к своему коду, и протестировать его еще более тщательно, чем код для одного проекта. Руководителям проектов требуется заранее выделить дополнительные ресурсы с самого начала работ — для разработки, рефакторинга, документирования и тестирования кода. Это вложение с долгосрочными выгодами. Есть четыре основных характеристики программного обеспечения, которые влияют на повторное использование, и при недостаточных усилиях могут обернуться проблемами: Безопасность. Безопасности можно добиться разными способами, например, ведением списков уязвимостей, внедрение автоматизированных средств проверки. Надежность. Требуется обеспечить доступность, отказоустойчивость и возможность восстановления. Эффективность производительности. Этого можно добиться за счет уменьшения времени отклика процессора, мониторинга использования памяти. Поддерживаемость. Один из способов обеспечить удобство сопровождения кода — обеспечить его соответствие. Исходя из вышесказанного, можно выделить такие плюсы и минусы: ➕ Сокращение общего времени разработки, так как программистам не нужно начинать все с нуля. Поскольку разработчики могут использовать существующий код, организациям не нужны дополнительные ресурсы, то есть можно сократить затраты. При code reuse мы получаем единый источник правды, который предоставляет достоверные, актуальные и пригодные к использованию данные. Меньше кода — следовательно, меньше вероятность наличия в нем недостатков, проще понимать код. Если по каким-то причинам нельзя переиспользовать код, то можно распознать его базовую функциональность, а затем создать новый код, который будет делать желаемое, но с рядом преимуществ (например, быстрее, потребляет меньше памяти, совместим с имеющимися элементами системы). ➖  Сторонняя зависимость может быть менее надежной, чем недавно написанный код, соответствующий стандартам безопасности. Проблема шаблонных решений: готовая библиотека, фреймворк или архитектура могут быть менее эффективны, чем специализированное решение в конкретном случае. Если при переиспользовании осуществляется доступ к API по всей системе, то это может снизить скорость работы приложения. Модульная система может оказать негативное влияние на скорость работы системы. Могут возникнуть проблемы с добавлением желаемых улучшений. Могут возникнуть проблемы с лицензированием. Итак, когда мы говорим о переиспользовании, то можем затронуть как сам код, так и целую архитектуру. Между ними можно выстроить целую цепочку из паттернов, библиотек, фреймворков и так далее. Чтобы ориентироваться в данных категориях, поможет классификация с подробным обзором наиболее интересных механизмов повторного использования. Данные механизмы, безусловно, полезны, но не всегда их можно применить, так как есть ограничения бизнеса, безопасности, бюджета, корпоративной культуры. Поэтому выбор и просчет рисков остается за вами. Software Architectural Styles Andrew Midwinter, Mark Mullen, Kevin Wong, Matt Jones  Методика выбора шаблона программной архитектуры на основе анализа параметров качества системы Эталонные решения (reference architectures)  Эталонные архитектуры бессерверных функций Центр архитектурных решений AWS Обзор видов архитектуры Azure Reference architectures Reference Architecture & Frameworks–A Consolidation Google Cloud solutions Next-Gen Enterprise Architecture Center Архитектурные шаблоны Самые важные архитектурные шаблоны, которые нужно знать Основные архитектурные шаблоны построения ПО Краткий обзор 10 популярных архитектурных шаблонов приложений Шаблоны развертывания Как использовать шаблоны развертывания Azure Resource Manager (ARM) с Azure CLI Что такое шаблоны ARM? Описание преимуществ использования шаблонов Azure Resource Manager (шаблоны ARM) для развертывания ресурсов Шаблоны AWS CloudFormation Тактики: Архитектурные тактики шпаргалка Системы для Больших Данных: конвергенция архитектур Описание процесса создания архитектуры системы онлайн-трейдинга: подход аналитика хедж-фонда Realizing and Refining Architectural. Tactics: Availability A Catalogue of Green Architectural Tactics for the Cloud Architectural Tactics A Catalog of Architectural Tactics for Cyber-Foraging Спасибо за внимание! Полезные материалы о разработке и архитектуре мы также публикуем в наших соцсетях – ВКонтакте и Telegram.