В прошлом году я присоединился к четырем проектам. Так получилось, что все они были начаты до моего прихода в команду. Это очень распространенное явление: в ходе своей карьеры разработчики частенько оказываются в ситуации, когда приходится тратить кучу времени, чтобы понять чужой код. Быть может, этот код написали пару дней назад, а быть может несколько лет. Автор кода может до сих пор работать в этой команде, и тогда он поможет вам разобраться. А может быть и так, что автор уже давно покинул проект. Но независимо от обстоятельств будьте готовы, что вам придется сидеть над чужим кодом и ломать голову, пытаясь понять, зачем он нужен.
Самый жёсткий случай в моей практике случился недавно, когда я взялся за проект, которым раньше занимались два других разработчика (их обоих уволили, но я хочу подчеркнуть, что это произошло не из-за низкого профессионализма, а из-за финансовых трудностей в компании). Мои предшественники проделали большую работу, но их сферы ответственности вообще не пересекались: один отвечал за клиентскую часть, другой – за серверную. Вряд ли кто-нибудь будет в восторге от перспективы оказаться в ситуации подобной моей, даже если предыдущие разработчики были супер-профессионалами. У меня не было ни файлов readme, ни тестов. Проверки кода по этому проекту не проводились ни разу. Когда я пришел, никто не стал вводить меня в курс дела и никакой формальной передачи проекта не произошло.
Несколько веселых недель спустя проект стал выглядеть намного лучше. После археологических раскопок, которые я провел вместе с замечательной командой, к которой мне посчастливилось присоединиться, у проекта появилась документация и автоматические тесты. Еще мы устранили ряд неполадок, которые просочились в код из-за того, что никто его не проверял. Это всё замечательно, но в идеале эта ситуация попросту не должна была возникнуть. И мы бы не потратили на ее разрешение в совокупности несколько месяцев, которые иначе бы мы посвятили разработке.
Все эти события заставили меня намного серьезнее относиться к коду, который я пишу. А еще я осознал, как часто нам, разработчикам, приходится думать как компилятор. Когда мы разрабатываем новые функции, нам нужно буквально перестроить свой мозг, чтобы понять, как написанный нами код будет интерпретироваться. И в целом это нормально, это часть работы. Но если вы видите модуль впервые, нормально ли мучиться и ломать голову, чтобы просто понять, для чего он нужен?
Посмотрите на эту функцию (написана на языке Haskell, но язык тут не важен), которая принимает сообщение и возвращает ответ:
responseFor :: String -> String
responseFor message
| length (dropWhileEnd isSpace message) == 0 = "Fine. Be that way!"
| not (null (filter isAlpha message)) && all isUpper (filter isAlpha message) = "Whoa, chill out!"
| isSuffixOf "?" (dropWhileEnd isSpace message) = "Sure."
| otherwise = "Whatever."
Если вы не знаете Haskell, то вы, наверное, сейчас пробежались глазами по коду и ничего не поняли. Я вас не виню: не код, а бардак какой-то! Но, по моему опыту копания в чужом коде, куча народу именно так и пишут. Добьются, чтобы код работал, и сразу переходят к следующей задаче. Я это прекрасно понимаю: над всеми нами нависают дедлайны, руководители проектов и владельцы продуктов. Но вы только вдумайтесь, как быстро можно нарушить понятную только автору логику кода и сделать функции более читаемыми. Потратьте буквально несколько минут, и вы сэкономите часы работы другим людям, которым придется возиться с вашим кодом. Очень часто экономия времени произойдет, как только ваш код попадет на проверку.
Посмотрите на исправленный вариант приведенного выше фрагмента кода:
responseFor :: String -> String
responseFor message
| isEmpty message = "Fine. Be that way!"
| isShouting message = "Whoa, chill out!"
| isQuestion message = "Sure."
| otherwise = "Whatever."
Как видите, я выкинул из кода изначальную логику. И хотя она осталось практически такой же, как и в первом примере, её больше не нужно видеть, потому что я поменял её на полезные названия функций. И если в изначальном варианте было непонятно, что делает функция responseFor
, теперь вы можете это легко и быстро узнать. Вам не обязательно знать, что функция isShouting
проверяет, чтобы в сообщении были буквы, а затем уточняет, все ли они в верхнем регистре, потому что вы не компилятор. Вам достаточно знать, что если сообщение написано капсом, ответ будет «Воу-воу, полегче!».
Многие любят писать такие функции, у которых каждая строчка выполняет множество действий, и я совсем не против такого подхода. Я люблю, чтобы функции были небольшими и элегантными, по-моему, это здорово. Например, когда я использую JavaScript, я стараюсь, чтобы мои функции находились на одной строке, чтобы не ставить фигурные скобки. Плюс я обычно выбираю функции, которые состоят из других функций. При этом последнее время я прилагаю сознательные усилия, чтобы мой модуль оставался понятным, если его читает человек, а не машина, и не важно, какая у модуля «основная» функция. Пока что результатами я доволен. Считаю, что стоит думать о следующем разработчике, который будет разбираться с моим кодом. Тем более что в половине случаев это я и есть!
Перевод статьи «Thinking of the next developer» by David Nimmo