В последнее время я видел мало действительно хорошего кода, много посредственного и очень много — плохого. (Много того, что я писал раньше — особенно, когда я только начинал — относится к последним, увы.) Читая случайные статьи в интернете и профессиональные книги, я пришел к выводу, что писать хороший код — легко. Невероятно трудно, но в то же время легко. На самом деле, это настолько просто, что сводится к трем правилам.
- Пишите код для людей, а не машины.
- Не повторяйте себя.
- Каждый фрагмент кода должен выполнять одну задачу.
Соблюдая их постоянно, вы будете писать хороший код. На любом языке программирования и в любой парадигме. Проблема в том, что это очень трудно. Все они требуют дисциплины, а для двух последних в большинстве случаев нужны еще и продолжительные размышления.
Пишите код для людей, а не машины
Это самое важное из трех правил, лежащее в основе двух других. Пишите код, который прост для человека; оставьте тяжелую работу компьютеру. Используйте осмысленные имена переменных и методов. Не создавайте запутанных логических цепочек там, где можно применить и простые. Не пытайтесь уместить в одной строке как можно больше. Соблюдайте единый стиль написания кода, в котором есть осмысленные отступы. Если ваши файлы настолько громоздкие, что их становится сложно прокручивать, разбейте их на несколько небольших.
Многие программисты пытаются писать то, что на их взгляд работает быстрее, уменьшает размер приложения — словом, “облегчает” работу компьютера. Это замечательно, но не забывайте, что гораздо важнее писать код, который будет легко читать и поддерживать другим людям.
Ваш компилятор (или интерпретатор) может обрабатывать абсолютно разные стили кода. Для него n и numberOfObjects — это одно и тоже. Для людей — нет. Они будут долго вчитываться в код, даже если предназначение переменной кажется вам очевидным.
Представьте, что вы сделали для себя маленький скрипт, и через несколько лет вам понадобилось немного изменить его. Что бы вы предпочли увидеть: хорошо структурированный скрипт, с комментариями и понятным наименованием, или одну функцию без единого комментария и с переменными, предназначение которых понять практически невозможно?
Если вы делаете что-то неочевидное, чтобы оптимизировать часть кода, опишите в комментарии, что именно она делает. Но не забывайте, что в большинстве случаев вы не сможете оптимизировать программу лучше, чем компилятор. Реальность такова, что он умнее вас. Это факт: компиляторы улучшались в течение десятилетий тяжелой работы профессионалов. Бывают и исключения, но они лишь подтверждают правило.
Пишите код, понятный людям.
Не повторяйте себя
Я не могу сосчитать, сколько раз один и тот же фрагмент кода встречался мне в разных частях программы. Как раз сегодня я работал над большой функцией в устаревшем коде и увидел одинаковые условия в двух разных частях условного выражения. Мне пришлось потратить время на то, чтобы убедиться, что это просто ошибка программиста.
Когда вы повторяете один и тот же фрагмент в нескольких местах, вам рано или поздно придется к нему вернутся, чтобы исправить какую-нибудь ошибку или добавить что-нибудь новое. Это затрудняет поддержку кода. Вместо того, чтобы повторять себя, поместите фрагмент в отдельный класс или функцию, к которой можно будет обратиться, как только она понадобится. Если вы в различных местах вызываете несколько методов в одном и том же порядке, оберните его в отдельную функцию.
Подумайте, что будет легче понять при знакомстве с кодом: фрагмент длиной в 30 строк, освобождающий блок памяти, или вызов функции clearMapVariableMemory()?
Возможно, вам понадобится изучить фрагмент позже, но даже в этом случае работать с отдельной функцией будет легче.
Этот же принцип может быть применен и к данным. Если вы часто используете одни и те же переменные, перенесите их в отдельный класс или тип данных.
Если соблюдать это правило, все изменения будут универсальными — вам не придется перерабатывать десятки мест, чтобы внести небольшую поправку.
Не повторяйте себя.
Каждый фрагмент кода должен выполнять одну задачу
Последнее правило основано на двух предыдущих: каждый фрагмент вашего кода должен выполнять только одну задачу. Оно верно на всех уровнях: для выражений, функций и методов, классов и объектов.
Несколько лет назад один разработчик показал мне неработающий фрагмент кода. Для того, чтобы разобраться в нем, программисту потребовалось несколько часов. В итоге проблема обнаружилась в пост-инкрементальных операторах C (в особых случаях их поведение разнится от компилятора к компилятору). Впоследствии, читая одну книгу по разработке, я отметил, что истинная проблема заключается не в операторах, а в том, что один фрагмент отвечал за выполнение множества разных задач.
Насколько я помню, строка, содержащая ошибку, была частью тернарной операции. Та, в свою очередь, выполняла несколько операций над указателями, чтобы посчитать условие, и еще несколько, в зависимости от результата условного выражения. Это был хороший пример написания кода в первую очередь для машины, а не для человека: никто, кроме автора фрагмента, не поймет, что именно делает строка, даже прочитав ее несколько раз. Если бы программист, написавший код, разбил логику на несколько частей, на решение проблемы ушло бы куда меньше времени.
Не стоит извлекать, обрабатывать и изменять данные в одном и том же методе. Словесное описание каждой функции должно помещаться в одно предложение. Предназначение каждой строки должно быть ясно. Это делает код понятным людям. Никто из нас не может хранить в голове функцию длиной в несколько тысяч строк. Нет и существенного основания создавать такие функции вместо нескольких небольших методов, используемых вместе.
Надо отметить, что это не так сложно: для выполнения одной большой задачи необходимо всего лишь разбить ее на несколько меньших, каждая из которых находится в отдельной функции. Важно следить за тем, чтобы предназначение каждой функции оставалось понятным, иначе код становится слишком запутанным.
Каждый фрагмент вашего кода должен выполнять одну задачу.
Заключение
Написание хорошего кода — это тяжелый труд. Я занимаюсь программированием в течение четырех лет — не так долго, но вполне достаточно, чтобы увидеть довольно много проблем, в том числе и своих. Мне стало понятно, что мы усложняем разработку, не соблюдая этих простых правил. Соблюдать их правильно — сложно: не всегда ведь очевидно, где нужен отдельный класс или метод. Это навык. На то, что бы стать хорошим программистом, требуется много времени. Но если мы не будем следовать этим правилам, написание и поддержка кода станут еще сложнее.
Перевод статьи Good Programming in 3 Simple Rules.
Автор: greatvote