Как понять, что перед вами плохой разработчик
Стоит отметить, что «плохой» — слишком сильное и недостаточно точное слово, давайте использовать категории «слабый» и «сильный», подразумевая, что речь идет про способность человека качественно решать правильно поставленные задачи. Конечно, критерии качества тоже относительны, но все, кому приходилось работать с чужим кодом, наверняка понимают, что при одинаковом результате он может быть как удобным, понятным и эффективным, так и запутанным и неочевидным. Тех, кто пишет нечто ближе к первому (при условии правильности решения, разумеется), традиционно считают более сильными разработчиками, чем тех, кто грешит вторым.
Человеческая природа такова, что в процессе становления, как личного, так и профессионального, большая часть людей набивает одни и те же шишки, становится жертвой одних и тех же заблуждений и проявляет себя одинаковым образом в одинаковых ситуациях. Путь инженерного мышления — не исключение, и есть общие признаки, которые позволяют понять, что в работе с программистом будут проблемы, еще даже не читая его код.
В этой статье мы разберем признаки слабых разработчиков, которые можно обнаружить на собеседовании, в ходе совместной работы или даже в процессе неформального разговора в курилке. Важное уточнение — все описанное в нашей статье не стоит рассматривать как чек-лист формальных правил. Это скорее некоторые закономерности, каждая из которых не является гарантией того, что перед вами — «плохой» разработчик. Но, если в одном человеке сочетаются несколько из них, то вероятность этого сильно увеличивается.
Злоупотребление жаргонизмами и buzzwords
Некоторые разработчики в общении (или в резюме) часто используют профессиональные термины. Особенно внимательным стоит быть к людям, которые изменяют их морфологию, используя уменьшительно-ласкательные формы, вплоть до превращения их в эвфемизмы — «багуля», «тэзэшка», «аппликуха», «батончик».
Велика вероятность, что таким образом человек пытается впечатлить слушателя, замаскировать неуверенность в себе, или скрыть отсутствие опыта и реальных знаний. То же самое относится к buzzwords — к «гламурной лексике», словам, которыми умышленно пытаются произвести ложное ощущение, а не передавать информацию. Например, «эксклюзивность» или «элитный» — слова, которые используются, чтобы произвести впечатление и апеллировать к эмоциям, а не передать информацию и апеллировать к разуму.
В этот же пункт входит слишком частое употребление новояза — особенно часто это встречается у людей, которые много работали в энтерпрайзах и часто общались с менеджерами, или в стартапах, где нужно регулярно выбивать инвестиции, создавая постоянную видимость прогресса. Такую манеру общения иногда называют «технотрёп» (“technobabble”), а в англоязычной культуре есть более общий (сугубо разговорный) термин “bullshitting”.
Вспомните свои университетские годы, когда некоторые студенты не готовятся к сессии, а во время экзамена пытаются налить преподавателю воды и создать видимость того, что они что-то понимают. С возрастом и опытом этот процесс становится менее очевидным, потому что слов по теме разработчик, даже «слабый», понахватается в больших количествах из общения с другими разработчиками и обучающих материалов. Некоторые разработчики доводят этот навык до уровня искусства, и нередко им удается обмануть собеседника, создав у него ложное впечатление владения предметом.
Если вы замечаете за разработчиком такую линию поведения, задавайте ему уточняющие вопросы в глубину и в ширину. Ирония тут в том, что даже если вы сами в этой теме не эксперт, поймать на на вранье такого «специалиста» будет достаточно просто. Поэтому разработчик, который может просто и без затей ответить на вопрос «я не знаю», уже немалого стоит, и такого точно не стоит списывать со счетов. А вот программист, который будет изображать осведомленность, жонглируя техническими жаргонизмами — однозначно «слабый».
Перфекционизм и идеализм
Среди разработчиков часто встречаются люди, которые имеют давно сформировавшееся мнение по многим вещам, и практически не меняют его. При этом часто никаких практических аргументов, которые бы подтверждали такое мнение, у них нет — как и релевантного опыта, то есть человек просто может уверенно повторять то, что где-то когда-то услышал. Например:
— Фреймворк или язык X лучше фреймворка или языка Y;
— Фреймворк или язык Z — вообще гадость;
— Задачи такого рода нужно всегда решать именно так;
— Надо делать так-то, потому что так сказал такой-то;
— Если в компании используют X, в этой компании не надо работать;
— Если в компании не используют X, в этой компании не надо работать;
— Бесплатные решения лучше платных;
— 100% кода должны быть покрыты тестами, иначе это плохой код;
— Тесты нужны только плохим разработчикам, хорошие могут работать и без них;
— Тернарные операторы это плохо;
— Мутабельные данные это неправильно;
— Однобуквенные названия переменных — это гадость.
Каждый подобный тезис может быть справедлив в ряде случаев — проблема в том, что человек возводит этот тезис в абсолют. Кроме того, сильная убежденность сопутствует некой эмоциональной привязанности к ней — это можно заметить по использованию субъективных эмоциональных оценок, таких как «хорошо/плохо» при обсуждении, даже сугубо теоретическом, решений и концепций программирования. Таким образом, рабочий вопрос может стать для человека личным, и этот человек будет весьма болезненно реагировать на критику и вносить очень нездоровую атмосферу в коллектив.
При этом такой разработчик может даже писать неплохой код, но едва ли с таким подходом он сможет подружить свои интересы с интересами команды и бизнеса. Люди такого склада характера не склонны искать компромиссы, и это неизбежно будет мешать эффективному решению задач. Помимо этого, такого разработчика крайне трудно вырастить до сеньора, поскольку одним из ключевых атрибутов высокого уровня является способность сравнивать, анализировать разные варианты и выбирать наиболее подходящие в конкретном случае по объективным причинам, а не по личным симпатиям.
Что же касается перфекционизма, тут все достаточно прозаично: как известно, лучшее — враг хорошего. Вряд ли можно назвать конструктивным для разработчика и для команды, если он тратит лишние часы на то, чтобы решить, какой цвет тени будет смотреться лучше — #444444 или #3e3e3e, или на переименование всех переменных и функций так, чтобы фрагмент кода был максимально приближен к грамматически корректному тексту.
Переусложнение или оверинженеринг
Классическая проблема новичков, которая может сохраниться с разработчиком на многие годы. Рано или поздно оверинженеринг станет проблемой — и не только для самого разработчика, но и для его коллег. Речь идет про систематическое привнесение избыточной сложности в решения как на микро-, так и на макроуровне. Достаточно сложно привести примеры этой проблемы, но можно выделить некоторые типовые случаи:
Желание учесть абсолютно все пограничные случаи работы приложения, независимо от их вероятности и степени рисков, которые они несут.
При разработке сервиса бронирования (ресторана, отеля, медицинских услуг) такой разработчик может потратить лишние часы или дни на особую обработку случаев, когда база данных пустая, когда объект бронирования меняет свой ID, когда два запроса от разных пользователей конкурируют за общий слот, и так далее. Важно, что это может быть неплохая идея сама по себе, но отличие в том, что «сильный» разработчик поинтересуется у менеджера или заказчика, насколько это важно делать прямо сейчас, и реальна ли вообще проблема, прежде чем ее решать. Тогда как «слабый» программист, склонный к переусложнению, потратит на это время при любом раскладе, ни с кем не посоветовавшись.
Трата ресурсов и времени на разные аспекты задачи непропорционально их фактической значимости.
Например, разработчик написал для своего сервиса невероятно продвинутую систему логирования из 30 файлов и с 5-ю различными слоями абстракции. В то время, как вся бизнес-логика этого сервиса умещается в сотню строк, и задачу можно было бы решить за считанные часы — тогда как заняло это несколько дней. Такая система может принести огромную пользу при некоторых обстоятельствах, но нужна ли она на данном этапе, и наступят ли вообще такие обстоятельства — «слабый» разработчик не задается такими вопросами.
Инновации ради инноваций.
Разработчик, решая задачу, которая уже неоднократно решена в проекте, подключает для этого стороннюю библиотеку, потому что она решает эту задачу лучше (как ему кажется), или ему просто хочется ее попробовать. Это не только неоправданная трата времени на изучение вопросов интеграции, освоение нового инструментария и повторной реализации решения. Это и создание в проекте избыточной сложности и точки отказа из-за появления новых зависимостей, новой семантики и вероятного отсутствия у других членов команды знаний по этому компоненту. Такие процессы бывают нужны и полезны для проекта, но проводятся они, в случае «сильных» разработчиков, для решения конкретных, известных и локализованных проблем. И делается это централизованно и планово, чтобы все участники процесса могли погрузиться в эту инновацию плавно и одновременно.
Сюда же можно отнести и преждевременную оптимизацию, которую Дональд Кнут назвал корнем всех зол в программировании. И самостоятельное привнесение в продукт фичей, которые никто не заказывал, и еще много чего, что довольно точно сформулировал автор блога «Code Simplicity» и одноименной книги:
Самому разработчику заниматься оверинженерингом — сплошное удовольствие: таким образом он изучает новые технологии, увеличивает глубину экспертизы и искренне вовлекается в процесс. При этом для команды и проекта это идет во вред — увеличиваются сроки доставки и стоимость реализации задач, а в репозитории становится больше кода и больше зависимостей, которыми нужно управлять, а вместе с этим копится и технический долг.
Требуется некоторый опыт, чтобы понять, что больше кода значит больше багов, и что краткость — действительно, сестра таланта. На этот счет есть расхожая и абсолютно верная фраза: «The best code is no code», — то есть самый лучший код — это его отсутствие. Если разработчик может решить задачу компактно и элегантно — может быть и вовсе без изменения кодовой базы, а большие и сложные задачи декомпозировать до компактных и элегантных — это верный индикатор того, что перед вами очень «сильный» разработчик.
Важно уточнить, что далеко не все непринципиальные для решения задачи дополнительные работы над кодом можно считать переусложнением. Рефакторинг и форматирование кода для соответствия принятым в команде стандартам, обогащение его комментариями, тестами, выделение дополнительных абстракций для снижения связности — это полезные действия, хоть и необязательные, которые целесообразно совершить при решении задачи, тут важен именно баланс.
Также важно качество самих решений: одно дело написать лишнего, но полноценно решить задачу, и совсем другое — просто написать лишнего. Кроме того, надо учитывать контекст: например, при разработке программного обеспечения для авиации, космических летательных аппаратов, медицинского оборудования существует жесткий регламент, который требует обработки всех возможных, даже самых невероятных условий. Плюс требуется максимальное покрытие тестами с самых ранних этапов, создание дублирующих механизмов для наиболее критичных участков, в то время как в типовом коммерческом проекте это все будет плохой практикой.
Самоуверенность и «велосипедизм»
Еще одна достаточно типовая проблема, сопутствующая многим разработчикам в начале их карьерного пути — в популярной литературе она называется термином «эффект Даннинга-Крюгера», и касается не только программистов.
Излишняя самоуверенность может быть логичным следствием ограниченности знаний и маркером «слабых» разработчиков. У программистов она проявляется как стремление для любой типичной задачи сделать свое решение — нередко еще и переусложнив его, вместо того, чтобы использовать существующие решения.
Часто это еще называют «изобретением велосипеда», и такой подход может иметь и куда более обширные и далеко идущие последствия. Например, такой разработчик бросается делать задачу, до конца не вникнув в требования — ему «и так все понятно». При этом он не задает никаких уточняющих вопросов, поэтому в итоге выдает результат, совершенно не соответствующий ожиданиям. При этом когда ему руководители указывают на ошибки, он может впасть во фрустрацию и еще сильнее снизить свою производительность.
Вообще, привычка задавать уточняющие вопросы — исключительно положительная, и ее наличие у разработчика добавляет ему очков в пользу «сильного». Нередко на собеседованиях программистам дают ситуационные или технические задачи с заведомо неполным условием, чтобы проверить именно эту способность кандидата.
Главное отличие самоуверенности от уверенности в себе разработчика в том, что уверенный в себе программист осознает границы своих знаний и не стесняется спрашивать более опытных коллег, советоваться и собирать мнения, валидировать гипотезы и проводить работу над собой.
Самоуверенному же разработчику, даже при наличии хороших задатков, предстоит пройти немалый путь, прежде чем он сможет избавиться от иллюзий о себе и своих способностях. И очень часто это является одним из главных препятствий на пути к тому, чтобы он смог реализовать свой потенциал.
Туннельное зрение
Мы используем термин «туннельное зрение» в переносном смысле — это когнитивное искажение, которое проявляется в человеке как безусловная приверженность выбранной позиции по какому-либо вопросу, которую он не подвергает попыткам критического осмысления.
В случае с разработчиками речь обычно идет о предпочтениях в выборе технологий, паттернов, каких-либо стилевых особенностей в написании кода и иных инженерных решений, которые обычно выбираются под конкретную задачу на основании некоторых аргументов, фактов и метрик. В некотором роде, это еще одна грань уже упомянутого идеализма, но важное отличие в том, что эта привычка основана именно на предшествующем опыте и мешает разработчику получать новый, более конструктивный опыт.
Это может быть случаем «синдрома утенка», когда разработчик просто «прикипает» к подходу, который он применил для решения аналогичных задач в первый раз, романтизирует его и с тех пор продолжает пользоваться только им.
Предметом такой привязанности может быть как язык программирования, фреймворк или платформа, так и инструмент, не являющийся специфическим, например, редактор кода. Да, vim/emacs/eclipse/подставить нужное — классные инструменты, но точно не идеальные для всех возможных случаев.
Примеры такого поведения при написании кода:
- Решение любых задач по работе со строками через регулярные выражения.
- Реализация абсолютно всех модулей и сущностей в виде классов (в тех случаях, когда язык предлагает альтернативы).
- Верстка абсолютно любых страниц и компонентов при помощи одного и того же приема разметки, например, flexbox.
- Привычка использовать избыточные или неявные синтаксические конструкции. Например, оборачивать весь код код функции в try/catch, явным образом приводить типы в слаботипизированных языках или отдавать предпочтение однострочным выражениям, просто потому что они однострочные.
В более широком смысле это может быть иррациональная приверженность каким-либо пакетам и библиотекам или стремление затащить их в любую кодовую базу. Сюда же входит необдуманное покрытие тестами всего и вся или, например, слияние веток в git всенепременно через rebase.
Эти приемы не обязательно являются проблемой сами по себе. Проблемой оказывается именно то, что человек использует бездумно и даже не интересуется альтернативами. Как следствие, такой разработчик становится негибким, начинает постепенно отставать от идущей быстрыми темпами индустрии, привлекая слишком сложные или плохо читаемые решения в современные кодовые базы. Со временем он становится «слабым» и устаревшим разработчиком.
Такие программисты создают много лишних итераций своим командам в процессе code review и продуцируют баги, которые возникли из-за использования устаревших приемов и фрагментов кода в новых контекстах, и которых можно было бы избежать. Помимо этого, такие подходы у разработчика можно обнаружить и в ходе устного интервью — нужно просто предложить ему обдумать решения тех или иных задач. И вы, скорее всего, услышите одни и те же ключевые слова, повторяющиеся названия и имена, или похожую линию мысли во всех случаях.