• Если вы сделали 90 % работы и безнадежно увязли в отладке остальных 10 %, то, видимо, нельзя считать, что сделано 90 %? Исправление ошибок — это не движение вперед. Вам не платят за отладку. Отладка — пустая трата времени. Хорошо, если пустая трата времени будет более заметна, чтобы можно было видеть ее реальную цену и, прежде всего, постараться не допускать этого.
• Если кажется, что ваш проект идет по графику, а через неделю обнаруживается, что он опаздывает на полгода, то у вас есть проблемы, главная из которых, возможно, не в том, что он опаздывает на полгода, а в существовании невидимых силовых полей, способных скрыть полугодовую задержку! Отсутствие видимого прогресса — то же самое, что отсутствие прогресса вообще.
Невидимость таит в себе опасность. Рассуждение становится яснее, когда есть конкретный предмет для обдумывания. Легче управлять вещами, которые можно видеть, и видеть в непрерывном изменении:
• При написании модульных тестов вы узнаете, насколько легко проводить модульное тестирование для конкретного модуля кода. Модульное тестирование выявляет присутствие (или отсутствие) качеств, которые желательны для кода, такие
• Прогон модульных тестов демонстрирует, как ведет себя код. Он позволяет обнаружить присутствие (или отсутствие) характеристик времени выполнения, желательных для приложения, например устойчивости и корректности.
• С помощью доски и карточек можно сделать прогресс наглядным и конкретным. Можно увидеть, что задачи находятся в состоянии
• Итеративная разработка повышает наглядность прогресса (или его отсутствия), поскольку чаще фиксируются факты того, что разработка ведется. Создание программного обеспечения, готового к выпуску, отражает реальное положение вещей, в отличие от оценок.
Лучше всего разрабатывать программы, имея многочисленные наглядные показатели. Наглядность дает уверенность в том, что прогресс является реальным, а не вымышленным; спланированным, а не непреднамеренным; воспроизводимым, а не случайным.
Передача сообщений улучшает масштабируемость параллельных систем
Рассел Уиндер
Уже на первых лекциях по информатике программистов учат, что конкурентные вычисления — и в особенности параллельные как особый подвид конкурентных — вещь трудная, и что лишь лучшим дается надежда справиться с этой задачей, и что даже лучшие не справляются. При этом неизменно уделяется большое внимание потокам, семафорам, мониторам и трудностям организации потоковой безопасности при одновременном доступе к переменным.
Сложных проблем здесь действительно много, и решать их бывает очень трудно. Но в чем корень проблем? Общая память. Практически все проблемы конкурентных вычислений, о которых постоянно приходится слышать, касаются общей памяти с изменяемыми данными: состояние гонки (race conditions), взаимная блокировка (deadlock), активная блокировка (livelock) и т. п. Кажется, ответ очевиден: забудьте о конкурентности либо держитесь подальше от общей памяти!
Отказ от конкурентности почти наверняка не вариант. Количество ядер в компьютерах возрастает чуть ли не каждый квартал, поэтому достижение настоящего параллелизма становится все важнее. Мы не можем больше полагаться на непрерывный рост тактовой частоты процессоров как основу производительности приложений. Производительность может вырасти только за счет параллелизма. Конечно, можно не заботиться о производительности приложений, но едва ли это понравится пользователям.
Так можно ли отказаться от общей памяти? Определенно, да.
Вместо потоков и общей памяти можно воспользоваться процессами и передачей сообщений. Под