Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>А почему в entity мне должно быть это итересно? она сама по себе сохранением-то и не занимается.

T>>Почему ради того, чтобы следовать SRP я должен выставлять все члены наружу?
S>Ты слишком много думаешь об entity.

S>В нормальной системе entity моделируют нижележащие данные, которые и есть предметная область.


В этом и предмет разногласия. Для domain model "нижележащие данные" — это всего лишь способ долговременного хранения сущностей.

S>То, что сами эти данные в свою очередь являются моделью чего-то еще, в этот момент несущественно.


S>У данных есть только одна обязанность — "быть". Способ сохранения данных ортогонален самим данным. То, что атрибут "зарплата" не может быть меньше нуля — ортогонально структуре "карточка сотрудника". Алгоритм капитализации ФИО ортогонален структуре "Карточка сотрудника".


Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

S>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.


И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

T>>Есть много разных вещей, которые не могут быть вынесены за пределы сущности, т.к. они могут ломать валидность класса.

S>Ты слишком много думаешь о классах. Выносить за пределы класса нужно всё, что можно вынести за пределы класса.
S>Поскольку публичный контракт "сущности" сводится к умению группировать данные, то 100% поведения должно быть вынесено за ее пределы.

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

T>>Зато поднимают настроение

S>Заранее намекаю: злоупотребление некошерными методами подъема настроения на этом форуме чревато воспитательными мерами.

Ок, не буду.
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:03
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Классы customer, customercotainer, location, department, person

T>>Помогло?

G>Да, прямо ER-модель получилась.


Не, получилась вполне себе rich domain model
Re[21]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

T>>Классы customer, customercotainer, location, department, person

T>>Помогло?
S>А чему в предметной области соответствует customercontainer?

Да. Это понятие, которыем оперируют те, кто продает услуги кастомерам.

S>Вообще, как правило структура данных не совпадает с устройством предметной области. Она иногда на неё похожа, но это иллюзорное сходство.

S>Простейший пример — есть список кастомеров. Надо понимать, во-первых, что элементами списка являются не кастомеры, а записи о кастомерах.

Вы забыли добавить "при моем подходе". Если используем domain model, то вполне себе customer-ы, точнее их программное представление в domain model.

S>Во-вторых, что сам список кастомеров в "предметной области" может быть организован, к примеру, в виде Post-it бумажек, наклеенных на whiteboard.


Это не кастомер, это способ хранения информации о кастомере.

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

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

Это некорректная аналогия, т.к. моделировать нужно не листочки о кастомерах, а их самих.

S>При этом в entity "customer" появятся какие-то атрибуты, которые не имеют никакого отношения ни к реальным покупателям, ни к доске, ни к бумажкам.


Ближе к телу. Что за атрибуты?

S>Этакие "артефакты модели". Задача "максимально приблизиться к предметной области" звучит хорошо, но работает плохо. Мне больше нравится задача "придумать максимально простую модель предметной области, которая покрывает максимальное количество пользовательских сценариев".


Такой моделью как раз и является domain model
Re[22]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:17
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Классы customer, customercotainer, location, department, person

T>>>Помогло?

G>>Да, прямо ER-модель получилась.


T>Не, получилась вполне себе rich domain model

И чем же она Rich?

например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.

G>Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

Вот пример:
//#define COMPLEX

#if !COMPLEX
using System;
using System.Collections.Generic;
#endif

namespace ConsoleApplication1 {
    class Program {
        private enum State { One, Two, Three, Four, Five }

        #if !COMPLEX
        private static readonly IDictionary<State, Action> _mapping = new Dictionary<State, Action> {
            { State.One, Action1 },
            { State.Two, Action2 },
            { State.Three, Action3 },
            { State.Four, Action4 },
            { State.Five, Action5 },
        };
        #endif

        private static void Main() {
            State state = GetState();
            #if !COMPLEX
            _mapping[state]();
            #endif

            #if COMPLEX
            if (state == State.One)
                Action1();
            if (state == State.Two)
                Action2();
            if (state == State.Three)
                Action3();
            if (state == State.Four)
                Action4();
            if (state == State.Five)
                Action5();
            #endif
        }

