Анимация
JavaScript
|
Главная Библионтека printf("%s", str ? str : "<пусто>"); гораздо элегантнее, чем: if ( str == NULL ) printf( "<пусто>" ); else printf( "%s", str ); Вы к тому же экономите на двух вызовах printf() . Мне также часто приходится видеть неправильное использование операций ++ и --. Весь смысл автоинкремента или автодекремента заключается в соединении этих операций с другими. Вместо: while (*p) putchar ( *p ); ++p; или: for (;*p;++p ) putchar ( *p ); используйте: while(*p) putchar ( *p++ ); Этот код вполне читаем для компетентного программиста на языке Си, даже если ему нет эквивалентной операции в ФОРТРАНе или Паскале. Вы также никогда не должны прятать операторы в макросах из-за того, что вам просто не нравится, как они выглядят. Я однажды видел следующее в реальной программе: struct tree node struct tree node *lftchld; #define left child(x) ((x)->lftchld) ... traverse( tree node *root ) if( left child(root) ) traverse( left child( root ) ); ... Программист намеренно сделал определение структуры труднее читаемым для того, чтобы избежать конфликта имен между полем и совершенно необходимым макросом, и все из-за того, что ему не нравился внешний вид оператора ->. Для него было бы гораздо лучшим выходом просто назвать поле left child и совсем избавиться от макроса. Если вы действительно думаете, что программа должна внешне выглядеть как на Паскале, чтобы быть читаемой, то вы должны программировать на Паскале, а не на Си или Си++. 51. Функция должна делать только одно дело Это обычно не очень удачная мысль - записывать то, что должна делать функция, через ее аргументы. Это должно делать имя функции. Например: UpdateAllViews( CView *sender, long lhint, CObject *phint ) sender lhint phint NULL xx xx Начальное обновление, вызываемое из обрамляющего окна Cview* 0 Crect* Вызывается, когда встроенный объект становится действительным. phint указывает на прямоугольник документа, сохраняя положение недействительного объекта Cview* 1 Crect* Сообщение, посылаемое объектом CView* ("sender" - передатчик). phint сохраняет для CView* обрамляющее окно его клиента. Вам нужны вместо этого три функции: initial update() , update embedded object() и update view(). Верным ключом для понимания того, что здесь что-то не так, является туманная природа имен аргументов. Функциям не должны передаваться "намеки". Им должны даваться указания. 52. Иметь слишком много уровней абстракции или инкапсуляции так же плохо, как и слишком мало Основной смысл использования таких абстракций, как функции или символьные константы (или инкапсуляций, подобных определениям struct или class), заключается в улучшении читаемости программ. Не пользуйтесь ими просто потому, что вы можете делать это. Например, вложенные структуры в данном фрагменте не служат какой-либо полезной цели: struct tree node; struct child ptr unsigned is thread; struct tree node *child; struct tree node struct child ptr left, right; tree node *p; if( !p->left.am a thread ) p = p->left.child; Следующий код лучше читается, потому что в нем меньше точек, и легче сопровождается, так как в нем нужно отлаживать на одно определение меньше: struct tree node struct tree node *left child; unsigned left is thread : 1; struct tree node *right child; unsigned right is thread : 1; if( !p->left is thread ) p = p->left child; 53. Функция должна вызываться более одного раза, Кроме того, если функция должным образом связана (т.е. если она выполняет единственную операцию и весь код функции работает на ее результат), то нет причины извлекать кусок кода в другие функции, если только вы не желаете использовать эту часть кода где-то еще. Мой опыт говорит, что когда функция становится слишком большой, то часто возможно выделить куски, которые обладают достаточной общностью, чтобы быть использованными где-либо еще в программе, так что это правило на самом деле не противоречит правилу "маленькое - прекрасно". Если вы не выделяете этот код, то блочный комментарий, описывающий назначение этого блока программы, который вы могли бы выделить, служит той же самой цели, что и имя функции - документированию. Тем не менее, иногда выделение кода в функции меньшего размера существенно улучшает читаемость этого кода по причине устранения беспорядка. Однако эта практика - создание абстракции для части кода в виде имени функции - добавляет идентификаторы в область глобальных имен, и эта возросшая общая сложность является определенным минусом. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [ 19 ] 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |