Антипаттерны, которых следует избегать в коде
Источник:
Free Code Camp
Каждый разработчик стремится писать структурированный, хорошо спланированный код с хорошими комментариями. Существует множество шаблонов проектирования с четкими правилами, которым нужно следовать, и структурой о которой нужно помнить.
Тем не менее, мы все еще можем найти в софте антипаттерны. Особенно часто они встречаются программах, написанных давно или в спешке.
Безобидный базовый прием, добавленный ради быстрого решения проблемы, может создать прецедент в вашей кодовой базе. Со временем его могут скопировать в несколько разных мест, что превратит этот прием в антипаттерн, с которым придется разбираться.
Что же такое антипаттерн?
В программном обеспечении антипаттерн (антишаблон) — это термин, обозначающий приемы, которые НЕ нужно применять при решении задач. Антипаттерны считаются плохим дизайном программного обеспечения. Они неэффективны и вносят путаницу в программу. Как правило, это код, к которому нужно вернуться позже и переделать, то есть по сути это технический долг.
Существует шесть антипаттернов: спагетти-код, золотой молоток, лодочный якорь, мертвый код, разрастание кода и божественный объект.
Спагетти-код
Спагетти-код — самый известный антипаттерн. Это код с практически нулевой структурой. В нем ничего не модулируется. Файлы случайным образом разбросаны по случайным каталогам. Ход программы трудно проследить, он полностью переплетен как спагетти.
Обычно такая проблема возникает, когда кто-то не продумал ход своей программы заранее и просто сразу начал писать код.
Спагетти-код — это не только кошмар в плане обслуживания. Он также практически не позволяет добавлять новый функционал.
У вас постоянно будет что-то ломаться. При внесении изменений вы никогда не сможете точно сказать, какие части кодовой базы это изменение затронет. Из-за этого вы не сможете точно прогнозировать время работы, поскольку в таком коде невозможно предвидеть появление бесчисленных проблем.
Дополнительно почитать о спагетти-коде можно
здесь.
Золотой молот
Представьте себе такой сценарий: ваша команда разработчиков очень хорошо разбирается в новой архитектуре Hammer. Она фантастически подходила для всех ваших прошлых задач. Вы — лучшая в мире команда специалистов по архитектуре Hammer.
Но теперь почему-то всегда все задачи заканчиваются использованием этой архитектуры. Винт с плоской головкой? Молоток. Винт с крестообразным шлицем? Молоток. Что? Вам нужен шестигранный ключ? Нет, просто бейте молотком!
Так вы начинаете везде применять знакомый и любимый архитектурный подход. Да, он не для всех случаев является оптимальным решением, но с задачей ведь он справляется! Хотя с помощью молотка вы будете писать код вдвое дольше, а программа в итоге станет менее производительной, но лично вам молоток удобен, потому проще взять его.
Проблема здесь в том, что золотой молот далеко не всегда может быть универсальным решением. У разных языков есть и общие подходы к решению задач, и свои собственные стандарты. И если вы успешно что-то применили, работая с одним языком, это не значит, что все так же хорошо обернется в работе с другим.
Не пренебрегайте постоянной учебой на протяжении всей своей карьеры. Для каждого проекта выбирайте наиболее подходящий язык. Продумывайте архитектуру и выходите за рамки обыденного. Исследуйте и пробуйте в работе новые инструменты и новые способы решения проблем.
О золотом молоте можно почитать
здесь.
Лодочный якорь
Антипаттерн «лодочный якорь» предполагает, что программисты оставляют неиспользуемый код в базе, потому что он может понадобиться им позже.
Например, разработчики написали что-то немного не по спецификации, и этот код пока не нужен, но они уверены, что в следующем месяце он им пригодится. Поэтому разработчики этот код не удаляют. Код отправляется в производство, чтобы позже, когда он понадобится, его можно было быстро использовать.
Но в итоге кодовая база переполняется лишним кодом, а обслуживание этой базы превращается в настоящую проблему.
Представьте, что вам срочно нужно внести некоторые правки. Вы отчаянно пытаетесь выяснить, какая именно часть кода отвечает за отправку данных карт клиентов в API для вывода средств из банка. В такой ситуации вы запросто можете потерять зря время, вычитывая и исправляя лишний код, не осознавая при этом, что находитесь даже не в том месте кодовой базы.
Лишний или устаревший код увеличивает время сборки, а вы можете перепутать рабочий и нерабочий код, нечаянно добавив последний в производство.
Теперь вы, вероятно, понимаете, почему этот антипаттерн называется лодочным якорем: его тяжело нести (он увеличивает технический долг) и при этом он ничего не делает (код совершенно бесполезен, он не работает).
Об антипаттерне «лодочный якорь» можно почитать
здесь.
Мертвый код
Приходилось ли вам когда-нибудь видеть код, написанный кем-то, кто больше не работает в вашей компании? Например, есть функция, которая вроде бы ничего не делает. Но она вызывается отовсюду! Вы спрашиваете об этой функции у всех, но никто не знает, что она делает и поэтому ее боятся удалять.
Иногда вы видите, что делает тот или иной кусок кода, но не знаете контекста. По сути, вы можете прочесть и понять этот код, но не понимаете, зачем он здесь.
Такой код обычно называют мертвым. Чаще всего этот антипаттерн встречается в коде, который написали для проверки концепции, а затем запустили в производство. Этот код вреден, потому что нельзя определить, нужен ли он для работы программы, или нет.
Однажды на одном из митапов я встретил парня, у которого была именно такая проблема. В его проекте были тонны точно мертвого кода и большое количество возможно мертвого, но руководство не разрешало удалять весь мертвый код.
Этот парень назвал свой подход «обезьяньим тестированием». С помощью комментариев он начал выключать все поочередно, чтобы увидеть, что сломается в производстве. Да, это было немного рискованно!
Если вы не хотите применять “обезьянье тестирование” в своей работе, попробуйте убедить руководство, что технический долг — это риск, и именно поэтому его нужно привести в порядок.
В качестве альтернативы запишите все, что делает модуль (раздел), который вы хотите переписать, и начинайте удалять мертвый код по частям, применяя итеративный подход. При каждой итерации проверяйте, не сломалось ли что-нибудь. Так вы поймете, какая часть кода важна, а затем удалите неработающие части.
О мертвом коде можно почитать
здесь.
Разрастание кода
Объекты или модули регулярно взаимодействуют друг с другом. Если у вас есть чистая модульная кодовая база, вам часто придется вызывать отдельные модули и новые функции.
Антипаттерн «разрастание кода» предполагает наличие в кодовой базе объектов, которые существуют исключительно для вызова других, более важных объектов. Их можно назвать «объекты-посредники».
Наличие таких объектов добавляет ненужный уровень абстракции и лишь сбивает с толку, когда необходимо разобраться в работе программы.
Лучшее решение — просто удалить лишний объект. Переместите ответственность за вызов необходимого объекта на вызывающий объект.
О разрастании кода можно почитать
здесь.
Божественный объект
Если в вашей кодовой базе всегда требуется доступ к одному объекту, то этот объект вполне может быть «божественным».
Божественные объекты делают слишком много. Например, они могут одновременно отвечать за идентификатор пользователя, идентификатор транзакции, имя и фамилию клиента, общую сумму транзакции, товары, которые покупает пользователь… Короче, вы поняли.
Такой антипаттерн иногда называют «швейцарским ножом», потому что фактически он вам нужен только для того, чтобы отрезать кусок веревки, но при этом в нем есть пилочка для ногтей, пила, пара пинцетов, ножницы, открывалка для бутылок и штопор.
Если у вас есть такой божественный объект, лучше разделить его на отдельные модули.
В объектно-ориентированных языках проблеме божественных объектов уделяется особое внимание. Чтобы не допускать их появления, нужно следовать принципам SOLID, которые помогают нам лучше моделировать программное обеспечение. Буква S в аббревиатуре SOLID означает Single Responsibility — каждый класс или модуль отвечает за одну часть системы, а не за несколько.
Проблему «божественного объекта» вы можете увидеть на следующем примере:
interface Animal {
numOfLegs: string;
weight: number;
engine: string;
model: string;
sound: string;
claws: boolean;
wingspan: string;
customerId: string;
}
Можете ли вы, быстро просмотрев этот код, определить, что зона ответственности здесь слишком широка и требуется рефакторинг? Тут мы явно наблюдаем создание потенциального божественного объекта.
Как насчет такого изменения?
interface Animal {
numOfLegs: string;
weight: number;
sound: string;
claws: boolean;
}
interface Car {
engine: string;
model: string;
}
interface Bird {
wingspan: string;
}
interface Transaction {
customerId: string;
}
Разделение интерфейсов позволит разработчику ясно увидеть зону ответственности каждого из них. Кроме того, классам, которым нужен только wingspan, не придется реализовать также engine, customerId и model.
О божественных объектах можно почитать
здесь.
Заключение
В любой крупной кодовой базе всегда должен поддерживаться баланс между управлением техническим долгом, разработкой нового функционала и исправлением ошибок.
Я надеюсь, эта статья помогла начинающим разработчикам понять, к чему может привести применение антипаттернов, а также научила некоторым способам исправления подобных ошибок.
Как научиться решать задачи на техническом интервью
Источник:
Codeburst
«У вас есть монеты разного номинала. Также вы знаете общую сумму денег. Напишите программу для вычисления наименьшего количества монет, необходимого, чтобы составить эту сумму».
Какой код нужно написать для решения
этой задачи? С чего бы вы вообще начали? Google, Amazon и все крупные компании, занимающиеся разработкой программного обеспечения, почти всегда используют нечто подобное при найме новых сотрудников.
Не бойтесь, если вы не знаете ответ. Я до сих пор его не знаю, как и 63% всех программистов, которые брались за эту задачу. Что вам действительно нужно для того, чтобы занять позицию разработчика, так это
основа, принцип решения таких задач, а также навыки, которые позволят решить ту задачу, которую вам предложат на техническом собеседовании.
Полгода назад я устроился на свою первую работу в качестве full-stack веб-разработчика в компании из списка Fortune 500. В процессе подготовки к собеседованиям я познакомился со множеством задач подобного типа и потратил бесчисленные часы на их решение. В этой статье я попытался изложить пять рекомендаций на основе личного опыта. Надеюсь, они помогут вам более успешно решать задачи по программированию на техническом собеседовании.
1. Используйте таймер или секундомер
Подумайте, сколько времени вы хотите выделить себе на решение одной задачи, и придерживайтесь этого плана. Вы можете решить задачу быстрее, а можете и не решить ее вообще —
в любом случае, это не важно. Как только время истечет, прекращайте работать над задачей, которую решали, и переходите к следующей. Я серьезно.
Ваша цель — это получение зеленой галочки или золотой звездочки.
Оставьте эту ерунду «сдал / не сдал» для начальной школы, где ей самое место. Вместо этого вашей целью должно быть получение знаний. Как они приобретаются? Путем неудач и адаптации. Снова и снова. Для этого вам нужно познакомиться со множеством различных задач. Причем
быстро.
Когда я начинал решать задачи по программированию, я тратил от 45 минут до часа на каждую и «проваливал» почти все. Теперь на каждую задачу я трачу не больше 20 минут и решаю 50–75% в зависимости от сложности. Но забудьте обо мне: подумайте о собственном таймере и установите его так, как вам удобно. Со временем вы обнаружите, что начали решать задачи на несколько минут быстрее запланированного.
2. Ежедневно ставьте перед собой цели
Это поможет вам сосредоточиться и избавиться от некоторых отвлекающих факторов. Конечно, звучит это просто, ведь поставить цель способен каждый. Куда сложнее достигать намеченных целей день за днем. Здесь важно оставаться последовательным. Одна ежедневная цель, которую вы достигаете каждый день, намного лучше, чем достичь пять целей в понедельник и не выполнить ни одной во вторник.
«Сложные проценты — восьмое чудо света. Тот, кто в них разбирается — зарабатывает, а кто не разбирается — платит», — Альберт Эйнштейн.
В этой цитате Эйнштейн имел в виду известное правило: «деньги делают деньги». Если вы со временем примените ту же идею к своему росту
знаний, вас будет просто не остановить.
Есть еще одна вещь, которая может оказаться вам полезной. Я заметил, что отлично выполняю чужие инструкции и ужасно выполняю свои собственные. К счастью, я нашел способ обойти это. Если у вас такая же проблема, запишите вечером свои цели на завтра. Положите их на стол и забудьте о них. Утром вы проснетесь с ясной головой, встанете и заметите на столе список задач от очень умного и организованного незнакомца.
Еще один полезный совет:
ставьте перед собой небольшое количество легко достижимых целей. Мотивация — ключ к успеху, а у вас гораздо больше шансов решить три задачи, если вы планировали решить две, чем если нацеливались на 30.
3. Придерживайтесь определенной системы
Когда я решал ежедневные задачи по программированию, я по каждой писал заметки. При следующем поиске работы
моей целью будет заполнить еще одну записную книжку. Я делюсь этим с вами по двум причинам. Во-первых, потому что на своих курсах научился очень простой системе ведения заметок, которая называется «UPER»:
- • Understand (понять)
- • Plan (спланировать)
- • Execute (выполнить)
- • Review (проверить)
Первые два шага должны быть выполнены еще до того, как вы напишете какой-либо код. Чтобы добиться чего-либо, вы должны спланировать, как вы это сделаете. Но перед этим вам нужно убедиться, что вы понимаете, чего от вас хотят.
Например, какой тип ввода получит ваша функция? Что будет на выходе — строка или, может быть, число с плавающей запятой? Вам не хватает важной информации? Выполните каждый этап своего плана, определив переменные и написав свои функции. Затем, наконец, проверьте результат: что вы сделали хорошо, что можно улучшить и в чем вы не были уверены.
Я искренне убежден, что задачи по программированию — один из лучших способов улучшить ваши навыки. Да, они отнимают много времени, и вам не нужно быть такими одержимым по поводу их решения, но эти
ежедневные упражнения позволят вам подняться на новый уровень. Вы многое узнаете о своем языке программирования и нарастите свои «аналитические мускулы». А когда придет время ежедневно писать код на работе,
эти мускулы вам очень пригодятся.
4. Регулярно отдыхайте
Врачи подтверждают, что наш мозг больше склонен к творчеству, когда мы делаем частые перерывы. Свежий воздух и физические упражнения полезны не только для здоровья. Когда вы застряли на решении какой-то проблемы, смещение внимания на что-то новое может быть наилучшим способом продвинуться вперед. Внезапная вспышка творческого озарения может появиться откуда угодно. Особенно часто такие вспышки случаются, когда вы вышли на улицу подышать свежим воздухом.
5. Учитесь у других
При овладении новых навыков в малознакомой для вас сфере деятельности наибольшая сложность заключается в том, что
вы многого чего не знаете. Самостоятельно это определить тяжело, потому что, не зная контекста, вы попросту не можете предположить, откуда начать.
Вы не знаете, что важно, а что нет. Концепции функционального программирования? Структуры данных?
Когда я решаю задачи, я всегда заглядываю в чужие решения, даже если сам решил задачу правильно. И обязательно делаю пометки. Тот факт, что вы решили задачу, не означает, что исчерпали возможность стать лучше. Ведь вполне может существовать более элегантный способ решения той же задачи. Например, с меньшим количеством строк кода. Возможно, вы могли бы написать более эффективный алгоритм.
Чтение чужих решений укладывается в пункт «проверка» системы UPER. Обращайте внимание, как пишут код другие люди, и вы удивитесь, как много нового узнаете о своей работе.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