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

Объект учета и результат его классификации (существительные)


Проведем мысленный эксперимент. Представьте себе два хранилища моделей. В одном хранилище созданы классы для хранения моделей плавательных средств, в другом – классы для хранения моделей автомобилей. Допустим, что есть объект, который в одном хранилище описан как объект класса плавсредство, а во второй – как объект класса автомобиль. Допустим, что стоит задача объединения этих хранилищ в одно. Как вы это сделаете?

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

Как бы вы не поступили, у меня вопрос: как теперь вы назовете моделируемый объект? Автомобиль-плавсредство? А, если потом появятся другие классы, к которым относится этот объект? Будете перечислять их названия через дефис, и говорить: автомобиль-плавсредство-альфа-омега? Если задать этот вопрос аналитику, то ответом будет: это один и тот же объект, одновременно являющийся и автомобилем и плавсредством. Буквально это значит, что есть объект учета, который может быть одновременно классифицирован и как автомобиль, и как плавсредство. Из этого следует, что мы моделируем не автомобили и плавсредства, а объекты учета!

  • Создание объекта в хранилище – это моделирование объекта учета
  • Помещение созданного объекта в класс – это его классификация.

Поскольку эти две разные операции обычно производятся одновременно, то их не различают. Из-за этого возникает чувство, будто мы моделируем автомобили и плавсредства, хотя на самом деле – объекты учета. Этой путанице способствует наш язык.

Сравните высказывания:

  1. Это- дерево
  2. Это- объект учета, классифицированный как дерево.

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

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

В этом смысле стандарт OWL более корректен, потому что в нем можно создать неклассифицированную модель объекта учета. Это позволяет отделить операцию по моделированию объекта учета от операции по его классификации.

Объект учета и результат его классификации (прилагательные)


Когда мы говорим, что машина красная, мы предполагаем, что машина может обладать свойством – быть черной, красной и тд. Но могут ли на самом деле машины иметь свойства?

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

Ранее для моделирования объекта вы создали подкласс автомобилей и плавсредств. Теперь стоит задача моделирования одного цвета вместо двух. Для решения этой задачи вы можете поступить разными способами.

Возможно вы создадите один надкласс для класса автомобилей и класса плавсредств, у которого создадите атрибут цвет. У классов автомобилей и плавсредств вы создадите наследуемые от надкласса атрибуты «цвет». Затем переделаете все объекты, чтобы они соответствовали новому видению.
Возможно, вы определите интерфейс «цвет» и выполните реализацию этого интерфейса в каждом классе.

Что бы вы ни сделали, важно понять, что полученный атрибут «цвет» не будет принадлежать ни автомобилям ни плавсредствам. Это нечто, что существует вне этих классов. И это правильно, поскольку атрибут не связан с типом. Атрибут – это способ деления множества объектов на подмножества другим способом, отличным от типа. Об этом я писал ранее в статье Понятия: множество, тип, атрибут.
.
Поэтому, если быть строгим, нельзя говорить о свойстве, принадлежащем объекту, надо говорить о свойстве независимо от типа, или объекта, например, так:

Объект учета отнесен к классу красных объектов, то есть классифицирован.

Хот я утверждения такого рода являются корректными, на деле говорить подобным образом слишком затратно. Причина в языке. Когда мы передаем информацию другому субъекту, мы стремимся сократить объем выполняемой работы. Сравните высказывания:

  1. Красный автомобиль
  2. Объект учета относится к классу автомобилей и к классу красных объектов

В каком случае вы совершили меньше работы? Конечно, в первом. Но беда этого высказывания в том, что он наводит нас на мысль, будто атрибут принадлежит типу, а значение атрибута принадлежит классифицированному объекту.

ООП унаследовал и это заблуждение. С помощью ООП невозможно создать атрибут отдельно от класса (правда для этого можно использовать интерфейсы). И снова OWL нам в помощь: в этом стандарте типы и атрибуты существуют отдельно друг от друга. Поэтому при слиянии двух моделей в OWL нам не придется делать столько работы, сколько пришлось бы делать в ООП. Для слияния надо только объявить два атрибута тождественно равными и более ничего.

Смысл процесса классификации


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

На скорую руку приходит решение о создании новой модели, которая будет моделировать операцию под названием «купля-продажа», исполнителем которой будут Мартынов и Гаврилов. Но тут возникает вопрос: куда делась операция по продаже, исполнителем которой был Мартынов, и куда делась операция по покупке, исполнителем которой был Гаврилов? В новой модели эта информация оказалась потерянной, да еще и возникла коллизия, ведь операция – это такое действие, которое должно иметь цель. У продажи цель есть – продать подороже, и ради нее работал Мартынов. У покупки есть цель – купить подешевле, и ради нее работал Гаврилов. А у купли-продажи нет цели, потому что у нее нет стейкхолдера. Как же сохранить информацию, которая была в хранилищах до их объединения, избежать коллизии и, в то же время, объединить модели операций?

Для этого нам надо поступить так же, как мы поступили с автомобилями. Надо создать модель объекта учета и отнести его к двум разным классам одновременно: к классу операций по продаже и к классу операций по покупке. В разных классах будет один атрибут «исполнитель», значения которого будут зависеть от того, какой класс мы рассматриваем: класс покупок, или класс продаж. И это неожиданно – оказывается, что значения атрибутов одного объекта учета могут зависеть от того, как мы классифицировали объект учета.

Это кажется странным, но здесь нет ничего удивительного. Разные люди могут классифицировать один и тот же объект по-разному. Кто-то считает, что это – машина, а кто-то считает, что это – плавсредство. Для кого-то это — операция по продаже, а для кого-то – операция по покупке. Теперь проясняется смысл классификации. Классификация объекта учета – это выражение определенной точки зрения на объект учета. Нет автомобилей, но есть объект учета и субъект, трактующий этот объект учета как автомобиль. Нет операции по продаже, есть субъект, который трактует объект учета как операцию по продаже.

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

Поэтому тезисы про автомобиль и плавсредство надо уточнить:

  1. Объект учета с точки зрения Иванова классифицирован как плавсредство.
  2. Тот же объект учета с точки зрения Сидорова отнесен к классу плавсредств.
  3. Тот же объект с точки зрения Иванова и Сидорова отнесен к классу красных объектов.

Говорить что-либо об объекте учета без ссылки на субъект, который провел описание этого объекта, не имеет смысла. Это как-бы очевидно, но почему-то аналитики об этом забывают.

О том, как при помощи OWL можно построить хранилище, в котором будут учтены разнообразные точки зрения, рассказано в статье: Multi-viewpoint Ontologies for Decision-Making Support.

