А пока поделюсь с вами книгой, которая, по моему личному мнению, абсолютный “маст рид” для разработчика приложений. Именно для разработчика, а не для труЪ программиста, который не считается труЪ, если не вызубрил Кнута. Ну а для обитателей грешной земли незаменимым руководством по разработке является “Совершенный код” Стива МакКоннелла. Сам перечитывал её несколько раз, а также посмотрел курс лекций самого Стива на https://construx.vueocity.com Решил освежить в памяти основные моменты, поэтому буду выкладывать периодически конспекты с лекций.
0. Введение
Основной концепцией создания программного обеспечения является концепция “Защитного программирования”. Точно так же, как вы смотрите по сторонам при переходе дороги, даже на зелёный свет, в создании ПО есть несколько принципов, которые помогут вам создавать качественный код с минимумом ошибок. Основные принципы:
1. Управление сложностью
2. Именование
3. Процесс программирования псевдокодом
4. Утверждения
5. Отладка
6. Оптимизация кода
7. Обработка ошибок
8. Предвидение изменений
В следующих постах разберу каждый принцип подробнее.
#CodeComplete
0. Введение
Основной концепцией создания программного обеспечения является концепция “Защитного программирования”. Точно так же, как вы смотрите по сторонам при переходе дороги, даже на зелёный свет, в создании ПО есть несколько принципов, которые помогут вам создавать качественный код с минимумом ошибок. Основные принципы:
1. Управление сложностью
2. Именование
3. Процесс программирования псевдокодом
4. Утверждения
5. Отладка
6. Оптимизация кода
7. Обработка ошибок
8. Предвидение изменений
В следующих постах разберу каждый принцип подробнее.
#CodeComplete
👍5
День девятый. #CodeComplete
1. Управление сложностью. Начало
Управление сложностью - самая важная задача при создании программного обеспечения. Два главных принципа управления сложностью:
1. Управляйте существенной сложностью (сложностью реальной проблемы). Например, делите программу на части, причём таким образом, чтобы работая над одной частью, можно было легко игнорировать другие части.
2. Избегайте случайной сложности (добавляемой в программу вами).
Приёмы проектирования для управления сложностью:
1. Иерархии
2. Сокрытие информации
3. Модуляризация
4. Инкапсуляция
5. Абстракция
6. Связность
7. Разделение ответственности
Важно: Пробуйте БОЛЕЕ ОДНОГО варианта проектирования. Не спешите реализовывать первый вариант, пришедший в голову.
1. Иерархии.
Иерархии – это естественный способ организации сложной информации. Используйте иерархии в ПО: многоуровневая информационная структура, иерархии модулей, иерархии классов.
2. Сокрытие информации
Цель: скрывайте сложность
Процедура:
- перечислите проектные решения, которые скорее всего будут изменены
- разработайте модули так, чтобы скрыть эти проектные решения
- разработайте интерфейсы модулей так, чтобы они не зависели от возможных изменений в модулях
Важно: Не жертвуйте удобством чтения кода во имя удобства его написания! Код читается гораздо чаще, чем пишется.
3. Модуляризация
Модуляризация основана на сокрытии информации.
Модули должны быть хорошо спроектированными чёрными ящиками, которые легко могут быть заменены.
4. Абстракция
Абстракция – это не то же самое, что инкапсуляция.
Абстракция позволяет вам смотреть на сложную информационную структуру в упрощённом виде. Хорошо спроектированный объект представляет из себя идеальную абстракцию (объект реального мира). У него есть только свойства и методы объекта реального мира и никаких других.
Абстракция – мощный инструмент управления сложностью.
Продолжение следует…
1. Управление сложностью. Начало
Управление сложностью - самая важная задача при создании программного обеспечения. Два главных принципа управления сложностью:
1. Управляйте существенной сложностью (сложностью реальной проблемы). Например, делите программу на части, причём таким образом, чтобы работая над одной частью, можно было легко игнорировать другие части.
2. Избегайте случайной сложности (добавляемой в программу вами).
Приёмы проектирования для управления сложностью:
1. Иерархии
2. Сокрытие информации
3. Модуляризация
4. Инкапсуляция
5. Абстракция
6. Связность
7. Разделение ответственности
Важно: Пробуйте БОЛЕЕ ОДНОГО варианта проектирования. Не спешите реализовывать первый вариант, пришедший в голову.
1. Иерархии.
Иерархии – это естественный способ организации сложной информации. Используйте иерархии в ПО: многоуровневая информационная структура, иерархии модулей, иерархии классов.
2. Сокрытие информации
Цель: скрывайте сложность
Процедура:
- перечислите проектные решения, которые скорее всего будут изменены
- разработайте модули так, чтобы скрыть эти проектные решения
- разработайте интерфейсы модулей так, чтобы они не зависели от возможных изменений в модулях
Важно: Не жертвуйте удобством чтения кода во имя удобства его написания! Код читается гораздо чаще, чем пишется.
3. Модуляризация
Модуляризация основана на сокрытии информации.
Модули должны быть хорошо спроектированными чёрными ящиками, которые легко могут быть заменены.
4. Абстракция
Абстракция – это не то же самое, что инкапсуляция.
Абстракция позволяет вам смотреть на сложную информационную структуру в упрощённом виде. Хорошо спроектированный объект представляет из себя идеальную абстракцию (объект реального мира). У него есть только свойства и методы объекта реального мира и никаких других.
Абстракция – мощный инструмент управления сложностью.
Продолжение следует…
👍3
День двенадцатый. #CodeComplete
1. Управление сложностью. Окончание
5. Инкапсуляция
Инкапсуляция – это не то же самое, что абстракция.
- Инкапсуляция не позволяет вам смотреть на упрощённую информационную структуру в усложнённом виде.
- Скрывайте детали за хорошо спроектированным интерфейсом, чтобы избежать программирования «сквозь» интерфейс (использовать класс, зная о деталях его реализации).
- Сосредоточьте своё внимание на интерфейсах. Реализация интерфейса воздействует только на качество кода. Качество интерфейса воздействует на срок жизни, расширяемость, масштабируемость и т.п. программного обеспечения в целом.
6. Связность
- Каждый метод/класс должен решать РОВНО ОДНУ задачу!
- Сложность создания ясного имени для метода или класса часто тревожный знак плохой его связности. Это не проблема именования, это проблема дизайна.
7. Разделение ответственности
- Основная идея – «Разделяй и властвуй»
- Пытайтесь разделять программу на сферы ответственности
- Разделение ответственности применяется к более высоким уровням проектирования, например, разделению на подсистемы (см. картинку ниже).
- Часто разделение невыполнимо из-за синтаксиса языка.
1. Управление сложностью. Окончание
5. Инкапсуляция
Инкапсуляция – это не то же самое, что абстракция.
- Инкапсуляция не позволяет вам смотреть на упрощённую информационную структуру в усложнённом виде.
- Скрывайте детали за хорошо спроектированным интерфейсом, чтобы избежать программирования «сквозь» интерфейс (использовать класс, зная о деталях его реализации).
- Сосредоточьте своё внимание на интерфейсах. Реализация интерфейса воздействует только на качество кода. Качество интерфейса воздействует на срок жизни, расширяемость, масштабируемость и т.п. программного обеспечения в целом.
6. Связность
- Каждый метод/класс должен решать РОВНО ОДНУ задачу!
- Сложность создания ясного имени для метода или класса часто тревожный знак плохой его связности. Это не проблема именования, это проблема дизайна.
7. Разделение ответственности
- Основная идея – «Разделяй и властвуй»
- Пытайтесь разделять программу на сферы ответственности
- Разделение ответственности применяется к более высоким уровням проектирования, например, разделению на подсистемы (см. картинку ниже).
- Часто разделение невыполнимо из-за синтаксиса языка.
День пятнадцатый. #CodeComplete
2. Именование
1. Имена переменных
Обычно имена переменных, которые недостаточно конкретны, чтобы быть использованы только для одной цели в процедуре, это плохие имена.
- Имя переменной должно быть существительным, описывающим реальную сущность
- Не используйте префиксы, обозначающие тип переменной или отделяющие поля класса от локальных переменных (“
- Делайте имена переменным настолько конкретными, насколько это возможно
- Чем очевиднее, тем лучше
- Чем ближе имя к сущности реального мира, тем обычно оно более полезно
2. Именование методов
- Описывайте в имени всё, что делает метод (либо разбейте его на несколько)
- Делайте имена настолько длинными, насколько можно
- Бессмысленные или неопределённые глаголы (
- Приближайте имена к необходимому уровню абстракции, чтобы скрыть детали реализации метода
- Делайте имена методов настолько высокоуровневыми (близкими бизнес-логике или к реальному миру), насколько это возможно
3. Соглашения об именовании
- утвердите соглашение о согласованном наименовании стандартных операций, например,
- избегайте ненужных вариаций: сокращения, непонятные аббревиатуры, смесь языков и т.п. (
2. Именование
1. Имена переменных
Обычно имена переменных, которые недостаточно конкретны, чтобы быть использованы только для одной цели в процедуре, это плохие имена.
- Имя переменной должно быть существительным, описывающим реальную сущность
- Не используйте префиксы, обозначающие тип переменной или отделяющие поля класса от локальных переменных (“
__...
”, “m_...
”, “s_...
”, “i_...
” и т.п.)- Делайте имена переменным настолько конкретными, насколько это возможно
- Чем очевиднее, тем лучше
- Чем ближе имя к сущности реального мира, тем обычно оно более полезно
2. Именование методов
- Описывайте в имени всё, что делает метод (либо разбейте его на несколько)
- Делайте имена настолько длинными, насколько можно
- Бессмысленные или неопределённые глаголы (
Calc
, HandleClass
, ProcessInput
и т.п.) – тревожный знак- Приближайте имена к необходимому уровню абстракции, чтобы скрыть детали реализации метода
- Делайте имена методов настолько высокоуровневыми (близкими бизнес-логике или к реальному миру), насколько это возможно
3. Соглашения об именовании
- утвердите соглашение о согласованном наименовании стандартных операций, например,
user.GetID()
или user.ID.Get()
- то же касается стандартных аббревиатур и языковых вариаций (color
/colour
)- избегайте ненужных вариаций: сокращения, непонятные аббревиатуры, смесь языков и т.п. (
totalCount
/ttlCnt
/itog
, firstName
/fName
/firstNm
/FN
/imya
).День восемнадцатый. #CodeComplete
3. Процесс Программирования с Псевдокодом
При проектировании сложных или объёмных методов сложно написать метод от начала до конца из головы. В этих случаях помогает процесс программирования с псевдокодом. Он состоит из нескольких этапов:
1. Напишите, что должен делать каждый блок кода на естественном языке, используя комментарии (это будет псевдокод).
Комментарии должны быть на достаточно высоком уровне, чтобы не дублировать то, что будет написано в коде, а объяснять, что делает блок кода. Например, вместо:
используйте
3. Напишите код каждого блока под каждым блоком комментариев.
Применяйте ППП рекурсивно, если нужно. Например, если блок написан слишком общими словами, которые сложно сразу перевести в код, примените ППП к этому блоку (рассмотрите возможность вынести этот блок в отдельный метод).
4. Оставьте псевдокод в виде комментариев.
Преимущества ППП:
- Упрощает изначальное написание кода
- Упрощает обзор кода
- Приводит к лучше организованному коду
- Автоматизирует процесс добавления комментариев
- Упрощает возвращение к работе, если вас прервали на середине
- Сокращает количество ошибок, поскольку процесс позволяет (вынуждает) вас больше думать о правильном проектировании метода
3. Процесс Программирования с Псевдокодом
При проектировании сложных или объёмных методов сложно написать метод от начала до конца из головы. В этих случаях помогает процесс программирования с псевдокодом. Он состоит из нескольких этапов:
1. Напишите, что должен делать каждый блок кода на естественном языке, используя комментарии (это будет псевдокод).
Комментарии должны быть на достаточно высоком уровне, чтобы не дублировать то, что будет написано в коде, а объяснять, что делает блок кода. Например, вместо:
// для каждого i меньше длины массива objectArr
используйте
// перебираем все объекты массива в цикле2. Проверьте весь псевдокод метода. Добавьте более детальные комментарии там, где это необходимо.
3. Напишите код каждого блока под каждым блоком комментариев.
Применяйте ППП рекурсивно, если нужно. Например, если блок написан слишком общими словами, которые сложно сразу перевести в код, примените ППП к этому блоку (рассмотрите возможность вынести этот блок в отдельный метод).
4. Оставьте псевдокод в виде комментариев.
Преимущества ППП:
- Упрощает изначальное написание кода
- Упрощает обзор кода
- Приводит к лучше организованному коду
- Автоматизирует процесс добавления комментариев
- Упрощает возвращение к работе, если вас прервали на середине
- Сокращает количество ошибок, поскольку процесс позволяет (вынуждает) вас больше думать о правильном проектировании метода
👍2
День двадцать второй. #CodeComplete
4. Утверждения
Утверждение – условие, которое всегда верно; предположение о дизайне, на котором основана процедура.
- документируйте предположения о дизайне через утверждения вместо комментариев;
- документируйте условия, которые всегда верны – в 100% случаев;
- если проверка утверждения терпит неудачу, правильное действие – изменить и перекомпилировать код;
- концептуально утверждение — это помощь при разработке, оно не используется в продакшн-коде (удаляется при компиляции).
Роль утверждений:
- полезны при использовании метода проектирования по контракту (с предусловиями и постусловиями);
- полезны в больших и сложных программах;
- используются как защитная техника, чтобы люди правильно использовали ваш код.
Важно:
Не путайте утверждения с обработкой ошибок!
4. Утверждения
Утверждение – условие, которое всегда верно; предположение о дизайне, на котором основана процедура.
- документируйте предположения о дизайне через утверждения вместо комментариев;
- документируйте условия, которые всегда верны – в 100% случаев;
- если проверка утверждения терпит неудачу, правильное действие – изменить и перекомпилировать код;
- концептуально утверждение — это помощь при разработке, оно не используется в продакшн-коде (удаляется при компиляции).
Роль утверждений:
- полезны при использовании метода проектирования по контракту (с предусловиями и постусловиями);
- полезны в больших и сложных программах;
- используются как защитная техника, чтобы люди правильно использовали ваш код.
Важно:
Не путайте утверждения с обработкой ошибок!
День двадцать седьмой. #CodeComplete
5. Отладка
Иногда бывает полезным проходить новый код по шагам в отладчике, наблюдая за изменением значений переменных. Это может быть формой самостоятельного обзора кода. Кроме того, это помогает уменьшить временной интервал между внесением ошибки и обнаружением её.
Этапы отладки:
1) Стабилизация ошибки. Найдите сценарий, при котором ошибка всегда проявляется.
2) Локализация источника ошибки. Точно найдите место в коде, где возникает ошибка.
3) Исправление ошибки.
4) Проверка и тестирование исправления.
5) Поиск похожих ошибок. Определите тип ошибки и проверьте, нет ли в остальном коде ошибок этого типа.
Советы по обнаружению ошибок
Следующие советы не обязательно применимы ко всем случаям, но могут помочь в некоторых сложных ситуациях:
- используйте все доступные данные для формулирования гипотезы о сути ошибки;
- создайте точные тесты, которые приводят к ошибке;
- воссоздайте ошибку несколькими разными способами;
- по ситуации: сузьте/расширьте сектор кода для поиска ошибки;
- проверьте методы, которые имели ошибки ранее (часто исправление одной ошибки приводит к возникновению другой);
- проверьте недавно изменённый код;
- проверьте код на типичные ошибки (широко распространённые вообще, вроде деления на ноль, нулевых указателей, выхода за границы массива и т.п., либо типичные для вашей области/организации/вас лично);
- поговорите с другим человеком (обзор кода): часто просто объяснение проблемы кому-то другому помогает понять, что не так;
- сделайте паузу: займитесь чем-то отвлечённым на некоторое время;
- прочитайте все предупреждения компилятора: предупреждения компилятора не сообщают об ошибках напрямую, но могут свидетельствовать о недостатках в коде, приводящих к ошибкам в связанных с этим блоком местах;
- проверьте, не является ли это ошибкой проектирования: плохо спроектированный класс или метод иногда проще переписать заново, чем постоянно исправлять;
- проверьте, нет ли ошибки в тестовых данных: написанию тестов обычно уделяют меньше внимания, чем основному коду, поэтому ошибки в тестах встречаются гораздо чаще;
- изначально избегайте ошибок: правильное проектирование и написание кода приводит к значительному сокращению количества ошибок.
Инструкция по исправлению ошибки:
1) убедитесь, что вы понимаете проблему, прежде чем исправлять её;
2) убедитесь, что вы понимаете всю программу, а не только проблемную часть;
3) подтвердите диагноз: убедитесь с помощью различных тестов, что ошибка именно здесь и именно в этом;
4) расслабьтесь :)
5) сохраните исходный вариант кода (системы управления версиями очень помогают);
6) делайте ОДНО исправление за раз: не пытайтесь исправить сразу несколько ошибок одновременно, это приводит к возникновению новых ошибок;
7) проверьте ваше исправление;
8) выполните юнит-тесты (не только относящиеся к исправлению, чтобы проверить, не привело ли исправление к ошибкам в других местах);
9) выполните интеграционные тесты с изменённым кодом;
10) поищите похожие ошибки.
Отладка с применением грубой силы
1) Установите максимальное время на отладку обычным способом, а потом рассмотрите вариант перехода на отладку грубой силой.
2) Составьте список вещей, которые стоит проверить.
Примеры отладки грубой силой:
- переписывание кода с нуля;
- компиляция кода с полной отладочной информацией;
- установка прерывания на каждом исключении;
- создание набора автоматизированных тестов и запуск их на всю ночь;
- выполнение полного обзора проекта/кода;
- точное воссоздание конфигурации оборудования конечного пользователя.
5. Отладка
Иногда бывает полезным проходить новый код по шагам в отладчике, наблюдая за изменением значений переменных. Это может быть формой самостоятельного обзора кода. Кроме того, это помогает уменьшить временной интервал между внесением ошибки и обнаружением её.
Этапы отладки:
1) Стабилизация ошибки. Найдите сценарий, при котором ошибка всегда проявляется.
2) Локализация источника ошибки. Точно найдите место в коде, где возникает ошибка.
3) Исправление ошибки.
4) Проверка и тестирование исправления.
5) Поиск похожих ошибок. Определите тип ошибки и проверьте, нет ли в остальном коде ошибок этого типа.
Советы по обнаружению ошибок
Следующие советы не обязательно применимы ко всем случаям, но могут помочь в некоторых сложных ситуациях:
- используйте все доступные данные для формулирования гипотезы о сути ошибки;
- создайте точные тесты, которые приводят к ошибке;
- воссоздайте ошибку несколькими разными способами;
- по ситуации: сузьте/расширьте сектор кода для поиска ошибки;
- проверьте методы, которые имели ошибки ранее (часто исправление одной ошибки приводит к возникновению другой);
- проверьте недавно изменённый код;
- проверьте код на типичные ошибки (широко распространённые вообще, вроде деления на ноль, нулевых указателей, выхода за границы массива и т.п., либо типичные для вашей области/организации/вас лично);
- поговорите с другим человеком (обзор кода): часто просто объяснение проблемы кому-то другому помогает понять, что не так;
- сделайте паузу: займитесь чем-то отвлечённым на некоторое время;
- прочитайте все предупреждения компилятора: предупреждения компилятора не сообщают об ошибках напрямую, но могут свидетельствовать о недостатках в коде, приводящих к ошибкам в связанных с этим блоком местах;
- проверьте, не является ли это ошибкой проектирования: плохо спроектированный класс или метод иногда проще переписать заново, чем постоянно исправлять;
- проверьте, нет ли ошибки в тестовых данных: написанию тестов обычно уделяют меньше внимания, чем основному коду, поэтому ошибки в тестах встречаются гораздо чаще;
- изначально избегайте ошибок: правильное проектирование и написание кода приводит к значительному сокращению количества ошибок.
Инструкция по исправлению ошибки:
1) убедитесь, что вы понимаете проблему, прежде чем исправлять её;
2) убедитесь, что вы понимаете всю программу, а не только проблемную часть;
3) подтвердите диагноз: убедитесь с помощью различных тестов, что ошибка именно здесь и именно в этом;
4) расслабьтесь :)
5) сохраните исходный вариант кода (системы управления версиями очень помогают);
6) делайте ОДНО исправление за раз: не пытайтесь исправить сразу несколько ошибок одновременно, это приводит к возникновению новых ошибок;
7) проверьте ваше исправление;
8) выполните юнит-тесты (не только относящиеся к исправлению, чтобы проверить, не привело ли исправление к ошибкам в других местах);
9) выполните интеграционные тесты с изменённым кодом;
10) поищите похожие ошибки.
Отладка с применением грубой силы
1) Установите максимальное время на отладку обычным способом, а потом рассмотрите вариант перехода на отладку грубой силой.
2) Составьте список вещей, которые стоит проверить.
Примеры отладки грубой силой:
- переписывание кода с нуля;
- компиляция кода с полной отладочной информацией;
- установка прерывания на каждом исключении;
- создание набора автоматизированных тестов и запуск их на всю ночь;
- выполнение полного обзора проекта/кода;
- точное воссоздание конфигурации оборудования конечного пользователя.
👍1
День тридцать первый. #CodeComplete
6. Оптимизация кода
Оптимизация кода – это изменение программы на уровне детального кодирования с сохранением семантики кода с целью улучшения производительности.
К оптимизации кода не относятся:
- выбор алгоритма;
- изначальная разработка, нацеленная на высокую производительность.
Правила оптимизации:
1. НЕ ДЕЛАЙТЕ ЭТОГО!
2. (только для экспертов) Не делайте этого… пока. До тех пор, пока у вас нет идеального, но неоптимизированного решения.
Защитный подход к оптимизации кода:
1. Пишите изначальный код, делая акцент на простоту, читаемость, удобство сопровождения, модульность и т.п.
!!! Только если производительность неудовлетворительная !!!
2. Измерьте слабые места производительности.
3. Внедрите изменения с сохранением семантики ПО ОДНОМУ ЗА РАЗ.
4. Измерьте каждое изменение; отмените 2/3 изменений, которые не улучшили производительность.
5. Повторяйте, пока не будет достигнут желаемый результат.
ВАЖНО:
1. Нужно измерить, чтобы быть уверенным.
2. Если вы не измерили, вы НЕ МОЖЕТЕ БЫТЬ УВЕРНЫ!
Общие принципы:
1. Результаты зачастую контринтуитивны. Попытки оптимизировать код, основываясь на теоретических предположениях о скорости работы того или иного кода, часто приводят к замедлению программы.
2. Результаты различаются в зависимости от языков, компиляторов, версий компиляторов.
Не думайте, что вы умнее компилятора и его создателей. В подавляющем большинстве случаев компилятор создаёт более эффективный машинный код из стандартных блоков кода, чем из «хитро оптимизированного» вами кода.
6. Оптимизация кода
Оптимизация кода – это изменение программы на уровне детального кодирования с сохранением семантики кода с целью улучшения производительности.
К оптимизации кода не относятся:
- выбор алгоритма;
- изначальная разработка, нацеленная на высокую производительность.
Правила оптимизации:
1. НЕ ДЕЛАЙТЕ ЭТОГО!
2. (только для экспертов) Не делайте этого… пока. До тех пор, пока у вас нет идеального, но неоптимизированного решения.
Защитный подход к оптимизации кода:
1. Пишите изначальный код, делая акцент на простоту, читаемость, удобство сопровождения, модульность и т.п.
!!! Только если производительность неудовлетворительная !!!
2. Измерьте слабые места производительности.
3. Внедрите изменения с сохранением семантики ПО ОДНОМУ ЗА РАЗ.
4. Измерьте каждое изменение; отмените 2/3 изменений, которые не улучшили производительность.
5. Повторяйте, пока не будет достигнут желаемый результат.
ВАЖНО:
1. Нужно измерить, чтобы быть уверенным.
2. Если вы не измерили, вы НЕ МОЖЕТЕ БЫТЬ УВЕРНЫ!
Общие принципы:
1. Результаты зачастую контринтуитивны. Попытки оптимизировать код, основываясь на теоретических предположениях о скорости работы того или иного кода, часто приводят к замедлению программы.
2. Результаты различаются в зависимости от языков, компиляторов, версий компиляторов.
Не думайте, что вы умнее компилятора и его создателей. В подавляющем большинстве случаев компилятор создаёт более эффективный машинный код из стандартных блоков кода, чем из «хитро оптимизированного» вами кода.
День тридцать четвёртый. #CodeComplete
7. Обработка ошибок
Ситуации, в которых требуется обработка ошибок, возникают, когда значения данных
- выходят за границы,
- необычного характера,
- неверного типа,
- не определены,
- неполные,
- избыточные,
- несоответствующие,
и т.п.
Решения по обработке ошибок:
1. Что программа делает с неверными данными?
2. Нужно ли обрабатывать все возможные ошибки или только самые основные?
3. Какая часть (части) программы ответственны за это?
4. Какие механизмы языка использовать для обработки ошибок?
5. Должны ли все ошибки обрабатываться одинаково?
6. Должны ли все части программы обрабатывать ошибки одинаково?
7. Являются ли эти решения решениями уровня кодирования, проектирования, архитектуры?
Варианты обработки ошибок в списке ниже представлены для использования в системах от наиболее устойчивых до наиболее корректных. В устойчивых системах (пользовательских приложениях) можно выдать хоть какой-нибудь результат, даже неточный. Например, в видеоигре выдать цвет соседнего пикселя или в потоке некритичных данных выдать предыдущее значение. В корректных системах (где безопасность данных критична) важен только точный результат. В противном случае лучше завершить работу приложения, чем выдавать ошибочные данные. Например, машине МРТ лучше выдать ошибку, чем выдать неверный снимок.
1. Использовать нейтральное значение
- null, 0, пустую строку
2. Заменить следующим верным значением
- следующая запись в базе, следующие данные, прочитанные с датчика
3. Выдать тот же ответ, что и в предыдущий раз
- та же температура термометра, ближайшее максимальное/минимальное значение
4. Записать сообщение в лог
- полезно при отладке (стоит обратить внимание на защищённость логов)
5. Вернуть код ошибки
- решение на уровне архитектуры приложения
- некоторые модули могут просто передавать ошибку на верхние уровни и рассчитывать, что она будет обработана там
6. Вызвать объект/процедуру обработки ошибок
- в этом случае обработка ошибок централизована
- вся программа должна знать об этой централизованной возможности и быть связана с ней
7. Вывести сообщение об ошибке
- ошибки обрабатываются локально
- способ обработки отдельных ошибок оставлен на откуп низким уровням (там выбирается наиболее подходящий в конкретном случае)
- имеет потенциальную опасность распространения кода пользовательского интерфейса по всему приложению
8. Завершить работу
- наиболее корректный способ
- используется в приложениях, для которых критична безопасность
Важность обработки ошибок:
- влияет на всю систему приложения (в разных приложениях это 25-75% всего кода);
- влияет на производительность всего приложения;
- это решение на уровне архитектуры приложения. Вы бы не хотели, чтобы обработка ошибок в приложении осуществлялась случайным образом и разным способом в каждом случае.
7. Обработка ошибок
Ситуации, в которых требуется обработка ошибок, возникают, когда значения данных
- выходят за границы,
- необычного характера,
- неверного типа,
- не определены,
- неполные,
- избыточные,
- несоответствующие,
и т.п.
Решения по обработке ошибок:
1. Что программа делает с неверными данными?
2. Нужно ли обрабатывать все возможные ошибки или только самые основные?
3. Какая часть (части) программы ответственны за это?
4. Какие механизмы языка использовать для обработки ошибок?
5. Должны ли все ошибки обрабатываться одинаково?
6. Должны ли все части программы обрабатывать ошибки одинаково?
7. Являются ли эти решения решениями уровня кодирования, проектирования, архитектуры?
Варианты обработки ошибок в списке ниже представлены для использования в системах от наиболее устойчивых до наиболее корректных. В устойчивых системах (пользовательских приложениях) можно выдать хоть какой-нибудь результат, даже неточный. Например, в видеоигре выдать цвет соседнего пикселя или в потоке некритичных данных выдать предыдущее значение. В корректных системах (где безопасность данных критична) важен только точный результат. В противном случае лучше завершить работу приложения, чем выдавать ошибочные данные. Например, машине МРТ лучше выдать ошибку, чем выдать неверный снимок.
1. Использовать нейтральное значение
- null, 0, пустую строку
2. Заменить следующим верным значением
- следующая запись в базе, следующие данные, прочитанные с датчика
3. Выдать тот же ответ, что и в предыдущий раз
- та же температура термометра, ближайшее максимальное/минимальное значение
4. Записать сообщение в лог
- полезно при отладке (стоит обратить внимание на защищённость логов)
5. Вернуть код ошибки
- решение на уровне архитектуры приложения
- некоторые модули могут просто передавать ошибку на верхние уровни и рассчитывать, что она будет обработана там
6. Вызвать объект/процедуру обработки ошибок
- в этом случае обработка ошибок централизована
- вся программа должна знать об этой централизованной возможности и быть связана с ней
7. Вывести сообщение об ошибке
- ошибки обрабатываются локально
- способ обработки отдельных ошибок оставлен на откуп низким уровням (там выбирается наиболее подходящий в конкретном случае)
- имеет потенциальную опасность распространения кода пользовательского интерфейса по всему приложению
8. Завершить работу
- наиболее корректный способ
- используется в приложениях, для которых критична безопасность
Важность обработки ошибок:
- влияет на всю систему приложения (в разных приложениях это 25-75% всего кода);
- влияет на производительность всего приложения;
- это решение на уровне архитектуры приложения. Вы бы не хотели, чтобы обработка ошибок в приложении осуществлялась случайным образом и разным способом в каждом случае.
День тридцать седьмой. #CodeComplete
8. Предвидение изменений
Отличительной чертой великих разработчиков является то, что они предвидят больше источников изменений, чем разработчики среднего уровня.
Источники изменений:
- Зависимость от оборудования
- Форматы файлов
- Входящие и выходящие данные
- Нестандартный функционал языка
- Глобальные переменные
- Бизнес-правила
- Последовательность обработки элементов
- Требования, исключённые из текущей версии
- Функционал, запланированный на следующую версию
- И МНОГОЕ ДРУГОЕ…
Основные правила:
1. Используйте абстрактные интерфейсы.
2. Используйте именованные константы вместо жёстко прописанных литералов.
3. Используйте стратегии позднего связывания.
4. Используйте табличные техники (поиск значения в таблице вместо многоуровневых условных операторов).
5. Используйте процедуры вместо копирования кода.
6. Используйте простые процедуры, решающие одну простую задачу.
7. Разделяйте несвязанные между собой операторы.
8. Разделяйте код, реализующий основную функциональность, и специализированный код.
8. Предвидение изменений
Отличительной чертой великих разработчиков является то, что они предвидят больше источников изменений, чем разработчики среднего уровня.
Источники изменений:
- Зависимость от оборудования
- Форматы файлов
- Входящие и выходящие данные
- Нестандартный функционал языка
- Глобальные переменные
- Бизнес-правила
- Последовательность обработки элементов
- Требования, исключённые из текущей версии
- Функционал, запланированный на следующую версию
- И МНОГОЕ ДРУГОЕ…
Основные правила:
1. Используйте абстрактные интерфейсы.
2. Используйте именованные константы вместо жёстко прописанных литералов.
3. Используйте стратегии позднего связывания.
4. Используйте табличные техники (поиск значения в таблице вместо многоуровневых условных операторов).
5. Используйте процедуры вместо копирования кода.
6. Используйте простые процедуры, решающие одну простую задачу.
7. Разделяйте несвязанные между собой операторы.
8. Разделяйте код, реализующий основную функциональность, и специализированный код.
День сороковой. #CodeComplete
Командная работа
Важно:
1. По статистике код в среднем «переживает» до 10 поколений поддерживающих его программистов.
2. Программисты, поддерживающие код, проводят 50-60% своего времени, читая код.
Поэтому критически важно писать код, который будет понятен другим людям. Написание кода, понятного компилятору компьютера, это данность для любого программиста. Написание кода, который могут понять другие люди, это признак настоящего профессионала.
Помимо собственно грамотно написанного кода, его пониманию способствуют комментарии.
Виды комментариев:
1. Повторяющие код. Такие комментарии не нужны, их необходимо убрать.
Замените
3. Отмечающие место в коде.
Замените такой комментарий на стандартный блок
4. Комментарии исправлений. Переместите такие комментарии в систему контроля версий.
6. Описывающие предназначение кода. Используйте комментарии, близкие к реальному миру, а не к техническим подробностям реализации, например:
8. Содержащие краткий обзор или вводную информацию для модуля или библиотеки.
Командная работа
Важно:
1. По статистике код в среднем «переживает» до 10 поколений поддерживающих его программистов.
2. Программисты, поддерживающие код, проводят 50-60% своего времени, читая код.
Поэтому критически важно писать код, который будет понятен другим людям. Написание кода, понятного компилятору компьютера, это данность для любого программиста. Написание кода, который могут понять другие люди, это признак настоящего профессионала.
Помимо собственно грамотно написанного кода, его пониманию способствуют комментарии.
Виды комментариев:
1. Повторяющие код. Такие комментарии не нужны, их необходимо убрать.
// добавляем 1 к i2. Объясняющие код.
i = i + 1;
// i обозначает номер клиента
i = i + 1;
Замените
i
на какое-нибудь значимое имя, например, customer
, и уберите такие комментарии.3. Отмечающие место в коде.
return null; // *** НЕ СДЕЛАНО!!! ***
Замените такой комментарий на стандартный блок
TODO
.4. Комментарии исправлений. Переместите такие комментарии в систему контроля версий.
for i = 1 to maxElements-1 //исправлена ошибка №12345. Кратко объясняющие суть блока кода. Важно поддерживать актуальность таких комментариев!
6. Описывающие предназначение кода. Используйте комментарии, близкие к реальному миру, а не к техническим подробностям реализации, например:
// получаем информацию о работникевместо
// обновляем объект employeeRecord7. Содержащие информацию, которая не может быть представлена в коде. Например, авторские права, Javadoc, ссылки на онлайн ресурсы и т.п.
8. Содержащие краткий обзор или вводную информацию для модуля или библиотеки.