Наша кодовая база устарела, и новые программисты, как и я, быстро учатся делать это так, как это делается для единообразия. Думая, что мы должны с чего-то начать, я взял на себя реорганизацию класса держателей данных как такового:
- Удалил методы установки и сделал все поля
final
(я беру "final
хорошо" аксиоматически). Как оказалось, сеттеры использовались только в конструкторе, поэтому побочных эффектов не было. - Введен класс Builder
Класс Builder был необходим, потому что конструктор (что и вызвало рефакторинг в первую очередь) занимает около 3 строк кода. У него много параметров.
По счастливой случайности, мой товарищ по команде работал над другим модулем, и ему понадобились сеттеры, потому что требуемые ему значения стали доступны в разных точках потока. Таким образом, код выглядел так:
public void foo(Bar bar){
//do stuff
bar.setA(stuff);
//do more stuff
bar.setB(moreStuff);
}
Я утверждал, что он должен использовать вместо этого конструктор, потому что избавление от сеттеров позволяет полям оставаться неизменными (они слышали, как я разглагольствовал об неизменности ранее), а также потому, что строители позволяют создавать объекты транзакционными. Я набросал следующий псевдокод:
public void foo(Bar bar){
try{
bar.setA(a);
//enter exception-throwing stuff
bar.setB(b);
}catch(){}
}
Если это исключение bar
сработает , будут поврежденные данные, которых можно было бы избежать с помощью компоновщика:
public Bar foo(){
Builder builder=new Builder();
try{
builder.setA(a);
//dangerous stuff;
builder.setB(b);
//more dangerous stuff
builder.setC(c);
return builder.build();
}catch(){}
return null;
}
Мои товарищи по команде возразили, что рассматриваемое исключение никогда не сработает, что достаточно справедливо для этой конкретной области кода, но я считаю, что для дерева не хватает леса.
Компромисс состоял в том, чтобы вернуться к старому решению, а именно использовать конструктор без параметров и установить все с помощью установщиков по мере необходимости. Обоснованием было то, что это решение следует принципу KISS, который нарушает мой.
Я новичок в этой компании (менее 6 месяцев) и полностью осознаю, что потерял эту. У меня есть следующие вопросы:
- Есть ли еще один аргумент в пользу использования Builders вместо «старого способа»?
- Является ли изменение, которое я предлагаю, действительно ли оно того стоит?
но действительно,
- Есть ли у вас какие-либо советы для того, чтобы лучше представить такие аргументы, когда вы пытаетесь попробовать что-то новое?
setA
?Ответы:
Вот где это пошло не так - вы внесли существенное архитектурное изменение в кодовую базу так, что оно сильно отличалось от ожидаемого. Вы удивили своих коллег. Сюрприз хорош только в том случае, если в нем участвует вечеринка, принцип наименьшего удивления - золотой (даже если в нем участвуют вечеринки, я бы знал, что надену чистые трусы!)
Теперь, если вы считаете, что это изменение имеет смысл, было бы гораздо лучше набросать псевдокод, показывающий это изменение, и представить его своим коллегам (или, по крайней мере, тому, кто имеет роль, ближайшую к архитектору), и посмотреть, что они думают, прежде чем что-либо делать. На самом деле, вы пошли на изгой, подумали, что вся кодовая база - ваша, чтобы играть с ней так, как вы считаете нужным. Игрок в команде, а не командный игрок!
Я могу быть немного резок с тобой, но я был в противоположном месте: посмотри какой-нибудь код и подумай «WTF здесь случился ?!», только чтобы найти нового парня (его почти всегда новый парень), решившего измениться. множество вещей, основанных на том, что он считает «правильным путем». Винты с историей SCM тоже, что является еще одной серьезной проблемой.
источник
Как описано выше, я не вижу, что делает код требует установки. Я, вероятно, недостаточно разбираюсь в сценарии использования, но почему бы не подождать, пока все параметры станут известны, прежде чем создавать экземпляр объекта?
В качестве альтернативы, если в ситуации требуются установщики: предложите способ заморозить ваш код, чтобы установщики выдавали ошибку утверждения (она же ошибка программиста), если вы пытаетесь изменить поля после того, как объект будет готов.
Я думаю, что удаление сеттеров и использование final - это «правильный» способ сделать это, а также обеспечить неизменность, но действительно ли это то, с чем вам следует проводить время?
Общие советы
Старый = плохой, новый = хороший, по-моему, по-вашему ... обсуждение такого рода не конструктивно.
В настоящее время способ использования вашего объекта соответствует неявному правилу. Это часть неписаной спецификации вашего кода, и ваша команда может подумать, что другие части кода не сильно рискуют его использовать. Здесь вы хотите сделать правило более явным с помощью проверок Builder и времени компиляции.
В некотором смысле рефакторинг кода связан с теорией « разбитого окна» : вы считаете правильным исправить любую проблему так, как вы ее видите (или сделать заметку для некоторого более позднего совещания по «улучшению качества»), так что код всегда выглядит приятным для работы, безопасно и чисто. Однако вы и ваша команда не имеете единого представления о том, что является «достаточно хорошим». То, что вы видите как возможность внести свой вклад и сделать код лучше и добросовестно, вероятно, отличается от существующей команды.
Между прочим, нельзя полагать, что ваша команда обязательно страдает от инертности, вредных привычек, недостатка образования ... худшее, что вы можете сделать, - это проецировать образ всезнающего, который там, чтобы показать им как кодировать Например, неизменность не является чем-то новым , ваши коллеги, вероятно, читали об этом, но только потому, что эта тема становится популярной в блогах, недостаточно, чтобы убедить их потратить время на изменение своего кода.
В конце концов, есть бесконечные способы улучшить существующую кодовую базу, но это стоит времени и денег. Я мог бы взглянуть на твой код, назвать его «старым» и найти вещи, которые надо придираться. Например: нет формальной спецификации, недостаточно утверждений, может быть, недостаточно комментариев или тестов, недостаточно покрытия кода, неоптимальный алгоритм, слишком много использования памяти, отсутствие использования «наилучшего» возможного шаблона проектирования в каждом случае и т. Д. До тошноты . Но в большинстве случаев, которые я хотел бы поднять, вы могли бы подумать: все в порядке, мой код работает, нет необходимости тратить на него больше времени.
Может быть, ваша команда думает, что то, что вы предлагаете, прошло через границу убывающей отдачи. Даже если вы нашли фактический экземпляр ошибки из-за того примера, который вы показываете (за исключением), они, вероятно, просто исправят его один раз и не захотят рефакторинга кода.
Итак, вопрос в том, как тратить свое время и силы, учитывая, что они ограничены ? В программное обеспечение вносятся постоянные изменения, но, как правило, ваша идея начинается с отрицательной оценки, пока вы не предоставите ей веские аргументы. Даже если вы правы в отношении выгоды, она сама по себе не является достаточным аргументом, поскольку она попадет в корзину « Хорошо иметь один день ... ».
Когда вы представляете свои аргументы, вы должны сделать некоторые проверки «здравомыслия»: вы пытаетесь продать идею или себя? Что если кто-то еще подарит это команде? Вы найдете некоторые недостатки в их рассуждениях? Вы пытаетесь применить некоторые общие рекомендации или вы приняли во внимание специфику вашего кода?
Тогда вы должны быть уверены, что не будете выглядеть так, как будто вы пытаетесь исправить прошлые «ошибки» своей команды. Это помогает показать, что вы не ваша идея, но можете разумно воспринимать обратную связь. Чем больше вы делаете это, тем больше у ваших предложений будет возможность следовать.
источник
Вы не
Если ваш конструктор имеет 3 строки параметров, он слишком большой и слишком сложный. Никакой шаблон дизайна не исправит это.
Если у вас есть класс, данные которого поступают в разное время, это должны быть два разных объекта, или ваш потребитель должен объединить компоненты и затем создать объект. Им не нужен строитель, чтобы сделать это.
источник
String
s и других примитивов. Там нигде нет логики, даже проверкаnull
s и т. Д. Так что это просто размер, а не сложность как таковая. Я думал, что делать что-то вродеbuilder.addA(a).addB(b); /*...*/ return builder.addC(c).build();
этого будет намного проще для глаз.Вы, кажется, больше сосредоточены на том, чтобы быть правым, чем на хорошей работе с другими. Хуже того, вы понимаете, что то, что вы делаете, это борьба за власть, и все же не можете обдумать, что, вероятно, будут чувствовать люди, чей опыт и авторитет вы бросаете вызов.
Переверните это.
Сосредоточьтесь на работе с другими. Обрамляйте свои мысли как предложения и идеи. Пусть они обсудят свои идеи, прежде чем задавать вопросы, чтобы они подумали о ваших. Избегайте прямых конфронтаций и внешне желайте признать, что продолжать делать что-то групповым способом (на данный момент) более продуктивно, чем вести тяжелую борьбу за изменение группы. (Хотя верните вещи обратно.) Сделайте работу с вами радостью.
Делайте это последовательно, и вы должны создавать меньше конфликтов, и найти больше своих идей, принятых другими. Мы все страдаем от иллюзии, что идеальный логический аргумент потрясет других и победит. И если это не сработает, мы думаем, что должно .
Но это находится в прямом противоречии с реальностью. Большинство аргументов теряются до того, как было сделано первое логическое замечание. Даже среди якобы логичных людей психология превосходит разум. Убеждать людей в том, чтобы преодолеть психологические барьеры на пути к тому, чтобы их правильно услышали, а не в том, чтобы иметь совершенную логику
источник
Frame your thoughts as suggestions and ideas. Get THEM to talk through THEIR ideas before asking questions to make them think about yours
+1 за это тем не менее«Когда у тебя новый молот, все будет выглядеть как гвоздь». - это то, что я подумал, когда прочитал твой вопрос.
Если бы я был вашим коллегой, я бы спросил вас: «Почему бы не инициализировать весь объект в конструкторе?» Это то, что это его функциональность в конце концов. Зачем использовать шаблон конструктора (или любой другой дизайн)?
Трудно сказать по этому небольшому фрагменту кода. Возможно, это так - вы и ваши коллеги должны оценить это.
Да, узнайте больше о теме, прежде чем обсуждать ее. Вооружитесь хорошими аргументами и обоснованиями, прежде чем вступать в дискуссию.
источник
Я был в ситуации, когда меня завербовали за мои навыки. Когда я просмотрел код, ну ... это было более чем ужасно. Когда кто-то пытался его почистить, он всегда подавляет изменения, потому что не видит преимуществ. Это звучит как то, что вы описываете. Это закончилось тем, что я ушел с этой должности, и теперь я могу развиваться намного лучше в компании, которая имеет лучшую практику.
Я не думаю, что вы должны просто играть роль вместе с другими в команде, потому что они были там дольше. Если вы видите, что члены вашей команды используют плохие практики в проектах, в которых вы работаете, то вы должны указать на это imo, как и вы. Если нет, то вы не очень ценный ресурс. Если вы все время повторяете, но никто не слушает, попросите руководство заменить или сменить работу. Очень важно, чтобы вы не позволяли себе адаптироваться к таким плохим практикам.
К актуальному вопросу
Зачем использовать неизменяемые объекты? Потому что ты знаешь, с чем имеешь дело.
Скажем, у вас есть соединение db, которое позволяет вам менять хост через установщик, тогда вы не знаете, какое это соединение. Будучи неизменным, тогда вы знаете.
Скажем, однако, что у вас есть структура данных, которую можно извлечь из постоянства и затем повторно сохранить с новыми данными, тогда имеет смысл, что эта структура не является неизменной. Это та же сущность, но значения могут измениться. Вместо этого используйте неизменные значения объектов в качестве аргументов.
Однако вопрос, на котором вы сосредоточиваете внимание, - это шаблон конструктора, позволяющий избавиться от зависимостей в конструкторе. Я говорю большой жирный НЕТ на это. Пример, очевидно, уже сложный. Не пытайтесь скрыть это, исправить это!
Tl; др
Удаление сеттеров может быть правильным, в зависимости от класса. Шаблон строителя не решает проблему, а просто скрывает ее. (Грязь под ковром все еще существует, даже если вы ее не видите)
источник
Хотя все остальные ответы очень полезны (более полезны, чем мой), есть свойство строителей, о котором вы еще не упомянули: превращая создание объекта в процесс, вы можете применять сложные логические ограничения.
Например, вы можете назначить определенные поля вместе или в определенном порядке. Вы даже можете вернуть другую реализацию целевого объекта в зависимости от этих решений.
Это простой пример, который не имеет особого смысла, но демонстрирует все три свойства: символ всегда устанавливается первым, пределы диапазона всегда устанавливаются и проверяются вместе, и вы выбираете свою реализацию во время сборки.
Легко увидеть, как это может привести к более читабельному и надежному пользовательскому коду, но, как вы также можете видеть, есть и обратная сторона: много-много кода компоновщика (и я даже оставил конструкторы для сокращения фрагментов). Таким образом, вы пытаетесь рассчитать компромисс, задав такие вопросы, как:
Ваши коллеги просто решили, что компромисс не будет полезным. Вы должны обсуждать причины открыто и честно, желательно не прибегая к абстрактным принципам, но концентрируясь на практических последствиях того или иного решения.
источник
Похоже, этот класс на самом деле является более чем одним классом, собранным в одном определении файла / класса. Если это DTO, то должна быть возможность создать его за один раз и сделать его неизменным. Если вы не используете все его поля / свойства в какой-либо одной транзакции, то это почти наверняка нарушает принцип единой ответственности. Может быть, это поможет разбить его на более мелкие, более сплоченные, неизменные классы DTO. Подумайте о том, чтобы прочитать « Чистый код», если вы этого еще не сделали, поэтому вы сможете лучше сформулировать проблемы и преимущества внесения изменений.
Я не думаю, что вы можете разрабатывать код на этом уровне по комитетам, если вы не буквально моб-программист (это не похоже на то, что вы в такой команде), поэтому я думаю, что можно вносить изменения, основываясь на вашем лучшее суждение, а затем возьмите его на подбородок, если окажется, что вы ошиблись.
Однако до тех пор, пока вы можете сформулировать потенциальные проблемы с кодом, как он есть, вы все равно можете спорить о том, что решение необходимо , даже если ваше не является принятым. Люди могут свободно предлагать альтернативы.
« Сильные мнения, слабые убеждения » - это хороший принцип - вы идете вперед с уверенностью, основываясь на том, что вы знаете, но если вы найдете какую-то новую информацию, которая противостоит ей, будьте скромны и уйдите в отставку и вступите в дискуссию о том, какое правильное решение должно быть быть. Единственный неправильный ответ - оставить все хуже.
источник