Мир в строчке кода

Увидеть мир в строчке кода

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

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

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

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

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

Размышляя о проекте, совершенно естественно, что разработчики видят у себя в голове высокоуровневое описание внешних частей системы, вероятно ввод/вывод, более детальное описание внутренних частей, вероятно группу определений таблиц базы данных, а прямо посередине, в точке, где выполняется основная работа системы, они часто знают лишь критические участки кода, которые могут быть очень сложными. С этой позиции они могут убедить себя, что детали внешней части системы в порядке, тем не менее даже не продумав их. Не всегда при проектировании в центре внимания оказывается факт, что существуют ошибки при передаче (сбойные биты) -- разработчик мог бы заметить критическую часть протокола низкоуровневого восстановления ошибок, и осознать необходимость продумывания его реализации. Нет лучшего способа ощутить безопасность того, что ты разрабатываешь, чем найти хотя бы один практический способ его реализации.

Мы не говорим, что вы обязаны видеть, как в процессе проектирования в голове проскакивают строки. Мы говорим о том, что это может быть очень полезным способом прояснения ваших размышлений о предмете, а если ваши мысли поворачиваются к коду, следуйте за ними. Не отметайте эти размышления только потому, что ваша задача -- высокоуровневый документ. На этом пути вы получите проектный документ, который можно эффективно использовать, а люди будут называть вас волшебником процесса разработки. Помните, каково держать зубную щетку и палочки для еды? Люди, которые имеют такую привычку, скорее поверят, что вы хорошо владеете палочками для еды, чем то, что вы просто зажали зубную щетку в [другом] кулаке.

Другая область, где на этапе высокоуровневого проектирования действительно очень полезны небольшие фрагменты кода -- получение реального ощущения семантики системы, которую вы собираетесь использовать. Мы всегда должны изучить новые API для операционных систем, GUI, библиотек и т.д. Потребуются годы, чтобы действительно полностью освоить правильное использование API. Поэтому заглядывайте в книги, которые обсуждают API, и пишите небольшие программки, демонстрирующие свойства, которые, как вы думаете, вам понадобятся. Это на самом деле помогает сконцентрировать ваш ум на том, что вам нужно, чтобы проследить путь снизу вверх, в то время, пока ваша разработка происходит сверху вниз, и гарантирует, что вы не пытаетесь использовать семантику, которой на самом деле нет. Попытка разработать проект, требующий другого дизайна операционной системы, может оказаться очень сложной, но если вы провели несколько минут за написанием маленькой программки с целью поупражняться с какой-то особенностью, то вы будете использовать ее как есть, и никогда не вспомните, что говорится в документации. Вы отыграете эти минуты во время реализации, поскольку вы можете просто скопировать ваши заготовки в исходный код и немного их поправить.

Посвятите некоторое время просмотру дизайна используемых вами API. Взгляните на их валюту - значения, передаваемые из/в API. Как части этого интерфейса стыкуются друг с другом? Хорошо ли они спроектированы? Какие идиомы предлагают вам использовать их разработчики? API обычно проектируют опытные разработчики, и они похожи на небольшие послания от очень ярких людей о том, как они видят мир. Стиль UNIX API Кена Томпсона (Ken Thompson) прекрасно сохранился за 30 лет. Он сам говорил, что единственное изменение, которое он бы сделал: " Я бы написал creat() c e!" В UNIX API есть что-то очень близкое к тому, как работают компьютеры.

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