Статьи

Свободные интерфейсы плохи для обслуживания

Свободный интерфейс , впервые введенный в качестве термина Мартином Фаулером, является очень удобным способом общения с объектами в ООП. Это делает их фасады проще в использовании и понимании. Однако это разрушает их внутренний дизайн, делая их более сложными в обслуживании. Несколько слов было сказано об этом Марко Пиветтой в его посте « Свободные интерфейсы — зло» ; Теперь я добавлю свои несколько центов.

Донни Браско (1997) Майк Ньюэлл

Давайте возьмем мою собственную библиотеку jcabi-http , которую я создал несколько лет назад, когда думал, что хорошие интерфейсы — это хорошо. Вот как вы используете библиотеку для создания HTTP-запроса и проверки его вывода:

1
2
3
4
5
6
String html = new JdkRequest("https://www.google.com")
  .method("GET")
  .fetch()
  .as(RestResponse.class)
  .assertStatus(200)
  .body();

Этот удобный метод цепочки делает код коротким и очевидным, верно? Да, это так, на поверхности. Но внутренний дизайн классов библиотеки, включая JdkRequest , который вы видите, очень далек от элегантности. Самая большая проблема в том, что они довольно большие, и это

сложно
невозможно расширить их, не делая их еще больше.

Например, сейчас у JdkRequest есть методы method() , fetch() и некоторые другие. Что происходит, когда требуется новая функциональность? Единственный способ добавить к нему — увеличить класс, добавив новые методы, что ставит под угрозу его ремонтопригодность. Вот , например, мы добавили multipartBody() и здесь мы добавили timeout () .

Мне всегда страшно, когда я получаю запрос на новую функцию в jcabi-http. Я понимаю, что это, скорее всего, означает добавление новых методов к Request , Response и другим уже раздутым интерфейсам и классам.

Я действительно пытался что-то сделать в библиотеке, чтобы решить эту проблему, но это было нелегко. Посмотрите на этот .as(RestResponse.class) метода .as(RestResponse.class) . То, что он делает, это украшает Response с RestResponse , чтобы сделать его более богатым методом. Я просто не хотел, чтобы Response содержал более 50 методов, как это делают многие другие библиотеки. Вот что он делает (это псевдокод):

01
02
03
04
05
06
07
08
09
10
11
class Response {
  RestResponse as() {
    return new RestResponse(this);
  }
  // Seven methods
}
class RestResponse implements Response {
  private final Response origin;
  // Original seven methods from Response
  // Additional 14 methods
}

Как видите, вместо добавления всех возможных методов в Response я поместил их в дополнительные декораторы RestResponse , JsonResponse , XmlResponse и другие . Это помогает, но для того, чтобы написать эти декораторы с центральным объектом типа Response мы должны использовать этот «уродливый» метод as() , который сильно зависит от Reflection и приведения типов .

Свободные интерфейсы означают большие классы или некоторые уродливые обходные пути.

Другими словами, свободные интерфейсы означают большие классы или некоторые уродливые обходные пути. Я упоминал об этой проблеме ранее, когда писал о Streams API и интерфейсе Stream , который прекрасно понимается. Есть 43 метода!

Это самая большая проблема с беглыми интерфейсами — они заставляют объекты быть огромными.

Свободные интерфейсы идеально подходят для их пользователей, поскольку все методы находятся в одном месте, а количество классов очень мало. Их легко использовать, особенно с автозавершением кода в большинстве IDE. Они также делают клиентский код более читабельным, так как «плавные» конструкции выглядят аналогично простому английскому языку (он же DSL ).

Это все правда! Однако ущерб, который они наносят объекту дизайна, — это цена, которая слишком высока.

Какая альтернатива?

Я бы рекомендовал вам использовать декораторы и смарт-объекты . Вот как я бы разработал jcabi-http, если бы я мог сделать это сейчас:

1
2
3
4
5
6
7
8
9
String html = new BodyOfResponse(
  new ResponseAssertStatus(
    new RequestWithMethod(
      new JdkRequest("https://www.google.com"),
      "GET"
    ),
    200
  )
).toString();

Это тот же код, что и в первом фрагменте выше, но он гораздо более объектно-ориентирован. Конечно, очевидная проблема с этим кодом заключается в том, что среда IDE не сможет автоматически завершить почти все. Также нам придется запомнить многие из названий классов. И конструкция выглядит довольно трудно читать для тех, кто привык свободно говорить интерфейсы. Кроме того, это очень далеко от идеи DSL.

Свободные интерфейсы хороши для пользователей, но плохи для разработчиков. Небольшие объекты хороши для разработчиков, но сложны в использовании.

Но вот список преимуществ. Во-первых, каждый объект маленький, очень сплоченный, и все они слабо связаны, что является очевидным достоинством в ООП. Во-вторых, добавить новую функциональность в библиотеку так же просто, как создать новый класс; не нужно трогать существующие классы. В-третьих, модульное тестирование упрощено, так как классы небольшие. В-четвертых, все классы могут быть неизменяемыми, что также является очевидной заслугой в ООП.

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

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

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

Таким образом, больше нет свободных интерфейсов от меня, только объекты и декораторы.

Опубликовано на Java Code Geeks с разрешения Егора Бугаенко, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Свободные интерфейсы вредны для обслуживания

Мнения, высказанные участниками Java Code Geeks, являются их собственными.