Пример полезности архитектурного программирования

Недавно я, «Не корысти ради, а токмо волею пославшей мя супруги», был вынужден посмотреть изнутри на настройки Apache для поддержки https. Не буду приводить детали, и те слова, которые я говорил, пока в этом разбирался. Напомню только известный анекдот:

  • Мама, папа с лестницы упал!
  • И что он сказал?
  • Если маты убрать, то молча упал.

Итак, что у нас есть — есть несколько SSL и TLS протоколов, при этом новые протоколы появляются, потому что в предыдущих находятся уязвимости (например в TLS 1.0/1.1 и SSL 2.0/3.0). Кажется, в чем проблема — отключаем дырявые протоколы, оставляем не дырявые.

Увы, проблема есть. Есть старые системы, например, Windows Vista или Android 4, в которых было трудно поддержать хорошие протоколы, потому что этих протоколов тогда еще не было.

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

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

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

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

Сценарий 2 (глобальный): Обнаружена уязвимость в протоколе, выпущена новая версия. Некий ответственный центр принял решения о переходе на новый протокол, выпустил новую (одну!) арку и выставил глобальное уведомление. Любое устройство, проверив уведомление, и, если угроза существенная, выполнит обновление, возможно, запросив разрешение у хозяина.

Не важно, на каком языке программирования написана эта единственная арка, главное то, что она переведена в промежуточный код (типа Rust MIR) и теперь при запросе с устройства, промежуточный код арки будет переведен в бинарный для целевой машины и закеширован. Следующий запрос с такого же устройства выдаст код из кеша. И вуаля, мир проснулся, а уязвимости уже нет.

Весело? Безусловно. Страшно? Даже очень. Надо очень серьезно выстраивать защиту. Ну хорошо, не обязательно одна арка и один ответственный центр на все виды устройств, пусть несколько.

Все равно, это принципиально другой мир.

PS. Вовсе не обязательно, чтобы система целиком была сделана на основе архитектурного программирования, достаточно выделить «точки расширения» или «точки замены» и в них поставить разъемы и подключить арку.

12 комментариев


  1. Доброго времени суток. Ну а что, если никто не сделал арку для Windows Vista, потому что поставщик списал эту систему и хочет, чтобы пользователи перешли на другую. А пользователи не хотят платить деньги, тратить время и терять полезные возможности и поэтому остаются на старой системе. Как тут поможет архитектурность веб-сервера, на который они заходят со своего устройства, на котором нет новой версии протокола, и при чём тут архитектура веб-сервера вообще?

    Ответить

  2. Далее, если мы посмотрим, чем отличаются версии протокола и какие в них уязвимости, то выясняется, что в версии 1.0.1 было реализовано расширение протокола Heartbeat, позволявшее контролировать, что соединение не отвалилось, за счёт периодической подачи сигнала. В этом механизме была знаменитая уязвимость HeartBleed (сигнал как раз и содержал краденую информацию), которая угрожала в том числе и безопасности сервера, но вопрос не в том. Вопрос в том, что версия 1.0.1 является несовместимой «аркой» с предыдущими, поскольку в ней появился один новый разъём. Мы можем её поставить в старую систему, но не сможем ей управлять, т.к. в ответной части нет соответствующей галочки, через которую осуществляется управление. Если бы речь шла о микросхеме, то получалось бы, что в новой микросхеме больше ножек. Как предлагается решать такие ситуации?

    Ответить

    1. 1) Аналогия с микросхемой хорошая, но как и всякая аналогия не совсем точна. Например, (почти) любой арке для работы нужна оперативная память, то есть нужен «сервис» управления памятью. Скорее всего, нужны и другие сервисы, например, журнал (log), или работа с файлами. То есть, кроме разъемов нужна «платформа», которая обеспечивает работу, и, одновременно, является изолирующим слоем. В Вире такая была. Разделение на платформу (к которой может получить доступ любая арка) и собственные разъемы арки — это конкретная архитектура. Если в платформе есть работа с сокетами, то доп. разъема не надо. Или уже был разъем к сокету и надо добавить только логику работы. Точнее можно сказать, лучше понимая логику работы протокола.

      2) Допустим, что то, что в 1) не применимо в данном случае. Значит, надо заменить не одну арку, а несколько.

      Понятно, что и 1) и 2) это общий подход. Вся эта протокольная кухня, нужна всего лишь для показа того, как это глупо сейчас устроено.

      Ответить

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

    * пускать человека в автомобиль и из автомобиля
    * не пускать человека в автомобиль, если машина на замке
    * не выпускать человека из автомобиля, если машина на замке внутри, чтобы он не выпал

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

    Что дальше?

    * защищать от шума, ветра и пыли
    * пропускать свет (через неё смотрят в зеркальце)
    * пропускать воздух, когда надо (и эту функцию она делит с вентилятором и кондиционером)
    * защищать от ударов при ДТП, это она плохо делает, но в бронеавтомобиле она даже защищает от пуль

    Где здесь принцип Single Responsibility? Нету его. Просто раньше я приводил примеры из биологии, допустим, давайте выделим из организма печень и попробуем ей назначить некую одну функцию. Не получится так. Даже голова имеет несколько функций «а ещё я в неё ем», как сказал тот боксёр. Мы сразу приходим к тому, что принципы архитектуры являются некоей сказкой про Деда Мороза, или раем для программиста. В крайнем случае, можно сделать автомобиль, в котором будет отдельная дверь и отдельное окно. Программисты на таком не станут ездить, я думаю, но их пользователи зачастую на таком ездят.

    Но это уж так, просто мысли наутро по теме. Хотелось бы понять всё же, в чём Ваши идеи состоят.

    Ответить

    1. Если Вир — это мечта, то мечта воплощенная. И доказавшая для меня свою ценность.

      Пример с печенью интересный. Вот что нам пишут:

      Печень относится к пищеварительной системе, выполняет следующие основные функции:

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

      Явно компонента, на мой взгляд. Выделена из остальной системы и соединена разъемами. И, кстати, подключена к платформе — например, кровообращение.
      Single Responsibility? А зачем? Я уж точно нигде не упоминал.

      Single Responsibility полезен как «костыль» типа — не разделяй то, что надо делать вместе, на несколько частей. Но и это, далеко не всегда применимо. А если мне надо распараллелить задачу для масштабирования. Или запустить дополнительный (упрощенный) алгоритм для проверки основного? Или часть функциональности работает на одном устройстве, а часть на другом?

      То есть вот в этом, вроде как, классическом определении: The Single Responsibility Principle (SRP) is one of the SOLID principles in software engineering that states that every module or class should have only one responsibility and that responsibility should be entirely encapsulated within the class.

      «that every module or class should have only one responsibility» — это вообще бред. Софистика чистой воды. Библиотека работы с файлами — это single responsibility? Или надо разделять открыть/закрыть файл и читать/писать. Благоглупость.

      «entirely encapsulated within the class» — с этим тоже я бы поспорил. Почему? Кажется, в 2019 году на открытой конференции в ИСП я говорил про защиту — о том, что не надо защищаться от себя. Надо защищаться от врага. И так далее.

      Я вообще очень скептически отношусь ко всем «software principes» и «patterns». Любой принцип хорош в том месте, где его можно применить, и плох во всех остальных местах.

      Ну а про дверь мне скучно думать, вот про печень было интересно. Спасибо.

      Ответить

  4. Так я ж не говорю, что ВИР был бесполезен, я говорю, что я не понял. Честно сказать, доклад про ВИР я и не особо внимательно слушал. Но зачем говорить про ВИР, если сейчас Вы занимаетесь уже новым. Видимо, оно должно учесть опыт ВИРа и его превзойти. Сейчас Вы вводите понятие Арки, а где оно определено и что означает, если это, конечно, не «секрет фирмы»? Видимо, это не модуль и не «объект в смысле C++». Возможно, что-то от слова «архитектура». Вот я и отреагировал на это слово, чтобы хоть как-то понять. Хорошо, что у нас мнения сошлись на тему «S». Но пока понятнее не стало.

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

    Я потому и стараюсь уклониться от примеров рассмотрения живого, что оно слишком сложное для нас и мы его не понимаем. Особенно кто не медик. Лично мой уровень — это дверь, не более того. Хотя дверь не может выполнять функции других деталей автомобиля — тут явно архитекторы автомобиля до Творца не дотягивают по каким-то параметрам.

    Ответить

  5. Я тоже думаю, что описанное — мечта любого квалифицированного программера. При необходимости изъял компонент, новый поставил — и все работает.
    Если б системы проектировали разрабатывали алексеинедори — оно так бы и было. Но беда в том, что основная масса программеров не дотягивает даже до его колена, не говоря уж до пояса.
    Именно потому, что массовый программер достаточно низкого уровня, в гугле сделали Go — для этих самых массовых программеров, которым думать некогда — надо код педалить. При этом не совершая ошибок.

    Ответить

    1. Про «основную массу программистов» коротко написать не могу, может, напишу когда-нибудь.

      А что касается Go — то мое отношение к нему совсем другое. Это язык, который я уважаю, хотя и считаю ошибочными часть решений. Если надо «код педалить», то это, скорее, JavaScript. А Go — язык строгий и требующий перестройки привычек. Пусть в меньшей степени, чем Rust, но все же требующий.

      Ответить

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

      Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *