То, что делает Вы чувствуете, является сверхобобщением?

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

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

Одно такое консервативное отношение было недавно выражено мне:

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

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

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

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

Таким образом, что Вы думаете, ТАКИМ ОБРАЗОМ? Что Вы считаете сверхобобщением? Это правило имеет отличающуюся применимость в зависимости от контекста? Вы даже соглашаетесь, что это - правило?

12
задан Cogwheel 14 July 2010 в 02:37
поделиться

6 ответов

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

Есть принцип, которому следуют люди XP, называется YAGNI - You Ain't Gonna Need It.

В wiki сказано следующее:

Даже если вы полностью, полностью, полностью уверены, что функция понадобится вам позже, не реализуйте ее сейчас. Обычно оказывается, что либо а) она вам не нужна, либо б) то, что вам действительно нужно, сильно отличается от того, что вы предполагали ранее.

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

11
ответ дан 2 December 2019 в 03:53
поделиться

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

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

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

Однако здесь могут быть некоторые исключительные случаи.
а) Когда общее решение почти точно такое же усилие и сложность.Пример: написать реализацию Queue с использованием универсальных шаблонов не намного сложнее, чем сделать то же самое только для строк.
б) Если проще решить проблему в общем виде, да и решение проще для понимания. Это происходит не слишком часто, на данный момент я не могу придумать простой пример из реальной жизни :-(. Но даже в этом случае наличие / анализ конкретных примеров является обязательным ИМО, поскольку только он может подтвердить что вы на правильном пути.

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

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

И, конечно же, различные гибкие процессы также рекомендуют нечто подобное: начать с простого, рефакторировать, когда это необходимо.

2
ответ дан 2 December 2019 в 03:53
поделиться

есть 2 примера от microsoft в чрезмерном обобщении:
1.) CObject (MFC)
2.) Object (.Net)

оба они используются для "реализации" generics в c++, которые большинство людей не используют. На самом деле, все делали проверку типов параметров, заданных с помощью этих (CObject/Object) ~

0
ответ дан 2 December 2019 в 03:53
поделиться

Слишком общий? Должен признать, что я фанат универсального программирования (как принципа), и мне очень нравится идея, которую там используют Haskell и Go.

Однако при программировании на C ++ вам предлагается два способа достижения схожих целей:

  • Общее программирование: с помощью шаблонов, даже если есть проблемы со временем компиляции, зависимостью от реализации и т. Д.
  • Объектно-ориентированное программирование: его предок в некотором смысле, который ставит проблему в самом объекте (классе / структуре), а не в функции ...

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

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

// No container implements this, it's easy... but better write it only once!
template <class Container, class Pred>
void erase_if(Container& c, Pred p)
{
  c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
}

// Same as STL algo, but with precondition validation in debug mode
template <class Container, class Iterator = typename Container::iterator>
Iterator lower_bound(Container& c, typename Container::value_type const& v)
{
  ASSERT(is_sorted(c));
  return std::lower_bound(c.begin(), c.end(), v);
}

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

Вот почему я ценю принцип наименьших усилий. Когда я думаю о классе или методе, я сначала делаю шаг назад и немного думаю:

  • Имеет ли смысл сделать его более общим?
  • Сколько будет стоить?

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

Пример:

void Foo::print() { std::cout << /* some stuff */ << '\n'; }

// VS

std::ostream& operator<<(std::ostream& out, Foo const& foo)
{
  return out << /* some stuff */ << '\n';
}

Он не только более общий (я могу указать, куда выводить), но и более идиоматичен.

6
ответ дан 2 December 2019 в 03:53
поделиться

Чрезмерное обобщение сводит меня с ума. Я не боюсь шаблонов (почти не боюсь), и мне нравятся общие решения. Но мне также нравится решать проблему, за которую платит клиент. Если это недельный проект, то почему я финансирую месячную феерию, которая будет работать не только до очевидных возможных будущих изменений, таких как новые налоги, но и, возможно, до открытия новых лун или жизни на Марсе?

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

Конечно, не всякое обобщение является чрезмерным обобщением. Все должно быть настолько простым, насколько это возможно, но не проще. Настолько общим, насколько это необходимо, но не более общим. Настолько проверенным, насколько мы можем себе позволить, но не более проверенным. И т.д. Также "предсказывайте, что может измениться, и инкапсулируйте это". Все эти правила просты, но не легки. Вот почему мудрость имеет значение для разработчиков и тех, кто ими управляет.

13
ответ дан 2 December 2019 в 03:53
поделиться

Что-то является чрезмерно обобщенным, если вы тратите время на обобщение. Если вы собираетесь использовать обобщенные функции в будущем, то, вероятно, вы не тратите время впустую. Это действительно так просто [на мой взгляд].

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

4
ответ дан 2 December 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: