Как запутать аналитика. Часть вторая: что такое моделирование предметной области?
Комментарии (23)
- НЛО прилетело и опубликовало эту надпись здесь
1 июля 2017 в 12:40
+1↑
↓
Начальные данные таковы, что это не была одна транзакция. Это были две модели разных операций в разных хранилищах.- НЛО прилетело и опубликовало эту надпись здесь
1 июля 2017 в 13:13 (комментарий был изменён)
+1↑
↓
обращение в транзакцию убьет информацию, которая была изначально в хранилищах, а мы этого не хотим. Ведь никто не захочет, чтобы кто-то извне менял его модель. Сидоров хочет, чтобы информация о продажах хранилась в том виде, в котором он ее создал. Кому-то, кому надо, пусть создает новые модели, но Сидоров хочет видеть то, что он сделал. Он не согласен на транзакцию, он утверждает, что это была продажа.- НЛО прилетело и опубликовало эту надпись здесь
1 июля 2017 в 13:57 (комментарий был изменён)
+1↑
↓
Транзакция — не есть продажа. Это изменилось. Если мы перепишем класс sale в виде обертки над transaction, то вопрос: что делать, если появится третья точка зрения, в которой эта же операция была операцией по истреблению остатков. Если мы перепишем класс истреблений остатков в виде обертки над классом транзакций, то получится, что класс транзакций — это и есть класс неклассифицированных объектов учета. То есть, это будет еще один способ моделирования объекта учета и его классификации при помощи оберток.- НЛО прилетело и опубликовало эту надпись здесь
1 июля 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
{ car1, car2, house1, house2 }; var vehicles = new List { 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 июля 2017 в 13:54 (комментарий был изменён)
0↑
↓
А можно попросить объяснить мне что такое предметная область? А то я не понимаю, какое отношение имеет цвет, когда описывается предметная область сбыта автомобилей.1 июля 2017 в 14:50
+1↑
↓
Есть условие задачи. Оно сформулировано в статье. Надо ее решить. Это не практическая задача по моделированию сбыта авто. Это мысленный эксперимент.1 июля 2017 в 15:06
0↑
↓
Я понимаю что мысленный, но звучит он как «овощи очень вредны, ведь если съесть три тонны лука — то умрешь».
Мне кажется что если задачу поставить заведомо неправильным образом, то она может привести к неправильным решениям. Почему Вы говорите авто-плаволка, а не транспортное средство? Почему поведение зависит от второстепенных данных не относящихся к предметной области, как например цвет?1 июля 2017 в 15:16 (комментарий был изменён)
+1↑
↓
Если съесть три тонны лука, то умрешь. Это верно. Но из этого не следует вредность овощей. Из какого тезиса в моей задаче я сделал неверный вывод? То есть, если можно: тезис, вывод, и то, почему он неверный.
1 июля 2017 в 15:13 (комментарий был изменён)
0↑
↓
И почему не введено понятие «товар» с которым бы и проводились все операции. В условиях явно перемешались области-слои, какой Вывод Вы хотели получить? И Вы описываете структуру, а не поведение модели предметной области.1 июля 2017 в 15:21 (комментарий был изменён)
0↑
↓
Я хочу решение поставленной задачи. Более ничего. Есть два хранилища, их надо соединить в одно. Как бы программист решал эту задачу? Вот мой интерес. При этом стоит условие — для пользователя ничего не должно поменяться — ни названия объектов, ни их свойства.1 июля 2017 в 15:23
0↑
↓
Программист бы спросил «Зачем?». То есть, какая цель у этой операции.
1 июля 2017 в 16:02
0↑
↓
Будем считать, что ему ответили на этот вопрос, дали денег и заключили контракт. Как он будет это делать?1 июля 2017 в 16:46
0↑
↓
«Как» он будет это делать напрямую зависит от того, «что» ему ответили на этот вопрос. Он ведь не просто так спросил. А в такой формулировке ответ будет такой: будем считать, что он взял и сделал.
1 июля 2017 в 17:03
0↑
↓
Его попросили объединить два хранилища так, чтобы каждый из пользователей остался при своих моделях, но тот, кто заказал эту музыку, мог бы видеть, как модели объектов учета меняются в зависимости от разных точек зрения на них. Мы выяснили, что операция была одна и та же, но знаем, что было множество разных стейкхолдеров, которые могли бы видеть ее по-разному. Нам надо построить такую модель, которая удовлетворила бы потребности стейкхолдеров в своих представлениях о мире и могла бы дать нам возможность видеть общую картину в целом. То есть, наша задача интегрировать хранилища, обеспечить их представление для разных пользователей и дать нам инструмент для анализа.1 июля 2017 в 18:18
0↑
↓
Наверно вам это покажется неожиданным, но с такой формулировкой ничего менять не надо. Единственное что надо сделать — задать одинаковые идентификаторы записям об одной операции в разных хранилищах. Общего у всех точек зрения только информация о том, что это одна и та же операция. Ваш «объект учета» есть не что иное как первичный ключ.
В принципе можно и по-другому сказать. Объект учета — это объект, единственным атрибутом которого является первичный ключ. В базе данных это будет таблица с одним полем «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 июля 2017 в 19:58
0↑
↓
Верно, одним из атрибутов объекта учета является первичный ключ. Но можно добавить еще и другие. Поскольку объект (не множество) — есть 4-хмерный объем, то атрибутами его могут быть границы этого объекта, например, временные: с и по.
1 июля 2017 в 16:47
0↑
↓
ну так ответа однозначного нет. Все дело в том, что машина может быть выражена множеством вариантов в зависимости от позиции наблюдателя — предметной области. Если бы я продавал авто, то мне бы было удобно чтобы тип «авто» инкапсулировал даже цвет. Если бы я продовал машины по запчастям, то авто бы выражалось в виде коллекции её частей. Если бы мне сказали перепроектировать архитектуру магазина авто в магазин запчастей без изменения кода, да ещё за пару часов и пару тыщь, то скорее всего я бы послал просто нафиг.
1 июля 2017 в 15:28
0↑
↓
Я перечитал ещё раз про цвет и транспорт и хочу поправить себя — тут я согласен с Вам, атрибута цвет у транспорта нет.
1 июля 2017 в 14:02
0↑
↓
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
() { sedan, pickup, universalVehicle, swimmingCar, amphibian }; var swimmingVehicles = new List { universalVehicle, swimmingCar, amphibian, boat }; var amphibians = new List { 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 } } }