        private static State GetState() {
            return State.One;
        }

        private static void Action1() {
        }

        private static void Action2() {
        }

        private static void Action3() {
        }

        private static void Action4() {
        }

        private static void Action5() {
        }
    }
}


Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.
Re[23]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:29
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Не, получилась вполне себе rich domain model

G>И чем же она Rich?

G>например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).


ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:33
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>У данных есть только одна обязанность — "быть". Способ сохранения данных ортогонален самим данным. То, что атрибут "зарплата" не может быть меньше нуля — ортогонально структуре "карточка сотрудника". Алгоритм капитализации ФИО ортогонален структуре "Карточка сотрудника".


T>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

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

S>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
Причем тут хранилище? Сущности ортогональны хранилищу.

T>>>Есть много разных вещей, которые не могут быть вынесены за пределы сущности, т.к. они могут ломать валидность класса.

S>>Ты слишком много думаешь о классах. Выносить за пределы класса нужно всё, что можно вынести за пределы класса.
S>>Поскольку публичный контракт "сущности" сводится к умению группировать данные, то 100% поведения должно быть вынесено за ее пределы.

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

Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем. В отличие от класса очереди, где инварианты обеспечивают то что класс действительно является очередью.
Re[26]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.01.09 11:34
Оценка: +2
Здравствуйте, Tissot, Вы писали:
T>В этом и предмет разногласия. Для domain model "нижележащие данные" — это всего лишь способ долговременного хранения сущностей.
Совершенно верно. Это и есть основная ошибка. "Сущность" сегодня одна, завтра — другая. А "нижележащие данные" о к примеру, переписи населения США 1891 года до сих пор лежат, как лежали. Они никак не изменятся.


T>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

Вот именно! Замечательное свойство ортогональности исчезает, как только карточку начинают наделять сущностью. Чем отличается сущность от карточки? Правильно, наличием поведения. Ну так вот у карточки нет никакого поведения.
Искусственно внедрять в неё поведение можно, но от этого получаются негативные эффекты.

T>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

Вот как раз контракт взаимодействия с хранилищем может запросто поменяться. Сегодня XML, завтра CSV, послезавтра — RDBMS. Сами данные при этом, естественно, останутся всё теми же.

T>Не только к умению группировать но и к сохранению инвариантов.

У данных почти что нет инвариантов. Я уже об этом писал.
Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.
T>Если публичный контракт таков, что для реализации какого-то функционала реализацию можно разместить снаружи класса, то можно это оформить в виду сервисного класса. Но только в том случае, если сущность не может быть "поломана" извне.
Данные — это данные. Их никак не поломаешь. Даже null/not null — и то зачастую чрезмерно жесткие ограничения для статической формализации.
Очень немногие "инварианты" заслуживают встраивания в "сущность".
Как правило, в бизнесе вместо них есть пред- и пост-условия. Но они применимы не к "данным", а к "операции над данными". А операции над данными, как мы уже договорились, лежат снаружи — в некоем Manager или Service. Вот в нём да — нужно обеспечивать "неломаемость" операций.

Захочется поспорить — попробуй привести примеры "реализации функционала, который может поломать сущность, будучи размещенным извне".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:41
Оценка: -1
Здравствуйте, gandjustas, Вы писали:

T>>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

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

Да, ты прав. Имелось в виду сущность из domain model.

S>>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
G>Причем тут хранилище? Сущности ортогональны хранилищу.

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

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

G>Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем.

Нет, не ортогональны. Инвариант не должно быть разрешено нарушать. Если вы оставляете все поля сущности открытыми, вы не сожете гарантировать сохранность инватиантов.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:46
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Ну тогда еще проще — уменьшаем кол-во проходов цикла до минимума и комплексити падает.

G>>Ну покажите на вашем примере с кучей ифов как вы уменьшите Cyclomatic Complexity за счет таблицы.

T>Вот пример:

T>
T>код поскипан
T>


T>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

А если к вашему коду применить ООП, заменить enum классами (рефакторинг по фаулеру), то станет еще лучше.
Если писать хороший код, то таких примеров и возникать не будет.

