Пишите библиотеки вместо сервисов (если это возможно)
Сервис связан с постоянными административными затратами, нести которые приходится поставщику сервиса. Правильно спроектированная библиотека переносит все эти затраты на её пользователей.
Это означает, что библиотека (если её применение возможно) способна обеспечивать пользователю ту же функциональность, при этом стоя разработчику дешевле, чем сервис.
Обычно централизацию таких административных затрат считают преимуществом сервисов.
Люди говорят: «С сервисами легко работать, потому что их можно обновлять централизованно, благодаря чему не торопящиеся обновляться пользователи не портят жизнь остальным».
Но это подразумевает, что не обновляющиеся вовремя пользователи могут влиять на всех остальных. Если один пользователь не может отрицательно влиять на других пользователей, то нас не волнует, насколько быстро обновляются отдельные пользователи; они вредят только самим себе.
Можно предотвратить отрицательное влияние одних пользователей на других, не обмениваясь состоянием ресурсов между пользователями; другими словами, избегая сервисов.
Возьмём для примера распространённый сценарий: разработчик создаёт и библиотеку, и сервис, но впоследствии обнаруживает, что библиотека (уже выпущенная) содержит какой-то баг или несовместимость, и её нужно обновить у всех, прежде чем совершенствовать сервис. Это становится большой головной болью, из-за которой разработчик может наивно предположить, что функциональность нужно перенести из библиотеки в сервис для упрощения обновлений.
Но если у вас вообще нет сервиса, а только библиотека, содержащая все функции и выполняющая всё то, что должен выполнять сервис, то такая проблема вообще не возникнет. Не обновляющиеся пользователи, будут страдать от проблем, существующих в исходной версии библиотеки, а со всеми остальными всё будет в порядке.
Избегать сервисов таким способом не всегда возможно; но это возможно чаще, чем считается. Вот несколько идей, которые стоит рассмотреть:
- Вместо того, чтобы манипулировать ресурсами из сервиса, мы можем напрямую вызывать лежащие в их основе примитивы из библиотеки. По сути, в таком случае пользователь полагается на более устойчивые сервисы, которые поддерживаются кем-то другим, например, на ядро Linux или на Kubernetes. Если вы захотите создать абстракции поверх них, то с этим тоже справится библиотека.
Примерами сервисов, которых можно таким образом избежать, являются супервизор процессов и системы управления конфигурациями. - Если невозможно обеспечить безопасный доступ пользователей к низкоуровневым примитивам и ресурсам, то они не могут использовать библиотеку, осуществляющую к ним доступ. Можно прийти к выводу, что в таком случае необходим сервис для безопасного обмена ресурсами между пользователями; и в самом деле, это практически является определением «сервиса».
Однако часто, если хорошенько поразмыслить, на самом деле можно предоставить пользователям безопасный доступ к этим ресурсам, поэтому библиотека вполне подойдёт. Многие ресурсы не нуждаются в мультиплексировании ещё одним сервисом, потому что относятся к одной или нескольким из перечисленных категорий:
- они быстро создаются (поэтому мы можем просто создавать их на лету в библиотеке)
- их создание малозатратно (поэтому мы можем дать каждому пользователю собственный ресурс)
- они уже мультиплексированы и их можно безопасно передавать (удивительно, насколько просто забыть этот пункт, если не думать о нём)
- их легко можно настраивать так, чтобы делать их общими (например, ресурс можно предоставить в «аренду» пользователю, а затем выполнить его сброс после завершения работы)
- они безопасны или их можно сделать безопасными, чтобы напрямую передавать пользователям
Тщательно поразмыслите над этим, данный пункт часто неочевиден. - Допустим, мы на самом деле не можем предоставить пользователям доступ к низкоуровневым примитивам. Но это не означает, что сервис — это единственный вариант для обеспечения разделения полномочий между пользователем и библиотекой.
Если пользовательский код выполняется на достаточно совершенной платформе, не администрируемой пользователем, то библиотека может безопасно манипулировать ресурсами, недоступными для остальных частей программы. Примеры:
- Объект типобезопасного языка может содержать возможности для ресурсов, которые он использует для реализации своих методов, без этих возможностей будучи доступным коду, вызывающему эти методы.
- Проверка стека в стиле Java может ограничивать пользовательский код или код библиотеки, не позволяя получать во время выполнения доступ к неавторизованным методам.
- Capability-safe architectures, например, CHERI, не позволяют коду получать доступ к памяти, для которой он не имеет явно заданной возможности (capability).
- Локализация ошибок ПО (Software fault isolation) способна обеспечить создание «шлюзов вызовов» в стиле Multics, в которых библиотека имеет уровень привилегий, отличающийся от уровня другого кода.
Безусловно, самым распространённым является только первый пункт. - Обеспечение стабильного интерфейса с обратной совместимостью — относительно простой для сервисов процесс благодаря поддержке, предоставляемой многими стандартными протоколами с функциями, упрощающими совместимость (буферы протоколов, JSON, и т.п.).
Однако то же самое возможно и при использовании библиотеки. На самом деле, библиотека в этом случае всегда мощнее; ничто не мешает использовать те же протоколы для локальной библиотеки и иметь такие же преимущества совместимости. - При необходимости обновлять библиотеку можно и без вмешательства пользователя, благодаря применению динамического связывания библиотеки. Для получения новых библиотек простейшему динамическому связыванию всё равно требуется перезапуск процесса, однако более продвинутые техники, например, автоматическая перезагрузка библиотеки при каждом вызове, позволяет выполнять обновления в любой момент, даже если пользователи об этом не знают.
В наши дни динамическое связывание часто критикуют по тем же причинам, по которым критикуют обновление сервиса без участия пользователей, поэтому тщательно взвесьте, хотите ли вы идти таким путём. Если вы полностью избежите сервисов, то подобные обновления будут необязательными.
Воспользовавшись этой и другими идеями, зачастую можно создать вместо сервиса библиотеку.
Благодаря отсутствию затрат на поддержку и обновление, связанных с сервисами, библиотеки могут содержать в себе бОльшую функциональность, а это идёт на пользу и разработчику, и пользователю.
На правах рекламы
VDSina предлагает VDS в аренду под любые задачи, огромный выбор операционных систем для автоматической установки, есть возможность установить любую ОС с собственного ISO, удобная панель управления собственной разработки и посуточная оплата тарифа, который вы можете создать индивидуально под свои задачи.