ООП.Враньё.Бугаенко.Стенограмма

Программирую долго на разных языках и всегда была одна и та же ситуация, одно и то же ощущение, одни и те же эмоции испытывал от кода, который я пишу:
Cначала когда мы начинаем писать — всё выглядит прекрасно несколько файлов, очень красиво, мне очень всё нравится, я один или группа людей начинаем делать дизайн.
Проходит время, код становится всё крупнее …
И мы начинаем любить код меньше!
Его всё тяжелее понимать, всё больше в нем каких-то костылей, которые вставлены там и сям, всё больше в нём решений, которые со временем не нравятся, к нему уже не хочется возвращаться. его не хочется поддерживать.

Его хочется только выбросить!

Это широко распространённое явление.

Так происходило много лет — мне стало не интересно заниматься программированием, хотя за это платят деньги, хотя это приносит результаты, но:
Ощущения были неприятные!
И вот в 2011 году  наткнулся на книжку,  которая объясняет что такое объектно-ориентированное программирование и как нам вместо мыслить процедурно начать мыслить объектно.
David West – Object thinking.

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

Объектно-ориентированное программирование призвано было чтобы этого улучшить. Поставить нас программистов впереди, а компьютер позади. Мы главные, наше мышление первично, а компьютерные команды вторичны.

Ни в Java, ни в C++ этого не произошло.

Процедурно программировал в течение там 5-7 лет и не объяснив идею объектно-ориентированного программирования, просто дали язык, инструменты, сказали: а теперь у тебя есть объекты — теперь вместо того чтобы делать функции, данные теперь у тебя есть класс.
Ты создаёшь класс, помещаешь функции, какие-то кусочки данных и у тебя получаются «объекты».
Но мы не стали при этом мыслить объектно.

книга David West – Object thinking изменила моё понимание и я по-иному взглянул на известные фреймворки, утилитные классы, apache commons, гуавы библиотеки, многие дизайн-паттерны — и понял что они НЕ
объектно-ориентированные, они созданы людьми, которые по-прежнему мыслят процедурно и предлагают нам мыслить процедурно. 

когда говорят идти на процедуры, Мем Роберт Дауни младший

Переходим к самому интересному, самая главная проблема:
Определить что такое объект?

Стандартное, процедурное понимание объекта: какие-то данные, какие-то функции … это категорически не верно, неправильное определение!

Объект это НЕ данные с прикрепленными к нему функциями!

Объект — живая сущность, которая обладает поведением, на которое мы можем полагаться.
Объект НЕ процедуры, которые могут манипулировать данными, которые мы туда вложили.
Мы рассматриваем объект как живой организм, который внутри нашего кода представляет какие-то интересы, у него есть какое-то поведение, на которое полагаемся.
Мы НЕ рассматриваем его как как глупую структуру, которой мы можем просто вложить какие-то данные, а потом вызвать функции — такое мышление нас ведёт обратно в язык Си.

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

Java мешает нам создавать объекты правильно и провоцирует нас на создание тех самых неправильных объектов, которые являются просто блоками данных, data structures, хранилища данных с прикреплёнными методами.

Первые 3 проблемы, которых не должно быть в коде:
— сеттеры
— геттеры
— методы статические

Есил этих трёх не будет в Вашем коде,  Вы продвинетесь серьёзно вперед и ваш код станет значительно более объектно-ориентирован, мышление изменится.

По пунктам:
пункт 1 геттеры — вот наш класс, внутри у него инкапсулированный path, у меня есть геттер который этот path мне помогает вернуть — это категорически НЕ правильный дизайн!
Потому что в этом случае мы теряем идею инкапсуляции, мы разрешаем любому другому объекту находящемуся вне нашего объекта достать из нас наши данные и делать с ними что им захочется!
Мы теряем контроль над нашими данными, мы их отдали.

