SOLID против YAGNI


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

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

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

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

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

10 61

10 ответов:

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

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

- Роберт Гласс' правила трех,факты и заблуждения программной инженерии

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

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


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

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

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

это нормально, что я помещаю как функцию X, так и функцию Y в один и тот же класс. Это так просто, зачем беспокоиться о добавлении нового класса (т. е. сложности).

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

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

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

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

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

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

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

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

ответа нет, вернее, есть ответ, который может не понравиться ни вам, ни вашему собеседнику: и ЯГНИ, и Солид могут быть неверными подходами.

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

попытка пойти ЯГНИ для долгосрочного проекта и надеюсь, что вы можете выполнить рефакторинг позже работает только в определенной степени (ака добро пожаловать в реальный мир). YAGNI преуспевает в доказательстве концепций и демонстраторах, получая рынок/контракт, а затем может инвестировать во что-то более прочное.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

может ли это действительно быть правдой?

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

здесь есть и другие отличные ответы.

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

могут быть времена, когда то, что кажется сумасшедшим сейчас, было разумным в прошлом - иногда границы UI vs business или между различными наборами обязанностей, которые должны быть в другом классе, не так ясны или даже перемещаются. Там могут быть времена, когда 3 часа работы абсолютно необходимо в 2 часа времени. Бывают случаи, когда люди просто не делают правильный выбор. По этим причинам случайные перерывы в этом отношении будут происходить, но они будут мешать использованию принципа ЯГНИ, а не быть причиной этого.

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

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

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

tldr;

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

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

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

ответ :

прочитайте книгу "гибкая разработка программного обеспечения, принципы, шаблоны и практики"

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

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