Архітектура модульного додатку сервісу


11

Я дивлюсь на створення нового рішення, яке є дуже модульним за своєю суттю і хотів би створити структуру, яка підтримує цей дизайн, щоб забезпечити легке розширення в майбутньому, чітке розділення проблем, ліцензування за модулем тощо. Більшість того, що я маю В Інтернеті про модульні або складені програми є орієнтовані на інтерфейс користувача, орієнтовані на Silverlight, WPF тощо. У моєму випадку я розробляю службовий додаток WCF, яке споживають інші розробники, що працюють над різними проектами інтерфейсу.

Фон

Мета мого проекту - створити централізоване джерело логіки бізнесу / домену для підтримки декількох наших бізнес-додатків, які наразі дублюють процес, правила і т. Д. І хоча не всі переваги модульності будуть досягнуті, я хотів би скористатися можливість створити рамку, яка буде використовувати ті частини, якими ми можемо скористатися.

Я розпочав розробку, переглянувши API, виставлений службовою програмою. Зрозуміло, що послуги можна розділити за модульними лініями, які я розглядав. Наприклад, у мене будуть служби FinanceService, InventoryService, PersonnelService тощо., Які групують мої сервісні операції для забезпечення високої згуртованості в API, зберігаючи при цьому зв'язок низьким, щоб клієнти повинні споживати лише ті послуги, які стосуються їх застосування.

Для мене є сенс, що я можу мати окремі модулі для кожної з цих служб, такі як MyApp.Finance, MyApp.Inventory, My.Personnel тощо. Наскрізні проблеми та спільні типи були б у спільній збірці MyApp. Звідси я трохи прив’язуюсь.

(О, я повинен зазначити, що я буду використовувати контейнер IoC для ін'єкцій залежностей, щоб додаток було вільно пов'язане. Я не згадаю, який з них не хочу відкривати вікно Пандори!)

У MyApp.ServiceHost я створю файл хосту служби (.svc), відповідний кожному модулю, наприклад FinanceService.svc. Хост сервісу потребує ім'я послуги, яке відповідає інформації у файлі конфігурації, що містить інтерфейс, що визначає договір на обслуговування. Потім конфігурація IoC використовується для відображення конкретної реалізації інтерфейсу, який слід використовувати.

1. Чи повинен сервісний рівень реалізовувати API та делегувати модулі, або вони повинні бути самостійними (якщо вони містять все, що стосується цього модуля, включаючи реалізацію послуги)?

Один із способів підходу до проблеми - мати "модуль" MyApp.Services, який містить реалізацію договорів на обслуговування. Кожен клас сервісу просто делегує інший клас у відповідний модуль, який містить логіку домену для операції. Наприклад, клас WCF FinanceService в MyApp.Services делегує інший інтерфейс, який реалізується в модулі Фінанси для здійснення операції. Це дозволило б мені підтримувати тонкий фасад сервісу і «підключати» до виконання службу, а також усунути необхідність, щоб, наприклад, модулі турбувалися про WCF.

З іншого боку, можливо, бажано мати кожен модуль самостійним, оскільки він має інтерфейс та реалізацію. Хост сервісу посилається на інтерфейс контракту на послугу, знайдений в модулі, і IoC налаштований для використання відповідної реалізації також від модуля. Це означає, що додавання нового модуля можна проводити без будь-яких змін сервісного рівня, окрім додавання нового файлу .svc та інформації конфігурації IoC.

Я думаю про вплив, якщо я перейду зі стандартного WCF на інтерфейс RESTful сервісу або, можливо, перейду на послуги RIA чи щось таке. Якщо кожен модуль містить реалізацію договору на обслуговування, тоді я повинен внести зміни в кожен модуль, якщо я зміню технологію обслуговування або підхід. Але, якщо фасад - це власний модуль, то мені залишається лише поміняти цю частину, щоб внести зміни. Потім модулі повинні були б реалізувати інший набір контрактів (інтерфейсів), можливо визначених у спільній збірці ???

2. Який найкращий спосіб обробляти ресурси між модулями та / або залежностями між модулями?

Візьмемо, наприклад, операцію отримання. Спочатку рум'яна має сенс, що це переходить в модуль інвентаризації, оскільки отримання товарів є функцією інвентаризації. Однак є й фінансовий аспект у тому, що нам потрібно створити квитанцію та дозволити платіж.

З одного боку, я б очікував використовувати деякий тип подій / повідомлень домену для передачі операції. Модуль «Інвентаризація» піднімає CommReceivedEvent, який обробляється Фінансовим модулем, щоб генерувати квитанцію та ініціювати процес оплати. Однак це означає, що Фінансовий модуль повинен знати про товари, що надійшли. Я можу просто посилатися на них за ідентифікатором, але що робити, якщо мені потрібна додаткова інформація для квитанції, наприклад, ім'я та / або опис, вартість одиниці тощо? Чи має сенс для кожного модуля мати свою власну версію товарно-матеріальних цінностей, розроблену відповідно до потреб цього модуля? У цьому випадку Фінансовий модуль повинен був би здійснити власний пошук товарно-матеріальних цінностей під час обробки CommReceivedEvent.

