Концепция «код должен работать быстро» не так однозначна, как может показаться
Часто цель работы – угодить начальству, поэтому не воспринимайте мои слова чересчур серьезно и делайте все возможное, чтобы непосредственный руководитель был вами доволен. Это он отвечает за ваш карьерный рост, а не я. Тем не менее стоит знать, что скорость выполнения задач и строгость написания кода – не священный Грааль, как вам могли вбивать в голову в вузе.
Если вы программист или тимлид и хотите вынести из прочтения этой книги один урок, вот что я предлагаю запомнить:
Если в проекте работы на час, он будет готов через час. Если в нем работы на четыре часа, он займет день. Если в нем работы на день, он займет всю неделю. Если на неделю, он займет пару месяцев. Проекты, в которых работы на полгода и больше, как правило, не заканчиваются никогда.
Кен Уильямс
Запишите это. Это один из самых важных уроков в разработке программного обеспечения.
Чем меньше получатся кусочки, из которых состоит ваш проект, тем быстрее вы справитесь. Поэтому, если вам поручили большой проект, начать стоит с разделения его на ряд более мелких. Разделяй и властвуй. Если у вас получится распределить силы по мелким проектам, вы уложитесь в рамки времени и бюджета. А если не сможете – придется искать оправдания, чтобы выкрутиться. На хороших оправданиях можно протянуть не один год, так что это не конец света. Но нет ничего плохого и в том, чтобы сразу победить.
Если вы тимлид, заставьте своих программистов описать подход к написанию кода. Не позволяйте им приступать к работе, пока они не разобьют проект на мелкие кусочки. Требуйте список задач.
Приготовьтесь услышать такую фразу: «Не учите ученого, не надо меня по мелочам контролировать». Я не раз слышал подобное, и не только от программистов. В ней есть доля правды. Отличных программистов не надо контролировать по мелочам. Тем не менее у отличных программистов к моменту начала работ уже будет выстроен план, а проект разбит на мелкие части. Если этого не было сделано, то стоит задуматься, так ли он хорош.
Еще одна популярная фраза, которую часто можно услышать от исполнителей: «Я не знаю, сколько времени это займет. В процессе». Я считаю такой ответ неприемлемым. Лучше было бы сказать: «Я сейчас потрачу пару дней на изучение кода, а затем составлю план работ. Вот тогда я смогу дать точные оценки по срокам».
Нет правил без исключений, но я куда больше ценю надежность, читабельность и поддерживаемость кода, чем скорость выполнения или «строгость». И если вы постоянно пишете код, пытаясь увидеть его глазами какого-то другого программиста, которому через пару лет предстоит вносить в него изменения, вы обнаружите, что работа как по волшебству завершается в срок и в рамках бюджета. Код будет быстрее отлаживаться и надежнее работать на продакшене[19].
И, как всегда, все начинается с «проще значит лучше». Лучший код выглядит до безобразия просто.
Обычно я начинаю написание кода с определения имен методов (подпрограмм)[20]. Мне нравятся функциональные блоки с именами, которые четко говорят, что такая подпрограмма делает – типа get_input_from_customer («принять ввод от клиента») или put_record_to_database («отправить запись в базу данных»). Я стараюсь, чтобы функциональность процедуры сводилась к тому, что указано в названии метода. Другими словами, в методе под названием validate_customer_number («проверить номер клиента») не надо делать ничего, кроме проверки номера клиента. Если для этого вам нужно выполнить какую-то другую работу, вызовите для нее другой метод. Постарайтесь, чтобы каждый отдельно взятый метод занимал не более двадцати строк кода. Если для проверки номера клиента нужно провести, например, проверку того, активен ли счет клиента, вызовите метод check_customer_account_active («проверить, активен ли счет клиента»). Не помещайте предназначенный для этого код в тот же самый метод. Зачем это делать, если и надо-то всего четыре или пять строк кода? Ответ такой: большинство программистов в состоянии написать несколько строк кода и заставить этот метод из нескольких строк работать с первой попытки. При этом метод из 25 строк требует экспоненциально больше времени для отладки, чем кусок кода на 20 строк. Уж поверьте: надо быть простым как валенок. Используйте до омерзения длинные имена переменных. И вы закончите работу быстрее, чем «вундеркинд» за соседним столом.
Некоторые другие вещи, о которых стоит подумать…
Остерегайтесь логического отрицания (NOT). Всегда представляйте, что другой программист, которому предстоит поддерживать ваш код, – новичок, и вам надо ему помочь. Новичка очень легко сбить с толку конструкциями типа if (not customer_number is null)… Если вы постараетесь, чтобы код содержал как можно меньше отрицаний, вам самим будет проще его читать. Возможно, стоит подумать и о том, чтобы добавить метод для определения номера клиента. Конструкцию if (isValid(customer_number))… будет легче читать будущим кодерам.
В качестве примера того, как можно ускорить работу и при этом не спешить, я расскажу о своем подходе к большим сложным проектам по обслуживанию.
• Прежде чем изменить какую-либо часть кода, я один раз прохожусь по всему коду в целом, чтобы уловить, какие данные тут задействованы и что код в целом делает.
• Затем я рефакторю[21] код. Обычно я трачу день на переработку кода, разбивая большие методы на множество более мелких. Я ищу логические отрицания и преобразую код в позитивный. Я ищу сегменты кода с отступами более одного или максимум двух уровней и выделяю их в отдельные методы. Я ищу длинные методы, выполняющие десять различных действий, и разбиваю их на десять отдельных методов. Я ищу избыточный код и выделяю его в отдельный метод или класс. (Примечание: в процессе этой работы надо добавить комментарии, которые могут быть полезны будущим разработчикам и вам самим.)
• Затем я удостоверяюсь, что код по-прежнему выполняет то, что делал раньше.
Рефакторинг позволяет мне «проникнуть внутрь» программного кода и понять, что он делает. На этом этапе кажется, что проект стоит на месте или даже откатывается. Но после рефакторинга у меня уже есть понимание, сколько времени займет проект, и база исходного кода, с которой я могу работать. Что еще более важно, этой базой сможет воспользоваться другой программист, не проходя через ту же боль, что прошел я.
Еще несколько «правил» разработки программного обеспечения, большинство из которых основаны на здравом смысле и до боли очевидны, но я все равно включу их сюда:
• Используйте самоочевидные имена переменных и методов. Звучит как что-то из самого базового курса программирования, но поразительно, как много на свете программистов, которым об этом надо напоминать. Старайтесь не использовать имена переменных типа «foo» или «x». Гораздо лучше имена типа customer_number.
• Не используйте для одной и той же цели два разных имени переменных. Если в одном месте кода у вас будет переменная cust_num, а в другом месте те же данные будут обозначаться другой переменной customer_number, вы запутаетесь. Если нужно, определяйте где-то имя переменной, и не пишите его по-разному – например, db.customer_number и input.customer_number.
• Конечный пользователь не должен сидеть без дела. Это философия проектирования, а не стандарт программирования, но об этом определенно стоит подумать, работая с кодом. Конечным пользователям (людям, которые в итоге пользуются программой) трудно долго концентрироваться на одном предмете. Я всегда придерживался правила «семи секунд». Человека, сидящего перед компьютером, нужно каким-то образом задействовать каждые семь секунд. Может, и семь раз в секунду, но… я лично готов потерпеть в худшем случае семь секунд. Даже если это означает просто попросить пользователя «Нажмите ввод», нужно чем-то его занять. Не позволяйте ему скучать.
• Чем больше вопросов на странице, тем более запутанным становится пользовательский интерфейс. Если вы разрабатываете экран ввода данных, будьте проще. Не беспокойтесь о том, что пользователю, возможно, придется нажать «ввод» двадцать раз или несколько раз обновлять