Зачем эти геттеры были придуманы — для того чтобы защищать наши данные от внешнего воздействия от прямого доступа извне — на самом деле они НЕ защищают, мы по-прежнему разрешаем всем вне нашего объекта прийти к нам и забрать у нас из нас то, что в нас внутри лежит.
Он приходит к нам и, не спрося нас, забирает из нас данные, превращая
нас в глупую структуру данных, которая ничего делать не умеет.
В данном случае мы по-прежнему процедурно программируем просто эти данные лежали у нас все в одной по одной куче, в  одной длинной процедуре, а теперь мы вынесли в сторону — положили в класс, но по-прежнему управление этими данными происходит в какой-то одной длинной процедуре: из файла достали путь, отсюда мы достали что-то ещё, отсюда мы достали что-то еще, потом мы с этим поработали и получили результат …
Не превращать объект в хранилище данных.
Мы не должны позволять никому извне доставать из нас данные.

Если вы пишете на джаве, видели массу примеров геттеров в фреймворках, в хайбер или в spring масса этих гетеров, потому что они используют свои классы как хранилище каких-то данных большого объёма — инкапсуляция нарушается, мы мыслим как машина

Логика выносится в объекты и им поручается работать с этой логикой. Не просто процедура отдаётся, а мы поручаем объекту быть кем-то кто нам нужен.
Нам нужен файл, чтобы у этого файла были свойства и мы объекту полностью отдаём, поручаем ответственность за работу с этим файлом.
Как в реальной жизни — потому что этот класс — представитель реального файла на диске и он полностью для нас является представителем,  имеет все свойства этого файла, НО НИ в коем случае он не хранитель имени файла.
Потому что если он просто хранит имя файла, то мы можем имя файла вытащить из него и дальше решать что с ним делать, за границами объекта – нарушаем инкапсуляцию.

Идея инкапсуляции, которая говорит нам что всё должно быть завернуто в объекте,  всё должно быть внутри объекта: все его проблемы, задачи должны решаться внутри и ни в коем случае не должен никому разрешать снаружи брать его куски и там что то с ним делать — он должен все все проблемы решать внутри.
Геттеры против этого  и мешают нам это сделать!

Вторая проблема это сеттер – например, тот же самый путь и мы устанавливаем параметр внутри объекта!
Проблема более серьёзная чем геттеры, потому что она провоцирует нас на создание так называемых mutable objects

Мы создаём сначала объект, на втором шаге мы его инициализируем и его нашпиговываем нашими
данными … получается что после создания его, после конструктора мы имеем неполноценную структуру мы имеем что то что мы должны проинициализировать, а потом ещё через время опять.
Технически это ведёт большому количеству проблем.

Признаки immutable objects:
simpler
thread-safe
side-effect free
failure atomicity
easier to cache
no NULL
no identity mutability

Неизменяемы объекты технически лучше в обращении и в работе это общепризнанный факт.
Они компактные невозможно сделать размером в 5 тысяч строк.

Объект изменяемый нарушает самую главную идею — наш объект является является представителем сущности
реального мира.

Если я объект file, то вы со мной коммуницируете, я представляю для вас какой-то файл на диске, вы мне говорите что-то, а я с ним разберусь.
Допустим переименовать себя — я пошел на диск, в операционную систему и переименовал — но вас не касается, что я сделал — просто сказали мне переименуй себя — я пошел и переименовал.
Я представляю ту самую сущность реального мира, которая за мной, вы к той сущность никогда напрямую не попадёте, только со мной общаетесь.
И вдруг вы приходите ко мне и говорите setpos и меняете путь, я фактически предаю ту сущность, совершил предательство сущности реального мира, которая была сначала под моим контролем и вдруг вы пришли сказали мне set — это концептуально очень неправильно, очень плохо потому что вы перестаёте мне доверять, вы знаете что я такой, который может легко переметнуться, вы перестаёте мне доверять, теряется доверие, а значит вам тяжелее со мной работать —  вы коммуницируя со мной, создавая софт, передавая мне что-то, общаясь со мной вы не верите мне, а значит становитесь опять процедурным, опять на себя забираете контроль за ситуацией, опять начинаете управлять данными, не доверяя мне как объекту.