Выводы


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

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


  1. NLO
    01.07.2017 12:31

    НЛО прилетело и опубликовало эту надпись здесь


    1. maxstroy
      01.07.2017 12:40
      +1

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


      1. NLO
        01.07.2017 13:05

        НЛО прилетело и опубликовало эту надпись здесь


        1. maxstroy
          01.07.2017 13:13
          +1

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


          1. NLO
            01.07.2017 13:44

            НЛО прилетело и опубликовало эту надпись здесь


            1. maxstroy
              01.07.2017 13:57
              +1

              Транзакция — не есть продажа. Это изменилось. Если мы перепишем класс sale в виде обертки над transaction, то вопрос: что делать, если появится третья точка зрения, в которой эта же операция была операцией по истреблению остатков. Если мы перепишем класс истреблений остатков в виде обертки над классом транзакций, то получится, что класс транзакций — это и есть класс неклассифицированных объектов учета. То есть, это будет еще один способ моделирования объекта учета и его классификации при помощи оберток.


              1. NLO
                01.07.2017 14:07

                НЛО прилетело и опубликовало эту надпись здесь


  1. sand14
    01.07.2017 13:05
    +1

    using System;
    using System.Collections.Generic;
    using static System.Console;
    using static System.FormattableString;
    
    namespace InterfacesSample
    {
        interface IColoredEntity
        {
            int ColorCode { get; }
        }
    
        interface IVehicle : IColoredEntity
        {
            string VinNumber { get; }
            int WheelCount { get; }
            int MaxCarryingKgs { get; }
        }
    
        interface IBuilding : IColoredEntity
        {
            bool IsResidental { get; }
            int FloorCount { get; }
        }
    
        class PassengerCar : IVehicle
        {
            public string VinNumber { get; }
            public int WheelCount => 4;
            public int MaxCarryingKgs => 400;
            public int ColorCode { get; }
            public PassengerCar(string vinNumber, int colorCode)
            {
                VinNumber = vinNumber;
                ColorCode = colorCode;
            }
        }
    
        class ResidentalBuilding : IBuilding
        {
            public bool IsResidental => true;
            public int FloorCount { get; }
            public int ColorCode { get; }
            public ResidentalBuilding(int floorCount, int colorCode)
            {
                if (!(floorCount >= 1 && floorCount <= 100))
                    throw new ArgumentOutOfRangeException(nameof(floorCount));
    
                FloorCount = floorCount;
                ColorCode = colorCode;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var car1 = new PassengerCar(vinNumber: "VIN 1", colorCode: 0);
                var car2 = new PassengerCar(vinNumber: "VIN 2", colorCode: 1);
    
                var house1 = new ResidentalBuilding(floorCount: 100, colorCode: 2);
                var house2 = new ResidentalBuilding(floorCount: 100, colorCode: 3);
    
                var coloredObjects = new List<IColoredEntity>
                {
                    car1,
                    car2,
                    house1,
                    house2
                };
    
                var vehicles = new List<IVehicle>
                {
                    car1,
                    car2
                };
    
                WriteLine("Colored Objects:");
                foreach (var coloredObject in coloredObjects)
                {
                    WriteLine(Invariant(
                        $"Color: {coloredObject.ColorCode:X8}"));
                }
    
                WriteLine("Vehicles:");
                foreach (var vehicle in vehicles)
                {
                    WriteLine(Invariant(
                        $"Vin Number: {vehicle.VinNumber}; Color: {vehicle.ColorCode:X8}"));
                }
    
                // Output:
                //Colored Objects:
                //Color: 00000000
                //Color: 00000001
                //Color: 00000002
                //Color: 00000003
                //Vehicles:
                //Vin Number: VIN 1; Color: 00000000
                //Vin Number: VIN 2; Color: 00000001
            }
        }
    }


  1. copal
    01.07.2017 13:54

    А можно попросить объяснить мне что такое предметная область? А то я не понимаю, какое отношение имеет цвет, когда описывается предметная область сбыта автомобилей.


    1. maxstroy
      01.07.2017 14:50

      Есть условие задачи. Оно сформулировано в статье. Надо ее решить. Это не практическая задача по моделированию сбыта авто. Это мысленный эксперимент.


      1. copal
        01.07.2017 15:06
        +1

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


        1. maxstroy
          01.07.2017 15:16
          +1

          Если съесть три тонны лука, то умрешь. Это верно. Но из этого не следует вредность овощей. Из какого тезиса в моей задаче я сделал неверный вывод? То есть, если можно: тезис, вывод, и то, почему он неверный.


      1. copal
        01.07.2017 15:13
        +1

        И почему не введено понятие «товар» с которым бы и проводились все операции. В условиях явно перемешались области-слои, какой Вывод Вы хотели получить? И Вы описываете структуру, а не поведение модели предметной области.


        1. maxstroy
          01.07.2017 15:21

          Я хочу решение поставленной задачи. Более ничего. Есть два хранилища, их надо соединить в одно. Как бы программист решал эту задачу? Вот мой интерес. При этом стоит условие — для пользователя ничего не должно поменяться — ни названия объектов, ни их свойства.


          1. michael_vostrikov
            01.07.2017 15:23

            Программист бы спросил "Зачем?". То есть, какая цель у этой операции.


            1. maxstroy
              01.07.2017 16:02

              Будем считать, что ему ответили на этот вопрос, дали денег и заключили контракт. Как он будет это делать?


              1. michael_vostrikov
                01.07.2017 16:46

                "Как" он будет это делать напрямую зависит от того, "что" ему ответили на этот вопрос. Он ведь не просто так спросил. А в такой формулировке ответ будет такой: будем считать, что он взял и сделал.


                1. maxstroy
                  01.07.2017 17:03

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


                  1. michael_vostrikov
                    01.07.2017 18:18
                    +1

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


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


                    было:
                    
                    операции_продажи: (хранилище 1)
                    id: 123, время: 2017-06-10 10:26, товары: [A,B,C]
                    id: 124, время: 2017-06-10 10:27, товары: [D,E,F]
                    
                    операции_покупки: (хранилище 2)
                    id: 678, время: 2017-06-10 10:28, товары: [A,B,C]
                    id: 679, время: 2017-06-10 10:29, товары: [D,E,F]
                    
                    стало:
                    
                    операции_продажи: (общее хранилище)
                    id: 123, время: 2017-06-10 10:26, товары: [A,B,C]
                    id: 124, время: 2017-06-10 10:27, товары: [D,E,F]
                    
                    операции_покупки: (общее хранилище)
                    id: 123, время: 2017-06-10 10:28, товары: [A,B,C]
                    id: 124, время: 2017-06-10 10:29, товары: [D,E,F]
                    

                    Также в БД или на уровне приложения делается одно или несколько представлений, которые по первичному ключу будут объединять точки зрения в разных сочетаниях, которые нужны тому, кто заказал эту музыку.


                    В свою очередь прошу привести пример вашего решения на основе этих данных.


                    1. maxstroy
                      01.07.2017 19:58
                      +1

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


                1. svboobnov
                  05.07.2017 17:39

                  michael_vostrikov, Это называется Онтология.
                  maxstroy, наверное, решил рассказать об этом в следующей статье.


              1. copal
                01.07.2017 16:47

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


          1. copal
            01.07.2017 15:28

            Я перечитал ещё раз про цвет и транспорт и хочу поправить себя — тут я согласен с Вам, атрибута цвет у транспорта нет.


  1. sand14
    01.07.2017 14:02

    using System.Collections.Generic;
    using System.Globalization;
    using static System.Console;
    
    namespace InterfacesSample2
    {
        interface ILandVehicle
        {
            int MaxCarryingKgs { get; }
            int MaxPassengers { get; }
        }
    
        interface ISwimmingVehicle
        {
            int MaxCarryingKgs { get; }
            int MaxPassengers { get; }
        }
    
        interface IAmphibian : ILandVehicle, ISwimmingVehicle
        {
        }
    
        class Sedan : ILandVehicle
        {
            public int MaxCarryingKgs => 400;
            public int MaxPassengers => 4;
        }
    
        class Pickup : ILandVehicle
        {
            public int MaxCarryingKgs => 500;
            public int MaxPassengers => 1;
        }
    
        class Boat : ISwimmingVehicle
        {
            public int MaxCarryingKgs => 450;
            public int MaxPassengers => 3;
        }
    
        class UniversalVehicle : IAmphibian
        {
            public int MaxCarryingKgs => 250;
            public int MaxPassengers => 2;
        }
    
        class SwimmingCar : IAmphibian
        {
            public int MaxCarryingKgs => 300;
            public int MaxPassengers => 3;
    
            int ISwimmingVehicle.MaxCarryingKgs => 200;
            int ISwimmingVehicle.MaxPassengers => 1;
        }
    
        class Amphibian : IAmphibian
        {
            int ILandVehicle.MaxCarryingKgs => 350;
            int ILandVehicle.MaxPassengers => 3;
    
            int ISwimmingVehicle.MaxCarryingKgs => 250;
            int ISwimmingVehicle.MaxPassengers => 1;
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var sedan = new Sedan();
                var pickup = new Pickup();
                var universalVehicle = new UniversalVehicle();
                var swimmingCar = new SwimmingCar();
                var amphibian = new Amphibian();
                var boat = new Boat();
    
                var landVehicles = new List<ILandVehicle>()
                {
                    sedan, pickup, universalVehicle, swimmingCar, amphibian
                };
    
                var swimmingVehicles = new List<ISwimmingVehicle>
                {
                    universalVehicle, swimmingCar, amphibian, boat
                };
    
                var amphibians = new List<IAmphibian>
                {
                    universalVehicle, swimmingCar, amphibian
                };
    
                WriteLine("Land Vehicles:");
                foreach (var vehicle in landVehicles)
                {
                    WriteLine(string.Format(
                        CultureInfo.InvariantCulture,
                        "MaxCarryingKgs: {0}; MaxPassengers: {1}",
                        vehicle.MaxCarryingKgs, vehicle.MaxPassengers));
                }
    
                WriteLine("Swimming Vehicles:");
                foreach (var vehicle in swimmingVehicles)
                {
                    WriteLine(string.Format(
                        CultureInfo.InvariantCulture,
                        "MaxCarryingKgs: {0}; MaxPassengers: {1}",
                        vehicle.MaxCarryingKgs, vehicle.MaxPassengers));
                }
    
                WriteLine("Amphibians:");
                foreach (var vehicle in amphibians)
                {
                    WriteLine(string.Format(
                        CultureInfo.InvariantCulture,
                        "MaxCarryingKgs: {0}/{1}; MaxPassengers: {2}/{3}",
                        ((ILandVehicle)vehicle).MaxCarryingKgs,
                        ((ISwimmingVehicle)vehicle).MaxCarryingKgs,
                        ((ILandVehicle)vehicle).MaxPassengers,
                        ((ISwimmingVehicle)vehicle).MaxPassengers));
                }
    
                // Output:
                //Land Vehicles:
                //MaxCarryingKgs: 400; MaxPassengers: 4
                //MaxCarryingKgs: 500; MaxPassengers: 1
                //MaxCarryingKgs: 250; MaxPassengers: 2
                //MaxCarryingKgs: 300; MaxPassengers: 3
                //MaxCarryingKgs: 350; MaxPassengers: 3
                //Swimming Vehicles:
                //MaxCarryingKgs: 250; MaxPassengers: 2
                //MaxCarryingKgs: 200; MaxPassengers: 1
                //MaxCarryingKgs: 250; MaxPassengers: 1
                //MaxCarryingKgs: 450; MaxPassengers: 3
                //Amphibians:
                //MaxCarryingKgs: 250/250; MaxPassengers: 2/2
                //MaxCarryingKgs: 300/200; MaxPassengers: 3/1
                //MaxCarryingKgs: 350/250; MaxPassengers: 3/1
            }
        }
    }


  1. movsb
    02.07.2017 23:19

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

    Зачем что-то выдумывать, чтобы назвать моделируемый объект? Если мы моделируем классы для хранения моделей плавательных средств и классы для хранения моделей автомобилей, то у них уже есть названия – это названия моделей. Например, для глиссирующего автомобиля-амфибии «Тритон» мы выберем имя класса Тритон.


    1. maxstroy
      03.07.2017 07:58

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


      1. movsb
        03.07.2017 08:32

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


        1. maxstroy
          03.07.2017 09:10
          +1

          Оечь идет о возможности объединения разных хранилищ без переделки структуры хранилищ. Это требование к расширяемости модели. Я показываю, что при помощи ООП это сделать невозможно, потому что мы натыкаемся на необходимость менять структуру. Однако существуют подходы к моделированию, при которых модель расширяема без изменения структуры данных. Речь о том, как должна выглядеть такая модель, и что она значит?


          1. michael_vostrikov
            03.07.2017 13:01
            -2

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


          1. movsb
            03.07.2017 13:15
            +1

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


            1. maxstroy
              03.07.2017 14:25
              +1

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


              1. michael_vostrikov
                03.07.2017 22:26
                +1

                У вас тоже надо что-то менять в структуре. Стали рассматривать новый атрибут — вы ведь его вручную добавляете через интерфейс. То есть меняете модель.


                Я не понимаю

                Я вам там пример показал, как было и как стало. Отличие только в данных, но не в структуре.
                Если вы не понимаете ООП, может не стоит рассуждать на эту тему?


                1. maxstroy
                  05.07.2017 13:17

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


                  1. michael_vostrikov
                    05.07.2017 13:28
                    +1

                    без изменения структуры хранилища

                    Новый атрибут у типа это разве не изменение структуры?


                    это все делается единым образом через интерфейс

                    А в коде программ это делается единым образом через код. Код — это и есть модель. Если предметная область изменилась, надо изменять и модель.


                    и без изменения кода

                    В любой СУБД структура таблиц меняется без изменения кода СУБД.


                    У истоков было все иначе, например, атрибуты были отделены от классов

                    Это у каких например истоков?


                    Кто это сделал, тому просто не хотелось сильно думать.

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


                    1. maxstroy
                      05.07.2017 14:38

                      Мы ходим по кругу. Я объясняю свое мнение насчет ООП. Я считаю, что оно вредно более, чем полезно. И это мнение, которое сложилось на основе общения с программистами, которые ничего, кроме ООП не знают. Те же, кто вырос из ООП, скорее согласятся со мной. Но это не более, чем моя точка зрения. Можно ее критиковать, но я предпочел бы общаться фактами. Если ООП создает атрибуты внутри типа, то это -факт. И это вредно с моей точки зрения. Так же я считаю, что создание метода внутри типа — не менее вредное заблуждение. И опять — это мое мнение. Вам нравится ООП, на здоровье! Каждому свое.


                      1. michael_vostrikov
                        05.07.2017 15:55
                        +1

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


                        1. maxstroy
                          05.07.2017 16:11

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


                          1. michael_vostrikov
                            05.07.2017 17:36
                            +1

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


                            В статье вы рассказываете например такой факт: "Поэтому при слиянии двух моделей в OWL нам не придется делать столько работы, сколько пришлось бы делать в ООП.". Это неверно, и я привел пример это доказывающий. Вы никаких практических примеров вообще не привели.


              1. movsb
                05.07.2017 13:12

                Расширяемость модели должна быть, не вопрос. Но и структуру хранилищ менять надо, если это необходимо для новой модели. В противном случае, делая неизменной структуру базы данных, вы не сможете оптимально ее использовать, так как для новых типов предметной области могут понадобиться новые индексы, хранимые процедуры и прочее. А делая неизменными программные классы модели, вы не сможете добавить в них код. Модель предметной области это же не только данные, но и алгоритмы их обработки. Какие применения хранилищ, с которыми вы работаете?


            1. flancer
              03.07.2017 15:09
              +1

              Вот пример структуры хранилища (для MySQL), которая (в теории) позволяет сохранять данные об объектах (obj), различных способах их классификации (классах, моделях — classifier) и способах разбиения (конструкции — struct) целого (obj) на части (elem).


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


              1. flancer
                03.07.2017 22:52
                +1

                :( Ссылку не на тот скрипт дал. Вот правильный. Неверная ссылка ведет на более конкретную версию структуры данных под пример из статьи, а правильная — как раз на более универсальную версию.


        1. AnneSmith
          03.07.2017 09:27

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

          именно его всегда упускают при разработке и заменяют самим подмножеством; и в случае если ваше подмножество вдруг стало не единственным, у вас не средств объединить эти подмножества, и вы создадите еще один класс «модель 2», то есть по сути дубликат класса «модель 1»

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

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


    1. AnneSmith
      03.07.2017 09:15

      а завтра производители сменят «тритон» на «кватротрон», как это случилось, например, с Scion и Toyota, или добавят «пентатрон»

      название модели не может быть классом, за исключением ситуации, когда название модели объединяет абсолютно все объекты этого класса, и вы уверены, что это имя никогда не изменится, но тогда это имя вообще не имеет никакого значения, и можно использовать просто «item»


      1. movsb
        03.07.2017 12:57

        Задача же не в создании классов на все времена. Это попросту невозможно. Если произойдут изменения в предметной области, можно будет внести изменения в классы и выпустить обновление. По-любому придется пересматривать классификацию, когда появятся летающие автомобили.


        1. maxstroy
          03.07.2017 14:27

          Классы и объекты классов — все это объекты учета, которые должны храниться единым образом, что и реализовано в OWL. Именно поэтому не надо ничего менять, поскольку структура моделируется так же, как и данные в ней. В этом сила OWL. И слабость ООП, о которой я пишу.


        1. AnneSmith
          04.07.2017 21:49

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

          классификацию не придется пересматривать, если «летающие автомобили» — это всего лишь еще одна опция в категории «товары»

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


          1. maxstroy
            05.07.2017 07:42
            +1

            Код отделен от структуры хранилища. Потому что все записывается в виде триплетов RDF. Даже алгоритмы, представления интерфейсных форм и проч… — все записывается единым образом. Код умеет считывать эти данные и производит нужные построения, вычисления, записи, удаления и проч.


          1. movsb
            05.07.2017 11:23

            так вам все приложение придется переписывать

            Не переписывать, а дополнять и немного изменять, если мы правильно спроектировали иерархию классов и предусмотрели возможность развития и быстрого внесения изменений. Все приложения сейчас обновляются, и это в порядке вещей. «Soft» в отличие от «Hard» мягкий, то есть изменчивый. Бухгалтерский софт обновляется с изменением законодательства, драйвера обновляются с выходом новых устройств, и т.д. Изменения в моделируемой предметной области влекут изменения в приложении, что в этом необычного? И если руки не кривые, можно будет использовать созданные классы в аналогичных проектах.

            классификацию не придется пересматривать

            Давайте на примере. В классе «Транспортные средства» есть поля «Объем топливного бака, л» и «Расход топлива на 100 км». И мы реализовали функцию расчета, сколько можно проехать на полном баке без дозаправки «Максимальное расстояние» = Объем бака / Расход * 100. Отлично, но появляются летающие автомобили, которым требуется топливо на взлет и посадку. Мы добавляем класс «Летающий автомобиль» и поля «Расход топлива на взлет, л» и «Расход топлива на посадку, л». Если мы предусмотрительно объявили функцию «Максимальное расстояние» как виртуальную, то переопределяем ее: Расход на взлет + Объем бака / Расход * 100 + Расход на посадку. Как это сделать без ООП, если у нас один класс «Товары»?
            Поэтому классификация в коде вводится не для того, чтобы разбить товары на группы или выделить какие-то опции. Классы различаются еще и поведением, то есть методами.


            1. AnneSmith
              06.07.2017 04:26

              если у вас один класс товары, то вы можете добавлять туда любые категории товаров с любыми атрибутами, в том числе и летающие машины с любыми характеристиками

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

              что вам мешает сделать класс достаточно абстрактным и свести различия к минимуму?

              об этом же и идет речь: классы, которые вы придумали, находятся только в вашей голове, а значит из класса всегда можно сделать подкласс и ввести более общую категорию, которая избавит вас от большинства проблем, которые вы называете «обновлениями»


              1. movsb
                06.07.2017 07:07

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


                1. AnneSmith
                  06.07.2017 08:58

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

                  в моем примере ниже, с объектами интерфейса, алгоритмы обработки характеристик выделены в отдельные методы, которые в свою очередь организованы в соотвествии с характеристиками объектов — обьект 1, к которому не имеет отношение метод 2, никогда его и не увидит

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

                  кстати, те примеры полиморфизма, что можно быстро найти даже тут на хабре, как раз иллюстрируют неверный выбор hardcoded классов, которые невозможно перенести в другой проект :)


              1. michael_vostrikov
                06.07.2017 07:33
                -1

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


                Приведите пожалуйста конкретную реализацию с вашим подходом на примере операций покупки и продажи.


                которая избавит вас от большинства проблем, которые вы называете «обновлениями»

                Допустим, мы решили добавить понятие "vip-клиент" и давать таким клиентам скидку в 20%. До этого в предметной области никаких vip-клиентов не было. Как ваш подход поможет избежать "обновлений"?


                1. AnneSmith
                  06.07.2017 08:39

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

                  кстати, если бы вы рассуждали в ООП подходе, то вопроса об ифах у вас даже не должно было возникуть

                  попробуйте решить ваши задачи с товарами под названиями A, B, C etc, то есть в общем виде с общими категориями, не привязываясь к шкафам и автомобилям

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

                  ваша система должна уметь обрабатывать любой товар: вряд ли кто-то строит системы по продаже одних конфет или одних велосипедов

                  у меня другие объекты, не товары, а элементы интерфейса; как вы понимаете их много разных и они все работают по-разному, но мы все свели к абстрактному понятию типа «объект» и двум базовым функциям этих объектов, и теперь имеем полную свободу в коммуникации между этими объектами с возможностью добавлять в этот класс любое количество типов с любой логикой и таскать эти объекты с той же логикой в любой проект

                  это было бы невозможно, если бы мы пошли по вашему пути и делали бы классы типа «vip-клиент», «банк», «транзакция» и каждый со своими атрибутами и методами, а потом думали бы, как поженить мышку с кошкой

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

                  опять же красивые решения не возникают за 5 минут обсуждения в интернете, но это не значит, что они не возникают вообще


                  1. michael_vostrikov
                    06.07.2017 09:02
                    -1

                    сделайте разные функции и назначьте их в соответствии с категориями товаров

                    И как же это сделать? Приведите пример.


                    у меня другие объекты, не товары, а элементы интерфейса

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


                    с возможностью добавлять в этот класс любое количество типов

                    Опять же, приведите пример. Судя по описанию, у вас все-таки есть разные типы и наследование.


                    думаю, что решение добавить понятие «vip-клиент» в класс товаров ошибочно

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


                    то есть скидка — просто еще один атрибут товара

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


                    опять же красивые решения не возникают за 5 минут обсуждения в интернете

                    Но вы же говорите, что у вас уже есть решение, которое вы проверили и потому его советуете.


                    1. AnneSmith
                      06.07.2017 15:52

                      извините, но предметная область не имеет никакого значения — ваша задача должна решаться в общем виде

                      когда вы попробуете это сделать, то сами легко сможете привести любой пример

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

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

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

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


                      1. michael_vostrikov
                        06.07.2017 16:30
                        -1

                        То есть примеров, подтверждающих преимущество вашего подхода, у вас нет. Только слова о том, как это просто и удобно. Ок.


  1. flancer
    03.07.2017 12:27
    +1

    Надо создать модель объекта учета и отнести его к двум разным классам одновременно: к классу операций по продаже и к классу операций по покупке. В разных классах будет один атрибут «исполнитель», значения которого будут зависеть от того, какой класс мы рассматриваем: класс покупок, или класс продаж. И это неожиданно – оказывается, что значения атрибутов одного объекта учета могут зависеть от того, как мы классифицировали объект учета.

    Если я правильно понял задачу, то к одному объекту учета относятся 2 "исполнительных" атрибута:


    • "исполнитель-продавец"
    • "исполнитель-покупатель"

    Для класса "операция по покупке" атрибут "операция по покупке"."исполнитель" соответствует атрибуту "исполнитель-покупатель", для другого класса — "исполнитель-продавец":


    • "операция по покупке"."исполнитель" = "объект учета"."исполнитель-покупатель"
    • "операция по продаже"."исполнитель" = "объект учета"."исполнитель-продавец"

    Т.е. вовсе не оказывается, что "значения атрибутов одного объекта учета могут зависеть от того, как мы классифицировали объект учета". Значения атрибутов объекта учета не зависят от классификации. От классификации зависит маппинг (сопоставление) атрибутов класса (значимых в контексте рассматриваемой задачи) и атрибутов объекта учета (всех доступных атрибутов объекта). Другое дело, что мы в целях экономии, как правило, маппим атрибуты один-в-один: "цвет" на "цвет", "массу" на "массу", поэтому и создается впечатление, что "атрибут класса" == "атрибут объекта". По значению — да, а по имени — не всегда.


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


    А в целом — весьма интересно наблюдать за вашей серией публикаций. Чувствуется биение мысли :)


    1. maxstroy
      03.07.2017 14:32

      Значения атрибута, конечно, не зависят от классификации. Они зависят от точки зрения на объект учета. Иванов ли смотрит, или Сидоров. Пример с классификацией — лишь промежуточный вывод на пути к основному.

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


      1. flancer
        03.07.2017 14:53
        +1

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


        1. maxstroy
          03.07.2017 15:31

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


          1. flancer
            03.07.2017 16:39

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


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


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


            А как быть тогда в случае, если один человек правила создал, второй их изменил, а третий улучшил? Кого в этом случае указывать в качестве "субъекта, проведшего классификацию"?


            1. maxstroy
              03.07.2017 17:19

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


              1. flancer
                03.07.2017 17:43
                +1

                Под классификацией я понимаю отнесение объекта учета к классу.

                В таком случае совершенно верно "классификация — процесс субъективный". Т.к. при таком подходе возможно отнесение субъектом объекта учета, обладающего атрибутом "двигатель внутреннего сгорания", к классу "крокодилы Луизианы". Согласен, что в этом случае совершенно необходимо иметь "указание на субъект, проведший классификацию", дабы этому субъекту в следующий раз неповадно было.


                Залез в wiki, посмотреть про классификацию — познавательно.