2. О себе
• PHP разработчик более 5 лет
• Работа в компаниях
• Сертификаты
Афанасьев Юрий
oriand@yandex.ru
3. Почему важна читаемость?
• Чтение кода происходит чаще, нежели чем его
написание
• Чем проще читать код, тем легче его
сопровождать и находить в нём баги
• Эстетическое восприятие влияет на многие
показатели удобства работы с кодом и его
поддержку
3
4. Что делает этот код?
function calculate() {
return (hours + overtime * rate) * days * gradeRate
}
4
6. Плохо оформленный код
• Неприятно изучать и читать
• В нём сложно найти баги
• Возникают проблемы сопровождения и поддержки
• Его сложно дописывать, исправлять и что-либо с ним
делать
• Происходит постоянное наращивание кома никому
непонятного кода
• В конечном виде код превращается в спагетти-код
6
10. Магические числа
Это числа, такие как 100 или 32767, которые
появляются в программе без объяснений
Строковые значения (например, ’creditcard’) могут
также являться магическими числами
10
11. Что здесь не так?
class Booking {
function calculate (Cargo cargo, Voyage voyage) {
float maxBooking = voyage.Capacity() * 1,1
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
return false
}
return true
}
}
11
13. В чём удобство констант?
• Улучшает понимание значения числа за счёт
именованной константы
• Проще заменить значения таких чисел во всём
коде
• Код становится легко читаемым и понятным
13
14. Исключение
Числа исключения - 0 и 1 (если семантически
означают начало отсчёта)
integer maxRange = 10000
for (n = 0; n < maxRange; ++n) {
// ....
}
14
15. if (codeStatus == 403) {
const integer FORBIDDEN = 403
if (codeStatus == FORBIDDEN) {
15
20. Цель метода
Метод должен выполнять лишь одну четко
определенную цель: запись в БД, выполнение
сложных вычислений и т.д.
См. принципы SOLID (принцип одной
ответственности SPR)
20
22. Именование методов
• Описывайте все действия, происходящие в методе.
Например, sendRequest(), computeRecordDetails()
• Избегайте побочных действий в методах!
• Метод должен выражать действие, поэтому первое
слово всегда глагол. Например, getBankById(Id)
• Избегайте невыразительных имен.
Например, handleOutput(), formatAndPrintOutput()
22
24. Что здесь не так?
if (checkEmpty(message)) {
// … some code
if (maxValue < 100) {
// some code
if (foo->isValid()) {
// … save
} else {
logErrors();
}
}
}
24
25. Проблема вложенности
• Вложенность более 3-4 уровней сложно понять и
удержать в голове
• Глубокая вложенность говорит о том, что код
нужно рефакторить
25
26. Как избавиться?
• Переписать условия проверки if-else и циклов.
Например, чаще использовать блок выхода (return)
• Разбить код на небольшие методы
26
27. Перепишем пример
if ( !checkEmpty(message)) {
return
}
// … some code
if (maxValue > 100) {
return
}
// … some code
if (foo->isValid()) {
// … save
} else {
logErrors();
}
if (checkEmpty(message)) {
// … some code
if (maxValue < 100) {
// some code
if (foo->isValid()) {
// … save
} else {
logErrors();
}
}
}
27
28. В идеале
Пишите код таким, чтобы он читался словно книга
без постоянного перевода взгляда вверх и вниз
страницы
28
30. Комментирование кода
/* Убрано до лучших времён, которые вот-вот наступят
if (something) { return false } else { return true } */
GIT/SVN хранят историю изменений. Такие
комментарии сродни мусору в квартире
30
31. Волшебный TODO
// TODO: упрощённая реализация алгоритма
// Отрефакторить в задаче ETC-1510
• Указывайте все недоработки сразу и заводите на
них задачи
• Каждый такой комментарий указывает на
недоработку (потенциальную уязвимость)
31
32. Пояснения в начале файла
/* @author Testof Tester Testorovich
@changes 01.01.2016 bug fix
@example new A() */
• В совместном проекте нет единого автора, т.к.
каждый вносит свою лепту
• Историю изменений хранит git
• Пример использования может устареть
32
33. Описание намерений
// Проверка на загруженность транспортного средства
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
• Такой код чаще всего некачественный
• Комментарии часто устаревают
• Между комментарием и кодом может появиться
другой код (!)
33
34. Как избавиться?
• Куски кода выделяйте в методы или классы
if (voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)) {
• Строкам присваивайте пояснительные
переменные или константы
const double OVERBOOKING = 1,1
float maxBooking = voyage.Capacity * OVERBOOKING
34
37. Один и только один раз
Повторяющиеся куски кода указывают на
упущенную возможность для абстракции
Дублирующий код чаще выделяют в отдельный
метод, реже - класс
37
38. Де жа вю?
• Куски кода выделяйте в методы или классы
if (voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)) {
38
39. Польза DRY
• Другие разработчики могут воспользоваться
вашим кодом и не выдумывать его самим
• Выделение абстракций повышает скорость
разработки и уменьшает число ошибок
• Дублирующиеся части могут содержать
различные реализации и разные ошибки
39
40. Проблема
function findByName(name) {
// …
sql = ‘SELECT * FROM bar WHERE name = ’ . name
// …
}
function findById (id) {
// …
sql = ‘SELECT * FROM bar WHERE id = ’ . id
// …
}
40
42. Ложка дёгтя
Следование принципу неоправданно, если
• Объединение реализаций плохо связанных
сущностей (отзывы и комментарии)
• Код разных версий api
• В highload проектах (денормализация БД)
• И так далее
46. Несколько правил
Пишите код так, чтобы он никого не удивлял
• Константы, методы должны располагаться на
своём уровне абстракции
• Название метода должно соответствовать тому,
что оно действительно выполняет
• Избавляйтесь от побочных эффектов в коде
46
48. Код должен выражать намерения разработчика!
Магические числа, длинные и сложные выражения
и т.д. - скрывают намерения автора
49. И напоследок
• В первую очередь, используйте стандарты,
принятые в вашей компании
• Книги и статьи дают лишь рекомендации. Как
использовать полученные знания решать вам
• Не переусердствуйте в своём желании улучшить
мир кодом. Придерживайтесь золотой середины
49