Но вы вначала привели другой:
if (condition1())
  action1();
else if (condition2())
  action2();
...
else if (conditionN())
  actionN();

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

Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.
Re[24]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 11:51
Оценка: +1
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Не, получилась вполне себе rich domain model

G>>И чем же она Rich?

G>>например location, чтобы быть локейшеном надо какие-то данные о местоположении содержать, этодо достаточно. Вполне себе ER-модель (сущность и атрибуты).


T>ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.

По каким причинам они могут там появиться не нарушая SRP и другие принципы хорошего дизайна?

Например какие методы могут появиться у location, ну кроме переопределения Equals и ToString?
Re[27]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 11:54
Оценка:
Здравствуйте, Sinclair, Вы писали:


T>>Эти утверждения верны если только для вас "Карточка сотрудника" — это чисто данные. Если вы начинаете рассматривать ее как сущность, то ортогональность пропадает.

S>Вот именно! Замечательное свойство ортогональности исчезает, как только карточку начинают наделять сущностью. Чем отличается сущность от карточки? Правильно, наличием поведения. Ну так вот у карточки нет никакого поведения.

У карточки нет поведения, но мы моделируем не карточки, а то, представлением чего являются карточки.

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


Искуственно и не надо, надо естественно внедрять.

T>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.

S>Вот как раз контракт взаимодействия с хранилищем может запросто поменяться. Сегодня XML, завтра CSV, послезавтра — RDBMS. Сами данные при этом, естественно, останутся всё теми же.

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

T>>Не только к умению группировать но и к сохранению инвариантов.

S>У данных почти что нет инвариантов. Я уже об этом писал.

А я про данные и не говорю, я говорю о сущностях domain model. Прошу прощения, если неясно выразился.

S>Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.


Не прощай инвариант, а здравствуй domain model. Кроме zip-кода надо проверить еще и страну и в зависимости от страны выбирать ту или иную стратегию валидации.

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

S>Данные — это данные. Их никак не поломаешь. Даже null/not null — и то зачастую чрезмерно жесткие ограничения для статической формализации.
S>Очень немногие "инварианты" заслуживают встраивания в "сущность".

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

S>Как правило, в бизнесе вместо них есть пред- и пост-условия. Но они применимы не к "данным", а к "операции над данными". А операции над данными, как мы уже договорились, лежат снаружи — в некоем Manager или Service. Вот в нём да — нужно обеспечивать "неломаемость" операций.


Нет, мы не договаривались что опреации над данными "лежат снаружи". Мы договорились, что лишь те операции погут быть вынесены наружу, что не могут "сломать" инварианты.

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

update orderitem set qty = -100
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:00
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>>>Эти нюансы меняются как времена года. При этом сама структура "карточка сотрудника" и ее содержимое может пережить ядерную войну.

T>>>И что? Это всего лишь означает, что контракт взаимодействия с хранилищем не должен меняться со временем.
G>>Причем тут хранилище? Сущности ортогональны хранилищу.
T>Нет, сущность не ортогонально зхранилищу, т.к. именно хранилище определяет что именно, какие атрибуты у нас в сущности.
Если храним в XML, то одни атрибуты, а если храним в БД, то другие?

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

G>>Эти "инварианты" ортогональны сущности, поскольку могут меняться со временем.

T>Нет, не ортогональны. Инвариант не должно быть разрешено нарушать. Если вы оставляете все поля сущности открытыми, вы не сожете гарантировать сохранность инватиантов.

Так бизнес-правила не являются инвариантами для сущностей (фактически данных).
Простой пример. Есть бизнес-правило, что ЗП сотридника не должна быть меньше МРОТ. Был у нас МРОТ 2000 рублей и были сотрудники с ЗП 2500, тут МРОТ увеличили до 4000 рублей. Если мы оформляем бизнес-правило как инвариант сущности, то становится все плохо, сотрудник с ЗП ниже 4000 даже не может быть считан из базы, возникнет ошибка и исравить её можно только прямой правкой данных в базе.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:09
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

G>В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель. Кроме того, в код внесена ошибка.

G>Но вы вначала привели другой:

