Дисклеймер: все нижеописанное относится к использованию ООП в бизнес-приложениях и я бы хотел вынести за скобки применение ООП для описания типов вроде int, string и т.д. Концепцию ООП часто применяют для отражения объектов реального мира в коде программ. Так объект реального мира "Пользователь" может быть описан в коде как класс "Пользователь", у которого есть поля: имя и адрес электронной почты, а действия, которые можно совершить над объектами реального мира, превращаются в методы класса: назначить администратором, удалить учетную и т.д.  В простых учебных примерах такой подход позволяет познакомить начинающих программистов с основными инструментами ООП. Но когда дело доходит до более сложных примеров, кол-во методов в классе растет, а с ними и количество строк кода — код становится сложно читаемым. Но, главное, связь между объектами реального мира, когда изменение одного объекта влечет за собой изменение другого (удаление учетной записи пользователя, приводит к удалению учетной записи из всех списков где она была отмечена), сложно отразить в коде одного класса. Для меня апофеозом такого подхода стал проект eShopOnContainers, когда для решения, казалось бы, простой задачи, которая была решена уже тысячи раз, приходится писать огромное кол-во строк кода. Связь того, как изменение состояния одного объекта влияет на другой объект, прослеживается не явно, через очередь событий и несколько классов. Кол-во зависимостей, требующихся для инстанцирования одного класса, растет, что приводит к сложности использования такого класса как в приложении, так и в тестах. Вдобавок к этому, в современных системах практически отпала потребность хранить состояние объектов в приложении, все состояние хранят специализированные системы: базы данных или внешние сервисы (которые в итоге хранят его в БД). Задача многих приложений сводится к отображению состояния сущностей в разных проекциях и предоставлению методов изменения состояния с учетом правил предметной области этих приложений. В общем виде это можно представить как методы получения данных для отображения части состояния объекта и методы для изменения состояния. Описание и хранение самого состояния в приложении не требуется. В классах-проекциях (Data Transfer Object), которые передают данные между слоями приложения, не требуется иметь методов изменения состояния. Тогда возникает вопрос, где же хранить методы, позволяющие получить состояние или изменять его? Мы в Retail Rocket пришли к решению сделать по одному классу на каждую такую задачу. Те классы, которые относятся строго к одному объекту, можно сгруппировать в папке с именем этого объекта, а те, что, например, меняют состояние более одного класса, положить в папку с именем Services. Зачем же тогда нужен ООП, если все приложение — это набор функций? Для локализации границ зависимостей функции. ООП позволяет элегантно описать зависимости, которые требуются "функции". Вот пример "функции", которая меняет состояние системы Для работы этой функции требуется 1 внешняя зависимость в виде интерфейса к конкретной коллекции в базе данных, ее мы и принимаем через конструктор и сохраняем в private поле. Вот пример использования такой функции в MVC контроллере Данный подход меняет привычное использование концепции ООП как способ описания объектов реального мира, на способ описания функции с ее аргументами, возвращаемым значением и зависимостями (сайд эффектами). Технический директор