DWORD SecondThread (void *ThreadParm) { BOOL done = FALSE; while (!done && WaitForSingleObject(Mutex, INFINITE)==WAIT_OBJECT_0) { if (Index < MAX_TIMES) Times[Index++] = GetTickCount(); else done = TRUE; ReleaseMutex(Mutex); } return(0); }
Теперь смотрите. Мы достигнем Плато Качества...
DWORD SecondThread(void *ThreadParm) { while(Index < MAX_TIMES && WaitForSingleObject(Mutex, INFINITE) == WAIT_OBJECT_0) { if (Index < MAX_TIMES) Times[Index++] = GetTickCount(): ReleaseMutex(Mutex); } return(0); }
Одиннадцать строк против 26. На один уровень меньшая вложенность, но структура полностью прозрачна. Две локальных переменных исчезли. Нет блоков. Совсем нет вложенных else. Меньше мест, где могут скрываться ошибки.
(Если вы еще не программировали используя потоки (threads), то повторная проверка значения Index внутри тела цикла кажется грубой и ненужной. Если же программировали, то повторная проверка естественна и очевидна. Это очень важно: пока текущий поток приостановлен в WaitForSingleObject, другой поток скорее всего будет активен и изменит значение. То, что для вас очевидно, зависит от вашего опыта: еще одна мораль из этого примера -- рассмотрения только структуры куска кода недостаточно.)
Наконец, текст делает совершенно ясным, что разные потоки выполняют функции в разных контекстах. Поэтому совершенно не нужно определять функцию с именем FirstThread(), в точности такую же, как SecondThread(), и вызывать их так:
hThreads[0] = CreateThread(..., FirstThread, ...); hThreads[1] = CreateThread(..., SecondThread, ...);
Когда можно просто
hThreads[0] = CreateThread(..., TheThread, ...); hThreads[1] = CreateThread(..., TheThread, ...);
Почти треть этого примера получена клонированием! Если мы обнаружим ошибку в одной реализации, нам нужно будет не забыть исправить аналогичные ошибки везде. Зачем беспокоиться, когда можно просто слить их в одну. Это хороший способ, когда поджимают сроки.
Программисты дороги. Результаты их работы должны быть собраны и использованы к выгоде их организации. Проблема в том, что традиционный способ паковщика подбить результаты -- подсчитать то, что они могут увидеть. Результаты изучения проблемы командой программистов, пришедшей к пониманию и проверившей это понимание, получив надежный код, выражаются не в числе строк кода (KLOCS), которые они набрали во время изучения. Результаты в окончательном понимании, к которому они пришли, когда закончили.
Причина, по которой важно оценивать результат таким образом, в том, что понимание показывает гораздо более простой способ реализации, чем тот, с которого команда начинала. Классическое поле сражения картостроителей с паковщиками в программировании состоит в том, что картостроители видят, что с тем, что они узнали, повторная реализация может быть сделана быстрее и не будет страдать от проблем сопровождения, вырисовывающихся в существующем коде. Паковщики видят, что картостроители безумствуют, пытаясь разгромить всю их работу (как будто нет резервной копии) и повторить работу нескольких последних месяцев, которые были ужасны, поскольку они, очевидно, не знали, что они делали (они хранят изменяющиеся вещи). Паковщики настраивают одного из своих защитников остановить картостроителей, и организация вынуждена забыть о достигнутом понимании, которое не может быть использовано в контексте существующего кода.
Разумная организация хочет максимального понимания и минимального размера кода, которого только можно достигнуть. Организация, увязшая в модели производства разбухающего кода не учитывает понимание, а подсчитывает свои активы в растущих грудах кода.
Определение хорошей композиции, которое часто используют в художественных школах, звучит так: "Если убрать или изменить любой элемент, то изменится и целое". Вероятно, это морской пейзаж, с маяком, задающим с одной стороны сильную вертикаль, приковывающую взгляд и позиционирующуюся относительно волн позади. Ситуация с маяком (и волнами) -- то, что мы распознаем, и тут живопись показывает свою мощь. Если бы вместо величественного маяка стояло приземистое здание, картина говорила бы о чем-то другом. Если бы поверхность воды была гладкой или там резвились купальщики, то картина несла бы еще какие-то сообщения.
Дело в том, что вокруг не должно быть ничего, что не имело бы ясно означенной цели по отношению к другим элементам композиции. Художнику нужно сохранять контроль за сообщением, и если картина содержит случайные предметы, то они будут вызывать в уме зрителя непредсказуемые ассоциации и искажать отношения между важными элементами.