GrabDuck

Почему ООП не инкапсуляция, наследование и полиморфизм, или как я научился не ...

:

Всем привет!

Дамы и господа, в статье речь пойдет от том, как у меня жутко пригорает от Объектно Ориентированного Программирования и Проектирования. Скорее всего подобных дохера и трошку, и вполне возможно, что я нагло кого-то копирую. Я, честно говоря, не очень много гуглил, но минимально пытался. Добро пожаловать в комменты с пожеланиями, предложениями и срачем.



Нотация и терминология

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


Краткое введение

На мой взгляд главная проблема ООП в том, что его понимают не с той стороны.

К сожалению, в XXI веке каждый день возрастает гребаная тенденция к воITи и информационное пространство просто наполняется однотипными историями, как вчера он на токарном станке вытачивал железки, а сегодня я успешный 23-летний сеньор с ПТУшным образованием на своей галере клепает убогие сайтики на Битриксе, получая золотые горы. Таким не объясняют, что такое ООП, им объясняют, что такое инкапсуляция, наследование и полиморфизм, и то, если повезет. А что за зверь такой ООП — ну и хер с ним собственно.

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


Ремарка

Регулярно на "соискательных сессиях" (провожу такие каждый раз, когда заканчивается контракт как минимум, чтобы прощупать тенденции рынка труда) прохожу n-ое количество собеседований. Стоит отметить, что проблемы с этим возникают где-то в 70% случаев, в остальных реально дают решать какую-нибудь алгоритмическую задачу. В основном, это на какую-нибудь банальную методику в стиле жадных алгоритмов, простейшей комбинаторики или в худшем случае динамическое программирование

Я отучился в одном из лучших факультетов моей страны и там курс по ООП заключался в том, как его использовать в рамках платформы .NET. Инкапсуляция, наследование, полиморфизм. Но ни капли настоящего ООП. Это, кстати, одна из серьезнейших проблем современного IT образования. Между прочим, до сих пор ребята, с которыми я учился на потоке, не вдупляют, как его применять этот ООП, а потом у тебя в кодяре тонны бесполезных фабрик и какие-то жуткие зависимости.

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


Собственно ООП

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

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

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


Комментарий к примеру и технические детали

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

abstract class Vessel
{
     private $material;
     private $liquid;

     public function __construct(Material $material)
     {
          $this->material = material;
     }

     public function fill(Liquid $liquid)
     {
          $this->liquid = $liquid;
     }

     public function pour()
     {
          $liquid = $this->liquid;
          $this->liquid = null;

          return $liquid;
     }
}

class Cup extends Vessel
{
    //Чем-то он отличается
}

class Wineglass extends Vessel
{
    //Чем-то он отличается
}

class Mug extends Vessel
{
    //Чем-то он отличается
}

class Human
{
    // тут что-то происходит
    public function drink(Vessel $vessel)
    {
         $this->stomack->add($vessel->pour());
    }
}

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


Кодяра
class VesselFactory
{
    //не самый изящный код, зато наглядненько. $className - это имя класса, который нам нужно получить от фабрики, $material - из чего сделать
    public function getVessel($className, $material)
    {
          return $className($material);
    }
}

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


Комментарий к примеру и технические детали

Интерфейс требует у объекта наличие поведения для внешнего взаимодействия. Интерфейс не обзятально толжен быть Able. Например, если наш компьютер имплементит интерфейс USB, то этот интерфейс не будет Usbabel(юэсбибэбл). Это будет USB интерфейс.

interface Knob
{
    public function take(Holder $with);
}

class Cup extends Vessel implements Knob
{
    public function take(Holder $with)
    {
         //Как-то мы можем держать стакан держателем
    }
}

Этот пример не очень аккуратный и продуманный, зато полностью передает то, как из концепции ООП вытекает всё то, что так требуют на собеседованиях. Именно это понимание и позволяет следовать SOLID принципам, создавать красивую архитектуру и отделять бизнес-логику от контроллера. По сути в понимании этих простейших вещей лежит вся суть современной разработки. И даже, несмотря на то, что это просто как валенок, всё равно 60-70% разработчиков не могут прийти к этому. И причина в том, что разработчику не предлагают понимание процесса, ему предлагают инструмент.


Рассуждение

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

Мой опыт работы в одной команде с ребятами из UK, USA и EU показывает этот большой недостаток. Архитекторы и сеньоры всех пород и мастей, обладая невероятными технологическими познаниями, с трудом делают хорошую архитектуру(мы говорим про усредненный случай, есть множество гениальных ребят, которые такую красоту делают, что приходится дома под одеялом смотреть на их UMLы). Просто потому что следуют гайдлайнам, напрямую обозначенными в ООП. Но в жертву техническим деталям приносят куда более важные философские детали. Например, неправильно сделанная объектная декомпозиция системы превратит жизнь вашего разработчика в ад, даже если она сделана по всем гайдлайнам и согласно всем лучшим практикам. Обычно в этом случае получаются крутые классы с интерфейсами, фабриками, однако в них много, например, спагетти кода просто потому классов либо слишком мало(приходится их поведение превращать в условную логику) или слишком много(и приходится в условной логике хендлить разные виды классов). А там и экстендабилити страдает и склонность к алкоголизму растет.

Лучшая практика — это представить систему так, будто вы не программист, а строитель. Почему паттерны проектирования так хороши? Потому что они как раз таки позволяют абстрагироваться от технической реализации и создавать структуры у себя в голове такими, какими мы бы их делали не в коде, а используя гвозди, молоток и доски. Многие мои коллеги жаловались, что не поняли Банду Четырёх потому что там примеры кода на C++ или Smalltalk. Там идея совсем не в коде, на него вообще можно хер забить, там идея в том, что мы с вами можем строить программу так же, как и дом, и автомобиль. Понятным для человека образом, копируя инженерый гений из абсолютно других сфер. Программист сможет думать как инженер только тогда, когда начнет видеть матрицу вокруг. Декомпозировать предметы, которые его окружают, называть методы/интерфейсы/свойства всего, что попадается на глаза. Начиная от наших любимых кружек и заканчивая любимыми пиратами.

Дров в огонь подбрасывает то, что в современном мире миллионы языков, который либо предоставляют нам кастрированный ООП(привет Javascript, Go), либо технически ориентированный(C#, Java, C++), либо прекрасный и при этом пугающий своими возможностями(Python, Ruby), либо вообще PHP. И это не камень в огород этих языков, потому что у них есть назначение, применение и они хороши и пусть такими и будут.


Мои любимые языки

Python, C# и PHP. Просто потому что. Ещё я очень полюбил брейнфак, как язык с абсолютно нестандартным подходом, отлично подходит на собесы. Даешь за 30 минут написать прожку на брейнфаке, и тут сразу видно, насколько хорошо разработчик знаком со стандартными структурами данных, насколько у него развита логика и самое важное — насколько разработчик умеет учиться.


Заключение

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

Уважаемые читатели, если у вас есть идеи и предложения по данному топику — было бы очень круто, если вы поделитесь этим с нами.