Сколько абстракции слишком много?

В объектно-ориентированной программе: Сколько абстракций слишком много? Насколько это правильно?

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

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

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

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

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

Итак, когда это слишком много? В какой момент пустые слои и дополнительные "могут понадобиться" абстракции становятся излишними? Как мало мало? Где сладкое пятно?

Есть ли какие-либо надежные эмпирические правила, которые вы нашли в ходе своей карьеры, которые помогут вам судить о количестве требуемой абстракции?

Ответ 1

Итак, когда это слишком много? В какой момент сделать пустые слои и дополнительные "возможно нужны" абстракции"? Как мало мало? Где сладкое пятно?

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

Вот несколько ссылок, которые могут вдохновить вас на поиски ответов:

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

Ответ 2

Точка абстракций - это отделить общие свойства от конкретных, например, в математической операции:

ab + ac => a(b + c)

Теперь вы делаете то же самое с двумя операциями вместо трех. Этот факторинг упростил наше выражение.

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

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

Чем больше вещей разделяют общее свойство. Более выгодной абстракцией может быть:

ab + ac + ad + ae + af

в

a(b + c + d + e + f)

Это уменьшит 9 операций до 5.

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

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

10 => 5 * 2

Вы не можете определить слово "common", если у вас есть только одна сущность.

Итак, чтобы ответить на ваш вопрос. У вас достаточно абстракций, если они делают вашу систему максимально простой.

(В моих примерах добавление соединяет части системы, а умножение определяет абстрактно-конкретные отношения.)

Ответ 3

Как мало мало?

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

Итак, когда это слишком много?

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

Где сладкое пятно?

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

Ответ 4

В теории это должно быть простой математикой, использующей только три (довольно простые) переменные:

  • S = экономия от использования
  • C = стоимость дополнительных абстракций
  • P = вероятность использования

Если S * P > C, то код хорош. Если S * P < C, тогда это плохо.

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

По крайней мере, некоторые люди сделали вывод из этого. В TDD стандартная мантра "вам не понадобится" (YAGNI). Проще говоря, все, что прямо не влияет на код, отвечающий его текущим требованиям, считается плохим. По сути, они пришли к выводу, что вероятность использования настолько низка, что включение такого дополнительного кода никогда не оправдывается.

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

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

Ответ 5

Проще говоря, слишком много абстракции, если код трудно понять.

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

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

См. пункт (6a) RFC 1925 и знайте, что это действительно так. Единственные проблемы, которые вы не можете исправить, добавляя слои абстракции, - это те, которые вызваны слишком большим количеством уровней абстракции. (В частности, каждая часть абстракции делает все это труднее понять.)