Я давно вынашивал желание написать эту статью. И, наверное, мне бы стоило потратить некоторое время на то, чтобы написать её чуть более структурно и продуманно, но, пожалуй, я её в таком случае вообще не напишу, так что - статья будет ad hock, прям from the top of my mind.
Начнём с того, что в обсуждениях объектного программирования бытуют несколько популярных мнений
ОО появилось в ОО языках. Пришёл С++ и принёс нам объектность. А до него объектности не было. Тут не важно, что первым ОО языком был не С++ - важна сама мысль: объектную ориентированность принёс ОО язык, а до него она не существовала.
ОО есть этап на пути к более крутой парадигме, которая снесёт ОО, как ОО снёс структурное программирование. Мы находимся внутри эволюционного процесса. Бардачное спагетти программирование (Фортран), структурное программирование (Паскаль, отчасти Си), объектное программирование (С++, Ява) и его заменит, например, функциональное программирование.
Объектное программирование где-то, может быть, и уместно - например, в симуляторах, а где-то прям нафиг не сдалось. И вообще, когда меня учат объектному программированию на примере класса "животные", который ветвится в собачечек и кошечек, я понимаю, что объектная парадигма - фуфло, и только на собачках худо-бедно и работает. А в реальной жизни
собачекобъектов и классов нет.
Буду краток - все три пункта выше - фи-игня. А теперь приступим.
Давайте начнём с первого же пункта. ОО появилось в ОО языках.
Нет. ОО оформилось и осозналось в ОО языках, а появилось оно сильно раньше. Как будет видно ниже - оно появилось до программирования вообще, но не будем забегать вперёд.
Давайте возьмём операционную систему Юникс (ну - это как Линукс, только Линукс - это объект, а Юникс - это класс) и посмотрим на системный вызов write(). У него есть несколько интересных свойств, о которых вы, подозреваю, не задумывались.
Вы не видите реализацию этого вызова и не можете на неё влиять. Иногда это ещё называют инкапсуляцией.
Есть несколько разных реализаций этого вызова, которые реализованы различным образом и реализуют некоторые разновидности операции, обладающие характерной общей чертой - варианты для обычного файла, пайпа, сокета, блок-ориентированного и байт-ориентированного устройства. Это ещё зовут полиморфизмом.
Свойства вызова частично переиспользуются реализациями - например, запись в UDP сокет и запись в TCP сокет вызывают передачу данных в сеть. Запись в любой сокет вызывает передачу данных в сеть. Это ещё называют наследованием. (Вызов
writeтут не самый интересный пример -ioctlинтереснее.)
И - о чудо - мы вообще не рассматриваем никакой язык программирования, а уже имеем иерархию классов
абстрактный файл
- сокет
-- UDP
-- TCP
- дисковый файл
- устройство
-- блочное
-- байтовое
- пайп
и в ней - и инкапсуляцию, и наследование, и полиморфизм. И это я только один вызов привёл в пример, а там ещё ioctl есть, с множеством операций. Которые суть методы класса "файл". Кстати, запишите и абстрактные классы/интерфейсы.
Мало? Вот первая попавшаяся (честно!) мне на диске библиотека для языка Си.
TRex trex_compile(const TRexChar pattern, TRexChar error); void trex_free(TRex exp); TRexBool trex_match(TRex exp,const TRexChar text); TRexBool trex_search(TRex exp,const TRexChar text, const TRexChar** out_begin, const TRexChar** out_end); TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end); int trex_getsubexpcount(TRex* exp); TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
Что мы тут видим? А видим мы тут класс TRex, его конструктор, деструктор и его методы. Полиморфизма нет, но это просто библиотечка простенькая. В более сложных и полиморфизм есть, только в путь.
Так что: Объектная ориентированность в ОО языках не появилась, а была оформлена и поддержана языком. Появилась она в коде, написанном на языках предыдущего поколения.
Почему же она там появилась. Тому есть две причины. Одна более сермяжная - это следующий шаг по линии структуризации программ (инкапсуляция) и (в части про полиморфизм и наследование) инструмент переиспользования кода. Метод moveTo(x,y) нужен всем сущностям, которые реализуют интерфейс IMovable могут двигаться, и не надо его писать каждый раз заново.
Вторая причина чуть менее очевидна, но куда более значима.
Мы мыслим объектно!
Точнее - классово (не в смысле марксизма, нет:).
Каждый глагол и каждое прилагательное являются инструментами классификации. Красный - объект, имеющий цвет. Плыть - твари, способные не утонуть. И так далее.
Более того, в нашем языке есть абстрактные понятия, которые буквально определяют абстрактные классы. Инстанс такого класса без дальнейшей его детализации существовать не может, а вот если уточнить - то вполне.
Нельзя сделать объект типа "мебель", но можно конкретизировать абстрактный класс "мебель" до "стулья" и тут уже инстанс вполне жизнеспособен. А если он относится к подклассу "мягкие стулья", то даже желанен и мил.
Всё мышление человека - это выделение свойств (интерфейсы: пилить -> пригодный для распиливания) и классов (недвижимость -> дома -> школы). Мы просто никак иначе думать не умеем.
В этом плане замечательно одно странное русскому человеку свойство английского языка: артикли. Внимание, фокус: неопределённый артикль вводит класс, а определённый - описывает объект.
Это настолько чётко соответствует правилам ОО, что даже меня немного ошарашивает: a table - стол вообще, класс "столы", а the table - инстанс, совершенно определённый и данный нам в ощущениях.
Теперь, ради справедливости, ложка дёгтя. Кратко: никакие классификации реального мира не полны, не однозначны и не всеобъемлющи. Все реальные объекты принадлежат к тысяче разных классов одновременно и какой-то из них может быть предпочтительным только ситуативно. Нам важно, чтобы стол был красивый когда мы его покупаем, и чтобы он был деревянный, когда наводнение и мы бы хотели на нём уплыть.
Классификации ОО языков жестки, однозначны и являют собой изрядное прокрустово ложе.
С другой стороны - всё программирование вообще есть упрощение. Кастрированная модель предметной области. Потому что полная модель предметной области это только сама предметная область. Модель всегда что-то опускает и упрощает - это свойство программирования вообще, а не ОО в частности.
Тем не менее, подводя итог (в нашем веке в конце статьи читателю обязательно надо объяснить, что именно он в статье узнал - сам-то он не в курсе):
Объектная ориентированность - ключевое, основополагающее свойство мышления человека, и как таковое не есть что-то искусственно привнесённое в языки программирования. Оно с нами издревле и навсегда. Во всяком случае, пока существует вид homo sapiens sapiens.
(И да - ИИ, судя по всему, "мыслит" не классами.)
Комментарии (18)

