Jul. 3rd, 2007
Абстрагирование модулей.
Jul. 3rd, 2007 01:15 pmКак-то у нас с
belnetmon возник спор про абстрагирование частей программы друг от друга.
Я, когда мне не влом, делаю классическим способом - выделяю зависимости в интерфейсы или абстрактные базовые классы, потом от них наследую реализации и в итоге собираю из этого конечный результат. Но из этого получается в пару раз больше кода и модулей, чем если бы просто реализовать нужную функциональность, не заморачиваясь на абстрагирование.
Вот сейчас опять наткнулся на эту шизу. Был класс, генерящий кросс-таблицы(они же шахматки, они же двумерный вариант кубов). Заполнялся из датасета, вызовом метода Fill(DS:TDataset). Один юнит, в котором класс TCrossTable с этим методом.
В бухгалтерии постоянно возникает задача - кроме основной шахматки, нужны промежуточные итоги, общие итоги, часто с нетривиальным критериями группировки.
Обходил я это, добавляя в запрос, который заполняет датасет, всякие хитрые union и join, которые повторно вызывали основной запрос(в виде selectable stored procedure), группируя его заново. В итоге получалась заданная хитрая шахматка. Но: 1)запрос усложнялся 2)для каждого итога приходилось повторно выполнять запрос 3)полученный датасет начинал выглядеть как набор безумного бреда из цифр, хотя его было бы неплохо тоже просматривать в линейном табличном виде, для поиска заданных сумм.
Решил я передвинуть расчет промежуточных сверток итогов на клиента. Давно пора. Для этого надо впихнуть между датасетом и кросс-таблицей еще один слой, который на каждую запись датасета будет по хитрым условиям генерить несколько записей, попадающих в основную шахматку и итоги.
И вот задача - в каком виде сделать этот слой. Можно взять заполняемый вручную TClientDataset. А можно абстрагировать TCrossTable от датасета.
Выбрал второе решение. Итого один юнит и один класс превратились в:
1) Два базовых абстрактных класса для полей и источника данных.
2) TCrossTable получающий в Fill абстрактный источник данных
3) Два наследника для полей и источника данных, реализующих их поверх TDataset.
+2 юнита,+4 класса - цена абстрагирования. И это я всего лишь повторил уже существующую функциональность. А сейчас еще буду делать реализацию для расчета итогов.
И, скорее всего, придется сделать еще один класс-обертку, который будет на вход получать датасет, внутри себя держать класс кросс-таблицы, а абстрактный источник данных для него загружать из настроек отчета, для того чтобы настройками описывать этот самый промежуточный слой между датасетом и кросс-таблицей.
Теперь я наконец понял, почему крупные проекты содержат огромное количество мелких файлов.
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
Я, когда мне не влом, делаю классическим способом - выделяю зависимости в интерфейсы или абстрактные базовые классы, потом от них наследую реализации и в итоге собираю из этого конечный результат. Но из этого получается в пару раз больше кода и модулей, чем если бы просто реализовать нужную функциональность, не заморачиваясь на абстрагирование.
Вот сейчас опять наткнулся на эту шизу. Был класс, генерящий кросс-таблицы(они же шахматки, они же двумерный вариант кубов). Заполнялся из датасета, вызовом метода Fill(DS:TDataset). Один юнит, в котором класс TCrossTable с этим методом.
В бухгалтерии постоянно возникает задача - кроме основной шахматки, нужны промежуточные итоги, общие итоги, часто с нетривиальным критериями группировки.
Обходил я это, добавляя в запрос, который заполняет датасет, всякие хитрые union и join, которые повторно вызывали основной запрос(в виде selectable stored procedure), группируя его заново. В итоге получалась заданная хитрая шахматка. Но: 1)запрос усложнялся 2)для каждого итога приходилось повторно выполнять запрос 3)полученный датасет начинал выглядеть как набор безумного бреда из цифр, хотя его было бы неплохо тоже просматривать в линейном табличном виде, для поиска заданных сумм.
Решил я передвинуть расчет промежуточных сверток итогов на клиента. Давно пора. Для этого надо впихнуть между датасетом и кросс-таблицей еще один слой, который на каждую запись датасета будет по хитрым условиям генерить несколько записей, попадающих в основную шахматку и итоги.
И вот задача - в каком виде сделать этот слой. Можно взять заполняемый вручную TClientDataset. А можно абстрагировать TCrossTable от датасета.
Выбрал второе решение. Итого один юнит и один класс превратились в:
1) Два базовых абстрактных класса для полей и источника данных.
2) TCrossTable получающий в Fill абстрактный источник данных
3) Два наследника для полей и источника данных, реализующих их поверх TDataset.
+2 юнита,+4 класса - цена абстрагирования. И это я всего лишь повторил уже существующую функциональность. А сейчас еще буду делать реализацию для расчета итогов.
И, скорее всего, придется сделать еще один класс-обертку, который будет на вход получать датасет, внутри себя держать класс кросс-таблицы, а абстрактный источник данных для него загружать из настроек отчета, для того чтобы настройками описывать этот самый промежуточный слой между датасетом и кросс-таблицей.
Теперь я наконец понял, почему крупные проекты содержат огромное количество мелких файлов.
Интересные факты
Jul. 3rd, 2007 03:06 pmДень переезда в Монреале.
1) Только у 36% жителей Монреаля есть собственный дом. Сравните это с СССР или даже современной РБ. Видимо, рыночная экономика требует дикой мобильности рабочей силы и развитой инфраструктуры аренды жилья.
2) В домах часто используются внешние лестницы, вплоть до четвертых этажей. Цель - снизить налоги, за счет уменьшения плошади дома.
Цитата знакомого, которого задрало местное быдло и говно, и собирающегося эмигрировать в канаду: "Есть плюс очевидный - на них не сцут".
1) Только у 36% жителей Монреаля есть собственный дом. Сравните это с СССР или даже современной РБ. Видимо, рыночная экономика требует дикой мобильности рабочей силы и развитой инфраструктуры аренды жилья.
2) В домах часто используются внешние лестницы, вплоть до четвертых этажей. Цель - снизить налоги, за счет уменьшения плошади дома.
Цитата знакомого, которого задрало местное быдло и говно, и собирающегося эмигрировать в канаду: "Есть плюс очевидный - на них не сцут".
А вот еще позитивный коммент
Jul. 3rd, 2007 04:43 pmна тему уменьшения количества зависимостей.
Ссылко:
1. четкое следование принципу одна сущность - одна роль
2. выделение слоев (например, persistence->model->business->controller->presentation)
3. использование паттернов типа фасад или адаптер (в моем примере слой persistence является ORM-адаптером к СУБД)
4. Уменьшение количества зависимостей между классами с помощью 1-3
Потом, когда нормальная архитектура сложится, разделение на клиентские и серверные компоненты станет очевидным.
Ссылко:
1. четкое следование принципу одна сущность - одна роль
2. выделение слоев (например, persistence->model->business->controller->presentation)
3. использование паттернов типа фасад или адаптер (в моем примере слой persistence является ORM-адаптером к СУБД)
4. Уменьшение количества зависимостей между классами с помощью 1-3
Потом, когда нормальная архитектура сложится, разделение на клиентские и серверные компоненты станет очевидным.
Рынок говно-ентерпрайз решений.
Jul. 3rd, 2007 07:35 pmСтатья консультанта, участвовавшего в проекте вместе с IBM. Описывает тот тяжкий мрак, который творится при реализации крупных IT проектов силами крупных поставщиков решений. Достойно WorseThanFailure.
Я так понимаю, это является нормой для подобных проектов?
Я так понимаю, это является нормой для подобных проектов?