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


Для себя я разделил полезную IT-литературу на три категории: ремесленная, научная и агитационная. Первая помогает улучшить процесс разработки, разобраться в каком-то языке программирования или технологии, вторая — глубоко погрузиться в какую-то задачу, понять основные принципы решения различных проблем, сформировать целостный взгляд на вещи. Эти два типа отличает сдержанный эмоциональный фон текста, богатый ссылками на другие источники контекст и основательно подкреплённые фактами из реальных успешных (или не очень) проектов описания подходов и методик. Книги третьего типа пишут евангелисты. Недавно мне довелось прочитать «Elegant Objects» Егора Бугаенко. Многие устоявшиеся вещи, которые мы привыкли считать лучшими практиками, просто и понятно названы в книге злом: геттеры, сеттеры, ORM, DI контейнеры и прочие, казалось бы, облегчающие работу программиста техники.


Впрочем, такие эмоционально насыщенные тексты, если в них есть последовательный подход (в «Elegant Objects» это пуристский взгляд на ООП), а не только шаманизм и истерия, обычно заставляют задуматься. Например, те же геттеры и сеттеры всегда выглядели для меня подозрительно. С одной стороны, что-то они всё-таки инкапсулируют. С другой — все частные свойства как будто бы и перестают быть частными. Вообще, когда я с помощью IDE автоматически создаю набор этих методов для свойств какого-нибудь DTO, меня начинают мучить сомнения в необходимости программистской человеческой прослойки между идеей продукта и её реализацией.


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


В то же время мне трудно стать религиозным фанатиком. Если в работе используется инструмент, позволяющий сократить рутинные операции в целом ускорить процесс, я буду его использовать. Особенно когда такая практика уже показала свои преимущества при разработке большого числа промышленных проектов. Тот же IoC контейнер хотя и побуждает нас «неуважительно» относиться к объектам, отбирая у них право рождения, в то же время позволяет нам меньше думать о том, как нам создавать каждый объект в системе. Задача поставлена на конвейер.


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

Поделиться с друзьями
-->

