Как бы вы назвали класс, у которого есть база данных и множество связанных методов?

- Привет, Алиса, мне было интересно, не могли бы вы помочь мне с одним вопросом по программированию. А именно, вторая сложная проблема в информатике.
- Конечно, как вы пытаетесь назвать?
- Я создал класс, который содержит database и предоставляет набор методов, связанных с базами данных.

- Почему бы не назвать его Repository?
- Ну, Repository на самом деле является клиентом этого класса.
Компонент, над которым я сейчас работаю, обеспечивает надежный доступ к Coffee. Одна его часть - CoffeeRepository с обычными методами поиска-поиска-получения-чего угодно. Он CoffeeRepository содержит database и множество вещей, связанных с ним, таких как количество повторных попыток, префиксы и суффиксы имен таблиц и так далее. Так что я подумал, что было бы неплохо переместить всю эту низкоуровневую механику на свое место, и теперь мне интересно, как бы было хорошее название для этого места.

- Значит, этот класс - внутренняя деталь реализации CoffeeRepository?
- Да, конечно.
- Тогда на самом деле не имеет значения, как вы его назовете. Вы могли бы назвать это даже LowLevelMechanicalCoffeeRepositoryStuff, и это было бы хорошо. Я бы назвал его как-то вроде CoffeeDatabaseUtils и перейду к работе над важными вещами.

- Да, вот что я сделал. Я назвал его CoffeeDatabaseHelper, и код сейчас находится на рассмотрении. Но этот случай до сих пор меня озадачивает. Это как песня, которую вы точно знаете, что где-то слышали, и очень стараетесь вспомнить, где именно вы ее слышали. Для этого варианта использования должен существовать шаблон проектирования; просто я его еще не опознал.

- CoffeeDatabaseHelper просто нормально. Чем больше объем объекта, тем важнее дать ему хорошее имя. Если это внутреннее дело, *Helper в порядке
- Да, эта головоломка с именами непрактична, но от этого становится еще интереснее. Разве вы не согласны с тем, что самые прекрасные вещи вообще не имеют применения в реальном мире?

- Хорошо. Что делает этот класс?
- Как я уже сказал, он содержит database и связанную с ним конфигурацию, а также предоставляет методы для получения самого database (т. Е. Получателя), имен таблиц и столбцов.
- Зачем какому-либо компоненту знать имена таблиц?
- Потому что наш CoffeeRepository строит SQL-запросы, и для этого нам нужны имена столбцов и таблиц. Было бы хорошо оставить его в CoffeeRepository, если бы эти имена были постоянными значениями, но они создаются динамически. Например. имя таблицы <Table prefix> + <Table name>, но иногда <Table prefix> + <Table name> + <Table suffix>. Имена столбцов строятся аналогично. Не спрашивайте меня, зачем мы это делаем, все было так, как было раньше, а теперь миграция потребует слишком больших усилий. Прямо сейчас все эти методы находятся в CoffeeRepository, и я хочу убрать его.

- Правильно. Напомните мне, пожалуйста, почему вы думаете, что CoffeeDatabaseUtils (или CoffeeDatabaseHelper) - плохое имя?
- Во-первых, я не ожидал, что класс *Utils будет удерживать состояние. А здесь мы держим database и его конфиг. На мой взгляд, *Utils больше похож на набор статических методов - WriteToFile, ExtractDateFromId, GenerateBackupFilePath и так далее. Кроме того, *Utils слишком общий. Вы могли бы назвать это Random*Stuff, и это было бы даже честнее, чем называть его *Utils.

- Ну, то, что вы описали, в основном случайное, не так ли? Вы пытаетесь очистить свой репозиторий и переместить все неактуальные вещи в отдельное место. Вы делаете предположение, что все эти вещи принадлежат к одному набору, и это нормально, если вы поместите их в один класс. Иногда это так, а иногда - нет. Например, как насчет класса с именем CoffeeTables, который будет предоставлять имена таблиц и столбцов?
- Хм, CoffeeTables действительно хорош. Однако есть одна проблема - для CoffeeTables нет смысла хранить database.
- Да, вам придется хранить database отдельно.
- И тогда мне нужно будет сохранить конфигурацию, например, количество повторов или время ожидания запроса также отдельно, возможно, в другом классе, например CoffeeDatabaseConfig. И у метода checkPermissions() должен быть целый отдельный класс CoffeeDatabasePermissionChecker.
Тогда это как бы нарушает всю цель этого упражнения. Дело в том, чтобы упростить CoffeeRepository, но вместо этого мы создаем несколько новых сущностей - CoffeeTables, CoffeeDatabaseConfig, CoffeeDatabasePermissionChecker. Это могло бы быть хорошо с чисто дизайнерской точки зрения, но, честно говоря, это кажется немного переосмысленным.

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