yahooyaks
19.04.2026 10:17Парадигмы в программировании понадобились, чтобы упоавлять сложностью, чтобы упростить восприятие кода в частности. Разработчику надо быть хоть немного архитектором, чтобы осознанно выбирать тот или иной подход в реализации решения. Там где объекты уместны, там применение ООП снижает нагрузку и повышает эффективность ппрограммиста. А в статье очередное нытьё!

Emelian
19.04.2026 10:17Разработчику надо быть хоть немного архитектором, чтобы осознанно выбирать тот или иной подход в реализации решения. Там где объекты уместны, там применение ООП снижает нагрузку и повышает эффективность программиста.
Точно!
Поэтому считаю, что: «объекты и классы – дар Божий». Они очень хорошо позволяют структурировать код, выносить модули в автономные классы. А там, где слегка накосячил в первой версии программы, как у меня:

Структура первой версии обучающей программы «L'école» то, используя более трезвый подход, можно, на тех же принципах, ваять уже усовершенствованную версию своей программы, что я, сейчас, и делаю.

nemavasi
19.04.2026 10:17В ООП языках объекты часто стали превращаться в минибиблиотеки функций. И в проектах чаще вижу в коде не объекты, а дтошки с сервисами. Отделены код и данные. Наличие ООП объектов в коде не приводит автоматически к правильной модульности и минимизацией зависимостей. Это лишь один из способов структурирования кода. И не самый простой. Один разработчик считает, что документ должен иметь метод "Печатайся" с передачей ему объекта, куда печататься. Другой считает, что должен быть объект Принтер, имеющий метод "печатать", принимающий документ на вход. Это серьезная когнитивная нагрузка, каждый раз выбирать. ООП легче все же при симуляции конкретного процесса, лучше физического.. Там легче выбирать, так как ты его отчасти копипастишь с природы. Но когда ты имеешь дело с данными, которые живут в разных процессах, и могут пережить старые процессы, перекатившись в новые, то, гораздо проще иметь дело со более универсальными структурами данных и функциями, умеющими работать с ними. Но это мое личное мнение, не больше. У меня есть статья, тоже написанная на эмоциях на эту тему )

dzavalishin Автор
19.04.2026 10:17Пример, конечно, неудачный. Метод можно поместить куда угодно если он не трогает потроха класса и у нас вообще нет наследования. Что явно вырожденный случай. Если наследование есть, и оно предполагает разную реализацию печати для разных принтеров или для разных документов - то расположение метода очевидно.
Ну а разные процессы - это объекты обёрнутые в JSON-ы, вроде бы так.

GBR-613
19.04.2026 10:17Во-первых. "Есть несколько разных реализаций этого вызова.... Это ещё зовут полиморфизмом"
Вроде бы это зовут абстракцией?
Во-вторых, насколько я знаю, "a table" значит "какой-то инстанс", или "некий инстанс". Класс это просто table, без артикля.
Безусловно , ООП это не свойство языка, свидетельством чего являются первые версии Windows: ООП в чистом виде, и при этом на ANSI C.
На моих первых работах я в основном писал свой код, с нуля или почти с нуля. Я очень любил ООП и С++: все можно было сделать проще и понятнее. Потом так получилось, что я в основном читал чужой код и чинил там баги или делал небольшие добавки. И тут я ООП разлюбил. Когда длинная цепочка наследования, происходит что-то непонятное, и поди знай, откуда это выплывает, с какого уровня... Когда в суперклассе есть то, что мне нужно, а я не могу это использовать, потому что метод не protected, a private...
Как то раз в коде было написано что-то типа "х := у + 1". Результат: у был 0, х стал -1. Сначала я решил, что у меня сломался процессор :-) Оказалось, нет: кто-то перегрузил операторы "-" и "+", и в определённых условиях они срабатывали наоборот.

