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

Противоположность инкапсуляции — размазывание знаний о функционировании чего-либо по всей программе.

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

Пример: работа с денежными величинами. Не секрет, что во многих e-commerce системах денежные величины реализованы в виде чисел с плавающей запятой. Думаю, все из нас в курсе, что при простом сложении двух «целых» чисел, представленных в виде переменных с плавающих запятой, может образоваться «немного не целое число». Поэтому при такой реализации там и тут приходится вставлять вызов функции округления. Это и есть размазывание знаний об устройстве сущности по всей программе. Инкапсуляция в данном случае — собрать (спрятать) в одном месте знание о том, что деньги представлены в виде величины с плавающей запятой, и что её постоянно приходится округлять при самых невинных операциях. Спрятать так, чтобы при использовании сущности «деньги» речь об округлении даже не заходила. При инкапсуляции не будет никаких проблем заменить реализацию «денег» с числа с плавающей на число с фиксированной запятой.

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


  1. lair
    13.01.2019 14:52

    Подлинное назначение инкапсуляции — собрать в одном месте знания, относящиеся к устройству некой сущности, правилам обращения и операциям с ней.

    Откуда вы берете "подлинность" этого назначения, и почему вы считаете, что определение, данное, скажем, в вики — менее "подлинное"?


    1. SergeyGalanin
      13.01.2019 16:11

      Очень правильный вопрос.

      Для начала встречный вопрос: вы согласны, что размазывание деталей реализации по всему коду — это плохо?

      Второй вопрос: вы согласны, что значение термина — это вопрос договорённости?

      Теперь мой ответ.

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

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

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

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


      1. lair
        13.01.2019 16:21

        вы согласны, что размазывание деталей реализации по всему коду — это плохо?

        Да (обычно).


        вы согласны, что значение термина — это вопрос договорённости?

        Да.


        Я считаю, что определение в вики хуже, потому что оно не ведёт прямиком к полезному эффекту сокрытия реализации.

        Это очень странно, учитывая, что там явно написано про "information-hiding mechanism".


        Впрочем, ваше определение тоже не ведет к полезному эффекту сокрытия реализации.


        Более того, вы приравниваете "сокрытие реализации " к "неразмазыванию функциональности", хотя это не одно и то же.


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

        И это правило не обязательно будет инкапсуляцией, вот что важно.


        Фактически, определение из вики — это частный случай моего определения

        Нет. Ваше определение слишком размыто (до невыполнимости) в части information hiding.


        Определения терминов из мира программирования формируются исходя из работ авторитетных товарищей из этого мира программирования.

        И из консенсуса в сообществе.


        Между тем, товарищи Роберт Мартин и Мартин Фаулер не намного умнее нас с вами,

        У вас нет оснований для этого утверждения.


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

        Для этого надо сначала определиться, какое определение "более хорошее". Я вот ваше "более хорошим" не считаю.


      1. Hardcoin
        13.01.2019 18:29
        +1

        А зачем брать существующий термин с точным значением и пытаться его поменять? Что мешает придумать новый термин с нужным вам значением и использовать его?


        1. SergeyGalanin
          14.01.2019 09:41

          ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%BA%D0%B0%D0%BF%D1%81%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F

          Термин уж больно хороший: заворачивание чего-то во что-то. Как раз то, о чём я и говорю.


          1. lair
            14.01.2019 11:21

            1. TheShock
              14.01.2019 18:26

              Мне не нравится определение из вики:

              Инкапсуляция (англ. encapsulation, от лат. in capsula) — в информатике упаковка данных и функций в единый компонент.


              Оно слишком водянистое, недостаточно точное и вообще не раскрывает сути, которая используется при назывании четырех китов ООП. Ну вот, к примеру:
              То есть если упаковать все-все данные и функции в единый компонент — это будет инкапсуляция? Если это данные из разных предметных областей? То есть если я в одном компоненте опишу деньги на счете пользователя и количество сообщение на форуме, то, согласно этому определению, это будет инкапсуляция, но по духу, по моему мнению, это как раз будет нарушение инкапсуляции.

              Чтобы этот термин был более корректным — ему необходимо как минимум добавить описание данных и функций, которые могут объединятся в одном компоненте. То есть
              Инкапсуляция (англ. encapsulation, от лат. in capsula) — в информатике упаковка данных и функций (которые обладают определенным свойством) в единый компонент.


              Я понимаю, что с моими замечаниями инкапсуляция уже начинает набирать признаков SRP, но он близок по сути и к принципу сокрытия и к принципу абстракции.


              1. lair
                14.01.2019 18:27

                Там ниже есть "подробности":


                языковая конструкция, позволяющая связать данные с методами, предназначенными для обработки этих данных.


                1. TheShock
                  14.01.2019 18:38

                  Жаль, что этой подробности нету в определении. И жаль, что туда также добавляют совершенно (по моему) некорректный пассаж о сокрытии данных.

                  То есть, более правильное определение будет такое:

                  Инкапсуляция (англ. encapsulation, от лат. in capsula) — в информатике упаковка данных и функций, предназначенных для обработки этих данных в единый компонент.


                  Так? Всё дело в том, чтобы можно было положить данные и функции для них в один класс/неймспейс/итд?

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

                  Не знаю, смог ли я объяснить, я чувствую, что аргументы мутные. Просто это из разряда: «чтобы язык был ООПшный — там должно быть ключевое слово class». Это не подходит для теоретиков, которые придумали принцип подстановки Барбары Лисков, это подходит для ребят, которые спорят за пивом в баре.


                  1. lair
                    14.01.2019 18:42

                    Теперь мне это определение кажется слишком мелким в качестве основополагающего принципа ООП.

                    А я (лично) и не считаю, что инкапсуляция — это "основополагающий принцип ООП". Для меня это всего лишь один из принципов, которые делают разработку легче/более поддерживаемой. И как раз привязки к ООП в понимании термина "инкапсуляция" я пытаюсь избегать.


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


                    1. TheShock
                      14.01.2019 18:47

                      Но мы как раз спорим в контексте «определений из соответствующих предметных областей», а не в контексте «личного мнения». А в контексте современной Computer Science инкапсуляция является одним из основных принципов ООП


                      1. lair
                        14.01.2019 18:52

                        А в контексте современной Computer Science инкапсуляция является одним из основных принципов ООП

                        … но при этом не уникальна для ООП, про что явно написано в английской википедии.


                        Ну и на самом деле, тут есть очень интересный вопрос: а что такое "основной принцип"? Это принцип, без которого (ООП) не будет? Или принцип, который если есть, то ООП? Или что-то третье?


                        Вообще, чем дальше, тем интереснее найти, кто же конкретно ввел этот термин, и сказал, что "он основополагающий".


                        1. TheShock
                          14.01.2019 19:03

                          Эта ветка началась с вашего комментария:

                          Может все-таки стоит брать определение из соответствующей предметной области?

                          Я просто описал, почему считаю определение из предметной области сомнительным и согласен с идеей, что неплохо было бы над нам подумать, а вы, похоже, со мной согласны (как минимум, отчасти).

                          И как раз привязки к ООП в понимании термина «инкапсуляция» я пытаюсь избегать.

                          Да, я согласен. Мне нравится пример, который ниже привел автор статьи:

                          Правильно объединять деньги их округляя. То есть мы везде пишем:
                          const sum = round(amount1 + amount2);


                          Но это уже детали реализации, которые лишние каждый раз. Потому мы вводим функцию:
                          function add_money (amount1, amount2) {
                            return round(amount1 + amount2);
                          } 


                          И этим инкапсулируем логику. Такое видение инкапсуляции мне кажется намного лучше, чем то, что описано в википедии:

                          1. Это реальное влияние на поддержку кода
                          2. Оно не зависит от парадигм — подходит и под ООП и под ФП и под ПП.
                          3. Оно никак не зависит от механик языка. То есть нам не нужны специфические языковые конструкции для соблюдения этого принципа (меня страшно выбешивает, когда люди считают модификатор private как-то связанным с инкапсуляцией)
                          4. Я верю, что это близко к аксиоме, что такой подход к коду полезен, в отличии от холиварного подхода с «методами и свойствами в одном классе».

                          С таким видением инкапсуляции этот принцип становится реально теоретическим и полезным, но, увы, я недостаточно образован, чтобы это видение формализовать. Может вы сможете помочь?


  1. vasyan
    13.01.2019 14:53

    Только вот IRL люди отказываются от инкапсуляции и переходят к anemic object. Что бы там не говорил Фаулер.
    Вот разобрать причины перехода к anemic object было бы очень интересно.


    1. sshikov
      13.01.2019 15:23

      Падение (средней) квалификации? ;)


      1. DrPass
        13.01.2019 15:31

        Скорее, распространение всяких ORMов и REST-сервисов, а также популярность паттернов «модель-представление-фиговина с бизнес-логикой между ними».


        1. vasyan
          13.01.2019 18:25

          Я тоже это отношу к к REST и сериализации. Мол, когда объекты стали активно сериализовывать/десериализовывать и мэпить они потеряли свою субъектность.

          В значении:
          (Субъектность — свойство индивида быть субъектом активности.)


        1. sshikov
          13.01.2019 19:58

          Возможно, хотя и не факт. Скажем так, есть варианты (для сериализации в частности), которые не требуют, чтобы объект открывал свое устройство.


          1. DrPass
            13.01.2019 21:10
            +1

            Тут даже дело не в открытии устройства, по сути практически все сериализаторы и так просто тянут данные из публичный свойств, игнорируя остальные. Это становится архитектурно неудобно. Гоняя через эти сервисы и прокси анемичные объекты, вы можете быть уверены, что состояние объекта на одной стороне и на другой идентично.
            Если это объект, состояние которого определяется ещё и приватными свойствами, да ещё и с бизнес-логикой, то вы получите архитектурный косяк. В лучшем случае просто нарушение Single Responsibility, когда одна и та же сущность используется для двух совершенно разных задач. В худшем — проблему синхронизации состояний двух разных объектов.


            1. vasyan
              13.01.2019 21:13
              +1

              Вот прямо идеальная формулировка.


            1. sshikov
              13.01.2019 21:49

              Гонять через сервисы код вообще нехорошо и небезопасно. Поэтому сериализуемое состояние по большому счету обязано содержать только данные. Можно вспомнить хоть например сравнительно недавние CVE на тему apache commons collections.

              >Если это объект, состояние которого определяется ещё и приватными свойствами, да ещё и с бизнес-логикой, то вы получите архитектурный косяк.
              Если он сам себя сериализует/десериализует, теряя по дороге приватные свойства — то это его личные внутренние проблемы, разве нет? Ну да, согласен, архитектурно это косяк. Вполне себе очевидный — не надо было пихать бизнес логику в те объекты, которые могут путешествовать по сервисам или тем более передаваться по сети.

              Но из этого совершенно не следует, что все объекты должны быть только такими.


              1. DrPass
                13.01.2019 23:15

                Но из этого совершенно не следует, что все объекты должны быть только такими.

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


    1. lair
      13.01.2019 15:29
      +2

      Только вот IRL люди отказываются от инкапсуляции и переходят к anemic object.

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


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


    1. SergeyGalanin
      13.01.2019 15:33
      +1

      Anemic не исключает сокрытия реализации = инкапсуляции, хоть данные и помещаются отдельно от функций. Раз есть тенденция к популяризации anemic — значит, для кого-то это имеет смысл. Значит, инкапсуляция в смысле википедии не так уж и хороша, раз ей пренебрегают.

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


      1. DrPass
        13.01.2019 15:42

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

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


      1. rustacean137
        13.01.2019 21:46

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

        Мое мнение, anemic модели просто более есстественны, это всё же данные, например, у реального документа нет поведение.
        + это путь наименшего сопротивления, когда отсувствует четких правил по архитектуры.


        1. lair
          13.01.2019 22:03

          у реального документа нет поведение.

          … а у кого "реального" есть поведение?


          1. rustacean137
            14.01.2019 01:09

            Думаю неудачно написал.
            Если не проектируем живых организмов, поведение думаю нет, т.е. в большинстве случаев не проектируем ничего с поведением.


            1. lair
              14.01.2019 01:14

              Ой ли?


              "получив заказ от покупателя, оператор проверяет наличие всех позиций на складе, а затем отправляет покупателю счет на оплату"


              Это разве не поведение?


              1. rustacean137
                14.01.2019 01:20

                Оператор, покупатель, это не живые организмы в реале?


                1. lair
                  14.01.2019 01:22

                  Они-то живые организмы. Но вот дальше начинаются две маленьких проблемы.


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


                  1. rustacean137
                    14.01.2019 01:33

                    Да, вы правы, спасибо.


        1. DrPass
          13.01.2019 23:28
          +1

          например, у реального документа нет поведение.

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


          1. rustacean137
            14.01.2019 00:55

            Смотря где вы проведёте границу ваших абстракций.

            Согласен.


            А можете рассматривать как бумажку, правила валидации и соответствующий бизнес-процесс.

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


            1. rustacean137
              14.01.2019 01:34

              Ошибся, поведение есть
              см. https://habr.com/post/435900/#comment_19609626


          1. michael_vostrikov
            14.01.2019 08:38

            А можете рассматривать как бумажку, правила валидации и соответствующий бизнес-процесс

            Соответствующий бизнес-процесс обычно кроме документа включает и другие сущности. Почему его надо помещать в документ, а не в любую другую?


            Не существует никакой самоцели

            Самоцели такой нет, но разговор-то был о том, почему так делают. Цель же не только в том, чтобы сделать модель на текущий момент, а чтобы изменения было проще вносить. Можно сделать не так, как в бумажных аналогах, но может получиться так, что бумажные аналоги просто передадут в другой отдел, а в системе придется половину классов переписывать.


            1. DrPass
              14.01.2019 12:05

              Соответствующий бизнес-процесс обычно кроме документа включает и другие сущности. Почему его надо помещать в документ, а не в любую другую?

              Не «надо», а «можно». Проектируя архитектуру приложения, у вас стоит задача в том, чтобы она
              а) эффективно решала поставленную задачу
              б) была понятной
              в) была сопровождаемой
              г) укладывалась в бюджет разработки
              Всё остальное вторично. Более того, даже всякие DRY, SOLID и иже с ними — это лишь методы достижения этих целей, которые в общем случае помогают их достичь, но бывают кейсы, когда их нужно нарушать.
              Почему бизнес-процесс может быть помещён в документ? Например, в вашей системе документооборота центральной сущностью является документ, и не существует бизнес-процессов, не построенных вокруг какого-то документа. Они могут порождать другие документы, они связаны с сущностями участников и чего-либо ещё, но всегда вертятся вокруг одного документа. Здесь решение агрегировать их в документ будет вполне адекватным среди других решений.


              1. michael_vostrikov
                14.01.2019 15:07

                Но факт остается фактом — документ сам себя не заполняет, его заполняет кто-то извне, и во всех процессах это так. Значит представление документа как анемичной модели точнее моделирует реальные процессы. Автоматизация убирает участие человека, но выполняемая им функция остается. Она может быть отнесена к объектам типа "Отдел" или вынесена в техническую сущность "сервис", но не к самому документу. У нее даже может быть свое состояние, которое не зависит от состояния документов.


                1. DrPass
                  14.01.2019 17:40

                  Значит представление документа как анемичной модели точнее моделирует реальные процессы.

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


                  1. michael_vostrikov
                    14.01.2019 18:09

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


                    1. DrPass
                      14.01.2019 19:00

                      Ну так анемичная модель это все и дает.

                      Да ничего она сама по себе не даёт, если честно. Всё в руках и голове разработчика. Испоганить анемичный объект с сервисом так же легко, как и старый добрый толстый объект.
                      Я не раз видел, как делают модель справочника, например, «категории клиентов», и к ней сервис, который позволяет CRUDить эти категории. И так — ко всем аналогичным справочникам. Просто потому, что в книжке где-то было сказано, что делать надо было так. В итоге получается приложение с кучей классов-прослоек, который кошмарен в плане сопровождения.


                      1. michael_vostrikov
                        14.01.2019 19:42

                        А в чем сложности с сопровождением?


                        Вы имеете в виду, лучше в один справочник все поместить? А как быть если потом у категорий клиентов появятся дополнительные атрибуты?


                        1. DrPass
                          15.01.2019 00:33

                          Вы имеете в виду, лучше в один справочник все поместить?

                          Нет, в данном случае такого сервиса вообще быть не должно. Только контроллер с формой редактирования/добавления. А операции вида «назначить категорию клиенту» относятся к сущности клиента и должны быть в сервисе управления клиентами.
                          А как быть если потом у категорий клиентов появятся дополнительные атрибуты?

                          Есть очень простое правило в разработке, которое, как ни странно, чаще соблюдают джуниоры и намного реже опытные разработчики: пишите код с заделом на будущее, если вы точно знаете, что ваше приложение будет масштабироваться, и как оно будет масштабироваться. И не пишите код с заделом на будущее, если вы не знаете, будет ли оно масштабироваться в будущем. Потому что это означает в 90% случаев, что оно масштабироваться не будет. Намного эффективнее переписать заново узкие места в 10% случаев, чем потратить ненужные усилия в 90%, закладывая в архитектуру то, что вам никогда не понадобится.


                          1. michael_vostrikov
                            15.01.2019 08:29

                            Только контроллер с формой редактирования/добавления.

                            Редактирования/добавления категорий клиентов? Ну так если не будет отдельного сервиса, код для CRUD будет в контроллере, контроллер и будет таким сервисом. Просто зачем писать его в контроллере, у него другая ответственность.


                            И не пишите код с заделом на будущее, если вы не знаете, будет ли оно масштабироваться в будущем.

                            Я все-таки не совсем понимаю, что вы имеете в виду. В контексте данного примера этот совет выглядит так, что вы предлагаете хранить категории клиентов и категории заказов в одной таблице, потому что у них одинаковые поля "id, name". Потому что если хранить в разных и иметь соответствующие классы в коде, то проблемы нет. Но я бы не назвал этот код "с заделом на будущее", так как у него есть преимущества сразу — ссылочная целостность в базе, типизация в коде.


      1. TheShock
        14.01.2019 18:44

        Anemic не исключает сокрытия реализации = инкапсуляции

        Как раз сокрытие реализации оно исключает. Скорее оно не исключает методы, даже по определению:

        Anemic domain model is the use of a software domain model where the domain objects contain little or no business logic (validations, calculations, business rules etc.).


        То есть такой подход вполне себе анемичен, открытые данные, с которыми можно работать извне и мало бизнес-логики:

        class Box
        {
            public int Height { get; set; }
            public int Width { get; set; }
        
            public int area()
            {
               return Height * Width;
            }
        }


    1. michael_vostrikov
      13.01.2019 17:11

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


  1. DrPass
    13.01.2019 14:59
    +1

    Пример: работа с денежными величинами. Не секрет, что во многих e-commerce системах денежные величины реализованы в виде чисел с плавающей запятой.

    Не слишком правильный пример, т.к. в финансовых системах чаще используются специальные «денежные» типы без побочных эффектов точности. А в банковских так вообще вообще очень распространено использование целых чисел, представляя сумму операции изначально в копейках/центах


  1. sshikov
    13.01.2019 15:07
    +1

    >Не секрет, что во многих e-commerce системах денежные величины реализованы в виде чисел с плавающей запятой

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


  1. ivlevAstef
    13.01.2019 16:36

    А в чем полезность заметки/статьи? В википедии написано тоже самое только подробней и точнее. А ещё есть чудесная книжка ООАД от Гради Буч- там не только определение, но и описание зачем оно нужно.

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


    1. Daddy_Cool
      13.01.2019 20:12

      Лично мне пример с «не совсем целыми» деньгами показался полезным в психологическом смысле. Т.е. при написание полезно задаваться вопросом — а не размазываю ли я инфу по телу программы делая то или иное действие.


      1. sshikov
        13.01.2019 21:41
        +2

        И что, тот факт, что хранение денег с плавающей точкой является хорошо известной формой bad practice, вас при этом не смущает?


        1. Daddy_Cool
          14.01.2019 13:37

          «хорошо известной формой» ))) Смотря кому. Научные сотрудники — те еще программисты. На эту тему на Хабре как-то были даже чьи-то ироничные комменты. Мне ни разу не приходилось писать программу где бы фигурировали всякие «франки, фунты- стерлинги, да тугрики», но возможно/наверняка у меня были другие гм… " bad practice". Увы.


          1. sshikov
            14.01.2019 14:34

            Ну, лично меня этому учили на первом курсе института. Это было… в 1975 году еще, при изучении Алгола. Как бы уже тогда было хорошо известно, что плавающая точка — она не для точных вычислений, а деньги лучше считать точно :)

            Может и не хорошо, но что давно известной — это факт.


            1. Daddy_Cool
              15.01.2019 13:02

              В будущем про это увы… забудут… или как раз таки нет? )
              «Предположим, у тебя на счету в банке 8000 долларов, которые приносят тебе 8 процентов годовых. Раз в неделю банк пересчитывает твой счет. То есть в конце первой недели банк умножит сумму счета на 0,0015384 и прибавит результат к сумме счета. Твое состояние увеличится на 12,30 доллара. Правильно? Проверь на калькуляторе.Я подсчитал – результат был верен.
              – Ровно двенадцать долларов и тридцать сантимов, – подтвердил я.
              – А вот и нет, – решительно возразил он. – Прибыль-то составила 12,3072, не так ли?
              – Да, но как прибавишь к счету семьдесят две сотые сантима?
              – Да, это непросто, потому что банковские счета знают только вторую цифру после запятой.

              Гарри Гаррисон „Рождение Стальной Крысы“.
              ))))))))))


              1. lair
                15.01.2019 13:18

                … а при чем тут плавающая точка?


                1. Daddy_Cool
                  15.01.2019 13:25

                  А… да. Согласен. Это несколько из другой оперы.


  1. Antigluk
    13.01.2019 23:45

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

    А деньги нормальные люди хранят целыми числами в копейках или в Decimal-типах, так что мимо.


    1. SergeyGalanin
      14.01.2019 15:13

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

      Ну почему же поздно? Рефакторинг в данной ситуации и будет состоять в извлечении метода/класса, то есть, в «моей терминологии», в инкапсуляции кусочков кода куда-то там.

      А деньги нормальные люди хранят целыми числами в копейках или в Decimal-типах, так что мимо.

      А ненормальные обрабатывают во float-ах, и тоже неплохо зарабатывают.


  1. nicholas_k
    13.01.2019 23:57
    +1

    Позволю себе не согласиться.

    Главное назначение инкапсуляции — это сокрытие сложности, а вовсе не компоновка схожего функционала. Компоновка(как противоположность размазыванию) — это полезный, но побочный эффект инкапсуляции.


    1. 411
      14.01.2019 08:57

      Более того, ни компоновка схожего функционала в одном месте, ни разнесение функционала над каким-то типом в различные части программы(неправильное использование которого как раз приводит к размазыванию и создаёт проблемы) не противоречат инкапсуляции и не обязательно её подразумевают. Это уже проблемы God Object, Single Responsibility и т.д.


    1. SergeyGalanin
      14.01.2019 09:45

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


      1. nicholas_k
        14.01.2019 11:37

        Подлинное назначение инкапсуляции — собрать в одном месте знания, относящиеся к устройству некой сущности, правилам обращения и операциям с ней.


        Собрать в одном месте != спрятать.

        Далее вы говорите и о том, что бы спрятать:

        Инкапсуляция в данном случае — собрать (спрятать) в одном месте знание о том...


        но подлинным назначением инкапсуляции это не называете.


        1. SergeyGalanin
          14.01.2019 15:07

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

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

          sum = round(money_a + money_b)

          И таких мест по коду было очень много. В каждой такой точке содержался кусочек знания о том, что реализация денег в этом коде хреновая (в виде float), деньги нужно постоянно округлять.

          Потом я заменяю сложение с округлением на специальный вызов, который сам умеет правильно складывать деньги с нужным округлением:
          sum = add_money(money_a, money_b)

          Теперь вы читаете add_money, и не видите никаких round. Я спрятал round? — спрятал.
          Таким вот нехитрым способом я прячу от глаз подальше подробности того, как нужно работать с деньгами в этом коде: просто вызывай add_money — и всё всегда будет хорошо, и никаких проблем с точностью.

          А что я сделал? Я инкапсулировал код, который выполняет нужные операции, в отдельный модуль, в отдельную функцию. Инкапсулировал? — да. Спрятал? — тоже да.


          1. nicholas_k
            15.01.2019 09:51

            Собрать в одном месте:

            class A {
             public round(...);
             public add_money(...)
            }


            Инкапсуляция:
            class B {
             private round(...);
             public add_money(...)
            }


            1. TheShock
              15.01.2019 18:17

              Инкапсуляция:

              Не, это сокрытие. Почему вы считаете наличие ключевого слова private хоть сколько то важным для инкапсуляции?


    1. TheShock
      14.01.2019 18:49

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


      1. nicholas_k
        14.01.2019 19:44

        Так ведь инкапсуляция — это один из шагов процесса абстрагирования)


  1. Sinatr
    14.01.2019 13:04

    А про что статья вообще? Не уверен, что это даже можно назвать статьей: введение, пара тезисов и пример, далекий от реальности (по крайней мере для меня).

    Посмотрел предущую статью про мускулы. Похоже на тенденцию, людям нравится… Мини-блог? Бессвязные мысли вслух?

    Может написать статью «Солнце светит» или «Ветер дует»? Или может обобщить «Ветер дует не так, как солнце светит»? /confused


    1. SergeyGalanin
      14.01.2019 15:47

      Не-не-не: «Ветер дует неправильно. Правильно дуть вот так».


    1. KvanTTT
      15.01.2019 01:54

      Зато сколько комментариев! Поразительно просто.