Те, що багато реалізацій об’єктів – це надбудови над звичайними структурами, відволікає від головного: ООП – це не про методи замість функцій, а про коммунікацію між одиницями коду (об’єктами) через відправку повідомлень (асинхронно). Детальніше про власне розуміння ООП я писав у Що я розумію під об’єктною орієнтованістю, а ця публікація про те, що тотожність між типами і класами може бути легко порушена, що типи можуть втрачати сенс і що “Наказуй, а не запитуй” (TDA – Tell, Don’t Ask) – це не просто якийсь-там принцип, а лаконічно викладена суть ООП.
Найпростішим прикладом порушення TDA і неявного створення підтипів є використання методів-предикатів, накшталт: .isEven(), .isValid(), isPersisted() і т.п. Справа у тому, що якщо ми десь запитуємо в об’єкта про його стан, то використовуємо його не вірно.
Об’єкт має отримувати певне повідомлення та якось на нього реагувати, а користувач об’єкта має відправляти об’єкту повідомлення, аби той на них якось реагував. Якщо ми використовуємо методи – предикати, то у такий спосіб не користуємося поведінкою об’єкта, а вчиняємо над ним дії.
Крім того, використання методів-предикатів створює неявні підтипи. Наприклад, якщо ми можемо виконати певну дію лише якщо метод-предикат isEven() об’єкта повертає значення true, то це означає, що у сигнатурі функції міститься тип, який не описує вичерпно множину значень на якій ця функція дійсно визначена і тому вона має виконувати додаткові перевірки та обробляти ситуації заходу в глухий кут.
Далі розглянемо популярний метод в Ruby on Rails (ActiveRecord) #valid? Що він взагалі означає?! Він означає, що об’єкт може бути неправильним, тобто не відповідати власному типу! Сам фреймворк підштовхує обходити систему типів та продукувати складний для розуміння код.
Залишити відповідь