Третья проблема — статические методы.

Статический метод это метод, который не привязан ни к какому объекту.
Для вызова статического метода мне не нужно создавать объект, достаточно обратиться к классу и сказать ему
прочитай содержимое этого файл
В чём здесь проблема?
Проблема огромная — мы не имеем вообще объекта, поскольку мы не имеем объекта мы не имеем объектно-ориентированного программирования в принципе, у нас нет той самой сущности живой.
Мы ни с кем не коммуницирует, просто имеем набор процедур из процедурного программирования

Люди программировали, привыкли к тому что у них есть функции, а им говорят — нужно создать объект, программисты говорят это неудобно, давайте, чтобы мы её просто куда-нибудь могли поместить.
Java озаботилась этим — можно сделать как Cи.
Мы так много лет программирования си, нам удобно, привычно — я понимаю вы объектно-ориентированные ребята, но нам нужно — и дали эту возможность и мы потеряли вообще объектно-ориентированную
идею — у нас больше нет объектов, у нас процедуры, которые находятся в utility классах библиотек, всё состоит из процедур, которые мы вызываем вместо того чтобы идти к объекту и создавать объекты, делать его представителем сущности реального мира и разговаривать с ним, полагаться на его свойства, доверять ему и
 делать так чтобы он отвечал за одну проблему — мы всё это убираем и вместо этого говорим: мы не доверяем ни  каким объектам, мы прямо здесь и сейчас процедуру вызовем, эта процедура с с нашими данными выполнит
определённые операции — это классическая процедурная программа:
у меня есть пара цифр, я им передал эти пару цифр, они их сложили вернули мне результат, я контролирую, мыслю как компьютер, знаю что есть вызов функции, функция выполнит определенные операции, вернула результат, я пошел дальше с моими данными!

В объектно-ориентированном  иначе — у нас есть объект, который мы знаем что он собой представляет и вы полагаясь на его свойства дальше работаем с нашим кодом.

Если эти три момента запомнить и перестать ими пользоваться, то вы почувствуете, что вам придётся мыслить как объекты, строить объекты такими, чтобы с ними можно было коммуницировать как с правильными объектами.

Пример как я понимаю как правильный объект:
у нас есть класс, в этом классе должен быть конструктор, в который мы передаём путь  и он его он
сохраняет в property.
Обратим внимание:
1. Я не могу из него достать его путь. Я путь не знаю. После того как объект создан это его знание, он им обладает яэтого не должен больше касаться.
2. Я не могу изменить этот путь.
3. Нет статических методов — у меня есть просто свойство этого объекта — что у меня есть содержимое, объект — файл и у него есть контент, этот контент можно получить, объект этот контент может отдать.
Те кто вокруг меня находится может полагаться на то что у меня есть этот контент и за контент забирать.
Статических методов, геттеров и сеттеров у меня тоже нет — вот так должен выглядеть правильный объект в ООП.

Таких рекомендаций у меня порядка 45

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

Объект должен иметь одну ответственность. Если объект файл, то он должен уметь делать всё с файлом. Возникает вопрос – где должно быть это ВСЁ?
Правильный подход – использование декораторов – оборачивание самого простого метода другим простым методом и так далее. Декоратор возвращает чуть более усложнённый полученный объект.

Портянку утилитных классов мы раскладываем в иерархию декораторв.

Каждый раз под разные задачи создаём микроклассы, которые по-разному себя ведут, то есть  
функционал умножим не с помощью статических методов, а с помощью комбинации разных классов,

Если в конструктор класса нужно передавать более 7 параметров, то нужно пересмотреть своё объектное мышление и научиться создавать объекты с меньшим количеством параметров. Чем меньше по размеру объекты и чем больше их количество, тем качественнее код. Классов должно быть много и у них должно быть мало public методов, private может быть много.

NULL – большая ошибка, не должен присутствовать в ООП.

Класс не должен иметь более одной ответственности.

Оставить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.