Посмотрите на этот запрос:

SELECT c.id, c.name, c.address, o.items FROM customers c
JOIN orders o
ON o.customer_id = c.id
GROUP BY c.id

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

Теперь подумайте о реализации Java. Мы могли бы объявить классы для Customer и Order. Я помню, как благонамеренные консультанты говорили, что нам также следует создавать классы для инкапсуляции их коллекций, а не использовать «голые» коллекции Java. Нам по-прежнему нужно запрашивать базу данных, поэтому мы подключаем объектно-реляционный преобразователь (ORM) и пишем для этого код. Четыре строчки кода быстро превращаются в десятки, а то и сотни строк. Несколько минут, которые потребовались для написания и уточнения SQL-запроса, растянулись на часы или дни редактирования, написания модульных тестов, проверки кода и так далее.

Разве мы не можем просто реализовать все решение, используя только SQL-запрос? Мы уверены, что не можем? Даже если мы действительно не можем, можем ли мы избавиться от лишнего и писать только то, что необходимо? Рассмотрим качества SQL-запроса:

  • Нам не нужна новая таблица для выходных данных объединения, поэтому мы ее не создаем:Самым большим недостатком прикладного объектно-ориентированного программирования было убеждение, что вы должны точно воспроизводить вашу модель предметной области в коде. На самом деле несколько определений основных типов полезны для инкапсуляции и понимания, но кортежи, наборы, массивы и т. д. — это все, что нам нужно в остальное время. Ненужные классы становятся обузой по мере развития кода.
  • Запрос является декларативным:он нигде не сообщает базе данных, как выполнять запрос, он просто устанавливает реляционные ограничения, которым должна удовлетворять база данных. Java — императивный язык, поэтому мы склонны писать код, который говорит, что делать. Вместо этого мы должны объявить ограничения и желаемые результаты, а затем изолировать реализацию как в одном месте или делегировать ее библиотеке, которая может реализовать ее для нас. Как и функциональное программирование, SQL является декларативным. В функциональном программировании эквивалентные декларативные реализации достигаются с помощью составных примитивов, таких как map, filter, reduce и т. д.
  • Специфический для предметной области язык хорошо подходит для решения проблемы: DSL могут быть несколько противоречивыми. Очень сложно создать хороший проект, а реализация может быть запутанной. SQL — это DSL данных. Это причудливо, но его долговечность является доказательством того, насколько хорошо он выражает типичные потребности в обработке данных.

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