определенные наборы операций, например складывают два числа и выбирают следующую инструкцию в зависимости от результата их сравнения. Проблема заключается в том, что мы не используем компьютеры для решения простых задач. Мы хотим, чтобы они решали задачи, которые нам самим не под силу, но при этом забываем, что вычислительные машины — это придирчивые, ничего не прощающие и безмолвные существа. Более того, мир устроен более сложно, чем мы думаем, поэтому часто не представляем, к каким последствиям могут привести наши запросы.
Мы просто хотим, чтобы программа “делала что-то вроде этого”, и не вникаем в техническое детали. Кроме того, мы часто опираемся на “здравый смысл”. К сожалению, даже среди людей встречаются разные точки зрения на здравый смысл, а уж у компьютеров его вообще нет (хотя некоторые действительно хорошо спроектированные программы могут имитировать здравый смысл в конкретных, подробно изученных ситуациях).
Такой образ мышления приводит к заключению, что “программирование — это понимание”: если вы можете запрограммировать задачу, значит, понимаете ее. И наоборот, если вы глубоко разобрались в задаче, то сможете написать и программу для ее решения. Иначе говоря, программирование можно рассматривать как часть усилий по исследованию проблемы. Программы — это точное представление нашего понимания задачи. Когда вы программируете, то проводите много времени, пытаясь понять задачу, которую хотите автоматизировать.
Процесс разработки программ можно разделить на четыре этапа.
• Анализ. В чем заключается задача? Чего хочет пользователь? Что требуется пользователю? Что может позволить себе пользователь? Какая степень надежности нам необходима?
• Проектирование. Как решить задачу? Какую структуру должна иметь система? Из каких частей она должна состоять? Каким образом эти части будут взаимодействовать? Каким образом система будет взаимодействовать с пользователем?
• Программирование. Выражаем решение задачи (проект) в виде программы. Пишем программу, учитывая все установленные ограничения (по времени, объему, финансам, надежности и т.д.). Убеждаемся, что программа работает правильно и удобна в сопровождении.
• Тестирование. Убеждаемся, что во всех предусмотренных ситуациях система работает правильно.
Программирование и тестирование часто называют реализацией. Очевидно, это простое разделение на четыре части является условным. По этим четырем темам написаны толстые книги, и еще больше книг написано о том, как эти темы взаимосвязаны друг с другом. Следует помнить, что эти стадии проектирования не являются независимыми и на практике не следуют именно в таком порядке. Обычно мы начинаем с анализа, но обратная связь на этапе тестирования влияет на программирование; проблемы, возникающие на этапе программирования, могут свидетельствовать о проблемах, нерешенных на этапе проектирования; в свою очередь, проектирование может выявить аспекты, не учтенные на этапе анализа. На самом деле функционирование системы обычно сразу же выявляет слабость анализа.
Чрезвычайно важным обстоятельством является обратная связь. Мы учимся на ошибках и уточняем свое поведение, основываясь на обучении. Это очень важно для эффективной разработки программного обеспечения. В работе над любым крупным проектом нам неизвестна вся информация о проблеме и ее решении, пока мы не приступим к делу. Конечно, опробовать идеи и проанализировать обратную связь можно и на этапе программирования, но на более ранних стадиях разработки это можно сделать намного легче и быстрее, записав идеи, проработав их и испытав на друзьях. По нашему мнению, наилучшим инструментом проектирования является меловая доска (если вы предпочитаете химические запахи, а не запах мела, то можете использовать доску для фломастеров).
По возможности никогда не проектируйте в одиночку! Никогда не начинайте писать программу, пока не опробуете свои идеи, объяснив их кому-то еще. Обсуждение проекта и методов проектирования с друзьями, коллегами, потенциальными пользователями и другими людьми следует проводить еще до того, как вы сядете за клавиатуру. Просто удивительно, как много можно узнать, просто попытавшись объяснить свою идею словами. Помимо всего прочего, программа — это всего лишь средство выражения идей в виде кода.
Аналогично, попав в тупик при реализации программы, оторвитесь от клавиатуры. Думайте о самой задаче, а не о своем неполном решении этой задачи. Поговорите с кем-нибудь: объясните, что вы хотели и почему программа не работает. Просто удивительно, как часто можно найти решение, просто подробно объяснив задачу кому-то еще. Не занимайтесь отладкой программ (поиском ошибок) в одиночку, если есть такая возможность!
В центре внимания нашей книги лежит реализация и особенно программирование. Мы не учим решать задачи, заваливая вас грудой примеров и решений. Часто новую задачу можно свести к уже известной и применить традиционный метод ее решения. Только после того, как большая часть подзадач будет обработана таким образом, можно позволить себе увлекательное “свободное творчество”. Итак, сосредоточимся на методах выражения идей в виде программ.
Непосредственное выражение идей в виде программ — это основная цель программирования. Это совершенно очевидно, но до сих пор мы еще не привели достаточно ярких примеров. Мы еще не раз будем возвращаться к этому. Если в нашей программе необходимо целое число, мы храним его в виде переменной типа int, предусматривающего основные операции с целыми числами. Если мы хотим работать со строками символов, то храним их в виде переменных типа string, обеспечивающего основные операции по манипуляции с текстом. В идеале, если у нас есть идея, концепция, сущность или какая-то “вещь”, которую можно изобразить на доске и сослаться на нее в ходе дискуссии, про которую написано в учебнике (по некомпьютерным наукам), то мы хотим, чтобы это нечто существовало в нашей программе в виде именованной сущности (типа), предусматривающей требуемые операции. Если мы собираемся проводить математические вычисления, то нам потребуется тип complex для комплексных чисел и тип Matrix для матриц. Если хотим рисовать, то потребуются типы Shape (Фигура), Circle (Круг), Color (Цвет) и Dialog_box (Диалоговое окно). Если хотим работать с потоками данных, скажем, поступающих от датчика температуры, то нам понадобится тип istream (буква “i” означает ввод (input)). Очевидно, что каждый такой тип должен обеспечивать совершенно конкретный набор предусмотренных операций. Мы привели лишь несколько примеров из книги. Кроме них, мы опишем инструменты и методы, позволяющие создавать собственные типы, описывающие любые концепции, необходимые для вашей программы.
Программирование носит частично практический, частично теоретический характер. Если вы ограничитесь ее практическими аспектами, то будете создавать немасштабируемые и трудные для сопровождения поделки. Если же захотите остаться теоретиком, то будете разрабатывать непрактичные (и не экономичные) игрушки. Различные точки зрения на идеалы программирования и биографии людей, внесших значительный вклад в создание языков программирования, изложены