Совершенный код. Главная задача программирования

Этой записью я надеюсь начать цикл конспектов замечательной книги Стива Макконела "Совершенный код" - обязательного чтения для любого программиста. При всей своей замечательности книга очень большая и сложная, даже при повторном прочтении очень сложно удержать ее в голове всю.

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

Теоретическими исследованями сложности занимался один из пионеров информатики - Эдсгер Дийкстра. В 1989 году он первым обратил внимание на то, что только в компьютерных технологиях мозг человека должен работать с объемами информации диапазоном от отдельных бит до сотен мегабайт, что соответствует разнице в 9 порядков (а в наши времена вполне можно говорить о 15 порядках и более). Человеческий мозг физически не может вместить все детали современной программы, поэтому разработчикам остается один-единственный выход - разбивать программу на более мелкие части таким образом, чтобы их можно было писать независимо друг от друга минимизируя объем программы, который надо держать в голове в данный момент времени. Все принципы, паттерны и методики программирования исходят из этого основополагающего принципа, без которого их просто невозможно понять и правильно применить на практике.

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

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

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

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

3. Слабое сопряжение. Число соединений между разными частями программы должны быть сведено к минимуму. Именно ради этого придуманы принципы абстракции интерфейсов, инкапсуляции и сокрытия информации. Если при работе над одной частью программы нельзя игнорировать другие, проект скорее всего не удачен.

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

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

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

7. Возможность повторного использования кода и переноса системы в другую среду.

Основные уровни проектирования

1. Программная система в целом
2. Подсистемы или пакеты классов
3. Классы
4. Методы и данные конкретных классов
5. Код внутри конкретных методов

Одним из основных принципов структурного и объектно-ориентированного программирования является сокрытие информации. Согласно ему класс и методы должны проектироваться таким образом, чтобы внешний код как можно меньше знал о внутренних деталях их работы. Общее правило - если вы не знаете стоить ли давать доступ извне к определенным методам и данным класса, доступ давать не стоит. В качестве простейшего примера принципа сокрытия информации можно привести пример программы, в который каждый объект должен иметь уникальный номер. Простейшее решение - создать глобальную переменную maxId типа integer и для каждого нового обьекта выполнять простейшую операцию ++maxId. Какие проблемы это может вызвать? А что, если в будущем понадобится зарезервировать определенные диапазоны номеров для особых целей? Или изменить порядок назначения номеров? Или повторно использовать номера уничтоженных объектов? Включить тест, проверяющие превышение номером некого максимального уровня? Наконец изменить тип данных самого номера? В каждом из этих случаев придется проверять весь код программы и вносить огромное количество ручных правок рискуя что-то забыть или поломать. Таким образом и порядок генерации номера и его тип данных относятся к числу информации, которая должна быть скрыта.

Связанные с сокрытием информации секреты как правило относятся к двум областям:

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

2. Секреты, скрывающие источники изменений с целью локализации мест возможных изменений.

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

Несколько общих принципов качественного проектирования:

1. Определение областей вероятных изменений. Исследования показали, что самые лучшие проектировщики прежде всего предвосхищают области возможных изменений. Чаще всего изменения встречаются в следующих областях.

- бизнес-правила
- зависимости от оборудования
- ввод-вывод
- нестандартные возможности языка программирования
- сложные аспекты проектирования
- переменные статуса
- размеры структур данных

2. Поддерживание слабого сопряжения. Цель - создание классов и методов, имеющих немногочисленные, непосредственные, явные и гибкие взаимоотношения с другими классами и методами. Одни модули должны иметь возможность с легкостью использовать другие.

Критерии оценки сопряжения

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

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

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


Комментарии

Совершенный код. Главная задача программирования — Комментарии (2)

  1. Статья понравилась.
    Спасибо.
    Еще советую почитать книгу
    Т.Бадд, 'Объектно-ориентированное программирование'
    В свое время она мне сильно помогла переключить свое мышление...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>