Искусство программирования для Unix
Шрифт:
Другой способ заключается в разделении приложения на взаимодействующие процессы клиента (front-end) и сервера (back-end), которые обмениваются данными через специализированный протокол прикладного уровня посредством сокетов. Данный конструкторский подход рассматривается в главах 5 и 7. Во внешней или клиентской части реализуется политика, а во внутренней или серверной — механизм. Глобальная сложность данной пары часто является значительно меньшей, чем сложность одного процесса, в котором монолитно реализованы те же функции. Одновременно уменьшается уязвимость относительно ошибок и сокращаются затраты на жизненный цикл.
1.6.5. Правило простоты: необходимо проектировать простые программы и "добавлять сложность" только там, где
Многие факторы приводят к усложнению программ (а следовательно, делают их более дорогими и более уязвимыми относительно ошибок). Программисты — это зачастую яркие люди, которые гордятся (часто заслуженно) своей способностью справляться со сложностями и ловко обращаться с абстракциями. Часто они состязаются друг с другом, пытаясь выяснить, кто может создать "самые замысловатые и красивые сложности". Столь же часто их способность проектировать превалирует над способностью реализовывать и отлаживать, а результатом является дорогостоящий провал.
Мнение о "замысловатой и красивой сложности" является почти оксюмороном. Unix-программисты соперничают друг с другом за "простоту и красоту". Эта мысль неявно присутствует в данных правилах, но ее стоит сделать очевидной.
Дуг Макилрой.
Еще чаще (по крайней мере, в мире коммерческого программного обеспечения) излишняя сложность исходит от проектных требований, которые скорее основаны на маркетинговой причуде месяца, а не на реальных пожеланиях заказчика или фактических возможностях программы. Множество хороших конструкций были раздавлены маркетинговым нагромождением "статей контрольного перечня" — функций, которые часто вообще не востребованы заказчиком. Круг замыкается; соперники полагают, что должны соревноваться с чужими "украшательствами" путем добавления собственных. Довольно скоро "массивная опухоль" становится индустриальным стандартом, и все используют большие, переполненные ошибками программы, которые не способны удовлетворить даже их создателей.
В любом случае, в конечном результате проигрывают все.
Единственным способом избежать этих ловушек является поощрение культуры программного обеспечения, представители которой знают, что компактность красива, и активно сопротивляются "раздуванию" и сложности кода. Речь идет об инженерной традиции, высоко оценивающей простые решения и ищущей способы разделения программных систем на небольшие взаимодействующие блоки, традиции, которая борется с попытками создания программ с большим количеством "украшательств" (или даже хуже — проектирования программ вокруг "украшательств").
Таковой была бы культура, во многом похожая на культуру Unix.
1.6.6. Правило расчетливости: пишите большие программы, только если после демонстрации становится ясно, что ничего другого не остается
Под "большими программами" в здесь подразумеваются программы с большим объемом кода и значительной внутренней сложностью. Разрешая программе разрастаться, разработчик ставит под удар дальнейшее обслуживание данной программы. Поскольку люди неохотно расстаются с видимым результатом длительной работы, крупные программы привлекают излишние вложения в подходах, которые ошибочны или неоптимальны.
Проблема оптимального размера программного обеспечения более подробно рассмотрена в главе 13.
1.6.7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой
Поскольку отладка часто занимает три четверти или более времени разработки, раннее окончание работы в целях облегчения отладки может быть очень хорошим решением. Особенно эффективный способ простой отладки заключается в проектировании с учетом прозрачности (transparency)
и воспринимаемости (discoverability).Программная система прозрачна, если при ее минимальном изучении можно немедленно понять, что она делает и каким образом. Программа воспринимаема, когда она имеет средства для мониторинга и отображения внутреннего состояния, так что программа не только работает хорошо, но и позволяет понять признаки правильной работы.
Проектирование с учетом данных характеристик имеет ряд последствий на всем протяжении проекта. Как минимум, это означает, что отладочные возможности не должны запаздывать. Скорее они должны быть спроектированы с самого начала—с той точки зрения, что программа должна быть способна как продемонстрировать собственную корректность, так и передать будущим разработчикам ментальную модель решаемой программой проблемы, разработанную создателем программы.
Для того чтобы программа могла продемонстрировать свою корректность, в ней должны использоваться достаточно простые форматы входных и выходных данных, с тем чтобы можно было легко проверить соответствующую связь между допустимым вводом и корректным выводом.
Цель разработки с учетом прозрачности и воспринимаемости также должна поддерживать простые интерфейсы, которыми могут легко манипулировать другие программы, в особенности средства тестирования и мониторинга, а также отладочные сценарии.
1.6.8. Правило устойчивости: устойчивость-следствие прозрачности и простоты
Программное обеспечение называют устойчивым, когда оно выполняет свои функции в неожиданных условиях, которые выходят за рамки предположений разработчика, столь же хорошо, как и в нормальных условиях.
Большинство программ "являются хрупкими и переполненными ошибками, поскольку для человеческого мозга слишком сложно сразу понять всю программу целиком. Если нет возможности сделать корректный вывод о внутреннем устройстве программы, то нельзя быть уверенным в ее корректности, и ее невозможно исправить в случае поломки.
Следовательно, способ создания устойчивого программного обеспечения заключается в организации такого внутреннего устройства программ, которое было бы простым для понимания человеком. Существует два основных способа достижения этой цели: прозрачность и простота.
Для достижения устойчивости очень важным является проектирование, допускающее необычный или крайне объемный ввод. Этому способствует правило композиции; ввод, сгенерированный другими программами, известный для программ нагрузочных испытаний (например, оригинальный Unix-компилятор С по имеющимся сообщениям нуждался в небольшом обновлении, для того чтобы хорошо обрабатывать вывод утилиты Yacc). Используемые формы часто кажутся бесполезными для людей. Например, допускаются пустые списки, строки и т.д. даже в тех местах, где человек редко или никогда не вводит пустую строку. Это предотвращает особые ситуации при механическом генерировании ввода.
Генри Спенсер.
Один весьма важный тактический прием для достижения устойчивости при работе с необычным вводом заключается в том, чтобы избегать частных случаев в коде. Часто ошибки скрываются в коде для обработки частных случаев, а также возникают в процессе взаимодействия частей кода, предназначенных для обработки различных частных случаев.
Как отмечалось выше, программа является прозрачной в том случае, если при ее минимальном изучении немедленно становится ясно, что происходит. Программа является простой, если происходящее в ней не представляется сложным для восприятия человеком. Чем сильнее эти свойства проявляются в разрабатываемых программах, тем устойчивее они будут.