Upload
yuri-afanasiev
View
1.039
Download
2
Embed Size (px)
Citation preview
Практические советы по улучшению качества кода
О себе• PHP разработчик более 5 лет
• Работа в компаниях
• СертификатыАфанасьев Юрий [email protected]
Почему важна читаемость?• Чтение кода происходит чаще, нежели чем его написание
• Чем проще читать код, тем легче его сопровождать и находить в нём баги
• Эстетическое восприятие влияет на многие показатели удобства работы с кодом и его поддержку
3
Что делает этот код?
function calculate() {
return (hours + overtime * rate) * days * gradeRate
}
4
Бывает и хуже…
function result() {
return (hrs + plus_time * rate) * number * level
}
5
Плохо оформленный код• Неприятно изучать и читать
• В нём сложно найти баги
• Возникают проблемы сопровождения и поддержки
• Его сложно дописывать, исправлять и что-либо с ним делать
• Происходит постоянное наращивание кома никому непонятного кода
• В конечном виде код превращается в спагетти-код
6
Стандарты кодирования• Java: Sun Microsystems
• Python: PEP-8
• PHP: PSR
• JavaScript: JSCS, Google Style Guide
7
Примерclass Booking {
function calculate (Cargo cargo, Voyage voyage) {
float maxBooking = voyage.Capacity() * 1,1
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
return false
}
return true
}
}
8
Магические числа
Магические числаЭто числа, такие как 100 или 32767, которые появляются в программе без объяснений
Строковые значения (например, ’creditcard’) могут также являться магическими числами
10
Что здесь не так?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
float maxBooking = voyage.Capacity() * 1,1
const float OVERBOOKING = 1,1
float maxBooking = voyage.Capacity() * OVERBOOKING
12
В чём удобство констант?• Улучшает понимание значения числа за счёт именованной константы
• Проще заменить значения таких чисел во всём коде
• Код становится легко читаемым и понятным
13
ИсключениеЧисла исключения - 0 и 1 (если семантически означают начало отсчёта)
integer maxRange = 10000
for (n = 0; n < maxRange; ++n) {
// ....
}
14
if (codeStatus == 403) {
const integer FORBIDDEN = 403
if (codeStatus == FORBIDDEN) {
15
Методы в классах
Что такое метод?Метод - это отдельная функция или процедура, выполняющая одну задачу
17
Что здесь не так?class Booking {
function calculate (Cargo cargo, Voyage voyage) {
float maxBooking = voyage.Capacity() * 1,1
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
return false
}
return true
}
}
18
float maxBooking = voyage.Capacity() * 1,1
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
if (
voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)
) {
19
Цель методаМетод должен выполнять лишь одну четко определенную цель: запись в БД, выполнение сложных вычислений и т.д.
См. принципы SOLID (принцип одной ответственности SPR)
20
function calculate (Cargo cargo, Voyage voyage) {
function isFull (Cargo cargo, Voyage voyage) {
21
Именование методов• Описывайте все действия, происходящие в методе. Например, sendRequest(), computeRecordDetails()
• Избегайте побочных действий в методах!
• Метод должен выражать действие, поэтому первое слово всегда глагол. Например, getBankById(Id)
• Избегайте невыразительных имен. Например, handleOutput(), formatAndPrintOutput()
22
Вложенность кода
Что здесь не так?if (checkEmpty(message)) {
// … some code
if (maxValue < 100) {
// some code
if (foo->isValid()) {
// … save
} else {
logErrors();
}
}
}
24
Проблема вложенности• Вложенность более 3-4 уровней сложно понять и удержать в голове
• Глубокая вложенность говорит о том, что код нужно рефакторить
25
Как избавиться?• Переписать условия проверки if-else и циклов. Например, чаще использовать блок выхода (return)
• Разбить код на небольшие методы
26
Перепишем пример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
Комментарии
Комментирование кода/* Убрано до лучших времён, которые вот-вот наступят
if (something) { return false } else { return true } */
GIT/SVN хранят историю изменений. Такие комментарии сродни мусору в квартире
30
Волшебный TODO// TODO: упрощённая реализация алгоритма
// Отрефакторить в задаче ETC-1510
• Указывайте все недоработки сразу и заводите на них задачи
• Каждый такой комментарий указывает на недоработку (потенциальную уязвимость)
31
Пояснения в начале файла/* @author Testof Tester Testorovich
@changes 01.01.2016 bug fix
@example new A() */
• В совместном проекте нет единого автора, т.к. каждый вносит свою лепту
• Историю изменений хранит git
• Пример использования может устареть
32
Описание намерений// Проверка на загруженность транспортного средства
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
• Такой код чаще всего некачественный
• Комментарии часто устаревают
• Между комментарием и кодом может появиться другой код (!)
33
Как избавиться?• Куски кода выделяйте в методы или классы if (voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)) {
• Строкам присваивайте пояснительные переменные или константы
const double OVERBOOKING = 1,1
float maxBooking = voyage.Capacity * OVERBOOKING
34
Принцип DRYDon’t Repeat Yourself
float maxBooking = voyage.Capacity() * 1,1
if (voyage.bookedCargoSize() + cargo.size() > maxBooking) {
if (
voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)
) {
36
Один и только один разПовторяющиеся куски кода указывают на упущенную возможность для абстракции
Дублирующий код чаще выделяют в отдельный метод, реже - класс
37
Де жа вю?• Куски кода выделяйте в методы или классы if (voyage.bookedCargoSize() + cargo.size() > this.getMaxBooking(voyage)) {
38
Польза DRY• Другие разработчики могут воспользоваться вашим кодом и не выдумывать его самим
• Выделение абстракций повышает скорость разработки и уменьшает число ошибок
• Дублирующиеся части могут содержать различные реализации и разные ошибки
39
Проблемаfunction findByName(name) { // …
sql = ‘SELECT * FROM bar WHERE name = ’ . name
// …
}
function findById (id) {
// … sql = ‘SELECT * FROM bar WHERE id = ’ . id
// …
}
40
Решениеfunction findByName(name) { // …
sql = findBy(‘name’, name)
// …
}
function findById (id) {
// … sql = findBy(‘id’, id)
// …
}
41
Ложка дёгтяСледование принципу неоправданно, если • Объединение реализаций плохо связанных сущностей (отзывы и комментарии)
• Код разных версий api
• В highload проектах (денормализация БД) • И так далее
Принцип наименьшего удивления
Что делает этот код?
date.add(5)
44
Помните этот пример?
function result() {
return (hrs + plus_time * rate) * number * level
}
45
Несколько правилПишите код так, чтобы он никого не удивлял
• Константы, методы должны располагаться на своём уровне абстракции
• Название метода должно соответствовать тому, что оно действительно выполняет
• Избавляйтесь от побочных эффектов в коде
46
Выводы
Код должен выражать намерения разработчика!
Магические числа, длинные и сложные выражения и т.д. - скрывают намерения автора
И напоследок• В первую очередь, используйте стандарты, принятые в вашей компании
• Книги и статьи дают лишь рекомендации. Как использовать полученные знания решать вам
• Не переусердствуйте в своём желании улучшить мир кодом. Придерживайтесь золотой середины
49
Книги и ссылки
Совершенный код
Стив Макконнелл
Чистый кодРоберт Мартин
http://habrahabr.ru/post/266969/
http://geekbrains.ru/events/124
Ссылки
Вопросы?