Вещи, которые следует учитывать при построении структуры - PullRequest
9 голосов
/ 26 августа 2009

Мы планируем создать структуру: структуру оценки затрат, которая будет использоваться во всех областях нашей организации.

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

Теперь мой вопрос: Что нужно учитывать при разработке фреймворка?

Несколько моих мыслей:

  1. Реализация требований высокого уровня с помощью абстрактных классов и интерфейсов
  2. Предоставление служебных классов, которые могут быть полезны для пользователей Framework.
  3. Подумайте, что должно быть внутренним - это метаданные, которые не следует показывать пользователям платформы.
  4. Шаблон дизайна для использования в качестве шаблона.
  5. свойства и методы входных классов.

Ответы [ 5 ]

13 голосов
/ 26 августа 2009

Несколько идей:

  • Легче добавлять полезные функции позже, чем удалять функции, которые оказались плохо спроектированными или вредными.
  • Проектирование наследования или его запрещение: наследование создает целый дополнительный уровень сложности, так как вам необходимо проработать взаимодействия между суперклассами и подклассами. Это не значит, что это зло, но оно должно быть очень тщательно продуманным.
  • В моем опыте интерфейсы, как правило, чище, чем абстрактные классы, поскольку они продвигают композицию вместо наследования.
  • Для интерфейсов документируйте и то, что должен ожидать вызывающий , и что должен ожидать разработчик . В основном, подумайте о контракте с обеих сторон и запишите его. В частности, ограничения на недействительность документа - методы должны принимать ноль или нет? Должны ли они гарантировать, что они никогда не вернут ноль?
  • Дизайн для тестируемости, как вашей платформы, так и других, использующих вашу среду. Какие биты инфраструктуры могут быть разумно использованы в тестовом коде, а какие должны быть исключены?
  • Используйте свой собственный фреймворк с самого начала. Создайте пример приложения, которое другие могут использовать для понимания структуры.
6 голосов
/ 26 августа 2009

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

Общие рекомендации

  • Потратьте время, чтобы поговорить с некоторыми разработчиками, которые будут использовать ваш фреймворк. Убедитесь, что вы действительно понимаете, что будет полезно, а что нет.
  • Потратьте время, чтобы убедиться, что создаваемая вами абстракция понятна и понятна для ваших будущих пользователей.
  • Если вы не создаете что-то уникальное и революционное, не торопятся, чтобы взглянуть на другие структуры, существующие в вашем домене . Избегайте их ошибок, но не бойтесь заимствовать удачные концепции ... не все должно быть придумано вами.
  • Создание документации - как в виде формальных документов API, так и в виде примера кода. Если люди не могут понять, как применить вашу платформу, это не удастся.
  • Назовите вещи четко, но кратко. Это, вероятно, одна из самых сложных задач для разработчиков инфраструктуры - особенно при реализации абстрактных или обобщенных концепций. Поговорите с людьми, прежде чем остановиться на имени. Некоторые имена имеют несколько значений и могут интерпретироваться иначе, чем вы могли бы ожидать.
  • Подумайте о том, чтобы сделать ваш фреймворк совместимым с другими низкоуровневыми фреймворками (например, для ведения журналов, макетов и внедрения зависимостей). Это порадует ваших пользователей и уменьшит барьеры на пути к усыновлению.
  • Инвестируйте в хорошие юнит-тесты. Каркасы обычно имеют большую площадь поверхности, с которой пользователи могут взаимодействовать ... со многими классами, множеством методов, производными, реализациями интерфейса. Без возможности быстрого регрессионного тестирования рамки могут быстро вырасти за пределы уровня, на котором их можно поддерживать.
  • Держите ваши общедоступные интерфейсы узкими и небольшими. Помните об одном принципе ответственности при разработке функциональных возможностей в среде ... это действительно важно на этом уровне.

Советы по дизайну

  • Разработка и тестирование на параллелизм. Большинство фреймворков в наши дни используются для создания приложений с некоторой (и часто с большой) активностью параллельной обработки. Фреймворки, предназначенные для использования в веб-приложениях, особенно нуждаются в тщательном рассмотрении того, как многопоточный доступ повлияет на них. Вот некоторые общие принципы, которым я следую:
    • По возможности избегайте блокировок. Когда это невозможно, используйте явные блокирующие объекты вместо операторов .NET lock (...).
    • Используйте блокировки чтения / записи для общих объектов, которые читаются чаще, чем записаны.
  • Проектирование функциональности в слоях. Для больших платформ это помогает не только отсоединить функциональность, но и позволяет пользователям с большей готовностью использовать только ту часть вашей инфраструктуры, которая им действительно нужна.
  • Для каркасов, предназначенных для использования с .NET 2.0 и выше, используйте общие коллекции! Крайне трудно рассуждать о том, что хранится в объекте [], ArrayList или Hashtable ... особенно в большой каркас, где такие коллекции передаются внутри.
  • Избегайте использования объекта или объекта [] в общедоступном интерфейсе ... это зло в платформе и является основной причиной ошибок и проблем с обслуживаемостью. Вы почти всегда можете найти интерфейс или использовать дженерики вместо этого. В тех редких случаях вы не можете документировать точно то, что вы ожидаете передать или вывести ... и отстаивать это.
  • Предпочитают агрегацию наследованию. Хотя наследование является полезной и мощной концепцией, авторы фреймворка часто используют его или злоупотребляют им. Тщательно продумайте, действительно ли наследование является правильным инструментом для решения проблемы проектирования.
  • По возможности избегайте приведений типов и проверок типов во время выполнения. В моем опыте это, как правило, запах дизайна. Участие в кастинге означает, что вы не используете преимущества интерфейсов, обобщений или общих ограничений. Это может привести к ошибкам и путанице со стороны разработчиков относительно того, как использовать ваш фреймворк.
  • Разрешить абонентам вводить функциональные возможности, используя стратегии, когда это возможно. Наследование избыточно для определенных видов специализации. С уровнем поддержки функций, которые становятся гражданами в экологии .NET, вы должны использовать их (в форме лямбда-выражений или делегатов), чтобы позволить потребителям специализировать предоставляемые вами функции.

Рекомендации по внедрению

  • Избегайте свойств, геттеры которых вызывают побочные эффекты. Иногда это неизбежно (например, геттеры, которые выполняют внутреннее кэширование, или ленивые экземпляры объектов). Однако, по моему опыту, геттеры с побочными эффектами (особенно в коде уровня платформы) - это самый быстрый способ представить heisenbugs и заставить ваших пользователей проклинать ваше имя при отладке.
  • Когда возможно, сделайте небольшие, временные объекты неизменяемыми. Для этого используйте ключевое слово readonly (или эквивалентное) в языке. Преимущества неизменяемости огромны - и в .NET (где затраты на выделение сокращены) это не так дорого, как вы думаете.
  • Используйте самоинкапсуляцию , когда это возможно. Этот метод помогает избежать ошибок и упрощает рефакторинг, избегая различной семантики доступа к данным для внутренних и внешних абонентов.
  • Избегайте магических чисел и жестко закодированных констант. Фреймворк - это один из типов кода, в котором очень сложно предугадать точные потребности ваших пользователей. Оставьте некоторую гибкость, используя конфигурацию, а не скомпилированные константы.
  • Сохраняйте число параметров для методов небольшим (менее 7). Когда вам нужно передать много параметров, рассмотрите возможность создания облегченного объекта данных для поддержки метода.
  • Предпочитают универсальные методы перегрузкам нескольких методов для разных типов. Пусть язык и компилятор по возможности выполняют работу. Это также позволяет вашему коду быть более гибким и полезным. Изучите дизайн LINQ, чтобы понять, как это работает на практике.
3 голосов
/ 26 августа 2009

Вот как бы я поступил:

  1. создание широкого высокоуровневого дизайна - например, веб-приложение или толстый клиент, есть ли средний уровень, как будет происходить взаимодействие с БД, какие API / технологии будут использоваться и т. Д.
  2. выберите функцию, которая позволит вам создавать код на всех уровнях приложения (что обычно называют шипами).
  3. реализуйте минимум, чтобы эта функция работала ( K eep I t S Imple, S tupid ) вместе с тестами, чтобы доказать, что это работает.
  4. выберите другую функцию, перейдите к 3 (рефакторинг по необходимости).

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

И я думал, что агилиста во мне нет; -)

2 голосов
/ 26 августа 2009

Помимо общих советов по программированию, стоит взглянуть на некоторые основы теории проектирования программных рамок. Для начала взглянем на понятия «горячие точки» и «замороженные точки». Хотя это может показаться не сразу полезным, полезно помнить об этом во время разработки.

Как всегда, википедия - хорошая отправная точка:

http://en.wikipedia.org/wiki/Software_framework

Также хорошее резюме здесь:

http://www.acm.org/crossroads/xrds7-4/frameworks.html

Если вы хотите углубиться, взгляните на цитаты в обеих этих статьях.

0 голосов
/ 26 августа 2009

Использование интерфейсов в контрактах API. Это позволяет вам полностью отделить грязные детали и легко декорировать их при необходимости. (Просто посмотрите Свойства, которые замаскированы под Карты).

Очень хороший совет - используйте Test Driven Design - то есть сначала напишите тест, а затем реализацию. Это заставляет вас думать как ПОЛЬЗОВАТЕЛИ, а не дизайнер, что в конечном итоге приведет к улучшению API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...