Освой Java играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Пишем красивый код

Код, который вы пишете, должен быть красивым, как кот. Когда мы смотрим на красивого кота, мы умиляемся и говорим: ми-ми-ми. При чтении вашего кода должно возникать такое же чувство. В противном случае, у вас не код, а, извините, говнокод.


Косо смотрит кот на код,
Написанный хозяином.
Код большой, как бегемот,
Плохо он читаемый.

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

Этим сильно он коту
Душу задевает,
И программера в коте
Тихо подавляет.
***
Тихо смотрит кот на код
И в душе сомненье
Мой хозяин идиот, нет другого мнения.
Пишет код и жрет, баран, сахарные кексики,
Ты бы тему запорол, даже в старом бейсике,
Запятую не туда, снова эти скобки...
И мяуканье кота выбивает пробки.
Засыпает в темноте программист от скуки,
Кот дописывает код...на старом ноутбуке!
---
С просторов интернета.

Я часто получаю письма от пользователей, которые делятся своими листингами. И порой волосы дыбом встают. Некоторые программисты наивно полагают, что свой код они прекрасно понимают и им не нужно писать красиво - мол и так понятно. В своё время я тоже так думал, а потом мучительно вспоминал, что делает та или иная функция в программе, которую писал несколько лет назад. Кроме того, правильная система написания кода помогает разработке, как это ни странно звучит.

Сравните код для запуска второй активности через нажатие кнопки (из урока 5):


public void onClick(View v) {
	Intent intent = new Intent(PassingDataDemoActivity.this, Privet.class);
	
	intent.putExtra("username", userNameEditText.getText().toString()); // в ключ username пихаем текст из текстового поля
	intent.putExtra("gift", descriptionEditText.getText().toString());  // в ключ gift пихаем текст из текстового поля
    startActivity(intent);
}

А вот реальный пример из письма пользователя, который на основе того урока, писал своё приложение:


public void oc(View v) {
	Intent i = new Intent(P1.this, P2.class);
	
	i.putExtra("m1", t1.getText().toString());
	i.putExtra("bla", t2.getText().toString());
    startActivity(i);
}

В обоих случаях код делает одну и ту же работу. Но сколько же лишних усилий мне пришлось потратить, чтобы уяснить код даже в таком простом примере. При чтении такого кода нужно помнить, что oc - это метод обработки нажатия кнопки, t1 и t2 - это текстовые метки и т.д. и т.п.

Вот почему я беру плату за чтение чужих программ - разбор листингов отнимает много времени и сил.

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

Понимание к такому подходу приходит не сразу. Когда я только начинал учиться программированию, то не обращал внимания на подобные "мелочи". Потом стал приглядываться не только к коду, но и как он написан. Стиль написания кода многое говорит о программисте. Есть очень интересная книга Читаемый код, или Программирование как искусство, который рекомендую к прочтению. Вот одна иллюстрация из этой книги.

Температура у кота

Используйте говорящие имена

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

Когда вы придумываете имя для переменной, метода, класса и т.д., то подойдите к данному действию ответственно. Не стоит давать имена из непонятного набора символов типа m1, wl, KU, o, p, r, s, t. Представьте себе, что вы даёте имя коту. Вряд ли ему понравится имя m1 или t. Конечно, он сделает вид, что его это не касается, но карма у вас вряд ли повысится. А если вам такое имя дадут родители?

Итак, договорились - давайте нормальные имена. Даже если это временный тестовый пример на пять минут, который вы удалите. Выбрав хорошее имя, вы сообщаете гораздо больше информации, чем кажется на первый взгляд. По сути правильное имя уже содержит комментарий. Сравним:

// в этой переменной будем хранить имена котов
String c;

String catname;

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

С другой стороны даже целые слова типа size, put тоже не всегда оправданны, так как не дают ясности. Избегайте пустых и неинформативных слов и выражений.

Допустим, мы создали метод getPage(url), который получает какую-то страницу. А откуда получает: из интернета, базы данных, диска? Если из интернета, то может стоит назвать метод downloadPage(url)? Кстати, мы пока не рассматриваем приёмы, связанные со стилем кодирования. Например, для Android имена методов должны начинаться с маленькой буквы, а второе слово с большой. В других языках могут использоваться другие стили, например, в Visual Basic совсем по другому.

Ещё пример:

class Cat {
    int size();
}

Что возвращает метод size()? Метод getTailSize() даёт основание предполагать, что речь идёт о размере хвоста. Кроме того, метод должен начинаться с глагола.

Или метод stop() - мы понимаем, что метод что-то останавливает. Но может есть более подходящие имена, например, kill() или pause() с родственным ему методом resume(). Ищите яркие запоминающие имена-синонимы.

Примеры синонимов:

  • send (посылать) - deliver (доставлять), announce (извещать), route (направлять)
  • find (искать) - search (искать), locate (обнаруживать)
  • start (начинать) - launch (запускать), create (создавать), begin (начинать)
  • make (создавать) - create (создавать), setup (устанавливать), build (строить), generate (генерировать)

Избегайте общих имён

Часто разработчики используют имена вроде tmp, retval, foo и т.д. В учебных примерах этот приём вполне допустим, чтобы показать, что это именно учебный пример. В своих программах следует избегать подобной практики. Иначе получается, что автор признаётся, что никак не может придумать имя. Придумайте такое имя, которое описывает назначение или содержание объекта. Тот же retval - совершенно неинформативное имя, которое сообщает, что это возвращаемое значение, что и так очевидно.

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

if(right < left){
    tmp = right;
	right = left;
	left = tmp;
}

Здесь tmp хорошо подходит, так как служит для временного хранилища значения. Больше он нигде не используется и чтение кода не вызовет затруднений.

В более сложных примерах использование слова tmp неоправданно и свидетельствует о лени программиста.

String tmp = user.name();
tmp += " " + user.phone_number();
text.setText("Пользователь: " + tmp);

Если речь идёт о временном файле, то используйте, например, вариант tmp_file. Одного взгляда на код будет достаточно, чтобы понять, что в выражении используется объект файла:

saveData(tmp_file, ...);

Сравните с вариантом:

saveData(tmp, ...);

Для итераторов в цикле обычно используют имена i, j, k. Поэтому не стоит использовать подобные имена в других местах вашего кода. С другой стороны и циклах тоже лучше использовать говорящие имена. Иногда это помогает избежать ошибок, особенно во вложенных циклах, когда можно перепутать имена переменных и использовать неправильные индексы для массивов.

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

string hex_id; // содержит "AF45CD98"
string id; // плохой вариант

Переменные, связанные с измерениями

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

int start_ms;
int elapsed_ms; // и т.д.

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

Аналогично можно поступать и с другими мерами измерений:

start(int delay_secs);
createCache(int size_mb);
downloadFile(float max_kbps);
rotate(float degrees_cw);

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

Стиль кодирования для Android

На официальном сайте для разработчиков есть отдельная страница Code Style Guidelines for Contributors, посвящённая правилам оформления кода для проектов, написанных под Android.

А также есть ещё одна страница правил - Google Java Style

Пишите красиво!

Реклама