http://web.archive.org/web/200906180318 ... dcode.htmlНачинается с потрясной реальной истории о том, как из примитивной задачи могут раздуть десятки тысяч строк кода.
В середине немного воды, которую может быть скучновато читать, может показаться спорным сравнение с шахматами (типа, "перебор вариантов"). Но, в конечном счёте, если подумать, сходство в анализе ситуации есть - а дальше совершенно правильный вывод, что избежать взрыва вариантов можно только дисциплиной проектирования.
Цитата:
Лечение: локализация и минимизация
...
Лечение: архитектура
Кто-то из математиков сказал: если имеется нерешаемая задача, сначала ее надо разбить на подзадачи, решение которых известно. Это есть сущность арихитектуры: для того, чтобы система оставалась управляемой и maintainable для разработчика, ее следует разбить на части и определить интерфейсы и протоколы взаимодействия этих частей.
В теории часто говорят о модульности, однако по какой-то непонятной причине наиболее модульные языки, как Паскаль и Ада, постепенно вышли из моды. А ведь они прививали дисциплину стройной древовидной модульности и дисциплину мышления в терминах интерфейс-реализация. Оглядываясь назад, могу сказать, что практика программирования на Turbo Pascal и Delphi заменила мне чтение всевозможных умных книжек по архитекруре. (Ах, да, пресловутые begin...end вместо фигурных скобок - вот что потопило эти замечательные языки.)
Но былого не вернешь, и сегодня большинство пишут либо на Си++, где нет понятия модуля, либо на Java/C#, где есть некое подобие модулей, но нет деления на интерфейс и реализацию, хотя бы даже как в Си++. И куда катится этот мир? Полагаю, катится он в сторону какого-то хорошего нового языка, с хорошей модульностью, с лямбда-исчислением и ООП одновременно, и прочими крутыми штуками, - языка, которого пока еще нет.
То, что большинство разработчиков и архитекторов (никогда не понимал смысл этой специальности - человек, который не кодирует, но указывает как это надо делать) чаще всего упускают из виду, это следующая важная мысль: функции, особенно часто используемые, становятся частью языка программирования, и следовательно к их дизайну следует подходить примерно с такой же серьезностью, как к дизайну языка. Когда мы излагаем мысль на человеческом языке, мы по сути мыслим понятиями этого языка; аналогично, писать программу на алгоритмическом языке с использованием какого-то набора функций означает излагать мысль на этом формальном языке. Когда мы предлагаем другим разработчикам нашу библиотеку, мы навязываем им некий набор понятий и образ мышления.
В реальности же у большинства разработчиков цикл создания библиотеки примерной такой: реализуется какая-то функциональность, и "наружу" выдается набор точек доступа к этой функциональности. При этом считается хорошим тоном выдать наружу как можно больше возможностей на все случаи жизни.
Итак, главная дилемма архитектуры - это должны ли интерфейсы каждого модуля быть всеобъемлющими, или наоборот, они должны экономить понятия и давать минимальный набор гибких средств? Если спросить пользователей библиотек, они проголосуют за второе, но - парадокс! - перелезая в шкуру разработчика библиотеки, нам начинает казаться, что "правильнее" первое. Есть о чем подумать, не правда ли?
Я вам собираюсь показать, как несколькими легкими движениями можно сильно сократить или даже и вовсе избавиться от довольно громоздкого программного интерфейса.
Возьмем Windows Registry. Его предназначение - хранить дерево каких-то числовых и строковых значений, предположительно для хранения конфигурации приложений и самой системы. Эта функциональность описана в виде интерфейса с 41 функциями (!), примерно от 3 до 7 аргументов каждая, плюс какие-то структуры, и как водится, куча констант.
...
Какие на самом деле функции нужны для работы с деревом значений? ...
И тогда интерфейс работы с Registry сведется к следующим четырем глаголам: create, write, read, delete
Но у меня есть еще такая домашняя заготовка, которой мы нанесем Windows Registry удар ниже пояса. Мы решим задачу хранения конфигурационных данных в юниксоидном стиле.
Представьте себе, что вы установили в своей UNIX-системе некий продукт под названием UNIX Registry. Вы сразу открываете документацию, чтоб понять как с этим делом работать, и ожидая сотни страниц умного текста, обнаруживаете следующий параграф:
Здравствуйте, я ваш путеводитель по UNIX Registry. UR - это специальная файловая система, предназначенная для эффективной работы с очень маленькими файлами. Приложения могут использовать UR для хранения своих конфигурационных данных в виде дерева значений. По соглашению, эта файловая система маунтируется под /var/reg. Каждое приложение создает свое поддерево (напр. /var/reg/xcalendar), в котором рекомендуется также создать отдельные поддеревья для каждого пользователя. Права доступа регулируются как обычно; естественно, в директориях UR вы можете использовать все стандартные файловые утилиты, например find. Для удобства программирования, флаг "x" на файле в UR означает, что файл может хранить только числовое значение. Приятного отдыха.
Вот и всё. Всё!
Позволю себе дать еще три кратких совета по архитектуре и протоколам: во-первых, используйте технологии Интернета насколько это возможно, например для обмена данными - протокол HTTP. Это дает такую солидную кучу преимуществ, что для их описания понадобилась бы отдельная глава. Попробуйте сами, выберите правильный инструментарий, и поймете о чем речь. В конце концов, не зря технологии Интернета уже победили все остальные технологии.
Во-вторых, избегайте XML где возможно решить задачу более простыми текстовыми форматами в юниксоидном стиле. XML is a pain in the ass. Реально, он едва ли что-то упрощает в нашей жизни. Впрочем, может вам как раз надо усложнить?
В-третьих, для решения задачи выберите такой язык и такие библиотеки, чтобы основной код состоял исключительно из логики решения этой задачи, и ничего лишнего. Другими словами, никакого метапрограммирования, когда, например, приходится буквально нянчиться с COM/DCOM или же описывать крутые Си++ шаблоны, о которые сам черт ногу сломает. Нужно ли оно вам?
Словом, выбирайте такие интерфейсы и протоколы, чтобы пришлось меньше писать кода и зависеть от меньшего количества внешних компонент. Какая простая и очевидная мысль, и как часто мы выбираем в точности противоположную стратегию!
...