Расслоение системы в бизнес-приложениях
От: MozgC США http://nightcoder.livejournal.com
Дата: 27.12.07 13:55
Оценка:
И еще раз здравствуйте
Постараюсь быть кратким, хотя наверное не получится...
Читаю Нильссона, Фаулера и т.д. и т.п., пытаюсь поднять свой уровень, хочу понимать и грамотно уметь провести расслоение системы в типичном бизнес-приложении. Возникает много вопросов, вот некоторые из них:

Вопрос 1. А-ля "Передача connection'а vs получение (не открытие) connection'а где нужно"
Сам я сторонник возможности получения connection к БД в любом месте программы, а не передачи его из формы в форму, из метода в метод и т.д. Лично мне не нравится по всем слоям, классам и методам таскать объект соединения. Сначала я всем методам из DAL передавал коннекшен из кода форм, когда была простенькая архитектура — UI + DAL (к которому наверное можно отнести и классы сущностей типа Invoice, Customer и т.д. содержащие только поля). Особой бизнес-логики не было, потому что все было достаточно несложно и особая нужда в дополнительном слое бизнес-логики, бизнес-правил не чувствовалась. С развитием проекта и увеличением его сложности начинаешь понимать, что действительно нужен слой в котором были бы методы, инкапсулирующие внутри себе определенные бизнес-правила. Отвлекся. Вернемся к объекту соединения. С введением слоя бизнес-правил получается что объект соединения нужно сначала его передавать классам бизнес-логики, а те в свою очередь будут передавать его методам из DAL. Я не считаю что такое таскание соединения по всем слоям и методам оправдано. На моей практике объект соединения создается при открытии программы и потом его бедного по всей системе кидают, и только в некоторых редких отдельных случаях необходимо создать отдельное соединение, например в отдельном потоке. У Нильссона в книге вообще нигде не проглядывается работа с соединениями, кроме как в главе про ORM, из чего я прихожу к выводу что соединение он получает вызывая статический метод внутри DAL-методов. Открываю Фаулера [АКПП], внимательно листаю, по всей книге раскиданы вызовы типа DB.Connection и ConnectionManager.INSTANCE.getConnection() и только в некоторых местах где реально нужно отдельное соединение Фаулер его создает.

Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?

Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"
Второй вопрос по поводу отделения бизнес-логики от бизнес-классов (DTO? или я ошибаюсь в терминологии?). Допустим есть сущность "счет". Тогда при расслоении мы создаем класс Invoice с полями InvoiceID, InvoiceN, InvoiceDate, InvoiceAmount и т.д. Кстати в таком виде куда его относить ? к DAL или BLL? Далее в DAL мы создаем класс InvoiceAccessor, который будет например иметь метод GetInvoiceByID() и другие методы для непосредственной связи счетов с БД и фактически будет являться еще и фабрикой. Вопрос в том, а не включить ли в класс Invoice методы бизнес-логики? Например для отмены инвойса мы можем включить в этот класс метод CancelInvoice(). Но другой подход тут — отделить методы бизнес-логики от данных, оставить класс Invoice только с полями в покое, и создать класс InvoiceManager, который будет иметь статический метод CancelInvoice()?

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

private void btnCancelInvoice_Click(object sender, EventArgs e)
{
  ...
  // Ничего кстати что я DAL-метод вызываю из UI ?
  Invoice invoice = InvoiceAccessor.GetInvoiceByID(invoiceID);
  if(invoice.CancelInvoice())
    Presentation.ShowSuccess("Selected invoice has been successfully cancelled!");
  ...
}


Во втором варианте, код будет таким:

private void btnCancelInvoice_Click(object sender, EventArgs e)
{
  ...
  if(InvoiceManager.CancelInvoice(invoiceID))
    Presentation.ShowSuccess("Selected invoice has been successfully cancelled!");
  ...
}

Как правильнее и почему?

Вот так, на пока хватит, кратко не получилось.
Жду ответов, мнений и советов опытных людей.

С уважением, Павел.
Re: Расслоение системы в бизнес-приложениях
От: IB Австрия http://rsdn.ru
Дата: 27.12.07 14:34
Оценка: 3 (1) +2
Здравствуйте, MozgC, Вы писали:

MC>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?

Ни то и не другое, кури connection pooling. Сценарии, когда соединение надо держать открытым для разных вызовов, в реальных приложениях крайне редки.


MC>Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"

...
MC>Как правильнее и почему?

http://rsdn.ru/Forum/message/2706234.1.aspx
Автор: IB
Дата: 25.10.07
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re: Расслоение системы в бизнес-приложениях
От: Blazkowicz Россия  
Дата: 27.12.07 15:35
Оценка: 1 (1) +1
Здравствуйте, MozgC, Вы писали:

MC>Вопрос 1. А-ля "Передача connection'а vs получение (не открытие) connection'а где нужно"

Самая замечательная стратегия это иметь абстрактную фабрику соединений и инжектить её (IoC, Dependency Injection) в классы доступа к данным (паттерн DAO).
В фабрике реализуется нужный набор фич
— пулироваине соединения
— валиадация соединений
— ассоциация соединений с пользовательской сессией (если надо)
— ассоциация соединения с бизнес-транзакцией \ бизнес-операцией (если надо)


MC>Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности (т.е. отделять ли RemoveInvoice() от класса Invoice в класс InvoiceManager) ?"

Уже верное поделились ссылкой выше. Неоднозначный и не простой вопрос.

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


MC> // Ничего кстати что я DAL-метод вызываю из UI ?

Полный отстой. Где тут MVC, где тут отделение View/BL/DAL?
Re[2]: Расслоение системы в бизнес-приложениях
От: MozgC США http://nightcoder.livejournal.com
Дата: 03.01.08 16:33
Оценка:
Здравствуйте, IB, Вы писали:

MC>>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?

IB>Ни то и не другое, кури connection pooling. Сценарии, когда соединение надо держать открытым для разных вызовов, в реальных приложениях крайне редки.

Т.е. благодаря Connection Pooling в DAL-методах я просто пишу типа:

public static SupplierInvoice GetSupplierInvoiceByID(int supplierInvoiceID)
{
    SupplierInvoice supplierInvoice = null;
    using (SqlConnection conn = DB.ConnectToDb())
    {
        // ...
    }
    return supplierInvoice;
}

Правильно?
Re: Расслоение системы в бизнес-приложениях
От: Alex EXO http://aleksandr-zubarev.moikrug.ru/
Дата: 04.01.08 08:16
Оценка: +1
Здравствуйте, MozgC, Вы писали:
MC>Длинно получилось. Ваше мнение по этому вопросу: передавать соединение или получать где нужно вызовом статического метода или свойства?

Ни то, ни другое — соединение вообще не должно входить за пределы уровня "модели".
А если ты какой-нибудь из бизнес-объектов решишь перенести в другую систему и он станет доступен только через web-сервис? Бужешь перепахивать весь код завязанный на соединение с БД?

MC>[b]Вопрос 2. А-ля "Отделять ли бизнес-методы от класса бизнес-сущности


Это связанные вопросы. Две стороны одной монеты:
— "уровень модели" не должен публиковать методы которые могут разрушить целостность конкретного бизнес-объекта или модели в целом;
— набор методов "модели" должен быть достаточен для выполнения операций высокоуровневой логики, и при этом минимален (классическая формулировка "необходимо и достаточно").

То есть, если некоторая операция требует прямого обращения к служебным данным или функциям (соединение с БД к ним относится), она должна быть обобщена (!) и реализована не уровне модели. Если же эта опреация выражается через другие опреации модели — то ей место на уровне сервиса.
Re[3]: Расслоение системы в бизнес-приложениях
От: Blazkowicz Россия  
Дата: 04.01.08 09:56
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>
MC>public static SupplierInvoice GetSupplierInvoiceByID(int supplierInvoiceID)
MC>{
MC>    SupplierInvoice supplierInvoice = null;
MC>    using (SqlConnection conn = DB.ConnectToDb())
MC>    {
MC>        // ...
MC>    }
MC>    return supplierInvoice;
MC>}

MC>Правильно?
Типа того, только, ИМХО, статику всю нужно повыкидывать. В обоих методах GetSupplierInvoiceByID() и ConnectToDb()
Re[4]: Расслоение системы в бизнес-приложениях
От: MozgC США http://nightcoder.livejournal.com
Дата: 04.01.08 10:11
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

MC>>
MC>>public static SupplierInvoice GetSupplierInvoiceByID(int supplierInvoiceID)
MC>>{
MC>>    SupplierInvoice supplierInvoice = null;
MC>>    using (SqlConnection conn = DB.ConnectToDb())
MC>>    {
MC>>        // ...
MC>>    }
MC>>    return supplierInvoice;
MC>>}

MC>>Правильно?
B>Типа того, только, ИМХО, статику всю нужно повыкидывать. В обоих методах GetSupplierInvoiceByID() и ConnectToDb()

Вот этот вопрос меня тоже интересует. Почему некоторые люди советуют избавляться от статических методов?
Re[5]: Расслоение системы в бизнес-приложениях
От: Blazkowicz Россия  
Дата: 04.01.08 10:22
Оценка:
Здравствуйте, MozgC, Вы писали:

B>>Типа того, только, ИМХО, статику всю нужно повыкидывать. В обоих методах GetSupplierInvoiceByID() и ConnectToDb()

MC>Вот этот вопрос меня тоже интересует. Почему некоторые люди советуют избавляться от статических методов?

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