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