Servicestack - архитектура и повторное использование POCOs для всего

Я ссылаюсь на документацию ServiceStack, используя POCOs:

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

то есть. можно использовать тот же POCO:
В запросе и ответе DTO (на клиенте и сервере)
В текстовых сериализаторах JSON, JSV и CSV
В качестве модели данных в OrmLite, db4o и NHibernate
Как объекты, хранящиеся в Redis
Как капли, хранящиеся в кэшах и сеансах
Выброшено и выполнено в службах MQ "

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

В частности, я борюсь с архитектурной идеей возвращения объекта ответа, который также является моделью данных (как было предложено SS). Идея разделить озабоченность слишком сильно укоренилась во мне. Не будет ли у вас проблем в будущем, если вы будете использовать одни и те же POCO для всего. Разве это не "безопаснее", например, например, возвращать, например, объекты просмотра?

Ответ 1

Самый большой враг программного обеспечения

Во-первых, я хочу повторить Сложность и базы большого кода является самым злейшим врагом разработки программного обеспечения и что наряду с удовлетворением требований проекта (т.е. получение ценности от нашего программного обеспечения), управление сложностью и поддержание минимального и низкого трения, эволюционирующая кодовая база должна быть на переднем крае наших умов, поскольку мы постоянно совершенствуем наше программное обеспечение с помощью новые функции и требования. Любые рекомендации, правила или процессы, которые мы добавляем для повышения качества программного обеспечения, должны быть непосредственно сосредоточенным на управлении своей существенной сложностью. Одна из лучших вещей, которую мы можем сделать, чтобы уменьшить сложность заключается в уменьшении размера кодовой базы, то есть высыхании повторяющегося кода и устранении любых ненужных абстракций, косвенности, понятий, типов и трений, которые не являются абсолютно необходимыми для программной функции.

В этом свете YAGNI является одним из лучших принципов чтобы обеспечить простую и суровую базу кода, сосредоточив внимание на том, что необходимо для обеспечения ценности.

Избегайте правил одеяла

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

Будьте осторожны с неверными правилами и шаблонами

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

Простая жизнь POCO

Как вы заметили, ServiceStack обеспечивает большую простоту и повторное использование, поскольку он может повторно использовать один и тот же POCOs без разбора, чтобы взаимодействовать и свободно общаться между его различными библиотеками и компонентами. Это обеспечивает максимальное значение и повторное использование ваших моделей и уменьшает трение при сопоставлении между различными доменами которые обычно требуют наличия конкретных типов, каждая со своей собственной уникальной конфигурацией, ограничивающей ее применимость и потенциальное повторное использование.

Тяжелые модели ORM являются бедными DTO

Повторное использование моделей данных в качестве DTO применимо к Heavy ORM, которые поощряют модели данных с циклическими зависимостями и прокси-объекты с жесткой связью и встроенной логикой, которые могут вызвать непреднамеренный доступ к данным N + 1, эти модели плохо подходят для использования в качестве DTO и почему вы всегда должны копировать их в конкретные DTO, что ваши службы могут вернуться, поэтому они могут быть сериализованы без проблем.

Очистить POCOs

Комплексные модели данных, хранящиеся в OrmLite или Redis не страдает ни одной из этих проблем, которые могут использовать чистые, отключенные POCOs. Они слабо связаны друг с другом, где только "Форма" POCO значительна, т.е. перемещение проектов и изменение пространств имен не повлияет на сериализацию, то, как она хранится в таблицах РСУБД, Структуры данных Redis, поставщики кэширования и т.д. Вы также не привязаны к определенным типам, вы можете использовать другой тип для вставки данных в OrmLite, чем то, что вы использовать его для чтения, а также не нужно "точной формы", так как OrmLite может заполнять DTO только подмножество полей, доступных в базовой таблице. Также нет различия между таблицей, представлением или Хранимая процедура, OrmLite с радостью отобразит любой результат в любые соответствующие поля в указанном POCO, игнорируя других.

Эффективно это означает, что POCOs в ServiceStack чрезвычайно устойчивы и совместимы, поэтому вы можете с радостью повторно использовать те же DTO в OrmLite и наоборот без проблем. Если модели DTO и Data немного отклоняются, вы можете скрыть их от сериализации или сохранить в OrmLite с помощью следующие атрибуты:

public class Poco
{
    [Ignore]
    public int IgnoreInOrmLite { get; set; }

    [IgnoreDataMember]
    public int IgnoreInSerialization { get; set; }
}

В противном случае, когда вам нужно их разделить, например. в таблицу РСУБД было добавлено больше полей, чем вы хотите return, DTO включает дополнительные поля, заполненные из альтернативных источников, или вы просто хотите, чтобы ваши службы проектировать их по-разному. В этот момент (YAGNI) вы можете взять копию DTO и добавить ее в свои службы Таким образом, они могут расти отдельно, беспрепятственно из-за их различных проблем. Затем вы можете легко конвертировать между ними, используя Встроенное автоматическое сопоставление ServiceStack, например:

var dto = dbPoco.ConvertTo<Poco>();

Встроенное автоматическое сопоставление также очень толерантно и может сочетать свойства с различными типами,  например в/из строк, разных типов коллекций и т.д.

Объекты передачи данных - DTOs

Итак, если вы используете чистые, сериализуемые POCOs без внешних зависимостей (например, от OrmLite, Redis или alt Источники ServiceStack), вы можете с радостью повторно использовать их в качестве DTO и свободно реорганизовывать их в разные модели как и когда вам нужно. Но когда вы повторно используете Модели данных в качестве DTO, их все равно следует поддерживать в Проект ServiceModel (также известный как DTO.dll), который должен содержать все типы, возвращаемые службой. DTO должны быть логическими и зависимыми, поэтому единственной зависимостью, которую ссылается проект ServiceModel, является impl-free ServiceStack.Interfaces.dll, который, как и PCL.dll, может свободно ссылаться на все .NET мобильных и настольных платформ.

Вы хотите, чтобы все типы возвращаемых вами служб возвращались в DTO.dll, так как это, наряду с базовым URL-адресом где размещены ваши службы, все, что требуется для ваших пользователей услуг, чтобы знать, чтобы потребляйте свои Услуги. Что они могут использовать с любым из .NET Service Clients для получения сквозного типизированного API без кодирования кода, инструментария или любого другого искусственного оборудования. Если клиенты предпочитают исходный код, они могут использовать Добавить ссылку ServiceStack для доступа к серверным DTO-серверам на предпочтительной платформе и выбранном языке.

Услуги

Услуги - это окончательная форма инкапсулирования сложности и предлагает самый высокий уровень повторного использования программного обеспечения. Они упаковывают свои возможности и делают их доступными удаленно для ваших потребителей никогда больше сложность, чем стоимость вызова службы.

Интерфейс DTO vs Реализация Сервиса

DTO - это то, что определяет ваш контракт на услуги, сохраняя их изолированными от любой реализации сервера. как ваша Служба может инкапсулировать свои возможности (которые могут быть неограниченной сложности) и сделать их доступный за удаленным фасадом. Он отделяет то, что предоставляет ваша Служба, от сложности в том, как это понимает это. Он определяет API для вашей службы и сообщает потребителям услуг минимальную информацию, которую им нужно знать узнать, какие функции предоставляют ваши Услуги и как их использовать (поддерживая аналогичную роль для файлов заголовков в исходном коде C/С++). Четко определенные контракты на услуги, отделенные от реализации, обеспечивают совместимость, гарантируя, что ваши Услуги не предусматривают конкретные реализации клиента, гарантируя, что они могут быть использованы любым HTTP-протоколом Клиент на любой платформе. DTO также определяют форму и структуру вашего проводного формата услуг, гарантируя, что они могут быть чисто десериализованными в собственные структуры данных, устраняя усилия при ручном анализе ответов служб.

Разработка параллельных клиентов

Поскольку они фиксируют весь контракт, он также позволяет клиентам разрабатывать свои приложения до Услуги реализованы, поскольку они могут связывать свое приложение с его конкретными моделями DTO и могут легко mock их Service Client для возврата тестовых данных до тех пор, пока не будут реализованы вспомогательные службы.

Что касается правил, то обеспечение четко определенного контракта на обслуживание (DTO), отделенного от его реализации доходит до самой сути того, что такое Сервис и его ценность.

Запрос и ответные сообщения DTO

Что касается того, какие DTO делают хорошие кандидаты для повторного использования в качестве моделей данных, вы не хотите использовать Request DTOs для чего-либо иного, кроме определения внешнего API-интерфейсов служб, который обычно является Verb, который идеально подходит сгруппированы по семантике вызовов и типам ответов, например:

public class SearchProducts : IReturn<SearchProductsResponse> 
{
    public string Category { get; set; }
    public decimal? PriceGreaterThan { get; set; }
}

Ваши таблицы RDBMS обычно являются сущностями, которые определены как Существительные, то есть то, что возвращает ваша Служба:

public class SearchProductsResponse
{
    public List<Product> Results { get; set; }        
    public ResponseStatus ResponseStatus { get; set; }
}

Даже содержащий Response DTO, который определяет, что возвращает ваша Служба, не является хорошим кандидатом для повторного использования как модель данных. Обычно я использую дискретные DTO для ответных действий службы, поскольку он позволяет свободно распространять существующие Сервисы для возврата дополнительных данных или метаданных без нарушения существующих клиентов.

Помимо DTO запроса и ответа, все остальные Типы, которые будут возвращены вашей службой, будут кандидаты на повторное использование в качестве моделей данных, которые я часто делаю, сохраняя их в проекте ServiceModel по причинам выше.