16 лучших практик для написания читаемого кода: что нужно знать любому программисту перед устройством на работу и не только

Читаемость кода – универсальный показатель в мире программирования. Это одна из первых вещей, которые осваивают разработчики. В этой статье мы рассмотрим 15 лучших практик, которые помогают писать более читаемый код.

Публикуем перевод, сделанный для Tproger международной IT-компанией Noveo.

1. Комментирование и документация

За последние 5 лет среды разработки (IDE) прошли большой путь. Это сделало комментирование кода важным как никогда. Использование определённых стандартов комментирования позволяет среде разработки и другим инструментам использовать комментарии определённым образом.

Рассмотрим этот пример:
readable_code_1

Комментарий, который я добавил при определении функции, можно просматривать каждый раз, когда я использую функцию, даже из другого файла.

Вот ещё один пример, где я вызываю функцию из сторонней библиотеки:
readable_code_2

2. Последовательные отступы

Я думаю, вы уже знаете, как расставлять отступы в коде. В любом случае, нужно напомнить, что последовательность в отступах будет хорошей идеей.

Есть несколько вариантов выставления отступов:

Стиль 1:

function foo() {
    if ($maybe) {
        do_it_now();
        again();
    } else {
        abort_mission();
    }
    finalize();
}

Стиль 2

function foo()
{
    if ($maybe)
    {
        do_it_now();
        again();
    }
    else
    {
        abort_mission();
    }
    finalize();
}

Стиль 3

function foo()
{   if ($maybe)
    {   do_it_now();
        again();
    }
    else
    {   abort_mission();
    }
    finalize();
}

Раньше я использовал второй стиль, но недавно перешёл на первый. Впрочем, это дело вкуса. Не существует “лучшего” стиля, которого должны придерживаться все без исключения. На самом деле лучший стиль – это последовательный стиль. Если вы участвуете в проекте в составе команды, необходимо придерживаться стиля, который уже используется на проекте.