Комментарии (15)


  1. PerlPower
    03.08.2017 01:20
    +5

    Из вашей статьи я понял, что хотел донести автор «Elegant Objects», но так и не смог понять что хотели донести вы.


    1. agr_ugraweb
      03.08.2017 09:28
      +4

      похоже на агитационный материал к прочтению агитационной литературы :)


  1. SerafimArts
    03.08.2017 04:39
    +1

    Склонен согласиться на счёт геттеров и сеттеров, они мало имеют смысла в языках, где есть свойства (JS, C#) или язык позволяет оперировать уровнем доступа на уровне метамагии (PHP, Ruby). Переопределение поведения без переписывания всего кода — единственный смысл их существования. В какой-нибудь Java без них нормально не обойтись.


    В остальном, тема сис... DI, ORM и чего там ещё — не раскрыта, так что не убедительно.


    А больше в статье и нет ничего, правильно в комменте выше написано, лучше и не сказать: "так и не смог понять что хотели донести вы.". У меня такое же "послевкусие".


    1. MadridianFox
      03.08.2017 08:51

      Беда геттеров и сеттеров в том, что они соблазняют вас нарушить правило tell don't ask.
      На самом деле нет ничего плохого, чтобы получить у объекта какое-то значение вызвав метод. Или передать значение объекту через метод. Плохо именно то, что непродуманные геттеры и сеттеры (созданные на автомате) приводят к тому, что код который использует объект содержит, зачастую дублирующуюся, логику самого объекта.
      Например

      // с геттерами
      if($book->getPages() > 500 || $book->isHardSkin()){
         // set discount for strong books
      }
      // без них
      if($book->isStrong()){
         // set discount for strong books
      }
      

      Вполне вероятно, что такая проверка нужна не в одном месте, и геттеры будут провоцировать дублирование кода.


      1. Boeses_Genie
        03.08.2017 09:08

        Если я правильно понял автора «Elegant Objects», то главная проблема методов доступа не в дублировании кода, а в нарушении инкапсуляции. Мы как будто с помощью этой дополнительной прослойки делаем частные свойства общедоступными. А кроме того, объект автоматически становится изменяемым, — а «иммутабельность» объектов автор считает так же хорошей практикой. Поэтому и предлагается поручить операции с собственными свойствами самому объекту.


        1. MadridianFox
          03.08.2017 09:21

          Угу. Автор книги ввёл какие-то базовые «плохие» понятия, такие как мутабельные объекты, нарушение инкапсуляции (неуважение объекта) и т.д., а потом многое другое сводит к этим базовым понятиям. Вроде и доказательство теоремы… но какое-то незаконченное. Но это прокатывает, т.к. все мы видим в этих базовых понятиях свою проблему. Каждый многие программисты так или иначе обожглись на сеттерах, на коде в конструкторах, на многопоточном программировании, и когда кто-то говорит — «это плохо, я покажу как хорошо», начинаешь интересоваться этой темой.


      1. vintage
        03.08.2017 09:25
        +1

        Вы в обоих случаях написали геттеры. И не всегда второй код предпочтительней.


        1. MadridianFox
          03.08.2017 09:29

          Злоупотребление сеттерами позволяет получить невалидный объект. Все обязательные поля должны заполняться через конструктор. А чтобы конструктор не рос, количество полей в объекте должно быть не очень большим, что согласуется с single responsibility.
          Насчёт второго кода — пруф в студию)


          1. vintage
            03.08.2017 10:05
            +2

            Злоупотребление чем угодно может привести к чему угодно. Это не проблема того, чем злоупотребляют, а того, кто злоупотребляет.


            А подумать? У нас может быть 100500 видов скидок. Будете предикаты для каждой из них вносить в модель книги?


            1. MadridianFox
              03.08.2017 10:17

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

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

              Но концептуально — да. Не бывает такого, что предикат скидки используется в одном месте во всём приложении. Везде где фигурирует стоимость товара (с редкими исключениями) надо будет учитывать скидку. Но тут уже встаёт вопрос — а если нам важна стоимость, то почему бы не использовать $book->price() и пусть оно само внутри себя разбирается со своими скидками.


              1. vintage
                03.08.2017 10:32

                Потому, что стоимость зачастую — не характеристика товара и во многом зависит от контекста. Банально "в ваш день рождения любая книга (но только одна) за пол цены". Такие правила обычно выносят в отдельные сервисы, чтобы модель книги не зависела от вообще всех моделей.


                1. MadridianFox
                  03.08.2017 10:50

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


                  1. vintage
                    03.08.2017 11:00
                    +2

                    Это повод вынести общий код в переиспользуемую функцию. Стоит ли её помещать в сам объект или внешний сервис — зависит от кучи факторов.


                    1. OlegZH
                      04.08.2017 15:53

                      А что будет, если мы будем иметь несколько различных объектов, которые участвуют в различных иерархиях (семантических сетях) и некий общий объект, который связывает эти различные грани одного объекта воедино? (Просто иногда кажется, что проще добавить новую грань (в рантайм), а не пытаться переделать исходный код объекта.)


      1. OlegZH
        04.08.2017 15:48

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

        Ключевое замечание!
        Вообще, иногда кажется довольно странным, использовать объекты (они же экземпляры классов) как простые структуры данных, никак не распределяя логику работы между различными объектами.

        Книга — это довольно сложная сущность. Как и любая другая. Когда мы задаём для неё структуру, мы берём один, весьма скудный срез представлений связанных с книгой. Если бы мы хотели использовать не просто подход, ориентированный на объекты, а сами объекты, то мы должны были бы понять что: 1) каждый объект должен хранить некую элементарную сущность (данные); 2) семантика каждого объекта проявляется дважды при связывании объектов (различных классов) между собою; 3) встреча двух объектов во время исполнения программного кода должна автоматически приводить к созданию нового объекта нового класса.

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