Мой друг работает в небольшой компании над проектом, который ненавидит каждый разработчик: он вынужден выпустить как можно быстрее, он единственный, кто, похоже, заботится о техническом долге, у клиента нет технической подготовки и т. Д.
Он рассказал мне историю, которая заставила меня задуматься о целесообразности шаблонов проектирования в подобных проектах. Вот история.
Пришлось выставлять товары в разных местах на сайте. Например, менеджеры контента могут просматривать продукты, а также конечных пользователей или партнеров через API.
Иногда в продуктах отсутствовала информация: например, у некоторых из них не было цены, когда продукт был только что создан, но цена еще не указана. У некоторых не было описания (описание представляло собой сложный объект с историями изменений, локализованным контентом и т. Д.). Некоторым не хватало информации о доставке.
Вдохновленный моими недавними чтениями о шаблонах проектирования, я подумал, что это отличная возможность использовать волшебный шаблон Null Object . Я так и сделал, и все было гладко и чисто. Нужно было просто позвонить,
product.Price.ToString("c")
чтобы отобразить цену илиproduct.Description.Current
показать описание; никаких условных вещей не требуется. До тех пор, пока однажды заинтересованная сторона не попросила отображать его по-другому в API, добавивnull
в JSON. А также по-разному для контент-менеджеров, показывая «Цена не указана [Изменить]». И мне пришлось убить мою любимую модель Null Object, потому что в ней больше не было необходимости.Таким же образом мне пришлось удалить несколько абстрактных фабрик и несколько сборщиков, в итоге я заменил свой красивый шаблон Facade прямыми и некрасивыми вызовами, потому что базовые интерфейсы менялись два раза в день в течение трех месяцев, и даже Singleton оставил меня когда требования говорят, что соответствующий объект должен быть различным в зависимости от контекста.
Более чем три недели работы состояли из добавления шаблонов проектирования, а затем разрыва их на месяц позже, и мой код, наконец, стал достаточно спагетти, чтобы его никто не мог поддерживать, включая меня самого. Не лучше ли вообще никогда не использовать эти шаблоны?
Действительно, мне приходилось работать над проектами тех типов, где требования постоянно меняются и диктуются людьми, которые на самом деле не имеют в виду сплоченность или согласованность продукта. В этом контексте не важно, насколько вы гибки, вы получите элегантное решение проблемы, и когда вы, наконец, внедрите его, вы узнаете, что требования изменились настолько радикально, что ваше элегантное решение не подходит больше
Каково было бы решение в этом случае?
Не использовать какие-либо шаблоны проектирования, перестать думать и писать код напрямую?
Было бы интересно провести опыт, когда одна команда пишет код напрямую, а другая дважды подумает, прежде чем набирать текст, рискуя тем, что несколько дней спустя выбрасывает оригинальный дизайн: кто знает, может быть, обе команды получат тот же технический долг. В отсутствие таких данных я бы только утверждал, что он не считает нужным набирать код без предварительного обдумывания при работе над проектом на 20 человеко-месяцев.
Сохранить шаблон проектирования, который больше не имеет смысла, и попытаться добавить больше шаблонов для вновь созданной ситуации?
Это тоже не кажется правильным. Шаблоны используются для упрощения понимания кода; положить слишком много шаблонов, и код станет беспорядок.
Начать думать о новом дизайне, который охватывает новые требования, а затем постепенно преобразовать старый дизайн в новый?
Как теоретик и тот, кто предпочитает Agile, я полностью увлечен этим. На практике, когда вы знаете, что вам придется возвращаться к доске каждую неделю и переделывать большую часть предыдущего дизайна, и что у клиента просто не хватает средств, чтобы заплатить вам за это, или не хватает времени ждать это, вероятно, не сработает.
Итак, есть предложения?
источник
Ответы:
Я вижу некоторые неправильные предположения в этом вопросе:
Шаблоны проектирования не являются самоцелью, они должны служить вам, а не наоборот. Если шаблон проектирования не делает код более легким для реализации или, по крайней мере, лучше развивающимся (что означает: его легче адаптировать к изменяющимся требованиям), тогда шаблон не соответствует своему назначению. Не применяйте шаблоны, если они не облегчают жизнь команде. Если новый шаблон объекта Null служил вашему другу в течение того времени, когда он его использовал, то все было в порядке. Если это должно было быть устранено позже, тогда это могло бы быть также хорошо. Если шаблон объекта Null замедлял (правильную) реализацию, то его использование было неправильным. Обратите внимание, что из этой части истории пока нельзя сделать вывод о какой-либо причине «кода спагетти».
Это не его работа и не его вина! Ваша задача - заботиться о сплоченности и согласованности. Когда требования меняются два раза в день, ваше решение не должно жертвовать качеством кода. Просто скажите клиенту, сколько времени это займет, и если вы считаете, что вам нужно больше времени для «правильного» проектирования, то добавьте достаточно большой запас прочности к любой оценке. Особенно, когда у вас есть клиент, пытающийся оказать на вас давление, используйте «принцип Скотти» . И, споря с нетехническим клиентом об усилиях, избегайте таких терминов, как «рефакторинг», «модульные тесты», «шаблоны проектирования» или «документация кода» - это вещи, которые он не понимает и, вероятно, считает «ненужными». ерунда ", потому что он не видит в этом никакой ценности. или, по крайней мере, понятным для клиента (функции, подфункции, изменения поведения, пользовательские документы, исправления ошибок, оптимизация производительности и т. д.).
Честно говоря, если «базовые интерфейсы меняются два раза в день в течение трех месяцев», то решением не должно быть реагирование путем изменения кода два раза в день. Реальное решение состоит в том, чтобы спросить, почему требования так часто меняются и возможно ли внести изменения в этой части процесса. Может быть, поможет еще какой-то предварительный анализ. Возможно, интерфейс слишком широкий, потому что граница между компонентами выбрана неправильно. Иногда это помогает запросить дополнительную информацию о том, какая часть требований является стабильной, а какие все еще обсуждаются (и фактически откладывают реализацию обсуждаемых вопросов). И иногда некоторых людей просто «пинают в задницы» за то, что они не передумали дважды в день.
источник
Мое скромное мнение, что вы не должны избегать или не избегать использования шаблонов дизайна.
Шаблоны проектирования - это просто хорошо известные и надежные решения общих проблем, которым были даны имена. Они не отличаются в техническом отношении от любого другого решения или дизайна, о котором вы только можете подумать.
Я думаю, что корень проблемы может заключаться в том, что ваш друг думает с точки зрения «применения или не применения шаблона проектирования», а не с точки зрения «что является лучшим решением, которое я могу придумать, включая, но не ограничиваясь шаблонами» Я знаю".
Возможно, этот подход заставляет его использовать шаблоны частично искусственным или принудительным образом, в местах, где они не принадлежат. И это то, что приводит к беспорядку.
источник
В вашем примере использования шаблона Null Object я считаю, что в конечном итоге он потерпел неудачу, потому что он отвечал потребностям программиста, а не потребностям клиента. Клиент должен был отобразить цену в форме, соответствующей контексту. Программист должен был упростить некоторые коды отображения.
Итак, если шаблон проектирования не соответствует требованиям, мы говорим, что все шаблоны проектирования - пустая трата времени, или мы говорим, что нам нужен другой шаблон проектирования?
источник
Казалось бы, ошибка заключалась скорее в удалении объектов шаблона, чем в их использовании. В первоначальном проекте Нулевой Объект, по-видимому, обеспечил решение проблемы. Это, возможно, не было лучшим решением.
Быть единственным человеком, работающим над проектом, дает вам возможность испытать весь процесс разработки. Большим недостатком является отсутствие кого-то, чтобы быть вашим наставником. Потратив время на изучение и применение лучших или лучших практик, вы быстро окупитесь. Хитрость в том, чтобы определить, какую практику учить когда.
Связывание ссылок в форме product.Price.toString ('c') нарушает закон Деметры . Я видел все виды проблем с этой практикой, многие из которых относятся к нулям. Такой метод, как product.displayPrice ('c'), может внутренне обрабатывать нулевые цены. Аналогично product.Description.Current может обрабатываться product.displayDescription (), product.displayCurrentDescription (). или product.diplay («Текущий»).
Обработка нового требования к менеджерам и поставщикам контента должна выполняться с учетом контекста. Существует множество подходов, которые можно использовать. Методы фабрики могут использовать разные классы продуктов в зависимости от класса пользователя, которому они будут отображаться. Другой подход заключается в том, чтобы методы отображения класса продукта создавали разные данные для разных пользователей.
Хорошая новость в том, что ваш друг понимает, что все выходит из-под контроля. Надеюсь, у него есть код в контроле версий. Это позволит ему отвергать плохие решения, которые он всегда будет принимать. Часть обучения состоит в том, чтобы попробовать разные подходы, некоторые из которых потерпят неудачу. Если он справится со следующими несколькими месяцами, он может найти подходы, которые упростят его жизнь и очистят спагетти. Он мог попытаться исправить одну вещь каждую неделю.
источник
Вопрос кажется неправильным во многих аспектах. Но вопиющие из них:
Многие люди правильно сказали, что шаблоны проектирования - это очень много общего с маркировкой и наименованием. Так что подумайте о рубашке, у рубашки есть воротник, по какой-то причине вы снимаете воротник или часть воротника. Меняется название и маркировка, но по сути это все-таки рубашка. Это именно тот случай, незначительные изменения в деталях, которые не означают, что вы «убили» этот шаблон. (снова возражаю против крайних формулировок)
По моему опыту, когда появляются незначительные требования, вам нужно изменить только небольшую часть кода. Некоторые могут быть немного хакерскими, но ничего слишком серьезного, чтобы существенно повлиять на удобство обслуживания или читабельность, и часто достаточно нескольких строк комментария для объяснения хакерской части. Это очень распространенная практика.
источник
Давайте на минуту остановимся и рассмотрим фундаментальную проблему - создание системы, в которой архитектурная модель слишком связана с низкоуровневыми функциями в системе, что приводит к частым сбоям архитектуры в процессе разработки.
Я думаю, что мы должны помнить, что использование архитектуры и связанных с этим шаблонов проектирования должно быть заложено на соответствующем уровне, и что анализ того, что является правильным уровнем, не является тривиальным. С одной стороны, вы могли бы легко поддерживать архитектуру вашей системы на слишком высоком уровне только с очень простыми ограничениями, такими как «MVC» или тому подобное, что может привести к упущенным возможностям, как в четких рекомендациях и использовании кода, и где спагетти-код может легко процветать во всем этом свободном пространстве.
С другой стороны, вы можете с таким же успехом перепроектировать свою систему, как и при установке ограничений на детальный уровень, когда вы предполагаете, что можете полагаться на ограничения, которые в действительности более изменчивы, чем вы ожидаете, постоянно нарушая свои ограничения и заставляя вас постоянно переделывать и перестраивать, пока вы не начнете отчаиваться.
Изменения в требованиях к системе всегда будут в той или иной степени. И потенциальные преимущества использования архитектурных и дизайнерских шаблонов всегда будут присутствовать, поэтому на самом деле не стоит вопрос использования шаблонов проектирования или нет, но на каком уровне вы должны их использовать.
Это требует, чтобы вы не только понимали текущие требования к предлагаемой системе, но и определяли, какие ее аспекты можно рассматривать как стабильные основные свойства системы, и какие свойства могут измениться в ходе разработки.
Если вы обнаружите, что вам постоянно приходится бороться с неорганизованным спагетти-кодом, вы, вероятно, недостаточно работаете с архитектурой или на высоком уровне. Если вы обнаружите, что ваша архитектура часто ломается, вы, вероятно, делаете слишком подробную архитектуру.
Использование архитектурных и дизайнерских шаблонов - это не то, что можно просто «покрыть» системой, как если бы вы нарисовали стол. Это методы, которые следует применять вдумчиво, на уровне, где ограничения, на которые вы должны полагаться, имеют высокую вероятность быть стабильными, и где эти методы действительно стоят задач моделирования архитектуры и реализации фактических ограничений / архитектуры / шаблонов. как код
Относительно вопроса о слишком детальной архитектуре, вы также можете приложить немало усилий в архитектуре, где она не дает особой ценности. См. Ориентированную на риск архитектуру для справки, мне нравится эта книга - Достаточно программной архитектуры , возможно, вам тоже.
редактировать
Уточнил свой ответ, поскольку я понял, что часто выражал себя как «слишком много архитектуры», где я действительно имел в виду «слишком детальную архитектуру», что не совсем то же самое. Слишком детальная архитектура, вероятно, часто может рассматриваться как «слишком большая» архитектура, но даже если вы поддерживаете архитектуру на хорошем уровне и создаете самую красивую систему, которую когда-либо видело человечество, это все равно может быть слишком большим усилием для архитектуры, если приоритеты на особенности и время выхода на рынок.
источник
Ваш друг, кажется, сталкивается с многочисленными встречными ветрами, основанными на его анекдоте. Это прискорбно и может быть очень сложной средой для работы. Несмотря на трудности, он был на правильном пути использования шаблонов, чтобы облегчить свою жизнь, и это позор, что он ушел с этого пути. Код спагетти - это конечный результат.
Поскольку существуют две разные проблемные области, техническая и межличностная, я буду решать каждую из них отдельно.
Межличностные
Борьба вашего друга связана с быстро меняющимися требованиями и с тем, как это влияет на его способность писать поддерживаемый код. Прежде всего, я бы сказал, что требования, меняющиеся два раза в день, каждый день в течение такого длительного периода времени, являются более серьезной проблемой и имеют нереалистичные неявные ожидания. Требования меняются быстрее, чем код может измениться. Мы не можем ожидать, что код или программист будут в курсе. Этот быстрый темп изменений является симптомом неполной концепции желаемого продукта на более высоком уровне. Это проблема. Если они не знают, чего они на самом деле хотят, они потратят много времени и денег, чтобы никогда этого не получить.
Это может быть хорошо, чтобы установить границы для изменений. Сгруппируйте изменения в наборы каждые две недели, затем заморозьте их на две недели, пока они будут внедрены. Создайте новый список на следующие две недели. У меня есть чувство, что некоторые из этих изменений перекрываются или противоречат друг другу (например, колеблются между двумя вариантами). Когда изменения происходят быстро и яростно, все они имеют высший приоритет. Если вы позволите им накапливаться в списке, вы можете работать с ними, чтобы упорядочить и расставить приоритеты, что является наиболее важным для максимизации усилий и производительности. Они могут видеть, что некоторые из их изменений глупы или менее важны, давая вашему другу немного передышки.
Эти проблемы не должны мешать вам писать хороший код. Плохой код приводит к худшим проблемам. Рефакторинг от одного решения к другому может занять некоторое время, но сам факт того, что это возможно, показывает преимущества хорошей практики кодирования через шаблоны и принципы.
В условиях частых изменений, технический долг будет поступать из - за какими - то момент. Гораздо лучше совершать платежи к нему, чем бросать полотенце и ждать, пока оно не станет слишком большим, чтобы его преодолеть. Если шаблон больше не полезен, отредактируйте его, но не возвращайтесь к способам кодирования ковбоя.
технический
Кажется, ваш друг хорошо разбирается в основных шаблонах дизайна. Нулевой объект - это хороший подход к проблеме, с которой он столкнулся. По правде говоря, это все еще хороший подход. Там, где он, кажется, испытывает трудности, понимает принципы, лежащие в основе шаблонов, почему они есть. В противном случае, я не верю, что он отказался бы от своего подхода.
(Далее следует набор технических решений, которые не запрашивались в первоначальном вопросе, но которые показывают, как мы могли придерживаться шаблонов в иллюстративных целях.)
Принцип, лежащий в основе нулевого объекта - это идея инкапсулирования того, что меняется . Мы скрываем, что меняется, поэтому нам не приходится иметь дело с этим повсюду. Здесь нулевой объект инкапсулировал дисперсию в
product.Price
экземпляре (я назову этоPrice
объектом, и цена нулевого объекта будет равнаNullPrice
).Price
это предметный предмет, бизнес-концепция. Иногда в нашей бизнес-логике мы еще не знаем цену. Это случилось. Идеальный вариант использования для нулевого объекта.Price
У него естьToString
метод, который выводит цену или пустую строку, если она неизвестна (илиNullPrice#ToString
возвращает пустую строку). Это разумное поведение. Тогда требования меняются.Мы должны вывести a
null
в представление API или строку, отличную от представления менеджеров. Как это влияет на нашу бизнес-логику? Ну, это не так. В приведенном выше утверждении я дважды использовал слово «просмотр». Это слово, вероятно, не было сказано явно, но мы должны научиться слышать скрытые слова в требованиях. Так почему же «вид» так важен? Потому что это говорит нам, где действительно должны произойти изменения: на наш взгляд.Кроме того : неважно, используем мы фреймворк MVC или нет. В то время как MVC имеет очень специфическое значение для «View», я использую его в более общем (и, возможно, более применимом) значении фрагмента кода представления.
Так что нам действительно нужно это исправить в представлении. Как мы могли это сделать? Самым простым способом сделать это было бы
if
утверждение. Я знаю, что нулевой объект был предназначен, чтобы избавиться от всех ifs, но мы должны быть прагматичными. Мы можем проверить строку, чтобы увидеть, если она пуста, и переключиться:Как это влияет на инкапсуляцию? Наиболее важной частью здесь является то, что логика представления инкапсулирована в представление . Таким образом, мы можем сохранить нашу бизнес-логику / доменные объекты полностью изолированными от изменений в логике представления. Это некрасиво, но это работает. Это не единственный вариант, хотя.
Мы могли бы сказать, что наша бизнес-логика немного изменилась: мы хотим выводить строки по умолчанию, если цена не установлена. Мы можем внести незначительные изменения в наш
Price#ToString
метод (фактически создать перегруженный метод). Мы можем принять возвращаемое значение по умолчанию и вернуть его, если цена не установлена:И теперь наш код представления становится:
Условие ушло. Однако, если вы сделаете это слишком много, это может привести к распространению специальных методов case в ваши доменные объекты, так что это имеет смысл только в том случае, если будет только несколько примеров этого.
Вместо этого мы могли бы создать
IsSet
метод,Price
который возвращает логическое значение:Посмотреть логику:
Мы видим возврат условного в представлении, но дело в том, что бизнес-логика говорит, установлена ли цена. Мы можем использовать в
Price#IsSet
другом месте сейчас, когда у нас есть в наличии.Наконец, мы можем заключить в себе идею представления цены полностью в качестве помощника для представления. Это скрыло бы условное выражение, сохранив объект домена столько, сколько мы хотели бы:
Посмотреть логику:
Есть еще много способов внести изменения (мы можем обобщить
PriceStringHelper
в объект, который возвращает значение по умолчанию, если строка пуста), но это несколько быстрых, которые сохраняют (по большей части) как шаблоны, так и принципы, как а также прагматический аспект внесения таких изменений.источник
Сложность шаблона проектирования может укусить вас, если проблема, которую он должен был решить, внезапно исчезнет. К сожалению, из-за энтузиазма и популярности шаблонов проектирования этот риск редко выражается. Анекдот вашего друга очень помогает показать, как шаблоны не окупаются. У Джеффа Этвуда есть несколько слов на эту тему.
Документируйте точки отклонения (это риски) в требованиях
Многие из более сложных шаблонов проектирования (не так много Null Object) содержат концепцию защищенных вариантов , а именно: «Определение точек прогнозируемого изменения или нестабильности; распределение обязанностей по созданию стабильного интерфейса вокруг них». Адаптер, Посетитель, Фасад, Слои, Наблюдатель, Стратегия, Декоратор и т. Д. Используют этот принцип. Они «окупаются», когда программное обеспечение необходимо расширить в аспекте ожидаемой изменчивости, а «стабильные» допущения остаются стабильными.
Если ваши требования настолько нестабильны, что ваши «прогнозируемые отклонения» всегда неверны, то применяемые вами шаблоны причинят вам боль или станут в лучшем случае ненужной сложностью.
Крейг Ларман говорит о двух возможностях применения защищенных вариантов:
Предполагается, что оба документа задокументированы разработчиками, но, вероятно, у вас должна быть приверженность клиентов к вариантам.
Чтобы управлять рисками, можно сказать, что любой шаблон проектирования, использующий PV, должен быть прослежен до точки изменения требований, подписанных заказчиком. Если клиент меняет точку изменения в требованиях, ваш дизайн может измениться радикально (потому что вы, вероятно, вложили средства в дизайн [шаблоны], чтобы поддержать это изменение). Не нужно объяснять сплоченность, сцепление и т. Д.
Например, ваш клиент хочет, чтобы программное обеспечение работало с тремя различными устаревшими системами инвентаризации. Это точка вариации, которую вы разрабатываете вокруг. Если заказчик откажется от этого требования, то, конечно, у вас будет куча бесполезной инфраструктуры проектирования. Клиент должен знать, что точки изменения чего-то стоят.
CONSTANTS
в исходном коде это простая форма PVДругая аналогия с вашим вопросом - спросить, является ли использование
CONSTANTS
в исходном коде хорошей идеей. Ссылаясь на этот пример , скажем, клиент отказался от паролей. Таким образомMAX_PASSWORD_SIZE
, постоянное распространение по всему вашему коду станет бесполезным и даже станет помехой в обслуживании и удобочитаемости. Вы бы обвинить использование вCONSTANTS
качестве причины?источник
Я думаю, что это хотя бы частично зависит от характера вашей ситуации.
Вы упомянули постоянно меняющиеся требования. Если клиент говорит: «Я хочу, чтобы это приложение для пчеловодства также работало с осами», то это похоже на ситуацию, в которой тщательный дизайн поможет прогрессу, а не помешает ему (особенно если учесть, что в будущем она может захотеть держать и плодовых мушек тоже.)
С другой стороны, если природа изменения больше похожа на «Я хочу, чтобы это приложение для пчеловодства управляло платежной ведомостью моего конгломерата прачечной самообслуживания», никакое количество кода не вытащит вас из вашей дыры.
В шаблонах дизайна нет ничего хорошего. Они такие же инструменты, как и любые другие - мы используем их только для облегчения нашей работы в средне- и долгосрочной перспективе. Если другой инструмент (такой как коммуникация или исследование ) более полезен, тогда мы используем это.
источник