Иногда, открываешь какой-нибудь проект с историей и понимаешь, что история и у этого проекта была длинная… Да еще и авторы менялись, и видно, что у них был небольшой опыт.
В чем это выражается? — В том, что все части системы настолько переплетены, что невозможно оторвать один кусок и использовать где-то еще. Как результат, такой проект, конечно невозможно накрыть никакими модульными тестами кроме как приемочными со стороны группы QA. А значит, что со временем стоимость доработки будет возрастать, так как мы теряем уверенность в том, что наши изменения не поломают какие-то другие части.
Другим симптомом низкого качества проекта, может служить факт, что один класс выполняет одновременно множество ролей, то есть такой универсал-многостаночник. Это часто получается из-за того, что разработчику просто лень писать новый класс/интерфейс, потом его вводить в систему перестраивая связи. Намного проще просто «добавить метод по месту», «ведь если я добавлю сюда еще один метод ничего плохого не произойдет, так?» — думает он. Но после одного метода, появляется второй и третий. Если разработчик продвинутый, он запишет задачу «технический долг — надо выполнить рефакторинг и поделить всё на части», но часто он может даже не понимать, что проблема существует. Это обычно распространено в молодых командах, где нет специалиста с хорошим и правильным стажем.
А бывает ли такое, где есть специалист со стажем, но проект все-равно находится в запутанном состоянии? Да, и такое бывает. Как правило, на проектах, которые велись одним разработчиком, и его никто не наставлял на путь истинный. А потом, он вырастает, у него уж есть репутация «я тут давно работаю», «поработай тут, с мое, а потом говори» И он уже становится неспособным воспринимать правильный дизайн и правильное разделение компонент. Ему кажется, что это слишком сложно и запутанно.
Иногда, можно видеть ситуацию, когда профессионал пишет «по-быстрому», расширяя объекты несвойственным функционалом. Однако, профи точно знает, что прямо сейчас он решает задачу быстро, или делает макет, а завтра ему нужно будет обязательно выполнить рефакторинг. Но такой подход всё-таки оправдан только на быстрых и коротких проектах с очень маленькой длительностью. Технический долг имеет свою процентную ставку, и с каждой неделей она возрастает.
Как понять какой дизайн хороший, а какой плохой? Я рекомендую простой критерий:
Для каждого класса/объекта системы пишем ответы на вопросы:
- Чем класс должен заниматься? Какова его зона ответственности?
- Чем класс НЕ ДОЛЖЕН заниматься? В какие смежные области класс точно не должен лезть.
Ответы на эти вопросы сформируют систему связанных фактов, которую нужно проверить ответив на самый главный вопрос:
Почему ты считаешь, что (эта фича/действие/возможность) должна обеспечиваться этим классом?
Если вы нашли логическое и непротиворечивое доказательство, которое не конфликтует с ранее записанными фактами, значит ваш проект имеет хороший дизайн. Если же есть сомнения, значит что-то не так и нужно подумать о перепроектировании.
Это, конечно, не защищает от того, что дизайн будет гарантированно хороший, но даст почву для размышлений.
Кроме этих вопросов, можно применить еще несколько индикаторов, позволяющих «поймать» неверное решение на ранних фазах:
Класс выполняет больше одной роли. В ответе на вопрос «Что класс должен делать?» хочется начать перечислять возможности. И вы не можете сконцентрироваться на какой-то одной самой важной. Это означает, что надо подумать о разделении на несколько классов.
Не удается выразить одним кратким предложением, чем занимается класс. Это значит, что его зона ответственности размыта, и у вас нет понимания зачем этот класс нужен. Индикатор показывает, что в будущем это может стать «кучей мусора».
Есть острое желание вытащить наружу какие-то защищенные данные или методы. Показывает, что к класса меняется роль, и он становится агрегатором данных. Имеет смысл перепроверить назначение класса и его ограничения.
Используя такие простые логические инструменты, можно быстро проверить на устойчивость вашу архитектуру, чтобы она не стала рахитектурой.
Вопрос: Коллеги, а какие вы применяете способы проверки дизайна на устойчивость?
PHmaster
Вы описали один антипаттерн объектно-ориентированного программирования под названием «Божественный объект». И упомянули еще один: «Равиоли-код». Рекомендую ознакомиться с более обширным списком (далеко не полным). Под таким многообещающим названием прочитать статью с описанием двух общеизвестных антипаттернов… Я испытал разочарование =/
sbase Автор
Цель данной статьи было не перечисление антипаттернов, а пресечение их возникновения. Для того чтобы понять систему шаблонов проектирования нужно уже освоить базу языка. Так, как это более высокий уровень абстракции. Но несколько простых вопросов могут помочь в критической оценке создаваемого дизайна без знания всех паттернов и антипаттернов.
Для познания возможностей языка программирования нужно минимум 3 года, для познания паттернов и особенностей их применения еще 2 года. Таким образом, я хороший специалист с навыками проектирования должен иметь стаж не менее 5 лет. И то, если его кто-то наставлял на путь истинный.
Коллега, какие более быстрые способы обучения навыкам хорошего проектирования с нуля Вы знаете?
PHmaster
Всего лишь двух из огромного списка. Без упоминания даже, что существуют другие, и их много. Это как если, выпуская человека впервые одного в джунгли, снабдить его единственным советом: «Остерегайся мухи цеце — и ты останешься жив и здоров».
Самый быстрый способ: ознакомиться со списком паттернов проектирования и их кратким описанием, ознакомиться со списком и кратким описанием антипаттернов. И тогда вся Ваша статья (и без того не очень длинная) сведется вообще к одному предложению: «Не создавайте божественные объекты и не используйте равиоли-код — и всё, ваш дизайн будет хорошим». Как-то… жидковато для статьи с фундаментальным названием «Хороший дизайн, плохой дизайн…», Вам не кажется?
sbase Автор
Отвечая на Ваш вопрос, касательно фундаментальности статьи:
Возможно, мне не удалось правильно донести свою мысль и Ваши ожидания от статьи разошлись с реальностью. Однако у всяких паттернов есть ключевые условия их возникновения как и у антипаттернов. Именно их и хотелось рассмотреть и начать какую-то конструктивную дискуссию именно о простых базовых принципах, применимых в качестве отправной точки при аудите дизайна (вместо «у тебя здесь божественный объект — исправь»). Однако, к сожалению, не увидел от Вас, коллега, ни одного конструктивного комментария.
Что касается способа «RTFM паттерны»:
Коллега, Вы серьезно уверены что молодой специалист, почти без стажа работы, сможет удержать в голове все паттерны и антипаттерны?
Моя практика показывает, что беглый просмотр паттернов/антипаттернов без продолжительных навыков их применения не дает хорошего эффекта.
Поэтому, повторю вопрос: какой способ Вы считаете приемлемым для быстрого обучения навыкам хорошего дизайна молодых специалистов, кроме способа «RTFM паттерны»?
И, я полагаю, что у Вас, есть хороший опыт в аудите дизайна проекта и проведении рецензирования кода. Какими критериями Вы руководствуетесь при принятии решения, хороший дизайн проекта или нет и его нужно переписать?
PHmaster
В точку. Назови Вы статью «Антипаттерн 'Божественный объект'» — вообще никаких вопросов у меня бы не было. А так получается, что он единственный (ну вкупе еще с упомянутым «Равиоли-кодом») является корнем всех вообще зол в проектировании, и избавившись от этого антипаттерна в своем проекте — получишь идеальный дизайн.
Паттерны и антипаттерны проектирования и являются самой простой базовой отправной точкой, проще уже ничего даже придумать не получается. Это уже готовый к использованию, обкатанный временем инструментарий проектировщика. Не зная паттернов, он просто будет каждый день изобретать велосипеды. Не зная антипаттернов — эти велосипеды будут с квадратными колесами. И кстати, про аудит дизайна Вы заговорили только в комментариях, при прочтении статьи я больше воспринял информацию как «руководство» по разработке правильного дизайна.
Коллега, а Вы серьезно уверены, что такому молодому специалисту без стажа работы и элементарных знаний хватит двух антипаттернов на все случаи жизни? Вы серьезно уверены, что такого «нулёвого» молодого специалиста можно сразу же смело допускать к проектированию более-менее серьезных приложений? Или все же стоит отправить его хотя бы немного поучиться, если он настолько молодой и настолько неопытный?
Ну и давайте все же будем честными: мы же на Хабре, а не на страничке «программирование для чайников». Здесь от статьи ожидаешь немного большего, чем перечисления парочки всем известных прописных истин. Это мое личное мнение, конечно же, я могу и ошибаться.
Правда? Ну то есть я просто написал: «КГ/АМ», и не потрудился разъяснить, чем вызвана моя реакция, и из моих слов совсем не понятно, что бы могло, по моему мнению, сделать статью более содержательной? Тогда извините, что произвел такое впечатление.
velvetcat
Самый лучший вопрос — «о чем класс знает?»
sbase Автор
Да, это вопрос хороший, но, по моему мнению, он является следствием из того «что он должен делать?», Ведь, для того чтобы что-то делать нужно что-то знать. Хотя верно и обратное, не нужно чего-то знать чтобы что-то делать. Начинающие разработчики могут путать цели класса и его знания пытаясь запихнуть дополнительные знания в класс не сообразующиеся с его назначением.
velvetcat
Да, действительно, я с Вами согласен. «Что должен делать» — основной вопрос. «Что знает» — проверочный.
Кстати, это в точности то, как работает TDD: назначили действие — проверили, не слишком ли много классу надо знать для этого.
Спасибо за наводку!
0x13
Если Вы нашли такое логическое и непротиворечивое доказательство, то
у Вашего проекта тепличные условияу Вас есть время их искать. :)Мое убеждение таково, что если человек не научился думать и не имеет должного опыта, то никакие гайдлайны такого рода его не спасут. Простой пример — пишет неопытный программист GUI приложение со сложной логикой, например, тот же редактор Word. Нафигачил он всю логику в класс MainWindow, прочитал этот пост и понял, что у него проблема, класс перегружен функциональностью. И что дальше ему делать, как понять, как этот класс делить? Ну ок, прочитал он книгу и вынес всю бизнес-логику из класса, осталась только работа с GUI, но и она очень сложная, код запутанный, как его делить дальше? Понятно, что пост ни в каком роде не претендует на полноту, но, на мой взгляд, новичкам лучше давать Если вы нашли логическое и непротиворечивое доказательство, которое не конфликтует с ранее записанными фактами, значит ваш проект имеет хороший дизайн. и больше конкретики.
sbase Автор
Это хороший комментарий Тимофей, а есть ли у Вас какие нибудь свои рецепты ускорения развития разработчика? Как научить его думать правильно?
Мой рецепт такой, что если есть понимание что делить надо, то наиболее оптимально это разделение по ролям. И даже если разработчик будет вначале плодить слишком много классов это можно быстро вылечить, за счёт тех же обоснований «почему ты считаешь что это должно быть отдельным классом?»
Тимофей, а какой Ваш рецепт в этом случае?
0x13
Учить постоянно задавать себе вопросы «почему», формировать причино-следственные связи и избегать карго-культа всеми возможными способами. Ну и все это бессмысленно без опыта — много делать руками, ошибаться, исправлять ошибки (тут как раз и важна помощь грамотных старших товарищей), снова делать, снова ошибаться и т.п. Я другого пути не знаю. :) Рецепты в этом смысле тоже полезны, но скорее как справочный материал.