G>
G>if (condition1())
G>  action1();
G>else if (condition2())
G>  action2();
G>...
G>else if (conditionN())
G>  actionN();
G>

G>Предположим что все conditionN зависят от одного набора параметров (уже достаточно сильное условие), даже если вы сформируете список из пар (предикат, действие), то вам придется в цикле ходить по этому списку и проверять если предикат истинный, то выполнить действие.
G>Такое преобразование не уменьшит CyclomaticComplexity.

Не знаю, может и не уменьшит, может и уменьшить. Добавь var action = _mapping.FirstOrDefault(x => x.Key(state)).Value вот и весь цикл.
Цель примера была не в том, чтобы доказать, что всегда есть способ облапошить комплексити, а в том, что такие ситуации встречаются и уже на этом основании нельзя особо полагаться на этот показатель.

G>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.


И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
Re[28]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:17
Оценка:
Здравствуйте, Tissot, Вы писали:

S>>Вот только что в нашем продукте напоролись: встроенная валидация хочет не более 8 символов для зипкода. В Иране — 10. Прощай, инвариант.


T>Не прощай инвариант, а здравствуй domain model. Кроме zip-кода надо проверить еще и страну и в зависимости от страны выбирать ту или иную стратегию валидации.


Вот на этом месте начинают сыпаться все преимущества Domain Model.

Представляем себе код:
public class Customer
{
  private ZipCodeValidationStrategy _zipCodeValidationStrategy;

  ...
  public string ZipCode
  {
    get {return _zipCode;}
    set
    {
      if(_zipCodeValidationStrategy.Validate(value))
      {
         _zipCode = value;
      }
    }
  }
}

Вот теперь вопрос, как кастомер получает zipCodeValidationStrategy? Сам класс инстанцировать zipCodeValidationStrategy не может потому что от страны, а страна хранится где-то еще.
Это значит маппер должен уметь инжектить переданный ему инстанс стратегии в создаваемую сущность. С другой стороны при ручном создании инстанса надо инжектить такуюже стратегию.
Учитывая что не все мапперы позволяют перехватывать процесс создания объектов получается не очень хорошо.
Re[25]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:19
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>ER-содель — это когда только сущность и атрибуты. Появляются методы, она уже перестает быть ER.

G>По каким причинам они могут там появиться не нарушая SRP и другие принципы хорошего дизайна?

По той причине, чтобы не дать перевести сущность/модель в невалидное состояние. Я же об этом уже писал.

G>Например какие методы могут появиться у location, ну кроме переопределения Equals и ToString?


Ну например, при закрытии location-а equipment, расположеный в этом location-е должен быть переведен в статус "неактивный".
Как мне соблюсти это правило, если всем доступны напрямую все сущности (как в er-модели)?
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Причем тут хранилище? Сущности ортогональны хранилищу.

T>>Нет, сущность не ортогонально зхранилищу, т.к. именно хранилище определяет что именно, какие атрибуты у нас в сущности.
G>Если храним в XML, то одни атрибуты, а если храним в БД, то другие?

Кончай уже. Если у тебя er, то как тебе это поможет?


G>Простой пример. Есть бизнес-правило, что ЗП сотридника не должна быть меньше МРОТ. Был у нас МРОТ 2000 рублей и были сотрудники с ЗП 2500, тут МРОТ увеличили до 4000 рублей. Если мы оформляем бизнес-правило как инвариант сущности, то становится все плохо, сотрудник с ЗП ниже 4000 даже не может быть считан из базы, возникнет ошибка и исравить её можно только прямой правкой данных в базе.


Нет, не так. Инвариант будет несколько сложнее: МРОТ не существует один раз на веки вечные. Это некоторый закон, который начинает действовать с какого-то времени и теряет силу после того, как принят следующий мрот. Поэтому если уж ты проверяешь инвариант при загрузке сущности (кстати, зачем?), то ты должен взять последнюю дату модификации зарплаты и удостовериться, что зарплата не меньше значения, установленного законодательством не тот момент.
Re[29]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:33
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Вот на этом месте начинают сыпаться все преимущества Domain Model.


Посмотрим.

G>Представляем себе код:

G>
G>public class Customer
G>{
G>  private ZipCodeValidationStrategy _zipCodeValidationStrategy;

G>  ...
G>  public string ZipCode
G>  {
G>    get {return _zipCode;}
G>    set
G>    {
G>      if(_zipCodeValidationStrategy.Validate(value))
G>      {
G>         _zipCode = value;
G>      }
G>    }
G>  }
G>}
G>

G>Вот теперь вопрос, как кастомер получает zipCodeValidationStrategy? Сам класс инстанцировать zipCodeValidationStrategy не может потому что от страны, а страна хранится где-то еще.

Где-то еще — это где? Я предполагал, что у кастомера и так есть страна. Тогда получить валидацию можно так:
ZipCodeValidationStrategyFacory.GetByCountryCode(this.CountryCode)


G>Это значит маппер должен уметь инжектить переданный ему инстанс стратегии в создаваемую сущность. С другой стороны при ручном создании инстанса надо инжектить такуюже стратегию.

G>Учитывая что не все мапперы позволяют перехватывать процесс создания объектов получается не очень хорошо.

А теперь рассказывай, как ты будешь с этим бороться:

update customer set zipCode = "любой невалидный zip";
Re[26]: Некоторые мысли о LINQ
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.01.09 12:42
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Померьте комплексити в таком коде, потом раскомментите первую строчку и померьте еще раз. Мне студия насчитала 9 и 13 соответственно.

G>>В таком коде действительно сложность уменьшилась. Причем как формальный показатель CyclomaticComplexity, так и фактическая сложность чтения\сопровождения\расширения.

T>Я не считаю, что сложность уменьшилась. Меньшее кол-во строчек еще не показатель.

Еще как уменьшилась.
1)Структурированность кода стала выше, в сами ифы стало невозможно дописывать
2)Из-за сокращения объема кода он стал нашляднее, проще читать, следовательно меньше ошибок будет допущено, быстрее они будут выявлены.
3)Стало невозможно допустить ошибку недописывания else перед новым if при добавлении условия
Кроме того появилась дополнительная гибкость — появилась возможность формировать таблицу действий в run-time.
Почитайте книгу "жемчужины программирования", так описаны такие преобразования.

T>Кроме того, в код внесена ошибка.

какая?

G>>Но вы вначала привели другой:

G>>
G>>if (condition1())
G>>  action1();
G>>else if (condition2())
G>>  action2();
G>>...
G>>else if (conditionN())
G>>  actionN();
G>>

G>>Предположим что все conditionN зависят от одного набора параметров (уже достаточно сильное условие), даже если вы сформируете список из пар (предикат, действие), то вам придется в цикле ходить по этому списку и проверять если предикат истинный, то выполнить действие.
G>>Такое преобразование не уменьшит CyclomaticComplexity.

T>Не знаю, может и не уменьшит, может и уменьшить. Добавь var action = _mapping.FirstOrDefault(x => x.Key(state)).Value вот и весь цикл.

Так тоже CyclomaticComplexity уменьшается (фактически придется меньше тестов писать), но в этом случае общая сложность решения не изменилась. Хотя некоторые преимущества появились.

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

Вы доказали что качество кода состоит не только из CyclomaticComplexity, а из многих составляющих. Но это и так известно.

G>>Вот если у вас предикат одинаковый, а параметры разные, то это можно свести к таблице или паттернам состояние\стратегия.

T>И ты считаешь, что это проще? Вместе нескольких if-ов генерить интерфес стратегии + классы реализующие интерфейс.
Если это код, подверженный частым изменениям, то проще. Иначе можно ограничиться таблицей.
Re[15]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 09.01.09 12:47
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


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


Возможно, я не сталкивался сподобного рода задачами, но мне доводилось работать с достаточно крупной erp-системой (Axapta).
Там как раз было реализовано именно так, как я описывал — через объектную модель. Слышал краем уха что в том же SAP-е реализовано примерно таким же образом — логика не в базе, запросах, а в appserver cлое. Если все так плохо с работать через объектную модель, то почему в этих системах было реализовано именно так? Неужели тоже из-за недостатка опыта проектировщиков?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.