Что такое «преждевременная абстракция»?

10

Я слышал, как фразу бросают вокруг, и для меня аргументы звучат совершенно безумно (извините, если я здесь играю, это не мое намерение), как правило, это звучит примерно так:

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

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

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

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

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

Вот пример, скажем, клиент хочет, чтобы вы создали робота для упаковки предметов:

public abstract class BaggingRobot() {
    private Collection<Item> items;

    public abstract void bag(Item item);
}

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

Нет такой вещи как преждевременная абстракция, есть только преждевременная конкреция. Что не так с этим утверждением? Где недостатки в моих рассуждениях? Спасибо.

Джеймс
источник
1
Противоположностью преждевременной абстракции является YAGNI - это не нужно, что, на мой взгляд, почти всегда неправильно. Почти. Я видел, как это происходит, но это редко. Я в основном согласен с тем, что вы говорите здесь.
user1118321

Ответы:

19

По крайней мере, на мой взгляд, преждевременная абстракция довольно распространена, и это было особенно рано в истории ООП.

По крайней мере из того, что я увидел, возникла главная проблема - люди прочитали типичные примеры объектно-ориентированных иерархий. Им много говорили о том, что все готово для того, чтобы справиться с будущими изменениями, которые могут возникнуть (хотя не было особой причины полагать, что они это сделают). Еще одной темой, которая была распространена во многих статьях на какое-то время, были такие вещи, как утконос, который не поддается простым правилам о том, что «все млекопитающие такие» или «все такие птицы».

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

Джерри Гроб
источник
Таким образом, преждевременная абстракция - это не абстракция, а абстракция за пределами уровня абстракции. Это имеет больше смысла, и я мог видеть, что на самом деле происходит. Я думаю, мне просто нужно прояснить для моих коллег, что я работаю на уровне абстракции, изложенной моим менеджером.
Джеймс
1
@James: это также может означать абстрагирование «слишком много» после спецификаций версии 1.0, так как вы уверены, что знаете о новом требовании в спецификации более поздней версии, поэтому уже реализует v1.0 в более общем смысле, чем нужно. Кое-что, хорошо представить, что может произойти в более поздней версии, но есть также определенный риск переобучения.
Док Браун
@DocBrown Я бы назвал это преждевременным сращиванием. Акт абстракции состоит в том, чтобы удалять фрагменты информации, а не добавлять их. Если вы добавляете в абстракцию больше, чем необходимо, вы предполагаете что-то о более низких уровнях абстракции. Я хотел бы провести различие между этими двумя понятиями, так как считаю, что называть «абстракцию» не имеет особого смысла, поскольку определение абстракции - это «процесс извлечения основной сущности», где «конкреция» характеризуется или принадлежит непосредственному опыту. реальных вещей или событий ".
Джеймс
6

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

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

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

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

По общему признанию, искусство написания программ очень очень абстрактно концептуально. Стоит просто отметить, что абстракции существуют не ради абстракции, а потому, что они практичны в некотором смысле. Если вы чувствуете необходимость использовать абстракцию, пусть будет так, но не просите меня проверить вашу сантехнику впоследствии. ;)

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

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

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

После нескольких итераций это превратится в диаграмму классов.

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

Абстрактные классы вводятся только тогда, когда становится ясно, что:

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

Для меня «преждевременная абстракция» предполагает, что любой BaggingRobot должен наследовать от некоторых BaseRobot, и, что еще хуже, пытается разработать набор методов, BaseRobotпрежде чем вы даже узнаете, что является общим для всех роботов.

Саймон Б
источник
Абстракция не является синонимом абстрактных классов. Интерфейс - это абстракция. Я говорю об абстракциях в целом, а не только об абстрактных классах. Возможно, я мог бы сделать это более понятным, используя интерфейс. Если вы разрабатываете свою систему на том же уровне абстракции, что и ваш клиент, то, скорее всего, вы столкнетесь с некоторыми абстрактными классами, которые необходимо расширить, поскольку язык естественным образом является абстрактным. Работа ниже этого - это то, что я называю «преждевременной конкрецией», когда вы наивно полагаете, что идеи клиентов о том, как будет работать система, совпадают с вашими.
Джеймс
Объект BaggingRobot, который помещает объекты Item в объекты Bag, уже является абстракцией реального робота, который помещает вещи в сумки.
user253751
1

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

Следуя вашему примеру, представляете ли вы, что это сам робот , предметы, которые вы упаковываете, или метод , который изменится по линии?

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

Редактировать Чтобы ответить на некоторые моменты из OP в комментариях, я обновляю это, чтобы прояснить и ответить так, чтобы не требовалась длинная цепочка комментариев, обращаясь к пунктам (1) и (2) более конкретно.

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

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

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

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

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

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

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

Jimjam
источник
«Это звучит так, будто вы хотите решить проблему, которой еще нет, и у вас нет веских оснований предполагать, что это произойдет, если вы просто не верите, что клиент ошибается в том, что он запрашивает». - Это совсем не то, что я сказал, на самом деле я дал понять, что строю только на основе слов, которые использовал клиент. Это акт нежелания делать это, что заставило меня использовать абстракции.
Джеймс
«Я бы порекомендовал больше общения по поводу реализации решения угадать» - Вы имеете в виду, как я предложил? Процитирую то, что я сказал в OP: «Решение этой проблемы заключается не в том, чтобы придумать собственный конкремент и тратить ресурсы, когда вы обнаружите, что вы догадались, а в том, чтобы получить больше информации от клиента».
Джеймс
«Хотя это может показаться безобидным, просто набросать« абстракция »на определение класса и чувствовать себя в безопасности, зная, что вы можете расширить его позже» - когда я говорю «абстракция», я имею в виду «абстракцию», я не имею в виду «абстрактное ключевое слово». Интерфейсы могут быть абстракциями, абстракции - нечеткой логикой, именно об этом весь этот пост. Клиент общается в терминах абстракций, поэтому мы должны программировать в абстрактных терминах, пока не узнаем больше о предметной области.
Джеймс
1
«Вы можете обнаружить, что вам никогда не нужно» - это не имеет никакого смысла. Клиент говорит: «Я хочу робота, который упаковывает вещи», вы создаете абстракцию, которая соответствует этим критериям. Любая дополнительная информация, которую вы получите от клиента, будет подробной информацией о том, как они хотят, чтобы упаковка была выполнена. Это не лишает законной силы вашу абстракцию, клиент не внезапно меняет свое мнение об основной идее того, что он покупает. Робот все еще собирается собирать вещи. Созданная вами абстракция будет по-прежнему применяться.
Джеймс
«или вы можете расширить его таким образом, чтобы чрезмерно усложнить дизайн, абстрагируя неправильные вещи». ... Вы честно прочитали то, что я сказал, или просто название? Шутки в сторону? Прочитайте точку (1) и (2)
Джеймс