...

Я використовував цей приклад навмисно, тому що я багато працював з різними ERP-системами і знаю, що вони розроблені з таким типом модульності - я просто не знаю як. Я також прямо не згадую це вище, але я вважаю за краще керуватися принципами дизайну, керованим доменом при архітектурі рішення, і вважаю, що цей тип модульності вписується прямо в цю область.

Будемо дуже вдячні за будь-яку допомогу в закручуванні голови.


1
Вибачте. Не можете знайти питання в усьому мисленні. У чому питання?
С.Лотт

1
Шукайте знаки запитання. Є кілька моментів, де я пропоную варіанти, але не припускаю рішення та декілька конкретних питань, які допоможуть провести процес у правильному напрямку.
SonOfPirate

1
@SonOfPirate: Вибачте. Я сподівався, що вам може знадобитися час, щоб висвітлити або наголосити на питаннях, щоб інші люди могли вам допомогти.
С.Лотт

4
Я згоден із С.Лоттом. Вибачте, але це не питання, це потік свідомості. Ми можемо допомогти вам набагато краще, якщо ви зведете це на одне або два цілеспрямовані питання та спробуєте відокремити архітектурні проблеми від деталей реалізації.
Aaronaught

1
@SonOfPirate: "Архітектура" стосується структури та передачі цієї структури іншим розробникам. Починається з опису. Він повинен досягти рівня чіткості та прозорості, що дозволяє іншим розробникам повністю "отримати" його та слідувати принципам архітектурного проектування у всьому, що вони роблять.
С.Лотт

Відповіді:


2

Чи має сенс для кожного модуля мати свою власну версію товарно-матеріальних цінностей, розроблену відповідно до потреб цього модуля? У цьому випадку Фінансовий модуль повинен був би здійснити власний пошук товарно-матеріальних цінностей під час обробки CommReceivedEvent. Де я можу провести межу між модульністю та потребою в обміні інформацією?

Ви завжди повинні приймати компроміси. Це все, що потрібно сказати на ваші запитання. Належною практикою було зберігати об'єкти в окремій збірці, тому багато програм зберігають їх у спільній бібліотеці. Але це означає, що немає (фізичних) бізнес-логічних меж. Виконання власних пошукових запитів означає багато зайвого коду, який я б реалізував, лише якщо у вас є спеціальні вимоги до обох модулів. Звичайно, дивлячись на це з архітектурної точки зору, ваш фінансовий модуль та ваш інвентаризаційний модуль все одно повинні поділяти залежність. Фінансовий модуль, швидше за все, залежить від модуля інвентаризації. Якщо вимоги дозволяють вам дозволити один модуль залежати від іншого модуля, тоді я б сказав, що це нормально, щоб інкапсулювати об'єкти в модулі, до яких вони належать найбільше. Ти' Потрібно знайти хороший баланс між фізичною різницею (спільні залежності) та обслуговуванням. Занадто багато спільних залежностей можуть спричинити технічний кошмар версій версій. Крім того, з ORM виникнуть проблеми, якщо ви хочете зіставити нові відносини з існуючими об'єктами або розширити їх з модулів, які залежать від модуля, що містить сутність.

Якщо ви не використовуєте ORM, майте на увазі, що всі ваші модулі все-таки мають спільну базу даних, як це часто буває. Ви можете використовувати це як загальну точку зору.

Ви також можете зберігати дані прості (з точки зору наборів CSV / результатів, наприклад) та використовувати центральну службу обміну повідомленнями, щоб повідомляти модулі, які зареєстровані в ній, про нові дані разом з деякою метаінформацією. Це означає, що немає справжніх залежностей, але жертви типу безпечні та контракти, і можуть виникнути проблеми з неправильними даними. Я думаю, саме стільки великих ERP-систем це роблять.

Отже, коротше, вам доведеться вирішити, який тип інтерфейсу ви хочете. Більша модульність призводить до меншої кількості контрактів і навпаки.

Можливо, я використовую спільну бібліотеку для моїх об’єктів даних та центральну службу обміну повідомленнями з шаблоном subcibe публікації, що здається мені найкращим рішенням.


Також погоджуйтеся з цим - обмін повідомленнями + pub / sub та бібліотеки для dto-контрактів (внутрішнє nuget repo). Мені були цікаві ті самі запитання, що і @SonOfPirate, поки ця стаття не поставила мене в перспективу: msdn.microsoft.com/en-us/library/bb245678.aspx
diegohb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.