Fear of Decoupling

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Объекты общаются между собой с помощью своих методов. В основных языках программирования, таких как Java или C#, объект может иметь уникальный набор методов вместе с некоторыми методами, которые он обязан иметь, потому что реализует определенные типы, также известные как интерфейсы. Мой опыт общения с многими программистами говорит мне, что большинство из нас довольно пугаются объектов, которые реализуют слишком много методов интерфейса. Мы не хотим иметь с ними дело, поскольку они полиморфны и, из-за этого, ненадежны. Это справедливый страх. Давайте попробуем проанализировать, откуда он берется.

Как обычно, давайте начнем с простого примера на Java. Вот сумма денег, которую я собираюсь отправить пользователю, скажем, через API PayPal:

Вот я здесь, метод, который отправляет деньги:

Эти два фрагмента кода, как мы их называем, слабо связаны. Метод send() не имеет представления о том, какой класс предоставлен и как именно реализован метод cents(). Возможно, это простой постоянный объект в один доллар.

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

Метод send() не знает, что именно передается в качестве его первого аргумента. Все, что он может сделать, это надеяться, что метод cents() выполнит свою работу правильно. А что, если это не так?

Если я являюсь разработчиком метода send() и я полностью готов взять на себя ответственность за ошибки, которые мой метод может вызвать, мне действительно хочется знать, кто мои коллеги. И я хочу быть абсолютно уверенным в их работе. Не просто работе, но работе именно так, как я ожидаю. Я бы предпочел написать их сам. Идеально было бы гарантировать, что никто их не трогает после моей реализации. Ты понимаешь сарказм, верно?

Кажется, что это шутка, но я слышал этот аргумент много раз. Говорят: “лучше быть полностью уверенным, что две части взаимодействуют, вместо того чтобы полагаться на чертову полиморфность и затем тратить часы на отладку чего-то, что я не написал”. И они правы, знаешь ли. Полиморфизм - это когда кажущийся примитивный объект типа Money делает все, что хочет, включая HTTP-запросы и SQL-запросы UPDATE - он не добавляет надежности всему приложению, правда?

Очевидно, полиморфизм делает жизнь разработчиков этого типа Money и его “предков” гораздо проще, поскольку им не нужно много думать о пользователях. Все, о чем они заботятся, - это как вернуть double, когда вызывается cents(). Им не нужно беспокоиться о скорости, возможных исключениях, использовании памяти и многих других вещах, так как интерфейс не требует этого. Он просто говорит им вернуть double и считать это завершением работы. Пусть кто-то другой беспокоится обо всем остальном. Просто, верно? Но вы можете сказать, что это детское и эгоистичное мышление!

However…

Вы наверняка слышали о концепции “Fail Fast”, которая вкратце утверждает, что для того, чтобы сделать приложение надежным и стабильным, мы должны убедиться, что его компоненты максимально хрупкие и уязвимые в ответ на любую возможную исключительную ситуацию. Они должны ломаться всякий раз, когда только могут, и позволять пользователям справляться с ошибками. С такой философией ни один объект не будет предполагать что-либо хорошее о своих соратниках и всегда будет стремиться эскалировать проблемы на более высокие уровни, что в конечном итоге скажется на конечном пользователе, который сообщит о них команде. Команда исправит все ошибки, и весь продукт стабилизируется.

Если философия противоположная и каждый объект пытается справиться с проблемами на своем индивидуальном микроуровне, большинство исключительных ситуаций никогда не станут видимыми для пользователей, тестировщиков, архитекторов и программистов, которые должны заниматься ими и находить для них решения. Благодаря такому “осторожному” подходу индивидуальных объектов стабильность и надежность всего приложения будут страдать.

Мы можем применить ту же логику к “страху перед связностью”.

Когда мы беспокоимся о том, как работает Money.cents() и хотим контролировать его поведение, мы делаем себе и всему проекту большую несправедливость. В конечном итоге мы разрушаем продукт, вместо того чтобы сделать его более стабильным. Некоторые даже хотят запретить полиморфизм, объявляя метод send() таким образом:

Здесь мы ограничиваем количество ошибок в нашем коде, поскольку мы знаем Бобби, мы видели его код, мы знаем, как он работает и какие исключения ожидать. Мы в безопасности. Да, мы в безопасности. Но, стратегически говоря, не позволяя нашему программному обеспечению делать все возможные ошибки и выбрасывать все возможные исключения во всех необычных ситуациях, мы серьезно ограничиваем его способность к правильному тестированию, и поэтому оно нестабильно.

Как я упоминал ранее, единственный способ повысить качество программного обеспечения - найти и исправить его ошибки. Чем больше ошибок мы исправляем, тем меньше остается скрытых и пока не исправленных ошибок. Страх перед ошибками и наше намерение предотвращать их - это только причиняет нам вред.

Вместо этого, мы должны позволить каждому, не только Бобби, реализовывать Money и передавать эти реализации в send(). Да, некоторые из них могут вызвать проблемы и даже привести к видимым для пользователя сбоям. Но если наше руководство правильно понимает понятие качества программного обеспечения, они не будут винить нас за ошибки. Вместо этого, они будут поддерживать нас в поиске как можно большего их количества, воспроизведении их с помощью автоматических тестов, исправлении и повторном развертывании.

Таким образом, страх перед отсоединением - это ничто иное, как система аварийной защиты.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-18 at 05:30

sixnines availability badge   GitHub stars