dzavalishin Автор
19.04.2026 10:17Это проблема реализации ООП в ++. Собственно, поэтому в Java и большинстве последующих языков перегрузку операторов отменили.

dzavalishin Автор
19.04.2026 10:17Насчёт "какой-то инстанс" Вы правы, но это и есть введение класса, по сути. Мы не знаем конкретных свойств этого инстанса (значений полей и даже конкретного класса). Ну, то есть, даже не знаем, кухонный это тейбл, или верстак.

kreofil
19.04.2026 10:17Вообще-то в Линуксе издревле основным понятием был процесс, а не объект. А по поводу парадигм и программирования существуют и другие мнения. Например здесь: http://softcraft.ru/

dzavalishin Автор
19.04.2026 10:17Слова "издревле" и "линукс" несовместимы. Издревле существует Bell Labs Unix. Основных понятий в нём два. Процесс и файл.

XViivi
19.04.2026 10:17не столько некое замечание, сколько некая мысль, о которой я подумал во время чтения статьи
отдельно интересно мыслить из категории ооп без наследования классов, как в расте или хаскеле; а то и вовсе некую вырожденную категорию где есть строго только синглтоны ну или каждую структуру можно "инстанцировать" лишь единожды
по сути, исходя из такой, каждый объект характеризуется лишь своими свойствами. есть интерфейс/трейт "стул", характеризующийся тем что на нём можно сидеть и ещё какими-то свойствами.
есть трейт "деревянный стул" — по сути, объединение трейтов "стул" и "деревянный объект" + какие-то свои отдельные свойства.
и есть некий объект "The деревянный стул сделанный на фабрике в Швейцарии в 1998 году пекарем Николой Теслой во время запекания сапогов, украденных у соседки Зины, пока она …, масса которого составляет 10кг, состоит в данный момент из x.xE+27 атомов, …" — каждый такой объект уникален и каждый удовлетворяет каждый лишь строго своему набору трейтов.
каждый трейт это просто объединение других трейтов (ну или какой-то атомарный трейт по типу как условный трейт "объект со скоростью 1 м/с"), а каждый объект это некая уникальная сущность
хотя возможно, для такой модели ближе не oop, а ecs. тогда, сервисы — это те самые трейты, а компоненты… не уверен. возможно, сервисы — тоже компоненты, просто динамические? а объекты это как раз entity.
впрочем, из конкретно примера со стулом, можно ещё и привести непонятки, навроде парадокса корабля тесея… ну или что если взять половину атомов стула и использовать для создания одного стула, а половину для создания другого… будет ли хоть один из новых стульев считаться оригинальным объектом? как будто тогда уж стоит говорить и о уникальности во времени, ну или иммутабельности, что, как мне кажется, точно лишь запутывает…

dzavalishin Автор
19.04.2026 10:17Можно практически всё, но зачем? Наследование - способ структуризации и представлений о предметной области, и связанных с ним применимых к ней алгоритмов. Представить себе мир, где объекты компонуются из необъятного моря трейтов легко, но они же не будут ортогональны. Придётся сделать трейт "украдены у Зины" и трейт "украдены у Люси", вместо трейта "украдены у кого-то" и его конкретизации.
Я делал в своё время в Яндексе иерархическую ОО БД, в которой иерархия была именно и только иерархией наследования. То есть в ветке дерева можно было либо заявить новое свойство, либо зафиксировать значение заявленного выше свойства. Оказалось, что иерархия наследования самодостаточна и позволяет заменить собой иерархию хранения.
Это, конечно, немного взрывало мозг, но логика была безупречна. (Она делалась для Маркета) - на каждом уровне иерархии появлялись поля, актуальные для данного обобщения. И, кстати, множественное наследование работало и позволяло из "принтеры" и "сканеры" родить "МФУ".

chaetal
19.04.2026 10:17Если бы к "фиговым" трём пунктам добавить ещё и самый неправильный про то, что "ООП — это инкапсуляция, наследование, полиморфизм", могло бы получиться что-то дельное. А так, к сожалению, получился очередной наброс в спор глухих со слепыми о балете.

dzavalishin Автор
19.04.2026 10:17Предполагается, что уж определения с первой страницы букваря читатель знает. :) Читателю, который этого не знает и сам вопрос, наверное, не очень интересен...
gev
И ты, Брут?
dzavalishin Автор
Кто-то же должен подвести черту :)
gev
Было бы под чем ;)