Защита для шаблона?

14

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

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

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

рассеянный
источник
7
Аргументы против повторяющегося кода (при условии, что шаблон скопирован / вставлен): stackoverflow.com/a/2490897/1583
Одед
1
@Oded: Это правильно. Но вы неправильно поняли вопрос. :) Он пытается выяснить, есть ли что сказать по шаблонному коду. Я думаю, он очень хорошо осведомлен о недостатках.
Стивен Джеурис
3
@ StevenJeuris - я прочитал вопрос отлично. Вот почему я не опубликовал ответ. Я только добавляю к другой стороне аргумента. Точно так же, у ОП есть «готовый, хорошо продуманный аргумент, после того, как я разработал для него отвращение к этому времени» в следующий раз;)
Одед
2
Котельная табличка может быть эстетически приятной: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic
Несколько хороших ответов и комментариев, которые дополняют друг друга ... трудно выбрать, какой из них принять.
отвезено

Ответы:

15

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

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

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

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

Мейсон Уилер
источник
7
Конечно, этот аргумент работает в обе стороны. Значительный объем стандартного кода только для того, чтобы успокоить компилятор и не помогает людям понять - чтобы остаться с геттерами / сеттерами, эти десятки строк должны быть прочитаны полностью, чтобы быть уверенными, что «это просто бесполезные геттеры и сеттеры» вместо того, чтобы читать по одной короткой строке на свойство, которая просто указывает, что это свойство и какой у него тип.
6
Я думаю, что шаблон вреден и для читателя. Будучи вынужденными писать повторяющийся, бессмысленный текст, мы скрываем соответствующие части кода от других людей. Если что-то полезно, то по определению это не шаблон.
Андрес Ф.
1
@ Джорджио: Наоборот, это гораздо больше, чем просто мое мнение; Это мнение подавляющего большинства людей, которые когда-либо пытались его изучать. И когда «трудно читать» изначально является вопросом мнения, тот факт, что это мнение широко распространено, в значительной степени делает это фактом.
Мейсон Уилер
1
@ Мейсон Уилер: на то, как люди воспринимают языки программирования, часто влияет их прошлый опыт. Люди, которые научились программировать на Схеме, находят C или Pascal неуклюжим и трудными для чтения. С другой стороны, подавляющее большинство людей научились программировать на основном языке.
Джорджио
2
Я придерживаюсь мнения, что, когда больше контекста скрыто от программиста, удаляя шаблон, это означает лишь то, что Человек должен держать большую мысленную карту всего, что происходит незаметно за кулисами, и это является большим ущербом, когда речь идет о отладка, чем сохранение небольшого визуального пространства при разработке.
Патрик Хьюз
7

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

Допустим, у вас есть кусок кода, который говорит

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Это используется примерно в 2 местах в вашем коде.

Однажды кто-то приходит и говорит: «Хорошо, только на этом пути, мы хотим, чтобы вы заглушали бар перед тем, как его загнать».

И вы думаете: «Ну, это просто».

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Затем ваш пользователь добавляет некоторые новые функции, и вы считаете, что он хорошо вписывается в FooTheBar. И вы покорно спрашиваете их, стоит ли Grommit в этом баре перед вами, Foo it, и они говорят «нет, не в этот раз».

Так что вы просто вызываете метод выше.

Но затем ваш пользователь говорит: «Хорошо, подождите, в третьем случае мы хотим, чтобы вы Doodle the Bar перед вызовом BeFooed».

Нет проблем, вы думаете, я могу это сделать.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

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

Все это говорит, я бы возразил, что с «это не частый случай, и когда это произойдет, вы можете рефакторинг».

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

Я видел, как люди спорили о вещах IoC.

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

прецизионный самописец
источник
2
Я предпочел вторую часть вашего ответа. ; p +1
Стивен Джеурис
просто пойми, что мой пример очень похож на твой ... угадай, даже если это не здравый смысл, кажется, что это происходит совсем немного :)
kritzikratzi
6

Эволюция эффективности

Вы начинаете с этого:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

тогда вы избавитесь от всего этого надоедливого шаблона и включите его в функцию:

  1. createFieldHtml( id, label )

    это хорошо, я спасаю себя так много строк!

  2. createFieldHtml( id, label, defaultValue )

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

  3. createFieldHtml( id, label, defaultValue, type )

    круто, я тоже могу использовать его для галочек

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    UX дизайнер сказал, что метка должна быть после флажка.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

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

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    был один случай, когда мне нужно добавить классы CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

