Ниже мои заметки с курса, кусками (середина уже):
SOA предполагает “разделение” системы на “сервисы”.
Сервис определён как “the technical authority for a specific business capability”.
Это значит, что предписывается строить приложение не с использованием bottom-up подхода, а с использованием top-down подхода.
Bottom-up подход:
Делаем систему для продажи товаров.
Значит у нас есть объекты:
Customer of LoginName * FirstName * LastName * Status *
Address of AddressType * Country * City * Street
Product of Title * Description * Price
и т.д, разные другие логичные свойства и сущности
Делаем таблички для этих сущностей, это у нас слой БД. Берём EF4, это у нас модель. Делаем репозитории с операциями CRUD и всякими другими интересными, это у нас слой бизнес-логики. Делаем UI для всего этого дела.
Top-down подход:
Делаем систему для продажи товаров, но перестаём впихивать бизнес в термины базы данных.
Определяем business capabilities, то есть, изучаем бизнес и смотим, что и где происходит, какие данные изменяются совместно, какие требования изменяются совместно.
Приходим к мысли, что наш объект Customer из примера выше – сущность странная и не имеющая смысла ни в реальном мире, ни в мире бизнес-логики приложения. Остаётся загадкой, почему мы считаем её логичной.
Например, у меня, как у кастомера, есть имя и фамилия. Но у меня нет статуса. Этот “статус” существует для меня где-то отдельно от меня, причём в разных местах у меня могут быть разные статусы и т.д.
С точки же зрения бизнес-логики такая компоновка объекта Customer смысла тоже, скорее всего, не имеет.
Потому, что очень маловероятно, что бизнес-логике, осуществляющей работу c кастомером, когда-нибудь потребуется его логин или пароль. Очень маловероятно, что потребуется некий “статус” который, в свою очередь, будет требоваться там, где будет осуществляться работа с ценами и продажами, но там вряд ли кого-то будут интересовать не только логин и пароль кастомера, но и его имя, и его адреса.
Соответственно, с точки зрения биллинга кастомера, нас не интересует ничего, кроме кредитной карты и, может быть, биллинг адреса. Нас не интересует адрес доставки в этом случае так же, как бизнес-логике, отвечающей за доставку, не нужна информация о кредитной карте и адресе для биллинга.
Или, вот, скажем, продукт и его цена. Там, где мы имеем дело с описанием продукта, его спецификациями и т.д, его цена вряд ли имеет смысл. Более того, у продукта нет как таковой цены, ибо цена обычно есть функция времени, если бизнес-требования не диктуют фиксированых цен навсегда, чего они обычно не делают. Таким образом, цена продукта это всегда цена когда?.
Ну и так далее.
Получается, что определив определённые границы business capabilities для приложения мы получаем определённый набор сервисов.
В каждом из этих сервисов понятия Customer, Product и т.д. отличаются. Скажем, в сервисе аутентификации пользователь – это его логин и пароль, в сервисе продаж – статус, в сервисе биллинга – кредитная карта и адрес биллинга и т.д. и т.п.
Чётко определив границы business capabilities можно двигаться дальше и сказать, что каждый сервис технически – это solution в вижл студии, это отдельная ветка кода. Он никак не связан с другими сервисами. У него есть своя бизнес-логика, своя схема БД и всё, остальное, что полагается, если это нужно.
Такие сервисы легко изменять, ибо изменение в одном сервисе никак не затрагивает остальные части системы. Сервис полностью владеет своими схемами данных в частности.
Между собой сервисы могут обмениваться событиями, RPC между сервисами недопустимы.
Причём события одного сервиса имеют смысл в контексте самого сервиса и не более. То есть, сервис, занимающийся биллингом клиента, не может послать событие “а теперь заказ нужно отправить почтой”. Он только может послать событие “Клиент был забиллен”.
Сервис, занимающийся доставкой, подписывается на события, и это он и только он решает, когда можно оправлять товар, а когда ещё нет. Например, может быть нужно дождаться какого-то другого события кроме “клиент забиллен”, скажем, “заказ подтверждён”, и отправлять только тогда, когда оба эти события для заказа имели место произойти.
Тут вырисовываются интересные вещи.
Например, раз у сервисов разные базы данных, то мы не можем гарантировать referential integrity.
Но вопрос стоит в том: а нужно ли нам это? Если, скажем, мы получили событие “кастомер 5 положил в карту товар такой-то”, а где-то в другой базе пока ещё нет никакой информации о кастомере 5 (проблема с сетью, сервис “лежал”, обработка длится дольше и т.д), то является ли это проблемой?
С точки зрения IT-мозга – да.
С точки зрения бизнеса… Скорее всего – нет. Люди, наблюдающие за статистикой продаж, сильно вряд ли интересуются конкретными именами покупателей. Поэтому мы, скорее всего, вполне можем позволить себе получить событие о том, что товар положен в карту до того, как мы получили имя клиента.
Потому, что это разные business capabilities.
Поэтому мы можем иметь независимые друг от друга сервисы, которые могут быть установлены на одну и ту же, либо на разные физические машины, которые могут иметь совершенно разные структуры баз данных (или, что там говорить, вообще совершенно разные СУБД, где-то, быть может, будет более уместно использовать NoSQL и хранить там документы, где-то файловую систему и хранить там тонны сгенерированных по документам тайлов и т.д.)
Мы получаем возможность вертикального партицирования, а с ним – много других интересных возможностей, например, возможность перераспределить ресурсы и сделать какой-то аспект системы более приоритетным, нежели другой в терминах используемых ресурсов (например, размещение заказа гораздо более приоритетная операция, чем, скажем, отображение terms and conditions).