Простые решения могут быть хорошими
В прошлый раз я написал статью, в которой предложил несколько идей, как решить проблемы, задействовав простые инструменты, предлагаемые операционной системой. Мы увидели, как легко решать задачи, обычно связанные со сложными платформами и библиотеками. Цель статьи состояла в том, чтобы заставить нас подумать о тех случаях, когда мы могли решить сценарий, используя более простые инструменты, возможно, даже предлагаемые операционной системой, но предпочитали использовать архитектурные решения по умолчанию только потому, что они являются нормой.
На этот раз мы поговорим о других примерах, когда архитектура мешает развитию, а не помогает ему, опять же не для того, чтобы разрушить существующие и проверенные парадигмы, а для того, чтобы поставить под сомнение значения по умолчанию и, возможно, взглянуть на вещи по-новому. В первом примере снова будет ситуация, которая была у меня на одной из моих предыдущих работ.
Высокая безопасность входа в систему, которая защищает тривиальные данные
Мы обсуждали повторную реализацию входа в систему для нашего веб-приложения и обсуждали идеи. Во-первых, логин работал нормально, проблем с ним не было. Это был простой вход в систему, безопасный, с именем пользователя и паролем, шифрование выполнялось в соответствии с последними тенденциями: все хорошо. Но архитектор команды не был удовлетворен. Он только что прочитал о токене на предъявителя и о входе в систему с токеном обновления и хотел перенести все логины в компании на это по причинам.
Это не было проблемой. Замена простой системы входа в систему на лучшую схему входа должна того стоить. Дискуссия быстро переросла в поиск все более и более безопасных способов справиться с ситуацией, когда токен был украден. Совещания проводились, тестировщики приходили с большим количеством крайних случаев, каждый острее другого, был задействован кеш Redis, обсуждались эксплойты Redis, это действительно выходило из-под контроля. В конце концов, после многих совещаний, посвященных самым нелепым способам защиты входа пользователей, я задал вопрос: что мы пытаемся здесь защитить?
Имея дело со сложными решениями, мне всегда нравится время от времени делать шаг назад и пересматривать постановку задачи. Мы все еще реализуем то, что хотели изначально? Мы все еще реализуем то, что нам нужно? Конечно, я делаю что-то по прихоти архитектора. Но когда обсуждаемые решения становятся смешными, пришло время вернуться к исходной истории. Что мы пытаемся здесь сделать? Какие данные мы пытаемся защитить? Данные банка? Медицинские данные? Потому что в противном случае инвестиции в безопасность данных на государственном уровне — пустая трата времени на разработку. Хорошее упражнение, но не более того. Но это не случалось ни разу, что приводит меня к следующему пункту.
Архитектура для необоснованной масштабируемости
Много раз, думая об одном приложении, со мной случалось, что я начинал думать о далеком будущем, о времени, когда у приложения будет миллион пользователей, серверы будут затоплены, и мне нужно будет прыгать по информационным панелям Azure, пытаясь сдержать кризис. Многие компании задумываются о балансировке нагрузки с самого начала, даже несмотря на то, что всего у них несколько сотен тысяч пользователей, не говоря уже о том, что только сотни из них находятся в сети в данный момент.
Даже если количество пользователей растет, спешка с развитием инфраструктуры должна быть временным решением, пока вы не выясните, почему общая производительность низкая. И почему производительность медленная, начинает быть забытым вопросом, для некоторых даже запретным. Мы больше не спрашиваем об этом, мы просто увеличиваем количество серверов. Серверы — это крупный рогатый скот в облаке, поэтому нам все равно. Это очень расточительное мышление. Хорошо не думать о своих серверах, но нехорошо тратить ресурсы только потому, что вы можете.
Но это только о ресурсах, а как насчет архитектуры? А как насчет того, чтобы сознательно выбирать варианты разработки программного обеспечения, не нужные для вашего небольшого проекта, просто потому, что в ваших мечтах вы готовитесь иметь команду из 30 разработчиков, каждый из которых будет работать над одной и той же частью кода? Как это проявляется на практике? У меня есть другой пример на этот счет.
Внедрение зависимостей ради этого
Опять же, это просто пример, и я не хочу создавать впечатление, будто нам не нужна хорошая архитектура. Все проекты, над которыми я работаю, сильно выигрывают от многих функций внедрения зависимостей. Я просто привожу это в качестве примера, потому что мне нравится провоцировать вас самым худшим образом. Но, экстраполируя отсюда, вы можете предположить, что много раз вы применяли шаблон только потому, что использовали его везде, а не потому, что он что-то добавлял в проект.
Некоторое время назад это был небольшой проект, я даже не помню компанию. У него был небольшой пользовательский интерфейс, куда вы могли что-то загрузить, и процессор, объединяющий несколько типов файлов. Ничего страшного, но как пример вполне годится. Мы точно знали, сколько типов файлов, и мы точно знали, что это никогда не изменится при нормальных обстоятельствах. Но эта часть «нормальных обстоятельств» нас беспокоила. Нам нужно было решение, которое работало бы для всех файлов. И это положило начало падению.
Мы разделили процессоры на свои проекты, реализовали внедрение зависимостей, настроили контейнеры, родились сервисы, мы даже добавили слой базы данных на всякий случай, хоть мы и имели дело с файлами. Мы готовили архитектуру к росту, изменению, все включено. О чем мы забыли, так это о разработчиках и усилиях по разработке. Приложение стало настолько большим, что было смешно узнать, что оно на самом деле делает.
Вишенкой на торте была инъекция зависимостей. Это было абсолютно бесполезно. Он ничего не делал, ничем не помогал, мы всегда точно знали, какие инстансы нам нужны, даже юнит-тестов не делали. Итак, вот ловушка: да, но, может быть, однажды мы начнем создавать модульные тесты. И это такая сумасшедшая ловушка, потому что вы, как разработчик, знаете, что это правда. Вещи меняются, они всегда меняются. Как можно было не подготовиться ко всем возможным изменениям? Заманчивое решение, однако, также может стать причиной провала проекта. Подумайте, прежде чем применять гибкость в своем проекте. Может быть, он вам сейчас и не нужен, а может быть, через пять лет, когда он вам понадобится, приложение все равно потребует переписать.
Микросервисы должны быть крутыми
Я закончу с этой последней тенденцией. Но вместо микросервисов можно говорить любую трендовую архитектуру. Можно даже назвать любую трендовую технологию: React, Rust, вообще что угодно. Как архитектор, вы не хватаетесь за решение только потому, что оно новое. Вы делаете это не потому, что это круто и модно. Вы взвешиваете его полезность для вашего проекта.
В качестве примера я все еще могу использовать один из предыдущего заголовка, где каждый процессор был службой. Наш веб-сервер выглядел как рождественская елка со всеми процессорами в качестве REST-сервисов. Количество проектов, целей развертывания, шагов развертывания, строк кода — все было настолько раздутым только потому, что вместо того, чтобы изначально решить просто иметь одно решение .NET с консольным проектом и несколькими службами в папке, мы выбрали полный -проработанная бизнес-архитектура корпоративного уровня. По сути, для инструмента загрузки файлов. Просто потому, что мы хотели охватить последние тенденции и невозможный рост и изменение.
Микросервисы или любая другая архитектура должны прийти на помощь, они должны избавить разработчиков от сложности. Если это создает сложность, архитектура неверна. И это еще не все. Сегодня много программного обеспечения, например, написано на .NET. Что ж, мы могли бы добавить и Node.js. Но если при разработке программного обеспечения вы начинаете бороться с платформами, языками программирования, архитектурами и библиотеками, это верный признак того, что вы ошиблись. Если все ваше программное обеспечение написано на одном языке программирования, это признак того, что вы используете один инструмент для всех целей. Рано или поздно вы будете с этим бороться.
Я надеюсь, что мои примеры были не просто указанием на мой нелепый карьерный путь, но они также дают некоторое представление любому разработчику, новому или старому, о том, как технические решения, которые кажутся хорошими и правильными, могут привести проект к преждевременной кончине. Я надеюсь, что эти примеры заставят вас задуматься и подвергнуть сомнению проверенные и верные архитектурные решения, а также спровоцируют вас не бояться использовать более простые решения.
Более простые решения могут создать впечатление, что разработчики мало разбираются в разработке программного обеспечения. Но, честно говоря, если я оглядываюсь назад, я вижу, что много раз более простое решение дало бы гораздо лучшую разработку и пользовательский опыт в целом. Не беспокойтесь о будущих статьях по архитектуре, я обычно вообще не говорю на эту тему, но мне захотелось поделиться несколькими хорошими примерами. Увидимся в следующий раз!