В защиту шаблонного

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

  1. Мне кажется, что есть определенный страх иметь двойные линии, которые немного растягиваются. Если это всего лишь несколько строк, это может быть совсем не проблема. некоторые вещи по своей сути «почти повторяются» (как в примере выше). Я вижу мало шансов на оптимизацию там в долгосрочной перспективе.
  2. Люди любят где-то заключать функциональные возможности; если вы смотрите объективно и кажется, что это просто «скрывает беспорядок» - будьте подозрительны! это может быть время для старого доброго шаблона
  3. Когда у вас есть функция, которая становится все более и более мощной; в зависимости от ввода требуется много разных путей выполнения и, в конечном счете, очень мало - это может быть стандартное время!
  4. Когда вы добавляете слой абстракции поверх другого уровня абстракции, но просто для того, чтобы сделать ваш код короче (нижележащий слой не должен изменяться), - примерное время!
  5. Когда у вас есть функция, которая принимает столько параметров, что вам действительно нужно иметь именованные параметры - возможно, это стандартное время.

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

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


Обновление : я только что натолкнулся на статью, в которой мой пример выше фактического названия: «слишком СУХОЙ анти-паттерн».

Функция получает больше параметров и имеет все более сложную внутреннюю логику для управления своим поведением в разных случаях. Слишком СУХИЕ функции легко обнаружить. У них есть много сложной логики if-then, которая пытается охватить широкое разнообразие использования. [...] Кроме того, повторение кода не всегда плохо, если код маленький и выполняет дискретную функцию.

Это короткое и интересное чтение, вы можете найти статью здесь: Too Dry Anti-Pattern

kritzikratzi
источник
1
«Когда вы добавляете слой абстракции поверх другого уровня абстракции, но просто для того, чтобы сделать ваш код короче» Правда, вы должны добавлять слои абстракции только тогда, когда есть возможность повторного использования.
Стивен Джеурис
4
+1. Не повторяйте себя, но не идут в неудобных длины , чтобы избежать почти повторяя себя.
Джулия Хейворд
4

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

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

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

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

Стивен Джеурис
источник
Тем не менее, я все еще доволен результатом, который у меня есть на данный момент, и с удовольствием использую его в своих проектах в свободное время. :)
Steven Jeuris
3
каждый раз, когда я касаюсь WPF и этих свойств зависимостей, мне всегда хочется, чтобы в C # было что-то столь же простое, как в макросах C ++. Конечно, макросы злоупотребляют не в тех руках, но они могут устранить слишком много повторений здесь. В следующий раз, когда я начну желать эти макросы, мне придется взглянуть на вашу платформу AOP :)
DXM
@DXM Если вы это сделаете, и он с треском провалится, не забудьте обвинить меня и опубликовать ошибки. ; p
Стивен Джеурис
Фрагмент кода хорошо работал для свойств зависимостей.
Кодизм
@Codism: Ну, они являются решением, но я презираю их тоже . :)
Стивен Джеурис
1

Проблема с шаблоном в том, что он нарушает СУХОЙ. По сути, когда вы пишете шаблон, вы повторяете один и тот же код (или очень похожий код) для нескольких классов. Когда этот код необходимо изменить, он не уверен, что разработчик запомнит все места, где код повторялся. Это приводит к ошибкам при использовании старых API или старых методов.

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

quanticle
источник
2
Как это аргумент в пользу шаблонного ?
Крис Весселинг
0

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

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

  • Отправной точкой является понимание преамбулы (шаблона) в вашей функциональности, большинство ключевых классов и точек доступа обычно будут отображаться как часть шаблона. Это дает разработчикам отправную точку в документации
  • Ожидания, которые вы возлагаете на разработчиков, станут очевидными, например, если вы настроите трассирующий объект как часть преамбулы, разработчики будут знать, где регистрировать исключения и информацию.
  • Неявное понимание, когда вы заставляете разработчика пройти через процесс создания экземпляров классов, они могут вывести методы, которые им понадобятся для доступа к остальной части вашей библиотеки, и иметь возможность познакомить их с любыми соглашениями, которые вы использовали в своей библиотеке.
  • Легкая проверка, когда нужен ваш стандартный код, обычно он может очень легко подтвердить себя с помощью исключений и защитных положений, предотвращая застревание потребителей в дальнейшем, когда вы уже преданы ошибочному процессу.
  • Конфигурирование библиотеки, которая требует стандартного кода, легко, поскольку уже есть очевидная точка реализации для настройки функциональности для единственного пути выполнения. Это особенно полезно, если ваш требуемый шаблонный код дополнен шаблоном Factory или Command.

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

Dead.Rabit
источник
-3

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

Эдвард Стрендж
источник