Прокси-сервер? Нет, прокси дает вам идентичный интерфейс, который является своего рода дешевым и легким заполнителем для реального объекта. Например, в некоторых странах вы все еще можете использовать ретро-метод оплаты, называемый чеками: вы записываете, сколько денег вы даете человеку, на листе бумаги, и этот человек может пойти в bank и снимите эту сумму со своего счета. Этот чек является прокси на сумму денег.

Адаптер? Это тоже не переходник. Адаптер - это когда вы хотите сделать одно и то же разными способами. Допустим, вы пишете сообщение и хотите поделиться им в Facebook, Twitter, Instagram, канале Telegram и других социальных сетях. Может быть приложение, в котором вы пишете свой пост, нажимаете «Опубликовать», и оно выполняет всю публикацию для всех платформ - каждый из классов, которые будут взаимодействовать с API конкретной платформы, будет адаптером. Здесь дело обстоит не так.

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

Фасад? Кажется, это более-менее хороший кандидат. Шаблон призван скрыть сложность и предоставить упрощенный интерфейс. Например, кредитная карта - это фасад для банковского счета. Похоже на то, что мы здесь пытаемся сделать.

Знаете что, я думаю, что фасад на самом деле неплохой выбор.

- Как вы думаете, CoffeeDatabaseFacade лучше, чем DatabaseHelper?
- DatabaseHelper немного лучше, чем DatabaseUtils в том смысле, что не будет большим сюрпризом, если *Helper сохранит какое-то состояние. Но мне все равно кажется, что это CofeeDatabaseWhatever name.
Я имею в виду, что вы читаете код и видите класс с именем CoffeeDatabaseHelper. Что это имя сообщит вам? Конечно, в этом классе есть что-то связанное с базой данных. Это команда CLI для создания дампа базы данных? Может быть. Это набор методов для предоставления нескольких экземпляров Postgres для этой базы данных? Почему нет?

- CoffeeDatabaseFacade тоже не похоже на информативное имя.
- Я бы так не сказал. Ожидаете ли вы, что CoffeeDatabaseFacade будет содержать код DevOps? Возможно нет. Конечно, когда вы видите *Facade, непонятно, что там происходит, и это странное название. Хотя теоретически он должен говорить вам, что имеет какое-то отношение к database, он специфичен для Coffee и обеспечивает упрощенный интерфейс для чего-то сложного. Но разве вы не согласны с тем, что описание узора здесь хорошо подходит?
- Думаю, можно так сказать. Не то чтобы генерация имен - это что-то действительно сложное с инженерной точки зрения, но можно сказать, что это сложно с точки зрения бизнес-логики.

- Ладно, значит, фасад. Но я согласен, что *Facade - странное имя. Как вы думаете, если бы я назвал класс CofeeDatabase? И я бы упомянул фасад в комментарии:

// CoffeeDatabase is a facade for |database|.
// It holds |database| instance and provides methods to get table
// and column names, settings like retry count or timeout, etc.
class CoffeeDatabase {
  // ...
}

- Я бы не сказал, что это лучшее имя, но и не могу сказать, что оно и слишком плохое. Допустим, все в порядке.

- Привет, Боб, как дела с тем классом CoffeeDatabase, который мы обсуждали? Вы его переименовали?
- Ну нет. Как вы указали в самом начале, этот класс является деталью реализации. CofeeDatabaseHelper - достаточно хорошее имя, и я не хотел вызывать споры о лучшем имени для внутреннего компонента. Так что нет, я его не переименовывал. Но я по-прежнему считаю наше обсуждение очень ценным мысленным экспериментом. Спасибо!