Привет, Хабр!
Говорить о чистом коде можно бесконечно, но следующая статья Дэйва Николетта очень метафорична и, надеемся, действительно достойна перевода. Пусть и немного «назидательна», о чем автор заранее преуведомляет читателей в оригинале статьи.
Приятного чтения.
У нас дома с годами закрепилась дурная привычка. Попользовавшись каким-либо инструментом, мы то и дело забывали положить его на место. В следующий раз, когда он кому-то требовался, приходилось потратить больше времени на поиски инструмента, чем на решение возникшей задачи. Самое печальное – ровно на такие же поиски был обречен даже тот, кто брал инструмент последним и бросил его куда попало. Часто оказывалось, что быстрее купить новый инвентарь, чем искать тот инструмент, который у нас – мы точно знаем! – где-то завалялся.
Так у нас и скопилось четыре средних крестовых отвертки Philips, три с плоским шлицем, куча лишних щипцов и гаечных ключей, наборы переходников. Я уже не говорю о впечатляющей коллекции ручек, мотков скотча, батареек и прочего добра, разбросанного повсюду.
Однажды мы решили: хватит! Выделили для всех вещей свое место и навели порядок с нашим инвентарем. Подвойные инструменты сдали в благотворительность. Мы прилагали всяческие усилия, чтобы воспитать самодисциплину и всегда класть инструменты только на свое место после того как поработаем с ними. Качество и объемы работы в единицу времени резко пошли вверх. Стресса, впустую потраченных денег и испорченного настроения стало гораздо меньше.
Наводим порядок в корпоративном гараже
Что, если бы автомеханики, работающие в корпоративном гараже, бросали бы инструменты где попало? Они бы тратили больше времени на поиски инструментов, чем собственно на работу. Детали бы ставились не туда, терялись, ржавели, портились, их бы просто воровали. Расходы на снабжение сильно бы возросли.
На выполнение заданий уходило бы больше времени, но качество работы снижалось бы. Когда механику приходится работать с ржавыми, изношенными и поломанными инструментами, ему сложно как следует подогнать и закрепить детали. Кроме того, привычка устраивать в мастерской беспорядок неизбежно отразится и на качестве работы.
Клиенты будут сыты по горло бесконечными переносами окончания работ. Скоро они станут уходить в более надежные мастерские. Как-нибудь обойдутся без вас. Пожалуй, аналогии с разработкой и поддержкой ПО уже очевидны.
Наводим порядок в разработке ПО
Разберем конкретный пример: инкрементный рефакторинг.
Многих это выражение озадачивает. Не знаю, какое именно слово ставит их в тупик: «инкрементный» или «рефакторинг».
Инкрементный (постепенный) рефакторинг коренным образом отличается от крупномасштабного. Многим кажется, что любой рефакторинг обязательно «крупномасштабный», что он должен быть кем-то «санкционирован», и поэтому якобы работа обязательно должна затянуться. На самом деле, именно если пренебрегать рефакторингом по ходу работы, то все существенно затягивается.
Большинство технических коучей, и я в том числе, с трудом объясняют разницу в данном случае; не потому, что данная разница по определению сложна, а потому что ее действительно тяжело сформулировать словами. Однако, думаю, что привычка внимательно учитывать имеющийся инвентарь и следить за снабжением – удачная аналогия в данном случае.
Постепенный рефакторинг
Делать постепенный рефакторинг – все равно, что поддерживать порядок на верстаке даже в разгар работы. Попользовались отверткой – кладем ее на место. Мы же не будем перед каждой новой задачей заново возводить для этого мастерскую. Суть, скорее, в умении заканчивать… как следует заканчивать то, что вы начали. Зачищать концы.
На постепенный рефакторинг не уходит много лишнего времени и не требуется чьего-то разрешения сверху. Если уж на то пошло, нужно спрашивать разрешения не прибирать за собой в коде, если нужно спешить. Умение постоянно держать код чистым на самом деле должно считаться базовым профессиональным навыком программиста. Стыдно, что сегодня «чистый код» нуждается в пропаганде, а некоторые программисты даже противятся наведению такой чистоты. Постепенный рефакторинг не имеет ровно ничего с крупномасштабным архитектурным рефакторингом, который действительно требуется тщательно планировать, выделять на него время, деньги и людей.
Правило бойскаута
В программировании существует так называемое «правило бойскаута»: оставляй код как минимум столь же чистым, каким его принял. То же касается и хранения рабочих инструментов дома. Если мы ищем плоскогубцы, но замечаем, что шлицевая отвертка случайно попала к крестовым, а крестовая – к шлицевым, мы по ходу дела кладем их на свои места. Нам не нужно официального одобрения, чтобы сделать это.
Именно так работает и постепенный рефакторинг. Перед нами – фрагмент кода, и нам нужно добавить новое условие в список имеющихся конструкций. Замечаем, что список реализован в виде большого блока if/else. Решаем, что его нужно переоформить в виде switch или оператора выбора, одновременно добавляя условие. Можно возразить: а разве это намного лучше, чем блок if/else? Да, вы правы: ненамного. Но чуть-чуть лучше. Когда кто-то следующий будет читать этот код после вас, он сможет еще лучше доработать его, поскольку вы улучшили для него исходную позицию. Если вам доводилось делать что-то подобное ранее, то вы, вероятно, замечали, что, просто внимательно прочитав все условия, вы иногда находили то дублирующиеся конструкции, то неоптимальный порядок выражений; возможно, вам попадалось какое-нибудь условие, которое никогда не может быть выполнено, а то и логическая «дыра», через которую вся управляющая последовательность провалится через блок if/else, а некоторый случай вообще обработан не будет. Просто радуйтесь, что обнаружили это сейчас, а не глубокой ночью, когда вам прилетит соответствующий тикет от службы техподдержки. В такой момент, когда глаза слипаются, нет совершенно никакого желания разбираться в путаном коде.
Может быть, мы добавим в приложение какой-то новый функционал и заметим, что написанные нами функция/метод очень похожи на другую (другой), которые уже имеются у нас в базе кода. Потратив всего несколько секунд, мы избавимся от такого дублирования, даже без дополнительных инструментов, которые предлагаются к нашим услугам в шикарных IDE. Можно рефакторить не сомневаясь, поскольку мы приучили себя к самодисциплине и гарантируем, что уже написаны микротесты (модульные тесты), покрывающие этот случай. Тогда и рефакторинг вручную – не страшен. В конце концов, придумайте хотя бы одну причину, почему бы этого не сделать?
“Долгосрочный” –это обычно не так долго, как кажется
Часто слышу от разных людей, что рефакторинг приносит «долгосрочную» пользу. Хотя, в теории так и есть, здесь, в Реальном Мире постоянно приходится сдавать работу в жесткие сроки. Однако, если говорить о поддержании чистоты кода путем мелкого постепенного рефакторинга, «долгосрочное» длится ровно до того момента, когда кто-то еще притронется к базе кода. Ровно до следующего раза.
Плохая новость в том, что верно и обратное. Если не подчищать код по ходу работы, то он быстро портится. У нас нет десятилетней «подушки безопасности», которая позволила бы нам безнаказанно накапливать брак до тех пор, пока не начнутся проблемы. Следующее изменение, которое потребуется вносить, отберет у нас непозволительно много времени, повысится риск регрессии кода, и ситуация без должного внимания к ней будет только ухудшаться.
Если мы халтурим только ради того, чтобы удовлетворить желание заказчика (а он хочет готовый продукт побыстрее), как же мы собираемся и далее соответствовать этим запросам, после того, как убедимся, что никаких быстрых изменений больше не внести, поскольку мы довели код до состояния неразберихи, и поддерживать его невозможно?
Что такое быстро, что такое медленно?
Заказчики всегда будут хотеть, чтобы вы работали живее, независимо от того, насколько быструю доставку вы организуете. Наиболее эффективный способ сократить время до релиза – все делать правильно; делать хорошо; постоянно подчищать концы, всегда, без исключения. Срезая углы, чтобы «ускориться», на практике мы только замедляемся, причем, не в эфемерной «долгосрочной перспективе», а здесь и сейчас.
Когда заказчик требует, чтобы вы работали быстрее, это не значит, что он разрешает вам работать небрежно. Естественно ему кажется очевидным, что он не должен раз за разом при каждом запросе напоминать нам, что его интересует высокое качество. Высокое качество подразумевается как одна из составляющих нашей работы.
Мы как инженеры, сами выбираем, считать ли постепенный рефакторинг базовым элементом нашей профессиональной деятельности. Мы не спрашиваем, можно ли нам работать как следует, точно как хирург не спрашивает у бухгалтера, есть ли у него время помыть руки перед операцией. Время, затрачиваемое на операцию – это ровно столько времени, сколько нужно, чтобы операция прошла успешно. Пациенту нужно, чтобы ему аккуратно удалили аппендикс, и, выписавшись, человек мог вернуться к нормальной жизни – без раневой инфекции и без тампона в животе. Будет только хуже, если человека увезут из операционной на десять минут раньше чем нужно, а потом у него начнутся осложнения.
Зачастую в таком случае парируют, что если «все делать по науке», то получается «слишком долго». Нет, на самом деле, «слишком долго» — это время, которое уходит на исправление последствий, если работа делалась в спешке и без должного профессионализма. Восстановление после инфекции – это настоящее потрясение для самого пациента и его родных, это неминуемо отразится и на его работе. Повторная операция, при которой приходится вырезать из живота забытый тампон – это гораздо более серьезное вмешательство, а потребуется оно только потому, что в первый раз человека оперировали в спешке.
При программировании, если приходится идти на пять регрессий кода из-за того, что кто-то писал его в спешке, об «экономии времени» говорить не приходится. Наоборот, изменения вносятся дольше. Работа не «сделана», пока не сделана правильно. Если команде пришлось потратить часы и дни на исправление ошибок после «черновой готовности», то это утраченное время, которое можно было бы потратить на другую, полезную работу. Это упущенная выгода.
Такие ошибки дают волнообразные последствия и приводят к долгосрочным потерям времени и денег, а иногда – к потере клиентов. Дополнительный стресс ложится и на плечи самих инженеров; низкая мораль, высокая текучка кадров. Отсюда – все более жесткое завинчивание и дальнейшее снижение морали и вовлеченности в работу.
Технический долг как метафора
Всякий раз, когда обращаешься к теме постепенного рефакторинга, кто-нибудь обязательно напомнит тебе о техническом долге. Скажут: «нам выкатили такие сроки, что просто необходимо срезать углы». Добавят, что в данном случае команда сознательно накапливает технический долг, руководствуясь запросами бизнеса.
Те, кто так говорит, не понимают эту метафору, а возможно – и никаких метафор вообще.
Метафора не предназначена для полного и исчерпывающего описания характеризуемой вещи.
Метафора помогает в общих чертах составить впечатление о каком-либо аспекте этой вещи.
Люди склонны подменять вещь ее метафорой, а затем оперировать метафорой так, словно она и
описываемая вещь – суть одно и то же. Нет, это не одно и то же. Точка.
Кроме того, людям свойственно расширительно трактовать метафору за пределами ее исходного контекста. Таким образом смысл метафоры размывается, и она становится все менее полезной.
Уорд Каннингем предложил метафору технического долга, описывая взаимодействие с клиентом в финансовой индустрии. Он подыскивал подходящую метафору именно для этого контекста, чтобы подчеркнуть, как постепенное воплощение возможностей помогает создать цикл обратной связи, в ходе которого программа постоянно оптимизируется. Он не имел в виду «срезать углы ради того, чтобы создать иллюзию быстрой разработки».
В исходной концепции метафоры технического долга подразумевалось, что код обязательно поддерживается в чистоте. Люди, понимающие оставленную в коде проблему, шаг за шагом движутся к ее решению, и код всегда будет достаточно аккуратен, чтобы в него можно было вносить такие постепенные доработки. Речь не идет о том, что какие-то причины технического характера могут послужить оправданием, почему код барахлит и требует постоянных исправлений.
Срезание углов ради того, чтобы сдать работу побыстрее – это не накопление технического долга. Это обычная халтура.
Кто ответственный?
Чтобы добиться быстрой доставки, нужно по максимуму избавиться от проблем при работе. Одна из таких проблем – барахлящий код. Избавиться от этой преграды можно шаг за шагом, научившись рабочей самодисциплине. В данном случае не важно, как вы работаете – по «водопадной» модели или по «аджайлу». Мы сами выбираем как работать всякий раз, когда прикасаемся к клавиатуре.
Резюмирую. Если работать правильно, в том числе, подчищать концы, это пойдет только на пользу клиенту, спонсорам, менеджерам, тем, кто будет поддерживать наш код в будущем и, конечно же, нам самим.