Архитектурный вопрос: в какой сборке я должен поставить какой класс, для чистого решения? - PullRequest
2 голосов
/ 18 июля 2009

Преамбула:

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

У меня уже давно есть вопросы об этих вещах: как называть сборки и как разделять классы внутри них.

Я бы хотел привести пример приложения здесь с минимальным количеством классов, чтобы продемонстрировать то, что я пытаюсь понять.

Представьте себе приложение, которое

  • Принимает клиентские сообщения, сохраняет их в БД, а затем выводит их в очередь на сервер MTA.
  • Это веб-приложение, которое имеет интерфейс ASP.NET для написания сообщения + вложения.
  • Существует также клиент Silverlight, поэтому веб-приложение предоставляет ClientCervices WCF ServiceContract с одним OperationContract (SaveMessage).
  • Есть также клиент Windows ... делает то же самое, что и контракт Silerlight.

OK. Этого должно быть достаточно по поддельному сценарию, чтобы продемонстрировать мою невежественность.

Для вышеупомянутых нужны следующие классы:

  • Сообщение
  • MessageAddress
  • MessageAddressType (перечисление с From, To)
  • MessageAddressCollection

  • MessageAttachment

  • MessageAttachmentType
  • MessageAttachmentCollection

  • MessageException

  • MessageAddressFormatException

  • MessageExtensions (статическое расширение для сообщения)

  • MessageAddressExtensions (статическое расширение для MessageAddress)
  • MessageAttachmentExtensions (статическое расширение для MessageAttachment)

Project.Contract.dll

Моим первым шагом при организации вышеупомянутого в правильные сборки будет наблюдение, что Message, MessageAddress, MessageAttachment, перечисления, необходимые для его свойств (MessageAddressType, MessageAttachmentType) и необходимые для них коллекции (MessageAddressCollection, MessageAttachmentCollection), все в помечать как [DataContract], чтобы их можно было сериализовать между клиентом WCF и сервером. Будучи общим для обоих, я думаю, что переместил бы их в нейтральную общую сборку под названием Contract.

Project.Client.dll

Мне потребуется клиентский прокси сервера [ServiceContract], который ссылается на классы в Contract.dll.

Так что теперь сервер, который также ссылается на Project.Contract.dll, теперь может сохранять сериализованные сообщения, полученные от клиента WCF, и сохранять их в БД.

Плагины

Далее я бы понял, что хотел бы, чтобы эти объекты обрабатывались на стороне сервера сторонними плагинами (например, средством проверки на вирусы) ...

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

Так что я бы подумал о том, чтобы вернуться к тому, чтобы Message наследовал от IMessageReadOnly ... но где разместить этот интерфейс?

Project.Interfaces.dll

Если я помещу его в сборку под названием Project.Interfaces.dll, это будет работать для плагинов, которые могут ссылаться на это без ссылки на Contracts.dll ... но теперь клиент должен ссылаться как на сборку контрактов, так и на интерфейсы. ... не похоже на хорошее направление ...

Двойные объекты

В качестве альтернативы, я мог бы иметь две структуры сообщений (и дублировать другие классы MessageAttachment и т. Д.) ... одну для связи от клиента к серверу (в Contracts.dll), а затем использовать второй ServerMessage / ServerMessageAddress / ServerMessageAddressCollection на стороне сервера, которая наследуется от IMessageReadOnly, и тогда может показаться, что я ближе к тому, что хочу. С дублирующимися объектами плагины имеют ограниченный доступ, в то время как Server BL и т. Д. Имеет полный доступ к типам, относящимся к его работе, в то время как у клиента есть разные, но идентичные объекты ...На самом деле ... они, вероятно, мне следует начать рассматривать их как неидентичные, чтобы в моей голове стало ясно, что объекты просто для общения с клиентами, то есть объекты Contract / Comm) ...

Интерфейс веб-сайта

, который вызывает ... гул ... если есть два разных сообщения, и у них теперь разные свойства ... какое из них лучше всего использовать для поддержки форм ASP.NET? Объект ServerMessage кажется самым быстрым (нет сопоставления между типами) ... но вся логика уже проработана с объектами сообщений клиента (с различными свойствами и внутренней логикой). Итак, буду ли я использовать ClientMessage и сопоставлять его с Servermessage, чтобы различные логики пользовательского интерфейса были одинаковыми для разных сред? или я должен предпочесть отображение и просто переписать валидацию пользовательского интерфейса?

А как насчет третьего случая, Silverlight ... Сборка Contracts была сборкой Full Framework ... которую Silverlight не может перефразировать (другой механизм фреймворка / сборки) .... так что сборка, которую я имею на Silverlight сторона может быть точно таким же кодом, но должна быть другая сборка. Как это работает?

Что именно считать DataContract?

Наконец-то ... и это, клянусь, ближе к концу моего огромного вопроса ... как насчет надоедливых дополнительных классов, которые явно не являются DataContract?

Например, MessageAddress был DataContract. Хорошо. И перечисленные в нем перечисления являются его частью ... Имеет смысл ... Но если конструктор messageAddress вызывает MessageAddressFormatException ... считается ли он частью DataContract?

Могут ли быть классы, общие для сервера, клиента и плагинов?

Или это исключение, которое является общим для ОБА ServerMessageAddress и ClientMessageAddress, поэтому не должно дублироваться, а вместо этого находиться в общей сборке ... так что в конце концов клиент должен связываться с контрактами и общими? (Разве мы не пошли по этому переулку с сборкой Интерфейсов?)

А как насчет общих базовых классов / интерфейсов?

И должны ли эти исключения иметь общие базовые классы? например ... ClientMessageAddressException, ServerMessageAddressException, ServerMessageVirusException (из плагина) ... я должен изо всех сил пытаться получить их - как можно лучше - все происходят от абстрактного MessageException ... или есть время, когда наследование / повторное использование просто больше не подходящая цель, к которой нужно стремиться?

ОГРОМНОЕ СПАСИБО ЗА ЧТЕНИЕ ЭТОГО ДАРА.

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

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

Ответы [ 2 ]

6 голосов
/ 18 июля 2009

Потратив 10 минут на редактирование вопроса для форматирования, я все равно собираюсь понизить его. Там нет способ Я собираюсь прочитать все это.

Иди забери копию

image
Руководство по разработке структуры: соглашения, идиомы и шаблоны для многократно используемых библиотек .NET (2-е издание)

4 голосов
/ 18 июля 2009

Как архитектор, я узнал, что не стоит слишком увлекаться получением в первый раз абсолютно совершенных вещей, а совершенное - это субъективно. Рефакторинг, особенно перемещение классов между сборками, не требует слишком больших затрат. Для меня это звучит так, будто вы уже все продумываете логически и правильно. Вот мои мнения на несколько ваших вопросов:

В: Должны ли я иметь контракты только для чтения для моих классов контрактов данных?

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

В: Должен ли я использовать те же классы контрактов данных, что и мое приложение Silverlight в моем приложении ASP.NET, или использовать серверные классы напрямую?

Я бы пошел с объектами сообщений клиента, чтобы вы могли выиграть от повторного использования кода. Создание объекта довольно дешево, и я уверен, что большая часть сопоставления будет индивидуальной. Это не так быстро, правда, но это не будет узким местом в вашем приложении.

В: Куда мне поместить мои исключения?

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

В: Должны ли исключения иметь общие базовые классы?

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

Edit:

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

...