Стили отступов не всегда можно отличить друг от друга: иногда смешиваются различные правила. Например, в PEAR Coding Standards открывающая скобка (“{“) остаётся на той же строке, что и контролирующие структуры, но переносится на следующую строку при определении функций.

Стиль PEAR:

function foo()
{                     // placed on the next line
    if ($maybe) {     // placed on the same line
        do_it_now();
        again();
    } else {
        abort_mission();
    }
    finalize();
}

Также можно отметить, что вместо табуляции для отступов используется четыре пробела.

Здесь находится статья Википедии, где можно прочитать о различных стилях отступов. А здесь вы можете найти отличный инструмент, который позволяет создать единый формат настроек и раз и навсегда решить вопросы вроде “табы или пробелы” для всех IDE и всех языков программирования.

3. Избегайте очевидных комментариев

Комментировать код – это просто прекрасно, но иногда комментарии становятся необязательными или попросту лишними.

Возьмём этот пример:

// get the country code
$country_code = get_country_code($_SERVER['REMOTE_ADDR']);
 
// if country code is US
if ($country_code == 'US') {
 
    // display the form input for state
    echo form_input_state();
}

Когда текст настолько очевиден, нет смысла дублировать его комментарием.

Если же комментарий необходим, можно сделать это одной строкой:

// display state selection for US users
$country_code = get_country_code($_SERVER['REMOTE_ADDR']);
if ($country_code == 'US') {
    echo form_input_state();
}

4. Группировка кода

Как правило, для выполнения определённых задач требуется несколько строк кода. Разумным будет оформлять такие задачи как отдельные блоки с разрывами между ними.

Приведём пример:

// get list of forums
$forums = array();
$r = mysql_query("SELECT id, name, description FROM forums");
while ($d = mysql_fetch_assoc($r)) {
    $forums []= $d;
}
 
// load the templates
load_template('header');
load_template('forum_list',$forums);
load_template('footer');

Последовательность в наименованиях

PHP сам не всегда бывает последовательным в наименованиях:

  1. strpos() при str_split()
  2. imagetypes() при image_type_to_extension()

Прежде всего, в именах должны быть различимы граница слов. Есть два популярных варианта:

  1. camelCase: заглавной становится первая буква каждого слова, кроме первого.
  2. Нижнее_Подчёркивание: слова разделяются нижним подчёркиванием, например, mysql_real_escape_string().

Существование нескольких опций создаёт ту же ситуацию, что и с отступами. Если на проекте уже существуют договорённости, нужно им следовать. Помимо того, некоторые платформы стремятся к использованию определённого стиля.

Например, большая часть проектов на Java использует camelCase, в то время как в PHP более популярно нижнее подчёркивание.

Здесь также возможно смешение. Некоторые разработчики используют нижнее подчёркивание для функций и названий классов, но предпочитают camelCase при написании названий методов класса:

Повторюсь: нет «лучшего» стиля. Просто будьте последовательны.

5. Принцип DRY

DRY – аббревиатура от английского Don’t Repeat Yourself (не повторяйтесь). Иногда используется вариант DIE – Duplication Is Evil (повторение – это зло).

Принцип гласит: «Каждый элемент знания должен иметь в системе единственное, не вызывающее сомнений и авторитетное значение».

Цель большинства приложений (или компьютеров в целом) – автоматизировать повторяющиеся задачи. Этого принципа нужно придерживаться в любом коде, даже когда речь идёт о веб-приложениях. Один фрагмент не должен повторяться в коде снова и снова.

Например, бОльшая часть веб-приложений состоит из нескольких страниц. Вероятность того, что эти страницы будут содержать одинаковые элементы, весьма высока. Обычно для этой цели используются header и footer. Не самой лучшей идеей будет копировать их для каждой страницы.

Вот как создаются шаблоны в CodeIgniter:

$this->load->view('includes/header');
$this->load->view($main_content);
$this->load->view('includes/footer')

6. Избегайте глубокой вложенности кода

Слишком большое количество уровней вложения затрудняет чтение и понимание кода.

function do_stuff() {
 
// ...
 
    if (is_writable($folder)) {
 
        if ($fp = fopen($file_path,'w')) {
 
            if ($stuff = get_some_stuff()) {
 
                if (fwrite($fp,$stuff)) {
 
                    // ...
 
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

Ради удобства чтения можно изменить код, чтобы уменьшить количество уровней вложения:

function do_stuff() {
 
// ...
 
    if (!is_writable($folder)) {
        return false;
    }
 
    if (!$fp = fopen($file_path,'w')) {
        return false;
    }
 
    if (!$stuff = get_some_stuff()) {
        return false;
    }
 
    if (fwrite($fp,$stuff)) {
        // ...
    } else {
        return false;
    }
}

7. Ограничьте длину строки

Нашим глазам удобнее читать длинные и узкие колонки текста. Именно поэтому статьи в газетах обычно выглядят так:

newspaper

Избегать длинных строк кода – хорошая практика.

// bad
$my_email->set_from('test@email.com')->add_to('programming@gmail.com')->set_subject('Methods Chained')->set_body('Some long message')->send();
 
// good
$my_email
    ->set_from('test@email.com')
    ->add_to('programming@gmail.com')
    ->set_subject('Methods Chained')
    ->set_body('Some long message')
    ->send();
 
// bad
$query = "SELECT id, username, first_name, last_name, status FROM users LEFT JOIN user_posts USING(users.id, user_posts.user_id) WHERE post_id = '123'";
 
// good
$query = "SELECT id, username, first_name, last_name, status
    FROM users
    LEFT JOIN user_posts USING(users.id, user_posts.user_id)
    WHERE post_id = '123'";

Кроме того, если кому-то потребуется читать код из окна терминала (как, например, пользователям Vim), то будет разумно ограничить длину строки 80 символами.

8. Организация файлов и папок

Технически возможно написать приложение полностью в одном файле. Но чтение и поддержка такого проекта превратятся в кошмар.

На своих первых проектах я знал об идее создания «включённых файлов», но я тогда был не очень организованным человеком. Я создал папку “inc” с двумя файлами: db.php и functions.php. Но приложения росли, файл с функциями стал огромным, и поддерживать его стало невозможно.

Чтобы избежать этого можно или использовать фреймворк, или имитировать файловую структуру. Вот так, например, выглядит CodeIgniter:

readable_code_3

10. Последовательность во временных именах

Как правило, названия переменных описывают их суть и состоят из нескольких слов. Но это не всегда относится ко временным переменным, которые иногда могут состоять из одного символа.

Нужно поддерживать последовательность имён для временных переменных, у которых есть определённая роль. Вот несколько примеров, которые я использую в коде:

// $i for loop counters
for ($i = 0; $i < 100; $i++) {
 
    // $j for the nested loop counters
    for ($j = 0; $j < 100; $j++) {
 
    }
}
 
// $ret for return variables
function foo() {
    $ret['bar'] = get_bar();
    $ret['stuff'] = get_stuff();
 
    return $ret;
}
 
// $k and $v in foreach
foreach ($some_array as $k => $v) {
 
}
 
// $q, $r and $d for mysql
$q = "SELECT * FROM table";
$r = mysql_query($q);
while ($d = mysql_fetch_assocr($r)) {
 
}
 
// $fp for file pointers
$fp = fopen('file.txt','w');

 

11. Пишите специальные слова SQL заглавными буквами

Взаимодействие с базой данных – существенная часть большинства веб-приложений. Если вы пишете SQL-запросы, то будет разумно сделать читаемыми и их.

Несмотря на то, что специальные слова и названия функций SQL нечувствительны к регистру, их обычно пишут заглавными буквами, чтобы отличать от названий таблиц и колонок.

SELECT id, username FROM user;
 
UPDATE user SET last_login = NOW()
WHERE id = '123'
 
SELECT id, username FROM user u
LEFT JOIN user_address ua ON(u.id = ua.user_id)
WHERE ua.state = 'NY'
GROUP BY u.id
ORDER BY u.username
LIMIT 0,20

12. Разделение кода и данных

Это ещё один принцип, который относится практически ко всем языкам программирования во всех средах разработки. В случае веб-разработки «данные» обычно обозначают вывод HTML.

Много лет назад, во время первого релиза PHP, это было реализовано как движок шаблонов. Тогда HTML-файлы с несколькими строчками на PHP были привычным делом. В любом случае, с течением времени ситуация сильно изменилась и сайты стали более динамичными и функциональными. Сейчас код составляет значительную часть веб-приложений, и соединять его с HTML уже будет неразумно.

Вы можете или самостоятельно применить этот принцип к своему приложению, или использовать сторонние инструменты (шаблонизаторы, фреймворки, CMS) и следовать их договорённостям.

Популярные PHP фреймворки:

  1. CodeIgniter
  2. Zend Framework
  3. Cake PHP
  4. Symfony

Популярные шаблонизаторы:

  1. Smarty
  2. Dwoo
  3. Savant

13. Изменяйте синтаксис внутри шаблонов

Вы можете не использовать модные шаблонизаторы, ограничиваясь плоским PHP внутри своих файлов шаблонов. Это не обязательно будет нарушением принципа разделения кода и данных, если вложенный код напрямую относится к выводу и он читаем. В таком случае вам будет нужно изменить синтаксис для контрольных структур.

Приведу пример:

<div class="user_controls">
    <?php if ($user = Current_User::user()): ?>
        Hello, <em><?php echo $user->username; ?></em> <br/>
        <?php echo anchor('logout', 'Logout'); ?>
    <?php else: ?>
        <?php echo anchor('login','Login'); ?> |
        <?php echo anchor('signup', 'Register'); ?>
    <?php endif; ?>
</div>
 
<h1>My Message Board</h1>
 
<?php foreach($categories as $category): ?>
 
    <div class="category">
 
        <h2><?php echo $category->title; ?></h2>
 
        <?php foreach($category->Forums as $forum): ?>
 
            <div class="forum">
 
                <h3>
                    <?php echo anchor('forums/'.$forum->id, $forum->title) ?>
                    (<?php echo $forum->Threads->count(); ?> threads)
                </h3>
 
                <div class="description">
                    <?php echo $forum->description; ?>
                </div>
 
            </div>
 
        <?php endforeach; ?>
 
    </div>
 
<?php endforeach; ?>

Это позволяет избежать многих фигурных скобок. Кроме того, по отступам и структуре код становится похож на HTML-разметку.

14. Объектно-ориентированное против процедурного

Объектно-ориентированное программирование позволяет писать хорошо структурированный код, но это не значит, что вы должны полностью отказаться от процедурного программирования. На самом деле смешивание этих подходов может дать хорошие результаты.

Объекты можно использовать для представления данных, обычно они располагаются в базе данных.

class User {
 
    public $username;
    public $first_name;
    public $last_name;
    public $email;
 
    public function __construct() {
        // ...
    }
 
    public function create() {
        // ...
    }
 
    public function save() {
        // ...
    }
 
    public function delete() {
        // ...
    }
 
}

Процедуры и функции можно использовать для отдельных задач, которые могут выполняться отдельно.

function capitalize($string) {
 
    $ret = strtoupper($string[0]);
    $ret .= strtolower(substr($string,1));
    return $ret;
 
}

15. Читайте Open Source код

Open Source проекты создаются как результат труда многих людей. Такие проекты должны быть очень доступными для чтения, чтобы команда могла работать максимально эффективно. Следовательно, будет очень полезно просматривать код таких проектов, чтобы понять, какие методики применяют их разработчики.

open_source

16. Рефакторинг

Когда вы проводите рефакторинг, то меняете код, не изменяя возможности системы. Это можно представить как “чистку” кода для повышения читаемости и качества.

Рефакторинг не относится к багфиксингу или добавлению функционала. Можно рефакторить код, который был написан вчера, пока он ещё свеж в вашей голове, чтобы он был более читаемым и доступным для переиспользования, когда вы вернётесь к нему два месяца спустя. Как гласит старая истина «рефакторьте раньше, рефакторьте чаще».

Вы можете использовать любые из перечисленных «лучших практик» в процессе рефакторинга.

Перевод подготовлен международной IT-компанией Noveo.

Top 15+ Best Practices for Writing Super Readable Code