ТВЕРДОЕ И ЯГНИ

Один из самых частых аргументов, которые я слышу, не придерживаясь принципов SOLID в объектно-ориентированном дизайне, YAGNI (хотя аргумент часто не называет этого):

"Все в порядке, что я поставил обе функции X и включил Y в один класс. Это так просто, потому что нужно добавлять новый класс (т.е. сложность)".

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

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

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

Ответ 1

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

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

& ЕПРС; — Robert Glass 'Правила трех, Факты и ошибки разработки программного обеспечения

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

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


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

Действительно ли это единственный пользовательский интерфейс? Планируется ли начальный пакетный режим? Будет ли когда-либо веб-интерфейс?

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

Хорошо, что я поставил обе функции X и включил Y в один класс. Это так просто, почему нужно добавлять новый класс (т.е. Сложность).

Можете ли вы указать на общую ошибку, которой следует избегать? Некоторые вещи достаточно просты, например, возведение в квадрат числа (x * x vs squared(x)) для чрезмерно простого примера, но если вы можете указать конкретную ошибку, которую кто-то сделал, особенно в вашем проекте или в команде, вы можете показать, как общий класс или функция будут избегать этого в будущем.

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

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

Ответ 2

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

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

Ответ 3

Мне нравится думать о YAGNI в терминах "половина, а не наполовину", чтобы заимствовать фразу из 37 сигналов (https://gettingreal.37signals.com/ch05_Half_Not_Half_Assed.php). Это касается ограничения объема, поэтому вы можете сосредоточиться на том, чтобы делать самые важные вещи. Это не повод, чтобы получить неряшливый.

Бизнес-логика в графическом интерфейсе чувствует себя наполовину похожей на меня. Если ваша система тривиальна, я был бы удивлен, если ваша бизнес-логика и графический интерфейс не изменились независимо, несколько раз. Поэтому вам следует следовать SRP ( "S" в SOLID) и рефактору - YAGNI не применяется, потому что он вам уже нужен.

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

Ответ 4

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

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

Ответ 5

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

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

Что касается ваших индивидуальных точек:

ОК, я поставил обе функции X и включить Y в один класс. Это настолько просто, что нужно добавлять новые класс (т.е. сложность).

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

Не бойтесь маленьких классов, они не кусаются; -).

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

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

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

Это имеет некоторые достоинства, но только если они действительно реорганизуют позже. Поэтому примите это и примите их к их обещанию: -).

Ответ 6

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

  • "маловероятно, что появятся новые требования."
  • "Если в маловероятном случае новых требований"

Неужели это правда?

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

Здесь есть еще несколько отличных ответов.

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

Нет ответа, или, вернее, есть ответ, который вам не понравится ни вашему собеседнику: как YAGNI, так и SOLID могут быть неправильными подходами.

Попытка пойти на SOLID с неопытной командой или командой с жесткими задачами доставки в значительной степени гарантирует, что вы закончите с дорогостоящей, переработанной связкой кода..., которая НЕ будет ТВЕРДОЙ, просто переработанной (также добро пожаловать в реальный мир).

Попытка пойти YAGNI для долгосрочного проекта и надеяться, что вы сможете реорганизовать позже, работает только в определенной степени (также приветствуется в реальном мире). YAGNI преуспевает в доказательстве концепций и демонстрантов, приобретая рынок/контракт, а затем сможет инвестировать в нечто большее, чем SOLID.

Вам нужны оба в разные моменты времени.

Ответ 10

TL;DR;

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

Отсюда следует, что SOLID/SRP просит вас сформировать классы для кода, чтобы у него была одна причина для изменения. Например. небольшое изменение графического интерфейса или изменение ServiceCall.

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

Длинный ответ:

Прочтите книгу "Agile Software Development, принципы, шаблоны и практика"

Я размещаю короткую выдержку из нее о SOLID/SRP: "Если [...] приложение не меняется способами, которые заставляют две обязанности меняться в разное время, нет необходимости их разделять. Действительно, их разделение будет пахнуть ненужной сложностью.

Здесь есть пароход. Ось изменения является осью изменения, только если происходят изменения. Нецелесообразно применять SRP или любой другой принцип, если это не так, если нет симптомов ".