Я понимаю, что SOLID должен выполнять, и регулярно использую его в ситуациях, когда модульность важна и ее цели явно полезны. Однако две вещи мешают мне применять его последовательно в моей кодовой базе:
Я хочу избежать преждевременной абстракции. По моему опыту, рисование линий абстракции без конкретных вариантов использования (типа, существующего сейчас или в обозримом будущем) приводит к тому, что их рисуют в неправильных местах. Когда я пытаюсь изменить такой код, строки абстракции мешают, а не помогают. Поэтому я склонен ошибаться в том, что не рисую никаких линий абстракции, пока у меня нет четкого представления о том, где они будут полезны.
Мне трудно оправдать увеличение модульности ради самого себя, если это делает мой код более многословным, трудным для понимания и т. Д. И не устраняет никакого дублирования. Я считаю, что простой, тесно связанный процедурный или объектный код Бога иногда легче понять, чем очень хорошо продуманный код равиоли, потому что поток простой и линейный. Это также намного легче написать.
С другой стороны, это мышление часто приводит к объектам Бога. Я обычно достаточно осторожно рефакторинг, добавляя четкие линии абстракции только тогда, когда вижу четкие шаблоны. Что, если вообще что-то не так с объектами God и тесно связанным кодом, если вам явно не нужно больше модульности, нет значительного дублирования и код читабелен?
РЕДАКТИРОВАТЬ: Что касается отдельных принципов SOLID, я хотел подчеркнуть, что подстановка Лискова ИМХО является формализацией здравого смысла и должна применяться везде, поскольку абстракции не имеют смысла, если это не так. Кроме того, каждый класс должен нести одну ответственность на некотором уровне абстракции, хотя это может быть очень высокий уровень с деталями реализации, объединенными в один огромный класс из 2000 строк. По сути, ваши абстракции должны иметь смысл там, где вы решите абстрагироваться. Принципы, которые я подвергаю сомнению в случаях, когда модульность явно не полезна, являются открытыми-закрытыми, сегрегацией интерфейса и особенно инверсией зависимостей, поскольку они касаются модульности, а не просто наличия абстракций.
источник
Ответы:
Ниже приведены простые принципы, которые вы можете применить, чтобы помочь вам понять, как сбалансировать дизайн вашей системы:
S
в SOLID. Вы можете иметь очень большой объект с точки зрения количества методов или объема данных и при этом соблюдать этот принцип. Возьмите, например, объект Ruby String. Этот объект имеет больше методов, чем вы можете потрясти палкой, но у него все еще есть только одна обязанность: держать текстовую строку для приложения. Как только ваш объект начинает брать на себя новую ответственность, задумайтесь об этом. Вопрос обслуживания спрашивает себя: «Где бы я мог найти этот код, если бы у меня были проблемы с ним позже?»По сути, вы пытаетесь сделать все возможное, чтобы не застрелиться в ногу, когда приходит время поддерживать программное обеспечение. Если ваши большие объекты являются разумными абстракциями, то нет причин для их разделения просто потому, что кто-то придумал метрику, которая говорит, что класс должен быть не более чем X строк / методов / свойств / и т.д. Во всяком случае, это руководящие принципы, а не жесткие и быстрые правила.
источник
Я думаю, что по большей части вы ответили на свой вопрос. SOLID - это набор рекомендаций по рефакторингу вашего кода, когда концепции должны двигаться вверх по уровням абстракций.
Как и во всех других творческих дисциплинах, здесь нет абсолютов - только компромиссы. Чем больше вы делаете это, тем «легче» становится решать, когда этого достаточно для вашей текущей проблемной области или требований.
Сказав это - абстракция - это сердце разработки программного обеспечения - поэтому, если нет веской причины не делать этого, то практика сделает вас лучше в этом, и вы почувствуете внутреннее понимание компромиссов. Так одобрите это, если это не становится вредным.
источник
Это частично правильно и частично неправильно.
Неверно
Это не является причиной, препятствующей применению принципов OO / SOLID. Это только мешает применять их слишком рано.
Который...
Право
Не рефакторинг кода, пока он не рефакторинг; когда это требования выполнены. Или когда «варианты использования» все там, как вы говорите.
При работе в одиночку или в бункере
. Проблема с отсутствием ОО не сразу очевидна. После того, как вы напишите первую версию программы:
3/4 из этих хороших вещей быстро умирают за короткое время.
Наконец, вы узнаете, что у вас есть объекты Бога (объекты со многими функциями), поэтому вы распознаете отдельные функции. Инкапсуляция. Поместите их в папки. Используйте интерфейсы время от времени. Сделайте себе одолжение для долгосрочного обслуживания. Тем более что нерефакторированные методы имеют тенденцию бесконечно раздуты и превращаться в методы Бога.
В команде
Проблемы с отсутствием ОО сразу заметны. Хороший ОО-код как минимум самодокументирован и читабелен. Особенно в сочетании с хорошим зеленым кодом. Кроме того, отсутствие структуры затрудняет разделение задач и интеграцию намного сложнее.
источник
Нет ничего плохого в больших объектах и тесно связанном коде, когда они уместны и когда не требуется ничего более совершенного . Это просто еще одно проявление эмпирического правила, превращающегося в догму.
Слабая связь и небольшие простые объекты имеют тенденцию давать определенные преимущества во многих типичных случаях, поэтому в целом рекомендуется использовать их. Проблема заключается в людях, которые не понимают обоснования принципов, слепо пытающихся применять их повсеместно, даже там, где они не применяются.
источник
Я имею тенденцию подходить к этому больше с точки зрения «Ты не будешь нуждаться в этом». Этот пост будет посвящен, в частности, одному вопросу: наследованию.
В моем первоначальном проекте я создаю иерархию вещей, которые, как я знаю, будут двух или более. Скорее всего, им понадобится большая часть одного и того же кода, поэтому стоит разработать его с самого начала. После того, как начальный код установлен , и мне нужно добавить больше функций / возможностей, я смотрю на то, что у меня есть, и думаю: «Имеет ли что-то, что я уже реализовал, ту же или подобную функцию? Если это так, то, скорее всего, это новая абстракция, требующая выпуска.
Хорошим примером этого является инфраструктура MVC. Начиная с нуля, вы создаете одну большую страницу с кодом позади. Но тогда вы хотите добавить еще одну страницу. Однако один код позади уже реализует много логики, необходимой новой странице. Итак, вы абстрагируете
Controller
класс / интерфейс, который будет реализовывать логику, специфичную для этой страницы, оставляя общие вещи в исходном «богом» коде.источник
Если вы знаете, как разработчик, когда НЕ следует применять принципы из-за будущего кода, тогда это хорошо для вас.
Я надеюсь, что SOLID останется в вашей памяти, чтобы знать, когда необходимо абстрагироваться, чтобы избежать сложности и улучшить качество кода, если он начинает ухудшаться в указанных вами значениях.
Что еще более важно, учтите, что большинство разработчиков делают ежедневную работу и не заботятся так же, как вы. Если вы изначально установили долго работающие методы, что другие разработчики, которые придут к коду, подумают, когда они будут поддерживать или расширять его? ... Да, как вы уже догадались, BIGGER-функции, LONGER-запущенные классы и MORE объекты бога, и у них нет принципов, чтобы можно было уловить растущий код и правильно его инкапсулировать. Ваш «читаемый» код теперь превращается в гниющий беспорядок.
Таким образом, вы можете утверждать, что плохой разработчик будет делать это независимо, но, по крайней мере, у вас будет лучшее преимущество, если все будет просто и хорошо организовано с самого начала.
Я не особенно возражаю против глобальной «Карты реестра» или «Объекта Бога», если они просты. Это действительно зависит от конструкции системы, иногда вы можете сойти с рук и оставаться простым, а иногда нет.
Давайте также не будем забывать, что большие функции и объекты Бога могут оказаться чрезвычайно трудными для тестирования. Если вы хотите оставаться гибким и чувствовать себя в безопасности при перефакторинге и изменении кода, вам нужны тесты. Тесты сложно писать, когда функции или объекты делают много вещей.
источник
Проблема с божественным объектом состоит в том, что вы обычно можете выгодно разбить его на куски. По определению, это делает больше, чем одну вещь. Вся цель разбиения его на более мелкие классы состоит в том, чтобы у вас был класс, который хорошо выполняет одну вещь (и вам также не следует расширять определение «одной вещи»). Это означает, что для любого данного класса, когда вы знаете одну вещь, которую он должен делать, вы должны быть в состоянии прочитать его довольно легко и сказать, правильно ли он выполняет эту одну вещь.
Я думаю, что есть такая вещь, как слишком большая модульность и слишком большая гибкость, но это скорее проблема чрезмерного проектирования и чрезмерного проектирования, когда вы учитываете требования, которые вы даже не знаете, чего хочет клиент. Многие идеи дизайна ориентированы на то, чтобы упростить управление изменениями в коде, но если никто не ожидает изменений, то включать гибкость бессмысленно.
источник
Queryer
который оптимизирует запросы к базе данных, запрашивает СУБД и анализирует результаты в возвращаемых объектах. Если есть только один способ сделать это в вашем приложении, иQueryer
он герметически запечатан и инкапсулирует это одним способом, то это делает только одно. Если есть несколько способов сделать это, и кто-то может позаботиться о деталях одной его части, тогда он делает несколько вещей, и вы можете захотеть разделить его.Я использую более простое руководство: если вы можете написать для него модульные тесты и не иметь дублирования кода, это достаточно абстрактно. Кроме того, вы находитесь в хорошем положении для последующего рефакторинга.
Кроме того, вы должны помнить о SOLID, но скорее как руководство, а не как правило.
источник
Если приложение достаточно маленькое, все, что можно отремонтировать. В больших приложениях объекты Бога быстро становятся проблемой. В конечном итоге реализация новой функции требует модификации 17 объектов Бога. Люди не очень хорошо следуют 17-шаговым процедурам. Объекты Бога постоянно модифицируются несколькими разработчиками, и эти изменения необходимо объединять неоднократно. Вы не хотите идти туда.
источник
Я разделяю ваши опасения по поводу чрезмерной и неуместной абстракции, но я не обязательно так обеспокоен преждевременной абстракцией.
Это, вероятно, звучит как противоречие, но использование абстракции вряд ли вызовет проблему, если вы не слишком рано выполняете ее, то есть, если вы готовы и способны реорганизовать ее при необходимости.
Это подразумевает некоторую степень прототипирования, экспериментов и возврата в код.
Тем не менее, не существует простого детерминистического правила, которое могло бы решить все проблемы. Опыт имеет большое значение, но вы должны получить этот опыт, делая ошибки. И всегда есть больше ошибок, чтобы сделать, что предыдущие ошибки не подготовили вас к.
Несмотря на это, рассматривайте принципы учебника как отправную точку, затем изучите программирование и посмотрите, как эти принципы работают. Если бы можно было дать лучшие, более точные и надежные руководящие принципы, чем такие, как SOLID, кто-то, вероятно, сделал бы это сейчас - и даже если бы они это сделали, эти улучшенные принципы все еще были бы несовершенными, и люди спрашивали бы об ограничениях в этих ,
Хорошая работа - если бы кто-то мог предоставить четкий, детерминистический алгоритм для разработки и кодирования программ, для человека была бы только одна последняя программа - программа, которая автоматически напишет все будущие программы без вмешательства человека.
источник
Рисование соответствующих линий абстракции - это то, что человек извлекает из опыта. Вы будете делать ошибки при этом, что неоспоримо.
SOLID - это концентрированная форма того опыта, который передают вам люди, которые получили этот опыт трудным путем. Вы в значительной степени прибили это, когда говорите, что воздержитесь от создания абстракции, прежде чем увидите необходимость в этом. Опыт SOLID поможет вам решить проблемы, с которыми вы никогда не сталкивались . Но поверь мне ... там очень реально.
SOLID - это модульность, модульность - это удобство обслуживания, а удобство обслуживания - это возможность поддерживать гуманный рабочий график, как только программное обеспечение достигнет производства, и клиент начнет замечать ошибки, которых у вас нет.
Самым большим преимуществом модульности является тестируемость. Чем более модульна ваша система, тем легче ее тестировать, и тем быстрее вы сможете создать прочную основу для решения более сложных аспектов вашей проблемы. Таким образом, ваша проблема может не требовать этой модульности, но только тот факт, что она позволит вам быстрее создавать лучший тестовый код, не представляет никакой сложности для стремления к модульности.
Быть проворным - все о попытке найти тонкий баланс между быстрой доставкой и обеспечением хорошего качества. Agile не означает, что мы должны срезать угол, на самом деле, наиболее успешные гибкие проекты, с которыми я принимал участие, - это те, которые уделяют пристальное внимание таким рекомендациям.
источник
Важным моментом, который, кажется, упустили из виду, является то, что SOLID практикуется вместе с TDD. TDD имеет тенденцию выдвигать на первый план то, что "уместно" в вашем конкретном контексте, и помогает облегчить большую часть двусмысленности, которая, кажется, содержится в совете
источник